Skip to content

Commit

Permalink
Fix V5 transaction txid (#392)
Browse files Browse the repository at this point in the history
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.)
  • Loading branch information
Larry Ruane authored and LarryRuane committed May 24, 2022
1 parent ab4c0fe commit dfac020
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 19 deletions.
30 changes: 30 additions & 0 deletions common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down
23 changes: 8 additions & 15 deletions parser/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
package parser

import (
"crypto/sha256"
"fmt"

"github.com/pkg/errors"
Expand Down Expand Up @@ -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.
Expand Down
7 changes: 3 additions & 4 deletions parser/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package parser

import (
"bytes"
"encoding/hex"
"encoding/json"
"os"
Expand Down Expand Up @@ -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")
}
Expand Down

0 comments on commit dfac020

Please sign in to comment.