erigon-pulse/cl/merkle_tree/hasher.go
Enrique Jose Avila Asapche 94276deaf6
Caplin: added tests (#7623)
Added CL tests to have test coverage over 60% in all files covered by
running ssh ./cl/coverage
2023-06-02 01:21:08 +02:00

100 lines
2.7 KiB
Go

package merkle_tree
import (
"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
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),
}
}
// merkleizeTrieLeaves returns intermediate roots of given leaves.
func (m *merkleHasher) merkleizeTrieLeavesFlat(leaves []byte, out []byte, limit uint64) (err error) {
m.mu.Lock()
defer m.mu.Unlock()
layer := m.getBufferFromFlat(leaves)
for i := uint8(0); i < GetDepth(limit); i++ {
layerLen := len(layer)
if layerLen%2 != 0 {
layer = append(layer, ZeroHashes[i])
}
if err := gohashtree.Hash(layer, layer); err != nil {
return err
}
layer = layer[:len(layer)/2]
}
copy(out, layer[0][:])
return
}
// 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
}
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
}