This commit is contained in:
Sina Mahmoodi 2023-10-26 19:58:30 +02:00
parent 6735dde9ed
commit c0667ed1da
18 changed files with 66 additions and 183 deletions

View file

@ -304,7 +304,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
statedb.AddBalance(w.Address, amount)
}
// Commit block
root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber))
root, _, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber))
if err != nil {
return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err))
}
@ -349,7 +349,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB
}
}
// Commit and re-open to start with a clean state.
root, _ := statedb.Commit(0, false)
root, _, _ := statedb.Commit(0, false)
statedb, _ = state.New(root, sdb, nil)
return statedb
}

View file

@ -1407,7 +1407,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
log.Crit("Failed to write block into disk", "err", err)
}
// Commit all cached state changes into underlying memory database.
root, err := state.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number()))
root, _, err := state.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number()))
if err != nil {
return err
}

View file

@ -326,7 +326,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
}
// Write state changes to db
root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number))
root, _, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number))
if err != nil {
panic(fmt.Sprintf("state write error: %v", err))
}

View file

@ -139,7 +139,8 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) {
statedb.SetState(addr, key, value)
}
}
return statedb.Commit(0, false)
root, _, err := statedb.Commit(0, false)
return root, err
}
// flush is very similar with deriveHash, but the main difference is
@ -160,7 +161,7 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas
statedb.SetState(addr, key, value)
}
}
root, err := statedb.Commit(0, false)
root, _, err := statedb.Commit(0, false)
if err != nil {
return err
}

View file

@ -75,8 +75,6 @@ type Trie interface {
// a trie.MissingNodeError is returned.
GetStorage(addr common.Address, key []byte) ([]byte, error)
GetWitness() *trienode.Witness
// GetAccount abstracts an account read from the trie. It retrieves the
// account blob from the trie with provided account address and decodes it
// with associated decoding algorithm. If the specified account is not in

View file

@ -58,7 +58,7 @@ func TestDump(t *testing.T) {
// write some of them to the trie
s.state.updateStateObject(obj1)
s.state.updateStateObject(obj2)
root, _ := s.state.Commit(0, false)
root, _, _ := s.state.Commit(0, false)
// check that DumpToCollector contains the state objects that are in trie
s.state, _ = New(root, tdb, nil)
@ -114,7 +114,7 @@ func TestIterativeDump(t *testing.T) {
// write some of them to the trie
s.state.updateStateObject(obj1)
s.state.updateStateObject(obj2)
root, _ := s.state.Commit(0, false)
root, _, _ := s.state.Commit(0, false)
s.state, _ = New(root, tdb, nil)
b := &bytes.Buffer{}
@ -212,7 +212,7 @@ func TestSnapshot2(t *testing.T) {
so0.deleted = false
state.setStateObject(so0)
root, _ := state.Commit(0, false)
root, _, _ := state.Commit(0, false)
state, _ = New(root, state.db, state.snaps)
// and one with deleted == true

View file

@ -172,14 +172,6 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
return sdb, nil
}
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
// state trie concurrently while the state is mutated so that when we reach the
// commit phase, most of the needed data is already hot.
func (s *StateDB) GetWitness() *trienode.Witness {
return s.trie.GetWitness()
}
func (s *StateDB) CleanSnaps() {
s.snaps = nil
s.snap = nil
@ -1175,10 +1167,10 @@ func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.A
//
// The associated block number of the state transition is also provided
// for more chain context.
func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, error) {
func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, *trienode.Witnesses, error) {
// Short circuit in case any database failure occurred earlier.
if s.dbErr != nil {
return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr)
return common.Hash{}, nil, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr)
}
// Finalize any pending changes and merge everything into the tries
s.IntermediateRoot(deleteEmptyObjects)
@ -1196,7 +1188,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
// Handle all state deletions first
incomplete, err := s.handleDestruction(nodes)
if err != nil {
return common.Hash{}, err
return common.Hash{}, nil, err
}
// Handle all state updates afterwards
for addr := range s.stateObjectsDirty {
@ -1212,20 +1204,21 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
// Write any storage changes in the state object to its storage trie
set, witness, err := obj.commit()
if err != nil {
return common.Hash{}, err
return common.Hash{}, nil, err
}
// Merge the dirty nodes of storage trie into global set. It is possible
// that the account was destructed and then resurrected in the same block.
// In this case, the node set is shared by both accounts.
if set != nil {
if err := nodes.Merge(set); err != nil {
return common.Hash{}, err
return common.Hash{}, nil, err
}
updates, deleted := set.Size()
storageTrieNodesUpdated += updates
storageTrieNodesDeleted += deleted
}
if witness != nil {
fmt.Printf("witness owner: %x, witness len: %d\n", witness.Owner, len(witness.Nodes))
witnesses.Merge(witness)
}
}
@ -1241,12 +1234,12 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
}
root, set, witness, err := s.trie.Commit(true)
if err != nil {
return common.Hash{}, err
return common.Hash{}, nil, err
}
// Merge the dirty nodes of account trie into global set
if set != nil {
if err := nodes.Merge(set); err != nil {
return common.Hash{}, err
return common.Hash{}, nil, err
}
accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size()
}
@ -1299,7 +1292,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
start := time.Now()
set := triestate.New(s.accountsOrigin, s.storagesOrigin, incomplete)
if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil {
return common.Hash{}, err
return common.Hash{}, nil, err
}
s.originalRoot = root
if metrics.EnabledExpensive {
@ -1316,7 +1309,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
s.storagesOrigin = make(map[common.Address]map[common.Hash][]byte)
s.stateObjectsDirty = make(map[common.Address]struct{})
s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount)
return root, nil
return root, witnesses, nil
}
// Prepare handles the preparatory steps for executing a state transition with.

