erigon-pulse/commitment/commitment.go
Artem Tsebrovskiy abd93fe9c9
implement bin_patricia_hashed trie (#430)
* commitment: implemented semi-working bin patricia trie

* commitment: added initialize function to select commitment implementation

* deleted reference implementation of binary trie

* added branch merge function selection in accordance with current commitment type

* smarter branch prefix convolution to reduce disk usage

* implemented DELETE update

* commitment/bin-trie: fixed merge processing and storage encoding

* added changed hex to bin patricia trie

* fixed trie variant select

* allocate if bufPos larger than buf size

* added tracing code

* Fix lint

* Skip test

Co-authored-by: Alexey Sharp <alexeysharp@Alexeys-iMac.local>
2022-05-05 13:08:58 +01:00

127 lines
2.9 KiB
Go

package commitment
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/holiman/uint256"
"github.com/ledgerwatch/erigon-lib/common/length"
)
// Trie represents commitment variant.
type Trie interface {
ProcessUpdates(plainKeys, hashedKeys [][]byte, updates []Update) (branchNodeUpdates map[string][]byte, err error)
// RootHash produces root hash of the trie
RootHash() (hash []byte, err error)
// Variant returns commitment trie variant
Variant() TrieVariant
// Reset Drops everything from the trie
Reset()
ResetFns(
branchFn func(prefix []byte) ([]byte, error),
accountFn func(plainKey []byte, cell *Cell) error,
storageFn func(plainKey []byte, cell *Cell) error,
)
// Makes trie more verbose
SetTrace(bool)
}
type TrieVariant string
const (
// HexPatriciaHashed used as default commitment approach
VariantHexPatriciaTrie TrieVariant = "hex-patricia-hashed"
VariantReducedHexPatriciaTrie TrieVariant = "modified-hex-patricia-hashed"
// Experimental mode with binary key representation
VariantBinPatriciaTrie TrieVariant = "bin-patricia-hashed"
)
func InitializeTrie(tv TrieVariant) Trie {
switch tv {
case VariantBinPatriciaTrie:
return NewBinaryPatriciaTrie()
case VariantReducedHexPatriciaTrie:
return NewBinHashed(length.Addr, nil, nil, nil)
case VariantHexPatriciaTrie:
fallthrough
default:
return NewHexPatriciaHashed(length.Addr, nil, nil, nil)
}
}
type Account struct {
CodeHash []byte // hash of the bytecode
Nonce uint64
Balance uint256.Int
}
func (a *Account) String() string {
return fmt.Sprintf("Account{Nonce: %d, Balance: %s, CodeHash: %x}", a.Nonce, a.Balance.String(), a.CodeHash)
}
func (a *Account) decode(buffer []byte) *Account {
var pos int
if buffer[pos] < 128 {
a.Nonce = uint64(buffer[pos])
pos++
} else {
var nonce uint64
sizeBytes := int(buffer[pos] - 128)
pos++
nonce, n := binary.Uvarint(buffer[pos : pos+sizeBytes])
a.Nonce = nonce
pos += n
}
if buffer[pos] < 128 {
b := uint256.NewInt(uint64(buffer[pos]))
a.Balance = *b
pos++
} else {
bc := int(buffer[pos] - 128)
pos++
a.Balance.SetBytes(buffer[pos : pos+bc])
pos += bc
}
codeSize := int(buffer[pos] - 128)
if codeSize > 0 {
pos++
a.CodeHash = make([]byte, codeSize)
copy(a.CodeHash, buffer[pos:pos+codeSize])
}
return a
}
func (a *Account) encode(bb []byte) []byte {
buffer := bytes.NewBuffer(bb)
// Encoding nonce
if a.Nonce < 128 && a.Nonce != 0 {
buffer.WriteByte(byte(a.Nonce))
} else {
aux := [binary.MaxVarintLen64]byte{}
n := binary.PutUvarint(aux[:], a.Nonce)
buffer.WriteByte(byte(128 + n))
buffer.Write(aux[:n])
}
// Encoding balance
if a.Balance.LtUint64(128) && !a.Balance.IsZero() {
buffer.WriteByte(byte(a.Balance.Uint64()))
} else {
buffer.WriteByte(byte(128 + a.Balance.ByteLen()))
buffer.Write(a.Balance.Bytes())
}
buffer.WriteByte(byte(128 + len(a.CodeHash)))
buffer.Write(a.CodeHash)
return buffer.Bytes()
}