From 6ca0ac7b3b6bf69ae6a3c30cd426a6ec8bf91b96 Mon Sep 17 00:00:00 2001 From: lukechampine Date: Wed, 11 Oct 2023 13:28:21 -0400 Subject: [PATCH] types: Normalize proof in (V2Transaction).ID --- consensus/state.go | 4 ++-- types/hash.go | 11 ++++++----- types/multiproof_test.go | 3 --- types/types.go | 15 ++++++--------- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/consensus/state.go b/consensus/state.go index 8ad8a174..62d544ee 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -507,8 +507,8 @@ func (s State) Commitment(txnsHash types.Hash256, minerAddr types.Address) types // InputSigHash returns the hash that must be signed for each v2 transaction input. func (s State) InputSigHash(txn types.V2Transaction) types.Hash256 { - // NOTE: This currently covers exactly the same fields as txn.ID(), and for - // similar reasons. + // NOTE: This currently covers exactly the same fields as txn.ID(), for the + // same reasons. h := hasherPool.Get().(*types.Hasher) defer hasherPool.Put(h) h.Reset() diff --git a/types/hash.go b/types/hash.go index 258725c2..c8b2a958 100644 --- a/types/hash.go +++ b/types/hash.go @@ -15,8 +15,9 @@ func HashBytes(b []byte) Hash256 { // A Hasher streams objects into an instance of Sia's hash function. type Hasher struct { - h hash.Hash - E *Encoder + h hash.Hash + sum Hash256 // prevent Sum from allocating + E *Encoder } // Reset resets the underlying hash and encoder state. @@ -33,15 +34,15 @@ func (h *Hasher) WriteDistinguisher(p string) { // Sum returns the digest of the objects written to the Hasher. func (h *Hasher) Sum() (sum Hash256) { _ = h.E.Flush() // no error possible - h.h.Sum(sum[:0]) - return + h.h.Sum(h.sum[:0]) + return h.sum } // NewHasher returns a new Hasher instance. func NewHasher() *Hasher { h := blake2b.New256() e := NewEncoder(h) - return &Hasher{h, e} + return &Hasher{h: h, E: e} } // Pool for reducing heap allocations when hashing. This is only necessary diff --git a/types/multiproof_test.go b/types/multiproof_test.go index 464ce426..700dff1f 100644 --- a/types/multiproof_test.go +++ b/types/multiproof_test.go @@ -113,9 +113,6 @@ func TestMultiproofEncoding(t *testing.T) { t.Fatal(err) } if !reflect.DeepEqual(b, b2) { - t.Log(b.Transactions[0].SiacoinInputs[0].Parent.MerkleProof) - t.Log(b2.Transactions[0].SiacoinInputs[0].Parent.MerkleProof) - t.FailNow() t.Fatalf("multiproof encoding of %v txns did not survive roundtrip: expected %v, got %v", n, b, b2) } } diff --git a/types/types.go b/types/types.go index 7ca8940a..029bd632 100644 --- a/types/types.go +++ b/types/types.go @@ -712,15 +712,6 @@ type V2Transaction struct { // // To hash all of the data in a transaction, use the FullHash method. func (txn *V2Transaction) ID() TransactionID { - // NOTE: In general, it is not possible to change a transaction's ID without - // causing it to become invalid, but an exception exists for non-standard - // spend policies. Consider a policy that may be satisfied by either a - // signature or a timelock. If a transaction is broadcast that signs the - // input, and the timelock has expired, then anyone may remove the signature - // from the input without invalidating the transaction. Of course, the net - // result will be the same, so arguably there's little reason to care. You - // only need to worry about this if you're hashing the full transaction data - // for some reason. h := hasherPool.Get().(*Hasher) defer hasherPool.Put(h) h.Reset() @@ -753,6 +744,12 @@ func (txn *V2Transaction) ID() TransactionID { h.E.WritePrefix(len(txn.FileContractResolutions)) for _, fcr := range txn.FileContractResolutions { fcr.Parent.ID.EncodeTo(h.E) + // normalize proof + if sp, ok := fcr.Resolution.(*V2StorageProof); ok { + c := *sp // don't modify original + c.ProofIndex.MerkleProof = nil + fcr.Resolution = &c + } fcr.Resolution.(EncoderTo).EncodeTo(h.E) } h.E.WritePrefix(len(txn.Attestations))