mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
fix rebase issues
This commit is contained in:
parent
72144d8ac4
commit
1c712daa14
6 changed files with 24 additions and 490 deletions
|
|
@ -2346,7 +2346,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
|||
if constructBAL {
|
||||
if verifyBALHeader && *block.Header().BlockAccessListHash != balTracer.AccessList().ToEncodingObj().Hash() {
|
||||
err := fmt.Errorf("block access list hash mismatch (reported=%x, computed=%x)", *block.Header().BlockAccessListHash, balTracer.AccessList().ToEncodingObj().Hash())
|
||||
bc.reportBlock(block, res, err)
|
||||
bc.reportBadBlock(block, res, err)
|
||||
return nil, err
|
||||
}
|
||||
// very ugly... deepcopy the block body before setting the block access
|
||||
|
|
|
|||
|
|
@ -182,10 +182,16 @@ func (s *BALStateTransition) commitAccount(addr common.Address) (*accountUpdate,
|
|||
}
|
||||
|
||||
if s.diffs[addr].Code != nil {
|
||||
op.code = &contractCode{
|
||||
crypto.Keccak256Hash(s.diffs[addr].Code),
|
||||
s.diffs[addr].Code,
|
||||
code := contractCode{
|
||||
hash: crypto.Keccak256Hash(s.diffs[addr].Code),
|
||||
blob: s.diffs[addr].Code,
|
||||
}
|
||||
if op.origin == nil {
|
||||
code.originHash = types.EmptyCodeHash
|
||||
} else {
|
||||
code.originHash = crypto.Keccak256Hash(op.origin)
|
||||
}
|
||||
op.code = &code
|
||||
}
|
||||
|
||||
if len(s.diffs[addr].StorageWrites) == 0 {
|
||||
|
|
@ -357,6 +363,10 @@ func (s *BALStateTransition) CommitWithUpdate(block uint64, deleteEmptyObjects b
|
|||
s.metrics.TotalCommitTime = time.Since(commitStart)
|
||||
return root, ret, nil
|
||||
}
|
||||
func (s *BALStateTransition) Commit(block uint64, deleteEmptyObjects bool, noStorageWiping bool) (common.Hash, error) {
|
||||
root, _, err := s.CommitWithUpdate(block, deleteEmptyObjects, noStorageWiping)
|
||||
return root, err
|
||||
}
|
||||
|
||||
func (s *BALStateTransition) loadOriginStorages() {
|
||||
lastIdx := len(s.accessList.block.Transactions()) + 1
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ func (m *mutation) isDelete() bool {
|
|||
|
||||
type BlockStateTransition interface {
|
||||
CommitWithUpdate(block uint64, deleteEmptyObjects bool, noStorageWiping bool) (common.Hash, *stateUpdate, error)
|
||||
Commit(block uint64, deleteEmptyObjects bool, noStorageWiping bool) (common.Hash, error)
|
||||
IntermediateRoot(deleteEmpty bool) common.Hash
|
||||
Error() error
|
||||
Preimages() map[common.Hash][]byte
|
||||
|
|
|
|||
|
|
@ -274,6 +274,7 @@ type Hooks struct {
|
|||
OnSystemCallStart OnSystemCallStartHook
|
||||
OnSystemCallStartV2 OnSystemCallStartHookV2
|
||||
OnSystemCallEnd OnSystemCallEndHook
|
||||
OnStateUpdate StateUpdateHook
|
||||
|
||||
OnBlockFinalization func() // called after post-tx system contracts and consensus finalization are invoked
|
||||
|
||||
|
|
|
|||
|
|
@ -239,6 +239,14 @@ func (t *BinaryTrie) GetStorage(addr common.Address, key []byte) ([]byte, error)
|
|||
return t.root.Get(GetBinaryTreeKey(addr, key), t.nodeResolver)
|
||||
}
|
||||
|
||||
func (t *BinaryTrie) UpdateAccountBatch(addresses []common.Address, accounts []*types.StateAccount, _ []int) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (t *BinaryTrie) UpdateStorageBatch(_ common.Address, keys [][]byte, values [][]byte) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// UpdateAccount updates the account information for the given address.
|
||||
func (t *BinaryTrie) UpdateAccount(addr common.Address, acc *types.StateAccount, codeLen int) error {
|
||||
var (
|
||||
|
|
|
|||
486
trie/verkle.go
486
trie/verkle.go
|
|
@ -1,486 +0,0 @@
|
|||
// Copyright 2023 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package trie
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||
"github.com/ethereum/go-ethereum/trie/utils"
|
||||
"github.com/ethereum/go-ethereum/triedb/database"
|
||||
"github.com/ethereum/go-verkle"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
var (
|
||||
errInvalidRootType = errors.New("invalid node type for root")
|
||||
)
|
||||
|
||||
// VerkleTrie is a wrapper around VerkleNode that implements the trie.Trie
|
||||
// interface so that Verkle trees can be reused verbatim.
|
||||
type VerkleTrie struct {
|
||||
root verkle.VerkleNode
|
||||
cache *utils.PointCache
|
||||
reader *Reader
|
||||
tracer *PrevalueTracer
|
||||
}
|
||||
|
||||
// NewVerkleTrie constructs a verkle tree based on the specified root hash.
|
||||
func NewVerkleTrie(root common.Hash, db database.NodeDatabase, cache *utils.PointCache) (*VerkleTrie, error) {
|
||||
reader, err := NewReader(root, common.Hash{}, db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t := &VerkleTrie{
|
||||
root: verkle.New(),
|
||||
cache: cache,
|
||||
reader: reader,
|
||||
tracer: NewPrevalueTracer(),
|
||||
}
|
||||
// Parse the root verkle node if it's not empty.
|
||||
if root != types.EmptyVerkleHash && root != types.EmptyRootHash {
|
||||
blob, err := t.nodeResolver(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node, err := verkle.ParseNode(blob, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.root = node
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// GetKey returns the sha3 preimage of a hashed key that was previously used
|
||||
// to store a value.
|
||||
func (t *VerkleTrie) GetKey(key []byte) []byte {
|
||||
return key
|
||||
}
|
||||
|
||||
// GetAccount implements state.Trie, retrieving the account with the specified
|
||||
// account address. If the specified account is not in the verkle tree, nil will
|
||||
// be returned. If the tree is corrupted, an error will be returned.
|
||||
func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error) {
|
||||
var (
|
||||
acc = &types.StateAccount{}
|
||||
values [][]byte
|
||||
err error
|
||||
)
|
||||
switch n := t.root.(type) {
|
||||
case *verkle.InternalNode:
|
||||
values, err = n.GetValuesAtStem(t.cache.GetStem(addr[:]), t.nodeResolver)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetAccount (%x) error: %v", addr, err)
|
||||
}
|
||||
default:
|
||||
return nil, errInvalidRootType
|
||||
}
|
||||
if values == nil {
|
||||
return nil, nil
|
||||
}
|
||||
basicData := values[utils.BasicDataLeafKey]
|
||||
acc.Nonce = binary.BigEndian.Uint64(basicData[utils.BasicDataNonceOffset:])
|
||||
acc.Balance = new(uint256.Int).SetBytes(basicData[utils.BasicDataBalanceOffset : utils.BasicDataBalanceOffset+16])
|
||||
acc.CodeHash = values[utils.CodeHashLeafKey]
|
||||
|
||||
// TODO account.Root is leave as empty. How should we handle the legacy account?
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
// PrefetchAccount attempts to resolve specific accounts from the database
|
||||
// to accelerate subsequent trie operations.
|
||||
func (t *VerkleTrie) PrefetchAccount(addresses []common.Address) error {
|
||||
for _, addr := range addresses {
|
||||
if _, err := t.GetAccount(addr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetStorage implements state.Trie, retrieving the storage slot with the specified
|
||||
// account address and storage key. If the specified slot is not in the verkle tree,
|
||||
// nil will be returned. If the tree is corrupted, an error will be returned.
|
||||
func (t *VerkleTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) {
|
||||
k := utils.StorageSlotKeyWithEvaluatedAddress(t.cache.Get(addr.Bytes()), key)
|
||||
val, err := t.root.Get(k, t.nodeResolver)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return common.TrimLeftZeroes(val), nil
|
||||
}
|
||||
|
||||
// PrefetchStorage attempts to resolve specific storage slots from the database
|
||||
// to accelerate subsequent trie operations.
|
||||
func (t *VerkleTrie) PrefetchStorage(addr common.Address, keys [][]byte) error {
|
||||
for _, key := range keys {
|
||||
if _, err := t.GetStorage(addr, key); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateAccount implements state.Trie, writing the provided account into the tree.
|
||||
// If the tree is corrupted, an error will be returned.
|
||||
func (t *VerkleTrie) UpdateAccount(addr common.Address, acc *types.StateAccount, codeLen int) error {
|
||||
var (
|
||||
err error
|
||||
basicData [32]byte
|
||||
values = make([][]byte, verkle.NodeWidth)
|
||||
stem = t.cache.GetStem(addr[:])
|
||||
)
|
||||
|
||||
// Code size is encoded in BasicData as a 3-byte big-endian integer. Spare bytes are present
|
||||
// before the code size to support bigger integers in the future. PutUint32(...) requires
|
||||
// 4 bytes, so we need to shift the offset 1 byte to the left.
|
||||
binary.BigEndian.PutUint32(basicData[utils.BasicDataCodeSizeOffset-1:], uint32(codeLen))
|
||||
binary.BigEndian.PutUint64(basicData[utils.BasicDataNonceOffset:], acc.Nonce)
|
||||
if acc.Balance.ByteLen() > 16 {
|
||||
panic("balance too large")
|
||||
}
|
||||
acc.Balance.WriteToSlice(basicData[utils.BasicDataBalanceOffset : utils.BasicDataBalanceOffset+16])
|
||||
values[utils.BasicDataLeafKey] = basicData[:]
|
||||
values[utils.CodeHashLeafKey] = acc.CodeHash[:]
|
||||
|
||||
switch root := t.root.(type) {
|
||||
case *verkle.InternalNode:
|
||||
err = root.InsertValuesAtStem(stem, values, t.nodeResolver)
|
||||
default:
|
||||
return errInvalidRootType
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("UpdateAccount (%x) error: %v", addr, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateAccountBatch attempts to update a list accounts in the batch manner.
|
||||
func (t *VerkleTrie) UpdateAccountBatch(addresses []common.Address, accounts []*types.StateAccount, codeLens []int) error {
|
||||
if len(addresses) != len(accounts) {
|
||||
return fmt.Errorf("address and accounts length mismatch: %d != %d", len(addresses), len(accounts))
|
||||
}
|
||||
if len(addresses) != len(codeLens) {
|
||||
return fmt.Errorf("address and code length mismatch: %d != %d", len(addresses), len(codeLens))
|
||||
}
|
||||
for i, addr := range addresses {
|
||||
if err := t.UpdateAccount(addr, accounts[i], codeLens[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateStorage implements state.Trie, writing the provided storage slot into
|
||||
// the tree. If the tree is corrupted, an error will be returned.
|
||||
func (t *VerkleTrie) UpdateStorage(address common.Address, key, value []byte) error {
|
||||
// Left padding the slot value to 32 bytes.
|
||||
var v [32]byte
|
||||
if len(value) >= 32 {
|
||||
copy(v[:], value[:32])
|
||||
} else {
|
||||
copy(v[32-len(value):], value[:])
|
||||
}
|
||||
k := utils.StorageSlotKeyWithEvaluatedAddress(t.cache.Get(address.Bytes()), key)
|
||||
return t.root.Insert(k, v[:], t.nodeResolver)
|
||||
}
|
||||
|
||||
// UpdateStorageBatch attempts to update a list storages in the batch manner.
|
||||
func (t *VerkleTrie) UpdateStorageBatch(address common.Address, keys [][]byte, values [][]byte) error {
|
||||
if len(keys) != len(values) {
|
||||
return fmt.Errorf("keys and values length mismatch: %d != %d", len(keys), len(values))
|
||||
}
|
||||
for i, key := range keys {
|
||||
if err := t.UpdateStorage(address, key, values[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteAccount leaves the account untouched, as no account deletion can happen
|
||||
// in verkle.
|
||||
// There is a special corner case, in which an account that is prefunded, CREATE2-d
|
||||
// and then SELFDESTRUCT-d should see its funds drained. EIP161 says that account
|
||||
// should be removed, but this is verboten by the verkle spec. This contains a
|
||||
// workaround in which the method checks for this corner case, and if so, overwrites
|
||||
// the balance with 0. This will be removed once the spec has been clarified.
|
||||
func (t *VerkleTrie) DeleteAccount(addr common.Address) error {
|
||||
k := utils.BasicDataKeyWithEvaluatedAddress(t.cache.Get(addr.Bytes()))
|
||||
values, err := t.root.(*verkle.InternalNode).GetValuesAtStem(k, t.nodeResolver)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting data at %x in delete: %w", k, err)
|
||||
}
|
||||
var prefunded bool
|
||||
for i, v := range values {
|
||||
switch i {
|
||||
case 0:
|
||||
prefunded = len(v) == 32
|
||||
case 1:
|
||||
prefunded = len(v) == 32 && bytes.Equal(v, types.EmptyCodeHash[:])
|
||||
default:
|
||||
prefunded = v == nil
|
||||
}
|
||||
if !prefunded {
|
||||
break
|
||||
}
|
||||
}
|
||||
if prefunded {
|
||||
t.root.Insert(k, common.Hash{}.Bytes(), t.nodeResolver)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RollBackAccount removes the account info + code from the tree, unlike DeleteAccount
|
||||
// that will overwrite it with 0s. The first 64 storage slots are also removed.
|
||||
func (t *VerkleTrie) RollBackAccount(addr common.Address) error {
|
||||
var (
|
||||
evaluatedAddr = t.cache.Get(addr.Bytes())
|
||||
basicDataKey = utils.BasicDataKeyWithEvaluatedAddress(evaluatedAddr)
|
||||
)
|
||||
basicDataBytes, err := t.root.Get(basicDataKey, t.nodeResolver)
|
||||
if err != nil {
|
||||
return fmt.Errorf("rollback: error finding code size: %w", err)
|
||||
}
|
||||
if len(basicDataBytes) == 0 {
|
||||
return errors.New("rollback: basic data is not existent")
|
||||
}
|
||||
// The code size is encoded in BasicData as a 3-byte big-endian integer. Spare bytes are present
|
||||
// before the code size to support bigger integers in the future.
|
||||
// LittleEndian.Uint32(...) expects 4-bytes, so we need to shift the offset 1-byte to the left.
|
||||
codeSize := binary.BigEndian.Uint32(basicDataBytes[utils.BasicDataCodeSizeOffset-1:])
|
||||
|
||||
// Delete the account header + first 64 slots + first 128 code chunks
|
||||
_, err = t.root.(*verkle.InternalNode).DeleteAtStem(basicDataKey[:31], t.nodeResolver)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error rolling back account header: %w", err)
|
||||
}
|
||||
|
||||
// Delete all further code
|
||||
for i, chunknr := uint64(31*128), uint64(128); i < uint64(codeSize); i, chunknr = i+31*256, chunknr+256 {
|
||||
// evaluate group key at the start of a new group
|
||||
offset := uint256.NewInt(chunknr)
|
||||
key := utils.CodeChunkKeyWithEvaluatedAddress(evaluatedAddr, offset)
|
||||
|
||||
if _, err = t.root.(*verkle.InternalNode).DeleteAtStem(key[:], t.nodeResolver); err != nil {
|
||||
return fmt.Errorf("error deleting code chunk stem (addr=%x, offset=%d) error: %w", addr[:], offset, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteStorage implements state.Trie, deleting the specified storage slot from
|
||||
// the trie. If the storage slot was not existent in the trie, no error will be
|
||||
// returned. If the trie is corrupted, an error will be returned.
|
||||
func (t *VerkleTrie) DeleteStorage(addr common.Address, key []byte) error {
|
||||
var zero [32]byte
|
||||
k := utils.StorageSlotKeyWithEvaluatedAddress(t.cache.Get(addr.Bytes()), key)
|
||||
return t.root.Insert(k, zero[:], t.nodeResolver)
|
||||
}
|
||||
|
||||
// Hash returns the root hash of the tree. It does not write to the database and
|
||||
// can be used even if the tree doesn't have one.
|
||||
func (t *VerkleTrie) Hash() common.Hash {
|
||||
return t.root.Commit().Bytes()
|
||||
}
|
||||
|
||||
// Commit writes all nodes to the tree's memory database.
|
||||
func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet) {
|
||||
root := t.root.(*verkle.InternalNode)
|
||||
nodes, err := root.BatchSerialize()
|
||||
if err != nil {
|
||||
// Error return from this function indicates error in the code logic
|
||||
// of BatchSerialize, and we fail catastrophically if this is the case.
|
||||
panic(fmt.Errorf("BatchSerialize failed: %v", err))
|
||||
}
|
||||
nodeset := trienode.NewNodeSet(common.Hash{})
|
||||
for _, node := range nodes {
|
||||
// Hash parameter is not used in pathdb
|
||||
nodeset.AddNode(node.Path, trienode.NewNodeWithPrev(common.Hash{}, node.SerializedBytes, t.tracer.Get(node.Path)))
|
||||
}
|
||||
// Serialize root commitment form
|
||||
return t.Hash(), nodeset
|
||||
}
|
||||
|
||||
// NodeIterator implements state.Trie, returning an iterator that returns
|
||||
// nodes of the trie. Iteration starts at the key after the given start key.
|
||||
//
|
||||
// TODO(gballet, rjl493456442) implement it.
|
||||
func (t *VerkleTrie) NodeIterator(startKey []byte) (NodeIterator, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Prove implements state.Trie, constructing a Merkle proof for key. The result
|
||||
// contains all encoded nodes on the path to the value at key. The value itself
|
||||
// is also included in the last node and can be retrieved by verifying the proof.
|
||||
//
|
||||
// If the trie does not contain a value for key, the returned proof contains all
|
||||
// nodes of the longest existing prefix of the key (at least the root), ending
|
||||
// with the node that proves the absence of the key.
|
||||
//
|
||||
// TODO(gballet, rjl493456442) implement it.
|
||||
func (t *VerkleTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Copy returns a deep-copied verkle tree.
|
||||
func (t *VerkleTrie) Copy() *VerkleTrie {
|
||||
return &VerkleTrie{
|
||||
root: t.root.Copy(),
|
||||
cache: t.cache,
|
||||
reader: t.reader,
|
||||
tracer: t.tracer.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// IsVerkle indicates if the trie is a Verkle trie.
|
||||
func (t *VerkleTrie) IsVerkle() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Proof builds and returns the verkle multiproof for keys, built against
|
||||
// the pre tree. The post tree is passed in order to add the post values
|
||||
// to that proof.
|
||||
func (t *VerkleTrie) Proof(posttrie *VerkleTrie, keys [][]byte) (*verkle.VerkleProof, verkle.StateDiff, error) {
|
||||
var postroot verkle.VerkleNode
|
||||
if posttrie != nil {
|
||||
postroot = posttrie.root
|
||||
}
|
||||
proof, _, _, _, err := verkle.MakeVerkleMultiProof(t.root, postroot, keys, t.nodeResolver)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
p, kvps, err := verkle.SerializeProof(proof)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return p, kvps, nil
|
||||
}
|
||||
|
||||
// ChunkedCode represents a sequence of 32-bytes chunks of code (31 bytes of which
|
||||
// are actual code, and 1 byte is the pushdata offset).
|
||||
type ChunkedCode []byte
|
||||
|
||||
// Copy the values here so as to avoid an import cycle
|
||||
const (
|
||||
PUSH1 = byte(0x60)
|
||||
PUSH32 = byte(0x7f)
|
||||
)
|
||||
|
||||
// ChunkifyCode generates the chunked version of an array representing EVM bytecode
|
||||
func ChunkifyCode(code []byte) ChunkedCode {
|
||||
var (
|
||||
chunkOffset = 0 // offset in the chunk
|
||||
chunkCount = len(code) / 31
|
||||
codeOffset = 0 // offset in the code
|
||||
)
|
||||
if len(code)%31 != 0 {
|
||||
chunkCount++
|
||||
}
|
||||
chunks := make([]byte, chunkCount*32)
|
||||
for i := 0; i < chunkCount; i++ {
|
||||
// number of bytes to copy, 31 unless the end of the code has been reached.
|
||||
end := 31 * (i + 1)
|
||||
if len(code) < end {
|
||||
end = len(code)
|
||||
}
|
||||
copy(chunks[i*32+1:], code[31*i:end]) // copy the code itself
|
||||
|
||||
// chunk offset = taken from the last chunk.
|
||||
if chunkOffset > 31 {
|
||||
// skip offset calculation if push data covers the whole chunk
|
||||
chunks[i*32] = 31
|
||||
chunkOffset = 1
|
||||
continue
|
||||
}
|
||||
chunks[32*i] = byte(chunkOffset)
|
||||
chunkOffset = 0
|
||||
|
||||
// Check each instruction and update the offset it should be 0 unless
|
||||
// a PUSH-N overflows.
|
||||
for ; codeOffset < end; codeOffset++ {
|
||||
if code[codeOffset] >= PUSH1 && code[codeOffset] <= PUSH32 {
|
||||
codeOffset += int(code[codeOffset] - PUSH1 + 1)
|
||||
if codeOffset+1 >= 31*(i+1) {
|
||||
codeOffset++
|
||||
chunkOffset = codeOffset - 31*(i+1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunks
|
||||
}
|
||||
|
||||
// UpdateContractCode implements state.Trie, writing the provided contract code
|
||||
// into the trie.
|
||||
// Note that the code-size *must* be already saved by a previous UpdateAccount call.
|
||||
func (t *VerkleTrie) UpdateContractCode(addr common.Address, codeHash common.Hash, code []byte) error {
|
||||
var (
|
||||
chunks = ChunkifyCode(code)
|
||||
values [][]byte
|
||||
key []byte
|
||||
err error
|
||||
)
|
||||
for i, chunknr := 0, uint64(0); i < len(chunks); i, chunknr = i+32, chunknr+1 {
|
||||
groupOffset := (chunknr + 128) % 256
|
||||
if groupOffset == 0 /* start of new group */ || chunknr == 0 /* first chunk in header group */ {
|
||||
values = make([][]byte, verkle.NodeWidth)
|
||||
key = utils.CodeChunkKeyWithEvaluatedAddress(t.cache.Get(addr.Bytes()), uint256.NewInt(chunknr))
|
||||
}
|
||||
values[groupOffset] = chunks[i : i+32]
|
||||
|
||||
if groupOffset == 255 || len(chunks)-i <= 32 {
|
||||
switch root := t.root.(type) {
|
||||
case *verkle.InternalNode:
|
||||
err = root.InsertValuesAtStem(key[:31], values, t.nodeResolver)
|
||||
if err != nil {
|
||||
return fmt.Errorf("UpdateContractCode (addr=%x) error: %w", addr[:], err)
|
||||
}
|
||||
default:
|
||||
return errInvalidRootType
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *VerkleTrie) ToDot() string {
|
||||
return verkle.ToDot(t.root)
|
||||
}
|
||||
|
||||
func (t *VerkleTrie) nodeResolver(path []byte) ([]byte, error) {
|
||||
blob, err := t.reader.Node(path, common.Hash{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.tracer.Put(path, blob)
|
||||
return blob, nil
|
||||
}
|
||||
|
||||
// Witness returns a set containing all trie nodes that have been accessed.
|
||||
func (t *VerkleTrie) Witness() map[string][]byte {
|
||||
panic("not implemented")
|
||||
}
|
||||
Loading…
Reference in a new issue