// Copyright 2014 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package types import ( "bytes" "sync" "math" "fmt" "github.com/openrelayxyz/plugeth-utils/core" "github.com/openrelayxyz/plugeth-utils/restricted/crypto" "github.com/openrelayxyz/plugeth-utils/restricted/rlp" "golang.org/x/crypto/sha3" ) // hasherPool holds LegacyKeccak256 hashers for rlpHash. var hasherPool = sync.Pool{ New: func() interface{} { return sha3.NewLegacyKeccak256() }, } // deriveBufferPool holds temporary encoder buffers for DeriveSha and TX encoding. var encodeBufferPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, } // rlpHash encodes x and hashes the encoded bytes. func rlpHash(x interface{}) (h core.Hash) { sha := hasherPool.Get().(crypto.KeccakState) defer hasherPool.Put(sha) sha.Reset() rlp.Encode(sha, x) sha.Read(h[:]) return h } // prefixedRlpHash writes the prefix into the hasher before rlp-encoding x. // It's used for typed transactions. func prefixedRlpHash(prefix byte, x interface{}) (h core.Hash) { sha := hasherPool.Get().(crypto.KeccakState) defer hasherPool.Put(sha) sha.Reset() sha.Write([]byte{prefix}) rlp.Encode(sha, x) sha.Read(h[:]) return h } // TrieHasher is the tool used to calculate the hash of derivable list. // This is internal, do not use. type TrieHasher interface { Reset() Update([]byte, []byte) error Hash() core.Hash } // DerivableList is the input to DeriveSha. // It is implemented by the 'Transactions' and 'Receipts' types. // This is internal, do not use these methods. type DerivableList interface { Len() int EncodeIndex(int, *bytes.Buffer) } func encodeForDerive(list DerivableList, i int, buf *bytes.Buffer) []byte { buf.Reset() list.EncodeIndex(i, buf) // It's really unfortunate that we need to do perform this copy. // StackTrie holds onto the values until Hash is called, so the values // written to it must not alias. return core.CopyBytes(buf.Bytes()) } // DeriveSha creates the tree hashes of transactions and receipts in a block header. func DeriveSha(list DerivableList, hasher TrieHasher) core.Hash { hasher.Reset() valueBuf := encodeBufferPool.Get().(*bytes.Buffer) defer encodeBufferPool.Put(valueBuf) // StackTrie requires values to be inserted in increasing hash order, which is not the // order that `list` provides hashes in. This insertion sequence ensures that the // order is correct. var indexBuf []byte for i := 1; i < list.Len() && i <= 0x7f; i++ { indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i)) value := encodeForDerive(list, i, valueBuf) hasher.Update(indexBuf, value) } if list.Len() > 0 { indexBuf = rlp.AppendUint64(indexBuf[:0], 0) value := encodeForDerive(list, 0, valueBuf) hasher.Update(indexBuf, value) } for i := 0x80; i < list.Len(); i++ { indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i)) value := encodeForDerive(list, i, valueBuf) hasher.Update(indexBuf, value) } return hasher.Hash() } func getPooledBuffer(size uint64) ([]byte, *bytes.Buffer, error) { if size > math.MaxInt { return nil, nil, fmt.Errorf("can't get buffer of size %d", size) } buf := encodeBufferPool.Get().(*bytes.Buffer) buf.Reset() buf.Grow(int(size)) b := buf.Bytes()[:int(size)] return b, buf, nil }