View file

@ -223,7 +223,7 @@ func (test *stateTest) run() bool {
} else {
state.IntermediateRoot(true) // call intermediateRoot at the transaction boundary
}
nroot, err := state.Commit(0, true) // call commit at the block boundary
nroot, _, err := state.Commit(0, true) // call commit at the block boundary
if err != nil {
panic(err)
}

View file

@ -116,7 +116,7 @@ func TestIntermediateLeaks(t *testing.T) {
}
// Commit and cross check the databases.
transRoot, err := transState.Commit(0, false)
transRoot, _, err := transState.Commit(0, false)
if err != nil {
t.Fatalf("failed to commit transition state: %v", err)
}
@ -124,7 +124,7 @@ func TestIntermediateLeaks(t *testing.T) {
t.Errorf("can not commit trie %v to persistent database", transRoot.Hex())
}
finalRoot, err := finalState.Commit(0, false)
finalRoot, _, err := finalState.Commit(0, false)
if err != nil {
t.Fatalf("failed to commit final state: %v", err)
}
@ -534,7 +534,7 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
func TestTouchDelete(t *testing.T) {
s := newStateEnv()
s.state.GetOrNewStateObject(common.Address{})
root, _ := s.state.Commit(0, false)
root, _, _ := s.state.Commit(0, false)
s.state, _ = New(root, s.state.db, s.state.snaps)
snapshot := s.state.Snapshot()
@ -622,7 +622,7 @@ func TestCopyCommitCopy(t *testing.T) {
t.Fatalf("second copy committed storage slot mismatch: have %x, want %x", val, sval)
}
// Commit state, ensure states can be loaded from disk
root, _ := state.Commit(0, false)
root, _, _ := state.Commit(0, false)
state, _ = New(root, tdb, nil)
if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42)
@ -770,7 +770,7 @@ func TestDeleteCreateRevert(t *testing.T) {
addr := common.BytesToAddress([]byte("so"))
state.SetBalance(addr, big.NewInt(1))
root, _ := state.Commit(0, false)
root, _, _ := state.Commit(0, false)
state, _ = New(root, state.db, state.snaps)
// Simulate self-destructing in one transaction, then create-reverting in another
@ -782,7 +782,7 @@ func TestDeleteCreateRevert(t *testing.T) {
state.RevertToSnapshot(id)
// Commit the entire state and make sure we don't crash and have the correct state
root, _ = state.Commit(0, true)
root, _, _ = state.Commit(0, true)
state, _ = New(root, state.db, state.snaps)
if state.getStateObject(addr) != nil {
@ -825,7 +825,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
a2 := common.BytesToAddress([]byte("another"))
state.SetBalance(a2, big.NewInt(100))
state.SetCode(a2, []byte{1, 2, 4})
root, _ = state.Commit(0, false)
root, _, _ = state.Commit(0, false)
t.Logf("root: %x", root)
// force-flush
triedb.Commit(root, false)
@ -849,7 +849,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
}
// Modify the state
state.SetBalance(addr, big.NewInt(2))
root, err := state.Commit(0, false)
root, _, err := state.Commit(0, false)
if err == nil {
t.Fatalf("expected error, got root :%x", root)
}
@ -1045,7 +1045,7 @@ func TestFlushOrderDataLoss(t *testing.T) {
state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s})
}
}
root, err := state.Commit(0, false)
root, _, err := state.Commit(0, false)
if err != nil {
t.Fatalf("failed to commit state trie: %v", err)
}
@ -1124,7 +1124,7 @@ func TestResetObject(t *testing.T) {
state.CreateAccount(addr)
state.SetBalance(addr, big.NewInt(2))
state.SetState(addr, slotB, common.BytesToHash([]byte{0x2}))
root, _ := state.Commit(0, true)
root, _, _ := state.Commit(0, true)
// Ensure the original account is wiped properly
snap := snaps.Snapshot(root)
@ -1155,7 +1155,7 @@ func TestDeleteStorage(t *testing.T) {
value := common.Hash(uint256.NewInt(uint64(10 * i)).Bytes32())
state.SetState(addr, slot, value)
}
root, _ := state.Commit(0, true)
root, _, _ := state.Commit(0, true)
// Init phase done, create two states, one with snap and one without
fastState, _ := New(root, db, snaps)
slowState, _ := New(root, db, nil)

View file

@ -78,7 +78,7 @@ func makeTestState(scheme string) (ethdb.Database, Database, *trie.Database, com
}
accounts = append(accounts, acc)
}
root, _ := state.Commit(0, false)
root, _, _ := state.Commit(0, false)
// Return the generated state
return db, sdb, nodeDb, root, accounts

