erigon-pulse/cmd/verkle/pedersen_hashstate.go
Giulio rebuffo faebec48c9
Added pedersen hash generator utility in cmd/verkle (#5258)
* added tree key functions for verkle tries

* added tree key functions for verkle tries

* added tree key functions for verkle tries

* Pedersen hash generator

* removed extra functions

* better comment

* ops

Co-authored-by: giuliorebuffo <giuliorebuffo@system76-pc.localdomain>
2022-09-02 15:45:30 +02:00

128 lines
4.1 KiB
Go

package main
import (
"encoding/binary"
"time"
"github.com/holiman/uint256"
"github.com/ledgerwatch/erigon-lib/etl"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/core/types/accounts"
"github.com/ledgerwatch/erigon/turbo/trie/vtree"
"github.com/ledgerwatch/log/v3"
)
func retrieveAccountKeys(address common.Address) (versionKey, balanceKey, codeSizeKey, codeHashKey, noncekey [32]byte) {
// Process the polynomial
versionkey := vtree.GetTreeKeyVersion(address[:])
copy(balanceKey[:], versionkey)
balanceKey[31] = vtree.BalanceLeafKey
copy(noncekey[:], versionkey)
noncekey[31] = vtree.NonceLeafKey
copy(codeSizeKey[:], versionkey)
codeSizeKey[31] = vtree.CodeSizeLeafKey
copy(codeHashKey[:], versionkey)
codeHashKey[31] = vtree.CodeKeccakLeafKey
return
}
func RegeneratePedersenHashstate(outTx kv.RwTx, readTx kv.Tx) error {
pedersenHashStateBucket := "PedersenHashState"
pedersenHashStorageBucket := "PedersenHashStorage"
start := time.Now()
log.Info("Started Generation of the Pedersen Hashed State")
if err := outTx.CreateBucket(pedersenHashStateBucket); err != nil {
return err
}
if err := outTx.CreateBucket(pedersenHashStorageBucket); err != nil {
return err
}
stateCollector := etl.NewCollector("Pedersen State", "/tmp/etl-temp", etl.NewSortableBuffer(etl.BufferOptimalSize))
defer stateCollector.Close()
storageCollector := etl.NewCollector("Pedersen Storage", "/tmp/etl-temp", etl.NewSortableBuffer(etl.BufferOptimalSize))
defer storageCollector.Close()
plainStateCursor, err := readTx.Cursor(kv.PlainState)
if err != nil {
return err
}
logInterval := time.NewTicker(30 * time.Second)
for k, v, err := plainStateCursor.First(); k != nil; k, v, err = plainStateCursor.Next() {
if err != nil {
return err
}
if len(k) == 20 {
versionKey, balanceKey, codeSizeKey, codeHashKey, nonceKey := retrieveAccountKeys(common.BytesToAddress(k))
if err := stateCollector.Collect(versionKey[:], []byte{0}); err != nil {
return err
}
// Process nonce
nonceValue := make([]byte, 8)
acc := accounts.NewAccount()
if err := acc.DecodeForStorage(v); err != nil {
return err
}
binary.LittleEndian.PutUint64(nonceValue, acc.Nonce)
if err := stateCollector.Collect(nonceKey[:], nonceValue); err != nil {
return err
}
// Process Balance
balanceBytes := acc.Balance.ToBig().Bytes()
balanceValue := make([]byte, 32)
if len(balanceBytes) > 0 {
for i := range balanceBytes {
balanceValue[len(balanceBytes)-i-1] = balanceBytes[i]
}
}
if err := stateCollector.Collect(balanceKey[:], balanceValue); err != nil {
return err
}
// Process Code Size
codeSizeValue := make([]byte, 8)
if !accounts.IsEmptyCodeHash(acc.CodeHash) {
code, err := readTx.GetOne(kv.Code, acc.CodeHash[:])
if err != nil {
return err
}
// Chunkify contract code and build keys for each chunks and insert them in the tree
chunkedCode, err := vtree.ChunkifyCode(code)
if err != nil {
return err
}
// Write code chunks
for i := 0; i < len(chunkedCode); i += 32 {
stateCollector.Collect(vtree.GetTreeKeyCodeChunk(k, uint256.NewInt(uint64(i)/32)), chunkedCode[i:i+32])
}
// Set code size
binary.LittleEndian.PutUint64(codeSizeValue, uint64(len(code)))
}
if err := stateCollector.Collect(codeSizeKey[:], codeSizeValue); err != nil {
return err
}
// Process Code Hash
if err := stateCollector.Collect(codeHashKey[:], acc.CodeHash[:]); err != nil {
return err
}
} else if len(k) == 60 {
// Process storage
storageCollector.Collect(vtree.GetTreeKeyStorageSlot(k[:20], new(uint256.Int).SetBytes(k[28:])), v)
}
select {
case <-logInterval.C:
log.Info("[Pedersen Hashing] Current progress in Collection Phase", "key", common.Bytes2Hex(k))
default:
}
}
stateCollector.Load(outTx, pedersenHashStateBucket, etl.IdentityLoadFunc, etl.TransformArgs{})
storageCollector.Load(outTx, pedersenHashStorageBucket, etl.IdentityLoadFunc, etl.TransformArgs{})
log.Info("Pedersen hashed state finished", "elapsed", time.Until(start))
return outTx.Commit()
}