From 85766a0aa6be039041a0229e1c3354d27b50cef1 Mon Sep 17 00:00:00 2001 From: Larry Ruane Date: Mon, 23 May 2022 16:37:12 -0600 Subject: [PATCH] Fix V5 transaction txid (#392) This is a shortcut fix. Instead of replicating the zip244 transaction logic that's implemented in librustzcash: zcash_primitives/src/transaction/components/orchard.rs cheat by calling getblock with verbose level 1, which prints the txid of each transaction. This currently requires calling getblock twice, once for the raw hex (as we have always done), and again to get the transaction IDs. An easy improvement would be to add the raw hex to verbosity 1 result. (Or have a new verbosity that shows both.) --- common/common.go | 29 +++++++++++++++++++++++++++++ parser/transaction.go | 23 ++++++++--------------- parser/transaction_test.go | 7 +++---- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/common/common.go b/common/common.go index 6ba25ec9..f895e975 100644 --- a/common/common.go +++ b/common/common.go @@ -147,6 +147,11 @@ type ( Satoshis uint64 Height int } + + // reply to getblock verbose=1 (json includes txid list) + ZcashRpcReplyGetblock1 struct { + Tx []string + } ) // FirstRPC tests that we can successfully reach zcashd through the RPC @@ -271,6 +276,30 @@ func getBlockFromRPC(height int) (*walletrpc.CompactBlock, error) { return nil, errors.New("received unexpected height block") } + // Get the txids; it would be more efficient to implement a + // getblock verbose level that returns both raw hex and the txid list + // so that this second rpc wouldn't be needed. + { + params[1] = json.RawMessage("1") // JSON with list of txids + result, rpcErr := RawRequest("getblock", params) + if rpcErr != nil { + return nil, errors.Wrap(rpcErr, "error requesting verbose block") + } + var block1 ZcashRpcReplyGetblock1 + err = json.Unmarshal(result, &block1) + if err != nil { + return nil, err + } + for i, t := range block.Transactions() { + txid, err := hex.DecodeString(block1.Tx[i]) + if err != nil { + return nil, errors.Wrap(err, "error decoding getblock txid") + } + // convert from big-endian + t.SetTxID(parser.Reverse(txid)) + } + } + return block.ToCompact(), nil } diff --git a/parser/transaction.go b/parser/transaction.go index e59367ed..5c3fb24b 100644 --- a/parser/transaction.go +++ b/parser/transaction.go @@ -6,7 +6,6 @@ package parser import ( - "crypto/sha256" "fmt" "github.com/pkg/errors" @@ -339,29 +338,23 @@ func (p *action) ToCompact() *walletrpc.CompactOrchardAction { // Transaction encodes a full (zcashd) transaction. type Transaction struct { *rawTransaction - rawBytes []byte - cachedTxID []byte // cached for performance + rawBytes []byte + txID []byte // from getblock verbose=1 +} + +func (tx *Transaction) SetTxID(txid []byte) { + tx.txID = txid } // GetDisplayHash returns the transaction hash in big-endian display order. func (tx *Transaction) GetDisplayHash() []byte { - if tx.cachedTxID != nil { - return tx.cachedTxID - } - - // SHA256d - digest := sha256.Sum256(tx.rawBytes) - digest = sha256.Sum256(digest[:]) // Convert to big-endian - tx.cachedTxID = Reverse(digest[:]) - return tx.cachedTxID + return Reverse(tx.txID[:]) } // GetEncodableHash returns the transaction hash in little-endian wire format order. func (tx *Transaction) GetEncodableHash() []byte { - digest := sha256.Sum256(tx.rawBytes) - digest = sha256.Sum256(digest[:]) - return digest[:] + return tx.txID } // Bytes returns a full transaction's raw bytes. diff --git a/parser/transaction_test.go b/parser/transaction_test.go index dd9498a2..018cd892 100644 --- a/parser/transaction_test.go +++ b/parser/transaction_test.go @@ -4,7 +4,6 @@ package parser import ( - "bytes" "encoding/hex" "encoding/json" "os" @@ -85,9 +84,9 @@ func TestV5TransactionParser(t *testing.T) { if len(rest) != 0 { t.Fatalf("Test did not consume entire buffer, %d remaining", len(rest)) } - if bytes.Equal(tx.cachedTxID, []byte(txtestdata.Txid)) { - t.Fatal("txid") - } + // Currently, we can't check the txid because we get that from + // zcashd (getblock rpc) rather than computing it ourselves. + // https://github.com/zcash/lightwalletd/issues/392 if tx.version != uint32(txtestdata.Version) { t.Fatal("version miscompare") }