View file

@ -79,7 +79,7 @@ func TestAccountRange(t *testing.T) {
m[addr] = true
}
}
root, _ := sdb.Commit(0, true)
root, _, _ := sdb.Commit(0, true)
sdb, _ = state.New(root, statedb, nil)
trie, err := statedb.OpenTrie(root)
@ -178,7 +178,7 @@ func TestStorageRangeAt(t *testing.T) {
for _, entry := range storage {
sdb.SetState(addr, *entry.Key, entry.Value)
}
root, _ := sdb.Commit(0, false)
root, _, _ := sdb.Commit(0, false)
sdb, _ = state.New(root, db, nil)
// Check a few combinations of limit and start/end.

View file

@ -150,7 +150,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
return nil, nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err)
}
// Finalize the state so any modifications are written to the trie
root, err := statedb.Commit(current.NumberU64(), eth.blockchain.Config().IsEIP158(current.Number()))
root, _, err := statedb.Commit(current.NumberU64(), eth.blockchain.Config().IsEIP158(current.Number()))
if err != nil {
return nil, nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w",
current.NumberU64(), current.Root().Hex(), err)

View file

@ -19,7 +19,6 @@ package ethapi
import (
"context"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"math/big"
@ -962,35 +961,29 @@ type RecentBlockHash struct {
}
// GetRequiredBlockState returns all state required to execute a single historical block.
func (s *BlockChainAPI) GetRequiredBlockState(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*trienode.Witness, error) {
func (s *BlockChainAPI) GetRequiredBlockState(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (map[common.Hash]*trienode.Witness, error) {
block, err := s.b.BlockByNumberOrHash(ctx, blockNrOrHash)
if block == nil || err != nil {
// When the block doesn't exist, the RPC method should return JSON null
return nil, nil
}
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
parentHash := block.ParentHash()
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHash{BlockHash: &parentHash})
if err != nil {
return nil, nil
}
state.CleanSnaps()
s.ProcessBlock(ctx, block, state, vm.Config{})
return state.GetWitness(), nil
// return s.traceBlock(ctx, block)
}
if err := s.ProcessBlock(ctx, block, state, vm.Config{}); err != nil {
return nil, err
}
_, witnesses, err := state.Commit(block.NumberU64(), true)
if err != nil {
return nil, err
}
// txTraceResult is the result of a single transaction trace.
type txTraceResult struct {
TxHash common.Hash `json:"txHash"` // transaction hash
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
Error string `json:"error,omitempty"` // Trace failure produced by the tracer
return witnesses.Witnesses(), nil
}
const (
// defaultTraceTimeout is the amount of time a single transaction can execute
// by default before being forcefully aborted.
defaultTraceTimeout = 5 * time.Second
)
// Process processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb and applying any rewards to both
// the processor (coinbase) and any included uncles.
@ -998,15 +991,11 @@ const (
// Process returns the receipts and logs accumulated during the process and
// returns the amount of gas that was used in the process. If any of the
// transactions failed to execute due to insufficient gas it will return an error.
func (s *BlockChainAPI) ProcessBlock(ctx context.Context, block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) {
func (s *BlockChainAPI) ProcessBlock(ctx context.Context, block *types.Block, statedb *state.StateDB, cfg vm.Config) error {
var (
receipts types.Receipts
usedGas = new(uint64)
header = block.Header()
blockHash = block.Hash()
blockNumber = block.Number()
allLogs []*types.Log
gp = new(core.GasPool).AddGas(block.GasLimit())
usedGas = new(uint64)
header = block.Header()
gp = new(core.GasPool).AddGas(block.GasLimit())
)
var (
context = core.NewEVMBlockContext(header, NewChainContext(ctx, s.b), nil)
@ -1020,26 +1009,19 @@ func (s *BlockChainAPI) ProcessBlock(ctx context.Context, block *types.Block, st
for i, tx := range block.Transactions() {
msg, err := core.TransactionToMessage(tx, signer, header.BaseFee)
if err != nil {
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
return fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
statedb.SetTxContext(tx.Hash(), i)
receipt, err := applyTransaction(msg, s.b.ChainConfig(), gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
err = applyTransaction(msg, gp, statedb, usedGas, vmenv)
if err != nil {
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
return fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
receipts = append(receipts, receipt)
allLogs = append(allLogs, receipt.Logs...)
}
// Fail if Shanghai not enabled and len(withdrawals) is non-zero.
withdrawals := block.Withdrawals()
if len(withdrawals) > 0 && !s.b.ChainConfig().IsShanghai(block.Number(), block.Time()) {
return nil, nil, 0, errors.New("withdrawals before shanghai")
}
return receipts, allLogs, *usedGas, nil
return nil
}
func applyTransaction(msg *core.Message, config *params.ChainConfig, gp *core.GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
func applyTransaction(msg *core.Message, gp *core.GasPool, statedb *state.StateDB, usedGas *uint64, evm *vm.EVM) error {
// Create a new context to be used in the EVM environment.
txContext := core.NewEVMTxContext(msg)
evm.Reset(txContext, statedb)
@ -1047,98 +1029,14 @@ func applyTransaction(msg *core.Message, config *params.ChainConfig, gp *core.Ga
// Apply the transaction to the current state (included in the env).
result, err := core.ApplyMessage(evm, msg, gp)
if err != nil {
return nil, err
return err
}
// Update the state with pending changes.
var root []byte
if config.IsByzantium(blockNumber) {
statedb.Finalise(true)
} else {
root = statedb.IntermediateRoot(config.IsEIP158(blockNumber)).Bytes()
}
statedb.Finalise(true)
*usedGas += result.UsedGas
_ = root
return nil, err
}
// traceBlock configures a new tracer according to the provided configuration, and
// executes all the transactions contained within. The return value will be one item
// per transaction, dependent on the requested tracer.
func (s *BlockChainAPI) traceBlock(ctx context.Context, block *types.Block) ([]*txTraceResult, error) {
if block.NumberU64() == 0 {
return nil, errors.New("genesis is not traceable")
}
// Prepare base state
statedb, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.BlockNumber(block.NumberU64()-1))
if err != nil {
return nil, err
}
// Native tracers have low overhead
var (
txs = block.Transactions()
is158 = s.b.ChainConfig().IsEIP158(block.Number())
blockCtx = core.NewEVMBlockContext(block.Header(), NewChainContext(ctx, s.b), nil)
signer = types.MakeSigner(s.b.ChainConfig(), block.Number(), block.Time())
results = make([]*txTraceResult, len(txs))
)
for i, tx := range txs {
// Generate the next state snapshot fast without tracing
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
res, err := s.traceTx(ctx, msg, blockCtx, statedb)
if err != nil {
return nil, err
}
results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res}
// Finalize the state so any modifications are written to the trie
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
statedb.Finalise(is158)
}
return results, nil
}
// Tracer interface extends vm.EVMLogger and additionally
// allows collecting the tracing result.
type Tracer interface {
vm.EVMLogger
GetResult() (json.RawMessage, error)
// Stop terminates execution of the tracer at the first opportune moment.
Stop(err error)
}
// traceTx configures a new tracer according to the provided configuration, and
// executes the given message in the provided environment. The return value will
// be tracer dependent.
func (s *BlockChainAPI) traceTx(ctx context.Context, message *core.Message, vmctx vm.BlockContext, statedb *state.StateDB) (interface{}, error) {
var (
tracer Tracer
err error
timeout = defaultTraceTimeout
txContext = core.NewEVMTxContext(message)
)
// Default tracer is the struct logger
tracer = logger.NewStructLogger(&logger.Config{})
vmenv := vm.NewEVM(vmctx, txContext, statedb, s.b.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true})
// Define a meaningful timeout of a single transaction trace
deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
go func() {
<-deadlineCtx.Done()
if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
tracer.Stop(errors.New("execution timeout"))
// Stop evm execution. Note cancellation is not necessarily immediate.
vmenv.Cancel()
}
}()
defer cancel()
// Call Prepare to clear out the statedb access list
if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil {
return nil, fmt.Errorf("tracing failed: %w", err)
}
return tracer.GetResult()
return err
}
// OverrideAccount indicates the overriding fields of account during the execution

View file

@ -106,10 +106,6 @@ type odrTrie struct {
trie *trie.Trie
}
func (t *odrTrie) GetWitness() *trienode.Witness {
return t.trie.GetWitness()
}
func (t *odrTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
key = crypto.Keccak256(key)
var enc []byte

View file

@ -298,7 +298,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
statedb.AddBalance(block.Coinbase(), new(big.Int))
// Commit state mutations into database.
root, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number()))
root, _, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number()))
return triedb, snaps, statedb, root, err
}
@ -325,7 +325,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter boo
}
}
// Commit and re-open to start with a clean state.
root, _ := statedb.Commit(0, false)
root, _, _ := statedb.Commit(0, false)
var snaps *snapshot.Tree
if snapshotter {

View file

@ -81,10 +81,6 @@ func (t *StateTrie) MustGet(key []byte) []byte {
return t.trie.MustGet(t.hashKey(key))
}
func (t *StateTrie) GetWitness() *trienode.Witness {
return t.trie.GetWitness()
}
// GetStorage attempts to retrieve a storage slot with provided account address
// and slot key. The value bytes must not be modified by the caller.
// If the specified storage slot is not in the trie, nil will be returned.

View file

@ -688,7 +688,3 @@ func (t *Trie) Reset() {
t.witness = trienode.NewWitness(common.Hash{})
t.committed = false
}
func (t *Trie) GetWitness() *trienode.Witness {
return t.witness
}

View file

@ -101,8 +101,13 @@ func NewWitnesses() *Witnesses {
func (set *Witnesses) Merge(other *Witness) error {
_, present := set.witness[other.Owner]
if present {
return nil
//return subset.Merge(other.Owner, other.Nodes)
}
set.witness[other.Owner] = other
return nil
}
func (set *Witnesses) Witnesses() map[common.Hash]*Witness {
return set.witness
}