transaction: microoptimize Hash()

It doesn't cost much, but it's used _a lot_, so optimizing it makes sense.

name      old time/op    new time/op    delta
TxHash-8    4.89ns ± 5%    0.54ns ± 2%  -88.86%  (p=0.008 n=5+5)

name      old alloc/op   new alloc/op   delta
TxHash-8     0.00B          0.00B          ~     (all equal)

name      old allocs/op  new allocs/op  delta
TxHash-8      0.00           0.00          ~     (all equal)
This commit is contained in:
Roman Khimov 2021-12-02 14:48:35 +03:00
parent e3d8e7b613
commit ffeb3b8473
2 changed files with 21 additions and 1 deletions

View file

@ -68,6 +68,9 @@ type Transaction struct {
// Hash of the transaction (double SHA256). // Hash of the transaction (double SHA256).
hash util.Uint256 hash util.Uint256
// Whether hash is correct.
hashed bool
// Trimmed indicates this is a transaction from trimmed // Trimmed indicates this is a transaction from trimmed
// data. // data.
Trimmed bool Trimmed bool
@ -78,6 +81,7 @@ type Transaction struct {
func NewTrimmedTX(hash util.Uint256) *Transaction { func NewTrimmedTX(hash util.Uint256) *Transaction {
return &Transaction{ return &Transaction{
hash: hash, hash: hash,
hashed: true,
Trimmed: true, Trimmed: true,
} }
} }
@ -98,7 +102,7 @@ func New(script []byte, gas int64) *Transaction {
// Hash returns the hash of the transaction. // Hash returns the hash of the transaction.
func (t *Transaction) Hash() util.Uint256 { func (t *Transaction) Hash() util.Uint256 {
if t.hash.Equals(util.Uint256{}) { if !t.hashed {
if t.createHash() != nil { if t.createHash() != nil {
panic("failed to compute hash!") panic("failed to compute hash!")
} }
@ -172,6 +176,7 @@ func (t *Transaction) decodeHashableFields(br *io.BinReader, buf []byte) {
if buf != nil { if buf != nil {
end = len(buf) - br.Len() end = len(buf) - br.Len()
t.hash = hash.Sha256(buf[start:end]) t.hash = hash.Sha256(buf[start:end])
t.hashed = true
} }
} }
@ -261,6 +266,7 @@ func (t *Transaction) createHash() error {
} }
shaHash.Sum(t.hash[:0]) shaHash.Sum(t.hash[:0])
t.hashed = true
return nil return nil
} }

View file

@ -308,3 +308,17 @@ func TestTransaction_HasSigner(t *testing.T) {
require.True(t, tx.HasSigner(u1)) require.True(t, tx.HasSigner(u1))
require.False(t, tx.HasSigner(util.Uint160{})) require.False(t, tx.HasSigner(util.Uint160{}))
} }
func BenchmarkTxHash(b *testing.B) {
script := []byte{0x51}
tx := New(script, 1)
tx.NetworkFee = 123
tx.Signers = []Signer{{Account: util.Uint160{1, 2, 3}}}
tx.Scripts = []Witness{{InvocationScript: []byte{}, VerificationScript: []byte{}}}
// Prime cache.
tx.Hash()
for i := 0; i < b.N; i++ {
_ = tx.Hash()
}
}