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  }