github.com/ethw3/go-ethereuma@v0.0.0-20221013053120-c14602a4c23c/core/types/hashing.go (about) 1 // Copyright 2021 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package types 18 19 import ( 20 "bytes" 21 "sync" 22 23 "github.com/ethw3/go-ethereuma/common" 24 "github.com/ethw3/go-ethereuma/crypto" 25 "github.com/ethw3/go-ethereuma/rlp" 26 "golang.org/x/crypto/sha3" 27 ) 28 29 // hasherPool holds LegacyKeccak256 hashers for rlpHash. 30 var hasherPool = sync.Pool{ 31 New: func() interface{} { return sha3.NewLegacyKeccak256() }, 32 } 33 34 // encodeBufferPool holds temporary encoder buffers for DeriveSha and TX encoding. 35 var encodeBufferPool = sync.Pool{ 36 New: func() interface{} { return new(bytes.Buffer) }, 37 } 38 39 // rlpHash encodes x and hashes the encoded bytes. 40 func rlpHash(x interface{}) (h common.Hash) { 41 sha := hasherPool.Get().(crypto.KeccakState) 42 defer hasherPool.Put(sha) 43 sha.Reset() 44 rlp.Encode(sha, x) 45 sha.Read(h[:]) 46 return h 47 } 48 49 // prefixedRlpHash writes the prefix into the hasher before rlp-encoding x. 50 // It's used for typed transactions. 51 func prefixedRlpHash(prefix byte, x interface{}) (h common.Hash) { 52 sha := hasherPool.Get().(crypto.KeccakState) 53 defer hasherPool.Put(sha) 54 sha.Reset() 55 sha.Write([]byte{prefix}) 56 rlp.Encode(sha, x) 57 sha.Read(h[:]) 58 return h 59 } 60 61 // TrieHasher is the tool used to calculate the hash of derivable list. 62 // This is internal, do not use. 63 type TrieHasher interface { 64 Reset() 65 Update([]byte, []byte) 66 Hash() common.Hash 67 } 68 69 // DerivableList is the input to DeriveSha. 70 // It is implemented by the 'Transactions' and 'Receipts' types. 71 // This is internal, do not use these methods. 72 type DerivableList interface { 73 Len() int 74 EncodeIndex(int, *bytes.Buffer) 75 } 76 77 func encodeForDerive(list DerivableList, i int, buf *bytes.Buffer) []byte { 78 buf.Reset() 79 list.EncodeIndex(i, buf) 80 // It's really unfortunate that we need to do perform this copy. 81 // StackTrie holds onto the values until Hash is called, so the values 82 // written to it must not alias. 83 return common.CopyBytes(buf.Bytes()) 84 } 85 86 // DeriveSha creates the tree hashes of transactions and receipts in a block header. 87 func DeriveSha(list DerivableList, hasher TrieHasher) common.Hash { 88 hasher.Reset() 89 90 valueBuf := encodeBufferPool.Get().(*bytes.Buffer) 91 defer encodeBufferPool.Put(valueBuf) 92 93 // StackTrie requires values to be inserted in increasing hash order, which is not the 94 // order that `list` provides hashes in. This insertion sequence ensures that the 95 // order is correct. 96 var indexBuf []byte 97 for i := 1; i < list.Len() && i <= 0x7f; i++ { 98 indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i)) 99 value := encodeForDerive(list, i, valueBuf) 100 hasher.Update(indexBuf, value) 101 } 102 if list.Len() > 0 { 103 indexBuf = rlp.AppendUint64(indexBuf[:0], 0) 104 value := encodeForDerive(list, 0, valueBuf) 105 hasher.Update(indexBuf, value) 106 } 107 for i := 0x80; i < list.Len(); i++ { 108 indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i)) 109 value := encodeForDerive(list, i, valueBuf) 110 hasher.Update(indexBuf, value) 111 } 112 return hasher.Hash() 113 }