mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
resolve merge conflict
This commit is contained in:
commit
74fe8cbff9
43 changed files with 534 additions and 638 deletions
|
|
@ -42,7 +42,7 @@ func MakeTopics(query ...[]interface{}) ([][]common.Hash, error) {
|
||||||
case common.Address:
|
case common.Address:
|
||||||
copy(topic[common.HashLength-common.AddressLength:], rule[:])
|
copy(topic[common.HashLength-common.AddressLength:], rule[:])
|
||||||
case *big.Int:
|
case *big.Int:
|
||||||
copy(topic[:], math.U256Bytes(rule))
|
copy(topic[:], math.U256Bytes(new(big.Int).Set(rule)))
|
||||||
case bool:
|
case bool:
|
||||||
if rule {
|
if rule {
|
||||||
topic[common.HashLength-1] = 1
|
topic[common.HashLength-1] = 1
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,23 @@ func TestMakeTopics(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Run("does not mutate big.Int", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
want := [][]common.Hash{{common.HexToHash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")}}
|
||||||
|
|
||||||
|
in := big.NewInt(-1)
|
||||||
|
got, err := MakeTopics([]interface{}{in})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("makeTopics() error = %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Fatalf("makeTopics() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if orig := big.NewInt(-1); in.Cmp(orig) != 0 {
|
||||||
|
t.Fatalf("makeTopics() mutated an input parameter from %v to %v", orig, in)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,7 @@ func buildFlags(env build.Environment, staticLinking bool, buildTags []string) (
|
||||||
// See https://sourceware.org/binutils/docs-2.23.1/ld/Options.html#Options
|
// See https://sourceware.org/binutils/docs-2.23.1/ld/Options.html#Options
|
||||||
// regarding the options --build-id=none and --strip-all. It is needed for
|
// regarding the options --build-id=none and --strip-all. It is needed for
|
||||||
// reproducible builds; removing references to temporary files in C-land, and
|
// reproducible builds; removing references to temporary files in C-land, and
|
||||||
// making build-id reproducably absent.
|
// making build-id reproducibly absent.
|
||||||
extld := []string{"-Wl,-z,stack-size=0x800000,--build-id=none,--strip-all"}
|
extld := []string{"-Wl,-z,stack-size=0x800000,--build-id=none,--strip-all"}
|
||||||
if staticLinking {
|
if staticLinking {
|
||||||
extld = append(extld, "-static")
|
extld = append(extld, "-static")
|
||||||
|
|
|
||||||
|
|
@ -203,14 +203,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(vmContext, statedb, chainConfig, vmConfig)
|
evm := vm.NewEVM(vmContext, statedb, chainConfig, vmConfig)
|
||||||
if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil {
|
if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil {
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, evm)
|
||||||
}
|
}
|
||||||
if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) {
|
if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) {
|
||||||
var (
|
var (
|
||||||
prevNumber = pre.Env.Number - 1
|
prevNumber = pre.Env.Number - 1
|
||||||
prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)]
|
prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)]
|
||||||
)
|
)
|
||||||
core.ProcessParentBlockHash(prevHash, evm, statedb)
|
core.ProcessParentBlockHash(prevHash, evm)
|
||||||
}
|
}
|
||||||
for i := 0; txIt.Next(); i++ {
|
for i := 0; txIt.Next(); i++ {
|
||||||
tx, err := txIt.Tx()
|
tx, err := txIt.Tx()
|
||||||
|
|
@ -378,9 +378,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
requests = append(requests, depositRequests)
|
requests = append(requests, depositRequests)
|
||||||
|
|
||||||
// EIP-7002 withdrawals
|
// EIP-7002 withdrawals
|
||||||
requests = append(requests, core.ProcessWithdrawalQueue(evm, statedb))
|
requests = append(requests, core.ProcessWithdrawalQueue(evm))
|
||||||
// EIP-7251 consolidations
|
// EIP-7251 consolidations
|
||||||
requests = append(requests, core.ProcessConsolidationQueue(evm, statedb))
|
requests = append(requests, core.ProcessConsolidationQueue(evm))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit block
|
// Commit block
|
||||||
|
|
|
||||||
|
|
@ -84,19 +84,20 @@ type execStats struct {
|
||||||
|
|
||||||
func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, execStats, error) {
|
func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, execStats, error) {
|
||||||
if bench {
|
if bench {
|
||||||
|
testing.Init()
|
||||||
// Do one warm-up run
|
// Do one warm-up run
|
||||||
output, gasUsed, err := execFunc()
|
output, gasUsed, err := execFunc()
|
||||||
result := testing.Benchmark(func(b *testing.B) {
|
result := testing.Benchmark(func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
haveOutput, haveGasUsed, haveErr := execFunc()
|
haveOutput, haveGasUsed, haveErr := execFunc()
|
||||||
if !bytes.Equal(haveOutput, output) {
|
if !bytes.Equal(haveOutput, output) {
|
||||||
b.Fatalf("output differs, have\n%x\nwant%x\n", haveOutput, output)
|
panic(fmt.Sprintf("output differs\nhave %x\nwant %x\n", haveOutput, output))
|
||||||
}
|
}
|
||||||
if haveGasUsed != gasUsed {
|
if haveGasUsed != gasUsed {
|
||||||
b.Fatalf("gas differs, have %v want%v", haveGasUsed, gasUsed)
|
panic(fmt.Sprintf("gas differs, have %v want %v", haveGasUsed, gasUsed))
|
||||||
}
|
}
|
||||||
if haveErr != err {
|
if haveErr != err {
|
||||||
b.Fatalf("err differs, have %v want%v", haveErr, err)
|
panic(fmt.Sprintf("err differs, have %v want %v", haveErr, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -137,7 +138,7 @@ func runCmd(ctx *cli.Context) error {
|
||||||
var (
|
var (
|
||||||
tracer *tracing.Hooks
|
tracer *tracing.Hooks
|
||||||
debugLogger *logger.StructLogger
|
debugLogger *logger.StructLogger
|
||||||
statedb *state.StateDB
|
prestate *state.StateDB
|
||||||
chainConfig *params.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
sender = common.BytesToAddress([]byte("sender"))
|
sender = common.BytesToAddress([]byte("sender"))
|
||||||
receiver = common.BytesToAddress([]byte("receiver"))
|
receiver = common.BytesToAddress([]byte("receiver"))
|
||||||
|
|
@ -174,7 +175,7 @@ func runCmd(ctx *cli.Context) error {
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
genesis := genesisConfig.MustCommit(db, triedb)
|
genesis := genesisConfig.MustCommit(db, triedb)
|
||||||
sdb := state.NewDatabase(triedb, nil)
|
sdb := state.NewDatabase(triedb, nil)
|
||||||
statedb, _ = state.New(genesis.Root(), sdb)
|
prestate, _ = state.New(genesis.Root(), sdb)
|
||||||
chainConfig = genesisConfig.Config
|
chainConfig = genesisConfig.Config
|
||||||
|
|
||||||
if ctx.String(SenderFlag.Name) != "" {
|
if ctx.String(SenderFlag.Name) != "" {
|
||||||
|
|
@ -231,7 +232,7 @@ func runCmd(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
runtimeConfig := runtime.Config{
|
runtimeConfig := runtime.Config{
|
||||||
Origin: sender,
|
Origin: sender,
|
||||||
State: statedb,
|
State: prestate,
|
||||||
GasLimit: initialGas,
|
GasLimit: initialGas,
|
||||||
GasPrice: flags.GlobalBig(ctx, PriceFlag.Name),
|
GasPrice: flags.GlobalBig(ctx, PriceFlag.Name),
|
||||||
Value: flags.GlobalBig(ctx, ValueFlag.Name),
|
Value: flags.GlobalBig(ctx, ValueFlag.Name),
|
||||||
|
|
@ -274,14 +275,18 @@ func runCmd(ctx *cli.Context) error {
|
||||||
if ctx.Bool(CreateFlag.Name) {
|
if ctx.Bool(CreateFlag.Name) {
|
||||||
input = append(code, input...)
|
input = append(code, input...)
|
||||||
execFunc = func() ([]byte, uint64, error) {
|
execFunc = func() ([]byte, uint64, error) {
|
||||||
|
// don't mutate the state!
|
||||||
|
runtimeConfig.State = prestate.Copy()
|
||||||
output, _, gasLeft, err := runtime.Create(input, &runtimeConfig)
|
output, _, gasLeft, err := runtime.Create(input, &runtimeConfig)
|
||||||
return output, gasLeft, err
|
return output, gasLeft, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if len(code) > 0 {
|
if len(code) > 0 {
|
||||||
statedb.SetCode(receiver, code)
|
prestate.SetCode(receiver, code)
|
||||||
}
|
}
|
||||||
execFunc = func() ([]byte, uint64, error) {
|
execFunc = func() ([]byte, uint64, error) {
|
||||||
|
// don't mutate the state!
|
||||||
|
runtimeConfig.State = prestate.Copy()
|
||||||
output, gasLeft, err := runtime.Call(receiver, input, &runtimeConfig)
|
output, gasLeft, err := runtime.Call(receiver, input, &runtimeConfig)
|
||||||
return output, initialGas - gasLeft, err
|
return output, initialGas - gasLeft, err
|
||||||
}
|
}
|
||||||
|
|
@ -291,7 +296,7 @@ func runCmd(ctx *cli.Context) error {
|
||||||
output, stats, err := timedExec(bench, execFunc)
|
output, stats, err := timedExec(bench, execFunc)
|
||||||
|
|
||||||
if ctx.Bool(DumpFlag.Name) {
|
if ctx.Bool(DumpFlag.Name) {
|
||||||
root, err := statedb.Commit(genesisConfig.Number, true)
|
root, err := runtimeConfig.State.Commit(genesisConfig.Number, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to commit changes %v\n", err)
|
fmt.Printf("Failed to commit changes %v\n", err)
|
||||||
return err
|
return err
|
||||||
|
|
@ -310,7 +315,7 @@ func runCmd(ctx *cli.Context) error {
|
||||||
logger.WriteTrace(os.Stderr, debugLogger.StructLogs())
|
logger.WriteTrace(os.Stderr, debugLogger.StructLogs())
|
||||||
}
|
}
|
||||||
fmt.Fprintln(os.Stderr, "#### LOGS ####")
|
fmt.Fprintln(os.Stderr, "#### LOGS ####")
|
||||||
logger.WriteLogs(os.Stderr, statedb.Logs())
|
logger.WriteLogs(os.Stderr, runtimeConfig.State.Logs())
|
||||||
}
|
}
|
||||||
|
|
||||||
if bench || ctx.Bool(StatDumpFlag.Name) {
|
if bench || ctx.Bool(StatDumpFlag.Name) {
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,13 @@ func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLoo
|
||||||
if tx == nil {
|
if tx == nil {
|
||||||
progress, err := bc.TxIndexProgress()
|
progress, err := bc.TxIndexProgress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// No error is returned if the transaction indexing progress is unreachable
|
||||||
|
// due to unexpected internal errors. In such cases, it is impossible to
|
||||||
|
// determine whether the transaction does not exist or has simply not been
|
||||||
|
// indexed yet without a progress marker.
|
||||||
|
//
|
||||||
|
// In such scenarios, the transaction is treated as unreachable, though
|
||||||
|
// this is clearly an unintended and unexpected situation.
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
// The transaction indexing is not finished yet, returning an
|
// The transaction indexing is not finished yet, returning an
|
||||||
|
|
|
||||||
|
|
@ -98,11 +98,8 @@ func (b *BlockGen) Difficulty() *big.Int {
|
||||||
// block.
|
// block.
|
||||||
func (b *BlockGen) SetParentBeaconRoot(root common.Hash) {
|
func (b *BlockGen) SetParentBeaconRoot(root common.Hash) {
|
||||||
b.header.ParentBeaconRoot = &root
|
b.header.ParentBeaconRoot = &root
|
||||||
var (
|
blockContext := NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase)
|
||||||
blockContext = NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase)
|
ProcessBeaconBlockRoot(root, vm.NewEVM(blockContext, b.statedb, b.cm.config, vm.Config{}))
|
||||||
evm = vm.NewEVM(blockContext, b.statedb, b.cm.config, vm.Config{})
|
|
||||||
)
|
|
||||||
ProcessBeaconBlockRoot(root, evm, b.statedb)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// addTx adds a transaction to the generated block. If no coinbase has
|
// addTx adds a transaction to the generated block. If no coinbase has
|
||||||
|
|
@ -121,7 +118,7 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
|
||||||
evm = vm.NewEVM(blockContext, b.statedb, b.cm.config, vmConfig)
|
evm = vm.NewEVM(blockContext, b.statedb, b.cm.config, vmConfig)
|
||||||
)
|
)
|
||||||
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
|
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
|
||||||
receipt, err := ApplyTransaction(b.cm.config, evm, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed)
|
receipt, err := ApplyTransaction(evm, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -366,10 +363,10 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase)
|
blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase)
|
||||||
evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{})
|
evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{})
|
||||||
// EIP-7002 withdrawals
|
// EIP-7002 withdrawals
|
||||||
withdrawalRequests := ProcessWithdrawalQueue(evm, statedb)
|
withdrawalRequests := ProcessWithdrawalQueue(evm)
|
||||||
requests = append(requests, withdrawalRequests)
|
requests = append(requests, withdrawalRequests)
|
||||||
// EIP-7251 consolidations
|
// EIP-7251 consolidations
|
||||||
consolidationRequests := ProcessConsolidationQueue(evm, statedb)
|
consolidationRequests := ProcessConsolidationQueue(evm)
|
||||||
requests = append(requests, consolidationRequests)
|
requests = append(requests, consolidationRequests)
|
||||||
}
|
}
|
||||||
if requests != nil {
|
if requests != nil {
|
||||||
|
|
@ -471,7 +468,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
|
||||||
// EIP-2935
|
// EIP-2935
|
||||||
blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase)
|
blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase)
|
||||||
evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{})
|
evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{})
|
||||||
ProcessParentBlockHash(b.header.ParentHash, evm, statedb)
|
ProcessParentBlockHash(b.header.ParentHash, evm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute any user modifications to the block.
|
// Execute any user modifications to the block.
|
||||||
|
|
|
||||||
|
|
@ -50,16 +50,6 @@ type (
|
||||||
leafCallbackFn func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error)
|
leafCallbackFn func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error)
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenerateAccountTrieRoot takes an account iterator and reproduces the root hash.
|
|
||||||
func GenerateAccountTrieRoot(it AccountIterator) (common.Hash, error) {
|
|
||||||
return generateTrieRoot(nil, "", it, common.Hash{}, stackTrieGenerate, nil, newGenerateStats(), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateStorageTrieRoot takes a storage iterator and reproduces the root hash.
|
|
||||||
func GenerateStorageTrieRoot(account common.Hash, it StorageIterator) (common.Hash, error) {
|
|
||||||
return generateTrieRoot(nil, "", it, account, stackTrieGenerate, nil, newGenerateStats(), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateTrie takes the whole snapshot tree as the input, traverses all the
|
// GenerateTrie takes the whole snapshot tree as the input, traverses all the
|
||||||
// accounts as well as the corresponding storages and regenerate the whole state
|
// accounts as well as the corresponding storages and regenerate the whole state
|
||||||
// (account trie + all storage tries).
|
// (account trie + all storage tries).
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
bloomfilter "github.com/holiman/bloomfilter/v2"
|
bloomfilter "github.com/holiman/bloomfilter/v2"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -73,23 +74,14 @@ var (
|
||||||
// bloom key for an account/slot. This is randomized at init(), so that the
|
// bloom key for an account/slot. This is randomized at init(), so that the
|
||||||
// global population of nodes do not all display the exact same behaviour with
|
// global population of nodes do not all display the exact same behaviour with
|
||||||
// regards to bloom content
|
// regards to bloom content
|
||||||
bloomDestructHasherOffset = 0
|
bloomAccountHasherOffset = 0
|
||||||
bloomAccountHasherOffset = 0
|
bloomStorageHasherOffset = 0
|
||||||
bloomStorageHasherOffset = 0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Init the bloom offsets in the range [0:24] (requires 8 bytes)
|
// Init the bloom offsets in the range [0:24] (requires 8 bytes)
|
||||||
bloomDestructHasherOffset = rand.Intn(25)
|
|
||||||
bloomAccountHasherOffset = rand.Intn(25)
|
bloomAccountHasherOffset = rand.Intn(25)
|
||||||
bloomStorageHasherOffset = rand.Intn(25)
|
bloomStorageHasherOffset = rand.Intn(25)
|
||||||
|
|
||||||
// The destruct and account blooms must be different, as the storage slots
|
|
||||||
// will check for destruction too for every bloom miss. It should not collide
|
|
||||||
// with modified accounts.
|
|
||||||
for bloomAccountHasherOffset == bloomDestructHasherOffset {
|
|
||||||
bloomAccountHasherOffset = rand.Intn(25)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// diffLayer represents a collection of modifications made to a state snapshot
|
// diffLayer represents a collection of modifications made to a state snapshot
|
||||||
|
|
@ -106,29 +98,16 @@ type diffLayer struct {
|
||||||
root common.Hash // Root hash to which this snapshot diff belongs to
|
root common.Hash // Root hash to which this snapshot diff belongs to
|
||||||
stale atomic.Bool // Signals that the layer became stale (state progressed)
|
stale atomic.Bool // Signals that the layer became stale (state progressed)
|
||||||
|
|
||||||
// destructSet is a very special helper marker. If an account is marked as
|
|
||||||
// deleted, then it's recorded in this set. However it's allowed that an account
|
|
||||||
// is included here but still available in other sets(e.g. storageData). The
|
|
||||||
// reason is the diff layer includes all the changes in a *block*. It can
|
|
||||||
// happen that in the tx_1, account A is self-destructed while in the tx_2
|
|
||||||
// it's recreated. But we still need this marker to indicate the "old" A is
|
|
||||||
// deleted, all data in other set belongs to the "new" A.
|
|
||||||
destructSet map[common.Hash]struct{} // Keyed markers for deleted (and potentially) recreated accounts
|
|
||||||
accountList []common.Hash // List of account for iteration. If it exists, it's sorted, otherwise it's nil
|
|
||||||
accountData map[common.Hash][]byte // Keyed accounts for direct retrieval (nil means deleted)
|
accountData map[common.Hash][]byte // Keyed accounts for direct retrieval (nil means deleted)
|
||||||
storageList map[common.Hash][]common.Hash // List of storage slots for iterated retrievals, one per account. Any existing lists are sorted if non-nil
|
|
||||||
storageData map[common.Hash]map[common.Hash][]byte // Keyed storage slots for direct retrieval. one per account (nil means deleted)
|
storageData map[common.Hash]map[common.Hash][]byte // Keyed storage slots for direct retrieval. one per account (nil means deleted)
|
||||||
|
accountList []common.Hash // List of account for iteration. If it exists, it's sorted, otherwise it's nil
|
||||||
|
storageList map[common.Hash][]common.Hash // List of storage slots for iterated retrievals, one per account. Any existing lists are sorted if non-nil
|
||||||
|
|
||||||
diffed *bloomfilter.Filter // Bloom filter tracking all the diffed items up to the disk layer
|
diffed *bloomfilter.Filter // Bloom filter tracking all the diffed items up to the disk layer
|
||||||
|
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// destructBloomHash is used to convert a destruct event into a 64 bit mini hash.
|
|
||||||
func destructBloomHash(h common.Hash) uint64 {
|
|
||||||
return binary.BigEndian.Uint64(h[bloomDestructHasherOffset : bloomDestructHasherOffset+8])
|
|
||||||
}
|
|
||||||
|
|
||||||
// accountBloomHash is used to convert an account hash into a 64 bit mini hash.
|
// accountBloomHash is used to convert an account hash into a 64 bit mini hash.
|
||||||
func accountBloomHash(h common.Hash) uint64 {
|
func accountBloomHash(h common.Hash) uint64 {
|
||||||
return binary.BigEndian.Uint64(h[bloomAccountHasherOffset : bloomAccountHasherOffset+8])
|
return binary.BigEndian.Uint64(h[bloomAccountHasherOffset : bloomAccountHasherOffset+8])
|
||||||
|
|
@ -142,12 +121,11 @@ func storageBloomHash(h0, h1 common.Hash) uint64 {
|
||||||
|
|
||||||
// newDiffLayer creates a new diff on top of an existing snapshot, whether that's a low
|
// newDiffLayer creates a new diff on top of an existing snapshot, whether that's a low
|
||||||
// level persistent database or a hierarchical diff already.
|
// level persistent database or a hierarchical diff already.
|
||||||
func newDiffLayer(parent snapshot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer {
|
func newDiffLayer(parent snapshot, root common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer {
|
||||||
// Create the new layer with some pre-allocated data segments
|
// Create the new layer with some pre-allocated data segments
|
||||||
dl := &diffLayer{
|
dl := &diffLayer{
|
||||||
parent: parent,
|
parent: parent,
|
||||||
root: root,
|
root: root,
|
||||||
destructSet: destructs,
|
|
||||||
accountData: accounts,
|
accountData: accounts,
|
||||||
storageData: storage,
|
storageData: storage,
|
||||||
storageList: make(map[common.Hash][]common.Hash),
|
storageList: make(map[common.Hash][]common.Hash),
|
||||||
|
|
@ -161,10 +139,7 @@ func newDiffLayer(parent snapshot, root common.Hash, destructs map[common.Hash]s
|
||||||
panic("unknown parent type")
|
panic("unknown parent type")
|
||||||
}
|
}
|
||||||
// Sanity check that accounts or storage slots are never nil
|
// Sanity check that accounts or storage slots are never nil
|
||||||
for accountHash, blob := range accounts {
|
for _, blob := range accounts {
|
||||||
if blob == nil {
|
|
||||||
panic(fmt.Sprintf("account %#x nil", accountHash))
|
|
||||||
}
|
|
||||||
// Determine memory size and track the dirty writes
|
// Determine memory size and track the dirty writes
|
||||||
dl.memory += uint64(common.HashLength + len(blob))
|
dl.memory += uint64(common.HashLength + len(blob))
|
||||||
snapshotDirtyAccountWriteMeter.Mark(int64(len(blob)))
|
snapshotDirtyAccountWriteMeter.Mark(int64(len(blob)))
|
||||||
|
|
@ -179,7 +154,6 @@ func newDiffLayer(parent snapshot, root common.Hash, destructs map[common.Hash]s
|
||||||
snapshotDirtyStorageWriteMeter.Mark(int64(len(data)))
|
snapshotDirtyStorageWriteMeter.Mark(int64(len(data)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dl.memory += uint64(len(destructs) * common.HashLength)
|
|
||||||
return dl
|
return dl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,10 +178,6 @@ func (dl *diffLayer) rebloom(origin *diskLayer) {
|
||||||
} else {
|
} else {
|
||||||
dl.diffed, _ = bloomfilter.New(uint64(bloomSize), uint64(bloomFuncs))
|
dl.diffed, _ = bloomfilter.New(uint64(bloomSize), uint64(bloomFuncs))
|
||||||
}
|
}
|
||||||
// Iterate over all the accounts and storage slots and index them
|
|
||||||
for hash := range dl.destructSet {
|
|
||||||
dl.diffed.AddHash(destructBloomHash(hash))
|
|
||||||
}
|
|
||||||
for hash := range dl.accountData {
|
for hash := range dl.accountData {
|
||||||
dl.diffed.AddHash(accountBloomHash(hash))
|
dl.diffed.AddHash(accountBloomHash(hash))
|
||||||
}
|
}
|
||||||
|
|
@ -274,11 +244,8 @@ func (dl *diffLayer) AccountRLP(hash common.Hash) ([]byte, error) {
|
||||||
}
|
}
|
||||||
// Check the bloom filter first whether there's even a point in reaching into
|
// Check the bloom filter first whether there's even a point in reaching into
|
||||||
// all the maps in all the layers below
|
// all the maps in all the layers below
|
||||||
hit := dl.diffed.ContainsHash(accountBloomHash(hash))
|
|
||||||
if !hit {
|
|
||||||
hit = dl.diffed.ContainsHash(destructBloomHash(hash))
|
|
||||||
}
|
|
||||||
var origin *diskLayer
|
var origin *diskLayer
|
||||||
|
hit := dl.diffed.ContainsHash(accountBloomHash(hash))
|
||||||
if !hit {
|
if !hit {
|
||||||
origin = dl.origin // extract origin while holding the lock
|
origin = dl.origin // extract origin while holding the lock
|
||||||
}
|
}
|
||||||
|
|
@ -310,18 +277,14 @@ func (dl *diffLayer) accountRLP(hash common.Hash, depth int) ([]byte, error) {
|
||||||
if data, ok := dl.accountData[hash]; ok {
|
if data, ok := dl.accountData[hash]; ok {
|
||||||
snapshotDirtyAccountHitMeter.Mark(1)
|
snapshotDirtyAccountHitMeter.Mark(1)
|
||||||
snapshotDirtyAccountHitDepthHist.Update(int64(depth))
|
snapshotDirtyAccountHitDepthHist.Update(int64(depth))
|
||||||
snapshotDirtyAccountReadMeter.Mark(int64(len(data)))
|
if n := len(data); n > 0 {
|
||||||
|
snapshotDirtyAccountReadMeter.Mark(int64(n))
|
||||||
|
} else {
|
||||||
|
snapshotDirtyAccountInexMeter.Mark(1)
|
||||||
|
}
|
||||||
snapshotBloomAccountTrueHitMeter.Mark(1)
|
snapshotBloomAccountTrueHitMeter.Mark(1)
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
// If the account is known locally, but deleted, return it
|
|
||||||
if _, ok := dl.destructSet[hash]; ok {
|
|
||||||
snapshotDirtyAccountHitMeter.Mark(1)
|
|
||||||
snapshotDirtyAccountHitDepthHist.Update(int64(depth))
|
|
||||||
snapshotDirtyAccountInexMeter.Mark(1)
|
|
||||||
snapshotBloomAccountTrueHitMeter.Mark(1)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
// Account unknown to this diff, resolve from parent
|
// Account unknown to this diff, resolve from parent
|
||||||
if diff, ok := dl.parent.(*diffLayer); ok {
|
if diff, ok := dl.parent.(*diffLayer); ok {
|
||||||
return diff.accountRLP(hash, depth+1)
|
return diff.accountRLP(hash, depth+1)
|
||||||
|
|
@ -345,11 +308,8 @@ func (dl *diffLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro
|
||||||
dl.lock.RUnlock()
|
dl.lock.RUnlock()
|
||||||
return nil, ErrSnapshotStale
|
return nil, ErrSnapshotStale
|
||||||
}
|
}
|
||||||
hit := dl.diffed.ContainsHash(storageBloomHash(accountHash, storageHash))
|
|
||||||
if !hit {
|
|
||||||
hit = dl.diffed.ContainsHash(destructBloomHash(accountHash))
|
|
||||||
}
|
|
||||||
var origin *diskLayer
|
var origin *diskLayer
|
||||||
|
hit := dl.diffed.ContainsHash(storageBloomHash(accountHash, storageHash))
|
||||||
if !hit {
|
if !hit {
|
||||||
origin = dl.origin // extract origin while holding the lock
|
origin = dl.origin // extract origin while holding the lock
|
||||||
}
|
}
|
||||||
|
|
@ -391,14 +351,6 @@ func (dl *diffLayer) storage(accountHash, storageHash common.Hash, depth int) ([
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the account is known locally, but deleted, return an empty slot
|
|
||||||
if _, ok := dl.destructSet[accountHash]; ok {
|
|
||||||
snapshotDirtyStorageHitMeter.Mark(1)
|
|
||||||
snapshotDirtyStorageHitDepthHist.Update(int64(depth))
|
|
||||||
snapshotDirtyStorageInexMeter.Mark(1)
|
|
||||||
snapshotBloomStorageTrueHitMeter.Mark(1)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
// Storage slot unknown to this diff, resolve from parent
|
// Storage slot unknown to this diff, resolve from parent
|
||||||
if diff, ok := dl.parent.(*diffLayer); ok {
|
if diff, ok := dl.parent.(*diffLayer); ok {
|
||||||
return diff.storage(accountHash, storageHash, depth+1)
|
return diff.storage(accountHash, storageHash, depth+1)
|
||||||
|
|
@ -410,8 +362,8 @@ func (dl *diffLayer) storage(accountHash, storageHash common.Hash, depth int) ([
|
||||||
|
|
||||||
// Update creates a new layer on top of the existing snapshot diff tree with
|
// Update creates a new layer on top of the existing snapshot diff tree with
|
||||||
// the specified data items.
|
// the specified data items.
|
||||||
func (dl *diffLayer) Update(blockRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer {
|
func (dl *diffLayer) Update(blockRoot common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer {
|
||||||
return newDiffLayer(dl, blockRoot, destructs, accounts, storage)
|
return newDiffLayer(dl, blockRoot, accounts, storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// flatten pushes all data from this point downwards, flattening everything into
|
// flatten pushes all data from this point downwards, flattening everything into
|
||||||
|
|
@ -436,12 +388,6 @@ func (dl *diffLayer) flatten() snapshot {
|
||||||
if parent.stale.Swap(true) {
|
if parent.stale.Swap(true) {
|
||||||
panic("parent diff layer is stale") // we've flattened into the same parent from two children, boo
|
panic("parent diff layer is stale") // we've flattened into the same parent from two children, boo
|
||||||
}
|
}
|
||||||
// Overwrite all the updated accounts blindly, merge the sorted list
|
|
||||||
for hash := range dl.destructSet {
|
|
||||||
parent.destructSet[hash] = struct{}{}
|
|
||||||
delete(parent.accountData, hash)
|
|
||||||
delete(parent.storageData, hash)
|
|
||||||
}
|
|
||||||
for hash, data := range dl.accountData {
|
for hash, data := range dl.accountData {
|
||||||
parent.accountData[hash] = data
|
parent.accountData[hash] = data
|
||||||
}
|
}
|
||||||
|
|
@ -453,17 +399,13 @@ func (dl *diffLayer) flatten() snapshot {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Storage exists in both parent and child, merge the slots
|
// Storage exists in both parent and child, merge the slots
|
||||||
comboData := parent.storageData[accountHash]
|
maps.Copy(parent.storageData[accountHash], storage)
|
||||||
for storageHash, data := range storage {
|
|
||||||
comboData[storageHash] = data
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Return the combo parent
|
// Return the combo parent
|
||||||
return &diffLayer{
|
return &diffLayer{
|
||||||
parent: parent.parent,
|
parent: parent.parent,
|
||||||
origin: parent.origin,
|
origin: parent.origin,
|
||||||
root: dl.root,
|
root: dl.root,
|
||||||
destructSet: parent.destructSet,
|
|
||||||
accountData: parent.accountData,
|
accountData: parent.accountData,
|
||||||
storageData: parent.storageData,
|
storageData: parent.storageData,
|
||||||
storageList: make(map[common.Hash][]common.Hash),
|
storageList: make(map[common.Hash][]common.Hash),
|
||||||
|
|
@ -489,15 +431,7 @@ func (dl *diffLayer) AccountList() []common.Hash {
|
||||||
dl.lock.Lock()
|
dl.lock.Lock()
|
||||||
defer dl.lock.Unlock()
|
defer dl.lock.Unlock()
|
||||||
|
|
||||||
dl.accountList = make([]common.Hash, 0, len(dl.destructSet)+len(dl.accountData))
|
dl.accountList = maps.Keys(dl.accountData)
|
||||||
for hash := range dl.accountData {
|
|
||||||
dl.accountList = append(dl.accountList, hash)
|
|
||||||
}
|
|
||||||
for hash := range dl.destructSet {
|
|
||||||
if _, ok := dl.accountData[hash]; !ok {
|
|
||||||
dl.accountList = append(dl.accountList, hash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slices.SortFunc(dl.accountList, common.Hash.Cmp)
|
slices.SortFunc(dl.accountList, common.Hash.Cmp)
|
||||||
dl.memory += uint64(len(dl.accountList) * common.HashLength)
|
dl.memory += uint64(len(dl.accountList) * common.HashLength)
|
||||||
return dl.accountList
|
return dl.accountList
|
||||||
|
|
@ -512,18 +446,17 @@ func (dl *diffLayer) AccountList() []common.Hash {
|
||||||
// not empty but the flag is true.
|
// not empty but the flag is true.
|
||||||
//
|
//
|
||||||
// Note, the returned slice is not a copy, so do not modify it.
|
// Note, the returned slice is not a copy, so do not modify it.
|
||||||
func (dl *diffLayer) StorageList(accountHash common.Hash) ([]common.Hash, bool) {
|
func (dl *diffLayer) StorageList(accountHash common.Hash) []common.Hash {
|
||||||
dl.lock.RLock()
|
dl.lock.RLock()
|
||||||
_, destructed := dl.destructSet[accountHash]
|
|
||||||
if _, ok := dl.storageData[accountHash]; !ok {
|
if _, ok := dl.storageData[accountHash]; !ok {
|
||||||
// Account not tracked by this layer
|
// Account not tracked by this layer
|
||||||
dl.lock.RUnlock()
|
dl.lock.RUnlock()
|
||||||
return nil, destructed
|
return nil
|
||||||
}
|
}
|
||||||
// If an old list already exists, return it
|
// If an old list already exists, return it
|
||||||
if list, exist := dl.storageList[accountHash]; exist {
|
if list, exist := dl.storageList[accountHash]; exist {
|
||||||
dl.lock.RUnlock()
|
dl.lock.RUnlock()
|
||||||
return list, destructed // the cached list can't be nil
|
return list // the cached list can't be nil
|
||||||
}
|
}
|
||||||
dl.lock.RUnlock()
|
dl.lock.RUnlock()
|
||||||
|
|
||||||
|
|
@ -531,13 +464,9 @@ func (dl *diffLayer) StorageList(accountHash common.Hash) ([]common.Hash, bool)
|
||||||
dl.lock.Lock()
|
dl.lock.Lock()
|
||||||
defer dl.lock.Unlock()
|
defer dl.lock.Unlock()
|
||||||
|
|
||||||
storageMap := dl.storageData[accountHash]
|
storageList := maps.Keys(dl.storageData[accountHash])
|
||||||
storageList := make([]common.Hash, 0, len(storageMap))
|
|
||||||
for k := range storageMap {
|
|
||||||
storageList = append(storageList, k)
|
|
||||||
}
|
|
||||||
slices.SortFunc(storageList, common.Hash.Cmp)
|
slices.SortFunc(storageList, common.Hash.Cmp)
|
||||||
dl.storageList[accountHash] = storageList
|
dl.storageList[accountHash] = storageList
|
||||||
dl.memory += uint64(len(dl.storageList)*common.HashLength + common.HashLength)
|
dl.memory += uint64(len(dl.storageList)*common.HashLength + common.HashLength)
|
||||||
return storageList, destructed
|
return storageList
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,14 +28,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func copyDestructs(destructs map[common.Hash]struct{}) map[common.Hash]struct{} {
|
|
||||||
copy := make(map[common.Hash]struct{})
|
|
||||||
for hash := range destructs {
|
|
||||||
copy[hash] = struct{}{}
|
|
||||||
}
|
|
||||||
return copy
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyAccounts(accounts map[common.Hash][]byte) map[common.Hash][]byte {
|
func copyAccounts(accounts map[common.Hash][]byte) map[common.Hash][]byte {
|
||||||
copy := make(map[common.Hash][]byte)
|
copy := make(map[common.Hash][]byte)
|
||||||
for hash, blob := range accounts {
|
for hash, blob := range accounts {
|
||||||
|
|
@ -58,9 +50,8 @@ func copyStorage(storage map[common.Hash]map[common.Hash][]byte) map[common.Hash
|
||||||
// TestMergeBasics tests some simple merges
|
// TestMergeBasics tests some simple merges
|
||||||
func TestMergeBasics(t *testing.T) {
|
func TestMergeBasics(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
destructs = make(map[common.Hash]struct{})
|
accounts = make(map[common.Hash][]byte)
|
||||||
accounts = make(map[common.Hash][]byte)
|
storage = make(map[common.Hash]map[common.Hash][]byte)
|
||||||
storage = make(map[common.Hash]map[common.Hash][]byte)
|
|
||||||
)
|
)
|
||||||
// Fill up a parent
|
// Fill up a parent
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
|
|
@ -69,7 +60,7 @@ func TestMergeBasics(t *testing.T) {
|
||||||
|
|
||||||
accounts[h] = data
|
accounts[h] = data
|
||||||
if rand.Intn(4) == 0 {
|
if rand.Intn(4) == 0 {
|
||||||
destructs[h] = struct{}{}
|
accounts[h] = nil
|
||||||
}
|
}
|
||||||
if rand.Intn(2) == 0 {
|
if rand.Intn(2) == 0 {
|
||||||
accStorage := make(map[common.Hash][]byte)
|
accStorage := make(map[common.Hash][]byte)
|
||||||
|
|
@ -80,11 +71,12 @@ func TestMergeBasics(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add some (identical) layers on top
|
// Add some (identical) layers on top
|
||||||
parent := newDiffLayer(emptyLayer(), common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage))
|
parent := newDiffLayer(emptyLayer(), common.Hash{}, copyAccounts(accounts), copyStorage(storage))
|
||||||
child := newDiffLayer(parent, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage))
|
child := newDiffLayer(parent, common.Hash{}, copyAccounts(accounts), copyStorage(storage))
|
||||||
child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage))
|
child = newDiffLayer(child, common.Hash{}, copyAccounts(accounts), copyStorage(storage))
|
||||||
child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage))
|
child = newDiffLayer(child, common.Hash{}, copyAccounts(accounts), copyStorage(storage))
|
||||||
child = newDiffLayer(child, common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage))
|
child = newDiffLayer(child, common.Hash{}, copyAccounts(accounts), copyStorage(storage))
|
||||||
|
|
||||||
// And flatten
|
// And flatten
|
||||||
merged := (child.flatten()).(*diffLayer)
|
merged := (child.flatten()).(*diffLayer)
|
||||||
|
|
||||||
|
|
@ -99,18 +91,13 @@ func TestMergeBasics(t *testing.T) {
|
||||||
t.Errorf("accountList [2] wrong: have %v, want %v", have, want)
|
t.Errorf("accountList [2] wrong: have %v, want %v", have, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{ // Check account drops
|
|
||||||
if have, want := len(merged.destructSet), len(destructs); have != want {
|
|
||||||
t.Errorf("accountDrop wrong: have %v, want %v", have, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{ // Check storage lists
|
{ // Check storage lists
|
||||||
i := 0
|
i := 0
|
||||||
for aHash, sMap := range storage {
|
for aHash, sMap := range storage {
|
||||||
if have, want := len(merged.storageList), i; have != want {
|
if have, want := len(merged.storageList), i; have != want {
|
||||||
t.Errorf("[1] storageList wrong: have %v, want %v", have, want)
|
t.Errorf("[1] storageList wrong: have %v, want %v", have, want)
|
||||||
}
|
}
|
||||||
list, _ := merged.StorageList(aHash)
|
list := merged.StorageList(aHash)
|
||||||
if have, want := len(list), len(sMap); have != want {
|
if have, want := len(list), len(sMap); have != want {
|
||||||
t.Errorf("[2] StorageList() wrong: have %v, want %v", have, want)
|
t.Errorf("[2] StorageList() wrong: have %v, want %v", have, want)
|
||||||
}
|
}
|
||||||
|
|
@ -124,41 +111,32 @@ func TestMergeBasics(t *testing.T) {
|
||||||
|
|
||||||
// TestMergeDelete tests some deletion
|
// TestMergeDelete tests some deletion
|
||||||
func TestMergeDelete(t *testing.T) {
|
func TestMergeDelete(t *testing.T) {
|
||||||
var (
|
storage := make(map[common.Hash]map[common.Hash][]byte)
|
||||||
storage = make(map[common.Hash]map[common.Hash][]byte)
|
|
||||||
)
|
|
||||||
// Fill up a parent
|
// Fill up a parent
|
||||||
h1 := common.HexToHash("0x01")
|
h1 := common.HexToHash("0x01")
|
||||||
h2 := common.HexToHash("0x02")
|
h2 := common.HexToHash("0x02")
|
||||||
|
|
||||||
flipDrops := func() map[common.Hash]struct{} {
|
flip := func() map[common.Hash][]byte {
|
||||||
return map[common.Hash]struct{}{
|
|
||||||
h2: {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flipAccs := func() map[common.Hash][]byte {
|
|
||||||
return map[common.Hash][]byte{
|
return map[common.Hash][]byte{
|
||||||
h1: randomAccount(),
|
h1: randomAccount(),
|
||||||
|
h2: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flopDrops := func() map[common.Hash]struct{} {
|
flop := func() map[common.Hash][]byte {
|
||||||
return map[common.Hash]struct{}{
|
|
||||||
h1: {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flopAccs := func() map[common.Hash][]byte {
|
|
||||||
return map[common.Hash][]byte{
|
return map[common.Hash][]byte{
|
||||||
|
h1: nil,
|
||||||
h2: randomAccount(),
|
h2: randomAccount(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add some flipAccs-flopping layers on top
|
// Add some flipAccs-flopping layers on top
|
||||||
parent := newDiffLayer(emptyLayer(), common.Hash{}, flipDrops(), flipAccs(), storage)
|
parent := newDiffLayer(emptyLayer(), common.Hash{}, flip(), storage)
|
||||||
child := parent.Update(common.Hash{}, flopDrops(), flopAccs(), storage)
|
child := parent.Update(common.Hash{}, flop(), storage)
|
||||||
child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage)
|
child = child.Update(common.Hash{}, flip(), storage)
|
||||||
child = child.Update(common.Hash{}, flopDrops(), flopAccs(), storage)
|
child = child.Update(common.Hash{}, flop(), storage)
|
||||||
child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage)
|
child = child.Update(common.Hash{}, flip(), storage)
|
||||||
child = child.Update(common.Hash{}, flopDrops(), flopAccs(), storage)
|
child = child.Update(common.Hash{}, flop(), storage)
|
||||||
child = child.Update(common.Hash{}, flipDrops(), flipAccs(), storage)
|
child = child.Update(common.Hash{}, flip(), storage)
|
||||||
|
|
||||||
if data, _ := child.Account(h1); data == nil {
|
if data, _ := child.Account(h1); data == nil {
|
||||||
t.Errorf("last diff layer: expected %x account to be non-nil", h1)
|
t.Errorf("last diff layer: expected %x account to be non-nil", h1)
|
||||||
|
|
@ -166,12 +144,7 @@ func TestMergeDelete(t *testing.T) {
|
||||||
if data, _ := child.Account(h2); data != nil {
|
if data, _ := child.Account(h2); data != nil {
|
||||||
t.Errorf("last diff layer: expected %x account to be nil", h2)
|
t.Errorf("last diff layer: expected %x account to be nil", h2)
|
||||||
}
|
}
|
||||||
if _, ok := child.destructSet[h1]; ok {
|
|
||||||
t.Errorf("last diff layer: expected %x drop to be missing", h1)
|
|
||||||
}
|
|
||||||
if _, ok := child.destructSet[h2]; !ok {
|
|
||||||
t.Errorf("last diff layer: expected %x drop to be present", h1)
|
|
||||||
}
|
|
||||||
// And flatten
|
// And flatten
|
||||||
merged := (child.flatten()).(*diffLayer)
|
merged := (child.flatten()).(*diffLayer)
|
||||||
|
|
||||||
|
|
@ -181,12 +154,6 @@ func TestMergeDelete(t *testing.T) {
|
||||||
if data, _ := merged.Account(h2); data != nil {
|
if data, _ := merged.Account(h2); data != nil {
|
||||||
t.Errorf("merged layer: expected %x account to be nil", h2)
|
t.Errorf("merged layer: expected %x account to be nil", h2)
|
||||||
}
|
}
|
||||||
if _, ok := merged.destructSet[h1]; !ok { // Note, drops stay alive until persisted to disk!
|
|
||||||
t.Errorf("merged diff layer: expected %x drop to be present", h1)
|
|
||||||
}
|
|
||||||
if _, ok := merged.destructSet[h2]; !ok { // Note, drops stay alive until persisted to disk!
|
|
||||||
t.Errorf("merged diff layer: expected %x drop to be present", h1)
|
|
||||||
}
|
|
||||||
// If we add more granular metering of memory, we can enable this again,
|
// If we add more granular metering of memory, we can enable this again,
|
||||||
// but it's not implemented for now
|
// but it's not implemented for now
|
||||||
//if have, want := merged.memory, child.memory; have != want {
|
//if have, want := merged.memory, child.memory; have != want {
|
||||||
|
|
@ -206,22 +173,20 @@ func TestInsertAndMerge(t *testing.T) {
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var (
|
var (
|
||||||
destructs = make(map[common.Hash]struct{})
|
accounts = make(map[common.Hash][]byte)
|
||||||
accounts = make(map[common.Hash][]byte)
|
storage = make(map[common.Hash]map[common.Hash][]byte)
|
||||||
storage = make(map[common.Hash]map[common.Hash][]byte)
|
|
||||||
)
|
)
|
||||||
parent = newDiffLayer(emptyLayer(), common.Hash{}, destructs, accounts, storage)
|
parent = newDiffLayer(emptyLayer(), common.Hash{}, accounts, storage)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
var (
|
var (
|
||||||
destructs = make(map[common.Hash]struct{})
|
accounts = make(map[common.Hash][]byte)
|
||||||
accounts = make(map[common.Hash][]byte)
|
storage = make(map[common.Hash]map[common.Hash][]byte)
|
||||||
storage = make(map[common.Hash]map[common.Hash][]byte)
|
|
||||||
)
|
)
|
||||||
accounts[acc] = randomAccount()
|
accounts[acc] = randomAccount()
|
||||||
storage[acc] = make(map[common.Hash][]byte)
|
storage[acc] = make(map[common.Hash][]byte)
|
||||||
storage[acc][slot] = []byte{0x01}
|
storage[acc][slot] = []byte{0x01}
|
||||||
child = newDiffLayer(parent, common.Hash{}, destructs, accounts, storage)
|
child = newDiffLayer(parent, common.Hash{}, accounts, storage)
|
||||||
}
|
}
|
||||||
// And flatten
|
// And flatten
|
||||||
merged := (child.flatten()).(*diffLayer)
|
merged := (child.flatten()).(*diffLayer)
|
||||||
|
|
@ -250,14 +215,13 @@ func BenchmarkSearch(b *testing.B) {
|
||||||
// First, we set up 128 diff layers, with 1K items each
|
// First, we set up 128 diff layers, with 1K items each
|
||||||
fill := func(parent snapshot) *diffLayer {
|
fill := func(parent snapshot) *diffLayer {
|
||||||
var (
|
var (
|
||||||
destructs = make(map[common.Hash]struct{})
|
accounts = make(map[common.Hash][]byte)
|
||||||
accounts = make(map[common.Hash][]byte)
|
storage = make(map[common.Hash]map[common.Hash][]byte)
|
||||||
storage = make(map[common.Hash]map[common.Hash][]byte)
|
|
||||||
)
|
)
|
||||||
for i := 0; i < 10000; i++ {
|
for i := 0; i < 10000; i++ {
|
||||||
accounts[randomHash()] = randomAccount()
|
accounts[randomHash()] = randomAccount()
|
||||||
}
|
}
|
||||||
return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage)
|
return newDiffLayer(parent, common.Hash{}, accounts, storage)
|
||||||
}
|
}
|
||||||
var layer snapshot
|
var layer snapshot
|
||||||
layer = emptyLayer()
|
layer = emptyLayer()
|
||||||
|
|
@ -286,9 +250,8 @@ func BenchmarkSearchSlot(b *testing.B) {
|
||||||
accountRLP := randomAccount()
|
accountRLP := randomAccount()
|
||||||
fill := func(parent snapshot) *diffLayer {
|
fill := func(parent snapshot) *diffLayer {
|
||||||
var (
|
var (
|
||||||
destructs = make(map[common.Hash]struct{})
|
accounts = make(map[common.Hash][]byte)
|
||||||
accounts = make(map[common.Hash][]byte)
|
storage = make(map[common.Hash]map[common.Hash][]byte)
|
||||||
storage = make(map[common.Hash]map[common.Hash][]byte)
|
|
||||||
)
|
)
|
||||||
accounts[accountKey] = accountRLP
|
accounts[accountKey] = accountRLP
|
||||||
|
|
||||||
|
|
@ -299,7 +262,7 @@ func BenchmarkSearchSlot(b *testing.B) {
|
||||||
accStorage[randomHash()] = value
|
accStorage[randomHash()] = value
|
||||||
storage[accountKey] = accStorage
|
storage[accountKey] = accStorage
|
||||||
}
|
}
|
||||||
return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage)
|
return newDiffLayer(parent, common.Hash{}, accounts, storage)
|
||||||
}
|
}
|
||||||
var layer snapshot
|
var layer snapshot
|
||||||
layer = emptyLayer()
|
layer = emptyLayer()
|
||||||
|
|
@ -320,9 +283,8 @@ func BenchmarkSearchSlot(b *testing.B) {
|
||||||
func BenchmarkFlatten(b *testing.B) {
|
func BenchmarkFlatten(b *testing.B) {
|
||||||
fill := func(parent snapshot) *diffLayer {
|
fill := func(parent snapshot) *diffLayer {
|
||||||
var (
|
var (
|
||||||
destructs = make(map[common.Hash]struct{})
|
accounts = make(map[common.Hash][]byte)
|
||||||
accounts = make(map[common.Hash][]byte)
|
storage = make(map[common.Hash]map[common.Hash][]byte)
|
||||||
storage = make(map[common.Hash]map[common.Hash][]byte)
|
|
||||||
)
|
)
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
accountKey := randomHash()
|
accountKey := randomHash()
|
||||||
|
|
@ -336,7 +298,7 @@ func BenchmarkFlatten(b *testing.B) {
|
||||||
}
|
}
|
||||||
storage[accountKey] = accStorage
|
storage[accountKey] = accStorage
|
||||||
}
|
}
|
||||||
return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage)
|
return newDiffLayer(parent, common.Hash{}, accounts, storage)
|
||||||
}
|
}
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
|
|
@ -369,9 +331,8 @@ func BenchmarkFlatten(b *testing.B) {
|
||||||
func BenchmarkJournal(b *testing.B) {
|
func BenchmarkJournal(b *testing.B) {
|
||||||
fill := func(parent snapshot) *diffLayer {
|
fill := func(parent snapshot) *diffLayer {
|
||||||
var (
|
var (
|
||||||
destructs = make(map[common.Hash]struct{})
|
accounts = make(map[common.Hash][]byte)
|
||||||
accounts = make(map[common.Hash][]byte)
|
storage = make(map[common.Hash]map[common.Hash][]byte)
|
||||||
storage = make(map[common.Hash]map[common.Hash][]byte)
|
|
||||||
)
|
)
|
||||||
for i := 0; i < 200; i++ {
|
for i := 0; i < 200; i++ {
|
||||||
accountKey := randomHash()
|
accountKey := randomHash()
|
||||||
|
|
@ -385,7 +346,7 @@ func BenchmarkJournal(b *testing.B) {
|
||||||
}
|
}
|
||||||
storage[accountKey] = accStorage
|
storage[accountKey] = accStorage
|
||||||
}
|
}
|
||||||
return newDiffLayer(parent, common.Hash{}, destructs, accounts, storage)
|
return newDiffLayer(parent, common.Hash{}, accounts, storage)
|
||||||
}
|
}
|
||||||
layer := snapshot(emptyLayer())
|
layer := snapshot(emptyLayer())
|
||||||
for i := 1; i < 128; i++ {
|
for i := 1; i < 128; i++ {
|
||||||
|
|
|
||||||
|
|
@ -180,8 +180,8 @@ func (dl *diskLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro
|
||||||
// Update creates a new layer on top of the existing snapshot diff tree with
|
// Update creates a new layer on top of the existing snapshot diff tree with
|
||||||
// the specified data items. Note, the maps are retained by the method to avoid
|
// the specified data items. Note, the maps are retained by the method to avoid
|
||||||
// copying everything.
|
// copying everything.
|
||||||
func (dl *diskLayer) Update(blockHash common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer {
|
func (dl *diskLayer) Update(blockHash common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer {
|
||||||
return newDiffLayer(dl, blockHash, destructs, accounts, storage)
|
return newDiffLayer(dl, blockHash, accounts, storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// stopGeneration aborts the state snapshot generation if it is currently running.
|
// stopGeneration aborts the state snapshot generation if it is currently running.
|
||||||
|
|
|
||||||
|
|
@ -117,20 +117,22 @@ func TestDiskMerge(t *testing.T) {
|
||||||
base.Storage(conNukeCache, conNukeCacheSlot)
|
base.Storage(conNukeCache, conNukeCacheSlot)
|
||||||
|
|
||||||
// Modify or delete some accounts, flatten everything onto disk
|
// Modify or delete some accounts, flatten everything onto disk
|
||||||
if err := snaps.Update(diffRoot, baseRoot, map[common.Hash]struct{}{
|
if err := snaps.Update(diffRoot, baseRoot,
|
||||||
accDelNoCache: {},
|
map[common.Hash][]byte{
|
||||||
accDelCache: {},
|
accDelNoCache: nil,
|
||||||
conNukeNoCache: {},
|
accDelCache: nil,
|
||||||
conNukeCache: {},
|
conNukeNoCache: nil,
|
||||||
}, map[common.Hash][]byte{
|
conNukeCache: nil,
|
||||||
accModNoCache: reverse(accModNoCache[:]),
|
accModNoCache: reverse(accModNoCache[:]),
|
||||||
accModCache: reverse(accModCache[:]),
|
accModCache: reverse(accModCache[:]),
|
||||||
}, map[common.Hash]map[common.Hash][]byte{
|
}, map[common.Hash]map[common.Hash][]byte{
|
||||||
conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])},
|
conNukeNoCache: {conNukeNoCacheSlot: nil},
|
||||||
conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])},
|
conNukeCache: {conNukeCacheSlot: nil},
|
||||||
conDelNoCache: {conDelNoCacheSlot: nil},
|
conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])},
|
||||||
conDelCache: {conDelCacheSlot: nil},
|
conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])},
|
||||||
}); err != nil {
|
conDelNoCache: {conDelNoCacheSlot: nil},
|
||||||
|
conDelCache: {conDelCacheSlot: nil},
|
||||||
|
}); err != nil {
|
||||||
t.Fatalf("failed to update snapshot tree: %v", err)
|
t.Fatalf("failed to update snapshot tree: %v", err)
|
||||||
}
|
}
|
||||||
if err := snaps.Cap(diffRoot, 0); err != nil {
|
if err := snaps.Cap(diffRoot, 0); err != nil {
|
||||||
|
|
@ -340,20 +342,27 @@ func TestDiskPartialMerge(t *testing.T) {
|
||||||
assertStorage(conNukeCache, conNukeCacheSlot, conNukeCacheSlot[:])
|
assertStorage(conNukeCache, conNukeCacheSlot, conNukeCacheSlot[:])
|
||||||
|
|
||||||
// Modify or delete some accounts, flatten everything onto disk
|
// Modify or delete some accounts, flatten everything onto disk
|
||||||
if err := snaps.Update(diffRoot, baseRoot, map[common.Hash]struct{}{
|
if err := snaps.Update(diffRoot, baseRoot,
|
||||||
accDelNoCache: {},
|
map[common.Hash][]byte{
|
||||||
accDelCache: {},
|
accDelNoCache: nil,
|
||||||
conNukeNoCache: {},
|
accDelCache: nil,
|
||||||
conNukeCache: {},
|
conNukeNoCache: nil,
|
||||||
}, map[common.Hash][]byte{
|
conNukeCache: nil,
|
||||||
accModNoCache: reverse(accModNoCache[:]),
|
accModNoCache: reverse(accModNoCache[:]),
|
||||||
accModCache: reverse(accModCache[:]),
|
accModCache: reverse(accModCache[:]),
|
||||||
}, map[common.Hash]map[common.Hash][]byte{
|
},
|
||||||
conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])},
|
map[common.Hash]map[common.Hash][]byte{
|
||||||
conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])},
|
conNukeNoCache: {
|
||||||
conDelNoCache: {conDelNoCacheSlot: nil},
|
conNukeNoCacheSlot: nil,
|
||||||
conDelCache: {conDelCacheSlot: nil},
|
},
|
||||||
}); err != nil {
|
conNukeCache: {
|
||||||
|
conNukeCacheSlot: nil,
|
||||||
|
},
|
||||||
|
conModNoCache: {conModNoCacheSlot: reverse(conModNoCacheSlot[:])},
|
||||||
|
conModCache: {conModCacheSlot: reverse(conModCacheSlot[:])},
|
||||||
|
conDelNoCache: {conDelNoCacheSlot: nil},
|
||||||
|
conDelCache: {conDelCacheSlot: nil},
|
||||||
|
}); err != nil {
|
||||||
t.Fatalf("test %d: failed to update snapshot tree: %v", i, err)
|
t.Fatalf("test %d: failed to update snapshot tree: %v", i, err)
|
||||||
}
|
}
|
||||||
if err := snaps.Cap(diffRoot, 0); err != nil {
|
if err := snaps.Cap(diffRoot, 0); err != nil {
|
||||||
|
|
@ -462,9 +471,11 @@ func TestDiskGeneratorPersistence(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Modify or delete some accounts, flatten everything onto disk
|
// Modify or delete some accounts, flatten everything onto disk
|
||||||
if err := snaps.Update(diffRoot, baseRoot, nil, map[common.Hash][]byte{
|
if err := snaps.Update(diffRoot, baseRoot,
|
||||||
accTwo: accTwo[:],
|
map[common.Hash][]byte{
|
||||||
}, nil); err != nil {
|
accTwo: accTwo[:],
|
||||||
|
}, nil,
|
||||||
|
); err != nil {
|
||||||
t.Fatalf("failed to update snapshot tree: %v", err)
|
t.Fatalf("failed to update snapshot tree: %v", err)
|
||||||
}
|
}
|
||||||
if err := snaps.Cap(diffRoot, 0); err != nil {
|
if err := snaps.Cap(diffRoot, 0); err != nil {
|
||||||
|
|
@ -480,11 +491,14 @@ func TestDiskGeneratorPersistence(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Test scenario 2, the disk layer is fully generated
|
// Test scenario 2, the disk layer is fully generated
|
||||||
// Modify or delete some accounts, flatten everything onto disk
|
// Modify or delete some accounts, flatten everything onto disk
|
||||||
if err := snaps.Update(diffTwoRoot, diffRoot, nil, map[common.Hash][]byte{
|
if err := snaps.Update(diffTwoRoot, diffRoot,
|
||||||
accThree: accThree.Bytes(),
|
map[common.Hash][]byte{
|
||||||
}, map[common.Hash]map[common.Hash][]byte{
|
accThree: accThree.Bytes(),
|
||||||
accThree: {accThreeSlot: accThreeSlot.Bytes()},
|
},
|
||||||
}); err != nil {
|
map[common.Hash]map[common.Hash][]byte{
|
||||||
|
accThree: {accThreeSlot: accThreeSlot.Bytes()},
|
||||||
|
},
|
||||||
|
); err != nil {
|
||||||
t.Fatalf("failed to update snapshot tree: %v", err)
|
t.Fatalf("failed to update snapshot tree: %v", err)
|
||||||
}
|
}
|
||||||
diskLayer := snaps.layers[snaps.diskRoot()].(*diskLayer)
|
diskLayer := snaps.layers[snaps.diskRoot()].(*diskLayer)
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) {
|
||||||
|
|
||||||
snapRoot, err := generateTrieRoot(nil, "", accIt, common.Hash{}, stackTrieGenerate,
|
snapRoot, err := generateTrieRoot(nil, "", accIt, common.Hash{}, stackTrieGenerate,
|
||||||
func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) {
|
func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) {
|
||||||
storageIt, _ := snap.StorageIterator(accountHash, common.Hash{})
|
storageIt := snap.StorageIterator(accountHash, common.Hash{})
|
||||||
defer storageIt.Release()
|
defer storageIt.Release()
|
||||||
|
|
||||||
hash, err := generateTrieRoot(nil, "", storageIt, accountHash, stackTrieGenerate, nil, stat, false)
|
hash, err := generateTrieRoot(nil, "", storageIt, accountHash, stackTrieGenerate, nil, stat, false)
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ func (it *diffAccountIterator) Next() bool {
|
||||||
}
|
}
|
||||||
// Iterator seems to be still alive, retrieve and cache the live hash
|
// Iterator seems to be still alive, retrieve and cache the live hash
|
||||||
it.curHash = it.keys[0]
|
it.curHash = it.keys[0]
|
||||||
|
|
||||||
// key cached, shift the iterator and notify the user of success
|
// key cached, shift the iterator and notify the user of success
|
||||||
it.keys = it.keys[1:]
|
it.keys = it.keys[1:]
|
||||||
return true
|
return true
|
||||||
|
|
@ -135,7 +136,7 @@ func (it *diffAccountIterator) Hash() common.Hash {
|
||||||
// This method may _fail_, if the underlying layer has been flattened between
|
// This method may _fail_, if the underlying layer has been flattened between
|
||||||
// the call to Next and Account. That type of error will set it.Err.
|
// the call to Next and Account. That type of error will set it.Err.
|
||||||
// This method assumes that flattening does not delete elements from
|
// This method assumes that flattening does not delete elements from
|
||||||
// the accountdata mapping (writing nil into it is fine though), and will panic
|
// the accountData mapping (writing nil into it is fine though), and will panic
|
||||||
// if elements have been deleted.
|
// if elements have been deleted.
|
||||||
//
|
//
|
||||||
// Note the returned account is not a copy, please don't modify it.
|
// Note the returned account is not a copy, please don't modify it.
|
||||||
|
|
@ -143,10 +144,6 @@ func (it *diffAccountIterator) Account() []byte {
|
||||||
it.layer.lock.RLock()
|
it.layer.lock.RLock()
|
||||||
blob, ok := it.layer.accountData[it.curHash]
|
blob, ok := it.layer.accountData[it.curHash]
|
||||||
if !ok {
|
if !ok {
|
||||||
if _, ok := it.layer.destructSet[it.curHash]; ok {
|
|
||||||
it.layer.lock.RUnlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
panic(fmt.Sprintf("iterator referenced non-existent account: %x", it.curHash))
|
panic(fmt.Sprintf("iterator referenced non-existent account: %x", it.curHash))
|
||||||
}
|
}
|
||||||
it.layer.lock.RUnlock()
|
it.layer.lock.RUnlock()
|
||||||
|
|
@ -247,11 +244,11 @@ type diffStorageIterator struct {
|
||||||
// "destructed" returned. If it's true then it means the whole storage is
|
// "destructed" returned. If it's true then it means the whole storage is
|
||||||
// destructed in this layer(maybe recreated too), don't bother deeper layer
|
// destructed in this layer(maybe recreated too), don't bother deeper layer
|
||||||
// for storage retrieval.
|
// for storage retrieval.
|
||||||
func (dl *diffLayer) StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) {
|
func (dl *diffLayer) StorageIterator(account common.Hash, seek common.Hash) StorageIterator {
|
||||||
// Create the storage for this account even it's marked
|
// Create the storage for this account even it's marked
|
||||||
// as destructed. The iterator is for the new one which
|
// as destructed. The iterator is for the new one which
|
||||||
// just has the same address as the deleted one.
|
// just has the same address as the deleted one.
|
||||||
hashes, destructed := dl.StorageList(account)
|
hashes := dl.StorageList(account)
|
||||||
index := sort.Search(len(hashes), func(i int) bool {
|
index := sort.Search(len(hashes), func(i int) bool {
|
||||||
return bytes.Compare(seek[:], hashes[i][:]) <= 0
|
return bytes.Compare(seek[:], hashes[i][:]) <= 0
|
||||||
})
|
})
|
||||||
|
|
@ -260,7 +257,7 @@ func (dl *diffLayer) StorageIterator(account common.Hash, seek common.Hash) (Sto
|
||||||
layer: dl,
|
layer: dl,
|
||||||
account: account,
|
account: account,
|
||||||
keys: hashes[index:],
|
keys: hashes[index:],
|
||||||
}, destructed
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next steps the iterator forward one element, returning false if exhausted.
|
// Next steps the iterator forward one element, returning false if exhausted.
|
||||||
|
|
@ -339,13 +336,13 @@ type diskStorageIterator struct {
|
||||||
// If the whole storage is destructed, then all entries in the disk
|
// If the whole storage is destructed, then all entries in the disk
|
||||||
// layer are deleted already. So the "destructed" flag returned here
|
// layer are deleted already. So the "destructed" flag returned here
|
||||||
// is always false.
|
// is always false.
|
||||||
func (dl *diskLayer) StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool) {
|
func (dl *diskLayer) StorageIterator(account common.Hash, seek common.Hash) StorageIterator {
|
||||||
pos := common.TrimRightZeroes(seek[:])
|
pos := common.TrimRightZeroes(seek[:])
|
||||||
return &diskStorageIterator{
|
return &diskStorageIterator{
|
||||||
layer: dl,
|
layer: dl,
|
||||||
account: account,
|
account: account,
|
||||||
it: dl.diskdb.NewIterator(append(rawdb.SnapshotStoragePrefix, account.Bytes()...), pos),
|
it: dl.diskdb.NewIterator(append(rawdb.SnapshotStoragePrefix, account.Bytes()...), pos),
|
||||||
}, false
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next steps the iterator forward one element, returning false if exhausted.
|
// Next steps the iterator forward one element, returning false if exhausted.
|
||||||
|
|
|
||||||
|
|
@ -67,44 +67,17 @@ func (dl *diffLayer) initBinaryAccountIterator(seek common.Hash) Iterator {
|
||||||
func (dl *diffLayer) initBinaryStorageIterator(account, seek common.Hash) Iterator {
|
func (dl *diffLayer) initBinaryStorageIterator(account, seek common.Hash) Iterator {
|
||||||
parent, ok := dl.parent.(*diffLayer)
|
parent, ok := dl.parent.(*diffLayer)
|
||||||
if !ok {
|
if !ok {
|
||||||
// If the storage in this layer is already destructed, discard all
|
|
||||||
// deeper layers but still return a valid single-branch iterator.
|
|
||||||
a, destructed := dl.StorageIterator(account, seek)
|
|
||||||
if destructed {
|
|
||||||
l := &binaryIterator{
|
|
||||||
a: a,
|
|
||||||
account: account,
|
|
||||||
}
|
|
||||||
l.aDone = !l.a.Next()
|
|
||||||
l.bDone = true
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
// The parent is disk layer, don't need to take care "destructed"
|
|
||||||
// anymore.
|
|
||||||
b, _ := dl.Parent().StorageIterator(account, seek)
|
|
||||||
l := &binaryIterator{
|
l := &binaryIterator{
|
||||||
a: a,
|
a: dl.StorageIterator(account, seek),
|
||||||
b: b,
|
b: dl.Parent().StorageIterator(account, seek),
|
||||||
account: account,
|
account: account,
|
||||||
}
|
}
|
||||||
l.aDone = !l.a.Next()
|
l.aDone = !l.a.Next()
|
||||||
l.bDone = !l.b.Next()
|
l.bDone = !l.b.Next()
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
// If the storage in this layer is already destructed, discard all
|
|
||||||
// deeper layers but still return a valid single-branch iterator.
|
|
||||||
a, destructed := dl.StorageIterator(account, seek)
|
|
||||||
if destructed {
|
|
||||||
l := &binaryIterator{
|
|
||||||
a: a,
|
|
||||||
account: account,
|
|
||||||
}
|
|
||||||
l.aDone = !l.a.Next()
|
|
||||||
l.bDone = true
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
l := &binaryIterator{
|
l := &binaryIterator{
|
||||||
a: a,
|
a: dl.StorageIterator(account, seek),
|
||||||
b: parent.initBinaryStorageIterator(account, seek),
|
b: parent.initBinaryStorageIterator(account, seek),
|
||||||
account: account,
|
account: account,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,18 +90,10 @@ func newFastIterator(tree *Tree, root common.Hash, account common.Hash, seek com
|
||||||
priority: depth,
|
priority: depth,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// If the whole storage is destructed in this layer, don't
|
|
||||||
// bother deeper layer anymore. But we should still keep
|
|
||||||
// the iterator for this layer, since the iterator can contain
|
|
||||||
// some valid slots which belongs to the re-created account.
|
|
||||||
it, destructed := current.StorageIterator(account, seek)
|
|
||||||
fi.iterators = append(fi.iterators, &weightedIterator{
|
fi.iterators = append(fi.iterators, &weightedIterator{
|
||||||
it: it,
|
it: current.StorageIterator(account, seek),
|
||||||
priority: depth,
|
priority: depth,
|
||||||
})
|
})
|
||||||
if destructed {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
current = current.Parent()
|
current = current.Parent()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,8 @@ import (
|
||||||
// TestAccountIteratorBasics tests some simple single-layer(diff and disk) iteration
|
// TestAccountIteratorBasics tests some simple single-layer(diff and disk) iteration
|
||||||
func TestAccountIteratorBasics(t *testing.T) {
|
func TestAccountIteratorBasics(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
destructs = make(map[common.Hash]struct{})
|
accounts = make(map[common.Hash][]byte)
|
||||||
accounts = make(map[common.Hash][]byte)
|
storage = make(map[common.Hash]map[common.Hash][]byte)
|
||||||
storage = make(map[common.Hash]map[common.Hash][]byte)
|
|
||||||
)
|
)
|
||||||
// Fill up a parent
|
// Fill up a parent
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
|
|
@ -42,9 +41,6 @@ func TestAccountIteratorBasics(t *testing.T) {
|
||||||
data := randomAccount()
|
data := randomAccount()
|
||||||
|
|
||||||
accounts[h] = data
|
accounts[h] = data
|
||||||
if rand.Intn(4) == 0 {
|
|
||||||
destructs[h] = struct{}{}
|
|
||||||
}
|
|
||||||
if rand.Intn(2) == 0 {
|
if rand.Intn(2) == 0 {
|
||||||
accStorage := make(map[common.Hash][]byte)
|
accStorage := make(map[common.Hash][]byte)
|
||||||
value := make([]byte, 32)
|
value := make([]byte, 32)
|
||||||
|
|
@ -54,7 +50,7 @@ func TestAccountIteratorBasics(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add some (identical) layers on top
|
// Add some (identical) layers on top
|
||||||
diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, copyDestructs(destructs), copyAccounts(accounts), copyStorage(storage))
|
diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, copyAccounts(accounts), copyStorage(storage))
|
||||||
it := diffLayer.AccountIterator(common.Hash{})
|
it := diffLayer.AccountIterator(common.Hash{})
|
||||||
verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator
|
verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator
|
||||||
|
|
||||||
|
|
@ -95,15 +91,15 @@ func TestStorageIteratorBasics(t *testing.T) {
|
||||||
nilStorage[h] = nilstorage
|
nilStorage[h] = nilstorage
|
||||||
}
|
}
|
||||||
// Add some (identical) layers on top
|
// Add some (identical) layers on top
|
||||||
diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, nil, copyAccounts(accounts), copyStorage(storage))
|
diffLayer := newDiffLayer(emptyLayer(), common.Hash{}, copyAccounts(accounts), copyStorage(storage))
|
||||||
for account := range accounts {
|
for account := range accounts {
|
||||||
it, _ := diffLayer.StorageIterator(account, common.Hash{})
|
it := diffLayer.StorageIterator(account, common.Hash{})
|
||||||
verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator
|
verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
diskLayer := diffToDisk(diffLayer)
|
diskLayer := diffToDisk(diffLayer)
|
||||||
for account := range accounts {
|
for account := range accounts {
|
||||||
it, _ := diskLayer.StorageIterator(account, common.Hash{})
|
it := diskLayer.StorageIterator(account, common.Hash{})
|
||||||
verifyIterator(t, 100-nilStorage[account], it, verifyNothing) // Nil is allowed for single layer iterator
|
verifyIterator(t, 100-nilStorage[account], it, verifyNothing) // Nil is allowed for single layer iterator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -225,13 +221,13 @@ func TestAccountIteratorTraversal(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Stack three diff layers on top with various overlaps
|
// Stack three diff layers on top with various overlaps
|
||||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil,
|
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"),
|
||||||
randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil)
|
randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil)
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil,
|
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"),
|
||||||
randomAccountSet("0xbb", "0xdd", "0xf0"), nil)
|
randomAccountSet("0xbb", "0xdd", "0xf0"), nil)
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil,
|
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
|
||||||
randomAccountSet("0xcc", "0xf0", "0xff"), nil)
|
randomAccountSet("0xcc", "0xf0", "0xff"), nil)
|
||||||
|
|
||||||
// Verify the single and multi-layer iterators
|
// Verify the single and multi-layer iterators
|
||||||
|
|
@ -272,19 +268,19 @@ func TestStorageIteratorTraversal(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Stack three diff layers on top with various overlaps
|
// Stack three diff layers on top with various overlaps
|
||||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil,
|
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"),
|
||||||
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil))
|
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil))
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil,
|
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"),
|
||||||
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04", "0x05", "0x06"}}, nil))
|
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x04", "0x05", "0x06"}}, nil))
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil,
|
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
|
||||||
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil))
|
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x02", "0x03"}}, nil))
|
||||||
|
|
||||||
// Verify the single and multi-layer iterators
|
// Verify the single and multi-layer iterators
|
||||||
head := snaps.Snapshot(common.HexToHash("0x04"))
|
head := snaps.Snapshot(common.HexToHash("0x04"))
|
||||||
|
|
||||||
diffIter, _ := head.(snapshot).StorageIterator(common.HexToHash("0xaa"), common.Hash{})
|
diffIter := head.(snapshot).StorageIterator(common.HexToHash("0xaa"), common.Hash{})
|
||||||
verifyIterator(t, 3, diffIter, verifyNothing)
|
verifyIterator(t, 3, diffIter, verifyNothing)
|
||||||
verifyIterator(t, 6, head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}), verifyStorage)
|
verifyIterator(t, 6, head.(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa"), common.Hash{}), verifyStorage)
|
||||||
|
|
||||||
|
|
@ -357,14 +353,14 @@ func TestAccountIteratorTraversalValues(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Assemble a stack of snapshots from the account layers
|
// Assemble a stack of snapshots from the account layers
|
||||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, a, nil)
|
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), a, nil)
|
||||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, b, nil)
|
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), b, nil)
|
||||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, c, nil)
|
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), c, nil)
|
||||||
snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, d, nil)
|
snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), d, nil)
|
||||||
snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, e, nil)
|
snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), e, nil)
|
||||||
snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, f, nil)
|
snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), f, nil)
|
||||||
snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, g, nil)
|
snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), g, nil)
|
||||||
snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, h, nil)
|
snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), h, nil)
|
||||||
|
|
||||||
it, _ := snaps.AccountIterator(common.HexToHash("0x09"), common.Hash{})
|
it, _ := snaps.AccountIterator(common.HexToHash("0x09"), common.Hash{})
|
||||||
head := snaps.Snapshot(common.HexToHash("0x09"))
|
head := snaps.Snapshot(common.HexToHash("0x09"))
|
||||||
|
|
@ -456,14 +452,14 @@ func TestStorageIteratorTraversalValues(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Assemble a stack of snapshots from the account layers
|
// Assemble a stack of snapshots from the account layers
|
||||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, randomAccountSet("0xaa"), wrapStorage(a))
|
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), randomAccountSet("0xaa"), wrapStorage(a))
|
||||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, randomAccountSet("0xaa"), wrapStorage(b))
|
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), randomAccountSet("0xaa"), wrapStorage(b))
|
||||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, randomAccountSet("0xaa"), wrapStorage(c))
|
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), randomAccountSet("0xaa"), wrapStorage(c))
|
||||||
snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil, randomAccountSet("0xaa"), wrapStorage(d))
|
snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), randomAccountSet("0xaa"), wrapStorage(d))
|
||||||
snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), nil, randomAccountSet("0xaa"), wrapStorage(e))
|
snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), randomAccountSet("0xaa"), wrapStorage(e))
|
||||||
snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), nil, randomAccountSet("0xaa"), wrapStorage(e))
|
snaps.Update(common.HexToHash("0x07"), common.HexToHash("0x06"), randomAccountSet("0xaa"), wrapStorage(e))
|
||||||
snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), nil, randomAccountSet("0xaa"), wrapStorage(g))
|
snaps.Update(common.HexToHash("0x08"), common.HexToHash("0x07"), randomAccountSet("0xaa"), wrapStorage(g))
|
||||||
snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), nil, randomAccountSet("0xaa"), wrapStorage(h))
|
snaps.Update(common.HexToHash("0x09"), common.HexToHash("0x08"), randomAccountSet("0xaa"), wrapStorage(h))
|
||||||
|
|
||||||
it, _ := snaps.StorageIterator(common.HexToHash("0x09"), common.HexToHash("0xaa"), common.Hash{})
|
it, _ := snaps.StorageIterator(common.HexToHash("0x09"), common.HexToHash("0xaa"), common.Hash{})
|
||||||
head := snaps.Snapshot(common.HexToHash("0x09"))
|
head := snaps.Snapshot(common.HexToHash("0x09"))
|
||||||
|
|
@ -526,7 +522,7 @@ func TestAccountIteratorLargeTraversal(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i := 1; i < 128; i++ {
|
for i := 1; i < 128; i++ {
|
||||||
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil)
|
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), makeAccounts(200), nil)
|
||||||
}
|
}
|
||||||
// Iterate the entire stack and ensure everything is hit only once
|
// Iterate the entire stack and ensure everything is hit only once
|
||||||
head := snaps.Snapshot(common.HexToHash("0x80"))
|
head := snaps.Snapshot(common.HexToHash("0x80"))
|
||||||
|
|
@ -584,13 +580,13 @@ func testAccountIteratorFlattening(t *testing.T, newIterator func(snaps *Tree, r
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Create a stack of diffs on top
|
// Create a stack of diffs on top
|
||||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil,
|
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"),
|
||||||
randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil)
|
randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil)
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil,
|
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"),
|
||||||
randomAccountSet("0xbb", "0xdd", "0xf0"), nil)
|
randomAccountSet("0xbb", "0xdd", "0xf0"), nil)
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil,
|
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
|
||||||
randomAccountSet("0xcc", "0xf0", "0xff"), nil)
|
randomAccountSet("0xcc", "0xf0", "0xff"), nil)
|
||||||
|
|
||||||
// Create an iterator and flatten the data from underneath it
|
// Create an iterator and flatten the data from underneath it
|
||||||
|
|
@ -630,13 +626,13 @@ func testAccountIteratorSeek(t *testing.T, newIterator func(snaps *Tree, root, s
|
||||||
base.root: base,
|
base.root: base,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil,
|
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"),
|
||||||
randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil)
|
randomAccountSet("0xaa", "0xee", "0xff", "0xf0"), nil)
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil,
|
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"),
|
||||||
randomAccountSet("0xbb", "0xdd", "0xf0"), nil)
|
randomAccountSet("0xbb", "0xdd", "0xf0"), nil)
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil,
|
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
|
||||||
randomAccountSet("0xcc", "0xf0", "0xff"), nil)
|
randomAccountSet("0xcc", "0xf0", "0xff"), nil)
|
||||||
|
|
||||||
// Account set is now
|
// Account set is now
|
||||||
|
|
@ -708,13 +704,13 @@ func testStorageIteratorSeek(t *testing.T, newIterator func(snaps *Tree, root, a
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Stack three diff layers on top with various overlaps
|
// Stack three diff layers on top with various overlaps
|
||||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil,
|
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"),
|
||||||
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil))
|
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil))
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil,
|
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"),
|
||||||
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x05", "0x06"}}, nil))
|
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x05", "0x06"}}, nil))
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil,
|
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
|
||||||
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x05", "0x08"}}, nil))
|
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x05", "0x08"}}, nil))
|
||||||
|
|
||||||
// Account set is now
|
// Account set is now
|
||||||
|
|
@ -785,21 +781,16 @@ func testAccountIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, ro
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Stack three diff layers on top with various overlaps
|
// Stack three diff layers on top with various overlaps
|
||||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"),
|
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), randomAccountSet("0x11", "0x22", "0x33"), nil)
|
||||||
nil, randomAccountSet("0x11", "0x22", "0x33"), nil)
|
|
||||||
|
|
||||||
deleted := common.HexToHash("0x22")
|
|
||||||
destructed := map[common.Hash]struct{}{
|
|
||||||
deleted: {},
|
|
||||||
}
|
|
||||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"),
|
|
||||||
destructed, randomAccountSet("0x11", "0x33"), nil)
|
|
||||||
|
|
||||||
|
set := randomAccountSet("0x11", "0x33")
|
||||||
|
set[common.HexToHash("0x22")] = nil
|
||||||
|
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), set, nil)
|
||||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
|
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
|
||||||
nil, randomAccountSet("0x33", "0x44", "0x55"), nil)
|
randomAccountSet("0x33", "0x44", "0x55"), nil)
|
||||||
|
|
||||||
// The output should be 11,33,44,55
|
// The output should be 11,33,44,55
|
||||||
it := newIterator(snaps, common.HexToHash("0x04"), (common.Hash{}))
|
it := newIterator(snaps, common.HexToHash("0x04"), common.Hash{})
|
||||||
|
|
||||||
// Do a quick check
|
// Do a quick check
|
||||||
verifyIterator(t, 4, it, verifyAccount)
|
verifyIterator(t, 4, it, verifyAccount)
|
||||||
|
|
@ -813,8 +804,8 @@ func testAccountIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, ro
|
||||||
if it.Account() == nil {
|
if it.Account() == nil {
|
||||||
t.Errorf("iterator returned nil-value for hash %x", hash)
|
t.Errorf("iterator returned nil-value for hash %x", hash)
|
||||||
}
|
}
|
||||||
if hash == deleted {
|
if hash == common.HexToHash("0x22") {
|
||||||
t.Errorf("expected deleted elem %x to not be returned by iterator", deleted)
|
t.Errorf("expected deleted elem %x to not be returned by iterator", common.HexToHash("0x22"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -846,10 +837,10 @@ func testStorageIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, ro
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Stack three diff layers on top with various overlaps
|
// Stack three diff layers on top with various overlaps
|
||||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil,
|
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"),
|
||||||
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil))
|
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x01", "0x03", "0x05"}}, nil))
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil,
|
snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"),
|
||||||
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}}))
|
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x02", "0x04", "0x06"}}, [][]string{{"0x01", "0x03"}}))
|
||||||
|
|
||||||
// The output should be 02,04,05,06
|
// The output should be 02,04,05,06
|
||||||
|
|
@ -863,17 +854,16 @@ func testStorageIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, ro
|
||||||
it.Release()
|
it.Release()
|
||||||
|
|
||||||
// Destruct the whole storage
|
// Destruct the whole storage
|
||||||
destructed := map[common.Hash]struct{}{
|
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"),
|
||||||
common.HexToHash("0xaa"): {},
|
map[common.Hash][]byte{common.HexToHash("0xaa"): nil},
|
||||||
}
|
randomStorageSet([]string{"0xaa"}, nil, [][]string{{"0x02", "0x04", "0x05", "0x06"}}))
|
||||||
snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), destructed, nil, nil)
|
|
||||||
|
|
||||||
it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{})
|
it = newIterator(snaps, common.HexToHash("0x04"), common.HexToHash("0xaa"), common.Hash{})
|
||||||
verifyIterator(t, 0, it, verifyStorage)
|
verifyIterator(t, 0, it, verifyStorage)
|
||||||
it.Release()
|
it.Release()
|
||||||
|
|
||||||
// Re-insert the slots of the same account
|
// Re-insert the slots of the same account
|
||||||
snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"), nil,
|
snaps.Update(common.HexToHash("0x05"), common.HexToHash("0x04"),
|
||||||
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil))
|
randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x07", "0x08", "0x09"}}, nil))
|
||||||
|
|
||||||
// The output should be 07,08,09
|
// The output should be 07,08,09
|
||||||
|
|
@ -883,7 +873,9 @@ func testStorageIteratorDeletions(t *testing.T, newIterator func(snaps *Tree, ro
|
||||||
it.Release()
|
it.Release()
|
||||||
|
|
||||||
// Destruct the whole storage but re-create the account in the same layer
|
// Destruct the whole storage but re-create the account in the same layer
|
||||||
snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"), destructed, randomAccountSet("0xaa"), randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, nil))
|
snaps.Update(common.HexToHash("0x06"), common.HexToHash("0x05"),
|
||||||
|
randomAccountSet("0xaa"),
|
||||||
|
randomStorageSet([]string{"0xaa"}, [][]string{{"0x11", "0x12"}}, [][]string{{"0x07", "0x08", "0x09"}}))
|
||||||
it = newIterator(snaps, common.HexToHash("0x06"), common.HexToHash("0xaa"), common.Hash{})
|
it = newIterator(snaps, common.HexToHash("0x06"), common.HexToHash("0xaa"), common.Hash{})
|
||||||
verifyIterator(t, 2, it, verifyStorage) // The output should be 11,12
|
verifyIterator(t, 2, it, verifyStorage) // The output should be 11,12
|
||||||
it.Release()
|
it.Release()
|
||||||
|
|
@ -928,7 +920,7 @@ func BenchmarkAccountIteratorTraversal(b *testing.B) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i := 1; i <= 100; i++ {
|
for i := 1; i <= 100; i++ {
|
||||||
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(200), nil)
|
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), makeAccounts(200), nil)
|
||||||
}
|
}
|
||||||
// We call this once before the benchmark, so the creation of
|
// We call this once before the benchmark, so the creation of
|
||||||
// sorted accountlists are not included in the results.
|
// sorted accountlists are not included in the results.
|
||||||
|
|
@ -1023,9 +1015,9 @@ func BenchmarkAccountIteratorLargeBaselayer(b *testing.B) {
|
||||||
base.root: base,
|
base.root: base,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, makeAccounts(2000), nil)
|
snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), makeAccounts(2000), nil)
|
||||||
for i := 2; i <= 100; i++ {
|
for i := 2; i <= 100; i++ {
|
||||||
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), nil, makeAccounts(20), nil)
|
snaps.Update(common.HexToHash(fmt.Sprintf("0x%02x", i+1)), common.HexToHash(fmt.Sprintf("0x%02x", i)), makeAccounts(20), nil)
|
||||||
}
|
}
|
||||||
// We call this once before the benchmark, so the creation of
|
// We call this once before the benchmark, so the creation of
|
||||||
// sorted accountlists are not included in the results.
|
// sorted accountlists are not included in the results.
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
)
|
)
|
||||||
|
|
||||||
const journalVersion uint64 = 0
|
// 0: initial version
|
||||||
|
// 1: destruct flag in diff layer is removed
|
||||||
|
const journalVersion uint64 = 1
|
||||||
|
|
||||||
// journalGenerator is a disk layer entry containing the generator progress marker.
|
// journalGenerator is a disk layer entry containing the generator progress marker.
|
||||||
type journalGenerator struct {
|
type journalGenerator struct {
|
||||||
|
|
@ -48,11 +50,6 @@ type journalGenerator struct {
|
||||||
Storage uint64
|
Storage uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// journalDestruct is an account deletion entry in a diffLayer's disk journal.
|
|
||||||
type journalDestruct struct {
|
|
||||||
Hash common.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
// journalAccount is an account entry in a diffLayer's disk journal.
|
// journalAccount is an account entry in a diffLayer's disk journal.
|
||||||
type journalAccount struct {
|
type journalAccount struct {
|
||||||
Hash common.Hash
|
Hash common.Hash
|
||||||
|
|
@ -109,8 +106,8 @@ func loadAndParseJournal(db ethdb.KeyValueStore, base *diskLayer) (snapshot, jou
|
||||||
// is not matched with disk layer; or the it's the legacy-format journal,
|
// is not matched with disk layer; or the it's the legacy-format journal,
|
||||||
// etc.), we just discard all diffs and try to recover them later.
|
// etc.), we just discard all diffs and try to recover them later.
|
||||||
var current snapshot = base
|
var current snapshot = base
|
||||||
err := iterateJournal(db, func(parent common.Hash, root common.Hash, destructSet map[common.Hash]struct{}, accountData map[common.Hash][]byte, storageData map[common.Hash]map[common.Hash][]byte) error {
|
err := iterateJournal(db, func(parent common.Hash, root common.Hash, accountData map[common.Hash][]byte, storageData map[common.Hash]map[common.Hash][]byte) error {
|
||||||
current = newDiffLayer(current, root, destructSet, accountData, storageData)
|
current = newDiffLayer(current, root, accountData, storageData)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -238,16 +235,12 @@ func (dl *diffLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) {
|
||||||
if err := rlp.Encode(buffer, dl.root); err != nil {
|
if err := rlp.Encode(buffer, dl.root); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
destructs := make([]journalDestruct, 0, len(dl.destructSet))
|
|
||||||
for hash := range dl.destructSet {
|
|
||||||
destructs = append(destructs, journalDestruct{Hash: hash})
|
|
||||||
}
|
|
||||||
if err := rlp.Encode(buffer, destructs); err != nil {
|
|
||||||
return common.Hash{}, err
|
|
||||||
}
|
|
||||||
accounts := make([]journalAccount, 0, len(dl.accountData))
|
accounts := make([]journalAccount, 0, len(dl.accountData))
|
||||||
for hash, blob := range dl.accountData {
|
for hash, blob := range dl.accountData {
|
||||||
accounts = append(accounts, journalAccount{Hash: hash, Blob: blob})
|
accounts = append(accounts, journalAccount{
|
||||||
|
Hash: hash,
|
||||||
|
Blob: blob,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if err := rlp.Encode(buffer, accounts); err != nil {
|
if err := rlp.Encode(buffer, accounts); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
|
|
@ -271,7 +264,7 @@ func (dl *diffLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) {
|
||||||
|
|
||||||
// journalCallback is a function which is invoked by iterateJournal, every
|
// journalCallback is a function which is invoked by iterateJournal, every
|
||||||
// time a difflayer is loaded from disk.
|
// time a difflayer is loaded from disk.
|
||||||
type journalCallback = func(parent common.Hash, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error
|
type journalCallback = func(parent common.Hash, root common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error
|
||||||
|
|
||||||
// iterateJournal iterates through the journalled difflayers, loading them from
|
// iterateJournal iterates through the journalled difflayers, loading them from
|
||||||
// the database, and invoking the callback for each loaded layer.
|
// the database, and invoking the callback for each loaded layer.
|
||||||
|
|
@ -310,10 +303,8 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
|
||||||
for {
|
for {
|
||||||
var (
|
var (
|
||||||
root common.Hash
|
root common.Hash
|
||||||
destructs []journalDestruct
|
|
||||||
accounts []journalAccount
|
accounts []journalAccount
|
||||||
storage []journalStorage
|
storage []journalStorage
|
||||||
destructSet = make(map[common.Hash]struct{})
|
|
||||||
accountData = make(map[common.Hash][]byte)
|
accountData = make(map[common.Hash][]byte)
|
||||||
storageData = make(map[common.Hash]map[common.Hash][]byte)
|
storageData = make(map[common.Hash]map[common.Hash][]byte)
|
||||||
)
|
)
|
||||||
|
|
@ -325,18 +316,12 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
|
||||||
}
|
}
|
||||||
return fmt.Errorf("load diff root: %v", err)
|
return fmt.Errorf("load diff root: %v", err)
|
||||||
}
|
}
|
||||||
if err := r.Decode(&destructs); err != nil {
|
|
||||||
return fmt.Errorf("load diff destructs: %v", err)
|
|
||||||
}
|
|
||||||
if err := r.Decode(&accounts); err != nil {
|
if err := r.Decode(&accounts); err != nil {
|
||||||
return fmt.Errorf("load diff accounts: %v", err)
|
return fmt.Errorf("load diff accounts: %v", err)
|
||||||
}
|
}
|
||||||
if err := r.Decode(&storage); err != nil {
|
if err := r.Decode(&storage); err != nil {
|
||||||
return fmt.Errorf("load diff storage: %v", err)
|
return fmt.Errorf("load diff storage: %v", err)
|
||||||
}
|
}
|
||||||
for _, entry := range destructs {
|
|
||||||
destructSet[entry.Hash] = struct{}{}
|
|
||||||
}
|
|
||||||
for _, entry := range accounts {
|
for _, entry := range accounts {
|
||||||
if len(entry.Blob) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that
|
if len(entry.Blob) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that
|
||||||
accountData[entry.Hash] = entry.Blob
|
accountData[entry.Hash] = entry.Blob
|
||||||
|
|
@ -355,7 +340,7 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
|
||||||
}
|
}
|
||||||
storageData[entry.Hash] = slots
|
storageData[entry.Hash] = slots
|
||||||
}
|
}
|
||||||
if err := callback(parent, root, destructSet, accountData, storageData); err != nil {
|
if err := callback(parent, root, accountData, storageData); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
parent = root
|
parent = root
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ type snapshot interface {
|
||||||
// the specified data items.
|
// the specified data items.
|
||||||
//
|
//
|
||||||
// Note, the maps are retained by the method to avoid copying everything.
|
// Note, the maps are retained by the method to avoid copying everything.
|
||||||
Update(blockRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer
|
Update(blockRoot common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer
|
||||||
|
|
||||||
// Journal commits an entire diff hierarchy to disk into a single journal entry.
|
// Journal commits an entire diff hierarchy to disk into a single journal entry.
|
||||||
// This is meant to be used during shutdown to persist the snapshot without
|
// This is meant to be used during shutdown to persist the snapshot without
|
||||||
|
|
@ -145,7 +145,7 @@ type snapshot interface {
|
||||||
AccountIterator(seek common.Hash) AccountIterator
|
AccountIterator(seek common.Hash) AccountIterator
|
||||||
|
|
||||||
// StorageIterator creates a storage iterator over an arbitrary layer.
|
// StorageIterator creates a storage iterator over an arbitrary layer.
|
||||||
StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool)
|
StorageIterator(account common.Hash, seek common.Hash) StorageIterator
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config includes the configurations for snapshots.
|
// Config includes the configurations for snapshots.
|
||||||
|
|
@ -335,7 +335,7 @@ func (t *Tree) Snapshots(root common.Hash, limits int, nodisk bool) []Snapshot {
|
||||||
|
|
||||||
// Update adds a new snapshot into the tree, if that can be linked to an existing
|
// Update adds a new snapshot into the tree, if that can be linked to an existing
|
||||||
// old parent. It is disallowed to insert a disk layer (the origin of all).
|
// old parent. It is disallowed to insert a disk layer (the origin of all).
|
||||||
func (t *Tree) Update(blockRoot common.Hash, parentRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error {
|
func (t *Tree) Update(blockRoot common.Hash, parentRoot common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error {
|
||||||
// Reject noop updates to avoid self-loops in the snapshot tree. This is a
|
// Reject noop updates to avoid self-loops in the snapshot tree. This is a
|
||||||
// special case that can only happen for Clique networks where empty blocks
|
// special case that can only happen for Clique networks where empty blocks
|
||||||
// don't modify the state (0 block subsidy).
|
// don't modify the state (0 block subsidy).
|
||||||
|
|
@ -350,7 +350,7 @@ func (t *Tree) Update(blockRoot common.Hash, parentRoot common.Hash, destructs m
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return fmt.Errorf("parent [%#x] snapshot missing", parentRoot)
|
return fmt.Errorf("parent [%#x] snapshot missing", parentRoot)
|
||||||
}
|
}
|
||||||
snap := parent.(snapshot).Update(blockRoot, destructs, accounts, storage)
|
snap := parent.(snapshot).Update(blockRoot, accounts, storage)
|
||||||
|
|
||||||
// Save the new snapshot for later
|
// Save the new snapshot for later
|
||||||
t.lock.Lock()
|
t.lock.Lock()
|
||||||
|
|
@ -539,35 +539,6 @@ func diffToDisk(bottom *diffLayer) *diskLayer {
|
||||||
base.stale = true
|
base.stale = true
|
||||||
base.lock.Unlock()
|
base.lock.Unlock()
|
||||||
|
|
||||||
// Destroy all the destructed accounts from the database
|
|
||||||
for hash := range bottom.destructSet {
|
|
||||||
// Skip any account not covered yet by the snapshot
|
|
||||||
if base.genMarker != nil && bytes.Compare(hash[:], base.genMarker) > 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Remove all storage slots
|
|
||||||
rawdb.DeleteAccountSnapshot(batch, hash)
|
|
||||||
base.cache.Set(hash[:], nil)
|
|
||||||
|
|
||||||
it := rawdb.IterateStorageSnapshots(base.diskdb, hash)
|
|
||||||
for it.Next() {
|
|
||||||
key := it.Key()
|
|
||||||
batch.Delete(key)
|
|
||||||
base.cache.Del(key[1:])
|
|
||||||
snapshotFlushStorageItemMeter.Mark(1)
|
|
||||||
|
|
||||||
// Ensure we don't delete too much data blindly (contract can be
|
|
||||||
// huge). It's ok to flush, the root will go missing in case of a
|
|
||||||
// crash and we'll detect and regenerate the snapshot.
|
|
||||||
if batch.ValueSize() > 64*1024*1024 {
|
|
||||||
if err := batch.Write(); err != nil {
|
|
||||||
log.Crit("Failed to write storage deletions", "err", err)
|
|
||||||
}
|
|
||||||
batch.Reset()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
it.Release()
|
|
||||||
}
|
|
||||||
// Push all updated accounts into the database
|
// Push all updated accounts into the database
|
||||||
for hash, data := range bottom.accountData {
|
for hash, data := range bottom.accountData {
|
||||||
// Skip any account not covered yet by the snapshot
|
// Skip any account not covered yet by the snapshot
|
||||||
|
|
@ -575,10 +546,14 @@ func diffToDisk(bottom *diffLayer) *diskLayer {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Push the account to disk
|
// Push the account to disk
|
||||||
rawdb.WriteAccountSnapshot(batch, hash, data)
|
if len(data) != 0 {
|
||||||
base.cache.Set(hash[:], data)
|
rawdb.WriteAccountSnapshot(batch, hash, data)
|
||||||
snapshotCleanAccountWriteMeter.Mark(int64(len(data)))
|
base.cache.Set(hash[:], data)
|
||||||
|
snapshotCleanAccountWriteMeter.Mark(int64(len(data)))
|
||||||
|
} else {
|
||||||
|
rawdb.DeleteAccountSnapshot(batch, hash)
|
||||||
|
base.cache.Set(hash[:], nil)
|
||||||
|
}
|
||||||
snapshotFlushAccountItemMeter.Mark(1)
|
snapshotFlushAccountItemMeter.Mark(1)
|
||||||
snapshotFlushAccountSizeMeter.Mark(int64(len(data)))
|
snapshotFlushAccountSizeMeter.Mark(int64(len(data)))
|
||||||
|
|
||||||
|
|
@ -587,7 +562,7 @@ func diffToDisk(bottom *diffLayer) *diskLayer {
|
||||||
// the snapshot.
|
// the snapshot.
|
||||||
if batch.ValueSize() > 64*1024*1024 {
|
if batch.ValueSize() > 64*1024*1024 {
|
||||||
if err := batch.Write(); err != nil {
|
if err := batch.Write(); err != nil {
|
||||||
log.Crit("Failed to write storage deletions", "err", err)
|
log.Crit("Failed to write state changes", "err", err)
|
||||||
}
|
}
|
||||||
batch.Reset()
|
batch.Reset()
|
||||||
}
|
}
|
||||||
|
|
@ -616,6 +591,16 @@ func diffToDisk(bottom *diffLayer) *diskLayer {
|
||||||
}
|
}
|
||||||
snapshotFlushStorageItemMeter.Mark(1)
|
snapshotFlushStorageItemMeter.Mark(1)
|
||||||
snapshotFlushStorageSizeMeter.Mark(int64(len(data)))
|
snapshotFlushStorageSizeMeter.Mark(int64(len(data)))
|
||||||
|
|
||||||
|
// Ensure we don't write too much data blindly. It's ok to flush, the
|
||||||
|
// root will go missing in case of a crash and we'll detect and regen
|
||||||
|
// the snapshot.
|
||||||
|
if batch.ValueSize() > 64*1024*1024 {
|
||||||
|
if err := batch.Write(); err != nil {
|
||||||
|
log.Crit("Failed to write state changes", "err", err)
|
||||||
|
}
|
||||||
|
batch.Reset()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update the snapshot block marker and write any remainder data
|
// Update the snapshot block marker and write any remainder data
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ func TestDiskLayerExternalInvalidationFullFlatten(t *testing.T) {
|
||||||
accounts := map[common.Hash][]byte{
|
accounts := map[common.Hash][]byte{
|
||||||
common.HexToHash("0xa1"): randomAccount(),
|
common.HexToHash("0xa1"): randomAccount(),
|
||||||
}
|
}
|
||||||
if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil {
|
if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), accounts, nil); err != nil {
|
||||||
t.Fatalf("failed to create a diff layer: %v", err)
|
t.Fatalf("failed to create a diff layer: %v", err)
|
||||||
}
|
}
|
||||||
if n := len(snaps.layers); n != 2 {
|
if n := len(snaps.layers); n != 2 {
|
||||||
|
|
@ -151,10 +151,10 @@ func TestDiskLayerExternalInvalidationPartialFlatten(t *testing.T) {
|
||||||
accounts := map[common.Hash][]byte{
|
accounts := map[common.Hash][]byte{
|
||||||
common.HexToHash("0xa1"): randomAccount(),
|
common.HexToHash("0xa1"): randomAccount(),
|
||||||
}
|
}
|
||||||
if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil {
|
if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), accounts, nil); err != nil {
|
||||||
t.Fatalf("failed to create a diff layer: %v", err)
|
t.Fatalf("failed to create a diff layer: %v", err)
|
||||||
}
|
}
|
||||||
if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil {
|
if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), accounts, nil); err != nil {
|
||||||
t.Fatalf("failed to create a diff layer: %v", err)
|
t.Fatalf("failed to create a diff layer: %v", err)
|
||||||
}
|
}
|
||||||
if n := len(snaps.layers); n != 3 {
|
if n := len(snaps.layers); n != 3 {
|
||||||
|
|
@ -203,13 +203,13 @@ func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) {
|
||||||
accounts := map[common.Hash][]byte{
|
accounts := map[common.Hash][]byte{
|
||||||
common.HexToHash("0xa1"): randomAccount(),
|
common.HexToHash("0xa1"): randomAccount(),
|
||||||
}
|
}
|
||||||
if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), nil, accounts, nil); err != nil {
|
if err := snaps.Update(common.HexToHash("0x02"), common.HexToHash("0x01"), accounts, nil); err != nil {
|
||||||
t.Fatalf("failed to create a diff layer: %v", err)
|
t.Fatalf("failed to create a diff layer: %v", err)
|
||||||
}
|
}
|
||||||
if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), nil, accounts, nil); err != nil {
|
if err := snaps.Update(common.HexToHash("0x03"), common.HexToHash("0x02"), accounts, nil); err != nil {
|
||||||
t.Fatalf("failed to create a diff layer: %v", err)
|
t.Fatalf("failed to create a diff layer: %v", err)
|
||||||
}
|
}
|
||||||
if err := snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), nil, accounts, nil); err != nil {
|
if err := snaps.Update(common.HexToHash("0x04"), common.HexToHash("0x03"), accounts, nil); err != nil {
|
||||||
t.Fatalf("failed to create a diff layer: %v", err)
|
t.Fatalf("failed to create a diff layer: %v", err)
|
||||||
}
|
}
|
||||||
if n := len(snaps.layers); n != 4 {
|
if n := len(snaps.layers); n != 4 {
|
||||||
|
|
@ -263,12 +263,12 @@ func TestPostCapBasicDataAccess(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// The lowest difflayer
|
// The lowest difflayer
|
||||||
snaps.Update(common.HexToHash("0xa1"), common.HexToHash("0x01"), nil, setAccount("0xa1"), nil)
|
snaps.Update(common.HexToHash("0xa1"), common.HexToHash("0x01"), setAccount("0xa1"), nil)
|
||||||
snaps.Update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), nil, setAccount("0xa2"), nil)
|
snaps.Update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), setAccount("0xa2"), nil)
|
||||||
snaps.Update(common.HexToHash("0xb2"), common.HexToHash("0xa1"), nil, setAccount("0xb2"), nil)
|
snaps.Update(common.HexToHash("0xb2"), common.HexToHash("0xa1"), setAccount("0xb2"), nil)
|
||||||
|
|
||||||
snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), nil, setAccount("0xa3"), nil)
|
snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), setAccount("0xa3"), nil)
|
||||||
snaps.Update(common.HexToHash("0xb3"), common.HexToHash("0xb2"), nil, setAccount("0xb3"), nil)
|
snaps.Update(common.HexToHash("0xb3"), common.HexToHash("0xb2"), setAccount("0xb3"), nil)
|
||||||
|
|
||||||
// checkExist verifies if an account exists in a snapshot
|
// checkExist verifies if an account exists in a snapshot
|
||||||
checkExist := func(layer *diffLayer, key string) error {
|
checkExist := func(layer *diffLayer, key string) error {
|
||||||
|
|
@ -363,7 +363,7 @@ func TestSnaphots(t *testing.T) {
|
||||||
)
|
)
|
||||||
for i := 0; i < 129; i++ {
|
for i := 0; i < 129; i++ {
|
||||||
head = makeRoot(uint64(i + 2))
|
head = makeRoot(uint64(i + 2))
|
||||||
snaps.Update(head, last, nil, setAccount(fmt.Sprintf("%d", i+2)), nil)
|
snaps.Update(head, last, setAccount(fmt.Sprintf("%d", i+2)), nil)
|
||||||
last = head
|
last = head
|
||||||
snaps.Cap(head, 128) // 130 layers (128 diffs + 1 accumulator + 1 disk)
|
snaps.Cap(head, 128) // 130 layers (128 diffs + 1 accumulator + 1 disk)
|
||||||
}
|
}
|
||||||
|
|
@ -456,9 +456,9 @@ func TestReadStateDuringFlattening(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// 4 layers in total, 3 diff layers and 1 disk layers
|
// 4 layers in total, 3 diff layers and 1 disk layers
|
||||||
snaps.Update(common.HexToHash("0xa1"), common.HexToHash("0x01"), nil, setAccount("0xa1"), nil)
|
snaps.Update(common.HexToHash("0xa1"), common.HexToHash("0x01"), setAccount("0xa1"), nil)
|
||||||
snaps.Update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), nil, setAccount("0xa2"), nil)
|
snaps.Update(common.HexToHash("0xa2"), common.HexToHash("0xa1"), setAccount("0xa2"), nil)
|
||||||
snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), nil, setAccount("0xa3"), nil)
|
snaps.Update(common.HexToHash("0xa3"), common.HexToHash("0xa2"), setAccount("0xa3"), nil)
|
||||||
|
|
||||||
// Obtain the topmost snapshot handler for state accessing
|
// Obtain the topmost snapshot handler for state accessing
|
||||||
snap := snaps.Snapshot(common.HexToHash("0xa3"))
|
snap := snaps.Snapshot(common.HexToHash("0xa3"))
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ func checkDanglingDiskStorage(chaindb ethdb.KeyValueStore) error {
|
||||||
func checkDanglingMemStorage(db ethdb.KeyValueStore) error {
|
func checkDanglingMemStorage(db ethdb.KeyValueStore) error {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log.Info("Checking dangling journalled storage")
|
log.Info("Checking dangling journalled storage")
|
||||||
err := iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error {
|
err := iterateJournal(db, func(pRoot, root common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error {
|
||||||
for accHash := range storage {
|
for accHash := range storage {
|
||||||
if _, ok := accounts[accHash]; !ok {
|
if _, ok := accounts[accHash]; !ok {
|
||||||
log.Error("Dangling storage - missing account", "account", fmt.Sprintf("%#x", accHash), "root", root)
|
log.Error("Dangling storage - missing account", "account", fmt.Sprintf("%#x", accHash), "root", root)
|
||||||
|
|
@ -119,12 +119,11 @@ func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error {
|
||||||
}
|
}
|
||||||
var depth = 0
|
var depth = 0
|
||||||
|
|
||||||
return iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error {
|
return iterateJournal(db, func(pRoot, root common.Hash, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error {
|
||||||
_, a := accounts[hash]
|
_, a := accounts[hash]
|
||||||
_, b := destructs[hash]
|
_, b := storage[hash]
|
||||||
_, c := storage[hash]
|
|
||||||
depth++
|
depth++
|
||||||
if !a && !b && !c {
|
if !a && !b {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
fmt.Printf("Disklayer+%d: Root: %x, parent %x\n", depth, root, pRoot)
|
fmt.Printf("Disklayer+%d: Root: %x, parent %x\n", depth, root, pRoot)
|
||||||
|
|
@ -138,9 +137,6 @@ func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error {
|
||||||
fmt.Printf("\taccount.root: %x\n", account.Root)
|
fmt.Printf("\taccount.root: %x\n", account.Root)
|
||||||
fmt.Printf("\taccount.codehash: %x\n", account.CodeHash)
|
fmt.Printf("\taccount.codehash: %x\n", account.CodeHash)
|
||||||
}
|
}
|
||||||
if _, ok := destructs[hash]; ok {
|
|
||||||
fmt.Printf("\t Destructed!")
|
|
||||||
}
|
|
||||||
if data, ok := storage[hash]; ok {
|
if data, ok := storage[hash]; ok {
|
||||||
fmt.Printf("\tStorage\n")
|
fmt.Printf("\tStorage\n")
|
||||||
for k, v := range data {
|
for k, v := range data {
|
||||||
|
|
|
||||||
|
|
@ -932,16 +932,17 @@ func (s *StateDB) clearJournalAndRefund() {
|
||||||
// of a specific account. It leverages the associated state snapshot for fast
|
// of a specific account. It leverages the associated state snapshot for fast
|
||||||
// storage iteration and constructs trie node deletion markers by creating
|
// storage iteration and constructs trie node deletion markers by creating
|
||||||
// stack trie with iterated slots.
|
// stack trie with iterated slots.
|
||||||
func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
|
func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||||
iter, err := snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{})
|
iter, err := snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
defer iter.Release()
|
defer iter.Release()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
nodes = trienode.NewNodeSet(addrHash)
|
nodes = trienode.NewNodeSet(addrHash) // the set for trie node mutations (value is nil)
|
||||||
slots = make(map[common.Hash][]byte)
|
storages = make(map[common.Hash][]byte) // the set for storage mutations (value is nil)
|
||||||
|
storageOrigins = make(map[common.Hash][]byte) // the set for tracking the original value of slot
|
||||||
)
|
)
|
||||||
stack := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) {
|
stack := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) {
|
||||||
nodes.AddNode(path, trienode.NewDeleted())
|
nodes.AddNode(path, trienode.NewDeleted())
|
||||||
|
|
@ -949,42 +950,47 @@ func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash,
|
||||||
for iter.Next() {
|
for iter.Next() {
|
||||||
slot := common.CopyBytes(iter.Slot())
|
slot := common.CopyBytes(iter.Slot())
|
||||||
if err := iter.Error(); err != nil { // error might occur after Slot function
|
if err := iter.Error(); err != nil { // error might occur after Slot function
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
slots[iter.Hash()] = slot
|
key := iter.Hash()
|
||||||
|
storages[key] = nil
|
||||||
|
storageOrigins[key] = slot
|
||||||
|
|
||||||
if err := stack.Update(iter.Hash().Bytes(), slot); err != nil {
|
if err := stack.Update(key.Bytes(), slot); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := iter.Error(); err != nil { // error might occur during iteration
|
if err := iter.Error(); err != nil { // error might occur during iteration
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
if stack.Hash() != root {
|
if stack.Hash() != root {
|
||||||
return nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash())
|
return nil, nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash())
|
||||||
}
|
}
|
||||||
return slots, nodes, nil
|
return storages, storageOrigins, nodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// slowDeleteStorage serves as a less-efficient alternative to "fastDeleteStorage,"
|
// slowDeleteStorage serves as a less-efficient alternative to "fastDeleteStorage,"
|
||||||
// employed when the associated state snapshot is not available. It iterates the
|
// employed when the associated state snapshot is not available. It iterates the
|
||||||
// storage slots along with all internal trie nodes via trie directly.
|
// storage slots along with all internal trie nodes via trie directly.
|
||||||
func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
|
func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||||
tr, err := s.db.OpenStorageTrie(s.originalRoot, addr, root, s.trie)
|
tr, err := s.db.OpenStorageTrie(s.originalRoot, addr, root, s.trie)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err)
|
return nil, nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err)
|
||||||
}
|
}
|
||||||
it, err := tr.NodeIterator(nil)
|
it, err := tr.NodeIterator(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err)
|
return nil, nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err)
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
nodes = trienode.NewNodeSet(addrHash)
|
nodes = trienode.NewNodeSet(addrHash) // the set for trie node mutations (value is nil)
|
||||||
slots = make(map[common.Hash][]byte)
|
storages = make(map[common.Hash][]byte) // the set for storage mutations (value is nil)
|
||||||
|
storageOrigins = make(map[common.Hash][]byte) // the set for tracking the original value of slot
|
||||||
)
|
)
|
||||||
for it.Next(true) {
|
for it.Next(true) {
|
||||||
if it.Leaf() {
|
if it.Leaf() {
|
||||||
slots[common.BytesToHash(it.LeafKey())] = common.CopyBytes(it.LeafBlob())
|
key := common.BytesToHash(it.LeafKey())
|
||||||
|
storages[key] = nil
|
||||||
|
storageOrigins[key] = common.CopyBytes(it.LeafBlob())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if it.Hash() == (common.Hash{}) {
|
if it.Hash() == (common.Hash{}) {
|
||||||
|
|
@ -993,35 +999,36 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r
|
||||||
nodes.AddNode(it.Path(), trienode.NewDeleted())
|
nodes.AddNode(it.Path(), trienode.NewDeleted())
|
||||||
}
|
}
|
||||||
if err := it.Error(); err != nil {
|
if err := it.Error(); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
return slots, nodes, nil
|
return storages, storageOrigins, nodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteStorage is designed to delete the storage trie of a designated account.
|
// deleteStorage is designed to delete the storage trie of a designated account.
|
||||||
// The function will make an attempt to utilize an efficient strategy if the
|
// The function will make an attempt to utilize an efficient strategy if the
|
||||||
// associated state snapshot is reachable; otherwise, it will resort to a less
|
// associated state snapshot is reachable; otherwise, it will resort to a less
|
||||||
// efficient approach.
|
// efficient approach.
|
||||||
func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
|
func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
slots map[common.Hash][]byte
|
nodes *trienode.NodeSet // the set for trie node mutations (value is nil)
|
||||||
nodes *trienode.NodeSet
|
storages map[common.Hash][]byte // the set for storage mutations (value is nil)
|
||||||
|
storageOrigins map[common.Hash][]byte // the set for tracking the original value of slot
|
||||||
)
|
)
|
||||||
// The fast approach can be failed if the snapshot is not fully
|
// The fast approach can be failed if the snapshot is not fully
|
||||||
// generated, or it's internally corrupted. Fallback to the slow
|
// generated, or it's internally corrupted. Fallback to the slow
|
||||||
// one just in case.
|
// one just in case.
|
||||||
snaps := s.db.Snapshot()
|
snaps := s.db.Snapshot()
|
||||||
if snaps != nil {
|
if snaps != nil {
|
||||||
slots, nodes, err = s.fastDeleteStorage(snaps, addrHash, root)
|
storages, storageOrigins, nodes, err = s.fastDeleteStorage(snaps, addrHash, root)
|
||||||
}
|
}
|
||||||
if snaps == nil || err != nil {
|
if snaps == nil || err != nil {
|
||||||
slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root)
|
storages, storageOrigins, nodes, err = s.slowDeleteStorage(addr, addrHash, root)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
return slots, nodes, nil
|
return storages, storageOrigins, nodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleDestruction processes all destruction markers and deletes the account
|
// handleDestruction processes all destruction markers and deletes the account
|
||||||
|
|
@ -1068,16 +1075,16 @@ func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trieno
|
||||||
deletes[addrHash] = op
|
deletes[addrHash] = op
|
||||||
|
|
||||||
// Short circuit if the origin storage was empty.
|
// Short circuit if the origin storage was empty.
|
||||||
|
|
||||||
if prev.Root == types.EmptyRootHash || s.db.TrieDB().IsVerkle() {
|
if prev.Root == types.EmptyRootHash || s.db.TrieDB().IsVerkle() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Remove storage slots belonging to the account.
|
// Remove storage slots belonging to the account.
|
||||||
slots, set, err := s.deleteStorage(addr, addrHash, prev.Root)
|
storages, storagesOrigin, set, err := s.deleteStorage(addr, addrHash, prev.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to delete storage, err: %w", err)
|
return nil, nil, fmt.Errorf("failed to delete storage, err: %w", err)
|
||||||
}
|
}
|
||||||
op.storagesOrigin = slots
|
op.storages = storages
|
||||||
|
op.storagesOrigin = storagesOrigin
|
||||||
|
|
||||||
// Aggregate the associated trie node changes.
|
// Aggregate the associated trie node changes.
|
||||||
nodes = append(nodes, set)
|
nodes = append(nodes, set)
|
||||||
|
|
@ -1267,7 +1274,7 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateU
|
||||||
// If snapshotting is enabled, update the snapshot tree with this new version
|
// If snapshotting is enabled, update the snapshot tree with this new version
|
||||||
if snap := s.db.Snapshot(); snap != nil && snap.Snapshot(ret.originRoot) != nil {
|
if snap := s.db.Snapshot(); snap != nil && snap.Snapshot(ret.originRoot) != nil {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := snap.Update(ret.root, ret.originRoot, ret.destructs, ret.accounts, ret.storages); err != nil {
|
if err := snap.Update(ret.root, ret.originRoot, ret.accounts, ret.storages); err != nil {
|
||||||
log.Warn("Failed to update snapshot tree", "from", ret.originRoot, "to", ret.root, "err", err)
|
log.Warn("Failed to update snapshot tree", "from", ret.originRoot, "to", ret.root, "err", err)
|
||||||
}
|
}
|
||||||
// Keep 128 diff layers in the memory, persistent layer is 129th.
|
// Keep 128 diff layers in the memory, persistent layer is 129th.
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
@ -176,24 +177,16 @@ func (test *stateTest) String() string {
|
||||||
|
|
||||||
func (test *stateTest) run() bool {
|
func (test *stateTest) run() bool {
|
||||||
var (
|
var (
|
||||||
roots []common.Hash
|
roots []common.Hash
|
||||||
accountList []map[common.Address][]byte
|
accounts []map[common.Hash][]byte
|
||||||
storageList []map[common.Address]map[common.Hash][]byte
|
accountOrigin []map[common.Address][]byte
|
||||||
copyUpdate = func(update *stateUpdate) {
|
storages []map[common.Hash]map[common.Hash][]byte
|
||||||
accounts := make(map[common.Address][]byte, len(update.accountsOrigin))
|
storageOrigin []map[common.Address]map[common.Hash][]byte
|
||||||
for key, val := range update.accountsOrigin {
|
copyUpdate = func(update *stateUpdate) {
|
||||||
accounts[key] = common.CopyBytes(val)
|
accounts = append(accounts, maps.Clone(update.accounts))
|
||||||
}
|
accountOrigin = append(accountOrigin, maps.Clone(update.accountsOrigin))
|
||||||
accountList = append(accountList, accounts)
|
storages = append(storages, maps.Clone(update.storages))
|
||||||
|
storageOrigin = append(storageOrigin, maps.Clone(update.storagesOrigin))
|
||||||
storages := make(map[common.Address]map[common.Hash][]byte, len(update.storagesOrigin))
|
|
||||||
for addr, subset := range update.storagesOrigin {
|
|
||||||
storages[addr] = make(map[common.Hash][]byte, len(subset))
|
|
||||||
for key, val := range subset {
|
|
||||||
storages[addr][key] = common.CopyBytes(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
storageList = append(storageList, storages)
|
|
||||||
}
|
}
|
||||||
disk = rawdb.NewMemoryDatabase()
|
disk = rawdb.NewMemoryDatabase()
|
||||||
tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults})
|
tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults})
|
||||||
|
|
@ -250,7 +243,7 @@ func (test *stateTest) run() bool {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
root = roots[i-1]
|
root = roots[i-1]
|
||||||
}
|
}
|
||||||
test.err = test.verify(root, roots[i], tdb, accountList[i], storageList[i])
|
test.err = test.verify(root, roots[i], tdb, accounts[i], accountOrigin[i], storages[i], storageOrigin[i])
|
||||||
if test.err != nil {
|
if test.err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -265,7 +258,7 @@ func (test *stateTest) run() bool {
|
||||||
// - the account was indeed not present in trie
|
// - the account was indeed not present in trie
|
||||||
// - the account is present in new trie, nil->nil is regarded as invalid
|
// - the account is present in new trie, nil->nil is regarded as invalid
|
||||||
// - the slots transition is correct
|
// - the slots transition is correct
|
||||||
func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Database, otr, ntr *trie.Trie, addr common.Address, slots map[common.Hash][]byte) error {
|
func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Database, otr, ntr *trie.Trie, addr common.Address, account []byte, storages map[common.Hash][]byte, storagesOrigin map[common.Hash][]byte) error {
|
||||||
// Verify account change
|
// Verify account change
|
||||||
addrHash := crypto.Keccak256Hash(addr.Bytes())
|
addrHash := crypto.Keccak256Hash(addr.Bytes())
|
||||||
oBlob, err := otr.Get(addrHash.Bytes())
|
oBlob, err := otr.Get(addrHash.Bytes())
|
||||||
|
|
@ -282,6 +275,13 @@ func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Databa
|
||||||
if len(nBlob) == 0 {
|
if len(nBlob) == 0 {
|
||||||
return fmt.Errorf("missing account in new trie, %x", addrHash)
|
return fmt.Errorf("missing account in new trie, %x", addrHash)
|
||||||
}
|
}
|
||||||
|
full, err := types.FullAccountRLP(account)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !bytes.Equal(nBlob, full) {
|
||||||
|
return fmt.Errorf("unexpected account data, want: %v, got: %v", full, nBlob)
|
||||||
|
}
|
||||||
|
|
||||||
// Verify storage changes
|
// Verify storage changes
|
||||||
var nAcct types.StateAccount
|
var nAcct types.StateAccount
|
||||||
|
|
@ -290,7 +290,10 @@ func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Databa
|
||||||
}
|
}
|
||||||
// Account has no slot, empty slot set is expected
|
// Account has no slot, empty slot set is expected
|
||||||
if nAcct.Root == types.EmptyRootHash {
|
if nAcct.Root == types.EmptyRootHash {
|
||||||
if len(slots) != 0 {
|
if len(storagesOrigin) != 0 {
|
||||||
|
return fmt.Errorf("unexpected slot changes %x", addrHash)
|
||||||
|
}
|
||||||
|
if len(storages) != 0 {
|
||||||
return fmt.Errorf("unexpected slot changes %x", addrHash)
|
return fmt.Errorf("unexpected slot changes %x", addrHash)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -300,9 +303,22 @@ func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Databa
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for key, val := range slots {
|
for key, val := range storagesOrigin {
|
||||||
|
if _, exist := storages[key]; !exist {
|
||||||
|
return errors.New("storage data is not found")
|
||||||
|
}
|
||||||
|
got, err := st.Get(key.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !bytes.Equal(got, storages[key]) {
|
||||||
|
return fmt.Errorf("unexpected storage data, want: %v, got: %v", storages[key], got)
|
||||||
|
}
|
||||||
st.Update(key.Bytes(), val)
|
st.Update(key.Bytes(), val)
|
||||||
}
|
}
|
||||||
|
if len(storagesOrigin) != len(storages) {
|
||||||
|
return fmt.Errorf("extra storage found, want: %d, got: %d", len(storagesOrigin), len(storages))
|
||||||
|
}
|
||||||
if st.Hash() != types.EmptyRootHash {
|
if st.Hash() != types.EmptyRootHash {
|
||||||
return errors.New("invalid slot changes")
|
return errors.New("invalid slot changes")
|
||||||
}
|
}
|
||||||
|
|
@ -316,7 +332,7 @@ func (test *stateTest) verifyAccountCreation(next common.Hash, db *triedb.Databa
|
||||||
// - the account was indeed present in trie
|
// - the account was indeed present in trie
|
||||||
// - the account in old trie matches the provided value
|
// - the account in old trie matches the provided value
|
||||||
// - the slots transition is correct
|
// - the slots transition is correct
|
||||||
func (test *stateTest) verifyAccountUpdate(next common.Hash, db *triedb.Database, otr, ntr *trie.Trie, addr common.Address, origin []byte, slots map[common.Hash][]byte) error {
|
func (test *stateTest) verifyAccountUpdate(next common.Hash, db *triedb.Database, otr, ntr *trie.Trie, addr common.Address, account []byte, accountOrigin []byte, storages map[common.Hash][]byte, storageOrigin map[common.Hash][]byte) error {
|
||||||
// Verify account change
|
// Verify account change
|
||||||
addrHash := crypto.Keccak256Hash(addr.Bytes())
|
addrHash := crypto.Keccak256Hash(addr.Bytes())
|
||||||
oBlob, err := otr.Get(addrHash.Bytes())
|
oBlob, err := otr.Get(addrHash.Bytes())
|
||||||
|
|
@ -330,14 +346,23 @@ func (test *stateTest) verifyAccountUpdate(next common.Hash, db *triedb.Database
|
||||||
if len(oBlob) == 0 {
|
if len(oBlob) == 0 {
|
||||||
return fmt.Errorf("missing account in old trie, %x", addrHash)
|
return fmt.Errorf("missing account in old trie, %x", addrHash)
|
||||||
}
|
}
|
||||||
full, err := types.FullAccountRLP(origin)
|
full, err := types.FullAccountRLP(accountOrigin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !bytes.Equal(full, oBlob) {
|
if !bytes.Equal(full, oBlob) {
|
||||||
return fmt.Errorf("account value is not matched, %x", addrHash)
|
return fmt.Errorf("account value is not matched, %x", addrHash)
|
||||||
}
|
}
|
||||||
|
if len(nBlob) == 0 {
|
||||||
|
if len(account) != 0 {
|
||||||
|
return errors.New("unexpected account data")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
full, _ = types.FullAccountRLP(account)
|
||||||
|
if !bytes.Equal(full, nBlob) {
|
||||||
|
return fmt.Errorf("unexpected account data, %x, want %v, got: %v", addrHash, full, nBlob)
|
||||||
|
}
|
||||||
|
}
|
||||||
// Decode accounts
|
// Decode accounts
|
||||||
var (
|
var (
|
||||||
oAcct types.StateAccount
|
oAcct types.StateAccount
|
||||||
|
|
@ -361,16 +386,29 @@ func (test *stateTest) verifyAccountUpdate(next common.Hash, db *triedb.Database
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for key, val := range slots {
|
for key, val := range storageOrigin {
|
||||||
|
if _, exist := storages[key]; !exist {
|
||||||
|
return errors.New("storage data is not found")
|
||||||
|
}
|
||||||
|
got, err := st.Get(key.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !bytes.Equal(got, storages[key]) {
|
||||||
|
return fmt.Errorf("unexpected storage data, want: %v, got: %v", storages[key], got)
|
||||||
|
}
|
||||||
st.Update(key.Bytes(), val)
|
st.Update(key.Bytes(), val)
|
||||||
}
|
}
|
||||||
|
if len(storageOrigin) != len(storages) {
|
||||||
|
return fmt.Errorf("extra storage found, want: %d, got: %d", len(storageOrigin), len(storages))
|
||||||
|
}
|
||||||
if st.Hash() != oAcct.Root {
|
if st.Hash() != oAcct.Root {
|
||||||
return errors.New("invalid slot changes")
|
return errors.New("invalid slot changes")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (test *stateTest) verify(root common.Hash, next common.Hash, db *triedb.Database, accountsOrigin map[common.Address][]byte, storagesOrigin map[common.Address]map[common.Hash][]byte) error {
|
func (test *stateTest) verify(root common.Hash, next common.Hash, db *triedb.Database, accounts map[common.Hash][]byte, accountsOrigin map[common.Address][]byte, storages map[common.Hash]map[common.Hash][]byte, storagesOrigin map[common.Address]map[common.Hash][]byte) error {
|
||||||
otr, err := trie.New(trie.StateTrieID(root), db)
|
otr, err := trie.New(trie.StateTrieID(root), db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -379,12 +417,15 @@ func (test *stateTest) verify(root common.Hash, next common.Hash, db *triedb.Dat
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for addr, account := range accountsOrigin {
|
for addr, accountOrigin := range accountsOrigin {
|
||||||
var err error
|
var (
|
||||||
if len(account) == 0 {
|
err error
|
||||||
err = test.verifyAccountCreation(next, db, otr, ntr, addr, storagesOrigin[addr])
|
addrHash = crypto.Keccak256Hash(addr.Bytes())
|
||||||
|
)
|
||||||
|
if len(accountOrigin) == 0 {
|
||||||
|
err = test.verifyAccountCreation(next, db, otr, ntr, addr, accounts[addrHash], storages[addrHash], storagesOrigin[addr])
|
||||||
} else {
|
} else {
|
||||||
err = test.verifyAccountUpdate(next, db, otr, ntr, addr, accountsOrigin[addr], storagesOrigin[addr])
|
err = test.verifyAccountUpdate(next, db, otr, ntr, addr, accounts[addrHash], accountsOrigin[addr], storages[addrHash], storagesOrigin[addr])
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -1305,12 +1305,12 @@ func TestDeleteStorage(t *testing.T) {
|
||||||
obj := fastState.getOrNewStateObject(addr)
|
obj := fastState.getOrNewStateObject(addr)
|
||||||
storageRoot := obj.data.Root
|
storageRoot := obj.data.Root
|
||||||
|
|
||||||
_, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot)
|
_, _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, slowNodes, err := slowState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot)
|
_, _, slowNodes, err := slowState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"maps"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
|
|
@ -33,6 +35,7 @@ type contractCode struct {
|
||||||
type accountDelete struct {
|
type accountDelete struct {
|
||||||
address common.Address // address is the unique account identifier
|
address common.Address // address is the unique account identifier
|
||||||
origin []byte // origin is the original value of account data in slim-RLP encoding.
|
origin []byte // origin is the original value of account data in slim-RLP encoding.
|
||||||
|
storages map[common.Hash][]byte // storages stores mutated slots, the value should be nil.
|
||||||
storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format.
|
storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,7 +55,6 @@ type accountUpdate struct {
|
||||||
type stateUpdate struct {
|
type stateUpdate struct {
|
||||||
originRoot common.Hash // hash of the state before applying mutation
|
originRoot common.Hash // hash of the state before applying mutation
|
||||||
root common.Hash // hash of the state after applying mutation
|
root common.Hash // hash of the state after applying mutation
|
||||||
destructs map[common.Hash]struct{} // destructs contains the list of destructed accounts
|
|
||||||
accounts map[common.Hash][]byte // accounts stores mutated accounts in 'slim RLP' encoding
|
accounts map[common.Hash][]byte // accounts stores mutated accounts in 'slim RLP' encoding
|
||||||
accountsOrigin map[common.Address][]byte // accountsOrigin stores the original values of mutated accounts in 'slim RLP' encoding
|
accountsOrigin map[common.Address][]byte // accountsOrigin stores the original values of mutated accounts in 'slim RLP' encoding
|
||||||
storages map[common.Hash]map[common.Hash][]byte // storages stores mutated slots in 'prefix-zero-trimmed' RLP format
|
storages map[common.Hash]map[common.Hash][]byte // storages stores mutated slots in 'prefix-zero-trimmed' RLP format
|
||||||
|
|
@ -71,7 +73,6 @@ func (sc *stateUpdate) empty() bool {
|
||||||
// account deletions and account updates to form a comprehensive state update.
|
// account deletions and account updates to form a comprehensive state update.
|
||||||
func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common.Hash]*accountDelete, updates map[common.Hash]*accountUpdate, nodes *trienode.MergedNodeSet) *stateUpdate {
|
func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common.Hash]*accountDelete, updates map[common.Hash]*accountUpdate, nodes *trienode.MergedNodeSet) *stateUpdate {
|
||||||
var (
|
var (
|
||||||
destructs = make(map[common.Hash]struct{})
|
|
||||||
accounts = make(map[common.Hash][]byte)
|
accounts = make(map[common.Hash][]byte)
|
||||||
accountsOrigin = make(map[common.Address][]byte)
|
accountsOrigin = make(map[common.Address][]byte)
|
||||||
storages = make(map[common.Hash]map[common.Hash][]byte)
|
storages = make(map[common.Hash]map[common.Hash][]byte)
|
||||||
|
|
@ -82,8 +83,12 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common
|
||||||
// within the same block, the deletions must be aggregated first.
|
// within the same block, the deletions must be aggregated first.
|
||||||
for addrHash, op := range deletes {
|
for addrHash, op := range deletes {
|
||||||
addr := op.address
|
addr := op.address
|
||||||
destructs[addrHash] = struct{}{}
|
accounts[addrHash] = nil
|
||||||
accountsOrigin[addr] = op.origin
|
accountsOrigin[addr] = op.origin
|
||||||
|
|
||||||
|
if len(op.storages) > 0 {
|
||||||
|
storages[addrHash] = op.storages
|
||||||
|
}
|
||||||
if len(op.storagesOrigin) > 0 {
|
if len(op.storagesOrigin) > 0 {
|
||||||
storagesOrigin[addr] = op.storagesOrigin
|
storagesOrigin[addr] = op.storagesOrigin
|
||||||
}
|
}
|
||||||
|
|
@ -95,35 +100,41 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common
|
||||||
if op.code != nil {
|
if op.code != nil {
|
||||||
codes[addr] = *op.code
|
codes[addr] = *op.code
|
||||||
}
|
}
|
||||||
// Aggregate the account changes. The original account value will only
|
|
||||||
// be tracked if it's not present yet.
|
|
||||||
accounts[addrHash] = op.data
|
accounts[addrHash] = op.data
|
||||||
|
|
||||||
|
// Aggregate the account original value. If the account is already
|
||||||
|
// present in the aggregated accountsOrigin set, skip it.
|
||||||
if _, found := accountsOrigin[addr]; !found {
|
if _, found := accountsOrigin[addr]; !found {
|
||||||
accountsOrigin[addr] = op.origin
|
accountsOrigin[addr] = op.origin
|
||||||
}
|
}
|
||||||
// Aggregate the storage changes. The original storage slot value will
|
// Aggregate the storage mutation list. If a slot in op.storages is
|
||||||
// only be tracked if it's not present yet.
|
// already present in aggregated storages set, the value will be
|
||||||
|
// overwritten.
|
||||||
if len(op.storages) > 0 {
|
if len(op.storages) > 0 {
|
||||||
storages[addrHash] = op.storages
|
if _, exist := storages[addrHash]; !exist {
|
||||||
}
|
storages[addrHash] = op.storages
|
||||||
if len(op.storagesOrigin) > 0 {
|
} else {
|
||||||
origin := storagesOrigin[addr]
|
maps.Copy(storages[addrHash], op.storages)
|
||||||
if origin == nil {
|
|
||||||
storagesOrigin[addr] = op.storagesOrigin
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
for key, slot := range op.storagesOrigin {
|
}
|
||||||
if _, found := origin[key]; !found {
|
// Aggregate the storage original values. If the slot is already present
|
||||||
origin[key] = slot
|
// in aggregated storagesOrigin set, skip it.
|
||||||
|
if len(op.storagesOrigin) > 0 {
|
||||||
|
origin, exist := storagesOrigin[addr]
|
||||||
|
if !exist {
|
||||||
|
storagesOrigin[addr] = op.storagesOrigin
|
||||||
|
} else {
|
||||||
|
for key, slot := range op.storagesOrigin {
|
||||||
|
if _, found := origin[key]; !found {
|
||||||
|
origin[key] = slot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
storagesOrigin[addr] = origin
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &stateUpdate{
|
return &stateUpdate{
|
||||||
originRoot: types.TrieRootHash(originRoot),
|
originRoot: types.TrieRootHash(originRoot),
|
||||||
root: types.TrieRootHash(root),
|
root: types.TrieRootHash(root),
|
||||||
destructs: destructs,
|
|
||||||
accounts: accounts,
|
accounts: accounts,
|
||||||
accountsOrigin: accountsOrigin,
|
accountsOrigin: accountsOrigin,
|
||||||
storages: storages,
|
storages: storages,
|
||||||
|
|
@ -139,7 +150,6 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common
|
||||||
// package.
|
// package.
|
||||||
func (sc *stateUpdate) stateSet() *triedb.StateSet {
|
func (sc *stateUpdate) stateSet() *triedb.StateSet {
|
||||||
return &triedb.StateSet{
|
return &triedb.StateSet{
|
||||||
Destructs: sc.destructs,
|
|
||||||
Accounts: sc.accounts,
|
Accounts: sc.accounts,
|
||||||
AccountsOrigin: sc.accountsOrigin,
|
AccountsOrigin: sc.accountsOrigin,
|
||||||
Storages: sc.storages,
|
Storages: sc.storages,
|
||||||
|
|
|
||||||
|
|
@ -82,10 +82,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
evm := vm.NewEVM(context, tracingStateDB, p.config, cfg)
|
evm := vm.NewEVM(context, tracingStateDB, p.config, cfg)
|
||||||
|
|
||||||
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||||
ProcessBeaconBlockRoot(*beaconRoot, evm, tracingStateDB)
|
ProcessBeaconBlockRoot(*beaconRoot, evm)
|
||||||
}
|
}
|
||||||
if p.config.IsPrague(block.Number(), block.Time()) {
|
if p.config.IsPrague(block.Number(), block.Time()) {
|
||||||
ProcessParentBlockHash(block.ParentHash(), evm, tracingStateDB)
|
ProcessParentBlockHash(block.ParentHash(), evm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
|
|
@ -96,7 +96,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
}
|
}
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
|
|
||||||
receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, evm)
|
receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, tx, usedGas, evm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||||
}
|
}
|
||||||
|
|
@ -113,10 +113,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
}
|
}
|
||||||
requests = append(requests, depositRequests)
|
requests = append(requests, depositRequests)
|
||||||
// EIP-7002 withdrawals
|
// EIP-7002 withdrawals
|
||||||
withdrawalRequests := ProcessWithdrawalQueue(evm, tracingStateDB)
|
withdrawalRequests := ProcessWithdrawalQueue(evm)
|
||||||
requests = append(requests, withdrawalRequests)
|
requests = append(requests, withdrawalRequests)
|
||||||
// EIP-7251 consolidations
|
// EIP-7251 consolidations
|
||||||
consolidationRequests := ProcessConsolidationQueue(evm, tracingStateDB)
|
consolidationRequests := ProcessConsolidationQueue(evm)
|
||||||
requests = append(requests, consolidationRequests)
|
requests = append(requests, consolidationRequests)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,7 +134,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database
|
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database
|
||||||
// and uses the input parameters for its environment similar to ApplyTransaction. However,
|
// and uses the input parameters for its environment similar to ApplyTransaction. However,
|
||||||
// this method takes an already created EVM instance as input.
|
// this method takes an already created EVM instance as input.
|
||||||
func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
|
func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
|
||||||
if hooks := evm.Config.Tracer; hooks != nil {
|
if hooks := evm.Config.Tracer; hooks != nil {
|
||||||
if hooks.OnTxStart != nil {
|
if hooks.OnTxStart != nil {
|
||||||
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
|
|
@ -156,10 +156,10 @@ func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPo
|
||||||
|
|
||||||
// Update the state with pending changes.
|
// Update the state with pending changes.
|
||||||
var root []byte
|
var root []byte
|
||||||
if config.IsByzantium(blockNumber) {
|
if evm.ChainConfig().IsByzantium(blockNumber) {
|
||||||
evm.StateDB.Finalise(true)
|
evm.StateDB.Finalise(true)
|
||||||
} else {
|
} else {
|
||||||
root = statedb.IntermediateRoot(config.IsEIP158(blockNumber)).Bytes()
|
root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes()
|
||||||
}
|
}
|
||||||
*usedGas += result.UsedGas
|
*usedGas += result.UsedGas
|
||||||
|
|
||||||
|
|
@ -208,21 +208,21 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b
|
||||||
// and uses the input parameters for its environment. It returns the receipt
|
// and uses the input parameters for its environment. It returns the receipt
|
||||||
// for the transaction, gas used and an error if the transaction failed,
|
// for the transaction, gas used and an error if the transaction failed,
|
||||||
// indicating the block was invalid.
|
// indicating the block was invalid.
|
||||||
func ApplyTransaction(config *params.ChainConfig, evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, error) {
|
func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, error) {
|
||||||
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number, header.Time), header.BaseFee)
|
msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time), header.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Create a new context to be used in the EVM environment
|
// Create a new context to be used in the EVM environment
|
||||||
return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, evm)
|
return ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), tx, usedGas, evm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
||||||
// contract. This method is exported to be used in tests.
|
// contract. This method is exported to be used in tests.
|
||||||
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb vm.StateDB) {
|
func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) {
|
||||||
if tracer := vmenv.Config.Tracer; tracer != nil {
|
if tracer := evm.Config.Tracer; tracer != nil {
|
||||||
if tracer.OnSystemCallStartV2 != nil {
|
if tracer.OnSystemCallStartV2 != nil {
|
||||||
tracer.OnSystemCallStartV2(vmenv.GetVMContext())
|
tracer.OnSystemCallStartV2(evm.GetVMContext())
|
||||||
} else if tracer.OnSystemCallStart != nil {
|
} else if tracer.OnSystemCallStart != nil {
|
||||||
tracer.OnSystemCallStart()
|
tracer.OnSystemCallStart()
|
||||||
}
|
}
|
||||||
|
|
@ -239,18 +239,18 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb vm.St
|
||||||
To: ¶ms.BeaconRootsAddress,
|
To: ¶ms.BeaconRootsAddress,
|
||||||
Data: beaconRoot[:],
|
Data: beaconRoot[:],
|
||||||
}
|
}
|
||||||
vmenv.SetTxContext(NewEVMTxContext(msg))
|
evm.SetTxContext(NewEVMTxContext(msg))
|
||||||
statedb.AddAddressToAccessList(params.BeaconRootsAddress)
|
evm.StateDB.AddAddressToAccessList(params.BeaconRootsAddress)
|
||||||
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
_, _, _ = evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||||
statedb.Finalise(true)
|
evm.StateDB.Finalise(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessParentBlockHash stores the parent block hash in the history storage contract
|
// ProcessParentBlockHash stores the parent block hash in the history storage contract
|
||||||
// as per EIP-2935.
|
// as per EIP-2935.
|
||||||
func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb vm.StateDB) {
|
func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) {
|
||||||
if tracer := vmenv.Config.Tracer; tracer != nil {
|
if tracer := evm.Config.Tracer; tracer != nil {
|
||||||
if tracer.OnSystemCallStartV2 != nil {
|
if tracer.OnSystemCallStartV2 != nil {
|
||||||
tracer.OnSystemCallStartV2(vmenv.GetVMContext())
|
tracer.OnSystemCallStartV2(evm.GetVMContext())
|
||||||
} else if tracer.OnSystemCallStart != nil {
|
} else if tracer.OnSystemCallStart != nil {
|
||||||
tracer.OnSystemCallStart()
|
tracer.OnSystemCallStart()
|
||||||
}
|
}
|
||||||
|
|
@ -267,28 +267,28 @@ func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb vm.Stat
|
||||||
To: ¶ms.HistoryStorageAddress,
|
To: ¶ms.HistoryStorageAddress,
|
||||||
Data: prevHash.Bytes(),
|
Data: prevHash.Bytes(),
|
||||||
}
|
}
|
||||||
vmenv.SetTxContext(NewEVMTxContext(msg))
|
evm.SetTxContext(NewEVMTxContext(msg))
|
||||||
statedb.AddAddressToAccessList(params.HistoryStorageAddress)
|
evm.StateDB.AddAddressToAccessList(params.HistoryStorageAddress)
|
||||||
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
_, _, _ = evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||||
statedb.Finalise(true)
|
evm.StateDB.Finalise(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract.
|
// ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract.
|
||||||
// It returns the opaque request data returned by the contract.
|
// It returns the opaque request data returned by the contract.
|
||||||
func ProcessWithdrawalQueue(vmenv *vm.EVM, statedb vm.StateDB) []byte {
|
func ProcessWithdrawalQueue(evm *vm.EVM) []byte {
|
||||||
return processRequestsSystemCall(vmenv, statedb, 0x01, params.WithdrawalQueueAddress)
|
return processRequestsSystemCall(evm, 0x01, params.WithdrawalQueueAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract.
|
// ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract.
|
||||||
// It returns the opaque request data returned by the contract.
|
// It returns the opaque request data returned by the contract.
|
||||||
func ProcessConsolidationQueue(vmenv *vm.EVM, statedb vm.StateDB) []byte {
|
func ProcessConsolidationQueue(evm *vm.EVM) []byte {
|
||||||
return processRequestsSystemCall(vmenv, statedb, 0x02, params.ConsolidationQueueAddress)
|
return processRequestsSystemCall(evm, 0x02, params.ConsolidationQueueAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func processRequestsSystemCall(vmenv *vm.EVM, statedb vm.StateDB, requestType byte, addr common.Address) []byte {
|
func processRequestsSystemCall(evm *vm.EVM, requestType byte, addr common.Address) []byte {
|
||||||
if tracer := vmenv.Config.Tracer; tracer != nil {
|
if tracer := evm.Config.Tracer; tracer != nil {
|
||||||
if tracer.OnSystemCallStartV2 != nil {
|
if tracer.OnSystemCallStartV2 != nil {
|
||||||
tracer.OnSystemCallStartV2(vmenv.GetVMContext())
|
tracer.OnSystemCallStartV2(evm.GetVMContext())
|
||||||
} else if tracer.OnSystemCallStart != nil {
|
} else if tracer.OnSystemCallStart != nil {
|
||||||
tracer.OnSystemCallStart()
|
tracer.OnSystemCallStart()
|
||||||
}
|
}
|
||||||
|
|
@ -304,10 +304,10 @@ func processRequestsSystemCall(vmenv *vm.EVM, statedb vm.StateDB, requestType by
|
||||||
GasTipCap: common.Big0,
|
GasTipCap: common.Big0,
|
||||||
To: &addr,
|
To: &addr,
|
||||||
}
|
}
|
||||||
vmenv.SetTxContext(NewEVMTxContext(msg))
|
evm.SetTxContext(NewEVMTxContext(msg))
|
||||||
statedb.AddAddressToAccessList(addr)
|
evm.StateDB.AddAddressToAccessList(addr)
|
||||||
ret, _, _ := vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
ret, _, _ := evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||||
statedb.Finalise(true)
|
evm.StateDB.Finalise(true)
|
||||||
|
|
||||||
// Create withdrawals requestsData with prefix 0x01
|
// Create withdrawals requestsData with prefix 0x01
|
||||||
requestsData := make([]byte, len(ret)+1)
|
requestsData := make([]byte, len(ret)+1)
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ type StateDB interface {
|
||||||
GetBalance(common.Address) *uint256.Int
|
GetBalance(common.Address) *uint256.Int
|
||||||
GetNonce(common.Address) uint64
|
GetNonce(common.Address) uint64
|
||||||
GetCode(common.Address) []byte
|
GetCode(common.Address) []byte
|
||||||
|
GetCodeHash(common.Address) common.Hash
|
||||||
GetState(common.Address, common.Hash) common.Hash
|
GetState(common.Address, common.Hash) common.Hash
|
||||||
GetTransientState(common.Address, common.Hash) common.Hash
|
GetTransientState(common.Address, common.Hash) common.Hash
|
||||||
Exist(common.Address) bool
|
Exist(common.Address) bool
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ func TestProcessParentBlockHash(t *testing.T) {
|
||||||
header := &types.Header{ParentHash: common.Hash{byte(i)}, Number: big.NewInt(int64(i)), Difficulty: new(big.Int)}
|
header := &types.Header{ParentHash: common.Hash{byte(i)}, Number: big.NewInt(int64(i)), Difficulty: new(big.Int)}
|
||||||
vmContext := NewEVMBlockContext(header, nil, new(common.Address))
|
vmContext := NewEVMBlockContext(header, nil, new(common.Address))
|
||||||
evm := vm.NewEVM(vmContext, statedb, params.MergedTestChainConfig, vm.Config{})
|
evm := vm.NewEVM(vmContext, statedb, params.MergedTestChainConfig, vm.Config{})
|
||||||
ProcessParentBlockHash(header.ParentHash, evm, statedb)
|
ProcessParentBlockHash(header.ParentHash, evm)
|
||||||
}
|
}
|
||||||
// Read block hashes for block 0 .. num-1
|
// Read block hashes for block 0 .. num-1
|
||||||
for i := 0; i < num; i++ {
|
for i := 0; i < num; i++ {
|
||||||
|
|
@ -1033,7 +1033,7 @@ func TestProcessVerkleSelfDestructInSameTxWithSelfBeneficiaryAndPrefundedAccount
|
||||||
)
|
)
|
||||||
// Prefund the account, at an address that the contract will be deployed at,
|
// Prefund the account, at an address that the contract will be deployed at,
|
||||||
// before it selfdestrucs. We can therefore check that the account itseld is
|
// before it selfdestrucs. We can therefore check that the account itseld is
|
||||||
// NOT destroyed, which is what the currrent version of the spec requires.
|
// NOT destroyed, which is what the current version of the spec requires.
|
||||||
// TODO(gballet) revisit after the spec has been modified.
|
// TODO(gballet) revisit after the spec has been modified.
|
||||||
gspec.Alloc[contract] = types.Account{
|
gspec.Alloc[contract] = types.Account{
|
||||||
Balance: big.NewInt(100),
|
Balance: big.NewInt(100),
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ func (meta *functionMetadata) checkInputs(stackMin int) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkStackMax checks the if current maximum stack combined with the
|
// checkStackMax checks the if current maximum stack combined with the
|
||||||
// functin max stack will result in a stack overflow, and if so returns an error.
|
// function max stack will result in a stack overflow, and if so returns an error.
|
||||||
func (meta *functionMetadata) checkStackMax(stackMax int) error {
|
func (meta *functionMetadata) checkStackMax(stackMax int) error {
|
||||||
newMaxStack := stackMax + int(meta.maxStackHeight) - int(meta.inputs)
|
newMaxStack := stackMax + int(meta.maxStackHeight) - int(meta.inputs)
|
||||||
if newMaxStack > int(params.StackLimit) {
|
if newMaxStack > int(params.StackLimit) {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
@ -160,7 +161,8 @@ type Config struct {
|
||||||
// only exist on already merged networks.
|
// only exist on already merged networks.
|
||||||
func CreateConsensusEngine(config *params.ChainConfig, db ethdb.Database) (consensus.Engine, error) {
|
func CreateConsensusEngine(config *params.ChainConfig, db ethdb.Database) (consensus.Engine, error) {
|
||||||
if config.TerminalTotalDifficulty == nil {
|
if config.TerminalTotalDifficulty == nil {
|
||||||
return nil, fmt.Errorf("only PoS networks are supported, please transition old ones with Geth v1.13.x")
|
log.Error("Geth only supports PoS networks. Please transition legacy networks using Geth v1.13.x.")
|
||||||
|
return nil, fmt.Errorf("'terminalTotalDifficulty' is not set in genesis block")
|
||||||
}
|
}
|
||||||
// Wrap previously supported consensus engines into their post-merge counterpart
|
// Wrap previously supported consensus engines into their post-merge counterpart
|
||||||
if config.Clique != nil {
|
if config.Clique != nil {
|
||||||
|
|
|
||||||
|
|
@ -238,11 +238,11 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
||||||
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
|
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
|
||||||
evm := vm.NewEVM(context, statedb, eth.blockchain.Config(), vm.Config{})
|
evm := vm.NewEVM(context, statedb, eth.blockchain.Config(), vm.Config{})
|
||||||
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, evm)
|
||||||
}
|
}
|
||||||
// If prague hardfork, insert parent block hash in the state as per EIP-2935.
|
// If prague hardfork, insert parent block hash in the state as per EIP-2935.
|
||||||
if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) {
|
if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) {
|
||||||
core.ProcessParentBlockHash(block.ParentHash(), evm, statedb)
|
core.ProcessParentBlockHash(block.ParentHash(), evm)
|
||||||
}
|
}
|
||||||
if txIndex == 0 && len(block.Transactions()) == 0 {
|
if txIndex == 0 && len(block.Transactions()) == 0 {
|
||||||
return nil, vm.BlockContext{}, statedb, release, nil
|
return nil, vm.BlockContext{}, statedb, release, nil
|
||||||
|
|
|
||||||
|
|
@ -381,11 +381,11 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
||||||
context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil)
|
context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil)
|
||||||
evm := vm.NewEVM(context, statedb, api.backend.ChainConfig(), vm.Config{})
|
evm := vm.NewEVM(context, statedb, api.backend.ChainConfig(), vm.Config{})
|
||||||
if beaconRoot := next.BeaconRoot(); beaconRoot != nil {
|
if beaconRoot := next.BeaconRoot(); beaconRoot != nil {
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, evm)
|
||||||
}
|
}
|
||||||
// Insert parent hash in history contract.
|
// Insert parent hash in history contract.
|
||||||
if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) {
|
if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) {
|
||||||
core.ProcessParentBlockHash(next.ParentHash(), evm, statedb)
|
core.ProcessParentBlockHash(next.ParentHash(), evm)
|
||||||
}
|
}
|
||||||
// Clean out any pending release functions of trace state. Note this
|
// Clean out any pending release functions of trace state. Note this
|
||||||
// step must be done after constructing tracing state, because the
|
// step must be done after constructing tracing state, because the
|
||||||
|
|
@ -537,10 +537,10 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
||||||
)
|
)
|
||||||
evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{})
|
evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{})
|
||||||
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, evm)
|
||||||
}
|
}
|
||||||
if chainConfig.IsPrague(block.Number(), block.Time()) {
|
if chainConfig.IsPrague(block.Number(), block.Time()) {
|
||||||
core.ProcessParentBlockHash(block.ParentHash(), evm, statedb)
|
core.ProcessParentBlockHash(block.ParentHash(), evm)
|
||||||
}
|
}
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
|
|
@ -605,10 +605,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
||||||
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||||
evm := vm.NewEVM(blockCtx, statedb, api.backend.ChainConfig(), vm.Config{})
|
evm := vm.NewEVM(blockCtx, statedb, api.backend.ChainConfig(), vm.Config{})
|
||||||
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, evm)
|
||||||
}
|
}
|
||||||
if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) {
|
if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) {
|
||||||
core.ProcessParentBlockHash(block.ParentHash(), evm, statedb)
|
core.ProcessParentBlockHash(block.ParentHash(), evm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// JS tracers have high overhead. In this case run a parallel
|
// JS tracers have high overhead. In this case run a parallel
|
||||||
|
|
@ -784,10 +784,10 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{})
|
evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{})
|
||||||
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, evm)
|
||||||
}
|
}
|
||||||
if chainConfig.IsPrague(block.Number(), block.Time()) {
|
if chainConfig.IsPrague(block.Number(), block.Time()) {
|
||||||
core.ProcessParentBlockHash(block.ParentHash(), evm, statedb)
|
core.ProcessParentBlockHash(block.ParentHash(), evm)
|
||||||
}
|
}
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
// Prepare the transaction for un-traced execution
|
// Prepare the transaction for un-traced execution
|
||||||
|
|
@ -1037,7 +1037,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
|
||||||
|
|
||||||
// Call Prepare to clear out the statedb access list
|
// Call Prepare to clear out the statedb access list
|
||||||
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
||||||
_, err = core.ApplyTransactionWithEVM(message, api.backend.ChainConfig(), new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, evm)
|
_, err = core.ApplyTransactionWithEVM(message, new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, evm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("tracing failed: %w", err)
|
return nil, fmt.Errorf("tracing failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,26 +363,35 @@ func (t *mdLogger) OnEnter(depth int, typ byte, from common.Address, to common.A
|
||||||
if depth != 0 {
|
if depth != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
create := vm.OpCode(typ) == vm.CREATE
|
if create := vm.OpCode(typ) == vm.CREATE; !create {
|
||||||
if !create {
|
fmt.Fprintf(t.out, "Pre-execution info:\n"+
|
||||||
fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n",
|
" - from: `%v`\n"+
|
||||||
from.String(), to.String(),
|
" - to: `%v`\n"+
|
||||||
input, gas, value)
|
" - data: `%#x`\n"+
|
||||||
|
" - gas: `%d`\n"+
|
||||||
|
" - value: `%v` wei\n",
|
||||||
|
from.String(), to.String(), input, gas, value)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(t.out, "From: `%v`\nCreate at: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n",
|
fmt.Fprintf(t.out, "Pre-execution info:\n"+
|
||||||
from.String(), to.String(),
|
" - from: `%v`\n"+
|
||||||
input, gas, value)
|
" - create: `%v`\n"+
|
||||||
|
" - data: `%#x`\n"+
|
||||||
|
" - gas: `%d`\n"+
|
||||||
|
" - value: `%v` wei\n",
|
||||||
|
from.String(), to.String(), input, gas, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(t.out, `
|
fmt.Fprintf(t.out, `
|
||||||
| Pc | Op | Cost | Stack | RStack | Refund |
|
| Pc | Op | Cost | Refund | Stack |
|
||||||
|-------|-------------|------|-----------|-----------|---------|
|
|-------|-------------|------|-----------|-----------|
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
if depth == 0 {
|
if depth == 0 {
|
||||||
fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n",
|
fmt.Fprintf(t.out, "\nPost-execution info:\n"+
|
||||||
|
" - output: `%#x`\n"+
|
||||||
|
" - consumed gas: `%d`\n"+
|
||||||
|
" - error: `%v`\n",
|
||||||
output, gasUsed, err)
|
output, gasUsed, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -390,7 +399,8 @@ func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, r
|
||||||
// OnOpcode also tracks SLOAD/SSTORE ops to track storage change.
|
// OnOpcode also tracks SLOAD/SSTORE ops to track storage change.
|
||||||
func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||||
stack := scope.StackData()
|
stack := scope.StackData()
|
||||||
fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, vm.OpCode(op).String(), cost)
|
fmt.Fprintf(t.out, "| %4d | %10v | %3d |%10v |", pc, vm.OpCode(op).String(),
|
||||||
|
cost, t.env.StateDB.GetRefund())
|
||||||
|
|
||||||
if !t.cfg.DisableStack {
|
if !t.cfg.DisableStack {
|
||||||
// format stack
|
// format stack
|
||||||
|
|
@ -401,7 +411,6 @@ func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.
|
||||||
b := fmt.Sprintf("[%v]", strings.Join(a, ","))
|
b := fmt.Sprintf("[%v]", strings.Join(a, ","))
|
||||||
fmt.Fprintf(t.out, "%10v |", b)
|
fmt.Fprintf(t.out, "%10v |", b)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(t.out, "%10v |", t.env.StateDB.GetRefund())
|
|
||||||
fmt.Fprintln(t.out, "")
|
fmt.Fprintln(t.out, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(t.out, "Error: %v\n", err)
|
fmt.Fprintf(t.out, "Error: %v\n", err)
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks {
|
||||||
l.hooks = &tracing.Hooks{
|
l.hooks = &tracing.Hooks{
|
||||||
OnTxStart: l.OnTxStart,
|
OnTxStart: l.OnTxStart,
|
||||||
OnSystemCallStart: l.onSystemCallStart,
|
OnSystemCallStart: l.onSystemCallStart,
|
||||||
OnExit: l.OnEnd,
|
OnExit: l.OnExit,
|
||||||
OnOpcode: l.OnOpcode,
|
OnOpcode: l.OnOpcode,
|
||||||
OnFault: l.OnFault,
|
OnFault: l.OnFault,
|
||||||
}
|
}
|
||||||
|
|
@ -152,13 +152,6 @@ func (l *jsonLogger) OnEnter(depth int, typ byte, from common.Address, to common
|
||||||
l.encoder.Encode(frame)
|
l.encoder.Encode(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *jsonLogger) OnEnd(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
|
||||||
if depth > 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
l.OnExit(depth, output, gasUsed, err, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *jsonLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
func (l *jsonLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||||
type endLog struct {
|
type endLog struct {
|
||||||
Output string `json:"output"`
|
Output string `json:"output"`
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
|
||||||
gomath "math"
|
gomath "math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -254,7 +253,7 @@ func (api *TxPoolAPI) Inspect() map[string]map[string]map[string]string {
|
||||||
pending, queue := api.b.TxPoolContent()
|
pending, queue := api.b.TxPoolContent()
|
||||||
|
|
||||||
// Define a formatter to flatten a transaction into a string
|
// Define a formatter to flatten a transaction into a string
|
||||||
var format = func(tx *types.Transaction) string {
|
format := func(tx *types.Transaction) string {
|
||||||
if to := tx.To(); to != nil {
|
if to := tx.To(); to != nil {
|
||||||
return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice())
|
return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice())
|
||||||
}
|
}
|
||||||
|
|
@ -825,7 +824,7 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S
|
||||||
blockOverrides.Apply(&blockCtx)
|
blockOverrides.Apply(&blockCtx)
|
||||||
}
|
}
|
||||||
rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time)
|
rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time)
|
||||||
precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules))
|
precompiles := vm.ActivePrecompiledContracts(rules)
|
||||||
if err := overrides.Apply(state, precompiles); err != nil {
|
if err := overrides.Apply(state, precompiles); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1762,11 +1761,11 @@ func (api *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs,
|
||||||
matchTx := sendArgs.ToTransaction(types.LegacyTxType)
|
matchTx := sendArgs.ToTransaction(types.LegacyTxType)
|
||||||
|
|
||||||
// Before replacing the old transaction, ensure the _new_ transaction fee is reasonable.
|
// Before replacing the old transaction, ensure the _new_ transaction fee is reasonable.
|
||||||
var price = matchTx.GasPrice()
|
price := matchTx.GasPrice()
|
||||||
if gasPrice != nil {
|
if gasPrice != nil {
|
||||||
price = gasPrice.ToInt()
|
price = gasPrice.ToInt()
|
||||||
}
|
}
|
||||||
var gas = matchTx.Gas()
|
gas := matchTx.Gas()
|
||||||
if gasLimit != nil {
|
if gasLimit != nil {
|
||||||
gas = uint64(*gasLimit)
|
gas = uint64(*gasLimit)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -186,7 +185,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
Tracer: tracer.Hooks(),
|
Tracer: tracer.Hooks(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
var tracingStateDB = vm.StateDB(sim.state)
|
tracingStateDB := vm.StateDB(sim.state)
|
||||||
if hooks := tracer.Hooks(); hooks != nil {
|
if hooks := tracer.Hooks(); hooks != nil {
|
||||||
tracingStateDB = state.NewHookedState(sim.state, hooks)
|
tracingStateDB = state.NewHookedState(sim.state, hooks)
|
||||||
}
|
}
|
||||||
|
|
@ -265,7 +264,7 @@ func repairLogs(calls []simCallResult, hash common.Hash) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sim *simulator) sanitizeCall(call *TransactionArgs, state *state.StateDB, header *types.Header, blockContext vm.BlockContext, gasUsed *uint64) error {
|
func (sim *simulator) sanitizeCall(call *TransactionArgs, state vm.StateDB, header *types.Header, blockContext vm.BlockContext, gasUsed *uint64) error {
|
||||||
if call.Nonce == nil {
|
if call.Nonce == nil {
|
||||||
nonce := state.GetNonce(call.from())
|
nonce := state.GetNonce(call.from())
|
||||||
call.Nonce = (*hexutil.Uint64)(&nonce)
|
call.Nonce = (*hexutil.Uint64)(&nonce)
|
||||||
|
|
@ -289,7 +288,7 @@ func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContra
|
||||||
isMerge = (base.Difficulty.Sign() == 0)
|
isMerge = (base.Difficulty.Sign() == 0)
|
||||||
rules = sim.chainConfig.Rules(base.Number, isMerge, base.Time)
|
rules = sim.chainConfig.Rules(base.Number, isMerge, base.Time)
|
||||||
)
|
)
|
||||||
return maps.Clone(vm.ActivePrecompiledContracts(rules))
|
return vm.ActivePrecompiledContracts(rules)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sanitizeChain checks the chain integrity. Specifically it checks that
|
// sanitizeChain checks the chain integrity. Specifically it checks that
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ func (f *DirectoryFlag) Apply(set *flag.FlagSet) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
eachName(f, func(name string) {
|
eachName(f, func(name string) {
|
||||||
set.Var(&f.Value, f.Name, f.Usage)
|
set.Var(&f.Value, name, f.Usage)
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -172,7 +172,7 @@ func (f *BigFlag) Apply(set *flag.FlagSet) error {
|
||||||
}
|
}
|
||||||
eachName(f, func(name string) {
|
eachName(f, func(name string) {
|
||||||
f.Value = new(big.Int)
|
f.Value = new(big.Int)
|
||||||
set.Var((*bigValue)(f.Value), f.Name, f.Usage)
|
set.Var((*bigValue)(f.Value), name, f.Usage)
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,10 +128,10 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo
|
||||||
}
|
}
|
||||||
requests = append(requests, depositRequests)
|
requests = append(requests, depositRequests)
|
||||||
// EIP-7002 withdrawals
|
// EIP-7002 withdrawals
|
||||||
withdrawalRequests := core.ProcessWithdrawalQueue(work.evm, work.state)
|
withdrawalRequests := core.ProcessWithdrawalQueue(work.evm)
|
||||||
requests = append(requests, withdrawalRequests)
|
requests = append(requests, withdrawalRequests)
|
||||||
// EIP-7251 consolidations
|
// EIP-7251 consolidations
|
||||||
consolidationRequests := core.ProcessConsolidationQueue(work.evm, work.state)
|
consolidationRequests := core.ProcessConsolidationQueue(work.evm)
|
||||||
requests = append(requests, consolidationRequests)
|
requests = append(requests, consolidationRequests)
|
||||||
}
|
}
|
||||||
if requests != nil {
|
if requests != nil {
|
||||||
|
|
@ -231,10 +231,10 @@ func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*envir
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if header.ParentBeaconRoot != nil {
|
if header.ParentBeaconRoot != nil {
|
||||||
core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm, env.state)
|
core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm)
|
||||||
}
|
}
|
||||||
if miner.chainConfig.IsPrague(header.Number, header.Time) {
|
if miner.chainConfig.IsPrague(header.Number, header.Time) {
|
||||||
core.ProcessParentBlockHash(header.ParentHash, env.evm, env.state)
|
core.ProcessParentBlockHash(header.ParentHash, env.evm)
|
||||||
}
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
@ -309,7 +309,7 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*
|
||||||
snap = env.state.Snapshot()
|
snap = env.state.Snapshot()
|
||||||
gp = env.gasPool.Gas()
|
gp = env.gasPool.Gas()
|
||||||
)
|
)
|
||||||
receipt, err := core.ApplyTransaction(miner.chainConfig, env.evm, env.gasPool, env.state, env.header, tx, &env.header.GasUsed)
|
receipt, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx, &env.header.GasUsed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
env.state.RevertToSnapshot(snap)
|
env.state.RevertToSnapshot(snap)
|
||||||
env.gasPool.SetGas(gp)
|
env.gasPool.SetGas(gp)
|
||||||
|
|
|
||||||
|
|
@ -676,7 +676,7 @@ func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interf
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return math.U256Bytes(b), nil
|
return math.U256Bytes(new(big.Int).Set(b)), nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unrecognized type '%s'", encType)
|
return nil, fmt.Errorf("unrecognized type '%s'", encType)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ func (t *Trie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
|
||||||
for len(key) > 0 && tn != nil {
|
for len(key) > 0 && tn != nil {
|
||||||
switch n := tn.(type) {
|
switch n := tn.(type) {
|
||||||
case *shortNode:
|
case *shortNode:
|
||||||
if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) {
|
if !bytes.HasPrefix(key, n.Key) {
|
||||||
// The trie doesn't contain the key.
|
// The trie doesn't contain the key.
|
||||||
tn = nil
|
tn = nil
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -371,7 +371,7 @@ func unset(parent node, child node, key []byte, pos int, removeLeft bool) error
|
||||||
}
|
}
|
||||||
return unset(cld, cld.Children[key[pos]], key, pos+1, removeLeft)
|
return unset(cld, cld.Children[key[pos]], key, pos+1, removeLeft)
|
||||||
case *shortNode:
|
case *shortNode:
|
||||||
if len(key[pos:]) < len(cld.Key) || !bytes.Equal(cld.Key, key[pos:pos+len(cld.Key)]) {
|
if !bytes.HasPrefix(key[pos:], cld.Key) {
|
||||||
// Find the fork point, it's a non-existent branch.
|
// Find the fork point, it's a non-existent branch.
|
||||||
if removeLeft {
|
if removeLeft {
|
||||||
if bytes.Compare(cld.Key, key[pos:]) < 0 {
|
if bytes.Compare(cld.Key, key[pos:]) < 0 {
|
||||||
|
|
@ -434,7 +434,7 @@ func hasRightElement(node node, key []byte) bool {
|
||||||
}
|
}
|
||||||
node, pos = rn.Children[key[pos]], pos+1
|
node, pos = rn.Children[key[pos]], pos+1
|
||||||
case *shortNode:
|
case *shortNode:
|
||||||
if len(key)-pos < len(rn.Key) || !bytes.Equal(rn.Key, key[pos:pos+len(rn.Key)]) {
|
if !bytes.HasPrefix(key[pos:], rn.Key) {
|
||||||
return bytes.Compare(rn.Key, key[pos:]) > 0
|
return bytes.Compare(rn.Key, key[pos:]) > 0
|
||||||
}
|
}
|
||||||
node, pos = rn.Val, pos+len(rn.Key)
|
node, pos = rn.Val, pos+len(rn.Key)
|
||||||
|
|
@ -589,7 +589,7 @@ func get(tn node, key []byte, skipResolved bool) ([]byte, node) {
|
||||||
for {
|
for {
|
||||||
switch n := tn.(type) {
|
switch n := tn.(type) {
|
||||||
case *shortNode:
|
case *shortNode:
|
||||||
if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) {
|
if !bytes.HasPrefix(key, n.Key) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
tn = n.Val
|
tn = n.Val
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode no
|
||||||
case valueNode:
|
case valueNode:
|
||||||
return n, n, false, nil
|
return n, n, false, nil
|
||||||
case *shortNode:
|
case *shortNode:
|
||||||
if len(key)-pos < len(n.Key) || !bytes.Equal(n.Key, key[pos:pos+len(n.Key)]) {
|
if !bytes.HasPrefix(key[pos:], n.Key) {
|
||||||
// key not found in trie
|
// key not found in trie
|
||||||
return nil, n, false, nil
|
return nil, n, false, nil
|
||||||
}
|
}
|
||||||
|
|
@ -219,9 +219,6 @@ func (t *Trie) GetNode(path []byte) ([]byte, int, error) {
|
||||||
if resolved > 0 {
|
if resolved > 0 {
|
||||||
t.root = newroot
|
t.root = newroot
|
||||||
}
|
}
|
||||||
if item == nil {
|
|
||||||
return nil, resolved, nil
|
|
||||||
}
|
|
||||||
return item, resolved, nil
|
return item, resolved, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -254,7 +251,7 @@ func (t *Trie) getNode(origNode node, path []byte, pos int) (item []byte, newnod
|
||||||
return nil, nil, 0, nil
|
return nil, nil, 0, nil
|
||||||
|
|
||||||
case *shortNode:
|
case *shortNode:
|
||||||
if len(path)-pos < len(n.Key) || !bytes.Equal(n.Key, path[pos:pos+len(n.Key)]) {
|
if !bytes.HasPrefix(path[pos:], n.Key) {
|
||||||
// Path branches off from short node
|
// Path branches off from short node
|
||||||
return nil, n, 0, nil
|
return nil, n, 0, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ func StorageIndex(storageKey []byte) (*uint256.Int, byte) {
|
||||||
// The first MAIN_STORAGE_OFFSET group will see its
|
// The first MAIN_STORAGE_OFFSET group will see its
|
||||||
// first 64 slots unreachable. This is either a typo in the
|
// first 64 slots unreachable. This is either a typo in the
|
||||||
// spec or intended to conserve the 256-u256
|
// spec or intended to conserve the 256-u256
|
||||||
// aligment. If we decide to ever access these 64
|
// alignment. If we decide to ever access these 64
|
||||||
// slots, uncomment this.
|
// slots, uncomment this.
|
||||||
// // Get the new offset since we now know that we are above 64.
|
// // Get the new offset since we now know that we are above 64.
|
||||||
// pos.Sub(&pos, codeStorageDelta)
|
// pos.Sub(&pos, codeStorageDelta)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import (
|
||||||
|
|
||||||
// StateSet represents a collection of mutated states during a state transition.
|
// StateSet represents a collection of mutated states during a state transition.
|
||||||
type StateSet struct {
|
type StateSet struct {
|
||||||
Destructs map[common.Hash]struct{} // Destructed accounts
|
|
||||||
Accounts map[common.Hash][]byte // Mutated accounts in 'slim RLP' encoding
|
Accounts map[common.Hash][]byte // Mutated accounts in 'slim RLP' encoding
|
||||||
AccountsOrigin map[common.Address][]byte // Original values of mutated accounts in 'slim RLP' encoding
|
AccountsOrigin map[common.Address][]byte // Original values of mutated accounts in 'slim RLP' encoding
|
||||||
Storages map[common.Hash]map[common.Hash][]byte // Mutated storage slots in 'prefix-zero-trimmed' RLP format
|
Storages map[common.Hash]map[common.Hash][]byte // Mutated storage slots in 'prefix-zero-trimmed' RLP format
|
||||||
|
|
@ -33,7 +32,6 @@ type StateSet struct {
|
||||||
// NewStateSet initializes an empty state set.
|
// NewStateSet initializes an empty state set.
|
||||||
func NewStateSet() *StateSet {
|
func NewStateSet() *StateSet {
|
||||||
return &StateSet{
|
return &StateSet{
|
||||||
Destructs: make(map[common.Hash]struct{}),
|
|
||||||
Accounts: make(map[common.Hash][]byte),
|
Accounts: make(map[common.Hash][]byte),
|
||||||
AccountsOrigin: make(map[common.Address][]byte),
|
AccountsOrigin: make(map[common.Address][]byte),
|
||||||
Storages: make(map[common.Hash]map[common.Hash][]byte),
|
Storages: make(map[common.Hash]map[common.Hash][]byte),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue