erigon-pulse/cl/merkle_tree/hasher.go

139 lines
3.7 KiB
Go
Raw Normal View History

package merkle_tree
import (
"fmt"
"sync"
libcommon "github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon/cl/utils"
"github.com/prysmaticlabs/gohashtree"
)
var globalHasher *merkleHasher
const initialBufferSize = 0 // it is whatever
// merkleHasher is used internally to provide shared buffer internally to the merkle_tree package.
type merkleHasher struct {
// internalBuffer is the shared buffer we use for each operation
internalBuffer [][32]byte
internalFlatBuffer []byte
internalBufferForSSZList [][32]byte
// mu is the lock to ensure thread safety
mu sync.Mutex
mu2 sync.Mutex // lock onto ssz list buffer
}
func newMerkleHasher() *merkleHasher {
return &merkleHasher{
internalBuffer: make([][32]byte, initialBufferSize),
internalFlatBuffer: make([]byte, initialBufferSize*32),
}
}
// merkleizeTrieLeaves returns intermediate roots of given leaves.
func (m *merkleHasher) merkleizeTrieLeaves(leaves [][32]byte) ([32]byte, error) {
m.mu.Lock()
defer m.mu.Unlock()
layer := m.getBuffer(len(leaves) / 2)
for len(leaves) > 1 {
if !utils.IsPowerOf2(uint64(len(leaves))) {
return [32]byte{}, fmt.Errorf("hash layer is a non power of 2: %d", len(leaves))
}
if err := gohashtree.Hash(layer, leaves); err != nil {
return [32]byte{}, err
}
leaves = layer[:len(leaves)/2]
}
return leaves[0], nil
}
// merkleizeTrieLeaves returns intermediate roots of given leaves.
func (m *merkleHasher) merkleizeTrieLeavesFlat(leaves []byte, out []byte) (err error) {
m.mu.Lock()
defer m.mu.Unlock()
layer := m.getBufferFromFlat(leaves)
for len(layer) > 1 {
if err := gohashtree.Hash(layer, layer); err != nil {
return err
}
layer = layer[:len(layer)/2]
}
copy(out, layer[0][:])
return
}
func (m *merkleHasher) hashByteSlice(out []byte, in []byte) error {
m.mu.Lock()
defer m.mu.Unlock()
l := m.getBufferFromFlat(in)
o := make([][32]byte, len(l)/2)
err := gohashtree.Hash(o, l)
if err != nil {
return err
}
for i := range o {
copy(out[i*32:(i+1)*32], o[i][:])
}
return nil
}
// getBuffer provides buffer of given size.
func (m *merkleHasher) getBuffer(size int) [][32]byte {
if size > len(m.internalBuffer) {
m.internalBuffer = make([][32]byte, size*2)
}
return m.internalBuffer[:size]
}
// getBuffer provides buffer of given size.
func (m *merkleHasher) getBufferForSSZList(size int) [][32]byte {
if size > len(m.internalBufferForSSZList) {
m.internalBufferForSSZList = make([][32]byte, size*2)
}
return m.internalBufferForSSZList[:size]
}
func (m *merkleHasher) getBufferFromFlat(xs []byte) [][32]byte {
buf := m.getBuffer(len(xs) / 32)
for i := 0; i < len(xs)/32; i = i + 1 {
copy(buf[i][:], xs[i*32:(i+1)*32])
}
return buf
}
// getBuffer provides buffer of given size.
func (m *merkleHasher) getFlatBuffer(size int) []byte {
if size > len(m.internalFlatBuffer) {
m.internalFlatBuffer = make([]byte, size)
}
return m.internalFlatBuffer[:size]
}
func (m *merkleHasher) transactionsListRoot(transactions [][]byte) ([32]byte, error) {
m.mu.Lock()
defer m.mu.Unlock()
txCount := uint64(len(transactions))
leaves := m.getBuffer(len(transactions))
for i, transaction := range transactions {
transactionLength := uint64(len(transaction))
packedTransactions := packBits(transaction) // Pack transactions
transactionsBaseRoot, err := MerkleizeVector(packedTransactions, 33554432)
if err != nil {
return [32]byte{}, err
}
lengthRoot := Uint64Root(transactionLength)
leaves[i] = utils.Keccak256(transactionsBaseRoot[:], lengthRoot[:])
}
transactionsBaseRoot, err := MerkleizeVector(leaves, 1048576)
if err != nil {
return libcommon.Hash{}, err
}
countRoot := Uint64Root(txCount)
return utils.Keccak256(transactionsBaseRoot[:], countRoot[:]), nil
}