wire: Add new DoubleSha256SH function.
This commit adds a new function which is similar to the DoubleSha256 function except it returns a ShaHash copy instead of a byte slice. It also adds a new benchmark for it. This can be a slight optimization in certain cases where the caller ultimately wants a ShaHash since it can avoid a heap allocation and additional copy to convert the result to a ShaHash (the function simply performs a type cast against the returned array which is not possible against a []byte). existing: DoubleSha256 500000 3081 ns/op 32 B/op 1 allocs/op new: DoubleSha256SH 500000 2939 ns/op 0 B/op 0 allocs/op The hashing functions for blocks and transactions have also been updated to make use of the new function since they directly return the ShaHash. The transaction change in particular is quite useful since transactions are frequently hashed and this change allows all of those hashes to avoid an additional heap allocation.
This commit is contained in:
parent
f5cdf2d6a8
commit
6211eef7ee
5 changed files with 34 additions and 21 deletions
|
@ -34,11 +34,8 @@ func HashMerkleBranches(left *wire.ShaHash, right *wire.ShaHash) *wire.ShaHash {
|
||||||
copy(sha[:wire.HashSize], left[:])
|
copy(sha[:wire.HashSize], left[:])
|
||||||
copy(sha[wire.HashSize:], right[:])
|
copy(sha[wire.HashSize:], right[:])
|
||||||
|
|
||||||
// Create a new sha hash from the double sha 256. Ignore the error
|
newSha := wire.DoubleSha256SH(sha[:])
|
||||||
// here since SetBytes can't fail here due to the fact DoubleSha256
|
return &newSha
|
||||||
// always returns a []byte of the right size regardless of input.
|
|
||||||
newSha, _ := wire.NewShaHash(wire.DoubleSha256(sha[:]))
|
|
||||||
return newSha
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildMerkleTreeStore creates a merkle tree from a slice of transactions,
|
// BuildMerkleTreeStore creates a merkle tree from a slice of transactions,
|
||||||
|
|
|
@ -394,7 +394,7 @@ func BenchmarkTxSha(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// BenchmarkDoubleSha256 performs a benchmark on how long it takes to perform a
|
// BenchmarkDoubleSha256 performs a benchmark on how long it takes to perform a
|
||||||
// double sha 256.
|
// double sha 256 returning a byte slice.
|
||||||
func BenchmarkDoubleSha256(b *testing.B) {
|
func BenchmarkDoubleSha256(b *testing.B) {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
@ -409,3 +409,20 @@ func BenchmarkDoubleSha256(b *testing.B) {
|
||||||
_ = DoubleSha256(txBytes)
|
_ = DoubleSha256(txBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BenchmarkDoubleSha256SH performs a benchmark on how long it takes to perform
|
||||||
|
// a double sha 256 returning a ShaHash.
|
||||||
|
func BenchmarkDoubleSha256SH(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := genesisCoinbaseTx.Serialize(&buf); err != nil {
|
||||||
|
b.Errorf("Serialize: unexpected error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
txBytes := buf.Bytes()
|
||||||
|
b.StartTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = DoubleSha256SH(txBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -46,21 +46,17 @@ const blockHeaderLen = 80
|
||||||
|
|
||||||
// BlockSha computes the block identifier hash for the given block header.
|
// BlockSha computes the block identifier hash for the given block header.
|
||||||
func (h *BlockHeader) BlockSha() (ShaHash, error) {
|
func (h *BlockHeader) BlockSha() (ShaHash, error) {
|
||||||
// Encode the header and run double sha256 everything prior to the
|
// Encode the header and double sha256 everything prior to the number of
|
||||||
// number of transactions. Ignore the error returns since there is no
|
// transactions. Ignore the error returns since there is no way the
|
||||||
// way the encode could fail except being out of memory which would
|
// encode could fail except being out of memory which would cause a
|
||||||
// cause a run-time panic. Also, SetBytes can't fail here due to the
|
// run-time panic.
|
||||||
// fact DoubleSha256 always returns a []byte of the right size
|
|
||||||
// regardless of input.
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
var sha ShaHash
|
|
||||||
_ = writeBlockHeader(&buf, 0, h)
|
_ = writeBlockHeader(&buf, 0, h)
|
||||||
_ = sha.SetBytes(DoubleSha256(buf.Bytes()[0:blockHeaderLen]))
|
|
||||||
|
|
||||||
// Even though this function can't currently fail, it still returns
|
// Even though this function can't currently fail, it still returns
|
||||||
// a potential error to help future proof the API should a failure
|
// a potential error to help future proof the API should a failure
|
||||||
// become possible.
|
// become possible.
|
||||||
return sha, nil
|
return DoubleSha256SH(buf.Bytes()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deserialize decodes a block header from r into the receiver using a format
|
// Deserialize decodes a block header from r into the receiver using a format
|
||||||
|
|
|
@ -526,3 +526,10 @@ func DoubleSha256(b []byte) []byte {
|
||||||
second := fastsha256.Sum256(first[:])
|
second := fastsha256.Sum256(first[:])
|
||||||
return second[:]
|
return second[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DoubleSha256SH calculates sha256(sha256(b)) and returns the resulting bytes
|
||||||
|
// as a ShaHash.
|
||||||
|
func DoubleSha256SH(b []byte) ShaHash {
|
||||||
|
first := fastsha256.Sum256(b)
|
||||||
|
return ShaHash(fastsha256.Sum256(first[:]))
|
||||||
|
}
|
||||||
|
|
|
@ -170,18 +170,14 @@ func (msg *MsgTx) TxSha() (ShaHash, error) {
|
||||||
// Encode the transaction and calculate double sha256 on the result.
|
// Encode the transaction and calculate double sha256 on the result.
|
||||||
// Ignore the error returns since the only way the encode could fail
|
// Ignore the error returns since the only way the encode could fail
|
||||||
// is being out of memory or due to nil pointers, both of which would
|
// is being out of memory or due to nil pointers, both of which would
|
||||||
// cause a run-time panic. Also, SetBytes can't fail here due to the
|
// cause a run-time panic.
|
||||||
// fact DoubleSha256 always returns a []byte of the right size
|
|
||||||
// regardless of input.
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, msg.SerializeSize()))
|
buf := bytes.NewBuffer(make([]byte, 0, msg.SerializeSize()))
|
||||||
_ = msg.Serialize(buf)
|
_ = msg.Serialize(buf)
|
||||||
var sha ShaHash
|
|
||||||
_ = sha.SetBytes(DoubleSha256(buf.Bytes()))
|
|
||||||
|
|
||||||
// Even though this function can't currently fail, it still returns
|
// Even though this function can't currently fail, it still returns
|
||||||
// a potential error to help future proof the API should a failure
|
// a potential error to help future proof the API should a failure
|
||||||
// become possible.
|
// become possible.
|
||||||
return sha, nil
|
return DoubleSha256SH(buf.Bytes()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy creates a deep copy of a transaction so that the original does not get
|
// Copy creates a deep copy of a transaction so that the original does not get
|
||||||
|
|
Loading…
Reference in a new issue