diff --git a/common/common.go b/common/common.go index 6ba25ec9..56ad5f60 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,31 @@ func getBlockFromRPC(height int) (*walletrpc.CompactBlock, error) { return nil, errors.New("received unexpected height block") } + // `block.ParseFromSlice` correctly parses blocks containing v5 transactions, but + // incorrectly computes the IDs of the v5 transactions. We temporarily paper over this + // bug by fetching the correct txids via a second getblock RPC call. + // https://github.com/zcash/lightwalletd/issues/392 + { + 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") }