Skip to content

Commit dfac020

Browse files
Larry RuaneLarryRuane
authored andcommitted
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.)
1 parent ab4c0fe commit dfac020

File tree

3 files changed

+41
-19
lines changed

3 files changed

+41
-19
lines changed

common/common.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@ type (
147147
Satoshis uint64
148148
Height int
149149
}
150+
151+
// reply to getblock verbose=1 (json includes txid list)
152+
ZcashRpcReplyGetblock1 struct {
153+
Tx []string
154+
}
150155
)
151156

152157
// FirstRPC tests that we can successfully reach zcashd through the RPC
@@ -271,6 +276,31 @@ func getBlockFromRPC(height int) (*walletrpc.CompactBlock, error) {
271276
return nil, errors.New("received unexpected height block")
272277
}
273278

279+
// `block.ParseFromSlice` correctly parses blocks containing v5 transactions, but
280+
// incorrectly computes the IDs of the v5 transactions. We temporarily paper over this
281+
// bug by fetching the correct txids via a second getblock RPC call.
282+
// https://github.com/zcash/lightwalletd/issues/392
283+
{
284+
params[1] = json.RawMessage("1") // JSON with list of txids
285+
result, rpcErr := RawRequest("getblock", params)
286+
if rpcErr != nil {
287+
return nil, errors.Wrap(rpcErr, "error requesting verbose block")
288+
}
289+
var block1 ZcashRpcReplyGetblock1
290+
err = json.Unmarshal(result, &block1)
291+
if err != nil {
292+
return nil, err
293+
}
294+
for i, t := range block.Transactions() {
295+
txid, err := hex.DecodeString(block1.Tx[i])
296+
if err != nil {
297+
return nil, errors.Wrap(err, "error decoding getblock txid")
298+
}
299+
// convert from big-endian
300+
t.SetTxID(parser.Reverse(txid))
301+
}
302+
}
303+
274304
return block.ToCompact(), nil
275305
}
276306

parser/transaction.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
package parser
77

88
import (
9-
"crypto/sha256"
109
"fmt"
1110

1211
"github.com/pkg/errors"
@@ -339,29 +338,23 @@ func (p *action) ToCompact() *walletrpc.CompactOrchardAction {
339338
// Transaction encodes a full (zcashd) transaction.
340339
type Transaction struct {
341340
*rawTransaction
342-
rawBytes []byte
343-
cachedTxID []byte // cached for performance
341+
rawBytes []byte
342+
txID []byte // from getblock verbose=1
343+
}
344+
345+
func (tx *Transaction) SetTxID(txid []byte) {
346+
tx.txID = txid
344347
}
345348

346349
// GetDisplayHash returns the transaction hash in big-endian display order.
347350
func (tx *Transaction) GetDisplayHash() []byte {
348-
if tx.cachedTxID != nil {
349-
return tx.cachedTxID
350-
}
351-
352-
// SHA256d
353-
digest := sha256.Sum256(tx.rawBytes)
354-
digest = sha256.Sum256(digest[:])
355351
// Convert to big-endian
356-
tx.cachedTxID = Reverse(digest[:])
357-
return tx.cachedTxID
352+
return Reverse(tx.txID[:])
358353
}
359354

360355
// GetEncodableHash returns the transaction hash in little-endian wire format order.
361356
func (tx *Transaction) GetEncodableHash() []byte {
362-
digest := sha256.Sum256(tx.rawBytes)
363-
digest = sha256.Sum256(digest[:])
364-
return digest[:]
357+
return tx.txID
365358
}
366359

367360
// Bytes returns a full transaction's raw bytes.

parser/transaction_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package parser
55

66
import (
7-
"bytes"
87
"encoding/hex"
98
"encoding/json"
109
"os"
@@ -85,9 +84,9 @@ func TestV5TransactionParser(t *testing.T) {
8584
if len(rest) != 0 {
8685
t.Fatalf("Test did not consume entire buffer, %d remaining", len(rest))
8786
}
88-
if bytes.Equal(tx.cachedTxID, []byte(txtestdata.Txid)) {
89-
t.Fatal("txid")
90-
}
87+
// Currently, we can't check the txid because we get that from
88+
// zcashd (getblock rpc) rather than computing it ourselves.
89+
// https://github.com/zcash/lightwalletd/issues/392
9190
if tx.version != uint32(txtestdata.Version) {
9291
t.Fatal("version miscompare")
9392
}

0 commit comments

Comments
 (0)