mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
Code sync to go-ethereum v1.13.14 (#1152)
* all changes from v.13.2-x branch * squash initial changes * remove unneeded files * fix lint * gas estimation fix * accounts/keystore: fix test with sleep * rpc fixes * try with a smaller limit * logging * change the trim fn * remove main_test from rpc * txpool: remove unused "PendingFrom" * set local-txs-enabled in load tests * ready to format * format: remove upstream go-ethereum * format: rename packages as fork * Revert "format: remove avalanche header" This reverts commit 09d505bd5e906ac186643061437e665b116b5bf6. * fix logging * deadcode linting * more linting * fix mock * fix unused * expecteds * passing UTs * add comment * unused * resolve some open issues * undo script change * test resillience * fix compile * wip * test is fixed * fix expecteds * nits * fix merge * remove todos * try * try * try * docker stuff * fix * does this work * fix * hardcode for now * fix * hardcode for now * remove TODO comments * fix * make txindexer more similar to upstream * peer/network: move ctx check * enforce tips in miner * align nits with arr4n * remove use of deprecated type core.GenesisAccount * Revert "peer/network: move ctx check" This reverts commit f37bc6bc3ef228bbd6f997b00871aabfcd37403e. * fix ctx check * fix ctx again * undo vm_test changes * reduce diffs with ARR4N's branch * update for enforcing gasTip * unbuffer chan * update to use commit(true) * use TestOnlyAllowDuplicateBlocks * Revert "update to use commit(true)" This reverts commit 4aa9cc9efb36586a93cea9a39842d4d304b584b6. * overflow in state_transition err * add http body limit flag (#1327) * Tail lock revisited (#1328) * avoid modifying the pointer * improve readability * prevent race in tail reading * improve repairTxIndexTail readability * use shared func --------- Co-authored-by: Ceyhun Onur <[email protected]>
This commit is contained in:
committed by
GitHub
co-authored by
Ceyhun Onur
parent
f798683b59
commit
74327ea329
@@ -15,7 +15,6 @@ on:
|
||||
branches:
|
||||
- master
|
||||
|
||||
|
||||
jobs:
|
||||
publish_docker_image:
|
||||
name: Publish Docker Image
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ import (
|
||||
)
|
||||
|
||||
// The ABI holds information about a contract's context and available
|
||||
// invokable methods. It will allow you to type check function calls and
|
||||
// invocable methods. It will allow you to type check function calls and
|
||||
// packs data accordingly.
|
||||
type ABI struct {
|
||||
Constructor Method
|
||||
|
||||
@@ -94,6 +94,11 @@ type BlockHashContractCaller interface {
|
||||
// used when the user does not provide some needed values, but rather leaves it up
|
||||
// to the transactor to decide.
|
||||
type ContractTransactor interface {
|
||||
interfaces.GasEstimator
|
||||
interfaces.GasPricer
|
||||
interfaces.GasPricer1559
|
||||
interfaces.TransactionSender
|
||||
|
||||
// HeaderByNumber returns a block header from the current canonical chain. If
|
||||
// number is nil, the latest known header is returned.
|
||||
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
|
||||
@@ -101,40 +106,8 @@ type ContractTransactor interface {
|
||||
// AcceptedCodeAt returns the code of the given account in the accepted state.
|
||||
AcceptedCodeAt(ctx context.Context, account common.Address) ([]byte, error)
|
||||
|
||||
// AcceptedNonceAt retrieves the current accepted nonce associated with an account.
|
||||
AcceptedNonceAt(ctx context.Context, account common.Address) (uint64, error)
|
||||
|
||||
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
|
||||
// execution of a transaction.
|
||||
SuggestGasPrice(ctx context.Context) (*big.Int, error)
|
||||
|
||||
// SuggestGasTipCap retrieves the currently suggested 1559 priority fee to allow
|
||||
// a timely execution of a transaction.
|
||||
SuggestGasTipCap(ctx context.Context) (*big.Int, error)
|
||||
|
||||
// EstimateGas tries to estimate the gas needed to execute a specific
|
||||
// transaction based on the current pending state of the backend blockchain.
|
||||
// There is no guarantee that this is the true gas limit requirement as other
|
||||
// transactions may be added or removed by miners, but it should provide a basis
|
||||
// for setting a reasonable default.
|
||||
EstimateGas(ctx context.Context, call interfaces.CallMsg) (gas uint64, err error)
|
||||
|
||||
// SendTransaction injects the transaction into the pending pool for execution.
|
||||
SendTransaction(ctx context.Context, tx *types.Transaction) error
|
||||
}
|
||||
|
||||
// ContractFilterer defines the methods needed to access log events using one-off
|
||||
// queries or continuous event subscriptions.
|
||||
type ContractFilterer interface {
|
||||
// FilterLogs executes a log filter operation, blocking during execution and
|
||||
// returning all the results in one batch.
|
||||
//
|
||||
// TODO(karalabe): Deprecate when the subscription one can return past data too.
|
||||
FilterLogs(ctx context.Context, query interfaces.FilterQuery) ([]types.Log, error)
|
||||
|
||||
// SubscribeFilterLogs creates a background log filtering operation, returning
|
||||
// a subscription immediately, which can be used to stream the found events.
|
||||
SubscribeFilterLogs(ctx context.Context, query interfaces.FilterQuery, ch chan<- types.Log) (interfaces.Subscription, error)
|
||||
// NonceAt retrieves the nonce associated with an account.
|
||||
NonceAt(ctx context.Context, account common.Address, blockNum *big.Int) (uint64, error)
|
||||
}
|
||||
|
||||
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
|
||||
@@ -143,6 +116,12 @@ type DeployBackend interface {
|
||||
CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)
|
||||
}
|
||||
|
||||
// ContractFilterer defines the methods needed to access log events using one-off
|
||||
// queries or continuous event subscriptions.
|
||||
type ContractFilterer interface {
|
||||
interfaces.LogFilterer
|
||||
}
|
||||
|
||||
// ContractBackend defines the methods needed to work with contracts on a read-write basis.
|
||||
type ContractBackend interface {
|
||||
ContractCaller
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -37,6 +37,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/interfaces"
|
||||
"github.com/ava-labs/subnet-evm/rpc"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
@@ -387,7 +388,8 @@ func (c *BoundContract) estimateGasLimit(opts *TransactOpts, contract *common.Ad
|
||||
|
||||
func (c *BoundContract) getNonce(opts *TransactOpts) (uint64, error) {
|
||||
if opts.Nonce == nil {
|
||||
return c.transactor.AcceptedNonceAt(ensureContext(opts.Context), opts.From)
|
||||
pendingBlock := big.NewInt(int64(rpc.PendingBlockNumber))
|
||||
return c.transactor.NonceAt(ensureContext(opts.Context), opts.From, pendingBlock)
|
||||
} else {
|
||||
return opts.Nonce.Uint64(), nil
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ func (mt *mockTransactor) AcceptedCodeAt(ctx context.Context, account common.Add
|
||||
return []byte{1}, nil
|
||||
}
|
||||
|
||||
func (mt *mockTransactor) AcceptedNonceAt(ctx context.Context, account common.Address) (uint64, error) {
|
||||
func (mt *mockTransactor) NonceAt(ctx context.Context, account common.Address, blockNum *big.Int) (uint64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -299,7 +299,7 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -307,7 +307,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy an interaction tester contract and call a transaction on it
|
||||
@@ -315,6 +315,7 @@ var bindTests = []struct {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to deploy interactor contract: %v", err)
|
||||
}
|
||||
sim.Commit(false)
|
||||
if _, err := interactor.Transact(auth, "Transact string"); err != nil {
|
||||
t.Fatalf("Failed to transact with interactor contract: %v", err)
|
||||
}
|
||||
@@ -354,7 +355,7 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -362,7 +363,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a tuple tester contract and execute a structured call on it
|
||||
@@ -400,7 +401,7 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -408,7 +409,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a tuple tester contract and execute a structured call on it
|
||||
@@ -458,7 +459,7 @@ var bindTests = []struct {
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -466,7 +467,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a slice tester contract and execute a n array call on it
|
||||
@@ -506,7 +507,7 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -514,7 +515,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a default method invoker contract and execute its default method
|
||||
@@ -522,6 +523,7 @@ var bindTests = []struct {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to deploy defaulter contract: %v", err)
|
||||
}
|
||||
sim.Commit(false)
|
||||
if _, err := (&DefaulterRaw{defaulter}).Transfer(auth); err != nil {
|
||||
t.Fatalf("Failed to invoke default method: %v", err)
|
||||
}
|
||||
@@ -572,7 +574,7 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -580,7 +582,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a structs method invoker contract and execute its default method
|
||||
@@ -618,12 +620,12 @@ var bindTests = []struct {
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
`,
|
||||
`
|
||||
// Create a simulator and wrap a non-deployed contract
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{}, uint64(10000000000))
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{}, uint64(10000000000))
|
||||
defer sim.Close()
|
||||
|
||||
nonexistent, err := NewNonExistent(common.Address{}, sim)
|
||||
@@ -657,12 +659,12 @@ var bindTests = []struct {
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
`,
|
||||
`
|
||||
// Create a simulator and wrap a non-deployed contract
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{}, uint64(10000000000))
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{}, uint64(10000000000))
|
||||
defer sim.Close()
|
||||
|
||||
nonexistent, err := NewNonExistentStruct(common.Address{}, sim)
|
||||
@@ -704,7 +706,7 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -712,7 +714,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a funky gas pattern contract
|
||||
@@ -754,7 +756,7 @@ var bindTests = []struct {
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -762,7 +764,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a sender tester contract and execute a structured call on it
|
||||
@@ -829,7 +831,7 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -837,7 +839,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a underscorer tester contract and execute a structured call on it
|
||||
@@ -923,7 +925,7 @@ var bindTests = []struct {
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -931,7 +933,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy an eventer contract
|
||||
@@ -1113,7 +1115,7 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -1121,7 +1123,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
//deploy the test contract
|
||||
@@ -1248,7 +1250,7 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
|
||||
@@ -1256,7 +1258,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
_, _, contract, err := DeployTuple(auth, sim)
|
||||
@@ -1390,7 +1392,7 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -1398,7 +1400,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
//deploy the test contract
|
||||
@@ -1456,14 +1458,14 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
// Initialize test accounts
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: new(big.Int).Mul(big.NewInt(10000000000000000), big.NewInt(1000))}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: new(big.Int).Mul(big.NewInt(10000000000000000), big.NewInt(1000))}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// deploy the test contract
|
||||
@@ -1566,7 +1568,7 @@ var bindTests = []struct {
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
`,
|
||||
`
|
||||
// Initialize test accounts
|
||||
@@ -1574,7 +1576,7 @@ var bindTests = []struct {
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
|
||||
// Deploy registrar contract
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: new(big.Int).Mul(big.NewInt(10000000000000000), big.NewInt(1000))}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: new(big.Int).Mul(big.NewInt(10000000000000000), big.NewInt(1000))}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
@@ -1629,14 +1631,14 @@ var bindTests = []struct {
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
`,
|
||||
`
|
||||
key, _ := crypto.GenerateKey()
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
|
||||
// Deploy registrar contract
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
@@ -1690,7 +1692,7 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
@@ -1698,7 +1700,7 @@ var bindTests = []struct {
|
||||
key, _ := crypto.GenerateKey()
|
||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
defer sim.Close()
|
||||
|
||||
// Deploy a tester contract and execute a structured call on it
|
||||
@@ -1751,15 +1753,14 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
key, _ := crypto.GenerateKey()
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
|
||||
|
||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000000000000)}}, 1000000)
|
||||
sim := backends.NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(1000000000000000000)}}, 1000000)
|
||||
defer sim.Close()
|
||||
|
||||
opts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
@@ -1840,14 +1841,14 @@ var bindTests = []struct {
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
var (
|
||||
key, _ = crypto.GenerateKey()
|
||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
)
|
||||
defer sim.Close()
|
||||
|
||||
@@ -1905,18 +1906,19 @@ var bindTests = []struct {
|
||||
[]string{"0x6080604052348015600f57600080fd5b5060998061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063726c638214602d575b600080fd5b60336035565b005b60405163024876cd60e61b815260016004820152600260248201526003604482015260640160405180910390fdfea264697066735822122093f786a1bc60216540cd999fbb4a6109e0fef20abcff6e9107fb2817ca968f3c64736f6c63430008070033"},
|
||||
[]string{`[{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError1","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError2","type":"error"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"},{"internalType":"uint256","name":"c","type":"uint256"}],"name":"MyError3","type":"error"},{"inputs":[],"name":"Error","outputs":[],"stateMutability":"pure","type":"function"}]`},
|
||||
`
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
`
|
||||
var (
|
||||
key, _ = crypto.GenerateKey()
|
||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
)
|
||||
defer sim.Close()
|
||||
|
||||
@@ -1925,7 +1927,7 @@ var bindTests = []struct {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sim.Commit(true)
|
||||
_, err = bind.WaitDeployed(nil, sim, tx)
|
||||
_, err = bind.WaitDeployed(context.Background(), sim, tx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -1956,18 +1958,19 @@ var bindTests = []struct {
|
||||
bytecode: []string{`0x608060405234801561001057600080fd5b506040516101c43803806101c48339818101604052810190610032919061014a565b50610177565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6100958261004c565b810181811067ffffffffffffffff821117156100b4576100b361005d565b5b80604052505050565b60006100c7610038565b90506100d3828261008c565b919050565b6000819050919050565b6100eb816100d8565b81146100f657600080fd5b50565b600081519050610108816100e2565b92915050565b60006020828403121561012457610123610047565b5b61012e60206100bd565b9050600061013e848285016100f9565b60008301525092915050565b6000602082840312156101605761015f610042565b5b600061016e8482850161010e565b91505092915050565b603f806101856000396000f3fe6080604052600080fdfea2646970667358221220cdffa667affecefac5561f65f4a4ba914204a8d4eb859d8cd426fb306e5c12a364736f6c634300080a0033`},
|
||||
abi: []string{`[{"inputs":[{"components":[{"internalType":"uint256","name":"field","type":"uint256"}],"internalType":"struct ConstructorWithStructParam.StructType","name":"st","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"}]`},
|
||||
imports: `
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
tester: `
|
||||
var (
|
||||
key, _ = crypto.GenerateKey()
|
||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, 10000000)
|
||||
)
|
||||
defer sim.Close()
|
||||
|
||||
@@ -1977,7 +1980,7 @@ var bindTests = []struct {
|
||||
}
|
||||
sim.Commit(true)
|
||||
|
||||
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil {
|
||||
if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
|
||||
t.Logf("Deployment tx: %+v", tx)
|
||||
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
|
||||
}
|
||||
@@ -2003,11 +2006,12 @@ var bindTests = []struct {
|
||||
bytecode: []string{"0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033"},
|
||||
abi: []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`},
|
||||
imports: `
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
tester: `
|
||||
@@ -2015,7 +2019,7 @@ var bindTests = []struct {
|
||||
gasCeil = uint64(30000000) // Note: from geth's ethconfig.Defaults.Miner.GasCeil
|
||||
key, _ = crypto.GenerateKey()
|
||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, gasCeil)
|
||||
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, gasCeil)
|
||||
)
|
||||
defer sim.Close()
|
||||
|
||||
@@ -2025,7 +2029,7 @@ var bindTests = []struct {
|
||||
}
|
||||
sim.Commit(true)
|
||||
|
||||
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil {
|
||||
if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
|
||||
t.Logf("Deployment tx: %+v", tx)
|
||||
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
|
||||
}
|
||||
@@ -2043,11 +2047,12 @@ var bindTests = []struct {
|
||||
bytecode: []string{"0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"},
|
||||
abi: []string{`[{"inputs":[{"internalType":"uint256","name":"range","type":"uint256"}],"name":"functionWithKeywordParameter","outputs":[],"stateMutability":"pure","type":"function"}]`},
|
||||
imports: `
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
`,
|
||||
tester: `
|
||||
@@ -2055,7 +2060,7 @@ var bindTests = []struct {
|
||||
gasCeil = uint64(30000000) // Note: from geth's ethconfig.Defaults.Miner.GasCeil
|
||||
key, _ = crypto.GenerateKey()
|
||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, gasCeil)
|
||||
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, gasCeil)
|
||||
)
|
||||
_, tx, _, err := DeployRangeKeyword(user, sim)
|
||||
if err != nil {
|
||||
@@ -2063,7 +2068,7 @@ var bindTests = []struct {
|
||||
}
|
||||
sim.Commit(true)
|
||||
|
||||
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil {
|
||||
if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
|
||||
t.Errorf("error deploying the contract: %v", err)
|
||||
}
|
||||
`,
|
||||
|
||||
@@ -34,9 +34,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind"
|
||||
"github.com/ava-labs/subnet-evm/accounts/abi/bind/backends"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/ethclient/simulated"
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
@@ -65,21 +65,19 @@ var waitDeployedTests = map[string]struct {
|
||||
func TestWaitDeployed(t *testing.T) {
|
||||
t.Parallel()
|
||||
for name, test := range waitDeployedTests {
|
||||
backend := backends.NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
backend := simulated.NewBackend(
|
||||
types.GenesisAlloc{
|
||||
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: new(big.Int).Mul(big.NewInt(10000000000000000), big.NewInt(1000))},
|
||||
},
|
||||
10000000,
|
||||
)
|
||||
defer backend.Close()
|
||||
|
||||
// Create the transaction
|
||||
head, _ := backend.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
|
||||
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
|
||||
head, _ := backend.Client().HeaderByNumber(context.Background(), nil) // Should be child's, good enough
|
||||
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(params.GWei))
|
||||
|
||||
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, gasPrice, common.FromHex(test.code))
|
||||
signer := types.NewLondonSigner(big.NewInt(1337))
|
||||
tx, _ = types.SignTx(tx, signer, testKey)
|
||||
tx, _ = types.SignTx(tx, types.LatestSignerForChainID(big.NewInt(1337)), testKey)
|
||||
|
||||
// Wait for it to get mined in the background.
|
||||
var (
|
||||
@@ -89,13 +87,13 @@ func TestWaitDeployed(t *testing.T) {
|
||||
ctx = context.Background()
|
||||
)
|
||||
go func() {
|
||||
address, err = bind.WaitDeployed(ctx, backend, tx)
|
||||
address, err = bind.WaitDeployed(ctx, backend.Client(), tx)
|
||||
close(mined)
|
||||
}()
|
||||
|
||||
// Send and mine the transaction.
|
||||
if err := backend.SendTransaction(ctx, tx); err != nil {
|
||||
t.Errorf("Failed to send transaction: %s", err)
|
||||
if err := backend.Client().SendTransaction(ctx, tx); err != nil {
|
||||
t.Fatalf("Failed to send transaction: %s", err)
|
||||
}
|
||||
backend.Commit(true)
|
||||
|
||||
@@ -114,42 +112,40 @@ func TestWaitDeployed(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWaitDeployedCornerCases(t *testing.T) {
|
||||
t.Parallel()
|
||||
backend := backends.NewSimulatedBackend(
|
||||
core.GenesisAlloc{
|
||||
backend := simulated.NewBackend(
|
||||
types.GenesisAlloc{
|
||||
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(1000000000000000000)},
|
||||
},
|
||||
10000000,
|
||||
)
|
||||
defer backend.Close()
|
||||
|
||||
head, _ := backend.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
|
||||
head, _ := backend.Client().HeaderByNumber(context.Background(), nil) // Should be child's, good enough
|
||||
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
|
||||
|
||||
// Create a transaction to an account.
|
||||
code := "6060604052600a8060106000396000f360606040526008565b00"
|
||||
tx := types.NewTransaction(0, common.HexToAddress("0x01"), big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
|
||||
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
||||
tx, _ = types.SignTx(tx, types.LatestSigner(params.TestChainConfig), testKey)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
backend.SendTransaction(ctx, tx)
|
||||
backend.Client().SendTransaction(ctx, tx)
|
||||
backend.Commit(true)
|
||||
notContractCreation := errors.New("tx is not contract creation")
|
||||
if _, err := bind.WaitDeployed(ctx, backend, tx); err.Error() != notContractCreation.Error() {
|
||||
if _, err := bind.WaitDeployed(ctx, backend.Client(), tx); err.Error() != notContractCreation.Error() {
|
||||
t.Errorf("error mismatch: want %q, got %q, ", notContractCreation, err)
|
||||
}
|
||||
|
||||
// Create a transaction that is not mined.
|
||||
tx = types.NewContractCreation(1, big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
|
||||
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
||||
tx, _ = types.SignTx(tx, types.LatestSigner(params.TestChainConfig), testKey)
|
||||
|
||||
go func() {
|
||||
contextCanceled := errors.New("context canceled")
|
||||
if _, err := bind.WaitDeployed(ctx, backend, tx); err.Error() != contextCanceled.Error() {
|
||||
if _, err := bind.WaitDeployed(ctx, backend.Client(), tx); err.Error() != contextCanceled.Error() {
|
||||
t.Errorf("error mismatch: want %q, got %q, ", contextCanceled, err)
|
||||
}
|
||||
}()
|
||||
|
||||
backend.SendTransaction(ctx, tx)
|
||||
backend.Client().SendTransaction(ctx, tx)
|
||||
cancel()
|
||||
}
|
||||
|
||||
@@ -36,8 +36,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
var MaxHash = common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
|
||||
|
||||
func TestMakeTopics(t *testing.T) {
|
||||
t.Parallel()
|
||||
type args struct {
|
||||
@@ -86,7 +84,7 @@ func TestMakeTopics(t *testing.T) {
|
||||
{big.NewInt(math.MinInt64)},
|
||||
}},
|
||||
[][]common.Hash{
|
||||
{MaxHash},
|
||||
{common.MaxHash},
|
||||
{common.HexToHash("ffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000")},
|
||||
},
|
||||
false,
|
||||
|
||||
@@ -146,7 +146,7 @@ func (ks keyStorePassphrase) JoinPath(filename string) string {
|
||||
return filepath.Join(ks.keysDirPath, filename)
|
||||
}
|
||||
|
||||
// Encryptdata encrypts the data given as 'data' with the password 'auth'.
|
||||
// EncryptDataV3 encrypts the data given as 'data' with the password 'auth'.
|
||||
func EncryptDataV3(data, auth []byte, scryptN, scryptP int) (CryptoJSON, error) {
|
||||
salt := make([]byte, 32)
|
||||
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
||||
|
||||
@@ -251,7 +251,7 @@ func (hub *Hub) refreshWallets() {
|
||||
card.Disconnect(pcsc.LeaveCard)
|
||||
continue
|
||||
}
|
||||
// Card connected, start tracking in amongs the wallets
|
||||
// Card connected, start tracking among the wallets
|
||||
hub.wallets[reader] = wallet
|
||||
events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived})
|
||||
}
|
||||
|
||||
+1
-1
@@ -214,7 +214,7 @@ exitcode:3 OK
|
||||
|
||||
The chain configuration to be used for a transition is specified via the
|
||||
`--state.fork` CLI flag. A list of possible values and configurations can be
|
||||
found in [`tests/init.go`](tests/init.go).
|
||||
found in [`tests/init.go`](../../tests/init.go).
|
||||
|
||||
#### Examples
|
||||
##### Basic usage
|
||||
|
||||
@@ -38,18 +38,20 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/vm"
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/holiman/uint256"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
type Prestate struct {
|
||||
Env stEnv `json:"env"`
|
||||
Pre core.GenesisAlloc `json:"pre"`
|
||||
Env stEnv `json:"env"`
|
||||
Pre types.GenesisAlloc `json:"pre"`
|
||||
}
|
||||
|
||||
// ExecutionResult contains the execution status after running a state test, any
|
||||
@@ -148,6 +150,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
rejectedTxs []*rejectedTx
|
||||
includedTxs types.Transactions
|
||||
gasUsed = uint64(0)
|
||||
blobGasUsed = uint64(0)
|
||||
receipts = make(types.Receipts, 0)
|
||||
txIndex = 0
|
||||
)
|
||||
@@ -198,7 +201,6 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
|
||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
||||
}
|
||||
var blobGasUsed uint64
|
||||
|
||||
for i := 0; txIt.Next(); i++ {
|
||||
tx, err := txIt.Tx()
|
||||
@@ -219,15 +221,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||
continue
|
||||
}
|
||||
txBlobGas := uint64(0)
|
||||
if tx.Type() == types.BlobTxType {
|
||||
txBlobGas := uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes()))
|
||||
txBlobGas = uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes()))
|
||||
if used, max := blobGasUsed+txBlobGas, uint64(params.MaxBlobGasPerBlock); used > max {
|
||||
err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max)
|
||||
log.Warn("rejected tx", "index", i, "err", err)
|
||||
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||
continue
|
||||
}
|
||||
blobGasUsed += txBlobGas
|
||||
}
|
||||
tracer, err := getTracerFn(txIndex, tx.Hash())
|
||||
if err != nil {
|
||||
@@ -256,6 +258,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
if hashError != nil {
|
||||
return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError)
|
||||
}
|
||||
blobGasUsed += txBlobGas
|
||||
gasUsed += msgResult.UsedGas
|
||||
|
||||
// Receipt:
|
||||
@@ -316,9 +319,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta))
|
||||
reward.Mul(reward, blockReward)
|
||||
reward.Div(reward, big.NewInt(8))
|
||||
statedb.AddBalance(ommer.Address, reward)
|
||||
statedb.AddBalance(ommer.Address, uint256.MustFromBig(reward))
|
||||
}
|
||||
statedb.AddBalance(pre.Env.Coinbase, minerReward)
|
||||
statedb.AddBalance(pre.Env.Coinbase, uint256.MustFromBig(minerReward))
|
||||
}
|
||||
// Commit block
|
||||
root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber), false)
|
||||
@@ -351,13 +354,13 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
return statedb, execRs, body, nil
|
||||
}
|
||||
|
||||
func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB {
|
||||
sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true})
|
||||
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
|
||||
sdb := state.NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
||||
statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
|
||||
for addr, a := range accounts {
|
||||
statedb.SetCode(addr, a.Code)
|
||||
statedb.SetNonce(addr, a.Nonce)
|
||||
statedb.SetBalance(addr, a.Balance)
|
||||
statedb.SetBalance(addr, uint256.MustFromBig(a.Balance))
|
||||
for k, v := range a.Storage {
|
||||
statedb.SetState(addr, k, v)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import (
|
||||
"path"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/consensus/dummy"
|
||||
"github.com/ava-labs/subnet-evm/core"
|
||||
"github.com/ava-labs/subnet-evm/core/state"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/core/vm"
|
||||
@@ -84,10 +83,10 @@ var (
|
||||
)
|
||||
|
||||
type input struct {
|
||||
Alloc core.GenesisAlloc `json:"alloc,omitempty"`
|
||||
Env *stEnv `json:"env,omitempty"`
|
||||
Txs []*txWithKey `json:"txs,omitempty"`
|
||||
TxRlp string `json:"txsRlp,omitempty"`
|
||||
Alloc types.GenesisAlloc `json:"alloc,omitempty"`
|
||||
Env *stEnv `json:"env,omitempty"`
|
||||
Txs []*txWithKey `json:"txs,omitempty"`
|
||||
TxRlp string `json:"txsRlp,omitempty"`
|
||||
}
|
||||
|
||||
func Transition(ctx *cli.Context) error {
|
||||
@@ -198,7 +197,7 @@ func Transition(ctx *cli.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Dump the excution result
|
||||
// Dump the execution result
|
||||
collector := make(Alloc)
|
||||
s.DumpToCollector(collector, nil)
|
||||
return dispatchOutput(ctx, baseDir, result, collector, body)
|
||||
@@ -251,7 +250,7 @@ func applyCancunChecks(env *stEnv, chainConfig *params.ChainConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type Alloc map[common.Address]core.GenesisAccount
|
||||
type Alloc map[common.Address]types.Account
|
||||
|
||||
func (g Alloc) OnRoot(common.Hash) {}
|
||||
|
||||
@@ -259,7 +258,7 @@ func (g Alloc) OnAccount(addr *common.Address, dumpAccount state.DumpAccount) {
|
||||
if addr == nil {
|
||||
return
|
||||
}
|
||||
balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10)
|
||||
balance, _ := new(big.Int).SetString(dumpAccount.Balance, 0)
|
||||
var storage map[common.Hash]common.Hash
|
||||
if dumpAccount.Storage != nil {
|
||||
storage = make(map[common.Hash]common.Hash)
|
||||
@@ -267,7 +266,7 @@ func (g Alloc) OnAccount(addr *common.Address, dumpAccount state.DumpAccount) {
|
||||
storage[k] = common.HexToHash(v)
|
||||
}
|
||||
}
|
||||
genesisAccount := core.GenesisAccount{
|
||||
genesisAccount := types.Account{
|
||||
Code: dumpAccount.Code,
|
||||
Storage: storage,
|
||||
Balance: balance,
|
||||
|
||||
+3
-3
@@ -47,8 +47,8 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/eth/tracers/logger"
|
||||
"github.com/ava-labs/subnet-evm/internal/flags"
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/trie/triedb/hashdb"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ava-labs/subnet-evm/triedb/hashdb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -158,7 +158,7 @@ func runCmd(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
triedb := trie.NewDatabase(db, &trie.Config{
|
||||
triedb := triedb.NewDatabase(db, &triedb.Config{
|
||||
Preimages: preimages,
|
||||
HashDB: hashdb.Defaults,
|
||||
})
|
||||
|
||||
@@ -34,7 +34,6 @@ import (
|
||||
|
||||
"github.com/ava-labs/subnet-evm/core/rawdb"
|
||||
"github.com/ava-labs/subnet-evm/core/state"
|
||||
"github.com/ava-labs/subnet-evm/core/state/snapshot"
|
||||
"github.com/ava-labs/subnet-evm/core/vm"
|
||||
"github.com/ava-labs/subnet-evm/eth/tracers/logger"
|
||||
"github.com/ava-labs/subnet-evm/tests"
|
||||
@@ -100,26 +99,27 @@ func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var tests map[string]tests.StateTest
|
||||
if err := json.Unmarshal(src, &tests); err != nil {
|
||||
var testsByName map[string]tests.StateTest
|
||||
if err := json.Unmarshal(src, &testsByName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Iterate over all the tests, run them and aggregate the results
|
||||
results := make([]StatetestResult, 0, len(tests))
|
||||
for key, test := range tests {
|
||||
results := make([]StatetestResult, 0, len(testsByName))
|
||||
for key, test := range testsByName {
|
||||
for _, st := range test.Subtests() {
|
||||
// Run the test and aggregate the result
|
||||
result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true}
|
||||
test.Run(st, cfg, false, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, statedb *state.StateDB) {
|
||||
test.Run(st, cfg, false, rawdb.HashScheme, func(err error, tstate *tests.StateTestState) {
|
||||
var root common.Hash
|
||||
if statedb != nil {
|
||||
root = statedb.IntermediateRoot(false)
|
||||
if tstate.StateDB != nil {
|
||||
root = tstate.StateDB.IntermediateRoot(false)
|
||||
result.Root = &root
|
||||
if jsonOut {
|
||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||
}
|
||||
if dump { // Dump any state to aid debugging
|
||||
cpy, _ := state.New(root, statedb.Database(), nil)
|
||||
cpy, _ := state.New(root, tstate.StateDB.Database(), nil)
|
||||
dump := cpy.RawDump(nil)
|
||||
result.State = &dump
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ type Env struct {
|
||||
CurrentTimestamp uint64 `json:"currentTimestamp"`
|
||||
Withdrawals []*Withdrawal `json:"withdrawals"`
|
||||
// optional
|
||||
CurrentDifficulty *big.Int `json:"currentDifficuly"`
|
||||
CurrentDifficulty *big.Int `json:"currentDifficulty"`
|
||||
CurrentRandom *big.Int `json:"currentRandom"`
|
||||
CurrentBaseFee *big.Int `json:"currentBaseFee"`
|
||||
ParentDifficulty *big.Int `json:"parentDifficulty"`
|
||||
|
||||
@@ -70,6 +70,13 @@ func NewFakerWithMode(mode Mode) *DummyEngine {
|
||||
}
|
||||
}
|
||||
|
||||
func NewFakerWithModeAndClock(mode Mode, clock *mockable.Clock) *DummyEngine {
|
||||
return &DummyEngine{
|
||||
clock: clock,
|
||||
consensusMode: mode,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCoinbaseFaker() *DummyEngine {
|
||||
return &DummyEngine{
|
||||
clock: &mockable.Clock{},
|
||||
@@ -85,8 +92,8 @@ func NewFullFaker() *DummyEngine {
|
||||
}
|
||||
|
||||
// verifyCoinbase checks that the coinbase is valid for the given [header] and [parent].
|
||||
func (self *DummyEngine) verifyCoinbase(config *params.ChainConfig, header *types.Header, parent *types.Header, chain consensus.ChainHeaderReader) error {
|
||||
if self.consensusMode.ModeSkipCoinbase {
|
||||
func (eng *DummyEngine) verifyCoinbase(config *params.ChainConfig, header *types.Header, parent *types.Header, chain consensus.ChainHeaderReader) error {
|
||||
if eng.consensusMode.ModeSkipCoinbase {
|
||||
return nil
|
||||
}
|
||||
// get the coinbase configured at parent
|
||||
@@ -107,7 +114,7 @@ func (self *DummyEngine) verifyCoinbase(config *params.ChainConfig, header *type
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *DummyEngine) verifyHeaderGasFields(config *params.ChainConfig, header *types.Header, parent *types.Header, chain consensus.ChainHeaderReader) error {
|
||||
func (eng *DummyEngine) verifyHeaderGasFields(config *params.ChainConfig, header *types.Header, parent *types.Header, chain consensus.ChainHeaderReader) error {
|
||||
// Verify that the gas limit is <= 2^63-1
|
||||
if header.GasLimit > params.MaxGasLimit {
|
||||
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit)
|
||||
@@ -192,7 +199,7 @@ func (self *DummyEngine) verifyHeaderGasFields(config *params.ChainConfig, heade
|
||||
}
|
||||
|
||||
// modified from consensus.go
|
||||
func (self *DummyEngine) verifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parent *types.Header, uncle bool) error {
|
||||
func (eng *DummyEngine) verifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parent *types.Header, uncle bool) error {
|
||||
config := chain.Config()
|
||||
// Ensure that we do not verify an uncle
|
||||
if uncle {
|
||||
@@ -213,16 +220,16 @@ func (self *DummyEngine) verifyHeader(chain consensus.ChainHeaderReader, header
|
||||
}
|
||||
}
|
||||
// Ensure gas-related header fields are correct
|
||||
if err := self.verifyHeaderGasFields(config, header, parent, chain); err != nil {
|
||||
if err := eng.verifyHeaderGasFields(config, header, parent, chain); err != nil {
|
||||
return err
|
||||
}
|
||||
// Ensure that coinbase is valid
|
||||
if err := self.verifyCoinbase(config, header, parent, chain); err != nil {
|
||||
if err := eng.verifyCoinbase(config, header, parent, chain); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify the header's timestamp
|
||||
if header.Time > uint64(self.clock.Time().Add(allowedFutureBlockTime).Unix()) {
|
||||
if header.Time > uint64(eng.clock.Time().Add(allowedFutureBlockTime).Unix()) {
|
||||
return consensus.ErrFutureBlock
|
||||
}
|
||||
// Verify the header's timestamp is not earlier than parent's
|
||||
@@ -259,13 +266,13 @@ func (self *DummyEngine) verifyHeader(chain consensus.ChainHeaderReader, header
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *DummyEngine) Author(header *types.Header) (common.Address, error) {
|
||||
func (*DummyEngine) Author(header *types.Header) (common.Address, error) {
|
||||
return header.Coinbase, nil
|
||||
}
|
||||
|
||||
func (self *DummyEngine) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||
func (eng *DummyEngine) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||
// If we're running a full engine faking, accept any input as valid
|
||||
if self.consensusMode.ModeSkipHeader {
|
||||
if eng.consensusMode.ModeSkipHeader {
|
||||
return nil
|
||||
}
|
||||
// Short circuit if the header is known, or it's parent not
|
||||
@@ -278,28 +285,28 @@ func (self *DummyEngine) VerifyHeader(chain consensus.ChainHeaderReader, header
|
||||
return consensus.ErrUnknownAncestor
|
||||
}
|
||||
// Sanity checks passed, do a proper verification
|
||||
return self.verifyHeader(chain, header, parent, false)
|
||||
return eng.verifyHeader(chain, header, parent, false)
|
||||
}
|
||||
|
||||
func (self *DummyEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
|
||||
func (*DummyEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
|
||||
if len(block.Uncles()) > 0 {
|
||||
return errUnclesUnsupported
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *DummyEngine) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||
func (*DummyEngine) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||
header.Difficulty = big.NewInt(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *DummyEngine) verifyBlockFee(
|
||||
func (eng *DummyEngine) verifyBlockFee(
|
||||
baseFee *big.Int,
|
||||
requiredBlockGasCost *big.Int,
|
||||
txs []*types.Transaction,
|
||||
receipts []*types.Receipt,
|
||||
) error {
|
||||
if self.consensusMode.ModeSkipBlockFee {
|
||||
if eng.consensusMode.ModeSkipBlockFee {
|
||||
return nil
|
||||
}
|
||||
if baseFee == nil || baseFee.Sign() <= 0 {
|
||||
@@ -352,7 +359,7 @@ func (self *DummyEngine) verifyBlockFee(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *DummyEngine) Finalize(chain consensus.ChainHeaderReader, block *types.Block, parent *types.Header, state *state.StateDB, receipts []*types.Receipt) error {
|
||||
func (eng *DummyEngine) Finalize(chain consensus.ChainHeaderReader, block *types.Block, parent *types.Header, state *state.StateDB, receipts []*types.Receipt) error {
|
||||
if chain.Config().IsSubnetEVM(block.Time()) {
|
||||
// we use the parent to determine the fee config
|
||||
// since the current block has not been finalized yet.
|
||||
@@ -376,7 +383,7 @@ func (self *DummyEngine) Finalize(chain consensus.ChainHeaderReader, block *type
|
||||
return fmt.Errorf("invalid blockGasCost: have %d, want %d", blockBlockGasCost, blockGasCost)
|
||||
}
|
||||
// Verify the block fee was paid.
|
||||
if err := self.verifyBlockFee(
|
||||
if err := eng.verifyBlockFee(
|
||||
block.BaseFee(),
|
||||
block.BlockGasCost(),
|
||||
block.Transactions(),
|
||||
@@ -389,7 +396,7 @@ func (self *DummyEngine) Finalize(chain consensus.ChainHeaderReader, block *type
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *DummyEngine) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, parent *types.Header, state *state.StateDB, txs []*types.Transaction,
|
||||
func (eng *DummyEngine) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, parent *types.Header, state *state.StateDB, txs []*types.Transaction,
|
||||
uncles []*types.Header, receipts []*types.Receipt,
|
||||
) (*types.Block, error) {
|
||||
if chain.Config().IsSubnetEVM(header.Time) {
|
||||
@@ -409,7 +416,7 @@ func (self *DummyEngine) FinalizeAndAssemble(chain consensus.ChainHeaderReader,
|
||||
parent.Time, header.Time,
|
||||
)
|
||||
// Verify that this block covers the block fee.
|
||||
if err := self.verifyBlockFee(
|
||||
if err := eng.verifyBlockFee(
|
||||
header.BaseFee,
|
||||
header.BlockGasCost,
|
||||
txs,
|
||||
@@ -427,10 +434,10 @@ func (self *DummyEngine) FinalizeAndAssemble(chain consensus.ChainHeaderReader,
|
||||
), nil
|
||||
}
|
||||
|
||||
func (self *DummyEngine) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
|
||||
func (*DummyEngine) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int {
|
||||
return big.NewInt(1)
|
||||
}
|
||||
|
||||
func (self *DummyEngine) Close() error {
|
||||
func (*DummyEngine) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
+11
-6
@@ -175,7 +175,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
||||
// generator function.
|
||||
gspec := &Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: GenesisAlloc{benchRootAddr: {Balance: benchRootFunds}},
|
||||
Alloc: types.GenesisAlloc{benchRootAddr: {Balance: benchRootFunds}},
|
||||
}
|
||||
_, chain, _, _ := GenerateChainWithGenesis(gspec, dummy.NewCoinbaseFaker(), b.N, 10, gen)
|
||||
|
||||
@@ -229,7 +229,7 @@ func BenchmarkChainWrite_full_500k(b *testing.B) {
|
||||
|
||||
// makeChainForBench writes a given number of headers or empty blocks/receipts
|
||||
// into a database.
|
||||
func makeChainForBench(db ethdb.Database, full bool, count uint64) {
|
||||
func makeChainForBench(db ethdb.Database, genesis *Genesis, full bool, count uint64) {
|
||||
var hash common.Hash
|
||||
for n := uint64(0); n < count; n++ {
|
||||
header := &types.Header{
|
||||
@@ -241,13 +241,16 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) {
|
||||
TxHash: types.EmptyTxsHash,
|
||||
ReceiptHash: types.EmptyReceiptsHash,
|
||||
}
|
||||
if n == 0 {
|
||||
header = genesis.ToBlock().Header()
|
||||
}
|
||||
hash = header.Hash()
|
||||
|
||||
rawdb.WriteHeader(db, header)
|
||||
rawdb.WriteCanonicalHash(db, hash, n)
|
||||
|
||||
if n == 0 {
|
||||
rawdb.WriteChainConfig(db, hash, params.TestChainConfig)
|
||||
rawdb.WriteChainConfig(db, hash, genesis.Config)
|
||||
}
|
||||
rawdb.WriteHeadHeaderHash(db, hash)
|
||||
|
||||
@@ -260,13 +263,14 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) {
|
||||
}
|
||||
|
||||
func benchWriteChain(b *testing.B, full bool, count uint64) {
|
||||
genesis := &Genesis{Config: params.TestChainConfig}
|
||||
for i := 0; i < b.N; i++ {
|
||||
dir := b.TempDir()
|
||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false)
|
||||
if err != nil {
|
||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||
}
|
||||
makeChainForBench(db, full, count)
|
||||
makeChainForBench(db, genesis, full, count)
|
||||
db.Close()
|
||||
}
|
||||
}
|
||||
@@ -278,7 +282,8 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||
if err != nil {
|
||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||
}
|
||||
makeChainForBench(db, full, count)
|
||||
genesis := &Genesis{Config: params.TestChainConfig}
|
||||
makeChainForBench(db, genesis, full, count)
|
||||
db.Close()
|
||||
|
||||
b.ReportAllocs()
|
||||
@@ -289,7 +294,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||
if err != nil {
|
||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||
}
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfig, nil, dummy.NewFaker(), vm.Config{}, common.Hash{}, false)
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfig, genesis, dummy.NewFaker(), vm.Config{}, common.Hash{}, false)
|
||||
if err != nil {
|
||||
b.Fatalf("error creating chain: %v", err)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TODO: Add TestHeaderVerification
|
||||
|
||||
func TestCalcGasLimit(t *testing.T) {
|
||||
for i, tc := range []struct {
|
||||
pGasLimit uint64
|
||||
|
||||
+45
-126
@@ -51,8 +51,9 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/metrics"
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/trie/triedb/hashdb"
|
||||
"github.com/ava-labs/subnet-evm/trie/triedb/pathdb"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ava-labs/subnet-evm/triedb/hashdb"
|
||||
"github.com/ava-labs/subnet-evm/triedb/pathdb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/lru"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
@@ -193,8 +194,8 @@ type CacheConfig struct {
|
||||
}
|
||||
|
||||
// triedbConfig derives the configures for trie database.
|
||||
func (c *CacheConfig) triedbConfig() *trie.Config {
|
||||
config := &trie.Config{Preimages: c.Preimages}
|
||||
func (c *CacheConfig) triedbConfig() *triedb.Config {
|
||||
config := &triedb.Config{Preimages: c.Preimages}
|
||||
if c.StateScheme == rawdb.HashScheme {
|
||||
config.HashDB = &hashdb.Config{
|
||||
CleanCacheSize: c.TrieCleanLimit * 1024 * 1024,
|
||||
@@ -234,6 +235,13 @@ func DefaultCacheConfigWithScheme(scheme string) *CacheConfig {
|
||||
return &config
|
||||
}
|
||||
|
||||
// txLookup is wrapper over transaction lookup along with the corresponding
|
||||
// transaction object.
|
||||
type txLookup struct {
|
||||
lookup *rawdb.LegacyTxLookupEntry
|
||||
transaction *types.Transaction
|
||||
}
|
||||
|
||||
// BlockChain represents the canonical chain given a database with a genesis
|
||||
// block. The Blockchain manages chain imports, reverts, chain reorganisations.
|
||||
//
|
||||
@@ -252,10 +260,11 @@ type BlockChain struct {
|
||||
chainConfig *params.ChainConfig // Chain & network configuration
|
||||
cacheConfig *CacheConfig // Cache configuration for pruning
|
||||
|
||||
db ethdb.Database // Low level persistent database to store final content in
|
||||
snaps *snapshot.Tree // Snapshot tree for fast trie leaf access
|
||||
triedb *trie.Database // The database handler for maintaining trie nodes.
|
||||
stateCache state.Database // State database to reuse between imports (contains state cache)
|
||||
db ethdb.Database // Low level persistent database to store final content in
|
||||
snaps *snapshot.Tree // Snapshot tree for fast trie leaf access
|
||||
triedb *triedb.Database // The database handler for maintaining trie nodes.
|
||||
stateCache state.Database // State database to reuse between imports (contains state cache)
|
||||
txIndexer *txIndexer // Transaction indexer, might be nil if not enabled
|
||||
stateManager TrieWriter
|
||||
|
||||
hc *HeaderChain
|
||||
@@ -277,13 +286,13 @@ type BlockChain struct {
|
||||
|
||||
currentBlock atomic.Pointer[types.Header] // Current head of the block chain
|
||||
|
||||
bodyCache *lru.Cache[common.Hash, *types.Body] // Cache for the most recent block bodies
|
||||
receiptsCache *lru.Cache[common.Hash, []*types.Receipt] // Cache for the most recent receipts per block
|
||||
blockCache *lru.Cache[common.Hash, *types.Block] // Cache for the most recent entire blocks
|
||||
txLookupCache *lru.Cache[common.Hash, *rawdb.LegacyTxLookupEntry] // Cache for the most recent transaction lookup data.
|
||||
badBlocks *lru.Cache[common.Hash, *badBlock] // Cache for bad blocks
|
||||
feeConfigCache *lru.Cache[common.Hash, *cacheableFeeConfig] // Cache for the most recent feeConfig lookup data.
|
||||
coinbaseConfigCache *lru.Cache[common.Hash, *cacheableCoinbaseConfig] // Cache for the most recent coinbaseConfig lookup data.
|
||||
bodyCache *lru.Cache[common.Hash, *types.Body] // Cache for the most recent block bodies
|
||||
receiptsCache *lru.Cache[common.Hash, []*types.Receipt] // Cache for the most recent receipts per block
|
||||
blockCache *lru.Cache[common.Hash, *types.Block] // Cache for the most recent entire blocks
|
||||
txLookupCache *lru.Cache[common.Hash, txLookup] // Cache for the most recent transaction lookup data.
|
||||
badBlocks *lru.Cache[common.Hash, *badBlock] // Cache for bad blocks
|
||||
feeConfigCache *lru.Cache[common.Hash, *cacheableFeeConfig] // Cache for the most recent feeConfig lookup data.
|
||||
coinbaseConfigCache *lru.Cache[common.Hash, *cacheableCoinbaseConfig] // Cache for the most recent coinbaseConfig lookup data.
|
||||
|
||||
stopping atomic.Bool // false if chain is running, true when stopped
|
||||
|
||||
@@ -351,7 +360,7 @@ func NewBlockChain(
|
||||
return nil, errCacheConfigNotSpecified
|
||||
}
|
||||
// Open trie database with provided config
|
||||
triedb := trie.NewDatabase(db, cacheConfig.triedbConfig())
|
||||
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig())
|
||||
|
||||
// Setup the genesis block, commit the provided genesis specification
|
||||
// to database if the genesis block is not present yet, or load the
|
||||
@@ -379,7 +388,7 @@ func NewBlockChain(
|
||||
bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit),
|
||||
receiptsCache: lru.NewCache[common.Hash, []*types.Receipt](receiptsCacheLimit),
|
||||
blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit),
|
||||
txLookupCache: lru.NewCache[common.Hash, *rawdb.LegacyTxLookupEntry](txLookupCacheLimit),
|
||||
txLookupCache: lru.NewCache[common.Hash, txLookup](txLookupCacheLimit),
|
||||
badBlocks: lru.NewCache[common.Hash, *badBlock](badBlockLimit),
|
||||
feeConfigCache: lru.NewCache[common.Hash, *cacheableFeeConfig](feeConfigCacheLimit),
|
||||
coinbaseConfigCache: lru.NewCache[common.Hash, *cacheableCoinbaseConfig](coinbaseConfigCacheLimit),
|
||||
@@ -450,113 +459,19 @@ func NewBlockChain(
|
||||
// if txlookup limit is 0 (uindexing disabled), we don't need to repair the tx index tail.
|
||||
if bc.cacheConfig.TransactionHistory != 0 {
|
||||
latestStateSynced := rawdb.GetLatestSyncPerformed(bc.db)
|
||||
bc.setTxIndexTail(latestStateSynced)
|
||||
bc.repairTxIndexTail(latestStateSynced)
|
||||
}
|
||||
|
||||
// Start processing accepted blocks effects in the background
|
||||
go bc.startAcceptor()
|
||||
|
||||
// Start tx indexer/unindexer if required.
|
||||
// Start tx indexer if it's enabled.
|
||||
if bc.cacheConfig.TransactionHistory != 0 {
|
||||
bc.wg.Add(1)
|
||||
var (
|
||||
headCh = make(chan ChainEvent, 1) // Buffered to avoid locking up the event feed
|
||||
sub = bc.SubscribeChainAcceptedEvent(headCh)
|
||||
)
|
||||
go func() {
|
||||
defer bc.wg.Done()
|
||||
if sub == nil {
|
||||
log.Warn("could not create chain accepted subscription to unindex txs")
|
||||
return
|
||||
}
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
bc.maintainTxIndex(headCh)
|
||||
}()
|
||||
bc.txIndexer = newTxIndexer(bc.cacheConfig.TransactionHistory, bc)
|
||||
}
|
||||
return bc, nil
|
||||
}
|
||||
|
||||
// unindexBlocks unindexes transactions depending on user configuration
|
||||
func (bc *BlockChain) unindexBlocks(tail uint64, head uint64, done chan struct{}) {
|
||||
start := time.Now()
|
||||
txLookupLimit := bc.cacheConfig.TransactionHistory
|
||||
bc.txIndexTailLock.Lock()
|
||||
defer func() {
|
||||
txUnindexTimer.Inc(time.Since(start).Milliseconds())
|
||||
bc.txIndexTailLock.Unlock()
|
||||
close(done)
|
||||
bc.wg.Done()
|
||||
}()
|
||||
|
||||
// If head is 0, it means the chain is just initialized and no blocks are inserted,
|
||||
// so don't need to indexing anything.
|
||||
if head == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if head-txLookupLimit+1 >= tail {
|
||||
// Unindex a part of stale indices and forward index tail to HEAD-limit
|
||||
rawdb.UnindexTransactions(bc.db, tail, head-txLookupLimit+1, bc.quit)
|
||||
}
|
||||
}
|
||||
|
||||
// maintainTxIndex is responsible for the deletion of the
|
||||
// transaction index. This does not support reconstruction of removed indexes.
|
||||
// Invariant: If TxLookupLimit is 0, it means all tx indices will be preserved.
|
||||
// Meaning that this function should never be called.
|
||||
func (bc *BlockChain) maintainTxIndex(headCh <-chan ChainEvent) {
|
||||
txLookupLimit := bc.cacheConfig.TransactionHistory
|
||||
|
||||
// If the user just upgraded to a new version which supports transaction
|
||||
// index pruning, write the new tail and remove anything older.
|
||||
if rawdb.ReadTxIndexTail(bc.db) == nil {
|
||||
rawdb.WriteTxIndexTail(bc.db, 0)
|
||||
}
|
||||
|
||||
// Any reindexing done, start listening to chain events and moving the index window
|
||||
var (
|
||||
done chan struct{} // Non-nil if background unindexing or reindexing routine is active.
|
||||
)
|
||||
log.Info("Initialized transaction unindexer", "limit", txLookupLimit)
|
||||
|
||||
// Launch the initial processing if chain is not empty. This step is
|
||||
// useful in these scenarios that chain has no progress and indexer
|
||||
// is never triggered.
|
||||
if head := bc.CurrentBlock(); head != nil && head.Number.Uint64() > txLookupLimit {
|
||||
done = make(chan struct{})
|
||||
tail := rawdb.ReadTxIndexTail(bc.db)
|
||||
bc.wg.Add(1)
|
||||
go bc.unindexBlocks(*tail, head.Number.Uint64(), done)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case head := <-headCh:
|
||||
headNum := head.Block.NumberU64()
|
||||
if headNum < txLookupLimit {
|
||||
break
|
||||
}
|
||||
|
||||
if done == nil {
|
||||
done = make(chan struct{})
|
||||
// Note: tail will not be nil since it is initialized in this function.
|
||||
tail := rawdb.ReadTxIndexTail(bc.db)
|
||||
bc.wg.Add(1)
|
||||
go bc.unindexBlocks(*tail, headNum, done)
|
||||
}
|
||||
case <-done:
|
||||
done = nil
|
||||
case <-bc.quit:
|
||||
if done != nil {
|
||||
log.Info("Waiting background transaction unindexer to exit")
|
||||
<-done
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// writeBlockAcceptedIndices writes any indices that must be persisted for accepted block.
|
||||
// This includes the following:
|
||||
// - transaction lookup indices
|
||||
@@ -957,7 +872,7 @@ func (bc *BlockChain) ValidateCanonicalChain() error {
|
||||
// Ensure that all of the transactions have been stored correctly in the canonical
|
||||
// chain
|
||||
for txIndex, tx := range txs {
|
||||
txLookup := bc.GetTransactionLookup(tx.Hash())
|
||||
txLookup, _, _ := bc.GetTransactionLookup(tx.Hash())
|
||||
if txLookup == nil {
|
||||
return fmt.Errorf("failed to find transaction %s", tx.Hash().String())
|
||||
}
|
||||
@@ -1014,6 +929,10 @@ func (bc *BlockChain) stopWithoutSaving() {
|
||||
if !bc.stopping.CompareAndSwap(false, true) {
|
||||
return
|
||||
}
|
||||
// Signal shutdown tx indexer.
|
||||
if bc.txIndexer != nil {
|
||||
bc.txIndexer.close()
|
||||
}
|
||||
|
||||
log.Info("Closing quit channel")
|
||||
close(bc.quit)
|
||||
@@ -1434,7 +1353,7 @@ func (bc *BlockChain) insertBlock(block *types.Block, writes bool) error {
|
||||
// The chain importer is starting and stopping trie prefetchers. If a bad
|
||||
// block or other error is hit however, an early return may not properly
|
||||
// terminate the background threads. This defer ensures that we clean up
|
||||
// and dangling prefetcher, without defering each and holding on live refs.
|
||||
// and dangling prefetcher, without deferring each and holding on live refs.
|
||||
if activeState != nil {
|
||||
activeState.StopPrefetcher()
|
||||
}
|
||||
@@ -1646,6 +1565,12 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
|
||||
} else {
|
||||
log.Debug("Preference change (rewind to ancestor) occurred", "oldnum", oldHead.Number, "oldhash", oldHead.Hash(), "newnum", newHead.Number(), "newhash", newHead.Hash())
|
||||
}
|
||||
// Reset the tx lookup cache in case to clear stale txlookups.
|
||||
// This is done before writing any new chain data to avoid the
|
||||
// weird scenario that canonical chain is changed while the
|
||||
// stale lookups are still cached.
|
||||
bc.txLookupCache.Purge()
|
||||
|
||||
// Insert the new chain(except the head block(reverse order)),
|
||||
// taking care of the proper incremental order.
|
||||
for i := len(newChain) - 1; i >= 1; i-- {
|
||||
@@ -2199,7 +2124,7 @@ func (bc *BlockChain) ResetToStateSyncedBlock(block *types.Block) error {
|
||||
|
||||
// if txlookup limit is 0 (uindexing disabled), we don't need to repair the tx index tail.
|
||||
if bc.cacheConfig.TransactionHistory != 0 {
|
||||
bc.setTxIndexTail(block.NumberU64())
|
||||
bc.repairTxIndexTail(block.NumberU64())
|
||||
}
|
||||
|
||||
// Update all in-memory chain markers
|
||||
@@ -2235,18 +2160,12 @@ func (bc *BlockChain) CacheConfig() *CacheConfig {
|
||||
return bc.cacheConfig
|
||||
}
|
||||
|
||||
func (bc *BlockChain) setTxIndexTail(newTail uint64) error {
|
||||
func (bc *BlockChain) repairTxIndexTail(newTail uint64) error {
|
||||
bc.txIndexTailLock.Lock()
|
||||
defer bc.txIndexTailLock.Unlock()
|
||||
|
||||
tailP := rawdb.ReadTxIndexTail(bc.db)
|
||||
var tailV uint64
|
||||
if tailP != nil {
|
||||
tailV = *tailP
|
||||
}
|
||||
|
||||
if newTail > tailV {
|
||||
log.Info("Repairing tx index tail", "old", tailV, "new", newTail)
|
||||
if curr := rawdb.ReadTxIndexTail(bc.db); curr == nil || *curr < newTail {
|
||||
log.Info("Repairing tx index tail", "old", curr, "new", newTail)
|
||||
rawdb.WriteTxIndexTail(bc.db, newTail)
|
||||
}
|
||||
return nil
|
||||
|
||||
+33
-11
@@ -40,7 +40,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ava-labs/subnet-evm/precompile/contracts/feemanager"
|
||||
"github.com/ava-labs/subnet-evm/precompile/contracts/rewardmanager"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
@@ -203,20 +203,37 @@ func (bc *BlockChain) GetCanonicalHash(number uint64) common.Hash {
|
||||
return bc.hc.GetCanonicalHash(number)
|
||||
}
|
||||
|
||||
// GetTransactionLookup retrieves the lookup associate with the given transaction
|
||||
// hash from the cache or database.
|
||||
func (bc *BlockChain) GetTransactionLookup(hash common.Hash) *rawdb.LegacyTxLookupEntry {
|
||||
// GetTransactionLookup retrieves the lookup along with the transaction
|
||||
// itself associate with the given transaction hash.
|
||||
//
|
||||
// An error will be returned if the transaction is not found, and background
|
||||
// indexing for transactions is still in progress. The transaction might be
|
||||
// reachable shortly once it's indexed.
|
||||
//
|
||||
// A null will be returned in the transaction is not found and background
|
||||
// transaction indexing is already finished. The transaction is not existent
|
||||
// from the node's perspective.
|
||||
func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLookupEntry, *types.Transaction, error) {
|
||||
// Short circuit if the txlookup already in the cache, retrieve otherwise
|
||||
if lookup, exist := bc.txLookupCache.Get(hash); exist {
|
||||
return lookup
|
||||
if item, exist := bc.txLookupCache.Get(hash); exist {
|
||||
return item.lookup, item.transaction, nil
|
||||
}
|
||||
tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(bc.db, hash)
|
||||
if tx == nil {
|
||||
return nil
|
||||
// The transaction is already indexed, the transaction is either
|
||||
// not existent or not in the range of index, returning null.
|
||||
return nil, nil, nil
|
||||
}
|
||||
lookup := &rawdb.LegacyTxLookupEntry{BlockHash: blockHash, BlockIndex: blockNumber, Index: txIndex}
|
||||
bc.txLookupCache.Add(hash, lookup)
|
||||
return lookup
|
||||
lookup := &rawdb.LegacyTxLookupEntry{
|
||||
BlockHash: blockHash,
|
||||
BlockIndex: blockNumber,
|
||||
Index: txIndex,
|
||||
}
|
||||
bc.txLookupCache.Add(hash, txLookup{
|
||||
lookup: lookup,
|
||||
transaction: tx,
|
||||
})
|
||||
return lookup, tx, nil
|
||||
}
|
||||
|
||||
// HasState checks if state trie is fully present in the database or not.
|
||||
@@ -288,10 +305,15 @@ func (bc *BlockChain) GetVMConfig() *vm.Config {
|
||||
}
|
||||
|
||||
// TrieDB retrieves the low level trie database used for data storage.
|
||||
func (bc *BlockChain) TrieDB() *trie.Database {
|
||||
func (bc *BlockChain) TrieDB() *triedb.Database {
|
||||
return bc.triedb
|
||||
}
|
||||
|
||||
// HeaderChain returns the underlying header chain.
|
||||
func (bc *BlockChain) HeaderChain() *HeaderChain {
|
||||
return bc.hc
|
||||
}
|
||||
|
||||
// SubscribeRemovedLogsEvent registers a subscription of RemovedLogsEvent.
|
||||
func (bc *BlockChain) SubscribeRemovedLogsEvent(ch chan<- RemovedLogsEvent) event.Subscription {
|
||||
return bc.scope.Track(bc.rmLogsFeed.Subscribe(ch))
|
||||
|
||||
@@ -39,7 +39,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/core/vm"
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -564,7 +564,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
|
||||
var sideblocks types.Blocks
|
||||
if tt.sidechainBlocks > 0 {
|
||||
genDb := rawdb.NewMemoryDatabase()
|
||||
gspec.MustCommit(genDb, trie.NewDatabase(genDb, nil))
|
||||
gspec.MustCommit(genDb, triedb.NewDatabase(genDb, nil))
|
||||
sideblocks, _, err = GenerateChain(gspec.Config, gspec.ToBlock(), engine, genDb, tt.sidechainBlocks, 10, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{0x01})
|
||||
tx, err := types.SignTx(types.NewTransaction(b.TxNonce(addr1), common.Address{0x01}, big.NewInt(10000), params.TxGas, common.Big1, nil), signer, key1)
|
||||
@@ -577,7 +577,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
|
||||
}
|
||||
}
|
||||
genDb := rawdb.NewMemoryDatabase()
|
||||
gspec.MustCommit(genDb, trie.NewDatabase(genDb, nil))
|
||||
gspec.MustCommit(genDb, triedb.NewDatabase(genDb, nil))
|
||||
canonblocks, _, err := GenerateChain(gspec.Config, gspec.ToBlock(), engine, genDb, tt.canonicalBlocks, 10, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{0x02})
|
||||
b.SetDifficulty(big.NewInt(1000000))
|
||||
|
||||
+16
-239
@@ -21,7 +21,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -314,7 +314,7 @@ func testRepopulateMissingTriesParallel(t *testing.T, parallelism int) {
|
||||
genesisBalance := big.NewInt(1000000)
|
||||
gspec := &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int), FeeConfig: params.DefaultFeeConfig},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
}
|
||||
|
||||
blockchain, err := createBlockChain(chainDB, pruningConfig, gspec, common.Hash{})
|
||||
@@ -427,7 +427,7 @@ func TestUngracefulAsyncShutdown(t *testing.T) {
|
||||
genesisBalance := big.NewInt(1000000)
|
||||
gspec := &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int), FeeConfig: params.DefaultFeeConfig},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
}
|
||||
|
||||
blockchain, err := create(chainDB, gspec, common.Hash{})
|
||||
@@ -481,13 +481,13 @@ func TestUngracefulAsyncShutdown(t *testing.T) {
|
||||
// After inserting all blocks, we should confirm that txs added after the
|
||||
// async worker shutdown cannot be found.
|
||||
for _, tx := range foundTxs {
|
||||
txLookup := blockchain.GetTransactionLookup(tx)
|
||||
txLookup, _, _ := blockchain.GetTransactionLookup(tx)
|
||||
if txLookup == nil {
|
||||
t.Fatalf("missing transaction: %v", tx)
|
||||
}
|
||||
}
|
||||
for _, tx := range missingTxs {
|
||||
txLookup := blockchain.GetTransactionLookup(tx)
|
||||
txLookup, _, _ := blockchain.GetTransactionLookup(tx)
|
||||
if txLookup != nil {
|
||||
t.Fatalf("transaction should be missing: %v", tx)
|
||||
}
|
||||
@@ -499,9 +499,10 @@ func TestUngracefulAsyncShutdown(t *testing.T) {
|
||||
if nonce != 10 {
|
||||
return fmt.Errorf("expected nonce addr1: 10, found nonce: %d", nonce)
|
||||
}
|
||||
transferredFunds := big.NewInt(100000)
|
||||
transferredFunds := uint256.MustFromBig(big.NewInt(100000))
|
||||
balance1 := sdb.GetBalance(addr1)
|
||||
expectedBalance1 := new(big.Int).Sub(genesisBalance, transferredFunds)
|
||||
genesisBalance := uint256.MustFromBig(genesisBalance)
|
||||
expectedBalance1 := new(uint256.Int).Sub(genesisBalance, transferredFunds)
|
||||
if balance1.Cmp(expectedBalance1) != 0 {
|
||||
return fmt.Errorf("expected addr1 balance: %d, found balance: %d", expectedBalance1, balance1)
|
||||
}
|
||||
@@ -530,7 +531,7 @@ func TestUngracefulAsyncShutdown(t *testing.T) {
|
||||
|
||||
// We should confirm all transactions can now be queried
|
||||
for _, tx := range allTxs {
|
||||
txLookup := bc.GetTransactionLookup(tx)
|
||||
txLookup, _, _ := bc.GetTransactionLookup(tx)
|
||||
if txLookup == nil {
|
||||
t.Fatalf("missing transaction: %v", tx)
|
||||
}
|
||||
@@ -538,207 +539,6 @@ func TestUngracefulAsyncShutdown(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransactionIndices(t *testing.T) {
|
||||
// Configure and generate a sample block chain
|
||||
require := require.New(t)
|
||||
var (
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
funds = big.NewInt(10000000000000)
|
||||
gspec = &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: funds}},
|
||||
}
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
)
|
||||
genDb, blocks, _, err := GenerateChainWithGenesis(gspec, dummy.NewFaker(), 128, 10, func(i int, block *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
|
||||
require.NoError(err)
|
||||
block.AddTx(tx)
|
||||
})
|
||||
require.NoError(err)
|
||||
|
||||
blocks2, _, err := GenerateChain(gspec.Config, blocks[len(blocks)-1], dummy.NewFaker(), genDb, 10, 10, func(i int, block *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
|
||||
require.NoError(err)
|
||||
block.AddTx(tx)
|
||||
})
|
||||
require.NoError(err)
|
||||
|
||||
conf := &CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieDirtyCommitTarget: 20,
|
||||
TriePrefetcherParallelism: 4,
|
||||
Pruning: true,
|
||||
CommitInterval: 4096,
|
||||
SnapshotLimit: 256,
|
||||
SnapshotNoBuild: true, // Ensure the test errors if snapshot initialization fails
|
||||
AcceptorQueueLimit: 64,
|
||||
}
|
||||
|
||||
// Init block chain and check all needed indices has been indexed.
|
||||
chainDB := rawdb.NewMemoryDatabase()
|
||||
chain, err := createBlockChain(chainDB, conf, gspec, common.Hash{})
|
||||
require.NoError(err)
|
||||
|
||||
_, err = chain.InsertChain(blocks)
|
||||
require.NoError(err)
|
||||
|
||||
for _, block := range blocks {
|
||||
err := chain.Accept(block)
|
||||
require.NoError(err)
|
||||
}
|
||||
chain.DrainAcceptorQueue()
|
||||
|
||||
lastAcceptedBlock := blocks[len(blocks)-1]
|
||||
require.Equal(lastAcceptedBlock.Hash(), chain.CurrentHeader().Hash())
|
||||
|
||||
CheckTxIndices(t, nil, lastAcceptedBlock.NumberU64(), chain.db, false) // check all indices has been indexed
|
||||
chain.Stop()
|
||||
|
||||
// Reconstruct a block chain which only reserves limited tx indices
|
||||
// 128 blocks were previously indexed. Now we add a new block at each test step.
|
||||
limits := []uint64{
|
||||
0, /* tip: 129 reserve all (don't run) */
|
||||
131, /* tip: 130 reserve all */
|
||||
140, /* tip: 131 reserve all */
|
||||
64, /* tip: 132, limit:64 */
|
||||
32, /* tip: 133, limit:32 */
|
||||
}
|
||||
for i, l := range limits {
|
||||
t.Run(fmt.Sprintf("test-%d, limit: %d", i+1, l), func(t *testing.T) {
|
||||
conf.TransactionHistory = l
|
||||
|
||||
chain, err := createBlockChain(chainDB, conf, gspec, lastAcceptedBlock.Hash())
|
||||
require.NoError(err)
|
||||
|
||||
tail := getTail(l, lastAcceptedBlock.NumberU64())
|
||||
// check if startup indices are correct
|
||||
CheckTxIndices(t, tail, lastAcceptedBlock.NumberU64(), chain.db, false)
|
||||
|
||||
newBlks := blocks2[i : i+1]
|
||||
_, err = chain.InsertChain(newBlks) // Feed chain a higher block to trigger indices updater.
|
||||
require.NoError(err)
|
||||
|
||||
lastAcceptedBlock = newBlks[0]
|
||||
err = chain.Accept(lastAcceptedBlock) // Accept the block to trigger indices updater.
|
||||
require.NoError(err)
|
||||
chain.DrainAcceptorQueue()
|
||||
|
||||
tail = getTail(l, lastAcceptedBlock.NumberU64())
|
||||
// check if indices are updated correctly
|
||||
CheckTxIndices(t, tail, lastAcceptedBlock.NumberU64(), chain.db, false)
|
||||
chain.Stop()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func getTail(limit uint64, lastAccepted uint64) *uint64 {
|
||||
if limit == 0 {
|
||||
return nil
|
||||
}
|
||||
var tail uint64
|
||||
if lastAccepted > limit {
|
||||
// tail should be the oldest block number which is indexed
|
||||
// i.e the first block number that's in the lookup range
|
||||
tail = lastAccepted - limit + 1
|
||||
}
|
||||
return &tail
|
||||
}
|
||||
|
||||
func TestTransactionSkipIndexing(t *testing.T) {
|
||||
// Configure and generate a sample block chain
|
||||
require := require.New(t)
|
||||
var (
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
funds = big.NewInt(10000000000000)
|
||||
gspec = &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: funds}},
|
||||
}
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
)
|
||||
genDb, blocks, _, err := GenerateChainWithGenesis(gspec, dummy.NewCoinbaseFaker(), 5, 10, func(i int, block *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
|
||||
require.NoError(err)
|
||||
block.AddTx(tx)
|
||||
})
|
||||
require.NoError(err)
|
||||
|
||||
blocks2, _, err := GenerateChain(gspec.Config, blocks[len(blocks)-1], dummy.NewCoinbaseFaker(), genDb, 5, 10, func(i int, block *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
|
||||
require.NoError(err)
|
||||
block.AddTx(tx)
|
||||
})
|
||||
require.NoError(err)
|
||||
|
||||
conf := &CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieDirtyCommitTarget: 20,
|
||||
TriePrefetcherParallelism: 4,
|
||||
Pruning: true,
|
||||
CommitInterval: 4096,
|
||||
SnapshotLimit: 256,
|
||||
SnapshotNoBuild: true, // Ensure the test errors if snapshot initialization fails
|
||||
AcceptorQueueLimit: 64,
|
||||
SkipTxIndexing: true,
|
||||
}
|
||||
|
||||
// test1: Init block chain and check all indices has been skipped.
|
||||
chainDB := rawdb.NewMemoryDatabase()
|
||||
chain, err := createAndInsertChain(chainDB, conf, gspec, blocks, common.Hash{},
|
||||
func(b *types.Block) {
|
||||
bNumber := b.NumberU64()
|
||||
checkTxIndicesHelper(t, nil, bNumber+1, bNumber+1, bNumber, chainDB, false) // check all indices has been skipped
|
||||
})
|
||||
require.NoError(err)
|
||||
chain.Stop()
|
||||
|
||||
// test2: specify lookuplimit with tx index skipping enabled. Blocks should not be indexed but tail should be updated.
|
||||
conf.TransactionHistory = 2
|
||||
chainDB = rawdb.NewMemoryDatabase()
|
||||
chain, err = createAndInsertChain(chainDB, conf, gspec, blocks, common.Hash{},
|
||||
func(b *types.Block) {
|
||||
bNumber := b.NumberU64()
|
||||
tail := bNumber - conf.TransactionHistory + 1
|
||||
checkTxIndicesHelper(t, &tail, bNumber+1, bNumber+1, bNumber, chainDB, false) // check all indices has been skipped
|
||||
})
|
||||
require.NoError(err)
|
||||
chain.Stop()
|
||||
|
||||
// test3: tx index skipping and unindexer disabled. Blocks should be indexed and tail should be updated.
|
||||
conf.TransactionHistory = 0
|
||||
conf.SkipTxIndexing = false
|
||||
chainDB = rawdb.NewMemoryDatabase()
|
||||
chain, err = createAndInsertChain(chainDB, conf, gspec, blocks, common.Hash{},
|
||||
func(b *types.Block) {
|
||||
bNumber := b.NumberU64()
|
||||
checkTxIndicesHelper(t, nil, 0, bNumber, bNumber, chainDB, false) // check all indices has been indexed
|
||||
})
|
||||
require.NoError(err)
|
||||
chain.Stop()
|
||||
|
||||
// now change tx index skipping to true and check that the indices are skipped for the last block
|
||||
// and old indices are removed up to the tail, but [tail, current) indices are still there.
|
||||
conf.TransactionHistory = 2
|
||||
conf.SkipTxIndexing = true
|
||||
chain, err = createAndInsertChain(chainDB, conf, gspec, blocks2[0:1], chain.CurrentHeader().Hash(),
|
||||
func(b *types.Block) {
|
||||
bNumber := b.NumberU64()
|
||||
tail := bNumber - conf.TransactionHistory + 1
|
||||
checkTxIndicesHelper(t, &tail, tail, bNumber-1, bNumber, chainDB, false)
|
||||
})
|
||||
require.NoError(err)
|
||||
chain.Stop()
|
||||
}
|
||||
|
||||
// TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted
|
||||
// correctly in case reorg is called.
|
||||
func TestCanonicalHashMarker(t *testing.T) {
|
||||
@@ -785,7 +585,7 @@ func testCanonicalHashMarker(t *testing.T, scheme string) {
|
||||
var (
|
||||
gspec = &Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: GenesisAlloc{},
|
||||
Alloc: types.GenesisAlloc{},
|
||||
BaseFee: big.NewInt(params.TestInitialBaseFee),
|
||||
}
|
||||
engine = dummy.NewCoinbaseFaker()
|
||||
@@ -948,7 +748,7 @@ func testCreateThenDelete(t *testing.T, config *params.ChainConfig) {
|
||||
}...)
|
||||
gspec := &Genesis{
|
||||
Config: config,
|
||||
Alloc: GenesisAlloc{
|
||||
Alloc: types.GenesisAlloc{
|
||||
address: {Balance: funds},
|
||||
},
|
||||
}
|
||||
@@ -1034,7 +834,7 @@ func TestDeleteThenCreate(t *testing.T) {
|
||||
|
||||
gspec := &Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: GenesisAlloc{
|
||||
Alloc: types.GenesisAlloc{
|
||||
address: {Balance: funds},
|
||||
},
|
||||
}
|
||||
@@ -1150,7 +950,7 @@ func TestTransientStorageReset(t *testing.T) {
|
||||
}...)
|
||||
gspec := &Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: GenesisAlloc{
|
||||
Alloc: types.GenesisAlloc{
|
||||
address: {Balance: funds},
|
||||
},
|
||||
}
|
||||
@@ -1218,7 +1018,7 @@ func TestEIP3651(t *testing.T) {
|
||||
gspec = &Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Timestamp: uint64(upgrade.InitiallyActiveTime.Unix()),
|
||||
Alloc: GenesisAlloc{
|
||||
Alloc: types.GenesisAlloc{
|
||||
addr1: {Balance: funds},
|
||||
addr2: {Balance: funds},
|
||||
// The address 0xAAAA sloads 0x00 and 0x01
|
||||
@@ -1296,7 +1096,7 @@ func TestEIP3651(t *testing.T) {
|
||||
// Note this differs from go-ethereum where the miner receives the gasUsed * block baseFee,
|
||||
// as our handling of the coinbase payment is different.
|
||||
// Note we use block.GasUsed() here as there is only one tx.
|
||||
actual := state.GetBalance(block.Coinbase())
|
||||
actual := state.GetBalance(block.Coinbase()).ToBig()
|
||||
tx := block.Transactions()[0]
|
||||
gasPrice := new(big.Int).Add(block.BaseFee(), tx.EffectiveGasTipValue(block.BaseFee()))
|
||||
expected := new(big.Int).SetUint64(block.GasUsed() * gasPrice.Uint64())
|
||||
@@ -1307,31 +1107,8 @@ func TestEIP3651(t *testing.T) {
|
||||
// 4: Ensure the tx sender paid for the gasUsed * (block baseFee + effectiveGasTip).
|
||||
// Note this differs from go-ethereum where the miner receives the gasUsed * block baseFee,
|
||||
// as our handling of the coinbase payment is different.
|
||||
actual = new(big.Int).Sub(funds, state.GetBalance(addr1))
|
||||
actual = new(big.Int).Sub(funds, state.GetBalance(addr1).ToBig())
|
||||
if actual.Cmp(expected) != 0 {
|
||||
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func createAndInsertChain(db ethdb.Database, cacheConfig *CacheConfig, gspec *Genesis, blocks types.Blocks, lastAcceptedHash common.Hash, accepted func(*types.Block)) (*BlockChain, error) {
|
||||
chain, err := createBlockChain(db, cacheConfig, gspec, lastAcceptedHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = chain.InsertChain(blocks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, block := range blocks {
|
||||
err := chain.Accept(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
chain.DrainAcceptorQueue()
|
||||
if accepted != nil {
|
||||
accepted(block)
|
||||
}
|
||||
}
|
||||
|
||||
return chain, nil
|
||||
}
|
||||
|
||||
@@ -40,9 +40,10 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/core/vm"
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// BlockGen creates blocks for testing.
|
||||
@@ -169,7 +170,7 @@ func (b *BlockGen) AddTxWithVMConfig(tx *types.Transaction, config vm.Config) {
|
||||
}
|
||||
|
||||
// GetBalance returns the balance of the given address at the generated block.
|
||||
func (b *BlockGen) GetBalance(addr common.Address) *big.Int {
|
||||
func (b *BlockGen) GetBalance(addr common.Address) *uint256.Int {
|
||||
return b.statedb.GetBalance(addr)
|
||||
}
|
||||
|
||||
@@ -279,7 +280,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||
}
|
||||
cm := newChainMaker(parent, config, engine)
|
||||
|
||||
genblock := func(i int, parent *types.Block, triedb *trie.Database, statedb *state.StateDB) (*types.Block, types.Receipts, error) {
|
||||
genblock := func(i int, parent *types.Block, triedb *triedb.Database, statedb *state.StateDB) (*types.Block, types.Receipts, error) {
|
||||
b := &BlockGen{i: i, cm: cm, parent: parent, statedb: statedb, engine: engine}
|
||||
b.header = cm.makeHeader(parent, gap, statedb, b.engine)
|
||||
|
||||
@@ -311,8 +312,9 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||
}
|
||||
return block, b.receipts, nil
|
||||
}
|
||||
|
||||
// Forcibly use hash-based state scheme for retaining all nodes in disk.
|
||||
triedb := trie.NewDatabase(db, trie.HashDefaults)
|
||||
triedb := triedb.NewDatabase(db, triedb.HashDefaults)
|
||||
defer triedb.Close()
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
@@ -360,7 +362,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||
// then generate chain on top.
|
||||
func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gap uint64, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts, error) {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
triedb := trie.NewDatabase(db, trie.HashDefaults)
|
||||
triedb := triedb.NewDatabase(db, triedb.HashDefaults)
|
||||
defer triedb.Close()
|
||||
_, err := genesis.Commit(db, triedb)
|
||||
if err != nil {
|
||||
|
||||
@@ -35,7 +35,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/core/vm"
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
@@ -55,9 +55,9 @@ func ExampleGenerateChain() {
|
||||
// Ensure that key1 has some funds in the genesis block.
|
||||
gspec := &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
|
||||
Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
|
||||
}
|
||||
genesis := gspec.MustCommit(genDb, trie.NewDatabase(genDb, trie.HashDefaults))
|
||||
genesis := gspec.MustCommit(genDb, triedb.NewDatabase(genDb, triedb.HashDefaults))
|
||||
|
||||
// This call generates a chain of 3 blocks. The function runs for
|
||||
// each block and adds different features to gen based on the
|
||||
|
||||
@@ -109,4 +109,10 @@ var (
|
||||
// ErrBlobFeeCapTooLow is returned if the transaction fee cap is less than the
|
||||
// blob gas fee of the block.
|
||||
ErrBlobFeeCapTooLow = errors.New("max fee per blob gas less than block blob gas fee")
|
||||
|
||||
// ErrMissingBlobHashes is returned if a blob transaction has no blob hashes.
|
||||
ErrMissingBlobHashes = errors.New("blob transaction missing blob hashes")
|
||||
|
||||
// ErrBlobTxCreate is returned if a blob transaction has no explicit to field.
|
||||
ErrBlobTxCreate = errors.New("blob transaction of type create")
|
||||
)
|
||||
|
||||
+3
-3
@@ -36,7 +36,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/predicate"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
//"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// ChainContext supports retrieving headers and consensus parameters from the
|
||||
@@ -165,12 +165,12 @@ func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash
|
||||
|
||||
// CanTransfer checks whether there are enough funds in the address' account to make a transfer.
|
||||
// This does not take the necessary gas in to account to make the transfer valid.
|
||||
func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool {
|
||||
func CanTransfer(db vm.StateDB, addr common.Address, amount *uint256.Int) bool {
|
||||
return db.GetBalance(addr).Cmp(amount) >= 0
|
||||
}
|
||||
|
||||
// Transfer subtracts amount from sender and adds amount to recipient using the given Db
|
||||
func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {
|
||||
func Transfer(db vm.StateDB, sender, recipient common.Address, amount *uint256.Int) {
|
||||
db.SubBalance(sender, amount)
|
||||
db.AddBalance(recipient, amount)
|
||||
}
|
||||
|
||||
+39
-38
@@ -7,6 +7,7 @@ import (
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
@@ -18,24 +19,24 @@ var _ = (*genesisSpecMarshaling)(nil)
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (g Genesis) MarshalJSON() ([]byte, error) {
|
||||
type Genesis struct {
|
||||
Config *params.ChainConfig `json:"config"`
|
||||
Nonce math.HexOrDecimal64 `json:"nonce"`
|
||||
Timestamp math.HexOrDecimal64 `json:"timestamp"`
|
||||
ExtraData hexutil.Bytes `json:"extraData"`
|
||||
GasLimit math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"`
|
||||
Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"`
|
||||
Mixhash common.Hash `json:"mixHash"`
|
||||
Coinbase common.Address `json:"coinbase"`
|
||||
Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"`
|
||||
AirdropHash common.Hash `json:"airdropHash"`
|
||||
AirdropAmount *math.HexOrDecimal256 `json:"airdropAmount"`
|
||||
AirdropData []byte `json:"-"`
|
||||
Number math.HexOrDecimal64 `json:"number"`
|
||||
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
|
||||
ParentHash common.Hash `json:"parentHash"`
|
||||
BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"`
|
||||
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"`
|
||||
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"`
|
||||
Config *params.ChainConfig `json:"config"`
|
||||
Nonce math.HexOrDecimal64 `json:"nonce"`
|
||||
Timestamp math.HexOrDecimal64 `json:"timestamp"`
|
||||
ExtraData hexutil.Bytes `json:"extraData"`
|
||||
GasLimit math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"`
|
||||
Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"`
|
||||
Mixhash common.Hash `json:"mixHash"`
|
||||
Coinbase common.Address `json:"coinbase"`
|
||||
Alloc map[common.UnprefixedAddress]types.Account `json:"alloc" gencodec:"required"`
|
||||
AirdropHash common.Hash `json:"airdropHash"`
|
||||
AirdropAmount *math.HexOrDecimal256 `json:"airdropAmount"`
|
||||
AirdropData []byte `json:"-"`
|
||||
Number math.HexOrDecimal64 `json:"number"`
|
||||
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
|
||||
ParentHash common.Hash `json:"parentHash"`
|
||||
BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"`
|
||||
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"`
|
||||
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"`
|
||||
}
|
||||
var enc Genesis
|
||||
enc.Config = g.Config
|
||||
@@ -47,7 +48,7 @@ func (g Genesis) MarshalJSON() ([]byte, error) {
|
||||
enc.Mixhash = g.Mixhash
|
||||
enc.Coinbase = g.Coinbase
|
||||
if g.Alloc != nil {
|
||||
enc.Alloc = make(map[common.UnprefixedAddress]GenesisAccount, len(g.Alloc))
|
||||
enc.Alloc = make(map[common.UnprefixedAddress]types.Account, len(g.Alloc))
|
||||
for k, v := range g.Alloc {
|
||||
enc.Alloc[common.UnprefixedAddress(k)] = v
|
||||
}
|
||||
@@ -67,24 +68,24 @@ func (g Genesis) MarshalJSON() ([]byte, error) {
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (g *Genesis) UnmarshalJSON(input []byte) error {
|
||||
type Genesis struct {
|
||||
Config *params.ChainConfig `json:"config"`
|
||||
Nonce *math.HexOrDecimal64 `json:"nonce"`
|
||||
Timestamp *math.HexOrDecimal64 `json:"timestamp"`
|
||||
ExtraData *hexutil.Bytes `json:"extraData"`
|
||||
GasLimit *math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"`
|
||||
Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"`
|
||||
Mixhash *common.Hash `json:"mixHash"`
|
||||
Coinbase *common.Address `json:"coinbase"`
|
||||
Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"`
|
||||
AirdropHash *common.Hash `json:"airdropHash"`
|
||||
AirdropAmount *math.HexOrDecimal256 `json:"airdropAmount"`
|
||||
AirdropData []byte `json:"-"`
|
||||
Number *math.HexOrDecimal64 `json:"number"`
|
||||
GasUsed *math.HexOrDecimal64 `json:"gasUsed"`
|
||||
ParentHash *common.Hash `json:"parentHash"`
|
||||
BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"`
|
||||
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"`
|
||||
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"`
|
||||
Config *params.ChainConfig `json:"config"`
|
||||
Nonce *math.HexOrDecimal64 `json:"nonce"`
|
||||
Timestamp *math.HexOrDecimal64 `json:"timestamp"`
|
||||
ExtraData *hexutil.Bytes `json:"extraData"`
|
||||
GasLimit *math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"`
|
||||
Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"`
|
||||
Mixhash *common.Hash `json:"mixHash"`
|
||||
Coinbase *common.Address `json:"coinbase"`
|
||||
Alloc map[common.UnprefixedAddress]types.Account `json:"alloc" gencodec:"required"`
|
||||
AirdropHash *common.Hash `json:"airdropHash"`
|
||||
AirdropAmount *math.HexOrDecimal256 `json:"airdropAmount"`
|
||||
AirdropData []byte `json:"-"`
|
||||
Number *math.HexOrDecimal64 `json:"number"`
|
||||
GasUsed *math.HexOrDecimal64 `json:"gasUsed"`
|
||||
ParentHash *common.Hash `json:"parentHash"`
|
||||
BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"`
|
||||
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"`
|
||||
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"`
|
||||
}
|
||||
var dec Genesis
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
@@ -119,7 +120,7 @@ func (g *Genesis) UnmarshalJSON(input []byte) error {
|
||||
if dec.Alloc == nil {
|
||||
return errors.New("missing required field 'alloc' for Genesis")
|
||||
}
|
||||
g.Alloc = make(GenesisAlloc, len(dec.Alloc))
|
||||
g.Alloc = make(types.GenesisAlloc, len(dec.Alloc))
|
||||
for k, v := range dec.Alloc {
|
||||
g.Alloc[common.Address(k)] = v
|
||||
}
|
||||
|
||||
+22
-68
@@ -27,8 +27,6 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -40,20 +38,27 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/trie/triedb/pathdb"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ava-labs/subnet-evm/triedb/pathdb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
|
||||
//go:generate go run github.com/fjl/gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go
|
||||
|
||||
var errGenesisNoConfig = errors.New("genesis has no chain configuration")
|
||||
|
||||
// Deprecated: use types.GenesisAccount instead.
|
||||
type GenesisAccount = types.Account
|
||||
|
||||
// Deprecated: use types.GenesisAlloc instead.
|
||||
type GenesisAlloc = types.GenesisAlloc
|
||||
|
||||
type Airdrop struct {
|
||||
// Address strings are hex-formatted common.Address
|
||||
Address common.Address `json:"address"`
|
||||
@@ -70,7 +75,7 @@ type Genesis struct {
|
||||
Difficulty *big.Int `json:"difficulty" gencodec:"required"`
|
||||
Mixhash common.Hash `json:"mixHash"`
|
||||
Coinbase common.Address `json:"coinbase"`
|
||||
Alloc GenesisAlloc `json:"alloc" gencodec:"required"`
|
||||
Alloc types.GenesisAlloc `json:"alloc" gencodec:"required"`
|
||||
AirdropHash common.Hash `json:"airdropHash"`
|
||||
AirdropAmount *big.Int `json:"airdropAmount"`
|
||||
AirdropData []byte `json:"-"` // provided in a separate file, not serialized in this struct.
|
||||
@@ -85,30 +90,6 @@ type Genesis struct {
|
||||
BlobGasUsed *uint64 `json:"blobGasUsed"` // EIP-4844
|
||||
}
|
||||
|
||||
// GenesisAlloc specifies the initial state that is part of the genesis block.
|
||||
type GenesisAlloc map[common.Address]GenesisAccount
|
||||
|
||||
func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error {
|
||||
m := make(map[common.UnprefixedAddress]GenesisAccount)
|
||||
if err := json.Unmarshal(data, &m); err != nil {
|
||||
return err
|
||||
}
|
||||
*ga = make(GenesisAlloc)
|
||||
for addr, a := range m {
|
||||
(*ga)[common.Address(addr)] = a
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenesisAccount is an account in the state of the genesis block.
|
||||
type GenesisAccount struct {
|
||||
Code []byte `json:"code,omitempty"`
|
||||
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
||||
Balance *big.Int `json:"balance" gencodec:"required"`
|
||||
Nonce uint64 `json:"nonce,omitempty"`
|
||||
PrivateKey []byte `json:"secretKey,omitempty"` // for tests
|
||||
}
|
||||
|
||||
// field type overrides for gencodec
|
||||
type genesisSpecMarshaling struct {
|
||||
Nonce math.HexOrDecimal64
|
||||
@@ -118,41 +99,13 @@ type genesisSpecMarshaling struct {
|
||||
GasUsed math.HexOrDecimal64
|
||||
Number math.HexOrDecimal64
|
||||
Difficulty *math.HexOrDecimal256
|
||||
Alloc map[common.UnprefixedAddress]GenesisAccount
|
||||
Alloc map[common.UnprefixedAddress]types.Account
|
||||
BaseFee *math.HexOrDecimal256
|
||||
AirdropAmount *math.HexOrDecimal256
|
||||
ExcessBlobGas *math.HexOrDecimal64
|
||||
BlobGasUsed *math.HexOrDecimal64
|
||||
}
|
||||
|
||||
type genesisAccountMarshaling struct {
|
||||
Code hexutil.Bytes
|
||||
Balance *math.HexOrDecimal256
|
||||
Nonce math.HexOrDecimal64
|
||||
Storage map[storageJSON]storageJSON
|
||||
PrivateKey hexutil.Bytes
|
||||
}
|
||||
|
||||
// storageJSON represents a 256 bit byte array, but allows less than 256 bits when
|
||||
// unmarshaling from hex.
|
||||
type storageJSON common.Hash
|
||||
|
||||
func (h *storageJSON) UnmarshalText(text []byte) error {
|
||||
text = bytes.TrimPrefix(text, []byte("0x"))
|
||||
if len(text) > 64 {
|
||||
return fmt.Errorf("too many hex characters in storage key/value %q", text)
|
||||
}
|
||||
offset := len(h) - len(text)/2 // pad on the left
|
||||
if _, err := hex.Decode(h[offset:], text); err != nil {
|
||||
return fmt.Errorf("invalid hex storage key/value %q", text)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h storageJSON) MarshalText() ([]byte, error) {
|
||||
return hexutil.Bytes(h[:]).MarshalText()
|
||||
}
|
||||
|
||||
// GenesisMismatchError is raised when trying to overwrite an existing
|
||||
// genesis block with an incompatible one.
|
||||
type GenesisMismatchError struct {
|
||||
@@ -179,7 +132,7 @@ func (e *GenesisMismatchError) Error() string {
|
||||
// specify a fork block below the local head block). In case of a conflict, the
|
||||
// error is a *params.ConfigCompatError and the new, unwritten config is returned.
|
||||
func SetupGenesisBlock(
|
||||
db ethdb.Database, triedb *trie.Database, genesis *Genesis, lastAcceptedHash common.Hash, skipChainConfigCheckCompatible bool,
|
||||
db ethdb.Database, triedb *triedb.Database, genesis *Genesis, lastAcceptedHash common.Hash, skipChainConfigCheckCompatible bool,
|
||||
) (*params.ChainConfig, common.Hash, error) {
|
||||
if genesis == nil {
|
||||
return nil, common.Hash{}, ErrNoGenesis
|
||||
@@ -269,21 +222,21 @@ func (g *Genesis) IsVerkle() bool {
|
||||
// ToBlock returns the genesis block according to genesis specification.
|
||||
func (g *Genesis) ToBlock() *types.Block {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
return g.toBlock(db, trie.NewDatabase(db, g.trieConfig()))
|
||||
return g.toBlock(db, triedb.NewDatabase(db, g.trieConfig()))
|
||||
}
|
||||
|
||||
func (g *Genesis) trieConfig() *trie.Config {
|
||||
func (g *Genesis) trieConfig() *triedb.Config {
|
||||
if !g.IsVerkle() {
|
||||
return nil
|
||||
}
|
||||
return &trie.Config{
|
||||
return &triedb.Config{
|
||||
PathDB: pathdb.Defaults,
|
||||
IsVerkle: true,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: migrate this function to "flush" for more similarity with upstream.
|
||||
func (g *Genesis) toBlock(db ethdb.Database, triedb *trie.Database) *types.Block {
|
||||
func (g *Genesis) toBlock(db ethdb.Database, triedb *triedb.Database) *types.Block {
|
||||
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -298,8 +251,9 @@ func (g *Genesis) toBlock(db ethdb.Database, triedb *trie.Database) *types.Block
|
||||
if err := json.Unmarshal(g.AirdropData, &airdrop); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
airdropAmount := uint256.MustFromBig(g.AirdropAmount)
|
||||
for _, alloc := range airdrop {
|
||||
statedb.SetBalance(alloc.Address, g.AirdropAmount)
|
||||
statedb.SetBalance(alloc.Address, airdropAmount)
|
||||
}
|
||||
log.Debug(
|
||||
"applied airdrop allocation",
|
||||
@@ -331,7 +285,7 @@ func (g *Genesis) toBlock(db ethdb.Database, triedb *trie.Database) *types.Block
|
||||
// Do custom allocation after airdrop in case an address shows up in standard
|
||||
// allocation
|
||||
for addr, account := range g.Alloc {
|
||||
statedb.SetBalance(addr, account.Balance)
|
||||
statedb.SetBalance(addr, uint256.MustFromBig(account.Balance))
|
||||
statedb.SetCode(addr, account.Code)
|
||||
statedb.SetNonce(addr, account.Nonce)
|
||||
for key, value := range account.Storage {
|
||||
@@ -385,7 +339,7 @@ func (g *Genesis) toBlock(db ethdb.Database, triedb *trie.Database) *types.Block
|
||||
|
||||
// Commit writes the block and state of a genesis specification to the database.
|
||||
// The block is committed as the canonical head block.
|
||||
func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block, error) {
|
||||
func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Block, error) {
|
||||
block := g.toBlock(db, triedb)
|
||||
if block.Number().Sign() != 0 {
|
||||
return nil, errors.New("can't commit genesis block with number > 0")
|
||||
@@ -412,7 +366,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block
|
||||
|
||||
// MustCommit writes the genesis block and state to db, panicking on error.
|
||||
// The block is committed as the canonical head block.
|
||||
func (g *Genesis) MustCommit(db ethdb.Database, triedb *trie.Database) *types.Block {
|
||||
func (g *Genesis) MustCommit(db ethdb.Database, triedb *triedb.Database) *types.Block {
|
||||
block, err := g.Commit(db, triedb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -444,7 +398,7 @@ func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big
|
||||
Alloc: GenesisAlloc{addr: {Balance: balance}},
|
||||
BaseFee: big.NewInt(params.TestMaxBaseFee),
|
||||
}
|
||||
return g.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults))
|
||||
return g.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults))
|
||||
}
|
||||
|
||||
// ReadBlockByHash reads the block with the given hash from the database.
|
||||
|
||||
+20
-19
@@ -42,7 +42,8 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/precompile/allowlist"
|
||||
"github.com/ava-labs/subnet-evm/precompile/contracts/deployerallowlist"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/trie/triedb/pathdb"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ava-labs/subnet-evm/triedb/pathdb"
|
||||
"github.com/ava-labs/subnet-evm/utils"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -51,7 +52,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func setupGenesisBlock(db ethdb.Database, triedb *trie.Database, genesis *Genesis, lastAcceptedHash common.Hash) (*params.ChainConfig, common.Hash, error) {
|
||||
func setupGenesisBlock(db ethdb.Database, triedb *triedb.Database, genesis *Genesis, lastAcceptedHash common.Hash) (*params.ChainConfig, common.Hash, error) {
|
||||
return SetupGenesisBlock(db, triedb, genesis, lastAcceptedHash, false)
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||
customghash = common.HexToHash("0x4a12fe7bf8d40d152d7e9de22337b115186a4662aa3a97217b36146202bbfc66")
|
||||
customg = Genesis{
|
||||
Config: &preSubnetConfig,
|
||||
Alloc: GenesisAlloc{
|
||||
Alloc: types.GenesisAlloc{
|
||||
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
|
||||
},
|
||||
GasLimit: preSubnetConfig.FeeConfig.GasLimit.Uint64(),
|
||||
@@ -97,7 +98,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||
{
|
||||
name: "genesis without ChainConfig",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
return setupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), new(Genesis), common.Hash{})
|
||||
return setupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), new(Genesis), common.Hash{})
|
||||
},
|
||||
wantErr: errGenesisNoConfig,
|
||||
wantConfig: nil,
|
||||
@@ -105,7 +106,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||
{
|
||||
name: "no block in DB, genesis == nil",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
return setupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), nil, common.Hash{})
|
||||
return setupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil, common.Hash{})
|
||||
},
|
||||
wantErr: ErrNoGenesis,
|
||||
wantConfig: nil,
|
||||
@@ -113,7 +114,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||
{
|
||||
name: "custom block in DB, genesis == nil",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
tdb := trie.NewDatabase(db, newDbConfig(scheme))
|
||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||
customg.Commit(db, tdb)
|
||||
return setupGenesisBlock(db, tdb, nil, common.Hash{})
|
||||
},
|
||||
@@ -123,7 +124,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||
{
|
||||
name: "compatible config in DB",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
tdb := trie.NewDatabase(db, newDbConfig(scheme))
|
||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||
oldcustomg.Commit(db, tdb)
|
||||
return setupGenesisBlock(db, tdb, &customg, customghash)
|
||||
},
|
||||
@@ -135,7 +136,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
// Commit the 'old' genesis block with SubnetEVM transition at 90.
|
||||
// Advance to block #4, past the SubnetEVM transition block of customg.
|
||||
tdb := trie.NewDatabase(db, newDbConfig(scheme))
|
||||
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
|
||||
genesis, err := oldcustomg.Commit(db, tdb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -224,7 +225,7 @@ func TestStatefulPrecompilesConfigure(t *testing.T) {
|
||||
|
||||
genesis := &Genesis{
|
||||
Config: config,
|
||||
Alloc: GenesisAlloc{
|
||||
Alloc: types.GenesisAlloc{
|
||||
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
|
||||
},
|
||||
GasLimit: config.FeeConfig.GasLimit.Uint64(),
|
||||
@@ -235,7 +236,7 @@ func TestStatefulPrecompilesConfigure(t *testing.T) {
|
||||
genesisBlock := genesis.ToBlock()
|
||||
genesisRoot := genesisBlock.Root()
|
||||
|
||||
_, _, err := setupGenesisBlock(db, trie.NewDatabase(db, trie.HashDefaults), genesis, genesisBlock.Hash())
|
||||
_, _, err := setupGenesisBlock(db, triedb.NewDatabase(db, triedb.HashDefaults), genesis, genesisBlock.Hash())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -257,7 +258,7 @@ func TestPrecompileActivationAfterHeaderBlock(t *testing.T) {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
customg := Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: GenesisAlloc{
|
||||
Alloc: types.GenesisAlloc{
|
||||
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
|
||||
},
|
||||
GasLimit: params.TestChainConfig.FeeConfig.GasLimit.Uint64(),
|
||||
@@ -297,7 +298,7 @@ func TestPrecompileActivationAfterHeaderBlock(t *testing.T) {
|
||||
require.Less(bc.lastAccepted.Time(), *contractDeployerConfig.Timestamp())
|
||||
|
||||
// This should not return any error since the last accepted block is before the activation block.
|
||||
config, _, err := setupGenesisBlock(db, trie.NewDatabase(db, nil), &customg, bc.lastAccepted.Hash())
|
||||
config, _, err := setupGenesisBlock(db, triedb.NewDatabase(db, nil), &customg, bc.lastAccepted.Hash())
|
||||
require.NoError(err)
|
||||
if !reflect.DeepEqual(config, customg.Config) {
|
||||
t.Errorf("returned %v\nwant %v", config, customg.Config)
|
||||
@@ -309,14 +310,14 @@ func TestGenesisWriteUpgradesRegression(t *testing.T) {
|
||||
config := *params.TestChainConfig
|
||||
genesis := &Genesis{
|
||||
Config: &config,
|
||||
Alloc: GenesisAlloc{
|
||||
Alloc: types.GenesisAlloc{
|
||||
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
|
||||
},
|
||||
GasLimit: config.FeeConfig.GasLimit.Uint64(),
|
||||
}
|
||||
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
trieDB := trie.NewDatabase(db, trie.HashDefaults)
|
||||
trieDB := triedb.NewDatabase(db, triedb.HashDefaults)
|
||||
genesisBlock := genesis.MustCommit(db, trieDB)
|
||||
|
||||
_, _, err := SetupGenesisBlock(db, trieDB, genesis, genesisBlock.Hash(), false)
|
||||
@@ -346,11 +347,11 @@ func TestGenesisWriteUpgradesRegression(t *testing.T) {
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
func newDbConfig(scheme string) *trie.Config {
|
||||
func newDbConfig(scheme string) *triedb.Config {
|
||||
if scheme == rawdb.HashScheme {
|
||||
return trie.HashDefaults
|
||||
return triedb.HashDefaults
|
||||
}
|
||||
return &trie.Config{PathDB: pathdb.Defaults}
|
||||
return &triedb.Config{PathDB: pathdb.Defaults}
|
||||
}
|
||||
|
||||
func TestVerkleGenesisCommit(t *testing.T) {
|
||||
@@ -375,7 +376,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
||||
Config: verkleConfig,
|
||||
Timestamp: verkleTime,
|
||||
Difficulty: big.NewInt(0),
|
||||
Alloc: GenesisAlloc{
|
||||
Alloc: types.GenesisAlloc{
|
||||
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
|
||||
},
|
||||
}
|
||||
@@ -387,7 +388,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
||||
}
|
||||
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
triedb := trie.NewDatabase(db, &trie.Config{IsVerkle: true, PathDB: pathdb.Defaults})
|
||||
triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults})
|
||||
block := genesis.MustCommit(db, triedb)
|
||||
if !bytes.Equal(block.Root().Bytes(), expected) {
|
||||
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
|
||||
|
||||
@@ -303,7 +303,7 @@ func ReadStateScheme(db ethdb.Reader) string {
|
||||
return PathScheme
|
||||
}
|
||||
// The root node might be deleted during the initial snap sync, check
|
||||
// the persistentstent state id then.
|
||||
// the persistent state id then.
|
||||
if id := ReadPersistentStateID(db); id != 0 {
|
||||
return PathScheme
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool
|
||||
//
|
||||
// There is a passed channel, the whole procedure will be interrupted if any
|
||||
// signal received.
|
||||
func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool) {
|
||||
func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool, report bool) {
|
||||
// short circuit for invalid range
|
||||
if from >= to {
|
||||
return
|
||||
@@ -145,13 +145,13 @@ func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan
|
||||
batch = db.NewBatch()
|
||||
start = time.Now()
|
||||
logged = start.Add(-7 * time.Second)
|
||||
|
||||
// Since we iterate in reverse, we expect the first number to come
|
||||
// in to be [to-1]. Therefore, setting lastNum to means that the
|
||||
// prqueue gap-evaluation will work correctly
|
||||
lastNum = to
|
||||
queue = prque.New[int64, *blockTxHashes](nil)
|
||||
// for stats reporting
|
||||
blocks, txs = 0, 0
|
||||
// queue gap-evaluation will work correctly
|
||||
lastNum = to
|
||||
queue = prque.New[int64, *blockTxHashes](nil)
|
||||
blocks, txs = 0, 0 // for stats reporting
|
||||
)
|
||||
for chanDelivery := range hashesCh {
|
||||
// Push the delivery into the queue and process contiguous ranges.
|
||||
@@ -197,37 +197,41 @@ func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan
|
||||
log.Crit("Failed writing batch to db", "error", err)
|
||||
return
|
||||
}
|
||||
logger := log.Debug
|
||||
if report {
|
||||
logger = log.Info
|
||||
}
|
||||
select {
|
||||
case <-interrupt:
|
||||
log.Debug("Transaction indexing interrupted", "blocks", blocks, "txs", txs, "tail", lastNum, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
logger("Transaction indexing interrupted", "blocks", blocks, "txs", txs, "tail", lastNum, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
default:
|
||||
log.Debug("Indexed transactions", "blocks", blocks, "txs", txs, "tail", lastNum, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
logger("Indexed transactions", "blocks", blocks, "txs", txs, "tail", lastNum, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
}
|
||||
}
|
||||
|
||||
// // IndexTransactions creates txlookup indices of the specified block range. The from
|
||||
// // is included while to is excluded.
|
||||
// //
|
||||
// // This function iterates canonical chain in reverse order, it has one main advantage:
|
||||
// // We can write tx index tail flag periodically even without the whole indexing
|
||||
// // procedure is finished. So that we can resume indexing procedure next time quickly.
|
||||
// //
|
||||
// // There is a passed channel, the whole procedure will be interrupted if any
|
||||
// // signal received.
|
||||
// func IndexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}) {
|
||||
// indexTransactions(db, from, to, interrupt, nil)
|
||||
// }
|
||||
// IndexTransactions creates txlookup indices of the specified block range. The from
|
||||
// is included while to is excluded.
|
||||
//
|
||||
// This function iterates canonical chain in reverse order, it has one main advantage:
|
||||
// We can write tx index tail flag periodically even without the whole indexing
|
||||
// procedure is finished. So that we can resume indexing procedure next time quickly.
|
||||
//
|
||||
// There is a passed channel, the whole procedure will be interrupted if any
|
||||
// signal received.
|
||||
func IndexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, report bool) {
|
||||
indexTransactions(db, from, to, interrupt, nil, report)
|
||||
}
|
||||
|
||||
// indexTransactionsForTesting is the internal debug version with an additional hook.
|
||||
func indexTransactionsForTesting(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool) {
|
||||
indexTransactions(db, from, to, interrupt, hook)
|
||||
indexTransactions(db, from, to, interrupt, hook, false)
|
||||
}
|
||||
|
||||
// unindexTransactions removes txlookup indices of the specified block range.
|
||||
//
|
||||
// There is a passed channel, the whole procedure will be interrupted if any
|
||||
// signal received.
|
||||
func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool) {
|
||||
func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool, report bool) {
|
||||
// short circuit for invalid range
|
||||
if from >= to {
|
||||
return
|
||||
@@ -237,12 +241,12 @@ func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt ch
|
||||
batch = db.NewBatch()
|
||||
start = time.Now()
|
||||
logged = start.Add(-7 * time.Second)
|
||||
|
||||
// we expect the first number to come in to be [from]. Therefore, setting
|
||||
// nextNum to from means that the prqueue gap-evaluation will work correctly
|
||||
nextNum = from
|
||||
queue = prque.New[int64, *blockTxHashes](nil)
|
||||
// for stats reporting
|
||||
blocks, txs = 0, 0
|
||||
// nextNum to from means that the queue gap-evaluation will work correctly
|
||||
nextNum = from
|
||||
queue = prque.New[int64, *blockTxHashes](nil)
|
||||
blocks, txs = 0, 0 // for stats reporting
|
||||
)
|
||||
// Otherwise spin up the concurrent iterator and unindexer
|
||||
for delivery := range hashesCh {
|
||||
@@ -289,11 +293,15 @@ func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt ch
|
||||
log.Crit("Failed writing batch to db", "error", err)
|
||||
return
|
||||
}
|
||||
logger := log.Debug
|
||||
if report {
|
||||
logger = log.Info
|
||||
}
|
||||
select {
|
||||
case <-interrupt:
|
||||
log.Debug("Transaction unindexing interrupted", "blocks", blocks, "txs", txs, "tail", to, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
logger("Transaction unindexing interrupted", "blocks", blocks, "txs", txs, "tail", to, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
default:
|
||||
log.Debug("Unindexed transactions", "blocks", blocks, "txs", txs, "tail", to, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
logger("Unindexed transactions", "blocks", blocks, "txs", txs, "tail", to, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,11 +310,11 @@ func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt ch
|
||||
//
|
||||
// There is a passed channel, the whole procedure will be interrupted if any
|
||||
// signal received.
|
||||
func UnindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}) {
|
||||
unindexTransactions(db, from, to, interrupt, nil)
|
||||
func UnindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, report bool) {
|
||||
unindexTransactions(db, from, to, interrupt, nil, report)
|
||||
}
|
||||
|
||||
// unindexTransactionsForTesting is the internal debug version with an additional hook.
|
||||
func unindexTransactionsForTesting(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool) {
|
||||
unindexTransactions(db, from, to, interrupt, hook)
|
||||
unindexTransactions(db, from, to, interrupt, hook, false)
|
||||
}
|
||||
|
||||
@@ -172,18 +172,18 @@ func TestIndexTransactions(t *testing.T) {
|
||||
t.Fatalf("Transaction tail mismatch")
|
||||
}
|
||||
}
|
||||
indexTransactionsForTesting(chainDb, 5, 11, nil, nil)
|
||||
IndexTransactions(chainDb, 5, 11, nil, false)
|
||||
verify(5, 11, true, 5)
|
||||
verify(0, 5, false, 5)
|
||||
|
||||
indexTransactionsForTesting(chainDb, 0, 5, nil, nil)
|
||||
IndexTransactions(chainDb, 0, 5, nil, false)
|
||||
verify(0, 11, true, 0)
|
||||
|
||||
UnindexTransactions(chainDb, 0, 5, nil)
|
||||
UnindexTransactions(chainDb, 0, 5, nil, false)
|
||||
verify(5, 11, true, 5)
|
||||
verify(0, 5, false, 5)
|
||||
|
||||
UnindexTransactions(chainDb, 5, 11, nil)
|
||||
UnindexTransactions(chainDb, 5, 11, nil, false)
|
||||
verify(0, 11, false, 11)
|
||||
|
||||
// Testing corner cases
|
||||
@@ -200,7 +200,7 @@ func TestIndexTransactions(t *testing.T) {
|
||||
})
|
||||
verify(9, 11, true, 9)
|
||||
verify(0, 9, false, 9)
|
||||
indexTransactionsForTesting(chainDb, 0, 9, nil, nil)
|
||||
IndexTransactions(chainDb, 0, 9, nil, false)
|
||||
|
||||
signal = make(chan struct{})
|
||||
var once2 sync.Once
|
||||
|
||||
@@ -460,3 +460,5 @@ func ClearPrefix(db ethdb.KeyValueStore, prefix []byte, keyLen int) error {
|
||||
}
|
||||
return batch.Write()
|
||||
}
|
||||
|
||||
/// TODO: Consider adding ReadChainMetadata
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ func getBlock(transactions int, uncles int, dataSize int) *types.Block {
|
||||
funds = big.NewInt(50000 * 225000000000 * 200)
|
||||
gspec = &Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: GenesisAlloc{address: {Balance: funds}},
|
||||
Alloc: types.GenesisAlloc{address: {Balance: funds}},
|
||||
}
|
||||
)
|
||||
// We need to generate as many blocks +1 as uncles
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/trie/trienode"
|
||||
"github.com/ava-labs/subnet-evm/trie/utils"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/crate-crypto/go-ipa/banderwagon"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/lru"
|
||||
@@ -77,7 +78,7 @@ type Database interface {
|
||||
DiskDB() ethdb.KeyValueStore
|
||||
|
||||
// TrieDB returns the underlying trie database for managing trie nodes.
|
||||
TrieDB() *trie.Database
|
||||
TrieDB() *triedb.Database
|
||||
}
|
||||
|
||||
// Trie is a Ethereum Merkle Patricia trie.
|
||||
@@ -160,17 +161,17 @@ func NewDatabase(db ethdb.Database) Database {
|
||||
// NewDatabaseWithConfig creates a backing store for state. The returned database
|
||||
// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a
|
||||
// large memory cache.
|
||||
func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database {
|
||||
func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) Database {
|
||||
return &cachingDB{
|
||||
disk: db,
|
||||
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
||||
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
|
||||
triedb: trie.NewDatabase(db, config),
|
||||
triedb: triedb.NewDatabase(db, config),
|
||||
}
|
||||
}
|
||||
|
||||
// NewDatabaseWithNodeDB creates a state database with an already initialized node database.
|
||||
func NewDatabaseWithNodeDB(db ethdb.Database, triedb *trie.Database) Database {
|
||||
func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database {
|
||||
return &cachingDB{
|
||||
disk: db,
|
||||
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
||||
@@ -183,7 +184,7 @@ type cachingDB struct {
|
||||
disk ethdb.KeyValueStore
|
||||
codeSizeCache *lru.Cache[common.Hash, int]
|
||||
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
|
||||
triedb *trie.Database
|
||||
triedb *triedb.Database
|
||||
}
|
||||
|
||||
// OpenTrie opens the main account trie at a specific root hash.
|
||||
@@ -253,6 +254,6 @@ func (db *cachingDB) DiskDB() ethdb.KeyValueStore {
|
||||
}
|
||||
|
||||
// TrieDB retrieves any intermediate trie-node caching layer.
|
||||
func (db *cachingDB) TrieDB() *trie.Database {
|
||||
func (db *cachingDB) TrieDB() *triedb.Database {
|
||||
return db.triedb
|
||||
}
|
||||
|
||||
@@ -27,9 +27,8 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// journalEntry is a modification entry in the state change journal that can be
|
||||
@@ -113,13 +112,13 @@ type (
|
||||
selfDestructChange struct {
|
||||
account *common.Address
|
||||
prev bool // whether account had already self-destructed
|
||||
prevbalance *big.Int
|
||||
prevbalance *uint256.Int
|
||||
}
|
||||
|
||||
// Changes to individual accounts.
|
||||
balanceChange struct {
|
||||
account *common.Address
|
||||
prev *big.Int
|
||||
prev *uint256.Int
|
||||
}
|
||||
nonceChange struct {
|
||||
account *common.Address
|
||||
|
||||
@@ -37,17 +37,10 @@ import (
|
||||
bloomfilter "github.com/holiman/bloomfilter/v2"
|
||||
)
|
||||
|
||||
// stateBloomHasher is a wrapper around a byte blob to satisfy the interface API
|
||||
// requirements of the bloom library used. It's used to convert a trie hash or
|
||||
// contract code hash into a 64 bit mini hash.
|
||||
type stateBloomHasher []byte
|
||||
|
||||
func (f stateBloomHasher) Write(p []byte) (n int, err error) { panic("not implemented") }
|
||||
func (f stateBloomHasher) Sum(b []byte) []byte { panic("not implemented") }
|
||||
func (f stateBloomHasher) Reset() { panic("not implemented") }
|
||||
func (f stateBloomHasher) BlockSize() int { panic("not implemented") }
|
||||
func (f stateBloomHasher) Size() int { return 8 }
|
||||
func (f stateBloomHasher) Sum64() uint64 { return binary.BigEndian.Uint64(f) }
|
||||
// stateBloomHash is used to convert a trie hash or contract code hash into a 64 bit mini hash.
|
||||
func stateBloomHash(f []byte) uint64 {
|
||||
return binary.BigEndian.Uint64(f)
|
||||
}
|
||||
|
||||
// stateBloom is a bloom filter used during the state conversion(snapshot->state).
|
||||
// The keys of all generated entries will be recorded here so that in the pruning
|
||||
@@ -123,10 +116,10 @@ func (bloom *stateBloom) Put(key []byte, value []byte) error {
|
||||
if !isCode {
|
||||
return errors.New("invalid entry")
|
||||
}
|
||||
bloom.bloom.Add(stateBloomHasher(codeKey))
|
||||
bloom.bloom.AddHash(stateBloomHash(codeKey))
|
||||
return nil
|
||||
}
|
||||
bloom.bloom.Add(stateBloomHasher(key))
|
||||
bloom.bloom.AddHash(stateBloomHash(key))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -138,5 +131,5 @@ func (bloom *stateBloom) Delete(key []byte) error { panic("not supported") }
|
||||
// - If it says yes, the key may be contained
|
||||
// - If it says no, the key is definitely not contained.
|
||||
func (bloom *stateBloom) Contain(key []byte) bool {
|
||||
return bloom.bloom.Contains(stateBloomHasher(key))
|
||||
return bloom.bloom.ContainsHash(stateBloomHash(key))
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/state/snapshot"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
@@ -96,7 +97,7 @@ func NewPruner(db ethdb.Database, config Config) (*Pruner, error) {
|
||||
return nil, errors.New("failed to load head block")
|
||||
}
|
||||
// Offline pruning is only supported in legacy hash based scheme.
|
||||
triedb := trie.NewDatabase(db, trie.HashDefaults)
|
||||
triedb := triedb.NewDatabase(db, triedb.HashDefaults)
|
||||
|
||||
// Note: we refuse to start a pruning session unless the snapshot disk layer exists, which should prevent
|
||||
// us from ever needing to enter RecoverPruning in an invalid pruning session (a session where we do not have
|
||||
@@ -135,7 +136,7 @@ func prune(maindb ethdb.Database, stateBloom *stateBloom, bloomPath string, star
|
||||
// the trie nodes(and codes) belong to the active state will be filtered
|
||||
// out. A very small part of stale tries will also be filtered because of
|
||||
// the false-positive rate of bloom filter. But the assumption is held here
|
||||
// that the false-positive is low enough(~0.05%). The probablity of the
|
||||
// that the false-positive is low enough(~0.05%). The probability of the
|
||||
// dangling node is the state root is super low. So the dangling nodes in
|
||||
// theory will never ever be visited again.
|
||||
var (
|
||||
@@ -347,7 +348,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
|
||||
if genesis == nil {
|
||||
return errors.New("missing genesis block")
|
||||
}
|
||||
t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), trie.NewDatabase(db, trie.HashDefaults))
|
||||
t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), triedb.NewDatabase(db, triedb.HashDefaults))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -371,7 +372,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
|
||||
}
|
||||
if acc.Root != types.EmptyRootHash {
|
||||
id := trie.StorageTrieID(genesis.Root(), common.BytesToHash(accIter.LeafKey()), acc.Root)
|
||||
storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db, trie.HashDefaults))
|
||||
storageTrie, err := trie.NewStateTrie(id, triedb.NewDatabase(db, triedb.HashDefaults))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ import (
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
// generatorStats is a collection of statistics gathered by the snapshot generator
|
||||
// for logging purposes.
|
||||
type generatorStats struct {
|
||||
wiping chan struct{} // Notification channel if wiping is in progress
|
||||
origin uint64 // Origin prefix where generation started
|
||||
|
||||
@@ -53,7 +53,7 @@ var (
|
||||
aggregatorMemoryLimit = uint64(4 * 1024 * 1024)
|
||||
|
||||
// aggregatorItemLimit is an approximate number of items that will end up
|
||||
// in the agregator layer before it's flushed out to disk. A plain account
|
||||
// in the aggregator layer before it's flushed out to disk. A plain account
|
||||
// weighs around 14B (+hash), a storage slot 32B (+hash), a deleted slot
|
||||
// 0B (+hash). Slots are mostly set/unset in lockstep, so that average at
|
||||
// 16B (+hash). All in all, the average entry seems to be 15+32=47B. Use a
|
||||
@@ -135,47 +135,20 @@ type diffLayer struct {
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// destructBloomHasher is a wrapper around a common.Hash to satisfy the interface
|
||||
// API requirements of the bloom library used. It's used to convert a destruct
|
||||
// event into a 64 bit mini hash.
|
||||
type destructBloomHasher common.Hash
|
||||
|
||||
func (h destructBloomHasher) Write(p []byte) (n int, err error) { panic("not implemented") }
|
||||
func (h destructBloomHasher) Sum(b []byte) []byte { panic("not implemented") }
|
||||
func (h destructBloomHasher) Reset() { panic("not implemented") }
|
||||
func (h destructBloomHasher) BlockSize() int { panic("not implemented") }
|
||||
func (h destructBloomHasher) Size() int { return 8 }
|
||||
func (h destructBloomHasher) Sum64() uint64 {
|
||||
// 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])
|
||||
}
|
||||
|
||||
// accountBloomHasher is a wrapper around a common.Hash to satisfy the interface
|
||||
// API requirements of the bloom library used. It's used to convert an account
|
||||
// hash into a 64 bit mini hash.
|
||||
type accountBloomHasher common.Hash
|
||||
|
||||
func (h accountBloomHasher) Write(p []byte) (n int, err error) { panic("not implemented") }
|
||||
func (h accountBloomHasher) Sum(b []byte) []byte { panic("not implemented") }
|
||||
func (h accountBloomHasher) Reset() { panic("not implemented") }
|
||||
func (h accountBloomHasher) BlockSize() int { panic("not implemented") }
|
||||
func (h accountBloomHasher) Size() int { return 8 }
|
||||
func (h accountBloomHasher) Sum64() uint64 {
|
||||
// accountBloomHash is used to convert an account hash into a 64 bit mini hash.
|
||||
func accountBloomHash(h common.Hash) uint64 {
|
||||
return binary.BigEndian.Uint64(h[bloomAccountHasherOffset : bloomAccountHasherOffset+8])
|
||||
}
|
||||
|
||||
// storageBloomHasher is a wrapper around a [2]common.Hash to satisfy the interface
|
||||
// API requirements of the bloom library used. It's used to convert an account
|
||||
// hash into a 64 bit mini hash.
|
||||
type storageBloomHasher [2]common.Hash
|
||||
|
||||
func (h storageBloomHasher) Write(p []byte) (n int, err error) { panic("not implemented") }
|
||||
func (h storageBloomHasher) Sum(b []byte) []byte { panic("not implemented") }
|
||||
func (h storageBloomHasher) Reset() { panic("not implemented") }
|
||||
func (h storageBloomHasher) BlockSize() int { panic("not implemented") }
|
||||
func (h storageBloomHasher) Size() int { return 8 }
|
||||
func (h storageBloomHasher) Sum64() uint64 {
|
||||
return binary.BigEndian.Uint64(h[0][bloomStorageHasherOffset:bloomStorageHasherOffset+8]) ^
|
||||
binary.BigEndian.Uint64(h[1][bloomStorageHasherOffset:bloomStorageHasherOffset+8])
|
||||
// storageBloomHash is used to convert an account hash and a storage hash into a 64 bit mini hash.
|
||||
func storageBloomHash(h0, h1 common.Hash) uint64 {
|
||||
return binary.BigEndian.Uint64(h0[bloomStorageHasherOffset:bloomStorageHasherOffset+8]) ^
|
||||
binary.BigEndian.Uint64(h1[bloomStorageHasherOffset:bloomStorageHasherOffset+8])
|
||||
}
|
||||
|
||||
// newDiffLayer creates a new diff on top of an existing snapshot, whether that's a low
|
||||
@@ -245,14 +218,14 @@ func (dl *diffLayer) rebloom(origin *diskLayer) {
|
||||
}
|
||||
// Iterate over all the accounts and storage slots and index them
|
||||
for hash := range dl.destructSet {
|
||||
dl.diffed.Add(destructBloomHasher(hash))
|
||||
dl.diffed.AddHash(destructBloomHash(hash))
|
||||
}
|
||||
for hash := range dl.accountData {
|
||||
dl.diffed.Add(accountBloomHasher(hash))
|
||||
dl.diffed.AddHash(accountBloomHash(hash))
|
||||
}
|
||||
for accountHash, slots := range dl.storageData {
|
||||
for storageHash := range slots {
|
||||
dl.diffed.Add(storageBloomHasher{accountHash, storageHash})
|
||||
dl.diffed.AddHash(storageBloomHash(accountHash, storageHash))
|
||||
}
|
||||
}
|
||||
// Calculate the current false positive rate and update the error rate meter.
|
||||
@@ -318,9 +291,9 @@ func (dl *diffLayer) AccountRLP(hash common.Hash) ([]byte, error) {
|
||||
}
|
||||
// Check the bloom filter first whether there's even a point in reaching into
|
||||
// all the maps in all the layers below
|
||||
hit := dl.diffed.Contains(accountBloomHasher(hash))
|
||||
hit := dl.diffed.ContainsHash(accountBloomHash(hash))
|
||||
if !hit {
|
||||
hit = dl.diffed.Contains(destructBloomHasher(hash))
|
||||
hit = dl.diffed.ContainsHash(destructBloomHash(hash))
|
||||
}
|
||||
var origin *diskLayer
|
||||
if !hit {
|
||||
@@ -389,9 +362,9 @@ func (dl *diffLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro
|
||||
dl.lock.RUnlock()
|
||||
return nil, ErrSnapshotStale
|
||||
}
|
||||
hit := dl.diffed.Contains(storageBloomHasher{accountHash, storageHash})
|
||||
hit := dl.diffed.ContainsHash(storageBloomHash(accountHash, storageHash))
|
||||
if !hit {
|
||||
hit = dl.diffed.Contains(destructBloomHasher(accountHash))
|
||||
hit = dl.diffed.ContainsHash(destructBloomHash(accountHash))
|
||||
}
|
||||
var origin *diskLayer
|
||||
if !hit {
|
||||
|
||||
@@ -33,7 +33,7 @@ import (
|
||||
|
||||
"github.com/ava-labs/subnet-evm/core/rawdb"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ava-labs/subnet-evm/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
@@ -43,7 +43,7 @@ import (
|
||||
// diskLayer is a low level persistent snapshot built on top of a key-value store.
|
||||
type diskLayer struct {
|
||||
diskdb ethdb.KeyValueStore // Key-value store containing the base snapshot
|
||||
triedb *trie.Database // Trie node cache for reconstruction purposes
|
||||
triedb *triedb.Database // Trie node cache for reconstruction purposes
|
||||
cache *utils.MeteredCache // Cache to avoid hitting the disk for direct access
|
||||
|
||||
blockHash common.Hash // Block hash of the base snapshot
|
||||
|
||||
@@ -144,7 +144,7 @@ func TestDiskMerge(t *testing.T) {
|
||||
// Retrieve all the data through the disk layer and validate it
|
||||
base = snaps.Snapshot(diffRoot)
|
||||
if _, ok := base.(*diskLayer); !ok {
|
||||
t.Fatalf("update not flattend into the disk layer")
|
||||
t.Fatalf("update not flattened into the disk layer")
|
||||
}
|
||||
|
||||
// assertAccount ensures that an account matches the given blob.
|
||||
@@ -363,7 +363,7 @@ func TestDiskPartialMerge(t *testing.T) {
|
||||
// Retrieve all the data through the disk layer and validate it
|
||||
base = snaps.Snapshot(diffRoot)
|
||||
if _, ok := base.(*diskLayer); !ok {
|
||||
t.Fatalf("test %d: update not flattend into the disk layer", i)
|
||||
t.Fatalf("test %d: update not flattened into the disk layer", i)
|
||||
}
|
||||
assertAccount(accNoModNoCache, accNoModNoCache[:])
|
||||
assertAccount(accNoModCache, accNoModCache[:])
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/rawdb"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ava-labs/subnet-evm/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
@@ -49,7 +50,7 @@ const (
|
||||
// generateSnapshot regenerates a brand new snapshot based on an existing state
|
||||
// database and head block asynchronously. The snapshot is returned immediately
|
||||
// and generation is continued in the background until done.
|
||||
func generateSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, blockHash, root common.Hash, wiper chan struct{}) *diskLayer {
|
||||
func generateSnapshot(diskdb ethdb.KeyValueStore, triedb *triedb.Database, cache int, blockHash, root common.Hash, wiper chan struct{}) *diskLayer {
|
||||
// Wipe any previously existing snapshot from the database if no wiper is
|
||||
// currently in progress.
|
||||
if wiper == nil {
|
||||
|
||||
@@ -28,7 +28,6 @@ package snapshot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -36,13 +35,15 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/rawdb"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/trie/triedb/hashdb"
|
||||
"github.com/ava-labs/subnet-evm/trie/triedb/pathdb"
|
||||
"github.com/ava-labs/subnet-evm/trie/trienode"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ava-labs/subnet-evm/triedb/hashdb"
|
||||
"github.com/ava-labs/subnet-evm/triedb/pathdb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/holiman/uint256"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
@@ -70,9 +71,9 @@ func testGeneration(t *testing.T, scheme string) {
|
||||
var helper = newHelper(scheme)
|
||||
stRoot := helper.makeStorageTrie(common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, false)
|
||||
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
@@ -110,16 +111,16 @@ func testGenerateExistentState(t *testing.T, scheme string) {
|
||||
var helper = newHelper(scheme)
|
||||
|
||||
stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||
|
||||
root, snap := helper.CommitAndGenerate()
|
||||
@@ -166,20 +167,20 @@ func checkSnapRoot(t *testing.T, snap *diskLayer, trieRoot common.Hash) {
|
||||
|
||||
type testHelper struct {
|
||||
diskdb ethdb.Database
|
||||
triedb *trie.Database
|
||||
triedb *triedb.Database
|
||||
accTrie *trie.StateTrie
|
||||
nodes *trienode.MergedNodeSet
|
||||
}
|
||||
|
||||
func newHelper(scheme string) *testHelper {
|
||||
diskdb := rawdb.NewMemoryDatabase()
|
||||
config := &trie.Config{}
|
||||
config := &triedb.Config{}
|
||||
if scheme == rawdb.PathScheme {
|
||||
config.PathDB = &pathdb.Config{} // disable caching
|
||||
} else {
|
||||
config.HashDB = &hashdb.Config{} // disable caching
|
||||
}
|
||||
triedb := trie.NewDatabase(diskdb, config)
|
||||
triedb := triedb.NewDatabase(diskdb, config)
|
||||
accTrie, _ := trie.NewStateTrie(trie.StateTrieID(types.EmptyRootHash), triedb)
|
||||
return &testHelper{
|
||||
diskdb: diskdb,
|
||||
@@ -270,28 +271,28 @@ func testGenerateExistentStateWithWrongStorage(t *testing.T, scheme string) {
|
||||
helper := newHelper(scheme)
|
||||
|
||||
// Account one, empty root but non-empty database
|
||||
helper.addAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||
|
||||
// Account two, non empty root but empty database
|
||||
stRoot := helper.makeStorageTrie(hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-2", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
// Miss slots
|
||||
{
|
||||
// Account three, non empty root but misses slots in the beginning
|
||||
helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-3", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-3", []string{"key-2", "key-3"}, []string{"val-2", "val-3"})
|
||||
|
||||
// Account four, non empty root but misses slots in the middle
|
||||
helper.makeStorageTrie(hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-4", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-4", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-4", []string{"key-1", "key-3"}, []string{"val-1", "val-3"})
|
||||
|
||||
// Account five, non empty root but misses slots in the end
|
||||
helper.makeStorageTrie(hashData([]byte("acc-5")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-5", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-5", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"})
|
||||
}
|
||||
|
||||
@@ -299,22 +300,22 @@ func testGenerateExistentStateWithWrongStorage(t *testing.T, scheme string) {
|
||||
{
|
||||
// Account six, non empty root but wrong slots in the beginning
|
||||
helper.makeStorageTrie(hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-6", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-6", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"badval-1", "val-2", "val-3"})
|
||||
|
||||
// Account seven, non empty root but wrong slots in the middle
|
||||
helper.makeStorageTrie(hashData([]byte("acc-7")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-7", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-7", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "badval-2", "val-3"})
|
||||
|
||||
// Account eight, non empty root but wrong slots in the end
|
||||
helper.makeStorageTrie(hashData([]byte("acc-8")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-8", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-8", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "badval-3"})
|
||||
|
||||
// Account 9, non empty root but rotated slots
|
||||
helper.makeStorageTrie(hashData([]byte("acc-9")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-9", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-9", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"})
|
||||
}
|
||||
|
||||
@@ -322,17 +323,17 @@ func testGenerateExistentStateWithWrongStorage(t *testing.T, scheme string) {
|
||||
{
|
||||
// Account 10, non empty root but extra slots in the beginning
|
||||
helper.makeStorageTrie(hashData([]byte("acc-10")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-10", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-10", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-10", []string{"key-0", "key-1", "key-2", "key-3"}, []string{"val-0", "val-1", "val-2", "val-3"})
|
||||
|
||||
// Account 11, non empty root but extra slots in the middle
|
||||
helper.makeStorageTrie(hashData([]byte("acc-11")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-11", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-11", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-11", []string{"key-1", "key-2", "key-2-1", "key-3"}, []string{"val-1", "val-2", "val-2-1", "val-3"})
|
||||
|
||||
// Account 12, non empty root but extra slots in the end
|
||||
helper.makeStorageTrie(hashData([]byte("acc-12")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-12", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-12", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"})
|
||||
}
|
||||
|
||||
@@ -377,25 +378,25 @@ func testGenerateExistentStateWithWrongAccounts(t *testing.T, scheme string) {
|
||||
|
||||
// Missing accounts, only in the trie
|
||||
{
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Beginning
|
||||
helper.addTrieAccount("acc-4", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Middle
|
||||
helper.addTrieAccount("acc-6", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // End
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Beginning
|
||||
helper.addTrieAccount("acc-4", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Middle
|
||||
helper.addTrieAccount("acc-6", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // End
|
||||
}
|
||||
|
||||
// Wrong accounts
|
||||
{
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-2", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: common.Hex2Bytes("0x1234")})
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: common.Hex2Bytes("0x1234")})
|
||||
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-3", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
}
|
||||
|
||||
// Extra accounts, only in the snap
|
||||
{
|
||||
helper.addSnapAccount("acc-0", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // before the beginning
|
||||
helper.addSnapAccount("acc-5", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: common.Hex2Bytes("0x1234")}) // Middle
|
||||
helper.addSnapAccount("acc-7", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // after the end
|
||||
helper.addSnapAccount("acc-0", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // before the beginning
|
||||
helper.addSnapAccount("acc-5", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: common.Hex2Bytes("0x1234")}) // Middle
|
||||
helper.addSnapAccount("acc-7", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // after the end
|
||||
}
|
||||
|
||||
root, snap := helper.CommitAndGenerate()
|
||||
@@ -429,9 +430,9 @@ func testGenerateCorruptAccountTrie(t *testing.T, scheme string) {
|
||||
// without any storage slots to keep the test smaller.
|
||||
helper := newHelper(scheme)
|
||||
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4
|
||||
|
||||
root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978
|
||||
|
||||
@@ -473,11 +474,11 @@ func testGenerateMissingStorageTrie(t *testing.T, scheme string) {
|
||||
acc3 = hashData([]byte("acc-3"))
|
||||
helper = newHelper(scheme)
|
||||
)
|
||||
stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
|
||||
|
||||
root := helper.Commit()
|
||||
|
||||
@@ -513,11 +514,11 @@ func testGenerateCorruptStorageTrie(t *testing.T, scheme string) {
|
||||
// two of which also has the same 3-slot storage trie attached.
|
||||
helper := newHelper(scheme)
|
||||
|
||||
stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
stRoot = helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
|
||||
|
||||
root := helper.Commit()
|
||||
|
||||
@@ -557,7 +558,7 @@ func testGenerateWithExtraAccounts(t *testing.T, scheme string) {
|
||||
[]string{"val-1", "val-2", "val-3", "val-4", "val-5"},
|
||||
true,
|
||||
)
|
||||
acc := &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
|
||||
@@ -577,7 +578,7 @@ func testGenerateWithExtraAccounts(t *testing.T, scheme string) {
|
||||
[]string{"val-1", "val-2", "val-3", "val-4", "val-5"},
|
||||
true,
|
||||
)
|
||||
acc := &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
key := hashData([]byte("acc-2"))
|
||||
rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
|
||||
@@ -633,7 +634,7 @@ func testGenerateWithManyExtraAccounts(t *testing.T, scheme string) {
|
||||
[]string{"val-1", "val-2", "val-3"},
|
||||
true,
|
||||
)
|
||||
acc := &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
|
||||
@@ -647,7 +648,7 @@ func testGenerateWithManyExtraAccounts(t *testing.T, scheme string) {
|
||||
{
|
||||
// 100 accounts exist only in snapshot
|
||||
for i := 0; i < 1000; i++ {
|
||||
acc := &types.StateAccount{Balance: big.NewInt(int64(i)), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
acc := &types.StateAccount{Balance: uint256.NewInt(uint64(i)), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
key := hashData([]byte(fmt.Sprintf("acc-%d", i)))
|
||||
rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
|
||||
@@ -688,7 +689,7 @@ func testGenerateWithExtraBeforeAndAfter(t *testing.T, scheme string) {
|
||||
}
|
||||
helper := newHelper(scheme)
|
||||
{
|
||||
acc := &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val)
|
||||
helper.accTrie.MustUpdate(common.HexToHash("0x07").Bytes(), val)
|
||||
@@ -729,7 +730,7 @@ func testGenerateWithMalformedSnapdata(t *testing.T, scheme string) {
|
||||
}
|
||||
helper := newHelper(scheme)
|
||||
{
|
||||
acc := &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
acc := &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val)
|
||||
|
||||
@@ -771,7 +772,7 @@ func testGenerateFromEmptySnap(t *testing.T, scheme string) {
|
||||
for i := 0; i < 400; i++ {
|
||||
stRoot := helper.makeStorageTrie(hashData([]byte(fmt.Sprintf("acc-%d", i))), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount(fmt.Sprintf("acc-%d", i),
|
||||
&types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
&types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
}
|
||||
root, snap := helper.CommitAndGenerate()
|
||||
t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4
|
||||
@@ -812,7 +813,7 @@ func testGenerateWithIncompleteStorage(t *testing.T, scheme string) {
|
||||
for i := 0; i < 8; i++ {
|
||||
accKey := fmt.Sprintf("acc-%d", i)
|
||||
stRoot := helper.makeStorageTrie(hashData([]byte(accKey)), stKeys, stVals, true)
|
||||
helper.addAccount(accKey, &types.StateAccount{Balance: big.NewInt(int64(i)), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount(accKey, &types.StateAccount{Balance: uint256.NewInt(uint64(i)), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
var moddedKeys []string
|
||||
var moddedVals []string
|
||||
for ii := 0; ii < 8; ii++ {
|
||||
@@ -909,11 +910,11 @@ func testGenerateCompleteSnapshotWithDanglingStorage(t *testing.T, scheme string
|
||||
var helper = newHelper(scheme)
|
||||
|
||||
stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-2", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-3", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||
helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||
@@ -949,11 +950,11 @@ func testGenerateBrokenSnapshotWithDanglingStorage(t *testing.T, scheme string)
|
||||
var helper = newHelper(scheme)
|
||||
|
||||
stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
populateDangling(helper.diskdb)
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/core/rawdb"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
@@ -56,7 +56,7 @@ type journalGenerator struct {
|
||||
// loadSnapshot loads a pre-existing state snapshot backed by a key-value
|
||||
// store. If loading the snapshot from disk is successful, this function also
|
||||
// returns a boolean indicating whether or not the snapshot is fully generated.
|
||||
func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, blockHash, root common.Hash, noBuild bool) (snapshot, bool, error) {
|
||||
func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *triedb.Database, cache int, blockHash, root common.Hash, noBuild bool) (snapshot, bool, error) {
|
||||
// Retrieve the block number and hash of the snapshot, failing if no snapshot
|
||||
// is present in the database (or crashed mid-update).
|
||||
baseBlockHash := rawdb.ReadSnapshotBlockHash(diskdb)
|
||||
|
||||
@@ -37,7 +37,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/rawdb"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/metrics"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
@@ -186,7 +186,7 @@ type Config struct {
|
||||
type Tree struct {
|
||||
config Config // Snapshots configurations
|
||||
diskdb ethdb.KeyValueStore // Persistent database to store the snapshot
|
||||
triedb *trie.Database // In-memory cache to access the trie through
|
||||
triedb *triedb.Database // In-memory cache to access the trie through
|
||||
// Collection of all known layers
|
||||
// blockHash -> snapshot
|
||||
blockLayers map[common.Hash]snapshot
|
||||
@@ -208,7 +208,7 @@ type Tree struct {
|
||||
// If the snapshot is missing or the disk layer is broken, the snapshot will be
|
||||
// reconstructed using both the existing data and the state trie.
|
||||
// The repair happens on a background thread.
|
||||
func New(config Config, diskdb ethdb.KeyValueStore, triedb *trie.Database, blockHash, root common.Hash) (*Tree, error) {
|
||||
func New(config Config, diskdb ethdb.KeyValueStore, triedb *triedb.Database, blockHash, root common.Hash) (*Tree, error) {
|
||||
// Create a new, empty snapshot tree
|
||||
snap := &Tree{
|
||||
config: config,
|
||||
|
||||
@@ -29,7 +29,6 @@ package snapshot
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -38,6 +37,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// randomHash generates a random blob of data and returns it as a hash.
|
||||
@@ -52,7 +52,7 @@ func randomHash() common.Hash {
|
||||
// randomAccount generates a random account and returns it RLP encoded.
|
||||
func randomAccount() []byte {
|
||||
a := &types.StateAccount{
|
||||
Balance: big.NewInt(rand.Int63()),
|
||||
Balance: uint256.NewInt(rand.Uint64()),
|
||||
Nonce: rand.Uint64(),
|
||||
Root: randomHash(),
|
||||
CodeHash: types.EmptyCodeHash[:],
|
||||
@@ -610,19 +610,19 @@ func TestRebloomOnFlatten(t *testing.T) {
|
||||
t.Fatal("snapshot should be a diffLayer")
|
||||
}
|
||||
|
||||
if hitsA != dl.diffed.Contains(accountBloomHasher(addrA)) {
|
||||
if hitsA != dl.diffed.ContainsHash(accountBloomHash(addrA)) {
|
||||
t.Errorf("expected bloom filter to return %t but got %t", hitsA, !hitsA)
|
||||
}
|
||||
|
||||
if hitsB != dl.diffed.Contains(accountBloomHasher(addrB)) {
|
||||
if hitsB != dl.diffed.ContainsHash(accountBloomHash(addrB)) {
|
||||
t.Errorf("expected bloom filter to return %t but got %t", hitsB, !hitsB)
|
||||
}
|
||||
|
||||
if hitsC != dl.diffed.Contains(accountBloomHasher(addrC)) {
|
||||
if hitsC != dl.diffed.ContainsHash(accountBloomHash(addrC)) {
|
||||
t.Errorf("expected bloom filter to return %t but got %t", hitsC, !hitsC)
|
||||
}
|
||||
|
||||
if hitsD != dl.diffed.Contains(accountBloomHasher(addrD)) {
|
||||
if hitsD != dl.diffed.ContainsHash(accountBloomHash(addrD)) {
|
||||
t.Errorf("expected bloom filter to return %t but got %t", hitsD, !hitsD)
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -30,7 +30,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
@@ -39,6 +38,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
type Code []byte
|
||||
@@ -103,7 +103,7 @@ type stateObject struct {
|
||||
|
||||
// empty returns whether the account is considered empty.
|
||||
func (s *stateObject) empty() bool {
|
||||
return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, types.EmptyCodeHash.Bytes())
|
||||
return s.data.Nonce == 0 && s.data.Balance.IsZero() && bytes.Equal(s.data.CodeHash, types.EmptyCodeHash.Bytes())
|
||||
}
|
||||
|
||||
// newObject creates a state object.
|
||||
@@ -415,36 +415,36 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) {
|
||||
|
||||
// AddBalance adds amount to s's balance.
|
||||
// It is used to add funds to the destination account of a transfer.
|
||||
func (s *stateObject) AddBalance(amount *big.Int) {
|
||||
func (s *stateObject) AddBalance(amount *uint256.Int) {
|
||||
// EIP161: We must check emptiness for the objects such that the account
|
||||
// clearing (0,0,0 objects) can take effect.
|
||||
if amount.Sign() == 0 {
|
||||
if amount.IsZero() {
|
||||
if s.empty() {
|
||||
s.touch()
|
||||
}
|
||||
return
|
||||
}
|
||||
s.SetBalance(new(big.Int).Add(s.Balance(), amount))
|
||||
s.SetBalance(new(uint256.Int).Add(s.Balance(), amount))
|
||||
}
|
||||
|
||||
// SubBalance removes amount from s's balance.
|
||||
// It is used to remove funds from the origin account of a transfer.
|
||||
func (s *stateObject) SubBalance(amount *big.Int) {
|
||||
if amount.Sign() == 0 {
|
||||
func (s *stateObject) SubBalance(amount *uint256.Int) {
|
||||
if amount.IsZero() {
|
||||
return
|
||||
}
|
||||
s.SetBalance(new(big.Int).Sub(s.Balance(), amount))
|
||||
s.SetBalance(new(uint256.Int).Sub(s.Balance(), amount))
|
||||
}
|
||||
|
||||
func (s *stateObject) SetBalance(amount *big.Int) {
|
||||
func (s *stateObject) SetBalance(amount *uint256.Int) {
|
||||
s.db.journal.append(balanceChange{
|
||||
account: &s.address,
|
||||
prev: new(big.Int).Set(s.data.Balance),
|
||||
prev: new(uint256.Int).Set(s.data.Balance),
|
||||
})
|
||||
s.setBalance(amount)
|
||||
}
|
||||
|
||||
func (s *stateObject) setBalance(amount *big.Int) {
|
||||
func (s *stateObject) setBalance(amount *uint256.Int) {
|
||||
s.data.Balance = amount
|
||||
}
|
||||
|
||||
@@ -543,7 +543,7 @@ func (s *stateObject) CodeHash() []byte {
|
||||
return s.data.CodeHash
|
||||
}
|
||||
|
||||
func (s *stateObject) Balance() *big.Int {
|
||||
func (s *stateObject) Balance() *uint256.Int {
|
||||
return s.data.Balance
|
||||
}
|
||||
|
||||
|
||||
+230
-11
@@ -29,15 +29,15 @@ package state
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/core/rawdb"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
type stateEnv struct {
|
||||
@@ -51,21 +51,78 @@ func newStateEnv() *stateEnv {
|
||||
return &stateEnv{db: db, state: sdb}
|
||||
}
|
||||
|
||||
func TestIterativeDump(t *testing.T) {
|
||||
func TestDump(t *testing.T) {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
tdb := NewDatabaseWithConfig(db, &trie.Config{Preimages: true})
|
||||
tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
||||
sdb, _ := New(types.EmptyRootHash, tdb, nil)
|
||||
s := &stateEnv{db: db, state: sdb}
|
||||
|
||||
// generate a few entries
|
||||
obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
||||
obj1.AddBalance(big.NewInt(22))
|
||||
obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
|
||||
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
||||
obj1.AddBalance(uint256.NewInt(22))
|
||||
obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
|
||||
obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
|
||||
obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02}))
|
||||
obj3.SetBalance(big.NewInt(44))
|
||||
obj4 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x00}))
|
||||
obj4.AddBalance(big.NewInt(1337))
|
||||
obj3 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02}))
|
||||
obj3.SetBalance(uint256.NewInt(44))
|
||||
|
||||
// write some of them to the trie
|
||||
s.state.updateStateObject(obj1)
|
||||
s.state.updateStateObject(obj2)
|
||||
root, _ := s.state.Commit(0, false, false)
|
||||
|
||||
// check that DumpToCollector contains the state objects that are in trie
|
||||
s.state, _ = New(root, tdb, nil)
|
||||
got := string(s.state.Dump(nil))
|
||||
want := `{
|
||||
"root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2",
|
||||
"accounts": {
|
||||
"0x0000000000000000000000000000000000000001": {
|
||||
"balance": "22",
|
||||
"nonce": 0,
|
||||
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
||||
"address": "0x0000000000000000000000000000000000000001",
|
||||
"key": "0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000002": {
|
||||
"balance": "44",
|
||||
"nonce": 0,
|
||||
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
||||
"address": "0x0000000000000000000000000000000000000002",
|
||||
"key": "0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62"
|
||||
},
|
||||
"0x0000000000000000000000000000000000000102": {
|
||||
"balance": "0",
|
||||
"nonce": 0,
|
||||
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"codeHash": "0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3",
|
||||
"code": "0x03030303030303",
|
||||
"address": "0x0000000000000000000000000000000000000102",
|
||||
"key": "0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1"
|
||||
}
|
||||
}
|
||||
}`
|
||||
if got != want {
|
||||
t.Errorf("DumpToCollector mismatch:\ngot: %s\nwant: %s\n", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIterativeDump(t *testing.T) {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
tdb := NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
||||
sdb, _ := New(types.EmptyRootHash, tdb, nil)
|
||||
s := &stateEnv{db: db, state: sdb}
|
||||
|
||||
// generate a few entries
|
||||
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
||||
obj1.AddBalance(uint256.NewInt(22))
|
||||
obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
|
||||
obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
|
||||
obj3 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02}))
|
||||
obj3.SetBalance(uint256.NewInt(44))
|
||||
obj4 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x00}))
|
||||
obj4.AddBalance(uint256.NewInt(1337))
|
||||
|
||||
// write some of them to the trie
|
||||
s.state.updateStateObject(obj1)
|
||||
@@ -87,3 +144,165 @@ func TestIterativeDump(t *testing.T) {
|
||||
t.Errorf("DumpToCollector mismatch:\ngot: %s\nwant: %s\n", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNull(t *testing.T) {
|
||||
s := newStateEnv()
|
||||
address := common.HexToAddress("0x823140710bf13990e4500136726d8b55")
|
||||
s.state.CreateAccount(address)
|
||||
//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
|
||||
var value common.Hash
|
||||
|
||||
s.state.SetState(address, common.Hash{}, value)
|
||||
s.state.Commit(0, false, false)
|
||||
|
||||
if value := s.state.GetState(address, common.Hash{}); value != (common.Hash{}) {
|
||||
t.Errorf("expected empty current value, got %x", value)
|
||||
}
|
||||
if value := s.state.GetCommittedState(address, common.Hash{}); value != (common.Hash{}) {
|
||||
t.Errorf("expected empty committed value, got %x", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshot(t *testing.T) {
|
||||
stateobjaddr := common.BytesToAddress([]byte("aa"))
|
||||
var storageaddr common.Hash
|
||||
data1 := common.BytesToHash([]byte{42})
|
||||
data2 := common.BytesToHash([]byte{43})
|
||||
s := newStateEnv()
|
||||
|
||||
// snapshot the genesis state
|
||||
genesis := s.state.Snapshot()
|
||||
|
||||
// set initial state object value
|
||||
s.state.SetState(stateobjaddr, storageaddr, data1)
|
||||
snapshot := s.state.Snapshot()
|
||||
|
||||
// set a new state object value, revert it and ensure correct content
|
||||
s.state.SetState(stateobjaddr, storageaddr, data2)
|
||||
s.state.RevertToSnapshot(snapshot)
|
||||
|
||||
if v := s.state.GetState(stateobjaddr, storageaddr); v != data1 {
|
||||
t.Errorf("wrong storage value %v, want %v", v, data1)
|
||||
}
|
||||
if v := s.state.GetCommittedState(stateobjaddr, storageaddr); v != (common.Hash{}) {
|
||||
t.Errorf("wrong committed storage value %v, want %v", v, common.Hash{})
|
||||
}
|
||||
|
||||
// revert up to the genesis state and ensure correct content
|
||||
s.state.RevertToSnapshot(genesis)
|
||||
if v := s.state.GetState(stateobjaddr, storageaddr); v != (common.Hash{}) {
|
||||
t.Errorf("wrong storage value %v, want %v", v, common.Hash{})
|
||||
}
|
||||
if v := s.state.GetCommittedState(stateobjaddr, storageaddr); v != (common.Hash{}) {
|
||||
t.Errorf("wrong committed storage value %v, want %v", v, common.Hash{})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotEmpty(t *testing.T) {
|
||||
s := newStateEnv()
|
||||
s.state.RevertToSnapshot(s.state.Snapshot())
|
||||
}
|
||||
|
||||
func TestSnapshot2(t *testing.T) {
|
||||
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
|
||||
stateobjaddr0 := common.BytesToAddress([]byte("so0"))
|
||||
stateobjaddr1 := common.BytesToAddress([]byte("so1"))
|
||||
var storageaddr common.Hash
|
||||
|
||||
data0 := common.BytesToHash([]byte{17})
|
||||
data1 := common.BytesToHash([]byte{18})
|
||||
|
||||
state.SetState(stateobjaddr0, storageaddr, data0)
|
||||
state.SetState(stateobjaddr1, storageaddr, data1)
|
||||
|
||||
// db, trie are already non-empty values
|
||||
so0 := state.getStateObject(stateobjaddr0)
|
||||
so0.SetBalance(uint256.NewInt(42))
|
||||
so0.SetNonce(43)
|
||||
so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
|
||||
so0.selfDestructed = false
|
||||
so0.deleted = false
|
||||
state.setStateObject(so0)
|
||||
|
||||
root, _ := state.Commit(0, false, false)
|
||||
state, _ = New(root, state.db, nil)
|
||||
|
||||
// and one with deleted == true
|
||||
so1 := state.getStateObject(stateobjaddr1)
|
||||
so1.SetBalance(uint256.NewInt(52))
|
||||
so1.SetNonce(53)
|
||||
so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'})
|
||||
so1.selfDestructed = true
|
||||
so1.deleted = true
|
||||
state.setStateObject(so1)
|
||||
|
||||
so1 = state.getStateObject(stateobjaddr1)
|
||||
if so1 != nil {
|
||||
t.Fatalf("deleted object not nil when getting")
|
||||
}
|
||||
|
||||
snapshot := state.Snapshot()
|
||||
state.RevertToSnapshot(snapshot)
|
||||
|
||||
so0Restored := state.getStateObject(stateobjaddr0)
|
||||
// Update lazily-loaded values before comparing.
|
||||
so0Restored.GetState(storageaddr)
|
||||
so0Restored.Code()
|
||||
// non-deleted is equal (restored)
|
||||
compareStateObjects(so0Restored, so0, t)
|
||||
|
||||
// deleted should be nil, both before and after restore of state copy
|
||||
so1Restored := state.getStateObject(stateobjaddr1)
|
||||
if so1Restored != nil {
|
||||
t.Fatalf("deleted object not nil after restoring snapshot: %+v", so1Restored)
|
||||
}
|
||||
}
|
||||
|
||||
func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
|
||||
if so0.Address() != so1.Address() {
|
||||
t.Fatalf("Address mismatch: have %v, want %v", so0.address, so1.address)
|
||||
}
|
||||
if so0.Balance().Cmp(so1.Balance()) != 0 {
|
||||
t.Fatalf("Balance mismatch: have %v, want %v", so0.Balance(), so1.Balance())
|
||||
}
|
||||
if so0.Nonce() != so1.Nonce() {
|
||||
t.Fatalf("Nonce mismatch: have %v, want %v", so0.Nonce(), so1.Nonce())
|
||||
}
|
||||
if so0.data.Root != so1.data.Root {
|
||||
t.Errorf("Root mismatch: have %x, want %x", so0.data.Root[:], so1.data.Root[:])
|
||||
}
|
||||
if !bytes.Equal(so0.CodeHash(), so1.CodeHash()) {
|
||||
t.Fatalf("CodeHash mismatch: have %v, want %v", so0.CodeHash(), so1.CodeHash())
|
||||
}
|
||||
if !bytes.Equal(so0.code, so1.code) {
|
||||
t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code)
|
||||
}
|
||||
|
||||
if len(so1.dirtyStorage) != len(so0.dirtyStorage) {
|
||||
t.Errorf("Dirty storage size mismatch: have %d, want %d", len(so1.dirtyStorage), len(so0.dirtyStorage))
|
||||
}
|
||||
for k, v := range so1.dirtyStorage {
|
||||
if so0.dirtyStorage[k] != v {
|
||||
t.Errorf("Dirty storage key %x mismatch: have %v, want %v", k, so0.dirtyStorage[k], v)
|
||||
}
|
||||
}
|
||||
for k, v := range so0.dirtyStorage {
|
||||
if so1.dirtyStorage[k] != v {
|
||||
t.Errorf("Dirty storage key %x mismatch: have %v, want none.", k, v)
|
||||
}
|
||||
}
|
||||
if len(so1.originStorage) != len(so0.originStorage) {
|
||||
t.Errorf("Origin storage size mismatch: have %d, want %d", len(so1.originStorage), len(so0.originStorage))
|
||||
}
|
||||
for k, v := range so1.originStorage {
|
||||
if so0.originStorage[k] != v {
|
||||
t.Errorf("Origin storage key %x mismatch: have %v, want %v", k, so0.originStorage[k], v)
|
||||
}
|
||||
}
|
||||
for k, v := range so0.originStorage {
|
||||
if so1.originStorage[k] != v {
|
||||
t.Errorf("Origin storage key %x mismatch: have %v, want none.", k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
-20
@@ -29,7 +29,6 @@ package state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
@@ -45,6 +44,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -333,12 +333,12 @@ func (s *StateDB) Empty(addr common.Address) bool {
|
||||
}
|
||||
|
||||
// GetBalance retrieves the balance from the given address or 0 if object not found
|
||||
func (s *StateDB) GetBalance(addr common.Address) *big.Int {
|
||||
func (s *StateDB) GetBalance(addr common.Address) *uint256.Int {
|
||||
stateObject := s.getStateObject(addr)
|
||||
if stateObject != nil {
|
||||
return stateObject.Balance()
|
||||
}
|
||||
return new(big.Int).Set(common.Big0)
|
||||
return common.U2560
|
||||
}
|
||||
|
||||
// GetNonce retrieves the nonce from the given address or 0 if object not found
|
||||
@@ -384,10 +384,10 @@ func (s *StateDB) GetCodeSize(addr common.Address) int {
|
||||
|
||||
func (s *StateDB) GetCodeHash(addr common.Address) common.Hash {
|
||||
stateObject := s.getStateObject(addr)
|
||||
if stateObject == nil {
|
||||
return common.Hash{}
|
||||
if stateObject != nil {
|
||||
return common.BytesToHash(stateObject.CodeHash())
|
||||
}
|
||||
return common.BytesToHash(stateObject.CodeHash())
|
||||
return common.Hash{}
|
||||
}
|
||||
|
||||
// GetState retrieves a value from the given account's storage trie.
|
||||
@@ -426,44 +426,44 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
|
||||
*/
|
||||
|
||||
// AddBalance adds amount to the account associated with addr.
|
||||
func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
||||
stateObject := s.GetOrNewStateObject(addr)
|
||||
func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int) {
|
||||
stateObject := s.getOrNewStateObject(addr)
|
||||
if stateObject != nil {
|
||||
stateObject.AddBalance(amount)
|
||||
}
|
||||
}
|
||||
|
||||
// SubBalance subtracts amount from the account associated with addr.
|
||||
func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) {
|
||||
stateObject := s.GetOrNewStateObject(addr)
|
||||
func (s *StateDB) SubBalance(addr common.Address, amount *uint256.Int) {
|
||||
stateObject := s.getOrNewStateObject(addr)
|
||||
if stateObject != nil {
|
||||
stateObject.SubBalance(amount)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StateDB) SetBalance(addr common.Address, amount *big.Int) {
|
||||
stateObject := s.GetOrNewStateObject(addr)
|
||||
func (s *StateDB) SetBalance(addr common.Address, amount *uint256.Int) {
|
||||
stateObject := s.getOrNewStateObject(addr)
|
||||
if stateObject != nil {
|
||||
stateObject.SetBalance(amount)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StateDB) SetNonce(addr common.Address, nonce uint64) {
|
||||
stateObject := s.GetOrNewStateObject(addr)
|
||||
stateObject := s.getOrNewStateObject(addr)
|
||||
if stateObject != nil {
|
||||
stateObject.SetNonce(nonce)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StateDB) SetCode(addr common.Address, code []byte) {
|
||||
stateObject := s.GetOrNewStateObject(addr)
|
||||
stateObject := s.getOrNewStateObject(addr)
|
||||
if stateObject != nil {
|
||||
stateObject.SetCode(crypto.Keccak256Hash(code), code)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StateDB) SetState(addr common.Address, key, value common.Hash) {
|
||||
stateObject := s.GetOrNewStateObject(addr)
|
||||
stateObject := s.getOrNewStateObject(addr)
|
||||
if stateObject != nil {
|
||||
stateObject.SetState(key, value)
|
||||
}
|
||||
@@ -484,7 +484,7 @@ func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common
|
||||
if _, ok := s.stateObjectsDestruct[addr]; !ok {
|
||||
s.stateObjectsDestruct[addr] = nil
|
||||
}
|
||||
stateObject := s.GetOrNewStateObject(addr)
|
||||
stateObject := s.getOrNewStateObject(addr)
|
||||
for k, v := range storage {
|
||||
stateObject.SetState(k, v)
|
||||
}
|
||||
@@ -503,10 +503,10 @@ func (s *StateDB) SelfDestruct(addr common.Address) {
|
||||
s.journal.append(selfDestructChange{
|
||||
account: &addr,
|
||||
prev: stateObject.selfDestructed,
|
||||
prevbalance: new(big.Int).Set(stateObject.Balance()),
|
||||
prevbalance: new(uint256.Int).Set(stateObject.Balance()),
|
||||
})
|
||||
stateObject.markSelfdestructed()
|
||||
stateObject.data.Balance = new(big.Int)
|
||||
stateObject.data.Balance = new(uint256.Int)
|
||||
}
|
||||
|
||||
func (s *StateDB) Selfdestruct6780(addr common.Address) {
|
||||
@@ -667,8 +667,8 @@ func (s *StateDB) setStateObject(object *stateObject) {
|
||||
s.stateObjects[object.Address()] = object
|
||||
}
|
||||
|
||||
// GetOrNewStateObject retrieves a state object or create a new state object if nil.
|
||||
func (s *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
|
||||
// getOrNewStateObject retrieves a state object or create a new state object if nil.
|
||||
func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject {
|
||||
stateObject := s.getStateObject(addr)
|
||||
if stateObject == nil {
|
||||
stateObject, _ = s.createObject(addr)
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -43,11 +42,13 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/state/snapshot"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/trie/triedb/pathdb"
|
||||
"github.com/ava-labs/subnet-evm/trie/triestate"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ava-labs/subnet-evm/triedb/pathdb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// A stateTest checks that the state changes are correctly captured. Instances
|
||||
@@ -70,7 +71,7 @@ func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction
|
||||
{
|
||||
name: "SetBalance",
|
||||
fn: func(a testAction, s *StateDB) {
|
||||
s.SetBalance(addr, big.NewInt(a.args[0]))
|
||||
s.SetBalance(addr, uint256.NewInt(uint64(a.args[0])))
|
||||
},
|
||||
args: make([]int64, 1),
|
||||
},
|
||||
@@ -191,7 +192,7 @@ func (test *stateTest) run() bool {
|
||||
storageList = append(storageList, copy2DSet(states.Storages))
|
||||
}
|
||||
disk = rawdb.NewMemoryDatabase()
|
||||
tdb = trie.NewDatabase(disk, &trie.Config{PathDB: pathdb.Defaults})
|
||||
tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults})
|
||||
sdb = NewDatabaseWithNodeDB(disk, tdb)
|
||||
byzantium = rand.Intn(2) == 0
|
||||
)
|
||||
@@ -261,7 +262,7 @@ func (test *stateTest) run() bool {
|
||||
// - the account was indeed not present in trie
|
||||
// - the account is present in new trie, nil->nil is regarded as invalid
|
||||
// - the slots transition is correct
|
||||
func (test *stateTest) verifyAccountCreation(next common.Hash, db *trie.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, slots map[common.Hash][]byte) error {
|
||||
// Verify account change
|
||||
addrHash := crypto.Keccak256Hash(addr.Bytes())
|
||||
oBlob, err := otr.Get(addrHash.Bytes())
|
||||
@@ -312,7 +313,7 @@ func (test *stateTest) verifyAccountCreation(next common.Hash, db *trie.Database
|
||||
// - the account was indeed present in trie
|
||||
// - the account in old trie matches the provided value
|
||||
// - the slots transition is correct
|
||||
func (test *stateTest) verifyAccountUpdate(next common.Hash, db *trie.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, origin []byte, slots map[common.Hash][]byte) error {
|
||||
// Verify account change
|
||||
addrHash := crypto.Keccak256Hash(addr.Bytes())
|
||||
oBlob, err := otr.Get(addrHash.Bytes())
|
||||
@@ -366,7 +367,7 @@ func (test *stateTest) verifyAccountUpdate(next common.Hash, db *trie.Database,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (test *stateTest) verify(root common.Hash, next common.Hash, db *trie.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, accountsOrigin map[common.Address][]byte, storagesOrigin map[common.Address]map[common.Hash][]byte) error {
|
||||
otr, err := trie.New(trie.StateTrieID(root), db)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+64
-64
@@ -32,7 +32,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -44,9 +43,10 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/state/snapshot"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/trie/triedb/hashdb"
|
||||
"github.com/ava-labs/subnet-evm/trie/triedb/pathdb"
|
||||
"github.com/ava-labs/subnet-evm/trie/trienode"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ava-labs/subnet-evm/triedb/hashdb"
|
||||
"github.com/ava-labs/subnet-evm/triedb/pathdb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -59,14 +59,14 @@ func TestUpdateLeaks(t *testing.T) {
|
||||
// Create an empty state database
|
||||
var (
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
tdb = trie.NewDatabase(db, nil)
|
||||
tdb = triedb.NewDatabase(db, nil)
|
||||
)
|
||||
state, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(db, tdb), nil)
|
||||
|
||||
// Update it with some accounts
|
||||
for i := byte(0); i < 255; i++ {
|
||||
addr := common.BytesToAddress([]byte{i})
|
||||
state.AddBalance(addr, big.NewInt(int64(11*i)))
|
||||
state.AddBalance(addr, uint256.NewInt(uint64(11*i)))
|
||||
state.SetNonce(addr, uint64(42*i))
|
||||
if i%2 == 0 {
|
||||
state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i}))
|
||||
@@ -95,13 +95,13 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||
// Create two state databases, one transitioning to the final state, the other final from the beginning
|
||||
transDb := rawdb.NewMemoryDatabase()
|
||||
finalDb := rawdb.NewMemoryDatabase()
|
||||
transNdb := trie.NewDatabase(transDb, nil)
|
||||
finalNdb := trie.NewDatabase(finalDb, nil)
|
||||
transNdb := triedb.NewDatabase(transDb, nil)
|
||||
finalNdb := triedb.NewDatabase(finalDb, nil)
|
||||
transState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(transDb, transNdb), nil)
|
||||
finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil)
|
||||
|
||||
modify := func(state *StateDB, addr common.Address, i, tweak byte) {
|
||||
state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)))
|
||||
state.SetBalance(addr, uint256.NewInt(uint64(11*i)+uint64(tweak)))
|
||||
state.SetNonce(addr, uint64(42*i+tweak))
|
||||
if i%2 == 0 {
|
||||
state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{})
|
||||
@@ -176,8 +176,8 @@ func TestCopy(t *testing.T) {
|
||||
orig, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
|
||||
for i := byte(0); i < 255; i++ {
|
||||
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
obj.AddBalance(big.NewInt(int64(i)))
|
||||
obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
obj.AddBalance(uint256.NewInt(uint64(i)))
|
||||
orig.updateStateObject(obj)
|
||||
}
|
||||
orig.Finalise(false)
|
||||
@@ -190,13 +190,13 @@ func TestCopy(t *testing.T) {
|
||||
|
||||
// modify all in memory
|
||||
for i := byte(0); i < 255; i++ {
|
||||
origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
origObj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
ccopyObj := ccopy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
|
||||
origObj.AddBalance(big.NewInt(2 * int64(i)))
|
||||
copyObj.AddBalance(big.NewInt(3 * int64(i)))
|
||||
ccopyObj.AddBalance(big.NewInt(4 * int64(i)))
|
||||
origObj.AddBalance(uint256.NewInt(2 * uint64(i)))
|
||||
copyObj.AddBalance(uint256.NewInt(3 * uint64(i)))
|
||||
ccopyObj.AddBalance(uint256.NewInt(4 * uint64(i)))
|
||||
|
||||
orig.updateStateObject(origObj)
|
||||
copy.updateStateObject(copyObj)
|
||||
@@ -218,17 +218,17 @@ func TestCopy(t *testing.T) {
|
||||
|
||||
// Verify that the three states have been updated independently
|
||||
for i := byte(0); i < 255; i++ {
|
||||
origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
origObj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
ccopyObj := ccopy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||
|
||||
if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 {
|
||||
if want := uint256.NewInt(3 * uint64(i)); origObj.Balance().Cmp(want) != 0 {
|
||||
t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want)
|
||||
}
|
||||
if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 {
|
||||
if want := uint256.NewInt(4 * uint64(i)); copyObj.Balance().Cmp(want) != 0 {
|
||||
t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want)
|
||||
}
|
||||
if want := big.NewInt(5 * int64(i)); ccopyObj.Balance().Cmp(want) != 0 {
|
||||
if want := uint256.NewInt(5 * uint64(i)); ccopyObj.Balance().Cmp(want) != 0 {
|
||||
t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, ccopyObj.Balance(), want)
|
||||
}
|
||||
}
|
||||
@@ -276,14 +276,14 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
|
||||
{
|
||||
name: "SetBalance",
|
||||
fn: func(a testAction, s *StateDB) {
|
||||
s.SetBalance(addr, big.NewInt(a.args[0]))
|
||||
s.SetBalance(addr, uint256.NewInt(uint64(a.args[0])))
|
||||
},
|
||||
args: make([]int64, 1),
|
||||
},
|
||||
{
|
||||
name: "AddBalance",
|
||||
fn: func(a testAction, s *StateDB) {
|
||||
s.AddBalance(addr, big.NewInt(a.args[0]))
|
||||
s.AddBalance(addr, uint256.NewInt(uint64(a.args[0])))
|
||||
},
|
||||
args: make([]int64, 1),
|
||||
},
|
||||
@@ -541,12 +541,12 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
|
||||
|
||||
func TestTouchDelete(t *testing.T) {
|
||||
s := newStateEnv()
|
||||
s.state.GetOrNewStateObject(common.Address{})
|
||||
s.state.getOrNewStateObject(common.Address{})
|
||||
root, _ := s.state.Commit(0, false, false)
|
||||
s.state, _ = NewWithSnapshot(root, s.state.db, s.state.snap)
|
||||
|
||||
snapshot := s.state.Snapshot()
|
||||
s.state.AddBalance(common.Address{}, new(big.Int))
|
||||
s.state.AddBalance(common.Address{}, new(uint256.Int))
|
||||
|
||||
if len(s.state.journal.dirties) != 1 {
|
||||
t.Fatal("expected one dirty state object")
|
||||
@@ -562,7 +562,7 @@ func TestTouchDelete(t *testing.T) {
|
||||
func TestCopyOfCopy(t *testing.T) {
|
||||
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
addr := common.HexToAddress("aaaa")
|
||||
state.SetBalance(addr, big.NewInt(42))
|
||||
state.SetBalance(addr, uint256.NewInt(42))
|
||||
|
||||
if got := state.Copy().GetBalance(addr).Uint64(); got != 42 {
|
||||
t.Fatalf("1st copy fail, expected 42, got %v", got)
|
||||
@@ -585,11 +585,11 @@ func TestCopyCommitCopy(t *testing.T) {
|
||||
skey := common.HexToHash("aaa")
|
||||
sval := common.HexToHash("bbb")
|
||||
|
||||
state.SetBalance(addr, big.NewInt(42)) // Change the account trie
|
||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||
state.SetState(addr, skey, sval) // Change the storage trie
|
||||
state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie
|
||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||
state.SetState(addr, skey, sval) // Change the storage trie
|
||||
|
||||
if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
|
||||
if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
|
||||
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
|
||||
}
|
||||
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||
@@ -603,7 +603,7 @@ func TestCopyCommitCopy(t *testing.T) {
|
||||
}
|
||||
// Copy the non-committed state database and check pre/post commit balance
|
||||
copyOne := state.Copy()
|
||||
if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
|
||||
if balance := copyOne.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
|
||||
t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42)
|
||||
}
|
||||
if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||
@@ -617,7 +617,7 @@ func TestCopyCommitCopy(t *testing.T) {
|
||||
}
|
||||
// Copy the copy and check the balance once more
|
||||
copyTwo := copyOne.Copy()
|
||||
if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
|
||||
if balance := copyTwo.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
|
||||
t.Fatalf("second copy balance mismatch: have %v, want %v", balance, 42)
|
||||
}
|
||||
if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||
@@ -632,7 +632,7 @@ func TestCopyCommitCopy(t *testing.T) {
|
||||
// Commit state, ensure states can be loaded from disk
|
||||
root, _ := state.Commit(0, false, false)
|
||||
state, _ = New(root, tdb, nil)
|
||||
if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
|
||||
if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
|
||||
t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42)
|
||||
}
|
||||
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||
@@ -658,11 +658,11 @@ func TestCopyCopyCommitCopy(t *testing.T) {
|
||||
skey := common.HexToHash("aaa")
|
||||
sval := common.HexToHash("bbb")
|
||||
|
||||
state.SetBalance(addr, big.NewInt(42)) // Change the account trie
|
||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||
state.SetState(addr, skey, sval) // Change the storage trie
|
||||
state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie
|
||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||
state.SetState(addr, skey, sval) // Change the storage trie
|
||||
|
||||
if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
|
||||
if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
|
||||
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
|
||||
}
|
||||
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||
@@ -676,7 +676,7 @@ func TestCopyCopyCommitCopy(t *testing.T) {
|
||||
}
|
||||
// Copy the non-committed state database and check pre/post commit balance
|
||||
copyOne := state.Copy()
|
||||
if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
|
||||
if balance := copyOne.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
|
||||
t.Fatalf("first copy balance mismatch: have %v, want %v", balance, 42)
|
||||
}
|
||||
if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||
@@ -690,7 +690,7 @@ func TestCopyCopyCommitCopy(t *testing.T) {
|
||||
}
|
||||
// Copy the copy and check the balance once more
|
||||
copyTwo := copyOne.Copy()
|
||||
if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
|
||||
if balance := copyTwo.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
|
||||
t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42)
|
||||
}
|
||||
if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||
@@ -704,7 +704,7 @@ func TestCopyCopyCommitCopy(t *testing.T) {
|
||||
}
|
||||
// Copy the copy-copy and check the balance once more
|
||||
copyThree := copyTwo.Copy()
|
||||
if balance := copyThree.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
|
||||
if balance := copyThree.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
|
||||
t.Fatalf("third copy balance mismatch: have %v, want %v", balance, 42)
|
||||
}
|
||||
if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||
@@ -727,11 +727,11 @@ func TestCommitCopy(t *testing.T) {
|
||||
skey := common.HexToHash("aaa")
|
||||
sval := common.HexToHash("bbb")
|
||||
|
||||
state.SetBalance(addr, big.NewInt(42)) // Change the account trie
|
||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||
state.SetState(addr, skey, sval) // Change the storage trie
|
||||
state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie
|
||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||
state.SetState(addr, skey, sval) // Change the storage trie
|
||||
|
||||
if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
|
||||
if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
|
||||
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
|
||||
}
|
||||
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||
@@ -746,7 +746,7 @@ func TestCommitCopy(t *testing.T) {
|
||||
// Copy the committed state database, the copied one is not functional.
|
||||
state.Commit(0, true, false)
|
||||
copied := state.Copy()
|
||||
if balance := copied.GetBalance(addr); balance.Cmp(big.NewInt(0)) != 0 {
|
||||
if balance := copied.GetBalance(addr); balance.Cmp(uint256.NewInt(0)) != 0 {
|
||||
t.Fatalf("unexpected balance: have %v", balance)
|
||||
}
|
||||
if code := copied.GetCode(addr); code != nil {
|
||||
@@ -776,7 +776,7 @@ func TestDeleteCreateRevert(t *testing.T) {
|
||||
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
|
||||
addr := common.BytesToAddress([]byte("so"))
|
||||
state.SetBalance(addr, big.NewInt(1))
|
||||
state.SetBalance(addr, uint256.NewInt(1))
|
||||
|
||||
root, _ := state.Commit(0, false, false)
|
||||
state, _ = NewWithSnapshot(root, state.db, state.snap)
|
||||
@@ -786,7 +786,7 @@ func TestDeleteCreateRevert(t *testing.T) {
|
||||
state.Finalise(true)
|
||||
|
||||
id := state.Snapshot()
|
||||
state.SetBalance(addr, big.NewInt(2))
|
||||
state.SetBalance(addr, uint256.NewInt(2))
|
||||
state.RevertToSnapshot(id)
|
||||
|
||||
// Commit the entire state and make sure we don't crash and have the correct state
|
||||
@@ -809,34 +809,34 @@ func TestMissingTrieNodes(t *testing.T) {
|
||||
func testMissingTrieNodes(t *testing.T, scheme string) {
|
||||
// Create an initial state with a few accounts
|
||||
var (
|
||||
triedb *trie.Database
|
||||
memDb = rawdb.NewMemoryDatabase()
|
||||
tdb *triedb.Database
|
||||
memDb = rawdb.NewMemoryDatabase()
|
||||
)
|
||||
if scheme == rawdb.PathScheme {
|
||||
triedb = trie.NewDatabase(memDb, &trie.Config{PathDB: &pathdb.Config{
|
||||
tdb = triedb.NewDatabase(memDb, &triedb.Config{PathDB: &pathdb.Config{
|
||||
CleanCacheSize: 0,
|
||||
DirtyCacheSize: 0,
|
||||
}}) // disable caching
|
||||
} else {
|
||||
triedb = trie.NewDatabase(memDb, &trie.Config{HashDB: &hashdb.Config{
|
||||
tdb = triedb.NewDatabase(memDb, &triedb.Config{HashDB: &hashdb.Config{
|
||||
CleanCacheSize: 0,
|
||||
}}) // disable caching
|
||||
}
|
||||
db := NewDatabaseWithNodeDB(memDb, triedb)
|
||||
db := NewDatabaseWithNodeDB(memDb, tdb)
|
||||
|
||||
var root common.Hash
|
||||
state, _ := New(types.EmptyRootHash, db, nil)
|
||||
addr := common.BytesToAddress([]byte("so"))
|
||||
{
|
||||
state.SetBalance(addr, big.NewInt(1))
|
||||
state.SetBalance(addr, uint256.NewInt(1))
|
||||
state.SetCode(addr, []byte{1, 2, 3})
|
||||
a2 := common.BytesToAddress([]byte("another"))
|
||||
state.SetBalance(a2, big.NewInt(100))
|
||||
state.SetBalance(a2, uint256.NewInt(100))
|
||||
state.SetCode(a2, []byte{1, 2, 4})
|
||||
root, _ = state.Commit(0, false, false)
|
||||
t.Logf("root: %x", root)
|
||||
// force-flush
|
||||
triedb.Commit(root, false)
|
||||
tdb.Commit(root, false)
|
||||
}
|
||||
// Create a new state on the old root
|
||||
state, _ = New(root, db, nil)
|
||||
@@ -856,7 +856,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
|
||||
t.Errorf("expected %d, got %d", exp, got)
|
||||
}
|
||||
// Modify the state
|
||||
state.SetBalance(addr, big.NewInt(2))
|
||||
state.SetBalance(addr, uint256.NewInt(2))
|
||||
root, err := state.Commit(0, false, false)
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got root :%x", root)
|
||||
@@ -1043,7 +1043,7 @@ func TestFlushOrderDataLoss(t *testing.T) {
|
||||
// Create a state trie with many accounts and slots
|
||||
var (
|
||||
memdb = rawdb.NewMemoryDatabase()
|
||||
triedb = trie.NewDatabase(memdb, nil)
|
||||
triedb = triedb.NewDatabase(memdb, nil)
|
||||
statedb = NewDatabaseWithNodeDB(memdb, triedb)
|
||||
state, _ = New(types.EmptyRootHash, statedb, nil)
|
||||
)
|
||||
@@ -1115,7 +1115,7 @@ func TestStateDBTransientStorage(t *testing.T) {
|
||||
func TestResetObject(t *testing.T) {
|
||||
var (
|
||||
disk = rawdb.NewMemoryDatabase()
|
||||
tdb = trie.NewDatabase(disk, nil)
|
||||
tdb = triedb.NewDatabase(disk, nil)
|
||||
db = NewDatabaseWithNodeDB(disk, tdb)
|
||||
snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, common.Hash{}, types.EmptyRootHash)
|
||||
state, _ = New(types.EmptyRootHash, db, snaps)
|
||||
@@ -1124,13 +1124,13 @@ func TestResetObject(t *testing.T) {
|
||||
slotB = common.HexToHash("0x2")
|
||||
)
|
||||
// Initialize account with balance and storage in first transaction.
|
||||
state.SetBalance(addr, big.NewInt(1))
|
||||
state.SetBalance(addr, uint256.NewInt(1))
|
||||
state.SetState(addr, slotA, common.BytesToHash([]byte{0x1}))
|
||||
state.IntermediateRoot(true)
|
||||
|
||||
// Reset account and mutate balance and storages
|
||||
state.CreateAccount(addr)
|
||||
state.SetBalance(addr, big.NewInt(2))
|
||||
state.SetBalance(addr, uint256.NewInt(2))
|
||||
state.SetState(addr, slotB, common.BytesToHash([]byte{0x2}))
|
||||
root, _ := state.CommitWithSnap(0, true, snaps, common.Hash{}, common.Hash{}, false)
|
||||
|
||||
@@ -1149,14 +1149,14 @@ func TestResetObject(t *testing.T) {
|
||||
func TestDeleteStorage(t *testing.T) {
|
||||
var (
|
||||
disk = rawdb.NewMemoryDatabase()
|
||||
tdb = trie.NewDatabase(disk, nil)
|
||||
tdb = triedb.NewDatabase(disk, nil)
|
||||
db = NewDatabaseWithNodeDB(disk, tdb)
|
||||
snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, common.Hash{}, types.EmptyRootHash)
|
||||
state, _ = New(types.EmptyRootHash, db, snaps)
|
||||
addr = common.HexToAddress("0x1")
|
||||
)
|
||||
// Initialize account and populate storage
|
||||
state.SetBalance(addr, big.NewInt(1))
|
||||
state.SetBalance(addr, uint256.NewInt(1))
|
||||
state.CreateAccount(addr)
|
||||
for i := 0; i < 1000; i++ {
|
||||
slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32())
|
||||
@@ -1168,7 +1168,7 @@ func TestDeleteStorage(t *testing.T) {
|
||||
fastState, _ := New(root, db, snaps)
|
||||
slowState, _ := New(root, db, nil)
|
||||
|
||||
obj := fastState.GetOrNewStateObject(addr)
|
||||
obj := fastState.getOrNewStateObject(addr)
|
||||
storageRoot := obj.data.Root
|
||||
|
||||
_, _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot)
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/rawdb"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
const maxConcurrency = 4
|
||||
@@ -46,9 +47,9 @@ func filledStateDB() *StateDB {
|
||||
skey := common.HexToHash("aaa")
|
||||
sval := common.HexToHash("bbb")
|
||||
|
||||
state.SetBalance(addr, big.NewInt(42)) // Change the account trie
|
||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||
state.SetState(addr, skey, sval) // Change the storage trie
|
||||
state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie
|
||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||
state.SetState(addr, skey, sval) // Change the storage trie
|
||||
for i := 0; i < 100; i++ {
|
||||
sk := common.BigToHash(big.NewInt(int64(i)))
|
||||
state.SetState(addr, sk, sk) // Change the storage trie
|
||||
|
||||
@@ -199,7 +199,7 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
|
||||
}
|
||||
vmenv.Reset(NewEVMTxContext(msg), statedb)
|
||||
statedb.AddAddressToAccessList(params.BeaconRootsStorageAddress)
|
||||
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.Big0)
|
||||
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||
statedb.Finalise(true)
|
||||
}
|
||||
|
||||
|
||||
@@ -113,8 +113,8 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||
gspec = &Genesis{
|
||||
Config: config,
|
||||
Timestamp: uint64(upgrade.InitiallyActiveTime.Unix()),
|
||||
Alloc: GenesisAlloc{
|
||||
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
|
||||
Alloc: types.GenesisAlloc{
|
||||
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): types.Account{
|
||||
Balance: big.NewInt(4000000000000000000), // 4 ether
|
||||
Nonce: 0,
|
||||
},
|
||||
@@ -219,7 +219,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||
txs: []*types.Transaction{
|
||||
mkDynamicTx(0, common.Address{}, params.TxGas, bigNumber, bigNumber),
|
||||
},
|
||||
want: "could not apply tx 0 [0xd82a0c2519acfeac9a948258c47e784acd20651d9d80f9a1c67b4137651c3a24]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 4000000000000000000 want 2431633873983640103894990685182446064918669677978451844828609264166175722438635000",
|
||||
want: "could not apply tx 0 [0xd82a0c2519acfeac9a948258c47e784acd20651d9d80f9a1c67b4137651c3a24]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 required balance exceeds 256 bits",
|
||||
},
|
||||
{ // ErrMaxInitCodeSizeExceeded
|
||||
txs: []*types.Transaction{
|
||||
@@ -269,8 +269,8 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||
IstanbulBlock: big.NewInt(0),
|
||||
MuirGlacierBlock: big.NewInt(0),
|
||||
},
|
||||
Alloc: GenesisAlloc{
|
||||
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
|
||||
Alloc: types.GenesisAlloc{
|
||||
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): types.Account{
|
||||
Balance: big.NewInt(1000000000000000000), // 1 ether
|
||||
Nonce: 0,
|
||||
},
|
||||
@@ -308,8 +308,8 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
gspec = &Genesis{
|
||||
Config: config,
|
||||
Alloc: GenesisAlloc{
|
||||
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
|
||||
Alloc: types.GenesisAlloc{
|
||||
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): types.Account{
|
||||
Balance: big.NewInt(1000000000000000000), // 1 ether
|
||||
Nonce: 0,
|
||||
Code: common.FromHex("0xB0B0FACE"),
|
||||
|
||||
+34
-12
@@ -27,7 +27,6 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
@@ -40,6 +39,8 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/vmerrs"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
cmath "github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// ExecutionResult includes all output after executing given evm
|
||||
@@ -311,7 +312,11 @@ func (st *StateTransition) buyGas() error {
|
||||
mgval.Add(mgval, blobFee)
|
||||
}
|
||||
}
|
||||
if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 {
|
||||
balanceCheckU256, overflow := uint256.FromBig(balanceCheck)
|
||||
if overflow {
|
||||
return fmt.Errorf("%w: address %v required balance exceeds 256 bits", ErrInsufficientFunds, st.msg.From.Hex())
|
||||
}
|
||||
if have, want := st.state.GetBalance(st.msg.From), balanceCheckU256; have.Cmp(want) < 0 {
|
||||
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want)
|
||||
}
|
||||
if err := st.gp.SubGas(st.msg.GasLimit); err != nil {
|
||||
@@ -320,7 +325,8 @@ func (st *StateTransition) buyGas() error {
|
||||
st.gasRemaining += st.msg.GasLimit
|
||||
|
||||
st.initialGas = st.msg.GasLimit
|
||||
st.state.SubBalance(st.msg.From, mgval)
|
||||
mgvalU256, _ := uint256.FromBig(mgval)
|
||||
st.state.SubBalance(st.msg.From, mgvalU256)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -386,13 +392,18 @@ func (st *StateTransition) preCheck() error {
|
||||
}
|
||||
// Check the blob version validity
|
||||
if msg.BlobHashes != nil {
|
||||
// The to field of a blob tx type is mandatory, and a `BlobTx` transaction internally
|
||||
// has it as a non-nillable value, so any msg derived from blob transaction has it non-nil.
|
||||
// However, messages created through RPC (eth_call) don't have this restriction.
|
||||
if msg.To == nil {
|
||||
return ErrBlobTxCreate
|
||||
}
|
||||
if len(msg.BlobHashes) == 0 {
|
||||
return errors.New("blob transaction missing blob hashes")
|
||||
return ErrMissingBlobHashes
|
||||
}
|
||||
for i, hash := range msg.BlobHashes {
|
||||
if hash[0] != params.BlobTxHashVersion {
|
||||
return fmt.Errorf("blob %d hash version mismatch (have %d, supported %d)",
|
||||
i, hash[0], params.BlobTxHashVersion)
|
||||
if !kzg4844.IsValidVersionedHash(hash[:]) {
|
||||
return fmt.Errorf("blob %d has invalid hash version", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -466,7 +477,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||
st.gasRemaining -= gas
|
||||
|
||||
// Check clause 6
|
||||
if msg.Value.Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From, msg.Value) {
|
||||
value, overflow := uint256.FromBig(msg.Value)
|
||||
if overflow {
|
||||
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
|
||||
}
|
||||
if !value.IsZero() && !st.evm.Context.CanTransfer(st.state, msg.From, value) {
|
||||
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
|
||||
}
|
||||
|
||||
@@ -485,14 +500,20 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
|
||||
)
|
||||
if contractCreation {
|
||||
ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, msg.Value)
|
||||
ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, value)
|
||||
} else {
|
||||
// Increment the nonce for the next transaction
|
||||
st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1)
|
||||
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
|
||||
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, value)
|
||||
}
|
||||
price, overflow := uint256.FromBig(msg.GasPrice)
|
||||
if overflow {
|
||||
return nil, ErrGasUintOverflow
|
||||
}
|
||||
gasRefund := st.refundGas(rules.IsSubnetEVM)
|
||||
st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), msg.GasPrice))
|
||||
fee := new(uint256.Int).SetUint64(st.gasUsed())
|
||||
fee.Mul(fee, price)
|
||||
st.state.AddBalance(st.evm.Context.Coinbase, fee)
|
||||
|
||||
return &ExecutionResult{
|
||||
UsedGas: st.gasUsed(),
|
||||
@@ -515,7 +536,8 @@ func (st *StateTransition) refundGas(subnetEVM bool) uint64 {
|
||||
}
|
||||
|
||||
// Return ETH for remaining gas, exchanged at the original rate.
|
||||
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice)
|
||||
remaining := uint256.NewInt(st.gasRemaining)
|
||||
remaining = remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice))
|
||||
st.state.AddBalance(st.msg.From, remaining)
|
||||
|
||||
// Also return remaining gas to the block gas counter so it is
|
||||
|
||||
+35
-23
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -238,9 +239,10 @@ func TestInsertChainAcceptSingleBlock(t *testing.T, create func(db ethdb.Databas
|
||||
if nonce != 1 {
|
||||
return fmt.Errorf("expected nonce addr1: 1, found nonce: %d", nonce)
|
||||
}
|
||||
transferredFunds := big.NewInt(10000)
|
||||
transferredFunds := uint256.MustFromBig(big.NewInt(10000))
|
||||
balance1 := sdb.GetBalance(addr1)
|
||||
expectedBalance1 := new(big.Int).Sub(genesisBalance, transferredFunds)
|
||||
genesisBalance := uint256.MustFromBig(genesisBalance)
|
||||
expectedBalance1 := new(uint256.Int).Sub(genesisBalance, transferredFunds)
|
||||
if balance1.Cmp(expectedBalance1) != 0 {
|
||||
return fmt.Errorf("expected addr1 balance: %d, found balance: %d", expectedBalance1, balance1)
|
||||
}
|
||||
@@ -274,7 +276,7 @@ func TestInsertLongForkedChain(t *testing.T, create func(db ethdb.Database, gspe
|
||||
genesisBalance := big.NewInt(1000000000)
|
||||
gspec := &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
}
|
||||
|
||||
blockchain, err := create(chainDB, gspec, common.Hash{})
|
||||
@@ -405,8 +407,9 @@ func TestInsertLongForkedChain(t *testing.T, create func(db ethdb.Database, gspe
|
||||
return fmt.Errorf("expected addr1 nonce: 129, found nonce %d", nonce1)
|
||||
}
|
||||
balance1 := sdb.GetBalance(addr1)
|
||||
transferredFunds := new(big.Int).Mul(big.NewInt(129), big.NewInt(10000))
|
||||
expectedBalance := new(big.Int).Sub(genesisBalance, transferredFunds)
|
||||
transferredFunds := uint256.NewInt(129 * 10_000)
|
||||
genesisBalance := uint256.MustFromBig(genesisBalance)
|
||||
expectedBalance := new(uint256.Int).Sub(genesisBalance, transferredFunds)
|
||||
if balance1.Cmp(expectedBalance) != 0 {
|
||||
return fmt.Errorf("expected addr1 balance: %d, found balance: %d", expectedBalance, balance1)
|
||||
}
|
||||
@@ -437,7 +440,7 @@ func TestAcceptNonCanonicalBlock(t *testing.T, create func(db ethdb.Database, gs
|
||||
genesisBalance := big.NewInt(1000000000)
|
||||
gspec := &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
}
|
||||
|
||||
blockchain, err := create(chainDB, gspec, common.Hash{})
|
||||
@@ -513,8 +516,9 @@ func TestAcceptNonCanonicalBlock(t *testing.T, create func(db ethdb.Database, gs
|
||||
return fmt.Errorf("expected addr1 nonce: 1, found nonce: %d", nonce1)
|
||||
}
|
||||
balance1 := sdb.GetBalance(addr1)
|
||||
transferredFunds := big.NewInt(5000)
|
||||
expectedBalance := new(big.Int).Sub(genesisBalance, transferredFunds)
|
||||
transferredFunds := uint256.NewInt(5000)
|
||||
genesisBalance := uint256.MustFromBig(genesisBalance)
|
||||
expectedBalance := new(uint256.Int).Sub(genesisBalance, transferredFunds)
|
||||
if balance1.Cmp(expectedBalance) != 0 {
|
||||
return fmt.Errorf("expected balance1: %d, found balance: %d", expectedBalance, balance1)
|
||||
}
|
||||
@@ -545,7 +549,7 @@ func TestSetPreferenceRewind(t *testing.T, create func(db ethdb.Database, gspec
|
||||
genesisBalance := big.NewInt(1000000000)
|
||||
gspec := &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
}
|
||||
|
||||
blockchain, err := create(chainDB, gspec, common.Hash{})
|
||||
@@ -607,6 +611,7 @@ func TestSetPreferenceRewind(t *testing.T, create func(db ethdb.Database, gspec
|
||||
return fmt.Errorf("expected addr1 nonce: 0, found nonce: %d", nonce1)
|
||||
}
|
||||
balance1 := sdb.GetBalance(addr1)
|
||||
genesisBalance := uint256.MustFromBig(genesisBalance)
|
||||
if balance1.Cmp(genesisBalance) != 0 {
|
||||
return fmt.Errorf("expected addr1 balance: %d, found balance: %d", genesisBalance, balance1)
|
||||
}
|
||||
@@ -615,7 +620,7 @@ func TestSetPreferenceRewind(t *testing.T, create func(db ethdb.Database, gspec
|
||||
return fmt.Errorf("expected addr2 nonce: 0, found nonce: %d", nonce2)
|
||||
}
|
||||
balance2 := sdb.GetBalance(addr2)
|
||||
if balance2.Cmp(big.NewInt(0)) != 0 {
|
||||
if balance2.Cmp(common.U2560) != 0 {
|
||||
return fmt.Errorf("expected addr2 balance: 0, found balance %d", balance2)
|
||||
}
|
||||
return nil
|
||||
@@ -640,9 +645,10 @@ func TestSetPreferenceRewind(t *testing.T, create func(db ethdb.Database, gspec
|
||||
if nonce != 1 {
|
||||
return fmt.Errorf("expected addr1 nonce: 1, found nonce: %d", nonce)
|
||||
}
|
||||
transferredFunds := big.NewInt(10000)
|
||||
transferredFunds := uint256.NewInt(10000)
|
||||
balance1 := sdb.GetBalance(addr1)
|
||||
expectedBalance1 := new(big.Int).Sub(genesisBalance, transferredFunds)
|
||||
genesisBalance := uint256.MustFromBig(genesisBalance)
|
||||
expectedBalance1 := new(uint256.Int).Sub(genesisBalance, transferredFunds)
|
||||
if balance1.Cmp(expectedBalance1) != 0 {
|
||||
return fmt.Errorf("expected addr1 balance: %d, found balance %d", expectedBalance1, balance1)
|
||||
}
|
||||
@@ -796,6 +802,7 @@ func TestBuildOnVariousStages(t *testing.T, create func(db ethdb.Database, gspec
|
||||
return fmt.Errorf("expected nonce addr1: 5, found nonce: %d", nonce)
|
||||
}
|
||||
balance1 := sdb.GetBalance(addr1)
|
||||
genesisBalance := uint256.MustFromBig(genesisBalance)
|
||||
expectedBalance1 := genesisBalance
|
||||
if balance1.Cmp(expectedBalance1) != 0 {
|
||||
return fmt.Errorf("expected addr1 balance: %d, found balance: %d", expectedBalance1, balance1)
|
||||
@@ -813,7 +820,7 @@ func TestBuildOnVariousStages(t *testing.T, create func(db ethdb.Database, gspec
|
||||
}
|
||||
|
||||
balance3 := sdb.GetBalance(addr3)
|
||||
expectedBalance3 := common.Big0
|
||||
expectedBalance3 := common.U2560
|
||||
if balance3.Cmp(expectedBalance3) != 0 {
|
||||
return fmt.Errorf("expected addr3 balance: %d, found balance: %d", expectedBalance3, balance3)
|
||||
}
|
||||
@@ -879,7 +886,7 @@ func TestReorgReInsert(t *testing.T, create func(db ethdb.Database, gspec *Genes
|
||||
genesisBalance := big.NewInt(1000000000)
|
||||
gspec := &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
}
|
||||
|
||||
blockchain, err := create(chainDB, gspec, common.Hash{})
|
||||
@@ -939,8 +946,9 @@ func TestReorgReInsert(t *testing.T, create func(db ethdb.Database, gspec *Genes
|
||||
return fmt.Errorf("expected addr1 nonce: 3, found nonce: %d", nonce1)
|
||||
}
|
||||
balance1 := sdb.GetBalance(addr1)
|
||||
transferredFunds := big.NewInt(30000)
|
||||
expectedBalance := new(big.Int).Sub(genesisBalance, transferredFunds)
|
||||
transferredFunds := uint256.NewInt(30000)
|
||||
genesisBalance := uint256.MustFromBig(genesisBalance)
|
||||
expectedBalance := new(uint256.Int).Sub(genesisBalance, transferredFunds)
|
||||
if balance1.Cmp(expectedBalance) != 0 {
|
||||
return fmt.Errorf("expected balance1: %d, found balance: %d", expectedBalance, balance1)
|
||||
}
|
||||
@@ -984,7 +992,7 @@ func TestAcceptBlockIdenticalStateRoot(t *testing.T, create func(db ethdb.Databa
|
||||
genesisBalance := big.NewInt(1000000000)
|
||||
gspec := &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
}
|
||||
|
||||
blockchain, err := create(chainDB, gspec, common.Hash{})
|
||||
@@ -1082,7 +1090,7 @@ func TestAcceptBlockIdenticalStateRoot(t *testing.T, create func(db ethdb.Databa
|
||||
return fmt.Errorf("expected addr1 nonce: 2, found nonce: %d", nonce1)
|
||||
}
|
||||
balance1 := sdb.GetBalance(addr1)
|
||||
expectedBalance := common.Big0
|
||||
expectedBalance := common.U2560
|
||||
if balance1.Cmp(expectedBalance) != 0 {
|
||||
return fmt.Errorf("expected balance1: %d, found balance: %d", expectedBalance, balance1)
|
||||
}
|
||||
@@ -1091,6 +1099,7 @@ func TestAcceptBlockIdenticalStateRoot(t *testing.T, create func(db ethdb.Databa
|
||||
return fmt.Errorf("expected addr2 nonce: 0, found nonce %d", nonce2)
|
||||
}
|
||||
balance2 := sdb.GetBalance(addr2)
|
||||
genesisBalance := uint256.MustFromBig(genesisBalance)
|
||||
if balance2.Cmp(genesisBalance) != 0 {
|
||||
return fmt.Errorf("expected balance2: %d, found %d", genesisBalance, balance2)
|
||||
}
|
||||
@@ -1127,7 +1136,7 @@ func TestReprocessAcceptBlockIdenticalStateRoot(t *testing.T, create func(db eth
|
||||
genesisBalance := big.NewInt(1000000000)
|
||||
gspec := &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
}
|
||||
|
||||
blockchain, err := create(chainDB, gspec, common.Hash{})
|
||||
@@ -1249,7 +1258,7 @@ func TestReprocessAcceptBlockIdenticalStateRoot(t *testing.T, create func(db eth
|
||||
return fmt.Errorf("expected addr1 nonce: 2, found nonce: %d", nonce1)
|
||||
}
|
||||
balance1 := sdb.GetBalance(addr1)
|
||||
expectedBalance := common.Big0
|
||||
expectedBalance := common.U2560
|
||||
if balance1.Cmp(expectedBalance) != 0 {
|
||||
return fmt.Errorf("expected balance1: %d, found balance: %d", expectedBalance, balance1)
|
||||
}
|
||||
@@ -1258,6 +1267,7 @@ func TestReprocessAcceptBlockIdenticalStateRoot(t *testing.T, create func(db eth
|
||||
return fmt.Errorf("expected addr2 nonce: 0, found nonce %d", nonce2)
|
||||
}
|
||||
balance2 := sdb.GetBalance(addr2)
|
||||
genesisBalance := uint256.MustFromBig(genesisBalance)
|
||||
if balance2.Cmp(genesisBalance) != 0 {
|
||||
return fmt.Errorf("expected balance2: %d, found %d", genesisBalance, balance2)
|
||||
}
|
||||
@@ -1383,7 +1393,7 @@ func TestInsertChainValidBlockFee(t *testing.T, create func(db ethdb.Database, g
|
||||
genesisBalance := new(big.Int).Mul(big.NewInt(1000000), big.NewInt(params.Ether))
|
||||
gspec := &Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}},
|
||||
}
|
||||
|
||||
blockchain, err := create(chainDB, gspec, common.Hash{})
|
||||
@@ -1435,10 +1445,12 @@ func TestInsertChainValidBlockFee(t *testing.T, create func(db ethdb.Database, g
|
||||
return fmt.Errorf("expected nonce addr1: 1, found nonce: %d", nonce)
|
||||
}
|
||||
balance1 := sdb.GetBalance(addr1)
|
||||
expectedBalance1 := new(big.Int).Sub(genesisBalance, transfer)
|
||||
transfer := uint256.MustFromBig(transfer)
|
||||
genesisBalance := uint256.MustFromBig(genesisBalance)
|
||||
expectedBalance1 := new(uint256.Int).Sub(genesisBalance, transfer)
|
||||
baseFee := params.DefaultFeeConfig.MinBaseFee
|
||||
feeSpend := new(big.Int).Mul(new(big.Int).Add(baseFee, tip), new(big.Int).SetUint64(params.TxGas))
|
||||
expectedBalance1.Sub(expectedBalance1, feeSpend)
|
||||
expectedBalance1.Sub(expectedBalance1, uint256.MustFromBig(feeSpend))
|
||||
if balance1.Cmp(expectedBalance1) != 0 {
|
||||
return fmt.Errorf("expected addr1 balance: %d, found balance: %d", expectedBalance1, balance1)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
// TxIndexProgress is the struct describing the progress for transaction indexing.
|
||||
type TxIndexProgress struct {
|
||||
Indexed uint64 // number of blocks whose transactions are indexed
|
||||
Remaining uint64 // number of blocks whose transactions are not indexed yet
|
||||
}
|
||||
|
||||
// Done returns an indicator if the transaction indexing is finished.
|
||||
func (progress TxIndexProgress) Done() bool {
|
||||
return progress.Remaining == 0
|
||||
}
|
||||
|
||||
// txIndexer is the module responsible for maintaining transaction indexes
|
||||
// according to the configured indexing range by users.
|
||||
type txIndexer struct {
|
||||
// limit is the maximum number of blocks from head whose tx indexes
|
||||
// are reserved:
|
||||
// * 0: means the entire chain should be indexed
|
||||
// * N: means the latest N blocks [HEAD-N+1, HEAD] should be indexed
|
||||
// and all others shouldn't.
|
||||
limit uint64
|
||||
db ethdb.Database
|
||||
progress chan chan TxIndexProgress
|
||||
term chan chan struct{}
|
||||
closed chan struct{}
|
||||
|
||||
chain *BlockChain
|
||||
}
|
||||
|
||||
// newTxIndexer initializes the transaction indexer.
|
||||
func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer {
|
||||
indexer := &txIndexer{
|
||||
limit: limit,
|
||||
db: chain.db,
|
||||
progress: make(chan chan TxIndexProgress),
|
||||
term: make(chan chan struct{}),
|
||||
closed: make(chan struct{}),
|
||||
chain: chain,
|
||||
}
|
||||
chain.wg.Add(1)
|
||||
go func() {
|
||||
defer chain.wg.Done()
|
||||
indexer.loop(chain)
|
||||
}()
|
||||
|
||||
var msg string
|
||||
if limit == 0 {
|
||||
msg = "entire chain"
|
||||
} else {
|
||||
msg = fmt.Sprintf("last %d blocks", limit)
|
||||
}
|
||||
log.Info("Initialized transaction indexer", "range", msg)
|
||||
|
||||
return indexer
|
||||
}
|
||||
|
||||
// run executes the scheduled indexing/unindexing task in a separate thread.
|
||||
// If the stop channel is closed, the task should be terminated as soon as
|
||||
// possible, the done channel will be closed once the task is finished.
|
||||
func (indexer *txIndexer) run(tail *uint64, head uint64, stop chan struct{}, done chan struct{}) {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
txUnindexTimer.Inc(time.Since(start).Milliseconds())
|
||||
close(done)
|
||||
}()
|
||||
|
||||
// Short circuit if chain is empty and nothing to index.
|
||||
if head == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Defensively ensure tail is not nil.
|
||||
tailValue := uint64(0)
|
||||
if tail != nil {
|
||||
// use intermediate variable to avoid modifying the pointer
|
||||
tailValue = *tail
|
||||
}
|
||||
|
||||
if head-indexer.limit+1 >= tailValue {
|
||||
// Unindex a part of stale indices and forward index tail to HEAD-limit
|
||||
rawdb.UnindexTransactions(indexer.db, tailValue, head-indexer.limit+1, stop, false)
|
||||
}
|
||||
}
|
||||
|
||||
// loop is the scheduler of the indexer, assigning indexing/unindexing tasks depending
|
||||
// on the received chain event.
|
||||
func (indexer *txIndexer) loop(chain *BlockChain) {
|
||||
defer close(indexer.closed)
|
||||
// Listening to chain events and manipulate the transaction indexes.
|
||||
var (
|
||||
stop chan struct{} // Non-nil if background routine is active.
|
||||
done chan struct{} // Non-nil if background routine is active.
|
||||
lastHead uint64 // The latest announced chain head (whose tx indexes are assumed created)
|
||||
|
||||
headCh = make(chan ChainEvent)
|
||||
sub = chain.SubscribeChainAcceptedEvent(headCh)
|
||||
)
|
||||
if sub == nil {
|
||||
log.Warn("could not create chain accepted subscription to unindex txs")
|
||||
return
|
||||
}
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
log.Info("Initialized transaction unindexer", "limit", indexer.limit)
|
||||
|
||||
// Launch the initial processing if chain is not empty (head != genesis).
|
||||
// This step is useful in these scenarios that chain has no progress.
|
||||
if head := indexer.chain.CurrentBlock(); head != nil && head.Number.Uint64() > indexer.limit {
|
||||
stop = make(chan struct{})
|
||||
done = make(chan struct{})
|
||||
lastHead = head.Number.Uint64()
|
||||
indexer.chain.wg.Add(1)
|
||||
go func() {
|
||||
indexer.lockedRun(head.Number.Uint64(), stop, done)
|
||||
}()
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case head := <-headCh:
|
||||
headNum := head.Block.NumberU64()
|
||||
if headNum < indexer.limit {
|
||||
break
|
||||
}
|
||||
|
||||
if done == nil {
|
||||
stop = make(chan struct{})
|
||||
done = make(chan struct{})
|
||||
indexer.chain.wg.Add(1)
|
||||
go func() {
|
||||
indexer.lockedRun(headNum, stop, done)
|
||||
}()
|
||||
}
|
||||
lastHead = head.Block.NumberU64()
|
||||
case <-done:
|
||||
stop = nil
|
||||
done = nil
|
||||
case ch := <-indexer.progress:
|
||||
ch <- indexer.report(lastHead, rawdb.ReadTxIndexTail(indexer.db))
|
||||
case ch := <-indexer.term:
|
||||
if stop != nil {
|
||||
close(stop)
|
||||
}
|
||||
if done != nil {
|
||||
log.Info("Waiting background transaction unindexer to exit")
|
||||
<-done
|
||||
}
|
||||
close(ch)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// report returns the tx indexing progress.
|
||||
func (indexer *txIndexer) report(head uint64, tail *uint64) TxIndexProgress {
|
||||
total := indexer.limit
|
||||
if indexer.limit == 0 || total > head {
|
||||
total = head + 1 // genesis included
|
||||
}
|
||||
var indexed uint64
|
||||
if tail != nil {
|
||||
indexed = head - *tail + 1
|
||||
}
|
||||
// The value of indexed might be larger than total if some blocks need
|
||||
// to be unindexed, avoiding a negative remaining.
|
||||
var remaining uint64
|
||||
if indexed < total {
|
||||
remaining = total - indexed
|
||||
}
|
||||
return TxIndexProgress{
|
||||
Indexed: indexed,
|
||||
Remaining: remaining,
|
||||
}
|
||||
}
|
||||
|
||||
// close shutdown the indexer. Safe to be called for multiple times.
|
||||
func (indexer *txIndexer) close() {
|
||||
ch := make(chan struct{})
|
||||
select {
|
||||
case indexer.term <- ch:
|
||||
<-ch
|
||||
case <-indexer.closed:
|
||||
}
|
||||
}
|
||||
|
||||
// lockedRun runs the indexing/unindexing task in a locked manner. It reads
|
||||
// the current tail index from the database.
|
||||
func (indexer *txIndexer) lockedRun(head uint64, stop chan struct{}, done chan struct{}) {
|
||||
indexer.chain.txIndexTailLock.Lock()
|
||||
indexer.run(rawdb.ReadTxIndexTail(indexer.db), head, stop, done)
|
||||
indexer.chain.txIndexTailLock.Unlock()
|
||||
indexer.chain.wg.Done()
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/consensus/dummy"
|
||||
"github.com/ava-labs/subnet-evm/core/rawdb"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Should we try to use the TestTxIndexer from upstream here instead
|
||||
// or move this test to a new file eg, blockchain_extra_test.go?
|
||||
func TestTransactionIndices(t *testing.T) {
|
||||
// Configure and generate a sample block chain
|
||||
require := require.New(t)
|
||||
var (
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
funds = big.NewInt(10000000000000)
|
||||
gspec = &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: funds}},
|
||||
}
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
)
|
||||
genDb, blocks, _, err := GenerateChainWithGenesis(gspec, dummy.NewFaker(), 128, 10, func(i int, block *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
|
||||
require.NoError(err)
|
||||
block.AddTx(tx)
|
||||
})
|
||||
require.NoError(err)
|
||||
|
||||
blocks2, _, err := GenerateChain(gspec.Config, blocks[len(blocks)-1], dummy.NewFaker(), genDb, 10, 10, func(i int, block *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
|
||||
require.NoError(err)
|
||||
block.AddTx(tx)
|
||||
})
|
||||
require.NoError(err)
|
||||
|
||||
conf := &CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieDirtyCommitTarget: 20,
|
||||
TriePrefetcherParallelism: 4,
|
||||
Pruning: true,
|
||||
CommitInterval: 4096,
|
||||
SnapshotLimit: 256,
|
||||
SnapshotNoBuild: true, // Ensure the test errors if snapshot initialization fails
|
||||
AcceptorQueueLimit: 64,
|
||||
}
|
||||
|
||||
// Init block chain and check all needed indices has been indexed.
|
||||
chainDB := rawdb.NewMemoryDatabase()
|
||||
chain, err := createBlockChain(chainDB, conf, gspec, common.Hash{})
|
||||
require.NoError(err)
|
||||
|
||||
_, err = chain.InsertChain(blocks)
|
||||
require.NoError(err)
|
||||
|
||||
for _, block := range blocks {
|
||||
err := chain.Accept(block)
|
||||
require.NoError(err)
|
||||
}
|
||||
chain.DrainAcceptorQueue()
|
||||
|
||||
lastAcceptedBlock := blocks[len(blocks)-1]
|
||||
require.Equal(lastAcceptedBlock.Hash(), chain.CurrentHeader().Hash())
|
||||
|
||||
CheckTxIndices(t, nil, lastAcceptedBlock.NumberU64(), chain.db, false) // check all indices has been indexed
|
||||
chain.Stop()
|
||||
|
||||
// Reconstruct a block chain which only reserves limited tx indices
|
||||
// 128 blocks were previously indexed. Now we add a new block at each test step.
|
||||
limits := []uint64{
|
||||
0, /* tip: 129 reserve all (don't run) */
|
||||
131, /* tip: 130 reserve all */
|
||||
140, /* tip: 131 reserve all */
|
||||
64, /* tip: 132, limit:64 */
|
||||
32, /* tip: 133, limit:32 */
|
||||
}
|
||||
for i, l := range limits {
|
||||
t.Run(fmt.Sprintf("test-%d, limit: %d", i+1, l), func(t *testing.T) {
|
||||
conf.TransactionHistory = l
|
||||
|
||||
chain, err := createBlockChain(chainDB, conf, gspec, lastAcceptedBlock.Hash())
|
||||
require.NoError(err)
|
||||
|
||||
tail := getTail(l, lastAcceptedBlock.NumberU64())
|
||||
// check if startup indices are correct
|
||||
CheckTxIndices(t, tail, lastAcceptedBlock.NumberU64(), chain.db, false)
|
||||
|
||||
newBlks := blocks2[i : i+1]
|
||||
_, err = chain.InsertChain(newBlks) // Feed chain a higher block to trigger indices updater.
|
||||
require.NoError(err)
|
||||
|
||||
lastAcceptedBlock = newBlks[0]
|
||||
err = chain.Accept(lastAcceptedBlock) // Accept the block to trigger indices updater.
|
||||
require.NoError(err)
|
||||
chain.DrainAcceptorQueue()
|
||||
|
||||
tail = getTail(l, lastAcceptedBlock.NumberU64())
|
||||
// check if indices are updated correctly
|
||||
CheckTxIndices(t, tail, lastAcceptedBlock.NumberU64(), chain.db, false)
|
||||
chain.Stop()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func getTail(limit uint64, lastAccepted uint64) *uint64 {
|
||||
if limit == 0 {
|
||||
return nil
|
||||
}
|
||||
var tail uint64
|
||||
if lastAccepted > limit {
|
||||
// tail should be the oldest block number which is indexed
|
||||
// i.e the first block number that's in the lookup range
|
||||
tail = lastAccepted - limit + 1
|
||||
}
|
||||
return &tail
|
||||
}
|
||||
|
||||
func TestTransactionSkipIndexing(t *testing.T) {
|
||||
// Configure and generate a sample block chain
|
||||
require := require.New(t)
|
||||
var (
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
funds = big.NewInt(10000000000000)
|
||||
gspec = &Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)},
|
||||
Alloc: GenesisAlloc{addr1: {Balance: funds}},
|
||||
}
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
)
|
||||
genDb, blocks, _, err := GenerateChainWithGenesis(gspec, dummy.NewCoinbaseFaker(), 5, 10, func(i int, block *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
|
||||
require.NoError(err)
|
||||
block.AddTx(tx)
|
||||
})
|
||||
require.NoError(err)
|
||||
|
||||
blocks2, _, err := GenerateChain(gspec.Config, blocks[len(blocks)-1], dummy.NewCoinbaseFaker(), genDb, 5, 10, func(i int, block *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
|
||||
require.NoError(err)
|
||||
block.AddTx(tx)
|
||||
})
|
||||
require.NoError(err)
|
||||
|
||||
conf := &CacheConfig{
|
||||
TrieCleanLimit: 256,
|
||||
TrieDirtyLimit: 256,
|
||||
TrieDirtyCommitTarget: 20,
|
||||
TriePrefetcherParallelism: 4,
|
||||
Pruning: true,
|
||||
CommitInterval: 4096,
|
||||
SnapshotLimit: 256,
|
||||
SnapshotNoBuild: true, // Ensure the test errors if snapshot initialization fails
|
||||
AcceptorQueueLimit: 64,
|
||||
SkipTxIndexing: true,
|
||||
}
|
||||
|
||||
// test1: Init block chain and check all indices has been skipped.
|
||||
chainDB := rawdb.NewMemoryDatabase()
|
||||
chain, err := createAndInsertChain(chainDB, conf, gspec, blocks, common.Hash{},
|
||||
func(b *types.Block) {
|
||||
bNumber := b.NumberU64()
|
||||
checkTxIndicesHelper(t, nil, bNumber+1, bNumber+1, bNumber, chainDB, false) // check all indices has been skipped
|
||||
})
|
||||
require.NoError(err)
|
||||
chain.Stop()
|
||||
|
||||
// test2: specify lookuplimit with tx index skipping enabled. Blocks should not be indexed but tail should be updated.
|
||||
conf.TransactionHistory = 2
|
||||
chainDB = rawdb.NewMemoryDatabase()
|
||||
chain, err = createAndInsertChain(chainDB, conf, gspec, blocks, common.Hash{},
|
||||
func(b *types.Block) {
|
||||
bNumber := b.NumberU64()
|
||||
tail := bNumber - conf.TransactionHistory + 1
|
||||
checkTxIndicesHelper(t, &tail, bNumber+1, bNumber+1, bNumber, chainDB, false) // check all indices has been skipped
|
||||
})
|
||||
require.NoError(err)
|
||||
chain.Stop()
|
||||
|
||||
// test3: tx index skipping and unindexer disabled. Blocks should be indexed and tail should be updated.
|
||||
conf.TransactionHistory = 0
|
||||
conf.SkipTxIndexing = false
|
||||
chainDB = rawdb.NewMemoryDatabase()
|
||||
chain, err = createAndInsertChain(chainDB, conf, gspec, blocks, common.Hash{},
|
||||
func(b *types.Block) {
|
||||
bNumber := b.NumberU64()
|
||||
checkTxIndicesHelper(t, nil, 0, bNumber, bNumber, chainDB, false) // check all indices has been indexed
|
||||
})
|
||||
require.NoError(err)
|
||||
chain.Stop()
|
||||
|
||||
// now change tx index skipping to true and check that the indices are skipped for the last block
|
||||
// and old indices are removed up to the tail, but [tail, current) indices are still there.
|
||||
conf.TransactionHistory = 2
|
||||
conf.SkipTxIndexing = true
|
||||
chain, err = createAndInsertChain(chainDB, conf, gspec, blocks2[0:1], chain.CurrentHeader().Hash(),
|
||||
func(b *types.Block) {
|
||||
bNumber := b.NumberU64()
|
||||
tail := bNumber - conf.TransactionHistory + 1
|
||||
checkTxIndicesHelper(t, &tail, tail, bNumber-1, bNumber, chainDB, false)
|
||||
})
|
||||
require.NoError(err)
|
||||
chain.Stop()
|
||||
}
|
||||
|
||||
func createAndInsertChain(db ethdb.Database, cacheConfig *CacheConfig, gspec *Genesis, blocks types.Blocks, lastAcceptedHash common.Hash, accepted func(*types.Block)) (*BlockChain, error) {
|
||||
chain, err := createBlockChain(db, cacheConfig, gspec, lastAcceptedHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = chain.InsertChain(blocks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, block := range blocks {
|
||||
err := chain.Accept(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
chain.DrainAcceptorQueue()
|
||||
if accepted != nil {
|
||||
accepted(block)
|
||||
}
|
||||
}
|
||||
|
||||
return chain, nil
|
||||
}
|
||||
@@ -278,7 +278,7 @@ func newBlobTxMeta(id uint64, size uint32, tx *types.Transaction) *blobTxMeta {
|
||||
// going up, crossing the smaller positive jump counter). As such, the pool
|
||||
// cares only about the min of the two delta values for eviction priority.
|
||||
//
|
||||
// priority = min(delta-basefee, delta-blobfee)
|
||||
// priority = min(deltaBasefee, deltaBlobfee)
|
||||
//
|
||||
// - The above very aggressive dimensionality and noise reduction should result
|
||||
// in transaction being grouped into a small number of buckets, the further
|
||||
@@ -290,7 +290,7 @@ func newBlobTxMeta(id uint64, size uint32, tx *types.Transaction) *blobTxMeta {
|
||||
// with high fee caps since it could enable pool wars. As such, any positive
|
||||
// priority will be grouped together.
|
||||
//
|
||||
// priority = min(delta-basefee, delta-blobfee, 0)
|
||||
// priority = min(deltaBasefee, deltaBlobfee, 0)
|
||||
//
|
||||
// Optimisation tradeoffs:
|
||||
//
|
||||
@@ -352,7 +352,7 @@ func (p *BlobPool) Filter(tx *types.Transaction) bool {
|
||||
// Init sets the gas price needed to keep a transaction in the pool and the chain
|
||||
// head to allow balance / nonce checks. The transaction journal will be loaded
|
||||
// from disk and filtered based on the provided starting settings.
|
||||
func (p *BlobPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.AddressReserver) error {
|
||||
func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.AddressReserver) error {
|
||||
p.reserve = reserve
|
||||
|
||||
var (
|
||||
@@ -370,7 +370,7 @@ func (p *BlobPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.Addr
|
||||
}
|
||||
}
|
||||
// Initialize the state with head block, or fallback to empty one in
|
||||
// case the head state is not available(might occur when node is not
|
||||
// case the head state is not available (might occur when node is not
|
||||
// fully synced).
|
||||
state, err := p.chain.StateAt(head.Root)
|
||||
if err != nil {
|
||||
@@ -381,14 +381,14 @@ func (p *BlobPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.Addr
|
||||
}
|
||||
p.head, p.state = head, state
|
||||
|
||||
// Index all transactions on disk and delete anything inprocessable
|
||||
// Index all transactions on disk and delete anything unprocessable
|
||||
var fails []uint64
|
||||
index := func(id uint64, size uint32, blob []byte) {
|
||||
if p.parseTransaction(id, size, blob) != nil {
|
||||
fails = append(fails, id)
|
||||
}
|
||||
}
|
||||
store, err := billy.Open(billy.Options{Path: queuedir}, newSlotter(), index)
|
||||
store, err := billy.Open(billy.Options{Path: queuedir, Repair: true}, newSlotter(), index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -396,6 +396,8 @@ func (p *BlobPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.Addr
|
||||
|
||||
if len(fails) > 0 {
|
||||
log.Warn("Dropping invalidated blob transactions", "ids", fails)
|
||||
dropInvalidMeter.Mark(int64(len(fails)))
|
||||
|
||||
for _, id := range fails {
|
||||
if err := p.store.Delete(id); err != nil {
|
||||
p.Close()
|
||||
@@ -426,7 +428,7 @@ func (p *BlobPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.Addr
|
||||
var (
|
||||
// basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), p.head))
|
||||
basefee = uint256.MustFromBig(baseFee)
|
||||
blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice))
|
||||
blobfee = uint256.NewInt(params.BlobTxMinBlobGasprice)
|
||||
)
|
||||
if p.head.ExcessBlobGas != nil {
|
||||
blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(*p.head.ExcessBlobGas))
|
||||
@@ -444,7 +446,7 @@ func (p *BlobPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.Addr
|
||||
basefeeGauge.Update(int64(basefee.Uint64()))
|
||||
blobfeeGauge.Update(int64(blobfee.Uint64()))
|
||||
|
||||
p.SetGasTip(gasTip)
|
||||
p.SetGasTip(new(big.Int).SetUint64(gasTip))
|
||||
|
||||
// Since the user might have modified their pool's capacity, evict anything
|
||||
// above the current allowance
|
||||
@@ -460,7 +462,7 @@ func (p *BlobPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.Addr
|
||||
// Close closes down the underlying persistent store.
|
||||
func (p *BlobPool) Close() error {
|
||||
var errs []error
|
||||
if p.limbo != nil {
|
||||
if p.limbo != nil { // Close might be invoked due to error in constructor, before p,limbo is set
|
||||
if err := p.limbo.Close(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
@@ -484,7 +486,7 @@ func (p *BlobPool) parseTransaction(id uint64, size uint32, blob []byte) error {
|
||||
tx := new(types.Transaction)
|
||||
if err := rlp.DecodeBytes(blob, tx); err != nil {
|
||||
// This path is impossible unless the disk data representation changes
|
||||
// across restarts. For that ever unprobable case, recover gracefully
|
||||
// across restarts. For that ever improbable case, recover gracefully
|
||||
// by ignoring this data entry.
|
||||
log.Error("Failed to decode blob pool entry", "id", id, "err", err)
|
||||
return err
|
||||
@@ -495,11 +497,17 @@ func (p *BlobPool) parseTransaction(id uint64, size uint32, blob []byte) error {
|
||||
}
|
||||
|
||||
meta := newBlobTxMeta(id, size, tx)
|
||||
|
||||
if _, exists := p.lookup[meta.hash]; exists {
|
||||
// This path is only possible after a crash, where deleted items are not
|
||||
// removed via the normal shutdown-startup procedure and thus may get
|
||||
// partially resurrected.
|
||||
log.Error("Rejecting duplicate blob pool entry", "id", id, "hash", tx.Hash())
|
||||
return errors.New("duplicate blob entry")
|
||||
}
|
||||
sender, err := p.signer.Sender(tx)
|
||||
if err != nil {
|
||||
// This path is impossible unless the signature validity changes across
|
||||
// restarts. For that ever unprobable case, recover gracefully by ignoring
|
||||
// restarts. For that ever improbable case, recover gracefully by ignoring
|
||||
// this data entry.
|
||||
log.Error("Failed to recover blob tx sender", "id", id, "hash", tx.Hash(), "err", err)
|
||||
return err
|
||||
@@ -558,15 +566,17 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
|
||||
}
|
||||
delete(p.index, addr)
|
||||
delete(p.spent, addr)
|
||||
if inclusions != nil { // only during reorgs will the heap will be initialized
|
||||
if inclusions != nil { // only during reorgs will the heap be initialized
|
||||
heap.Remove(p.evict, p.evict.index[addr])
|
||||
}
|
||||
p.reserve(addr, false)
|
||||
|
||||
if gapped {
|
||||
log.Warn("Dropping dangling blob transactions", "from", addr, "missing", next, "drop", nonces, "ids", ids)
|
||||
dropDanglingMeter.Mark(int64(len(ids)))
|
||||
} else {
|
||||
log.Trace("Dropping filled blob transactions", "from", addr, "filled", nonces, "ids", ids)
|
||||
dropFilledMeter.Mark(int64(len(ids)))
|
||||
}
|
||||
for _, id := range ids {
|
||||
if err := p.store.Delete(id); err != nil {
|
||||
@@ -597,6 +607,8 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
|
||||
txs = txs[1:]
|
||||
}
|
||||
log.Trace("Dropping overlapped blob transactions", "from", addr, "overlapped", nonces, "ids", ids, "left", len(txs))
|
||||
dropOverlappedMeter.Mark(int64(len(ids)))
|
||||
|
||||
for _, id := range ids {
|
||||
if err := p.store.Delete(id); err != nil {
|
||||
log.Error("Failed to delete blob transaction", "from", addr, "id", id, "err", err)
|
||||
@@ -611,7 +623,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
|
||||
txs[0].evictionBlobFeeJumps = txs[0].blobfeeJumps
|
||||
|
||||
for i := 1; i < len(txs); i++ {
|
||||
// If there's no nonce gap, initialize the evicion thresholds as the
|
||||
// If there's no nonce gap, initialize the eviction thresholds as the
|
||||
// minimum between the cumulative thresholds and the current tx fees
|
||||
if txs[i].nonce == txs[i-1].nonce+1 {
|
||||
txs[i].evictionExecTip = txs[i-1].evictionExecTip
|
||||
@@ -628,10 +640,30 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Sanity check that there's no double nonce. This case would be a coding
|
||||
// error, but better know about it
|
||||
// Sanity check that there's no double nonce. This case would generally
|
||||
// be a coding error, so better know about it.
|
||||
//
|
||||
// Also, Billy behind the blobpool does not journal deletes. A process
|
||||
// crash would result in previously deleted entities being resurrected.
|
||||
// That could potentially cause a duplicate nonce to appear.
|
||||
if txs[i].nonce == txs[i-1].nonce {
|
||||
log.Error("Duplicate nonce blob transaction", "from", addr, "nonce", txs[i].nonce)
|
||||
id := p.lookup[txs[i].hash]
|
||||
|
||||
log.Error("Dropping repeat nonce blob transaction", "from", addr, "nonce", txs[i].nonce, "id", id)
|
||||
dropRepeatedMeter.Mark(1)
|
||||
|
||||
p.spent[addr] = new(uint256.Int).Sub(p.spent[addr], txs[i].costCap)
|
||||
p.stored -= uint64(txs[i].size)
|
||||
delete(p.lookup, txs[i].hash)
|
||||
|
||||
if err := p.store.Delete(id); err != nil {
|
||||
log.Error("Failed to delete blob transaction", "from", addr, "id", id, "err", err)
|
||||
}
|
||||
txs = append(txs[:i], txs[i+1:]...)
|
||||
p.index[addr] = txs
|
||||
|
||||
i--
|
||||
continue
|
||||
}
|
||||
// Otherwise if there's a nonce gap evict all later transactions
|
||||
var (
|
||||
@@ -649,6 +681,8 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
|
||||
txs = txs[:i]
|
||||
|
||||
log.Error("Dropping gapped blob transactions", "from", addr, "missing", txs[i-1].nonce+1, "drop", nonces, "ids", ids)
|
||||
dropGappedMeter.Mark(int64(len(ids)))
|
||||
|
||||
for _, id := range ids {
|
||||
if err := p.store.Delete(id); err != nil {
|
||||
log.Error("Failed to delete blob transaction", "from", addr, "id", id, "err", err)
|
||||
@@ -660,7 +694,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
|
||||
// Ensure that there's no over-draft, this is expected to happen when some
|
||||
// transactions get included without publishing on the network
|
||||
var (
|
||||
balance = uint256.MustFromBig(p.state.GetBalance(addr))
|
||||
balance = p.state.GetBalance(addr)
|
||||
spent = p.spent[addr]
|
||||
)
|
||||
if spent.Cmp(balance) > 0 {
|
||||
@@ -685,7 +719,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
|
||||
if len(txs) == 0 {
|
||||
delete(p.index, addr)
|
||||
delete(p.spent, addr)
|
||||
if inclusions != nil { // only during reorgs will the heap will be initialized
|
||||
if inclusions != nil { // only during reorgs will the heap be initialized
|
||||
heap.Remove(p.evict, p.evict.index[addr])
|
||||
}
|
||||
p.reserve(addr, false)
|
||||
@@ -693,6 +727,8 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
|
||||
p.index[addr] = txs
|
||||
}
|
||||
log.Warn("Dropping overdrafted blob transactions", "from", addr, "balance", balance, "spent", spent, "drop", nonces, "ids", ids)
|
||||
dropOverdraftedMeter.Mark(int64(len(ids)))
|
||||
|
||||
for _, id := range ids {
|
||||
if err := p.store.Delete(id); err != nil {
|
||||
log.Error("Failed to delete blob transaction", "from", addr, "id", id, "err", err)
|
||||
@@ -723,6 +759,8 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
|
||||
p.index[addr] = txs
|
||||
|
||||
log.Warn("Dropping overcapped blob transactions", "from", addr, "kept", len(txs), "drop", nonces, "ids", ids)
|
||||
dropOvercappedMeter.Mark(int64(len(ids)))
|
||||
|
||||
for _, id := range ids {
|
||||
if err := p.store.Delete(id); err != nil {
|
||||
log.Error("Failed to delete blob transaction", "from", addr, "id", id, "err", err)
|
||||
@@ -739,7 +777,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
|
||||
// offload removes a tracked blob transaction from the pool and moves it into the
|
||||
// limbo for tracking until finality.
|
||||
//
|
||||
// The method may log errors for various unexpcted scenarios but will not return
|
||||
// The method may log errors for various unexpected scenarios but will not return
|
||||
// any of it since there's no clear error case. Some errors may be due to coding
|
||||
// issues, others caused by signers mining MEV stuff or swapping transactions. In
|
||||
// all cases, the pool needs to continue operating.
|
||||
@@ -797,7 +835,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
|
||||
}
|
||||
}
|
||||
// Recheck the account's pooled transactions to drop included and
|
||||
// invalidated one
|
||||
// invalidated ones
|
||||
p.recheck(addr, inclusions)
|
||||
}
|
||||
if len(adds) > 0 {
|
||||
@@ -813,7 +851,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
|
||||
log.Error("Failed to get fee config to reset blobpool fees", "err", err)
|
||||
return
|
||||
}
|
||||
_, baseFee, err := dummy.EstimateNextBaseFee(
|
||||
_, baseFeeBig, err := dummy.EstimateNextBaseFee(
|
||||
p.chain.Config(),
|
||||
feeConfig,
|
||||
p.head,
|
||||
@@ -826,7 +864,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
|
||||
// Reset the price heap for the new set of basefee/blobfee pairs
|
||||
var (
|
||||
// basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), newHead))
|
||||
basefee = uint256.MustFromBig(baseFee)
|
||||
basefee = uint256.MustFromBig(baseFeeBig)
|
||||
blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice))
|
||||
)
|
||||
if newHead.ExcessBlobGas != nil {
|
||||
@@ -996,7 +1034,7 @@ func (p *BlobPool) reinject(addr common.Address, txhash common.Hash) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the indixes and metrics
|
||||
// Update the indices and metrics
|
||||
meta := newBlobTxMeta(id, p.store.Size(id), tx)
|
||||
if _, ok := p.index[addr]; !ok {
|
||||
if err := p.reserve(addr, true); err != nil {
|
||||
@@ -1063,6 +1101,8 @@ func (p *BlobPool) SetGasTip(tip *big.Int) {
|
||||
}
|
||||
// Clear out the transactions from the data store
|
||||
log.Warn("Dropping underpriced blob transaction", "from", addr, "rejected", tx.nonce, "tip", tx.execTipCap, "want", tip, "drop", nonces, "ids", ids)
|
||||
dropUnderpricedMeter.Mark(int64(len(ids)))
|
||||
|
||||
for _, id := range ids {
|
||||
if err := p.store.Delete(id); err != nil {
|
||||
log.Error("Failed to delete dropped transaction", "id", id, "err", err)
|
||||
@@ -1210,7 +1250,7 @@ func (p *BlobPool) Get(hash common.Hash) *types.Transaction {
|
||||
}
|
||||
|
||||
// Add inserts a set of blob transactions into the pool if they pass validation (both
|
||||
// consensus validity and pool restictions).
|
||||
// consensus validity and pool restrictions).
|
||||
func (p *BlobPool) Add(txs []*types.Transaction, local bool, sync bool) []error {
|
||||
var (
|
||||
adds = make([]*types.Transaction, 0, len(txs))
|
||||
@@ -1230,10 +1270,10 @@ func (p *BlobPool) Add(txs []*types.Transaction, local bool, sync bool) []error
|
||||
}
|
||||
|
||||
// Add inserts a new blob transaction into the pool if it passes validation (both
|
||||
// consensus validity and pool restictions).
|
||||
// consensus validity and pool restrictions).
|
||||
func (p *BlobPool) add(tx *types.Transaction) (err error) {
|
||||
// The blob pool blocks on adding a transaction. This is because blob txs are
|
||||
// only even pulled form the network, so this method will act as the overload
|
||||
// only even pulled from the network, so this method will act as the overload
|
||||
// protection for fetches.
|
||||
waitStart := time.Now()
|
||||
p.lock.Lock()
|
||||
@@ -1247,6 +1287,22 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) {
|
||||
// Ensure the transaction is valid from all perspectives
|
||||
if err := p.validateTx(tx); err != nil {
|
||||
log.Trace("Transaction validation failed", "hash", tx.Hash(), "err", err)
|
||||
switch {
|
||||
case errors.Is(err, txpool.ErrUnderpriced):
|
||||
addUnderpricedMeter.Mark(1)
|
||||
case errors.Is(err, core.ErrNonceTooLow):
|
||||
addStaleMeter.Mark(1)
|
||||
case errors.Is(err, core.ErrNonceTooHigh):
|
||||
addGappedMeter.Mark(1)
|
||||
case errors.Is(err, core.ErrInsufficientFunds):
|
||||
addOverdraftedMeter.Mark(1)
|
||||
case errors.Is(err, txpool.ErrAccountLimitExceeded):
|
||||
addOvercappedMeter.Mark(1)
|
||||
case errors.Is(err, txpool.ErrReplaceUnderpriced):
|
||||
addNoreplaceMeter.Mark(1)
|
||||
default:
|
||||
addInvalidMeter.Mark(1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// If the address is not yet known, request exclusivity to track the account
|
||||
@@ -1254,6 +1310,7 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) {
|
||||
from, _ := types.Sender(p.signer, tx) // already validated above
|
||||
if _, ok := p.index[from]; !ok {
|
||||
if err := p.reserve(from, true); err != nil {
|
||||
addNonExclusiveMeter.Mark(1)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
@@ -1293,6 +1350,8 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) {
|
||||
}
|
||||
if len(p.index[from]) > offset {
|
||||
// Transaction replaces a previously queued one
|
||||
dropReplacedMeter.Mark(1)
|
||||
|
||||
prev := p.index[from][offset]
|
||||
if err := p.store.Delete(prev.id); err != nil {
|
||||
// Shitty situation, but try to recover gracefully instead of going boom
|
||||
@@ -1371,6 +1430,7 @@ func (p *BlobPool) add(tx *types.Transaction) (err error) {
|
||||
}
|
||||
p.updateStorageMetrics()
|
||||
|
||||
addValidMeter.Mark(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1404,7 +1464,7 @@ func (p *BlobPool) drop() {
|
||||
p.stored -= uint64(drop.size)
|
||||
delete(p.lookup, drop.hash)
|
||||
|
||||
// Remove the transaction from the pool's evicion heap:
|
||||
// Remove the transaction from the pool's eviction heap:
|
||||
// - If the entire account was dropped, pop off the address
|
||||
// - Otherwise, if the new tail has better eviction caps, fix the heap
|
||||
if last {
|
||||
@@ -1420,7 +1480,9 @@ func (p *BlobPool) drop() {
|
||||
}
|
||||
}
|
||||
// Remove the transaction from the data store
|
||||
log.Warn("Evicting overflown blob transaction", "from", from, "evicted", drop.nonce, "id", drop.id)
|
||||
log.Debug("Evicting overflown blob transaction", "from", from, "evicted", drop.nonce, "id", drop.id)
|
||||
dropOverflownMeter.Mark(1)
|
||||
|
||||
if err := p.store.Delete(drop.id); err != nil {
|
||||
log.Error("Failed to drop evicted transaction", "id", drop.id, "err", err)
|
||||
}
|
||||
@@ -1428,7 +1490,15 @@ func (p *BlobPool) drop() {
|
||||
|
||||
// Pending retrieves all currently processable transactions, grouped by origin
|
||||
// account and sorted by nonce.
|
||||
func (p *BlobPool) Pending(enforceTips bool) map[common.Address][]*txpool.LazyTransaction {
|
||||
//
|
||||
// The transactions can also be pre-filtered by the dynamic fee components to
|
||||
// reduce allocations and load on downstream subsystems.
|
||||
func (p *BlobPool) Pending(filter txpool.PendingFilter) map[common.Address][]*txpool.LazyTransaction {
|
||||
// If only plain transactions are requested, this pool is unsuitable as it
|
||||
// contains none, don't even bother.
|
||||
if filter.OnlyPlainTxs {
|
||||
return nil
|
||||
}
|
||||
// Track the amount of time waiting to retrieve the list of pending blob txs
|
||||
// from the pool and the amount of time actually spent on assembling the data.
|
||||
// The latter will be pretty much moot, but we've kept it to have symmetric
|
||||
@@ -1438,20 +1508,40 @@ func (p *BlobPool) Pending(enforceTips bool) map[common.Address][]*txpool.LazyTr
|
||||
pendwaitHist.Update(time.Since(pendStart).Nanoseconds())
|
||||
defer p.lock.RUnlock()
|
||||
|
||||
defer func(start time.Time) {
|
||||
pendtimeHist.Update(time.Since(start).Nanoseconds())
|
||||
}(time.Now())
|
||||
execStart := time.Now()
|
||||
defer func() {
|
||||
pendtimeHist.Update(time.Since(execStart).Nanoseconds())
|
||||
}()
|
||||
|
||||
pending := make(map[common.Address][]*txpool.LazyTransaction)
|
||||
pending := make(map[common.Address][]*txpool.LazyTransaction, len(p.index))
|
||||
for addr, txs := range p.index {
|
||||
var lazies []*txpool.LazyTransaction
|
||||
lazies := make([]*txpool.LazyTransaction, 0, len(txs))
|
||||
for _, tx := range txs {
|
||||
// If transaction filtering was requested, discard badly priced ones
|
||||
if filter.MinTip != nil && filter.BaseFee != nil {
|
||||
if tx.execFeeCap.Lt(filter.BaseFee) {
|
||||
break // basefee too low, cannot be included, discard rest of txs from the account
|
||||
}
|
||||
tip := new(uint256.Int).Sub(tx.execFeeCap, filter.BaseFee)
|
||||
if tip.Gt(tx.execTipCap) {
|
||||
tip = tx.execTipCap
|
||||
}
|
||||
if tip.Lt(filter.MinTip) {
|
||||
break // allowed or remaining tip too low, cannot be included, discard rest of txs from the account
|
||||
}
|
||||
}
|
||||
if filter.BlobFee != nil {
|
||||
if tx.blobFeeCap.Lt(filter.BlobFee) {
|
||||
break // blobfee too low, cannot be included, discard rest of txs from the account
|
||||
}
|
||||
}
|
||||
// Transaction was accepted according to the filter, append to the pending list
|
||||
lazies = append(lazies, &txpool.LazyTransaction{
|
||||
Pool: p,
|
||||
Hash: tx.hash,
|
||||
Time: time.Now(), // TODO(karalabe): Maybe save these and use that?
|
||||
GasFeeCap: tx.execFeeCap.ToBig(),
|
||||
GasTipCap: tx.execTipCap.ToBig(),
|
||||
Time: execStart, // TODO(karalabe): Maybe save these and use that?
|
||||
GasFeeCap: tx.execFeeCap,
|
||||
GasTipCap: tx.execTipCap,
|
||||
Gas: tx.execGas,
|
||||
BlobGas: tx.blobGas,
|
||||
})
|
||||
@@ -1463,10 +1553,6 @@ func (p *BlobPool) Pending(enforceTips bool) map[common.Address][]*txpool.LazyTr
|
||||
return pending
|
||||
}
|
||||
|
||||
func (p *BlobPool) PendingWithBaseFee(enforceTips bool, baseFee *big.Int) map[common.Address][]*txpool.LazyTransaction {
|
||||
return p.Pending(enforceTips)
|
||||
}
|
||||
|
||||
// IteratePending iterates over [pool.pending] until [f] returns false.
|
||||
// The caller must not modify [tx]. Returns false if iteration was interrupted.
|
||||
func (pool *BlobPool) IteratePending(f func(tx *types.Transaction) bool) bool {
|
||||
@@ -1537,7 +1623,7 @@ func (p *BlobPool) updateStorageMetrics() {
|
||||
}
|
||||
|
||||
// updateLimboMetrics retrieves a bunch of stats from the limbo store and pushes
|
||||
// // them out as metrics.
|
||||
// them out as metrics.
|
||||
func (p *BlobPool) updateLimboMetrics() {
|
||||
stats := p.limbo.store.Infos()
|
||||
|
||||
|
||||
@@ -62,21 +62,9 @@ var (
|
||||
emptyBlob = kzg4844.Blob{}
|
||||
emptyBlobCommit, _ = kzg4844.BlobToCommitment(emptyBlob)
|
||||
emptyBlobProof, _ = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit)
|
||||
emptyBlobVHash = blobHash(emptyBlobCommit)
|
||||
emptyBlobVHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit)
|
||||
)
|
||||
|
||||
func blobHash(commit kzg4844.Commitment) common.Hash {
|
||||
hasher := sha256.New()
|
||||
hasher.Write(commit[:])
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
var vhash common.Hash
|
||||
vhash[0] = params.BlobTxHashVersion
|
||||
copy(vhash[1:], hash[1:])
|
||||
|
||||
return vhash
|
||||
}
|
||||
|
||||
// Chain configuration with Cancun enabled.
|
||||
//
|
||||
// TODO(karalabe): replace with params.MainnetChainConfig after Cancun.
|
||||
@@ -222,7 +210,7 @@ func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64,
|
||||
return types.MustSignNewTx(key, types.LatestSigner(testChainConfig), blobtx)
|
||||
}
|
||||
|
||||
// makeUnsignedTx is a utility method to construct a random blob tranasaction
|
||||
// makeUnsignedTx is a utility method to construct a random blob transaction
|
||||
// without signing it.
|
||||
func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx {
|
||||
return &types.BlobTx{
|
||||
@@ -342,7 +330,16 @@ func verifyPoolInternals(t *testing.T, pool *BlobPool) {
|
||||
// - 1. A transaction that cannot be decoded must be dropped
|
||||
// - 2. A transaction that cannot be recovered (bad signature) must be dropped
|
||||
// - 3. All transactions after a nonce gap must be dropped
|
||||
// - 4. All transactions after an underpriced one (including it) must be dropped
|
||||
// - 4. All transactions after an already included nonce must be dropped
|
||||
// - 5. All transactions after an underpriced one (including it) must be dropped
|
||||
// - 6. All transactions after an overdrafting sequence must be dropped
|
||||
// - 7. All transactions exceeding the per-account limit must be dropped
|
||||
//
|
||||
// Furthermore, some strange corner-cases can also occur after a crash, as Billy's
|
||||
// simplicity also allows it to resurrect past deleted entities:
|
||||
//
|
||||
// - 8. Fully duplicate transactions (matching hash) must be dropped
|
||||
// - 9. Duplicate nonces from the same account must be dropped
|
||||
func TestOpenDrops(t *testing.T) {
|
||||
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
|
||||
|
||||
@@ -375,7 +372,7 @@ func TestOpenDrops(t *testing.T) {
|
||||
badsig, _ := store.Put(blob)
|
||||
|
||||
// Insert a sequence of transactions with a nonce gap in between to verify
|
||||
// that anything gapped will get evicted (case 3)
|
||||
// that anything gapped will get evicted (case 3).
|
||||
var (
|
||||
gapper, _ = crypto.GenerateKey()
|
||||
|
||||
@@ -394,7 +391,7 @@ func TestOpenDrops(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// Insert a sequence of transactions with a gapped starting nonce to verify
|
||||
// that the entire set will get dropped.
|
||||
// that the entire set will get dropped (case 3).
|
||||
var (
|
||||
dangler, _ = crypto.GenerateKey()
|
||||
dangling = make(map[uint64]struct{})
|
||||
@@ -407,7 +404,7 @@ func TestOpenDrops(t *testing.T) {
|
||||
dangling[id] = struct{}{}
|
||||
}
|
||||
// Insert a sequence of transactions with already passed nonces to veirfy
|
||||
// that the entire set will get dropped.
|
||||
// that the entire set will get dropped (case 4).
|
||||
var (
|
||||
filler, _ = crypto.GenerateKey()
|
||||
filled = make(map[uint64]struct{})
|
||||
@@ -419,8 +416,8 @@ func TestOpenDrops(t *testing.T) {
|
||||
id, _ := store.Put(blob)
|
||||
filled[id] = struct{}{}
|
||||
}
|
||||
// Insert a sequence of transactions with partially passed nonces to veirfy
|
||||
// that the included part of the set will get dropped
|
||||
// Insert a sequence of transactions with partially passed nonces to verify
|
||||
// that the included part of the set will get dropped (case 4).
|
||||
var (
|
||||
overlapper, _ = crypto.GenerateKey()
|
||||
overlapped = make(map[uint64]struct{})
|
||||
@@ -437,7 +434,7 @@ func TestOpenDrops(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// Insert a sequence of transactions with an underpriced first to verify that
|
||||
// the entire set will get dropped (case 4).
|
||||
// the entire set will get dropped (case 5).
|
||||
var (
|
||||
underpayer, _ = crypto.GenerateKey()
|
||||
underpaid = make(map[uint64]struct{})
|
||||
@@ -456,7 +453,7 @@ func TestOpenDrops(t *testing.T) {
|
||||
}
|
||||
|
||||
// Insert a sequence of transactions with an underpriced in between to verify
|
||||
// that it and anything newly gapped will get evicted (case 4).
|
||||
// that it and anything newly gapped will get evicted (case 5).
|
||||
var (
|
||||
outpricer, _ = crypto.GenerateKey()
|
||||
outpriced = make(map[uint64]struct{})
|
||||
@@ -478,7 +475,7 @@ func TestOpenDrops(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// Insert a sequence of transactions fully overdrafted to verify that the
|
||||
// entire set will get invalidated.
|
||||
// entire set will get invalidated (case 6).
|
||||
var (
|
||||
exceeder, _ = crypto.GenerateKey()
|
||||
exceeded = make(map[uint64]struct{})
|
||||
@@ -496,7 +493,7 @@ func TestOpenDrops(t *testing.T) {
|
||||
exceeded[id] = struct{}{}
|
||||
}
|
||||
// Insert a sequence of transactions partially overdrafted to verify that part
|
||||
// of the set will get invalidated.
|
||||
// of the set will get invalidated (case 6).
|
||||
var (
|
||||
overdrafter, _ = crypto.GenerateKey()
|
||||
overdrafted = make(map[uint64]struct{})
|
||||
@@ -518,7 +515,7 @@ func TestOpenDrops(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// Insert a sequence of transactions overflowing the account cap to verify
|
||||
// that part of the set will get invalidated.
|
||||
// that part of the set will get invalidated (case 7).
|
||||
var (
|
||||
overcapper, _ = crypto.GenerateKey()
|
||||
overcapped = make(map[uint64]struct{})
|
||||
@@ -533,21 +530,59 @@ func TestOpenDrops(t *testing.T) {
|
||||
overcapped[id] = struct{}{}
|
||||
}
|
||||
}
|
||||
// Insert a batch of duplicated transactions to verify that only one of each
|
||||
// version will remain (case 8).
|
||||
var (
|
||||
duplicater, _ = crypto.GenerateKey()
|
||||
duplicated = make(map[uint64]struct{})
|
||||
)
|
||||
for _, nonce := range []uint64{0, 1, 2} {
|
||||
blob, _ := rlp.EncodeToBytes(makeTx(nonce, 1, 1, 1, duplicater))
|
||||
|
||||
for i := 0; i < int(nonce)+1; i++ {
|
||||
id, _ := store.Put(blob)
|
||||
if i == 0 {
|
||||
valids[id] = struct{}{}
|
||||
} else {
|
||||
duplicated[id] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Insert a batch of duplicated nonces to verify that only one of each will
|
||||
// remain (case 9).
|
||||
var (
|
||||
repeater, _ = crypto.GenerateKey()
|
||||
repeated = make(map[uint64]struct{})
|
||||
)
|
||||
for _, nonce := range []uint64{0, 1, 2} {
|
||||
for i := 0; i < int(nonce)+1; i++ {
|
||||
blob, _ := rlp.EncodeToBytes(makeTx(nonce, 1, uint64(i)+1 /* unique hashes */, 1, repeater))
|
||||
|
||||
id, _ := store.Put(blob)
|
||||
if i == 0 {
|
||||
valids[id] = struct{}{}
|
||||
} else {
|
||||
repeated[id] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
store.Close()
|
||||
|
||||
// Create a blob pool out of the pre-seeded data
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), big.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), uint256.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000))
|
||||
statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3)
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), uint256.NewInt(1000000))
|
||||
statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2)
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), uint256.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(duplicater.PublicKey), uint256.NewInt(1000000))
|
||||
statedb.AddBalance(crypto.PubkeyToAddress(repeater.PublicKey), uint256.NewInt(1000000))
|
||||
statedb.Commit(0, true, false)
|
||||
|
||||
chain := &testBlockChain{
|
||||
@@ -557,7 +592,7 @@ func TestOpenDrops(t *testing.T) {
|
||||
statedb: statedb,
|
||||
}
|
||||
pool := New(Config{Datadir: storage}, chain)
|
||||
if err := pool.Init(big.NewInt(1), chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
t.Fatalf("failed to create blob pool: %v", err)
|
||||
}
|
||||
defer pool.Close()
|
||||
@@ -591,6 +626,10 @@ func TestOpenDrops(t *testing.T) {
|
||||
t.Errorf("partially overdrafted transaction remained in storage: %d", tx.id)
|
||||
} else if _, ok := overcapped[tx.id]; ok {
|
||||
t.Errorf("overcapped transaction remained in storage: %d", tx.id)
|
||||
} else if _, ok := duplicated[tx.id]; ok {
|
||||
t.Errorf("duplicated transaction remained in storage: %d", tx.id)
|
||||
} else if _, ok := repeated[tx.id]; ok {
|
||||
t.Errorf("repeated nonce transaction remained in storage: %d", tx.id)
|
||||
} else {
|
||||
alive[tx.id] = struct{}{}
|
||||
}
|
||||
@@ -621,7 +660,7 @@ func TestOpenDrops(t *testing.T) {
|
||||
|
||||
// Tests that transactions loaded from disk are indexed correctly.
|
||||
//
|
||||
// - 1. Transactions must be groupped by sender, sorted by nonce
|
||||
// - 1. Transactions must be grouped by sender, sorted by nonce
|
||||
// - 2. Eviction thresholds are calculated correctly for the sequences
|
||||
// - 3. Balance usage of an account is totals across all transactions
|
||||
func TestOpenIndex(t *testing.T) {
|
||||
@@ -635,7 +674,7 @@ func TestOpenIndex(t *testing.T) {
|
||||
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil)
|
||||
|
||||
// Insert a sequence of transactions with varying price points to check that
|
||||
// the cumulative minimumw will be maintained.
|
||||
// the cumulative minimum will be maintained.
|
||||
var (
|
||||
key, _ = crypto.GenerateKey()
|
||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||
@@ -662,7 +701,7 @@ func TestOpenIndex(t *testing.T) {
|
||||
|
||||
// Create a blob pool out of the pre-seeded data
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
||||
statedb.AddBalance(addr, big.NewInt(1_000_000_000))
|
||||
statedb.AddBalance(addr, uint256.NewInt(1_000_000_000))
|
||||
statedb.Commit(0, true, false)
|
||||
|
||||
chain := &testBlockChain{
|
||||
@@ -672,7 +711,7 @@ func TestOpenIndex(t *testing.T) {
|
||||
statedb: statedb,
|
||||
}
|
||||
pool := New(Config{Datadir: storage}, chain)
|
||||
if err := pool.Init(big.NewInt(1), chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
t.Fatalf("failed to create blob pool: %v", err)
|
||||
}
|
||||
defer pool.Close()
|
||||
@@ -762,9 +801,9 @@ func TestOpenHeap(t *testing.T) {
|
||||
|
||||
// Create a blob pool out of the pre-seeded data
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
||||
statedb.AddBalance(addr1, big.NewInt(1_000_000_000))
|
||||
statedb.AddBalance(addr2, big.NewInt(1_000_000_000))
|
||||
statedb.AddBalance(addr3, big.NewInt(1_000_000_000))
|
||||
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000))
|
||||
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000))
|
||||
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000))
|
||||
statedb.Commit(0, true, false)
|
||||
|
||||
chain := &testBlockChain{
|
||||
@@ -774,7 +813,7 @@ func TestOpenHeap(t *testing.T) {
|
||||
statedb: statedb,
|
||||
}
|
||||
pool := New(Config{Datadir: storage}, chain)
|
||||
if err := pool.Init(big.NewInt(1), chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
t.Fatalf("failed to create blob pool: %v", err)
|
||||
}
|
||||
defer pool.Close()
|
||||
@@ -842,9 +881,9 @@ func TestOpenCap(t *testing.T) {
|
||||
for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} {
|
||||
// Create a blob pool out of the pre-seeded data, but cap it to 2 blob transaction
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
||||
statedb.AddBalance(addr1, big.NewInt(1_000_000_000))
|
||||
statedb.AddBalance(addr2, big.NewInt(1_000_000_000))
|
||||
statedb.AddBalance(addr3, big.NewInt(1_000_000_000))
|
||||
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000))
|
||||
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000))
|
||||
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000))
|
||||
statedb.Commit(0, true, false)
|
||||
|
||||
chain := &testBlockChain{
|
||||
@@ -854,7 +893,7 @@ func TestOpenCap(t *testing.T) {
|
||||
statedb: statedb,
|
||||
}
|
||||
pool := New(Config{Datadir: storage, Datacap: datacap}, chain)
|
||||
if err := pool.Init(big.NewInt(1), chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
t.Fatalf("failed to create blob pool: %v", err)
|
||||
}
|
||||
// Verify that enough transactions have been dropped to get the pool's size
|
||||
@@ -1214,6 +1253,24 @@ func TestAdd(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
// Blob transactions that don't meet the min blob gas price should be rejected
|
||||
{
|
||||
seeds: map[string]seed{
|
||||
"alice": {balance: 10000000},
|
||||
},
|
||||
adds: []addtx{
|
||||
{ // New account, no previous txs, nonce 0, but blob fee cap too low
|
||||
from: "alice",
|
||||
tx: makeUnsignedTx(0, 1, 1, 0),
|
||||
err: txpool.ErrUnderpriced,
|
||||
},
|
||||
{ // Same as above but blob fee cap equals minimum, should be accepted
|
||||
from: "alice",
|
||||
tx: makeUnsignedTx(0, 1, 1, params.BlobTxMinBlobGasprice),
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
// Create a temporary folder for the persistent backend
|
||||
@@ -1234,8 +1291,8 @@ func TestAdd(t *testing.T) {
|
||||
keys[acc], _ = crypto.GenerateKey()
|
||||
addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey)
|
||||
|
||||
// Seed the state database with this acocunt
|
||||
statedb.AddBalance(addrs[acc], new(big.Int).SetUint64(seed.balance))
|
||||
// Seed the state database with this account
|
||||
statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance))
|
||||
statedb.SetNonce(addrs[acc], seed.nonce)
|
||||
|
||||
// Sign the seed transactions and store them in the data store
|
||||
@@ -1256,7 +1313,7 @@ func TestAdd(t *testing.T) {
|
||||
statedb: statedb,
|
||||
}
|
||||
pool := New(Config{Datadir: storage}, chain)
|
||||
if err := pool.Init(big.NewInt(1), chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
t.Fatalf("test %d: failed to create blob pool: %v", i, err)
|
||||
}
|
||||
verifyPoolInternals(t, pool)
|
||||
@@ -1274,3 +1331,65 @@ func TestAdd(t *testing.T) {
|
||||
pool.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmarks the time it takes to assemble the lazy pending transaction list
|
||||
// from the pool contents.
|
||||
func BenchmarkPoolPending100Mb(b *testing.B) { benchmarkPoolPending(b, 100_000_000) }
|
||||
func BenchmarkPoolPending1GB(b *testing.B) { benchmarkPoolPending(b, 1_000_000_000) }
|
||||
func BenchmarkPoolPending10GB(b *testing.B) { benchmarkPoolPending(b, 10_000_000_000) }
|
||||
|
||||
func benchmarkPoolPending(b *testing.B, datacap uint64) {
|
||||
// Calculate the maximum number of transaction that would fit into the pool
|
||||
// and generate a set of random accounts to seed them with.
|
||||
capacity := datacap / params.BlobTxBlobGasPerBlob
|
||||
|
||||
var (
|
||||
basefee = uint64(1050)
|
||||
blobfee = uint64(105)
|
||||
signer = types.LatestSigner(testChainConfig)
|
||||
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
||||
chain = &testBlockChain{
|
||||
config: testChainConfig,
|
||||
basefee: uint256.NewInt(basefee),
|
||||
blobfee: uint256.NewInt(blobfee),
|
||||
statedb: statedb,
|
||||
}
|
||||
pool = New(Config{Datadir: ""}, chain)
|
||||
)
|
||||
|
||||
if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
b.Fatalf("failed to create blob pool: %v", err)
|
||||
}
|
||||
// Fill the pool up with one random transaction from each account with the
|
||||
// same price and everything to maximize the worst case scenario
|
||||
for i := 0; i < int(capacity); i++ {
|
||||
blobtx := makeUnsignedTx(0, 10, basefee+10, blobfee)
|
||||
blobtx.R = uint256.NewInt(1)
|
||||
blobtx.S = uint256.NewInt(uint64(100 + i))
|
||||
blobtx.V = uint256.NewInt(0)
|
||||
tx := types.NewTx(blobtx)
|
||||
addr, err := types.Sender(signer, tx)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
statedb.AddBalance(addr, uint256.NewInt(1_000_000_000))
|
||||
pool.add(tx)
|
||||
}
|
||||
statedb.Commit(0, true, false)
|
||||
defer pool.Close()
|
||||
|
||||
// Benchmark assembling the pending
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
p := pool.Pending(txpool.PendingFilter{
|
||||
MinTip: uint256.NewInt(1),
|
||||
BaseFee: chain.basefee,
|
||||
BlobFee: chain.blobfee,
|
||||
})
|
||||
if len(p) != int(capacity) {
|
||||
b.Fatalf("have %d want %d", len(p), capacity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ type Config struct {
|
||||
// DefaultConfig contains the default configurations for the transaction pool.
|
||||
var DefaultConfig = Config{
|
||||
Datadir: "blobpool",
|
||||
Datacap: 10 * 1024 * 1024 * 1024,
|
||||
PriceBump: 100, // either have patience or be aggressive, no mushy ground
|
||||
Datacap: 10 * 1024 * 1024 * 1024 / 4, // TODO(karalabe): /4 handicap for rollout, gradually bump back up to 10GB
|
||||
PriceBump: 100, // either have patience or be aggressive, no mushy ground
|
||||
}
|
||||
|
||||
// sanitize checks the provided user configurations and changes anything that's
|
||||
|
||||
@@ -40,7 +40,7 @@ import (
|
||||
// transaction from each account to determine which account to evict from.
|
||||
//
|
||||
// The heap internally tracks a slice of cheapest transactions from each account
|
||||
// and a mapping from addresses to indices for direct removals/udates.
|
||||
// and a mapping from addresses to indices for direct removals/updates.
|
||||
//
|
||||
// The goal of the heap is to decide which account has the worst bottleneck to
|
||||
// evict transactions from.
|
||||
|
||||
@@ -63,7 +63,7 @@ func newLimbo(datadir string) (*limbo, error) {
|
||||
index: make(map[common.Hash]uint64),
|
||||
groups: make(map[uint64]map[uint64]common.Hash),
|
||||
}
|
||||
// Index all limboed blobs on disk and delete anything inprocessable
|
||||
// Index all limboed blobs on disk and delete anything unprocessable
|
||||
var fails []uint64
|
||||
index := func(id uint64, size uint32, data []byte) {
|
||||
if l.parseBlob(id, data) != nil {
|
||||
@@ -99,7 +99,7 @@ func (l *limbo) parseBlob(id uint64, data []byte) error {
|
||||
item := new(limboBlob)
|
||||
if err := rlp.DecodeBytes(data, item); err != nil {
|
||||
// This path is impossible unless the disk data representation changes
|
||||
// across restarts. For that ever unprobable case, recover gracefully
|
||||
// across restarts. For that ever improbable case, recover gracefully
|
||||
// by ignoring this data entry.
|
||||
log.Error("Failed to decode blob limbo entry", "id", id, "err", err)
|
||||
return err
|
||||
@@ -182,7 +182,7 @@ func (l *limbo) pull(tx common.Hash) (*types.Transaction, error) {
|
||||
// update changes the block number under which a blob transaction is tracked. This
|
||||
// method should be used when a reorg changes a transaction's inclusion block.
|
||||
//
|
||||
// The method may log errors for various unexpcted scenarios but will not return
|
||||
// The method may log errors for various unexpected scenarios but will not return
|
||||
// any of it since there's no clear error case. Some errors may be due to coding
|
||||
// issues, others caused by signers mining MEV stuff or swapping transactions. In
|
||||
// all cases, the pool needs to continue operating.
|
||||
|
||||
@@ -75,8 +75,8 @@ var (
|
||||
pooltipGauge = metrics.NewRegisteredGauge("blobpool/pooltip", nil)
|
||||
|
||||
// addwait/time, resetwait/time and getwait/time track the rough health of
|
||||
// the pool and whether or not it's capable of keeping up with the load from
|
||||
// the network.
|
||||
// the pool and whether it's capable of keeping up with the load from the
|
||||
// network.
|
||||
addwaitHist = metrics.NewRegisteredHistogram("blobpool/addwait", nil, metrics.NewExpDecaySample(1028, 0.015))
|
||||
addtimeHist = metrics.NewRegisteredHistogram("blobpool/addtime", nil, metrics.NewExpDecaySample(1028, 0.015))
|
||||
getwaitHist = metrics.NewRegisteredHistogram("blobpool/getwait", nil, metrics.NewExpDecaySample(1028, 0.015))
|
||||
@@ -85,4 +85,31 @@ var (
|
||||
pendtimeHist = metrics.NewRegisteredHistogram("blobpool/pendtime", nil, metrics.NewExpDecaySample(1028, 0.015))
|
||||
resetwaitHist = metrics.NewRegisteredHistogram("blobpool/resetwait", nil, metrics.NewExpDecaySample(1028, 0.015))
|
||||
resettimeHist = metrics.NewRegisteredHistogram("blobpool/resettime", nil, metrics.NewExpDecaySample(1028, 0.015))
|
||||
|
||||
// The below metrics track various cases where transactions are dropped out
|
||||
// of the pool. Most are exceptional, some are chain progression and some
|
||||
// threshold cappings.
|
||||
dropInvalidMeter = metrics.NewRegisteredMeter("blobpool/drop/invalid", nil) // Invalid transaction, consensus change or bugfix, neutral-ish
|
||||
dropDanglingMeter = metrics.NewRegisteredMeter("blobpool/drop/dangling", nil) // First nonce gapped, bad
|
||||
dropFilledMeter = metrics.NewRegisteredMeter("blobpool/drop/filled", nil) // State full-overlap, chain progress, ok
|
||||
dropOverlappedMeter = metrics.NewRegisteredMeter("blobpool/drop/overlapped", nil) // State partial-overlap, chain progress, ok
|
||||
dropRepeatedMeter = metrics.NewRegisteredMeter("blobpool/drop/repeated", nil) // Repeated nonce, bad
|
||||
dropGappedMeter = metrics.NewRegisteredMeter("blobpool/drop/gapped", nil) // Non-first nonce gapped, bad
|
||||
dropOverdraftedMeter = metrics.NewRegisteredMeter("blobpool/drop/overdrafted", nil) // Balance exceeded, bad
|
||||
dropOvercappedMeter = metrics.NewRegisteredMeter("blobpool/drop/overcapped", nil) // Per-account cap exceeded, bad
|
||||
dropOverflownMeter = metrics.NewRegisteredMeter("blobpool/drop/overflown", nil) // Global disk cap exceeded, neutral-ish
|
||||
dropUnderpricedMeter = metrics.NewRegisteredMeter("blobpool/drop/underpriced", nil) // Gas tip changed, neutral
|
||||
dropReplacedMeter = metrics.NewRegisteredMeter("blobpool/drop/replaced", nil) // Transaction replaced, neutral
|
||||
|
||||
// The below metrics track various outcomes of transactions being added to
|
||||
// the pool.
|
||||
addInvalidMeter = metrics.NewRegisteredMeter("blobpool/add/invalid", nil) // Invalid transaction, reject, neutral
|
||||
addUnderpricedMeter = metrics.NewRegisteredMeter("blobpool/add/underpriced", nil) // Gas tip too low, neutral
|
||||
addStaleMeter = metrics.NewRegisteredMeter("blobpool/add/stale", nil) // Nonce already filled, reject, bad-ish
|
||||
addGappedMeter = metrics.NewRegisteredMeter("blobpool/add/gapped", nil) // Nonce gapped, reject, bad-ish
|
||||
addOverdraftedMeter = metrics.NewRegisteredMeter("blobpool/add/overdrafted", nil) // Balance exceeded, reject, neutral
|
||||
addOvercappedMeter = metrics.NewRegisteredMeter("blobpool/add/overcapped", nil) // Per-account cap exceeded, reject, neutral
|
||||
addNoreplaceMeter = metrics.NewRegisteredMeter("blobpool/add/noreplace", nil) // Replacement fees or tips too low, neutral
|
||||
addNonExclusiveMeter = metrics.NewRegisteredMeter("blobpool/add/nonexclusive", nil) // Plain transaction from same account exists, reject, neutral
|
||||
addValidMeter = metrics.NewRegisteredMeter("blobpool/add/valid", nil) // Valid transaction, add, neutral
|
||||
)
|
||||
|
||||
@@ -74,7 +74,7 @@ func BenchmarkDynamicFeeJumpCalculation(b *testing.B) {
|
||||
// Benchmarks how many priority recalculations can be done.
|
||||
func BenchmarkPriorityCalculation(b *testing.B) {
|
||||
// The basefee and blob fee is constant for all transactions across a block,
|
||||
// so we can assume theit absolute jump counts can be pre-computed.
|
||||
// so we can assume their absolute jump counts can be pre-computed.
|
||||
basefee := uint256.NewInt(17_200_000_000) // 17.2 Gwei is the 22.03.2023 zero-emission basefee, random number
|
||||
blobfee := uint256.NewInt(123_456_789_000) // Completely random, no idea what this will be
|
||||
|
||||
|
||||
@@ -64,4 +64,10 @@ var (
|
||||
// ErrFutureReplacePending is returned if a future transaction replaces a pending
|
||||
// one. Future transactions should only be able to replace other future transactions.
|
||||
ErrFutureReplacePending = errors.New("future transaction tries to replace pending")
|
||||
|
||||
// ErrAlreadyReserved is returned if the sender address has a pending transaction
|
||||
// in a different subpool. For example, this error is returned in response to any
|
||||
// input transaction of non-blob type when a blob transaction from this sender
|
||||
// remains pending (and vice-versa).
|
||||
ErrAlreadyReserved = errors.New("address already reserved")
|
||||
)
|
||||
|
||||
@@ -174,7 +174,12 @@ func (journal *journal) rotate(all map[common.Address]types.Transactions) error
|
||||
return err
|
||||
}
|
||||
journal.writer = sink
|
||||
log.Info("Regenerated local transaction journal", "transactions", journaled, "accounts", len(all))
|
||||
|
||||
logger := log.Info
|
||||
if len(all) == 0 {
|
||||
logger = log.Debug
|
||||
}
|
||||
logger("Regenerated local transaction journal", "transactions", journaled, "accounts", len(all))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/prque"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -223,7 +224,7 @@ type LegacyPool struct {
|
||||
config Config
|
||||
chainconfig *params.ChainConfig
|
||||
chain BlockChain
|
||||
gasTip atomic.Pointer[big.Int]
|
||||
gasTip atomic.Pointer[uint256.Int]
|
||||
minimumFee *big.Int
|
||||
txFeed event.Feed
|
||||
signer types.Signer
|
||||
@@ -317,15 +318,15 @@ func (pool *LegacyPool) Filter(tx *types.Transaction) bool {
|
||||
// head to allow balance / nonce checks. The transaction journal will be loaded
|
||||
// from disk and filtered based on the provided starting settings. The internal
|
||||
// goroutines will be spun up and the pool deemed operational afterwards.
|
||||
func (pool *LegacyPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.AddressReserver) error {
|
||||
func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserve txpool.AddressReserver) error {
|
||||
// Set the address reserver to request exclusive access to pooled accounts
|
||||
pool.reserve = reserve
|
||||
|
||||
// Set the basic pool parameters
|
||||
pool.gasTip.Store(gasTip)
|
||||
pool.gasTip.Store(uint256.NewInt(gasTip))
|
||||
|
||||
// Initialize the state with head block, or fallback to empty one in
|
||||
// case the head state is not available(might occur when node is not
|
||||
// case the head state is not available (might occur when node is not
|
||||
// fully synced).
|
||||
statedb, err := pool.chain.StateAt(head.Root)
|
||||
if err != nil {
|
||||
@@ -468,11 +469,13 @@ func (pool *LegacyPool) SetGasTip(tip *big.Int) {
|
||||
pool.mu.Lock()
|
||||
defer pool.mu.Unlock()
|
||||
|
||||
old := pool.gasTip.Load()
|
||||
pool.gasTip.Store(new(big.Int).Set(tip))
|
||||
|
||||
var (
|
||||
newTip = uint256.MustFromBig(tip)
|
||||
old = pool.gasTip.Load()
|
||||
)
|
||||
pool.gasTip.Store(newTip)
|
||||
// If the min miner fee increased, remove transactions below the new threshold
|
||||
if tip.Cmp(old) > 0 {
|
||||
if newTip.Cmp(old) > 0 {
|
||||
// pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead
|
||||
drop := pool.all.RemotesBelowTip(tip)
|
||||
for _, tx := range drop {
|
||||
@@ -480,7 +483,7 @@ func (pool *LegacyPool) SetGasTip(tip *big.Int) {
|
||||
}
|
||||
pool.priced.Removed(len(drop))
|
||||
}
|
||||
log.Info("Legacy pool tip threshold updated", "tip", tip)
|
||||
log.Info("Legacy pool tip threshold updated", "tip", newTip)
|
||||
}
|
||||
|
||||
func (pool *LegacyPool) SetMinFee(minFee *big.Int) {
|
||||
@@ -557,23 +560,33 @@ func (pool *LegacyPool) ContentFrom(addr common.Address) ([]*types.Transaction,
|
||||
}
|
||||
|
||||
// Pending retrieves all currently processable transactions, grouped by origin
|
||||
// account and sorted by nonce. The returned transaction set is a copy and can be
|
||||
// freely modified by calling code.
|
||||
// account and sorted by nonce.
|
||||
//
|
||||
// The enforceTips parameter can be used to do an extra filtering on the pending
|
||||
// transactions and only return those whose **effective** tip is large enough in
|
||||
// the next pending execution environment.
|
||||
func (pool *LegacyPool) Pending(enforceTips bool) map[common.Address][]*txpool.LazyTransaction {
|
||||
return pool.PendingWithBaseFee(enforceTips, nil)
|
||||
}
|
||||
|
||||
// If baseFee is nil, then pool.priced.urgent.baseFee is used.
|
||||
func (pool *LegacyPool) PendingWithBaseFee(enforceTips bool, baseFee *big.Int) map[common.Address][]*txpool.LazyTransaction {
|
||||
// The transactions can also be pre-filtered by the dynamic fee components to
|
||||
// reduce allocations and load on downstream subsystems.
|
||||
func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address][]*txpool.LazyTransaction {
|
||||
// If only blob transactions are requested, this pool is unsuitable as it
|
||||
// contains none, don't even bother.
|
||||
if filter.OnlyBlobTxs {
|
||||
return nil
|
||||
}
|
||||
pool.mu.Lock()
|
||||
defer pool.mu.Unlock()
|
||||
|
||||
if baseFee == nil {
|
||||
baseFee = pool.priced.urgent.baseFee
|
||||
// Convert the new uint256.Int types to the old big.Int ones used by the legacy pool
|
||||
var (
|
||||
minTipBig *big.Int
|
||||
baseFeeBig *big.Int
|
||||
)
|
||||
if filter.MinTip != nil {
|
||||
minTipBig = filter.MinTip.ToBig()
|
||||
}
|
||||
if filter.BaseFee != nil {
|
||||
baseFeeBig = filter.BaseFee.ToBig()
|
||||
}
|
||||
|
||||
if baseFeeBig == nil {
|
||||
baseFeeBig = pool.priced.urgent.baseFee
|
||||
}
|
||||
|
||||
pending := make(map[common.Address][]*txpool.LazyTransaction, len(pool.pending))
|
||||
@@ -581,9 +594,9 @@ func (pool *LegacyPool) PendingWithBaseFee(enforceTips bool, baseFee *big.Int) m
|
||||
txs := list.Flatten()
|
||||
|
||||
// If the miner requests tip enforcement, cap the lists now
|
||||
if enforceTips && !pool.locals.contains(addr) {
|
||||
if minTipBig != nil && !pool.locals.contains(addr) {
|
||||
for i, tx := range txs {
|
||||
if tx.EffectiveGasTipIntCmp(pool.gasTip.Load(), baseFee) < 0 {
|
||||
if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 {
|
||||
txs = txs[:i]
|
||||
break
|
||||
}
|
||||
@@ -597,8 +610,8 @@ func (pool *LegacyPool) PendingWithBaseFee(enforceTips bool, baseFee *big.Int) m
|
||||
Hash: txs[i].Hash(),
|
||||
Tx: txs[i].WithoutBlobTxSidecar(),
|
||||
Time: txs[i].Time(),
|
||||
GasFeeCap: txs[i].GasFeeCap(),
|
||||
GasTipCap: txs[i].GasTipCap(),
|
||||
GasFeeCap: uint256.MustFromBig(txs[i].GasFeeCap()),
|
||||
GasTipCap: uint256.MustFromBig(txs[i].GasTipCap()),
|
||||
Gas: txs[i].Gas(),
|
||||
BlobGas: txs[i].BlobGas(),
|
||||
}
|
||||
@@ -661,7 +674,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro
|
||||
1<<types.AccessListTxType |
|
||||
1<<types.DynamicFeeTxType,
|
||||
MaxSize: txMaxSize,
|
||||
MinTip: pool.gasTip.Load(),
|
||||
MinTip: pool.gasTip.Load().ToBig(),
|
||||
}
|
||||
if local {
|
||||
opts.MinTip = new(big.Int)
|
||||
@@ -699,7 +712,7 @@ func (pool *LegacyPool) validateTx(tx *types.Transaction, local bool) error {
|
||||
},
|
||||
ExistingExpenditure: func(addr common.Address) *big.Int {
|
||||
if list := pool.pending[addr]; list != nil {
|
||||
return list.totalcost
|
||||
return list.totalcost.ToBig()
|
||||
}
|
||||
return new(big.Int)
|
||||
},
|
||||
|
||||
@@ -36,6 +36,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
func pricedValuedTransaction(nonce uint64, value int64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
|
||||
@@ -59,7 +60,7 @@ func fillPool(t testing.TB, pool *LegacyPool) {
|
||||
nonExecutableTxs := types.Transactions{}
|
||||
for i := 0; i < 384; i++ {
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000))
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(10000000000))
|
||||
// Add executable ones
|
||||
for j := 0; j < int(pool.config.AccountSlots); j++ {
|
||||
executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key))
|
||||
@@ -94,14 +95,14 @@ func TestTransactionFutureAttack(t *testing.T) {
|
||||
config.GlobalQueue = 100
|
||||
config.GlobalSlots = 100
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
fillPool(t, pool)
|
||||
pending, _ := pool.Stats()
|
||||
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||
{
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000))
|
||||
futureTxs := types.Transactions{}
|
||||
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
||||
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key))
|
||||
@@ -128,7 +129,7 @@ func TestTransactionFuture1559(t *testing.T) {
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
@@ -138,7 +139,7 @@ func TestTransactionFuture1559(t *testing.T) {
|
||||
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||
{
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000))
|
||||
futureTxs := types.Transactions{}
|
||||
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
||||
futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key))
|
||||
@@ -161,7 +162,7 @@ func TestTransactionZAttack(t *testing.T) {
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
fillPool(t, pool)
|
||||
@@ -171,7 +172,7 @@ func TestTransactionZAttack(t *testing.T) {
|
||||
var ivpendingNum int
|
||||
pendingtxs, _ := pool.Content()
|
||||
for account, txs := range pendingtxs {
|
||||
cur_balance := new(big.Int).Set(pool.currentState.GetBalance(account))
|
||||
cur_balance := new(big.Int).Set(pool.currentState.GetBalance(account).ToBig())
|
||||
for _, tx := range txs {
|
||||
if cur_balance.Cmp(tx.Value()) <= 0 {
|
||||
ivpendingNum++
|
||||
@@ -192,7 +193,7 @@ func TestTransactionZAttack(t *testing.T) {
|
||||
for j := 0; j < int(pool.config.GlobalQueue); j++ {
|
||||
futureTxs := types.Transactions{}
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000))
|
||||
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key))
|
||||
pool.addRemotesSync(futureTxs)
|
||||
}
|
||||
@@ -200,7 +201,7 @@ func TestTransactionZAttack(t *testing.T) {
|
||||
overDraftTxs := types.Transactions{}
|
||||
{
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000))
|
||||
for j := 0; j < int(pool.config.GlobalSlots); j++ {
|
||||
overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key))
|
||||
}
|
||||
@@ -232,12 +233,12 @@ func BenchmarkFutureAttack(b *testing.B) {
|
||||
config.GlobalQueue = 100
|
||||
config.GlobalSlots = 100
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
fillPool(b, pool)
|
||||
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000))
|
||||
futureTxs := types.Transactions{}
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
|
||||
@@ -51,6 +51,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -203,7 +204,7 @@ func setupPoolWithConfig(config *params.ChainConfig) (*LegacyPool, *ecdsa.Privat
|
||||
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
if err := pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
if err := pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// wait for the pool to initialize
|
||||
@@ -238,9 +239,6 @@ func validatePoolInternals(pool *LegacyPool) error {
|
||||
if nonce := pool.pendingNonces.get(addr); nonce != last+1 {
|
||||
return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1)
|
||||
}
|
||||
if txs.totalcost.Cmp(common.Big0) < 0 {
|
||||
return fmt.Errorf("totalcost went negative: %v", txs.totalcost)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -295,7 +293,7 @@ func (c *testChain) State() (*state.StateDB, error) {
|
||||
c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
// simulate that the new head block included tx0 and tx1
|
||||
c.statedb.SetNonce(c.address, 2)
|
||||
c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether))
|
||||
c.statedb.SetBalance(c.address, new(uint256.Int).SetUint64(params.Ether))
|
||||
*c.trigger = false
|
||||
}
|
||||
return stdb, nil
|
||||
@@ -315,14 +313,14 @@ func TestStateChangeDuringReset(t *testing.T) {
|
||||
)
|
||||
|
||||
// setup pool with 2 transaction in it
|
||||
statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether))
|
||||
statedb.SetBalance(address, new(uint256.Int).SetUint64(params.Ether))
|
||||
blockchain := &testChain{newTestBlockChain(params.TestChainConfig, 1000000000, statedb, new(event.Feed)), address, &trigger}
|
||||
|
||||
tx0 := transaction(0, 100000, key)
|
||||
tx1 := transaction(1, 100000, key)
|
||||
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
nonce := pool.Nonce(address)
|
||||
@@ -349,7 +347,7 @@ func TestStateChangeDuringReset(t *testing.T) {
|
||||
|
||||
func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) {
|
||||
pool.mu.Lock()
|
||||
pool.currentState.AddBalance(addr, amount)
|
||||
pool.currentState.AddBalance(addr, uint256.MustFromBig(amount))
|
||||
pool.mu.Unlock()
|
||||
}
|
||||
|
||||
@@ -388,7 +386,7 @@ func TestInvalidTransactions(t *testing.T) {
|
||||
}
|
||||
|
||||
tx = transaction(1, 100000, key)
|
||||
pool.gasTip.Store(big.NewInt(1000))
|
||||
pool.gasTip.Store(uint256.NewInt(1000))
|
||||
if err, want := pool.addRemote(tx), txpool.ErrUnderpriced; !errors.Is(err, want) {
|
||||
t.Errorf("want %v have %v", want, err)
|
||||
}
|
||||
@@ -510,7 +508,7 @@ func TestChainFork(t *testing.T) {
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
resetState := func() {
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
statedb.AddBalance(addr, big.NewInt(100000000000000))
|
||||
statedb.AddBalance(addr, uint256.NewInt(100000000000000))
|
||||
|
||||
pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
|
||||
<-pool.requestReset(nil, nil)
|
||||
@@ -539,7 +537,7 @@ func TestDoubleNonce(t *testing.T) {
|
||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||
resetState := func() {
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
statedb.AddBalance(addr, big.NewInt(100000000000000))
|
||||
statedb.AddBalance(addr, uint256.NewInt(100000000000000))
|
||||
|
||||
pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
|
||||
<-pool.requestReset(nil, nil)
|
||||
@@ -742,7 +740,7 @@ func TestPostponing(t *testing.T) {
|
||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Create two test accounts to produce different gap profiles with
|
||||
@@ -959,7 +957,7 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) {
|
||||
config.GlobalQueue = config.AccountQueue*3 - 1 // reduce the queue limits to shorten test time (-1 to make it non divisible)
|
||||
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Create a number of test accounts and fund them (last one will be the local)
|
||||
@@ -1052,7 +1050,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) {
|
||||
config.NoLocals = nolocals
|
||||
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Create two test accounts to ensure remotes expire but locals do not
|
||||
@@ -1237,7 +1235,7 @@ func TestPendingGlobalLimiting(t *testing.T) {
|
||||
config.GlobalSlots = config.AccountSlots * 10
|
||||
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Create a number of test accounts and fund them
|
||||
@@ -1341,7 +1339,7 @@ func TestCapClearsFromAll(t *testing.T) {
|
||||
config.GlobalSlots = 8
|
||||
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Create a number of test accounts and fund them
|
||||
@@ -1374,7 +1372,7 @@ func TestPendingMinimumAllowance(t *testing.T) {
|
||||
config.GlobalSlots = 1
|
||||
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Create a number of test accounts and fund them
|
||||
@@ -1420,7 +1418,7 @@ func TestRepricing(t *testing.T) {
|
||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Keep track of transaction events to ensure all executables get announced
|
||||
@@ -1542,7 +1540,7 @@ func TestMinGasPriceEnforced(t *testing.T) {
|
||||
txPoolConfig := DefaultConfig
|
||||
txPoolConfig.NoLocals = true
|
||||
pool := New(txPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(txPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(txPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
key, _ := crypto.GenerateKey()
|
||||
@@ -1713,7 +1711,7 @@ func TestRepricingKeepsLocals(t *testing.T) {
|
||||
blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed))
|
||||
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Create a number of test accounts and fund them
|
||||
@@ -1791,7 +1789,7 @@ func TestUnderpricing(t *testing.T) {
|
||||
config.GlobalQueue = 2
|
||||
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Keep track of transaction events to ensure all executables get announced
|
||||
@@ -1906,7 +1904,7 @@ func TestStableUnderpricing(t *testing.T) {
|
||||
config.GlobalQueue = 0
|
||||
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Keep track of transaction events to ensure all executables get announced
|
||||
@@ -2137,7 +2135,7 @@ func TestDeduplication(t *testing.T) {
|
||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Create a test account to add transactions with
|
||||
@@ -2204,7 +2202,7 @@ func TestReplacement(t *testing.T) {
|
||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Keep track of transaction events to ensure all executables get announced
|
||||
@@ -2415,7 +2413,7 @@ func testJournaling(t *testing.T, nolocals bool) {
|
||||
config.Rejournal = time.Second
|
||||
|
||||
pool := New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
|
||||
// Create two test accounts to ensure remotes expire but locals do not
|
||||
local, _ := crypto.GenerateKey()
|
||||
@@ -2453,7 +2451,7 @@ func testJournaling(t *testing.T, nolocals bool) {
|
||||
blockchain = newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||
|
||||
pool = New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
|
||||
pending, queued = pool.Stats()
|
||||
if queued != 0 {
|
||||
@@ -2480,7 +2478,7 @@ func testJournaling(t *testing.T, nolocals bool) {
|
||||
statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1)
|
||||
blockchain = newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||
pool = New(config, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(config.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(config.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
|
||||
pending, queued = pool.Stats()
|
||||
if pending != 0 {
|
||||
@@ -2511,7 +2509,7 @@ func TestStatusCheck(t *testing.T) {
|
||||
blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed))
|
||||
|
||||
pool := New(testTxPoolConfig, blockchain)
|
||||
pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver())
|
||||
pool.Init(testTxPoolConfig.PriceLimit, blockchain.CurrentBlock(), makeAddressReserver())
|
||||
defer pool.Close()
|
||||
|
||||
// Create the test accounts to check various transaction statuses with
|
||||
@@ -2704,7 +2702,7 @@ func BenchmarkMultiAccountBatchInsert(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
key, _ := crypto.GenerateKey()
|
||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||
pool.currentState.AddBalance(account, big.NewInt(1000000))
|
||||
pool.currentState.AddBalance(account, uint256.NewInt(1000000))
|
||||
tx := transaction(uint64(0), 100000, key)
|
||||
batches[i] = tx
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ import (
|
||||
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/holiman/uint256"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// nonceHeap is a heap.Interface implementation over 64bit unsigned integers for
|
||||
@@ -169,14 +171,14 @@ func (m *sortedMap) Cap(threshold int) types.Transactions {
|
||||
}
|
||||
// Otherwise gather and drop the highest nonce'd transactions
|
||||
var drops types.Transactions
|
||||
|
||||
sort.Sort(*m.index)
|
||||
slices.Sort(*m.index)
|
||||
for size := len(m.items); size > threshold; size-- {
|
||||
drops = append(drops, m.items[(*m.index)[size-1]])
|
||||
delete(m.items, (*m.index)[size-1])
|
||||
}
|
||||
*m.index = (*m.index)[:threshold]
|
||||
heap.Init(m.index)
|
||||
// The sorted m.index slice is still a valid heap, so there is no need to
|
||||
// reheap after deleting tail items.
|
||||
|
||||
// If we had a cache, shift the back
|
||||
m.cacheMu.Lock()
|
||||
@@ -281,19 +283,19 @@ type list struct {
|
||||
strict bool // Whether nonces are strictly continuous or not
|
||||
txs *sortedMap // Heap indexed sorted hash map of the transactions
|
||||
|
||||
costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance)
|
||||
gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit)
|
||||
totalcost *big.Int // Total cost of all transactions in the list
|
||||
costcap *uint256.Int // Price of the highest costing transaction (reset only if exceeds balance)
|
||||
gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit)
|
||||
totalcost *uint256.Int // Total cost of all transactions in the list
|
||||
}
|
||||
|
||||
// newList create a new transaction list for maintaining nonce-indexable fast,
|
||||
// newList creates a new transaction list for maintaining nonce-indexable fast,
|
||||
// gapped, sortable transaction lists.
|
||||
func newList(strict bool) *list {
|
||||
return &list{
|
||||
strict: strict,
|
||||
txs: newSortedMap(),
|
||||
costcap: new(big.Int),
|
||||
totalcost: new(big.Int),
|
||||
costcap: new(uint256.Int),
|
||||
totalcost: new(uint256.Int),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,10 +337,15 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa
|
||||
l.subTotalCost([]*types.Transaction{old})
|
||||
}
|
||||
// Add new tx cost to totalcost
|
||||
l.totalcost.Add(l.totalcost, tx.Cost())
|
||||
cost, overflow := uint256.FromBig(tx.Cost())
|
||||
if overflow {
|
||||
return false, nil
|
||||
}
|
||||
l.totalcost.Add(l.totalcost, cost)
|
||||
|
||||
// Otherwise overwrite the old transaction with the current one
|
||||
l.txs.Put(tx)
|
||||
if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 {
|
||||
if l.costcap.Cmp(cost) < 0 {
|
||||
l.costcap = cost
|
||||
}
|
||||
if gas := tx.Gas(); l.gascap < gas {
|
||||
@@ -365,17 +372,17 @@ func (l *list) Forward(threshold uint64) types.Transactions {
|
||||
// a point in calculating all the costs or if the balance covers all. If the threshold
|
||||
// is lower than the costgas cap, the caps will be reset to a new high after removing
|
||||
// the newly invalidated transactions.
|
||||
func (l *list) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions, types.Transactions) {
|
||||
func (l *list) Filter(costLimit *uint256.Int, gasLimit uint64) (types.Transactions, types.Transactions) {
|
||||
// If all transactions are below the threshold, short circuit
|
||||
if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit {
|
||||
return nil, nil
|
||||
}
|
||||
l.costcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds
|
||||
l.costcap = new(uint256.Int).Set(costLimit) // Lower the caps to the thresholds
|
||||
l.gascap = gasLimit
|
||||
|
||||
// Filter out all the transactions above the account's funds
|
||||
removed := l.txs.Filter(func(tx *types.Transaction) bool {
|
||||
return tx.Gas() > gasLimit || tx.Cost().Cmp(costLimit) > 0
|
||||
return tx.Gas() > gasLimit || tx.Cost().Cmp(costLimit.ToBig()) > 0
|
||||
})
|
||||
|
||||
if len(removed) == 0 {
|
||||
@@ -466,7 +473,10 @@ func (l *list) LastElement() *types.Transaction {
|
||||
// total cost of all transactions.
|
||||
func (l *list) subTotalCost(txs []*types.Transaction) {
|
||||
for _, tx := range txs {
|
||||
l.totalcost.Sub(l.totalcost, tx.Cost())
|
||||
_, underflow := l.totalcost.SubOverflow(l.totalcost, uint256.MustFromBig(tx.Cost()))
|
||||
if underflow {
|
||||
panic("totalcost underflow")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,9 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// Tests that transactions can be added to strict lists and list contents and
|
||||
@@ -61,6 +63,21 @@ func TestStrictListAdd(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestListAddVeryExpensive tests adding txs which exceed 256 bits in cost. It is
|
||||
// expected that the list does not panic.
|
||||
func TestListAddVeryExpensive(t *testing.T) {
|
||||
key, _ := crypto.GenerateKey()
|
||||
list := newList(true)
|
||||
for i := 0; i < 3; i++ {
|
||||
value := big.NewInt(100)
|
||||
gasprice, _ := new(big.Int).SetString("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0)
|
||||
gaslimit := uint64(i)
|
||||
tx, _ := types.SignTx(types.NewTransaction(uint64(i), common.Address{}, value, gaslimit, gasprice, nil), types.HomesteadSigner{}, key)
|
||||
t.Logf("cost: %x bitlen: %d\n", tx.Cost(), tx.Cost().BitLen())
|
||||
list.Add(tx, DefaultConfig.PriceBump)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkListAdd(b *testing.B) {
|
||||
// Generate a list of transactions to insert
|
||||
key, _ := crypto.GenerateKey()
|
||||
@@ -70,7 +87,7 @@ func BenchmarkListAdd(b *testing.B) {
|
||||
txs[i] = transaction(uint64(i), 0, key)
|
||||
}
|
||||
// Insert the transactions in a random order
|
||||
priceLimit := big.NewInt(int64(DefaultConfig.PriceLimit))
|
||||
priceLimit := uint256.NewInt(DefaultConfig.PriceLimit)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
list := newList(true)
|
||||
@@ -80,3 +97,25 @@ func BenchmarkListAdd(b *testing.B) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkListCapOneTx(b *testing.B) {
|
||||
// Generate a list of transactions to insert
|
||||
key, _ := crypto.GenerateKey()
|
||||
|
||||
txs := make(types.Transactions, 32)
|
||||
for i := 0; i < len(txs); i++ {
|
||||
txs[i] = transaction(uint64(i), 0, key)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
list := newList(true)
|
||||
// Insert the transactions in a random order
|
||||
for _, v := range rand.Perm(len(txs)) {
|
||||
list.Add(txs[v], DefaultConfig.PriceBump)
|
||||
}
|
||||
b.StartTimer()
|
||||
list.Cap(list.Len() - 1)
|
||||
b.StopTimer()
|
||||
}
|
||||
}
|
||||
|
||||
+34
-10
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// LazyTransaction contains a small subset of the transaction properties that is
|
||||
@@ -44,9 +45,9 @@ type LazyTransaction struct {
|
||||
Hash common.Hash // Transaction hash to pull up if needed
|
||||
Tx *types.Transaction // Transaction if already resolved
|
||||
|
||||
Time time.Time // Time when the transaction was first seen
|
||||
GasFeeCap *big.Int // Maximum fee per gas the transaction may consume
|
||||
GasTipCap *big.Int // Maximum miner tip per gas the transaction can pay
|
||||
Time time.Time // Time when the transaction was first seen
|
||||
GasFeeCap *uint256.Int // Maximum fee per gas the transaction may consume
|
||||
GasTipCap *uint256.Int // Maximum miner tip per gas the transaction can pay
|
||||
|
||||
Gas uint64 // Amount of gas required by the transaction
|
||||
BlobGas uint64 // Amount of blob gas required by the transaction
|
||||
@@ -54,11 +55,17 @@ type LazyTransaction struct {
|
||||
|
||||
// Resolve retrieves the full transaction belonging to a lazy handle if it is still
|
||||
// maintained by the transaction pool.
|
||||
//
|
||||
// Note, the method will *not* cache the retrieved transaction if the original
|
||||
// pool has not cached it. The idea being, that if the tx was too big to insert
|
||||
// originally, silently saving it will cause more trouble down the line (and
|
||||
// indeed seems to have caused a memory bloat in the original implementation
|
||||
// which did just that).
|
||||
func (ltx *LazyTransaction) Resolve() *types.Transaction {
|
||||
if ltx.Tx == nil {
|
||||
ltx.Tx = ltx.Pool.Get(ltx.Hash)
|
||||
if ltx.Tx != nil {
|
||||
return ltx.Tx
|
||||
}
|
||||
return ltx.Tx
|
||||
return ltx.Pool.Get(ltx.Hash)
|
||||
}
|
||||
|
||||
// LazyResolver is a minimal interface needed for a transaction pool to satisfy
|
||||
@@ -73,13 +80,28 @@ type LazyResolver interface {
|
||||
// may request (and relinquish) exclusive access to certain addresses.
|
||||
type AddressReserver func(addr common.Address, reserve bool) error
|
||||
|
||||
// PendingFilter is a collection of filter rules to allow retrieving a subset
|
||||
// of transactions for announcement or mining.
|
||||
//
|
||||
// Note, the entries here are not arbitrary useful filters, rather each one has
|
||||
// a very specific call site in mind and each one can be evaluated very cheaply
|
||||
// by the pool implementations. Only add new ones that satisfy those constraints.
|
||||
type PendingFilter struct {
|
||||
MinTip *uint256.Int // Minimum miner tip required to include a transaction
|
||||
BaseFee *uint256.Int // Minimum 1559 basefee needed to include a transaction
|
||||
BlobFee *uint256.Int // Minimum 4844 blobfee needed to include a blob transaction
|
||||
|
||||
OnlyPlainTxs bool // Return only plain EVM transactions (peer-join announces, block space filling)
|
||||
OnlyBlobTxs bool // Return only blob transactions (block blob-space filling)
|
||||
}
|
||||
|
||||
// SubPool represents a specialized transaction pool that lives on its own (e.g.
|
||||
// blob pool). Since independent of how many specialized pools we have, they do
|
||||
// need to be updated in lockstep and assemble into one coherent view for block
|
||||
// production, this interface defines the common methods that allow the primary
|
||||
// transaction pool to manage the subpools.
|
||||
type SubPool interface {
|
||||
// Filter is a selector used to decide whether a transaction whould be added
|
||||
// Filter is a selector used to decide whether a transaction would be added
|
||||
// to this particular subpool.
|
||||
Filter(tx *types.Transaction) bool
|
||||
|
||||
@@ -90,7 +112,7 @@ type SubPool interface {
|
||||
// These should not be passed as a constructor argument - nor should the pools
|
||||
// start by themselves - in order to keep multiple subpools in lockstep with
|
||||
// one another.
|
||||
Init(gasTip *big.Int, head *types.Header, reserve AddressReserver) error
|
||||
Init(gasTip uint64, head *types.Header, reserve AddressReserver) error
|
||||
|
||||
// Close terminates any background processing threads and releases any held
|
||||
// resources.
|
||||
@@ -120,8 +142,10 @@ type SubPool interface {
|
||||
|
||||
// Pending retrieves all currently processable transactions, grouped by origin
|
||||
// account and sorted by nonce.
|
||||
Pending(enforceTips bool) map[common.Address][]*LazyTransaction
|
||||
PendingWithBaseFee(enforceTips bool, baseFee *big.Int) map[common.Address][]*LazyTransaction
|
||||
//
|
||||
// The transactions can also be pre-filtered by the dynamic fee components to
|
||||
// reduce allocations and load on downstream subsystems.
|
||||
Pending(filter PendingFilter) map[common.Address][]*LazyTransaction
|
||||
IteratePending(f func(tx *types.Transaction) bool) bool // Returns false if iteration was interrupted.
|
||||
|
||||
// SubscribeTransactions subscribes to new transaction events. The subscriber
|
||||
|
||||
+83
-24
@@ -88,6 +88,9 @@ type TxPool struct {
|
||||
|
||||
subs event.SubscriptionScope // Subscription scope to unsubscribe all on shutdown
|
||||
quit chan chan error // Quit channel to tear down the head updater
|
||||
term chan struct{} // Termination channel to detect a closed pool
|
||||
|
||||
sync chan chan error // Testing / simulator channel to block until internal reset is done
|
||||
|
||||
gasTip atomic.Pointer[big.Int] // Remember last value set so it can be retrieved
|
||||
reorgFeed event.Feed
|
||||
@@ -95,7 +98,7 @@ type TxPool struct {
|
||||
|
||||
// New creates a new transaction pool to gather, sort and filter inbound
|
||||
// transactions from the network.
|
||||
func New(gasTip *big.Int, chain BlockChain, subpools []SubPool) (*TxPool, error) {
|
||||
func New(gasTip uint64, chain BlockChain, subpools []SubPool) (*TxPool, error) {
|
||||
// Retrieve the current head so that all subpools and this main coordinator
|
||||
// pool will have the same starting state, even if the chain moves forward
|
||||
// during initialization.
|
||||
@@ -105,7 +108,11 @@ func New(gasTip *big.Int, chain BlockChain, subpools []SubPool) (*TxPool, error)
|
||||
subpools: subpools,
|
||||
reservations: make(map[common.Address]SubPool),
|
||||
quit: make(chan chan error),
|
||||
term: make(chan struct{}),
|
||||
sync: make(chan chan error),
|
||||
}
|
||||
pool.gasTip.Store(new(big.Int).SetUint64(gasTip))
|
||||
|
||||
for i, subpool := range subpools {
|
||||
if err := subpool.Init(gasTip, head, pool.reserver(i, subpool)); err != nil {
|
||||
for j := i - 1; j >= 0; j-- {
|
||||
@@ -114,7 +121,6 @@ func New(gasTip *big.Int, chain BlockChain, subpools []SubPool) (*TxPool, error)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
pool.gasTip.Store(gasTip)
|
||||
|
||||
// Subscribe to chain head events to trigger subpool resets
|
||||
var (
|
||||
@@ -146,7 +152,7 @@ func (p *TxPool) reserver(id int, subpool SubPool) AddressReserver {
|
||||
log.Error("pool attempted to reserve already-owned address", "address", addr)
|
||||
return nil // Ignore fault to give the pool a chance to recover while the bug gets fixed
|
||||
}
|
||||
return errors.New("address already reserved")
|
||||
return ErrAlreadyReserved
|
||||
}
|
||||
p.reservations[addr] = subpool
|
||||
if metrics.Enabled {
|
||||
@@ -205,6 +211,9 @@ func (p *TxPool) Close() error {
|
||||
// outside blockchain events as well as for various reporting and transaction
|
||||
// eviction events.
|
||||
func (p *TxPool) loop(head *types.Header, newHeadCh <-chan core.ChainHeadEvent) {
|
||||
// Close the termination marker when the pool stops
|
||||
defer close(p.term)
|
||||
|
||||
// Track the previous and current head to feed to an idle reset
|
||||
var (
|
||||
oldHead = head
|
||||
@@ -214,13 +223,23 @@ func (p *TxPool) loop(head *types.Header, newHeadCh <-chan core.ChainHeadEvent)
|
||||
var (
|
||||
resetBusy = make(chan struct{}, 1) // Allow 1 reset to run concurrently
|
||||
resetDone = make(chan *types.Header)
|
||||
|
||||
resetForced bool // Whether a forced reset was requested, only used in simulator mode
|
||||
resetWaiter chan error // Channel waiting on a forced reset, only used in simulator mode
|
||||
)
|
||||
// Notify the live reset waiter to not block if the txpool is closed.
|
||||
defer func() {
|
||||
if resetWaiter != nil {
|
||||
resetWaiter <- errors.New("pool already terminated")
|
||||
resetWaiter = nil
|
||||
}
|
||||
}()
|
||||
var errc chan error
|
||||
for errc == nil {
|
||||
// Something interesting might have happened, run a reset if there is
|
||||
// one needed but none is running. The resetter will run on its own
|
||||
// goroutine to allow chain head events to be consumed contiguously.
|
||||
if newHead != oldHead {
|
||||
if newHead != oldHead || resetForced {
|
||||
// Try to inject a busy marker and start a reset if successful
|
||||
select {
|
||||
case resetBusy <- struct{}{}:
|
||||
@@ -233,8 +252,17 @@ func (p *TxPool) loop(head *types.Header, newHeadCh <-chan core.ChainHeadEvent)
|
||||
resetDone <- newHead
|
||||
}(oldHead, newHead)
|
||||
|
||||
// If the reset operation was explicitly requested, consider it
|
||||
// being fulfilled and drop the request marker. If it was not,
|
||||
// this is a noop.
|
||||
resetForced = false
|
||||
|
||||
default:
|
||||
// Reset already running, wait until it finishes
|
||||
// Reset already running, wait until it finishes.
|
||||
//
|
||||
// Note, this will not drop any forced reset request. If a forced
|
||||
// reset was requested, but we were busy, then when the currently
|
||||
// running reset finishes, a new one will be spun up.
|
||||
}
|
||||
}
|
||||
// Wait for the next chain head event or a previous reset finish
|
||||
@@ -248,8 +276,26 @@ func (p *TxPool) loop(head *types.Header, newHeadCh <-chan core.ChainHeadEvent)
|
||||
oldHead = head
|
||||
<-resetBusy
|
||||
|
||||
// If someone is waiting for a reset to finish, notify them, unless
|
||||
// the forced op is still pending. In that case, wait another round
|
||||
// of resets.
|
||||
if resetWaiter != nil && !resetForced {
|
||||
resetWaiter <- nil
|
||||
resetWaiter = nil
|
||||
}
|
||||
|
||||
case errc = <-p.quit:
|
||||
// Termination requested, break out on the next loop round
|
||||
|
||||
case syncc := <-p.sync:
|
||||
// Transaction pool is running inside a simulator, and we are about
|
||||
// to create a new block. Request a forced sync operation to ensure
|
||||
// that any running reset operation finishes to make block imports
|
||||
// deterministic. On top of that, run a new reset operation to make
|
||||
// transaction insertions deterministic instead of being stuck in a
|
||||
// queue waiting for a reset.
|
||||
resetForced = true
|
||||
resetWaiter = syncc
|
||||
}
|
||||
}
|
||||
// Notify the closer of termination (no error possible for now)
|
||||
@@ -365,19 +411,12 @@ func (p *TxPool) AddRemotesSync(txs []*types.Transaction) []error {
|
||||
// account and sorted by nonce. The returned transaction set is a copy and can be
|
||||
// freely modified by calling code.
|
||||
//
|
||||
// The enforceTips parameter can be used to do an extra filtering on the pending
|
||||
// transactions and only return those whose **effective** tip is large enough in
|
||||
// the next pending execution environment.
|
||||
// account and sorted by nonce.
|
||||
func (p *TxPool) Pending(enforceTips bool) map[common.Address][]*LazyTransaction {
|
||||
return p.PendingWithBaseFee(enforceTips, nil)
|
||||
}
|
||||
|
||||
// If baseFee is nil, then pool.priced.urgent.baseFee is used.
|
||||
func (p *TxPool) PendingWithBaseFee(enforceTips bool, baseFee *big.Int) map[common.Address][]*LazyTransaction {
|
||||
// The transactions can also be pre-filtered by the dynamic fee components to
|
||||
// reduce allocations and load on downstream subsystems.
|
||||
func (p *TxPool) Pending(filter PendingFilter) map[common.Address][]*LazyTransaction {
|
||||
txs := make(map[common.Address][]*LazyTransaction)
|
||||
for _, subpool := range p.subpools {
|
||||
for addr, set := range subpool.PendingWithBaseFee(enforceTips, baseFee) {
|
||||
for addr, set := range subpool.Pending(filter) {
|
||||
txs[addr] = set
|
||||
}
|
||||
}
|
||||
@@ -386,13 +425,12 @@ func (p *TxPool) PendingWithBaseFee(enforceTips bool, baseFee *big.Int) map[comm
|
||||
|
||||
// PendingSize returns the number of pending txs in the tx pool.
|
||||
//
|
||||
// The enforceTips parameter can be used to do an extra filtering on the pending
|
||||
// transactions and only return those whose **effective** tip is large enough in
|
||||
// the next pending execution environment.
|
||||
func (p *TxPool) PendingSize(enforceTips bool) int {
|
||||
// The filter parameter can be used to do an extra filtering on the pending
|
||||
// transactions.
|
||||
func (p *TxPool) PendingSize(filter PendingFilter) int {
|
||||
count := 0
|
||||
for _, subpool := range p.subpools {
|
||||
for _, txs := range subpool.Pending(enforceTips) {
|
||||
for _, txs := range subpool.Pending(filter) {
|
||||
count += len(txs)
|
||||
}
|
||||
}
|
||||
@@ -412,9 +450,13 @@ func (p *TxPool) IteratePending(f func(tx *types.Transaction) bool) {
|
||||
// SubscribeTransactions registers a subscription for new transaction events,
|
||||
// supporting feeding only newly seen or also resurrected transactions.
|
||||
func (p *TxPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs bool) event.Subscription {
|
||||
subs := make([]event.Subscription, len(p.subpools))
|
||||
for i, subpool := range p.subpools {
|
||||
subs[i] = subpool.SubscribeTransactions(ch, reorgs)
|
||||
subs := make([]event.Subscription, 0, len(p.subpools))
|
||||
for _, subpool := range p.subpools {
|
||||
subpool := subpool.SubscribeTransactions(ch, reorgs)
|
||||
if subpool == nil {
|
||||
continue
|
||||
}
|
||||
subs = append(subs, subpool)
|
||||
}
|
||||
return p.subs.Track(event.JoinSubscriptions(subs...))
|
||||
}
|
||||
@@ -512,3 +554,20 @@ func (p *TxPool) Status(hash common.Hash) TxStatus {
|
||||
}
|
||||
return TxStatusUnknown
|
||||
}
|
||||
|
||||
// Sync is a helper method for unit tests or simulator runs where the chain events
|
||||
// are arriving in quick succession, without any time in between them to run the
|
||||
// internal background reset operations. This method will run an explicit reset
|
||||
// operation to ensure the pool stabilises, thus avoiding flakey behavior.
|
||||
//
|
||||
// Note, do not use this in production / live code. In live code, the pool is
|
||||
// meant to reset on a separate thread to avoid DoS vectors.
|
||||
func (p *TxPool) Sync() error {
|
||||
sync := make(chan error)
|
||||
select {
|
||||
case p.sync <- sync:
|
||||
return <-sync
|
||||
case <-p.term:
|
||||
return errors.New("pool already terminated")
|
||||
}
|
||||
}
|
||||
|
||||
+19
-17
@@ -42,6 +42,12 @@ import (
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
var (
|
||||
// blobTxMinBlobGasPrice is the big.Int version of the configured protocol
|
||||
// parameter to avoid constucting a new big integer for every transaction.
|
||||
blobTxMinBlobGasPrice = big.NewInt(params.BlobTxMinBlobGasprice)
|
||||
)
|
||||
|
||||
// ValidationOptions define certain differences between transaction validation
|
||||
// across the different pools without having to duplicate those checks.
|
||||
type ValidationOptions struct {
|
||||
@@ -119,15 +125,17 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
|
||||
return err
|
||||
}
|
||||
if txGas := tx.Gas(); txGas < intrGas {
|
||||
return fmt.Errorf("%w: address %v tx gas (%v) < intrinsic gas (%v)", core.ErrIntrinsicGas, from.Hex(), tx.Gas(), intrGas)
|
||||
return fmt.Errorf("%w: address %v tx gas (%v), minimum needed %v", core.ErrIntrinsicGas, from.Hex(), txGas, intrGas)
|
||||
}
|
||||
// Ensure the gasprice is high enough to cover the requirement of the calling
|
||||
// pool and/or block producer
|
||||
// Ensure the gasprice is high enough to cover the requirement of the calling pool
|
||||
if tx.GasTipCapIntCmp(opts.MinTip) < 0 {
|
||||
return fmt.Errorf("%w: tip needed %v, tip permitted %v", ErrUnderpriced, opts.MinTip, tx.GasTipCap())
|
||||
return fmt.Errorf("%w: gas tip cap %v, minimum needed %v", ErrUnderpriced, tx.GasTipCap(), opts.MinTip)
|
||||
}
|
||||
// Ensure blob transactions have valid commitments
|
||||
if tx.Type() == types.BlobTxType {
|
||||
// Ensure the blob fee cap satisfies the minimum blob gas price
|
||||
if tx.BlobGasFeeCapIntCmp(blobTxMinBlobGasPrice) < 0 {
|
||||
return fmt.Errorf("%w: blob fee cap %v, minimum needed %v", ErrUnderpriced, tx.BlobGasFeeCap(), blobTxMinBlobGasPrice)
|
||||
}
|
||||
sidecar := tx.BlobTxSidecar()
|
||||
if sidecar == nil {
|
||||
return fmt.Errorf("missing sidecar in blob transaction")
|
||||
@@ -141,6 +149,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
|
||||
if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob {
|
||||
return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob)
|
||||
}
|
||||
// Ensure commitments, proofs and hashes are valid
|
||||
if err := validateBlobSidecar(hashes, sidecar); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -161,17 +170,10 @@ func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) err
|
||||
// Blob quantities match up, validate that the provers match with the
|
||||
// transaction hash before getting to the cryptography
|
||||
hasher := sha256.New()
|
||||
for i, want := range hashes {
|
||||
hasher.Write(sidecar.Commitments[i][:])
|
||||
hash := hasher.Sum(nil)
|
||||
hasher.Reset()
|
||||
|
||||
var vhash common.Hash
|
||||
vhash[0] = params.BlobTxHashVersion
|
||||
copy(vhash[1:], hash[1:])
|
||||
|
||||
if vhash != want {
|
||||
return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, vhash, want)
|
||||
for i, vhash := range hashes {
|
||||
computed := kzg4844.CalcBlobHashV1(hasher, &sidecar.Commitments[i])
|
||||
if vhash != computed {
|
||||
return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, computed, vhash)
|
||||
}
|
||||
}
|
||||
// Blob commitments match with the hashes in the transaction, verify the
|
||||
@@ -243,7 +245,7 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op
|
||||
}
|
||||
// Ensure the transactor has enough funds to cover the transaction costs
|
||||
var (
|
||||
balance = opts.State.GetBalance(from)
|
||||
balance = opts.State.GetBalance(from).ToBig()
|
||||
cost = tx.Cost()
|
||||
)
|
||||
if balance.Cmp(cost) < 0 {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type Account -field-override accountMarshaling -out gen_account.go
|
||||
|
||||
// Account represents an Ethereum account and its attached data.
|
||||
// This type is used to specify accounts in the genesis block state, and
|
||||
// is also useful for JSON encoding/decoding of accounts.
|
||||
type Account struct {
|
||||
Code []byte `json:"code,omitempty"`
|
||||
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
||||
Balance *big.Int `json:"balance" gencodec:"required"`
|
||||
Nonce uint64 `json:"nonce,omitempty"`
|
||||
|
||||
// used in tests
|
||||
PrivateKey []byte `json:"secretKey,omitempty"`
|
||||
}
|
||||
|
||||
type accountMarshaling struct {
|
||||
Code hexutil.Bytes
|
||||
Balance *math.HexOrDecimal256
|
||||
Nonce math.HexOrDecimal64
|
||||
Storage map[storageJSON]storageJSON
|
||||
PrivateKey hexutil.Bytes
|
||||
}
|
||||
|
||||
// storageJSON represents a 256 bit byte array, but allows less than 256 bits when
|
||||
// unmarshaling from hex.
|
||||
type storageJSON common.Hash
|
||||
|
||||
func (h *storageJSON) UnmarshalText(text []byte) error {
|
||||
text = bytes.TrimPrefix(text, []byte("0x"))
|
||||
if len(text) > 64 {
|
||||
return fmt.Errorf("too many hex characters in storage key/value %q", text)
|
||||
}
|
||||
offset := len(h) - len(text)/2 // pad on the left
|
||||
if _, err := hex.Decode(h[offset:], text); err != nil {
|
||||
return fmt.Errorf("invalid hex storage key/value %q", text)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h storageJSON) MarshalText() ([]byte, error) {
|
||||
return hexutil.Bytes(h[:]).MarshalText()
|
||||
}
|
||||
|
||||
// GenesisAlloc specifies the initial state of a genesis block.
|
||||
type GenesisAlloc map[common.Address]Account
|
||||
|
||||
func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error {
|
||||
m := make(map[common.UnprefixedAddress]Account)
|
||||
if err := json.Unmarshal(data, &m); err != nil {
|
||||
return err
|
||||
}
|
||||
*ga = make(GenesisAlloc)
|
||||
for addr, a := range m {
|
||||
(*ga)[common.Address(addr)] = a
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||
|
||||
package core
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -12,62 +12,62 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
)
|
||||
|
||||
var _ = (*genesisAccountMarshaling)(nil)
|
||||
var _ = (*accountMarshaling)(nil)
|
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (g GenesisAccount) MarshalJSON() ([]byte, error) {
|
||||
type GenesisAccount struct {
|
||||
func (a Account) MarshalJSON() ([]byte, error) {
|
||||
type Account struct {
|
||||
Code hexutil.Bytes `json:"code,omitempty"`
|
||||
Storage map[storageJSON]storageJSON `json:"storage,omitempty"`
|
||||
Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"`
|
||||
Nonce math.HexOrDecimal64 `json:"nonce,omitempty"`
|
||||
PrivateKey hexutil.Bytes `json:"secretKey,omitempty"`
|
||||
}
|
||||
var enc GenesisAccount
|
||||
enc.Code = g.Code
|
||||
if g.Storage != nil {
|
||||
enc.Storage = make(map[storageJSON]storageJSON, len(g.Storage))
|
||||
for k, v := range g.Storage {
|
||||
var enc Account
|
||||
enc.Code = a.Code
|
||||
if a.Storage != nil {
|
||||
enc.Storage = make(map[storageJSON]storageJSON, len(a.Storage))
|
||||
for k, v := range a.Storage {
|
||||
enc.Storage[storageJSON(k)] = storageJSON(v)
|
||||
}
|
||||
}
|
||||
enc.Balance = (*math.HexOrDecimal256)(g.Balance)
|
||||
enc.Nonce = math.HexOrDecimal64(g.Nonce)
|
||||
enc.PrivateKey = g.PrivateKey
|
||||
enc.Balance = (*math.HexOrDecimal256)(a.Balance)
|
||||
enc.Nonce = math.HexOrDecimal64(a.Nonce)
|
||||
enc.PrivateKey = a.PrivateKey
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (g *GenesisAccount) UnmarshalJSON(input []byte) error {
|
||||
type GenesisAccount struct {
|
||||
func (a *Account) UnmarshalJSON(input []byte) error {
|
||||
type Account struct {
|
||||
Code *hexutil.Bytes `json:"code,omitempty"`
|
||||
Storage map[storageJSON]storageJSON `json:"storage,omitempty"`
|
||||
Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"`
|
||||
Nonce *math.HexOrDecimal64 `json:"nonce,omitempty"`
|
||||
PrivateKey *hexutil.Bytes `json:"secretKey,omitempty"`
|
||||
}
|
||||
var dec GenesisAccount
|
||||
var dec Account
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
if dec.Code != nil {
|
||||
g.Code = *dec.Code
|
||||
a.Code = *dec.Code
|
||||
}
|
||||
if dec.Storage != nil {
|
||||
g.Storage = make(map[common.Hash]common.Hash, len(dec.Storage))
|
||||
a.Storage = make(map[common.Hash]common.Hash, len(dec.Storage))
|
||||
for k, v := range dec.Storage {
|
||||
g.Storage[common.Hash(k)] = common.Hash(v)
|
||||
a.Storage[common.Hash(k)] = common.Hash(v)
|
||||
}
|
||||
}
|
||||
if dec.Balance == nil {
|
||||
return errors.New("missing required field 'balance' for GenesisAccount")
|
||||
return errors.New("missing required field 'balance' for Account")
|
||||
}
|
||||
g.Balance = (*big.Int)(dec.Balance)
|
||||
a.Balance = (*big.Int)(dec.Balance)
|
||||
if dec.Nonce != nil {
|
||||
g.Nonce = uint64(*dec.Nonce)
|
||||
a.Nonce = uint64(*dec.Nonce)
|
||||
}
|
||||
if dec.PrivateKey != nil {
|
||||
g.PrivateKey = *dec.PrivateKey
|
||||
a.PrivateKey = *dec.PrivateKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -15,10 +15,7 @@ func (obj *StateAccount) EncodeRLP(_w io.Writer) error {
|
||||
if obj.Balance == nil {
|
||||
w.Write(rlp.EmptyString)
|
||||
} else {
|
||||
if obj.Balance.Sign() == -1 {
|
||||
return rlp.ErrNegativeBigInt
|
||||
}
|
||||
w.WriteBigInt(obj.Balance)
|
||||
w.WriteUint256(obj.Balance)
|
||||
}
|
||||
w.WriteBytes(obj.Root[:])
|
||||
w.WriteBytes(obj.CodeHash)
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/rawdb"
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/trie"
|
||||
"github.com/ava-labs/subnet-evm/triedb"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
@@ -49,7 +50,7 @@ func TestDeriveSha(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for len(txs) < 1000 {
|
||||
exp := types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
|
||||
exp := types.DeriveSha(txs, trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
|
||||
got := types.DeriveSha(txs, trie.NewStackTrie(nil))
|
||||
if !bytes.Equal(got[:], exp[:]) {
|
||||
t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp)
|
||||
@@ -96,7 +97,7 @@ func BenchmarkDeriveSha200(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
exp = types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
|
||||
exp = types.DeriveSha(txs, trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -117,7 +118,7 @@ func TestFuzzDeriveSha(t *testing.T) {
|
||||
rndSeed := mrand.Int()
|
||||
for i := 0; i < 10; i++ {
|
||||
seed := rndSeed + i
|
||||
exp := types.DeriveSha(newDummy(i), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
|
||||
exp := types.DeriveSha(newDummy(i), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
|
||||
got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil))
|
||||
if !bytes.Equal(got[:], exp[:]) {
|
||||
printList(newDummy(seed))
|
||||
@@ -145,7 +146,7 @@ func TestDerivableList(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for i, tc := range tcs[1:] {
|
||||
exp := types.DeriveSha(flatList(tc), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
|
||||
exp := types.DeriveSha(flatList(tc), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
|
||||
got := types.DeriveSha(flatList(tc), trie.NewStackTrie(nil))
|
||||
if !bytes.Equal(got[:], exp[:]) {
|
||||
t.Fatalf("case %d: got %x exp %x", i, got, exp)
|
||||
|
||||
@@ -28,10 +28,10 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/ethereum/go-ethereum/rlp/rlpgen -type StateAccount -out gen_account_rlp.go
|
||||
@@ -40,7 +40,7 @@ import (
|
||||
// These objects are stored in the main account trie.
|
||||
type StateAccount struct {
|
||||
Nonce uint64
|
||||
Balance *big.Int
|
||||
Balance *uint256.Int
|
||||
Root common.Hash // merkle root of the storage trie
|
||||
CodeHash []byte
|
||||
}
|
||||
@@ -48,7 +48,7 @@ type StateAccount struct {
|
||||
// NewEmptyStateAccount constructs an empty state account.
|
||||
func NewEmptyStateAccount() *StateAccount {
|
||||
return &StateAccount{
|
||||
Balance: new(big.Int),
|
||||
Balance: new(uint256.Int),
|
||||
Root: EmptyRootHash,
|
||||
CodeHash: EmptyCodeHash.Bytes(),
|
||||
}
|
||||
@@ -56,9 +56,9 @@ func NewEmptyStateAccount() *StateAccount {
|
||||
|
||||
// Copy returns a deep-copied state account object.
|
||||
func (acct *StateAccount) Copy() *StateAccount {
|
||||
var balance *big.Int
|
||||
var balance *uint256.Int
|
||||
if acct.Balance != nil {
|
||||
balance = new(big.Int).Set(acct.Balance)
|
||||
balance = new(uint256.Int).Set(acct.Balance)
|
||||
}
|
||||
return &StateAccount{
|
||||
Nonce: acct.Nonce,
|
||||
@@ -73,7 +73,7 @@ func (acct *StateAccount) Copy() *StateAccount {
|
||||
// or slim format which replaces the empty root and code hash as nil byte slice.
|
||||
type SlimAccount struct {
|
||||
Nonce uint64
|
||||
Balance *big.Int
|
||||
Balance *uint256.Int
|
||||
Root []byte // Nil if root equals to types.EmptyRootHash
|
||||
CodeHash []byte // Nil if hash equals to types.EmptyCodeHash
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ package types
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
@@ -330,6 +331,7 @@ func (tx *Transaction) Cost() *big.Int {
|
||||
|
||||
// RawSignatureValues returns the V, R, S signature values of the transaction.
|
||||
// The return values should not be modified by the caller.
|
||||
// The return values may be nil or zero, if the transaction is unsigned.
|
||||
func (tx *Transaction) RawSignatureValues() (v, r, s *big.Int) {
|
||||
return tx.inner.rawSignatureValues()
|
||||
}
|
||||
@@ -518,6 +520,9 @@ func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, e
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r == nil || s == nil || v == nil {
|
||||
return nil, fmt.Errorf("%w: r: %s, s: %s, v: %s", ErrInvalidSig, r, s, v)
|
||||
}
|
||||
cpy := tx.inner.copy()
|
||||
cpy.setSignatureValues(signer.ChainID(), v, r, s)
|
||||
return &Transaction{inner: cpy, time: tx.time}, nil
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
@@ -57,6 +58,11 @@ type txJSON struct {
|
||||
S *hexutil.Big `json:"s"`
|
||||
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
|
||||
|
||||
// Blob transaction sidecar encoding:
|
||||
Blobs []kzg4844.Blob `json:"blobs,omitempty"`
|
||||
Commitments []kzg4844.Commitment `json:"commitments,omitempty"`
|
||||
Proofs []kzg4844.Proof `json:"proofs,omitempty"`
|
||||
|
||||
// Only used for encoding:
|
||||
Hash common.Hash `json:"hash"`
|
||||
}
|
||||
@@ -152,6 +158,11 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
||||
enc.S = (*hexutil.Big)(itx.S.ToBig())
|
||||
yparity := itx.V.Uint64()
|
||||
enc.YParity = (*hexutil.Uint64)(&yparity)
|
||||
if sidecar := itx.Sidecar; sidecar != nil {
|
||||
enc.Blobs = itx.Sidecar.Blobs
|
||||
enc.Commitments = itx.Sidecar.Commitments
|
||||
enc.Proofs = itx.Sidecar.Proofs
|
||||
}
|
||||
}
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
@@ -28,9 +28,11 @@ package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -51,7 +53,7 @@ func TestEIP155Signing(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if from != addr {
|
||||
t.Errorf("exected from and address to be equal. Got %x want %x", from, addr)
|
||||
t.Errorf("expected from and address to be equal. Got %x want %x", from, addr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,3 +151,53 @@ func TestChainId(t *testing.T) {
|
||||
t.Error("expected no error")
|
||||
}
|
||||
}
|
||||
|
||||
type nilSigner struct {
|
||||
v, r, s *big.Int
|
||||
Signer
|
||||
}
|
||||
|
||||
func (ns *nilSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
|
||||
return ns.v, ns.r, ns.s, nil
|
||||
}
|
||||
|
||||
// TestNilSigner ensures a faulty Signer implementation does not result in nil signature values or panics.
|
||||
func TestNilSigner(t *testing.T) {
|
||||
key, _ := crypto.GenerateKey()
|
||||
innerSigner := LatestSignerForChainID(big.NewInt(1))
|
||||
for i, signer := range []Signer{
|
||||
&nilSigner{v: nil, r: nil, s: nil, Signer: innerSigner},
|
||||
&nilSigner{v: big.NewInt(1), r: big.NewInt(1), s: nil, Signer: innerSigner},
|
||||
&nilSigner{v: big.NewInt(1), r: nil, s: big.NewInt(1), Signer: innerSigner},
|
||||
&nilSigner{v: nil, r: big.NewInt(1), s: big.NewInt(1), Signer: innerSigner},
|
||||
} {
|
||||
t.Run(fmt.Sprintf("signer_%d", i), func(t *testing.T) {
|
||||
t.Run("legacy", func(t *testing.T) {
|
||||
legacyTx := createTestLegacyTxInner()
|
||||
_, err := SignNewTx(key, signer, legacyTx)
|
||||
if !errors.Is(err, ErrInvalidSig) {
|
||||
t.Fatal("expected signature values error, no nil result or panic")
|
||||
}
|
||||
})
|
||||
// test Blob tx specifically, since the signature value types changed
|
||||
t.Run("blobtx", func(t *testing.T) {
|
||||
blobtx := createEmptyBlobTxInner(false)
|
||||
_, err := SignNewTx(key, signer, blobtx)
|
||||
if !errors.Is(err, ErrInvalidSig) {
|
||||
t.Fatal("expected signature values error, no nil result or panic")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func createTestLegacyTxInner() *LegacyTx {
|
||||
return &LegacyTx{
|
||||
Nonce: uint64(0),
|
||||
To: nil,
|
||||
Value: big.NewInt(0),
|
||||
Gas: params.TxGas,
|
||||
GasPrice: big.NewInt(params.GWei),
|
||||
Data: nil,
|
||||
}
|
||||
}
|
||||
|
||||
+3
-11
@@ -43,7 +43,7 @@ type BlobTx struct {
|
||||
BlobHashes []common.Hash
|
||||
|
||||
// A blob transaction can optionally contain blobs. This field must be set when BlobTx
|
||||
// is used to create a transaction for sigining.
|
||||
// is used to create a transaction for signing.
|
||||
Sidecar *BlobTxSidecar `rlp:"-"`
|
||||
|
||||
// Signature values
|
||||
@@ -61,9 +61,10 @@ type BlobTxSidecar struct {
|
||||
|
||||
// BlobHashes computes the blob hashes of the given blobs.
|
||||
func (sc *BlobTxSidecar) BlobHashes() []common.Hash {
|
||||
hasher := sha256.New()
|
||||
h := make([]common.Hash, len(sc.Commitments))
|
||||
for i := range sc.Blobs {
|
||||
h[i] = blobHash(&sc.Commitments[i])
|
||||
h[i] = kzg4844.CalcBlobHashV1(hasher, &sc.Commitments[i])
|
||||
}
|
||||
return h
|
||||
}
|
||||
@@ -235,12 +236,3 @@ func (tx *BlobTx) decode(input []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func blobHash(commit *kzg4844.Commitment) common.Hash {
|
||||
hasher := sha256.New()
|
||||
hasher.Write(commit[:])
|
||||
var vhash common.Hash
|
||||
hasher.Sum(vhash[:0])
|
||||
vhash[0] = params.BlobTxHashVersion
|
||||
return vhash
|
||||
}
|
||||
|
||||
@@ -65,6 +65,12 @@ var (
|
||||
)
|
||||
|
||||
func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction {
|
||||
blobtx := createEmptyBlobTxInner(withSidecar)
|
||||
signer := NewCancunSigner(blobtx.ChainID.ToBig())
|
||||
return MustSignNewTx(key, signer, blobtx)
|
||||
}
|
||||
|
||||
func createEmptyBlobTxInner(withSidecar bool) *BlobTx {
|
||||
sidecar := &BlobTxSidecar{
|
||||
Blobs: []kzg4844.Blob{emptyBlob},
|
||||
Commitments: []kzg4844.Commitment{emptyBlobCommit},
|
||||
@@ -85,6 +91,5 @@ func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction {
|
||||
if withSidecar {
|
||||
blobtx.Sidecar = sidecar
|
||||
}
|
||||
signer := NewCancunSigner(blobtx.ChainID.ToBig())
|
||||
return MustSignNewTx(key, signer, blobtx)
|
||||
return blobtx
|
||||
}
|
||||
|
||||
+3
-5
@@ -27,8 +27,6 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
@@ -69,11 +67,11 @@ type Contract struct {
|
||||
Input []byte
|
||||
|
||||
Gas uint64
|
||||
value *big.Int
|
||||
value *uint256.Int
|
||||
}
|
||||
|
||||
// NewContract returns a new contract environment for the execution of EVM.
|
||||
func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract {
|
||||
func NewContract(caller ContractRef, object ContractRef, value *uint256.Int, gas uint64) *Contract {
|
||||
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object}
|
||||
|
||||
if parent, ok := caller.(*Contract); ok {
|
||||
@@ -183,7 +181,7 @@ func (c *Contract) Address() common.Address {
|
||||
}
|
||||
|
||||
// Value returns the contract's value (sent to it from it's caller)
|
||||
func (c *Contract) Value() *big.Int {
|
||||
func (c *Contract) Value() *uint256.Int {
|
||||
return c.value
|
||||
}
|
||||
|
||||
|
||||
@@ -306,7 +306,6 @@ type bigModExp struct {
|
||||
}
|
||||
|
||||
var (
|
||||
big0 = big.NewInt(0)
|
||||
big1 = big.NewInt(1)
|
||||
big3 = big.NewInt(3)
|
||||
big4 = big.NewInt(4)
|
||||
|
||||
@@ -233,7 +233,7 @@ func BenchmarkPrecompiledRipeMD(bench *testing.B) {
|
||||
benchmarkPrecompiled("03", t, bench)
|
||||
}
|
||||
|
||||
// Benchmarks the sample inputs from the identiy precompile.
|
||||
// Benchmarks the sample inputs from the identity precompile.
|
||||
func BenchmarkPrecompiledIdentity(bench *testing.B) {
|
||||
t := precompiledTest{
|
||||
Input: "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02",
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ func enable1884(jt *JumpTable) {
|
||||
}
|
||||
|
||||
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||
balance, _ := uint256.FromBig(interpreter.evm.StateDB.GetBalance(scope.Contract.Address()))
|
||||
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
|
||||
scope.Stack.push(balance)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
+19
-22
@@ -63,9 +63,9 @@ func IsProhibited(addr common.Address) bool {
|
||||
|
||||
type (
|
||||
// CanTransferFunc is the signature of a transfer guard function
|
||||
CanTransferFunc func(StateDB, common.Address, *big.Int) bool
|
||||
CanTransferFunc func(StateDB, common.Address, *uint256.Int) bool
|
||||
// TransferFunc is the signature of a transfer function
|
||||
TransferFunc func(StateDB, common.Address, common.Address, *big.Int)
|
||||
TransferFunc func(StateDB, common.Address, common.Address, *uint256.Int)
|
||||
// GetHashFunc returns the n'th block hash in the blockchain
|
||||
// and is used by the BLOCKHASH EVM op code.
|
||||
GetHashFunc func(uint64) common.Hash
|
||||
@@ -254,16 +254,13 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
|
||||
// parameters. It also handles any necessary value transfer required and takes
|
||||
// the necessary steps to create accounts and reverses the state in case of an
|
||||
// execution error or failed value transfer.
|
||||
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
|
||||
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) {
|
||||
// Fail if we're trying to execute above the call depth limit
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, vmerrs.ErrDepth
|
||||
}
|
||||
// Fail if we're trying to transfer more than the available balance
|
||||
// Note: it is not possible for a negative value to be passed in here due to the fact
|
||||
// that [value] will be popped from the stack and decoded to a *big.Int, which will
|
||||
// always yield a positive result.
|
||||
if value.Sign() != 0 && !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||
if !value.IsZero() && !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||
return nil, gas, vmerrs.ErrInsufficientBalance
|
||||
}
|
||||
snapshot := evm.StateDB.Snapshot()
|
||||
@@ -271,14 +268,14 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||
debug := evm.Config.Tracer != nil
|
||||
|
||||
if !evm.StateDB.Exist(addr) {
|
||||
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
|
||||
if !isPrecompile && evm.chainRules.IsEIP158 && value.IsZero() {
|
||||
// Calling a non existing account, don't do anything, but ping the tracer
|
||||
if debug {
|
||||
if evm.depth == 0 {
|
||||
evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
|
||||
evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value.ToBig())
|
||||
evm.Config.Tracer.CaptureEnd(ret, 0, nil)
|
||||
} else {
|
||||
evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
|
||||
evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value.ToBig())
|
||||
evm.Config.Tracer.CaptureExit(ret, 0, nil)
|
||||
}
|
||||
}
|
||||
@@ -291,13 +288,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||
// Capture the tracer start/end events in debug mode
|
||||
if debug {
|
||||
if evm.depth == 0 {
|
||||
evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
|
||||
evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value.ToBig())
|
||||
defer func(startGas uint64) { // Lazy evaluation of the parameters
|
||||
evm.Config.Tracer.CaptureEnd(ret, startGas-gas, err)
|
||||
}(gas)
|
||||
} else {
|
||||
// Handle tracer events for entering and exiting a call frame
|
||||
evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
|
||||
evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value.ToBig())
|
||||
defer func(startGas uint64) {
|
||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||
}(gas)
|
||||
@@ -344,7 +341,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||
//
|
||||
// CallCode differs from Call in the sense that it executes the given address'
|
||||
// code with the caller as context.
|
||||
func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
|
||||
func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) {
|
||||
// Fail if we're trying to execute above the call depth limit
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, vmerrs.ErrDepth
|
||||
@@ -363,7 +360,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.Config.Tracer != nil {
|
||||
evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value)
|
||||
evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value.ToBig())
|
||||
defer func(startGas uint64) {
|
||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||
}(gas)
|
||||
@@ -408,7 +405,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||
// that caller is something other than a Contract.
|
||||
parent := caller.(*Contract)
|
||||
// DELEGATECALL inherits value from parent call
|
||||
evm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, parent.value)
|
||||
evm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, parent.value.ToBig())
|
||||
defer func(startGas uint64) {
|
||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||
}(gas)
|
||||
@@ -454,7 +451,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,
|
||||
// but is the correct thing to do and matters on other networks, in tests, and potential
|
||||
// future scenarios
|
||||
evm.StateDB.AddBalance(addr, big0)
|
||||
evm.StateDB.AddBalance(addr, new(uint256.Int))
|
||||
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.Config.Tracer != nil {
|
||||
@@ -473,7 +470,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||
addrCopy := addr
|
||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||
// The contract is a scoped environment for this execution context only.
|
||||
contract := NewContract(caller, AccountRef(addrCopy), new(big.Int), gas)
|
||||
contract := NewContract(caller, AccountRef(addrCopy), new(uint256.Int), gas)
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
// When an error was returned by the EVM or when setting the creation code
|
||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||
@@ -503,7 +500,7 @@ func (c *codeAndHash) Hash() common.Hash {
|
||||
}
|
||||
|
||||
// create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address, typ OpCode) ([]byte, common.Address, uint64, error) {
|
||||
func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *uint256.Int, address common.Address, typ OpCode) ([]byte, common.Address, uint64, error) {
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
// limit.
|
||||
if evm.depth > int(params.CallCreateDepth) {
|
||||
@@ -558,9 +555,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||
|
||||
if evm.Config.Tracer != nil {
|
||||
if evm.depth == 0 {
|
||||
evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
|
||||
evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value.ToBig())
|
||||
} else {
|
||||
evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value)
|
||||
evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value.ToBig())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -610,7 +607,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||
}
|
||||
|
||||
// Create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
|
||||
return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE)
|
||||
}
|
||||
@@ -619,7 +616,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||
//
|
||||
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
|
||||
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
|
||||
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
codeAndHash := &codeAndHash{code: code}
|
||||
contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes())
|
||||
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)
|
||||
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/vmerrs"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
func TestMemoryGasCost(t *testing.T) {
|
||||
@@ -102,12 +103,12 @@ func TestEIP2200(t *testing.T) {
|
||||
statedb.Finalise(true) // Push the state into the "original" slot
|
||||
|
||||
vmctx := BlockContext{
|
||||
CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true },
|
||||
Transfer: func(StateDB, common.Address, common.Address, *big.Int) {},
|
||||
CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true },
|
||||
Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {},
|
||||
}
|
||||
vmenv := NewEVM(vmctx, TxContext{}, statedb, params.TestChainConfig, Config{ExtraEips: []int{2200}})
|
||||
|
||||
_, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(big.Int))
|
||||
_, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(uint256.Int))
|
||||
if err != tt.failure {
|
||||
t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure)
|
||||
}
|
||||
@@ -152,8 +153,8 @@ func TestCreateGas(t *testing.T) {
|
||||
statedb.SetCode(address, hexutil.MustDecode(tt.code))
|
||||
statedb.Finalise(true)
|
||||
vmctx := BlockContext{
|
||||
CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true },
|
||||
Transfer: func(StateDB, common.Address, common.Address, *big.Int) {},
|
||||
CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true },
|
||||
Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {},
|
||||
BlockNumber: big.NewInt(0),
|
||||
}
|
||||
config := Config{}
|
||||
@@ -165,7 +166,7 @@ func TestCreateGas(t *testing.T) {
|
||||
// because it is the last fork before the activation of EIP-3860
|
||||
vmenv := NewEVM(vmctx, TxContext{}, statedb, params.TestSubnetEVMChainConfig, config)
|
||||
var startGas = uint64(testGas)
|
||||
ret, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, startGas, new(big.Int))
|
||||
ret, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, startGas, new(uint256.Int))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
+13
-32
@@ -27,6 +27,8 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ava-labs/subnet-evm/vmerrs"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -270,7 +272,7 @@ func opAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
||||
func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||
slot := scope.Stack.peek()
|
||||
address := common.Address(slot.Bytes20())
|
||||
slot.SetFromBig(interpreter.evm.StateDB.GetBalance(address))
|
||||
slot.Set(interpreter.evm.StateDB.GetBalance(address))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -285,8 +287,7 @@ func opCaller(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||
}
|
||||
|
||||
func opCallValue(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||
v, _ := uint256.FromBig(scope.Contract.value)
|
||||
scope.Stack.push(v)
|
||||
scope.Stack.push(scope.Contract.value)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -358,9 +359,7 @@ func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||
}
|
||||
|
||||
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||
l := new(uint256.Int)
|
||||
l.SetUint64(uint64(len(scope.Contract.Code)))
|
||||
scope.Stack.push(l)
|
||||
scope.Stack.push(new(uint256.Int).SetUint64(uint64(len(scope.Contract.Code))))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -372,7 +371,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||
)
|
||||
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||
if overflow {
|
||||
uint64CodeOffset = 0xffffffffffffffff
|
||||
uint64CodeOffset = math.MaxUint64
|
||||
}
|
||||
codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64())
|
||||
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||
@@ -390,7 +389,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||
)
|
||||
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||
if overflow {
|
||||
uint64CodeOffset = 0xffffffffffffffff
|
||||
uint64CodeOffset = math.MaxUint64
|
||||
}
|
||||
addr := common.Address(a.Bytes20())
|
||||
codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
|
||||
@@ -596,13 +595,8 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||
stackvalue := size
|
||||
|
||||
scope.Contract.UseGas(gas)
|
||||
//TODO: use uint256.Int instead of converting with toBig()
|
||||
var bigVal = big0
|
||||
if !value.IsZero() {
|
||||
bigVal = value.ToBig()
|
||||
}
|
||||
|
||||
res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract, input, gas, bigVal)
|
||||
res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract, input, gas, &value)
|
||||
// Push item on the stack based on the returned error. If the ruleset is
|
||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||
// rule) and treat as an error, if the ruleset is frontier we must
|
||||
@@ -641,13 +635,8 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
||||
scope.Contract.UseGas(gas)
|
||||
// reuse size int for stackvalue
|
||||
stackvalue := size
|
||||
//TODO: use uint256.Int instead of converting with toBig()
|
||||
bigEndowment := big0
|
||||
if !endowment.IsZero() {
|
||||
bigEndowment = endowment.ToBig()
|
||||
}
|
||||
res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract, input, gas,
|
||||
bigEndowment, &salt)
|
||||
&endowment, &salt)
|
||||
// Push item on the stack based on the returned error.
|
||||
if suberr != nil {
|
||||
stackvalue.Clear()
|
||||
@@ -680,16 +669,11 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
|
||||
if interpreter.readOnly && !value.IsZero() {
|
||||
return nil, vmerrs.ErrWriteProtection
|
||||
}
|
||||
var bigVal = big0
|
||||
//TODO: use uint256.Int instead of converting with toBig()
|
||||
// By using big0 here, we save an alloc for the most common case (non-ether-transferring contract calls),
|
||||
// but it would make more sense to extend the usage of uint256.Int
|
||||
if !value.IsZero() {
|
||||
gas += params.CallStipend
|
||||
bigVal = value.ToBig()
|
||||
}
|
||||
ret, returnGas, err := interpreter.evm.Call(scope.Contract, toAddr, args, gas, &value)
|
||||
|
||||
ret, returnGas, err := interpreter.evm.Call(scope.Contract, toAddr, args, gas, bigVal)
|
||||
if err != nil {
|
||||
temp.Clear()
|
||||
} else {
|
||||
@@ -717,14 +701,11 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||
// Get arguments from the memory.
|
||||
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
||||
|
||||
//TODO: use uint256.Int instead of converting with toBig()
|
||||
var bigVal = big0
|
||||
if !value.IsZero() {
|
||||
gas += params.CallStipend
|
||||
bigVal = value.ToBig()
|
||||
}
|
||||
|
||||
ret, returnGas, err := interpreter.evm.CallCode(scope.Contract, toAddr, args, gas, bigVal)
|
||||
ret, returnGas, err := interpreter.evm.CallCode(scope.Contract, toAddr, args, gas, &value)
|
||||
if err != nil {
|
||||
temp.Clear()
|
||||
} else {
|
||||
@@ -828,7 +809,7 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
||||
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
|
||||
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
|
||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
||||
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
|
||||
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||
tracer.CaptureExit([]byte{}, 0, nil)
|
||||
}
|
||||
return nil, errStopToken
|
||||
@@ -844,7 +825,7 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
|
||||
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
|
||||
interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address())
|
||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
||||
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
|
||||
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||
tracer.CaptureExit([]byte{}, 0, nil)
|
||||
}
|
||||
return nil, errStopToken
|
||||
|
||||
@@ -601,7 +601,7 @@ func TestOpTstore(t *testing.T) {
|
||||
caller = common.Address{}
|
||||
to = common.Address{1}
|
||||
contractRef = contractRef{caller}
|
||||
contract = NewContract(contractRef, AccountRef(to), new(big.Int), 0)
|
||||
contract = NewContract(contractRef, AccountRef(to), new(uint256.Int), 0)
|
||||
scopeContext = ScopeContext{mem, stack, contract}
|
||||
value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700")
|
||||
)
|
||||
|
||||
@@ -32,15 +32,16 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/core/types"
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// StateDB is an EVM database for full state querying.
|
||||
type StateDB interface {
|
||||
CreateAccount(common.Address)
|
||||
|
||||
SubBalance(common.Address, *big.Int)
|
||||
AddBalance(common.Address, *big.Int)
|
||||
GetBalance(common.Address) *big.Int
|
||||
SubBalance(common.Address, *uint256.Int)
|
||||
AddBalance(common.Address, *uint256.Int)
|
||||
GetBalance(common.Address) *uint256.Int
|
||||
|
||||
GetNonce(common.Address) uint64
|
||||
SetNonce(common.Address, uint64)
|
||||
|
||||
@@ -157,7 +157,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||
)
|
||||
|
||||
// Don't move this deferred function, it's placed before the capturestate-deferred method,
|
||||
// so that it get's executed _after_: the capturestate needs the stacks before
|
||||
// so that it gets executed _after_: the capturestate needs the stacks before
|
||||
// they are returned to the pools
|
||||
defer func() {
|
||||
returnStack(stack)
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -37,6 +36,7 @@ import (
|
||||
"github.com/ava-labs/subnet-evm/params"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
var loopInterruptTests = []string{
|
||||
@@ -49,7 +49,7 @@ var loopInterruptTests = []string{
|
||||
func TestLoopInterrupt(t *testing.T) {
|
||||
address := common.BytesToAddress([]byte("contract"))
|
||||
vmctx := BlockContext{
|
||||
Transfer: func(StateDB, common.Address, common.Address, *big.Int) {},
|
||||
Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {},
|
||||
}
|
||||
|
||||
for i, tt := range loopInterruptTests {
|
||||
@@ -64,7 +64,7 @@ func TestLoopInterrupt(t *testing.T) {
|
||||
timeout := make(chan bool)
|
||||
|
||||
go func(evm *EVM) {
|
||||
_, _, err := evm.Call(AccountRef(common.Address{}), address, nil, math.MaxUint64, new(big.Int))
|
||||
_, _, err := evm.Call(AccountRef(common.Address{}), address, nil, math.MaxUint64, new(uint256.Int))
|
||||
errChannel <- err
|
||||
}(evm)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user