Skip to content

Commit 8d4760f

Browse files
authored
Merge pull request #17 from HorizenOfficial/zendoo-support
Zendoo support for Rosetta
2 parents 8a12763 + 8bbb23d commit 8d4760f

12 files changed

+2218
-476
lines changed

Dockerfile

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ MAINTAINER cronic@horizen.io
2020

2121
SHELL ["/bin/bash", "-c"]
2222

23-
# Latest release zen 2.0.24
24-
ARG ZEN_COMMITTISH=v2.0.24
23+
# Latest release zen 3.0.0
24+
# TODO: Update ZEN_COMMITTISH to newest tag
25+
ARG ZEN_COMMITTISH=v3.0.0
2526
ARG IS_RELEASE=false
2627
# cronic <cronic@zensystem.io> http://pool.sks-keyservers.net:11371/pks/lookup?search=0x219F55740BBF7A1CE368BA45FB7053CE4991B669&op=vindex
2728
# Luigi Varriale <luigi@zensystem.io> http://pool.sks-keyservers.net:11371/pks/lookup?search=0x7C20EDC1CABFC9D1005EADBF3C80D9DD9F971AB6&op=vindex
@@ -39,11 +40,11 @@ RUN set -euxo pipefail \
3940
&& git clone https://github.com/HorizenOfficial/zen.git \
4041
&& cd /zen && git checkout "${ZEN_COMMITTISH}" \
4142
&& if [ "$IS_RELEASE" = "true" ]; then \
42-
( gpg2 --batch --keyserver hkp://p80.pool.sks-keyservers.net:80 --keyserver-options timeout=15 --recv-keys $MAINTAINER_KEYS || \
43-
gpg2 --batch --keyserver hkp://ha.pool.sks-keyservers.net --keyserver-options timeout=15 --recv-keys $MAINTAINER_KEYS || \
44-
gpg2 --batch --keyserver pgp.mit.edu --keyserver-options timeout=15 --recv-keys $MAINTAINER_KEYS || \
45-
gpg2 --batch --keyserver keyserver.pgp.com --keyserver-options timeout=15 --recv-keys $MAINTAINER_KEYS || \
46-
gpg2 --batch --keyserver pgp.key-server.io --keyserver-options timeout=15 --recv-keys $MAINTAINER_KEYS ) \
43+
( gpg2 --batch --keyserver hkps://keys.openpgp.org --keyserver-options timeout=15 --recv $MAINTAINER_KEYS || \
44+
gpg2 --batch --keyserver keyserver.ubuntu.com --keyserver-options timeout=15 --recv $MAINTAINER_KEYS || \
45+
gpg2 --batch --keyserver hkp://p80.pool.sks-keyservers.net:80 --keyserver-options timeout=15 --recv-keys $MAINTAINER_KEYS || \
46+
gpg2 --batch --keyserver hkp://ipv4.pool.sks-keyservers.net --keyserver-options timeout=15 --recv-keys $MAINTAINER_KEYS || \
47+
gpg2 --batch --keyserver hkp://pgp.mit.edu:80 --keyserver-options timeout=15 --recv-keys $MAINTAINER_KEYS ) \
4748
&& if git verify-tag -v "${ZEN_COMMITTISH}"; then \
4849
echo "Valid signed tag"; \
4950
else \

assets/zen-mainnet.conf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ rpcallowip=::/0
1717
rpcthreads=16
1818
rpcworkqueue=1000
1919
disablewallet=1
20-
txindex=0
20+
txindex=1
2121
port=9033
2222
rpcport=8231
2323
rpcuser=rosetta
2424
rpcpassword=rosetta
2525
showmetrics=0
2626
printtoconsole=1
27+
maturityheightindex=1
2728

2829
# manual pruning is not supported in zend
2930
#prune=1

assets/zen-regtest.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ rpcpassword=rosetta
2525
showmetrics=0
2626
printtoconsole=1
2727
regtest=1
28+
maturityheightindex=1
2829

2930
# manual pruning is not supported in zend
3031
#prune=1

assets/zen-testnet.conf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ rpcallowip=::/0
1717
rpcthreads=16
1818
rpcworkqueue=1000
1919
disablewallet=1
20-
txindex=0
20+
txindex=1
2121
port=19033
2222
rpcport=18231
2323
rpcuser=rosetta
2424
rpcpassword=rosetta
2525
showmetrics=0
2626
printtoconsole=1
2727
testnet=1
28+
maturityheightindex=1
2829

2930
# manual pruning is not supported in zend
3031
#prune=1

ci/setup_env.sh

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ set -eo pipefail
55
if [ ! -z "${TRAVIS_TAG}" ]; then
66
export GNUPGHOME="$(mktemp -d 2>/dev/null || mktemp -d -t 'GNUPGHOME')"
77
echo "Tagged build, fetching maintainer keys."
8-
gpg -v --batch --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys $MAINTAINER_KEYS ||
9-
gpg -v --batch --keyserver hkp://ipv4.pool.sks-keyservers.net --recv-keys $MAINTAINER_KEYS ||
10-
gpg -v --batch --keyserver hkp://pgp.mit.edu:80 --recv-keys $MAINTAINER_KEYS
8+
gpg -v --batch --keyserver hkps://keys.openpgp.org --recv $MAINTAINER_KEYS ||
9+
gpg -v --batch --keyserver keyserver.ubuntu.com --recv $MAINTAINER_KEYS ||
10+
gpg -v --batch --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys $MAINTAINER_KEYS ||
11+
gpg -v --batch --keyserver hkp://ipv4.pool.sks-keyservers.net --recv-keys $MAINTAINER_KEYS ||
12+
gpg -v --batch --keyserver hkp://pgp.mit.edu:80 --recv-keys $MAINTAINER_KEYS
1113
if git verify-tag -v "${TRAVIS_TAG}"; then
1214
echo "Valid signed tag"
1315
export version="${TRAVIS_TAG}"

services/network_service_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ import (
2626
)
2727

2828
var (
29-
middlewareVersion = "0.0.5"
29+
middlewareVersion = "0.0.6"
3030
defaultNetworkOptions = &types.NetworkOptionsResponse{
3131
Version: &types.Version{
3232
RosettaVersion: types.RosettaAPIVersion,
33-
NodeVersion: "2.0.24",
33+
NodeVersion: "3.0.0",
3434
MiddlewareVersion: &middlewareVersion,
3535
},
3636
Allow: &types.Allow{

services/types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
const (
2525
// NodeVersion is the version of
2626
// zend core we are using.
27-
NodeVersion = "2.0.24"
27+
NodeVersion = "3.0.0"
2828

2929
// HistoricalBalanceLookup indicates
3030
// that historical balance lookup is supported.
@@ -41,7 +41,7 @@ var (
4141
// variable instead of a constant because
4242
// we typically need the pointer of this
4343
// value.
44-
MiddlewareVersion = "0.0.5"
44+
MiddlewareVersion = "0.0.6"
4545
)
4646

4747
// Client is used by the servicers to get Peer information

zen/client.go

Lines changed: 111 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ type requestMethod string
5656

5757
const (
5858
// https://bitcoin.org/en/developer-reference#getblock
59-
requestMethodGetBlock requestMethod = "getblock"
59+
requestMethodGetBlock requestMethod = "getblockexpanded"
6060

6161
// https://bitcoin.org/en/developer-reference#getblockhash
6262
requestMethodGetBlockHash requestMethod = "getblockhash"
@@ -221,24 +221,36 @@ func (b *Client) GetRawBlock(
221221
coins := []string{}
222222
blockTxHashes := []string{}
223223
for txIndex, tx := range block.Txs {
224-
blockTxHashes = append(blockTxHashes, tx.Hash)
225-
for inputIndex, input := range tx.Inputs {
226-
txHash, vout, ok := b.getInputTxHash(input, txIndex, inputIndex)
227-
if !ok {
228-
continue
229-
}
224+
coins, blockTxHashes = addCoins(txIndex, blockTxHashes, tx.Hash, tx.Inputs, b, coins)
225+
}
230226

231-
// If any transactions spent in the same block they are created, don't include them
232-
// in previousTxHashes to fetch.
233-
if !utils.ContainsString(blockTxHashes, txHash) {
234-
coins = append(coins, CoinIdentifier(txHash, vout))
235-
}
236-
}
227+
blockCertTxHashes := []string{}
228+
for certTxIndex, certTx := range block.Certs {
229+
coins, blockCertTxHashes = addCoins(certTxIndex, blockCertTxHashes, certTx.Hash, certTx.Inputs, b, coins)
237230
}
238231

239232
return block, coins, nil
240233
}
241234

235+
236+
func addCoins(txIndex int, blockTxHashes []string, hash string, inputs []*Input, b *Client, coins []string) ([]string, []string) {
237+
blockTxHashes = append(blockTxHashes, hash)
238+
for inputIndex, input := range inputs {
239+
txHash, vout, ok := b.getInputTxHash(input, txIndex, inputIndex)
240+
if !ok {
241+
continue
242+
}
243+
244+
// If any transactions spent in the same block they are created, don't include them
245+
// in previousTxHashes to fetch.
246+
if !utils.ContainsString(blockTxHashes, txHash) {
247+
coins = append(coins, CoinIdentifier(txHash, vout))
248+
}
249+
}
250+
251+
return coins, blockTxHashes
252+
}
253+
242254
// ParseBlock returns a parsed bitcoin block given a raw bitcoin
243255
// block and a map of transactions containing inputs.
244256
func (b *Client) ParseBlock(
@@ -493,9 +505,9 @@ func (b *Client) parseTransactions(
493505
if block == nil {
494506
return nil, errors.New("error parsing nil block")
495507
}
496-
txs := make([]*types.Transaction, len(block.Txs))
508+
txs := make([]*types.Transaction, len(block.Txs) + len(block.Certs))
497509
for index, transaction := range block.Txs {
498-
txOps, err := b.parseTxOperations(transaction, index, coins)
510+
txOps, err := b.parseTxOperations(transaction.Inputs, transaction.Outputs, transaction.Hash, index, coins, false)
499511
if err != nil {
500512
return nil, fmt.Errorf("%w: error parsing transaction operations", err)
501513
}
@@ -515,41 +527,95 @@ func (b *Client) parseTransactions(
515527

516528
txs[index] = tx
517529

518-
// In some cases, a transaction will spent an output
519-
// from the same block.
520-
for _, op := range tx.Operations {
521-
if op.CoinChange == nil {
522-
continue
523-
}
530+
coins = addCoinsFromSameBlock(tx.Operations, coins)
531+
}
524532

525-
if op.CoinChange.CoinAction != types.CoinCreated {
526-
continue
527-
}
533+
for index, certificate := range block.Certs {
534+
txIndex := len(block.Txs) + index;
535+
certTxOps, err := b.parseTxOperations(certificate.Inputs, certificate.Outputs, certificate.Hash, txIndex, coins, true)
536+
if err != nil {
537+
return nil, fmt.Errorf("%w: error parsing certificate transaction operations", err)
538+
}
539+
540+
tx := &types.Transaction{
541+
TransactionIdentifier: &types.TransactionIdentifier{
542+
Hash: certificate.Hash,
543+
},
544+
Operations: certTxOps,
545+
}
546+
547+
txs[txIndex] = tx
548+
549+
coins = addCoinsFromSameBlock(tx.Operations, coins)
550+
}
528551

529-
coins[op.CoinChange.CoinIdentifier.Identifier] = &storage.AccountCoin{
530-
Coin: &types.Coin{
531-
CoinIdentifier: op.CoinChange.CoinIdentifier,
532-
Amount: op.Amount,
533-
},
534-
Account: op.Account,
552+
for index, certificate := range block.MaturedCerts {
553+
// For matured certificates, we only parse outputs that are backward transfers
554+
backwardTransferOutputs := []*Output{}
555+
556+
for i := range certificate.Outputs {
557+
if certificate.Outputs[i].BackwardTransfer == true {
558+
backwardTransferOutputs = append(backwardTransferOutputs, certificate.Outputs[i])
535559
}
536560
}
561+
562+
certTxOps, err := b.parseTxOperations([]*Input{}, backwardTransferOutputs, certificate.Hash, len(block.Txs) + len(block.Certs) + index, coins, false)
563+
if err != nil {
564+
return nil, fmt.Errorf("%w: error parsing mature certificate transaction operations", err)
565+
}
566+
567+
tx := &types.Transaction{
568+
TransactionIdentifier: &types.TransactionIdentifier{
569+
Hash: certificate.Hash,
570+
},
571+
Operations: certTxOps,
572+
}
573+
574+
txs = append(txs, tx)
575+
576+
coins = addCoinsFromSameBlock(tx.Operations, coins)
537577
}
538578

539579
return txs, nil
580+
}
540581

582+
func addCoinsFromSameBlock(operations []*types.Operation, coins map[string]*storage.AccountCoin) map[string]*storage.AccountCoin {
583+
// In some cases, a transaction will spent an output
584+
// from the same block.
585+
for _, op := range operations {
586+
if op.CoinChange == nil {
587+
continue
588+
}
589+
590+
if op.CoinChange.CoinAction != types.CoinCreated {
591+
continue
592+
}
593+
594+
coins[op.CoinChange.CoinIdentifier.Identifier] = &storage.AccountCoin{
595+
Coin: &types.Coin{
596+
CoinIdentifier: op.CoinChange.CoinIdentifier,
597+
Amount: op.Amount,
598+
},
599+
Account: op.Account,
600+
}
601+
}
602+
603+
return coins
541604
}
542605

543606
// parseTransactions returns the transaction operations for a specified transaction.
544607
// It uses a map of previous transactions to properly hydrate the input operations.
545608
func (b *Client) parseTxOperations(
546-
tx *Transaction,
609+
inputs []*Input,
610+
outputs []*Output,
611+
hash string,
547612
txIndex int,
548613
coins map[string]*storage.AccountCoin,
614+
isImmatureCertificate bool,
549615
) ([]*types.Operation, error) {
550616
txOps := []*types.Operation{}
551617

552-
for networkIndex, input := range tx.Inputs {
618+
for networkIndex, input := range inputs {
553619
if bitcoinIsCoinbaseInput(input, txIndex, networkIndex) {
554620
txOp, err := b.coinbaseTxOperation(input, int64(len(txOps)), int64(networkIndex))
555621
if err != nil {
@@ -566,7 +632,7 @@ func (b *Client) parseTxOperations(
566632
return nil, fmt.Errorf(
567633
"error finding previous tx: %s, for tx: %s, input index: %d",
568634
input.TxHash,
569-
tx.Hash,
635+
hash,
570636
networkIndex,
571637
)
572638
}
@@ -585,20 +651,26 @@ func (b *Client) parseTxOperations(
585651
txOps = append(txOps, txOp)
586652
}
587653

588-
for networkIndex, output := range tx.Outputs {
654+
for _, output := range outputs {
655+
if isImmatureCertificate == true && output.BackwardTransfer == true {
656+
continue
657+
}
658+
659+
outputIndex := int64(output.Index)
660+
589661
txOp, err := b.parseOutputTransactionOperation(
590662
output,
591-
tx.Hash,
663+
hash,
592664
int64(len(txOps)),
593-
int64(networkIndex),
665+
outputIndex,
594666
txIndex,
595667
)
596668
if err != nil {
597669
return nil, fmt.Errorf(
598670
"%w: error parsing tx output, hash: %s, index: %d",
599671
err,
600-
tx.Hash,
601-
networkIndex,
672+
hash,
673+
outputIndex,
602674
)
603675
}
604676

@@ -651,7 +723,7 @@ func (b *Client) parseOutputTransactionOperation(
651723
account.Address = fmt.Sprintf("%s:%d", txHash, networkIndex)
652724
}
653725

654-
//if it's a coinbase output and we are not in regtest populate SubAccount field
726+
// if it's a coinbase output and we are not in regtest populate SubAccount field
655727
if txIndex == 0 && b.genesisBlockIdentifier.Hash != RegtestGenesisBlockIdentifier.Hash {
656728
account.SubAccount = &types.SubAccountIdentifier{
657729
Address: "coinbase",

0 commit comments

Comments
 (0)