mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-23 15:14:32 +00:00
Merge branch 'ethereum:master' into master
This commit is contained in:
commit
fe6edf97ae
78 changed files with 1098 additions and 972 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
## Go Ethereum
|
## Go Ethereum
|
||||||
|
|
||||||
Official Golang execution layer implementation of the Ethereum protocol.
|
Golang execution layer implementation of the Ethereum protocol.
|
||||||
|
|
||||||
[
|
)
|
||||||
|
|
||||||
|
|
@ -308,15 +309,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta))
|
reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta))
|
||||||
reward.Mul(reward, blockReward)
|
reward.Mul(reward, blockReward)
|
||||||
reward.Div(reward, big.NewInt(8))
|
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))
|
||||||
}
|
}
|
||||||
// Apply withdrawals
|
// Apply withdrawals
|
||||||
for _, w := range pre.Env.Withdrawals {
|
for _, w := range pre.Env.Withdrawals {
|
||||||
// Amount is in gwei, turn into wei
|
// Amount is in gwei, turn into wei
|
||||||
amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei))
|
amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei))
|
||||||
statedb.AddBalance(w.Address, amount)
|
statedb.AddBalance(w.Address, uint256.MustFromBig(amount))
|
||||||
}
|
}
|
||||||
// Commit block
|
// Commit block
|
||||||
root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber))
|
root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber))
|
||||||
|
|
@ -359,7 +360,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB
|
||||||
for addr, a := range accounts {
|
for addr, a := range accounts {
|
||||||
statedb.SetCode(addr, a.Code)
|
statedb.SetCode(addr, a.Code)
|
||||||
statedb.SetNonce(addr, a.Nonce)
|
statedb.SetNonce(addr, a.Nonce)
|
||||||
statedb.SetBalance(addr, a.Balance)
|
statedb.SetBalance(addr, uint256.MustFromBig(a.Balance))
|
||||||
for k, v := range a.Storage {
|
for k, v := range a.Storage {
|
||||||
statedb.SetState(addr, k, v)
|
statedb.SetState(addr, k, v)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ func (g Alloc) OnAccount(addr *common.Address, dumpAccount state.DumpAccount) {
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10)
|
balance, _ := new(big.Int).SetString(dumpAccount.Balance, 0)
|
||||||
var storage map[common.Hash]common.Hash
|
var storage map[common.Hash]common.Hash
|
||||||
if dumpAccount.Storage != nil {
|
if dumpAccount.Storage != nil {
|
||||||
storage = make(map[common.Hash]common.Hash)
|
storage = make(map[common.Hash]common.Hash)
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// geth is the official command-line client for Ethereum.
|
// geth is a command-line client for Ethereum.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,11 @@
|
||||||
|
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import "math/big"
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
)
|
||||||
|
|
||||||
// Common big integers often used
|
// Common big integers often used
|
||||||
var (
|
var (
|
||||||
|
|
@ -27,4 +31,6 @@ var (
|
||||||
Big32 = big.NewInt(32)
|
Big32 = big.NewInt(32)
|
||||||
Big256 = big.NewInt(256)
|
Big256 = big.NewInt(256)
|
||||||
Big257 = big.NewInt(257)
|
Big257 = big.NewInt(257)
|
||||||
|
|
||||||
|
U2560 = uint256.NewInt(0)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Proof-of-stake protocol constants.
|
// Proof-of-stake protocol constants.
|
||||||
|
|
@ -355,8 +356,8 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
|
||||||
// Withdrawals processing.
|
// Withdrawals processing.
|
||||||
for _, w := range withdrawals {
|
for _, w := range withdrawals {
|
||||||
// Convert amount from gwei to wei.
|
// Convert amount from gwei to wei.
|
||||||
amount := new(big.Int).SetUint64(w.Amount)
|
amount := new(uint256.Int).SetUint64(w.Amount)
|
||||||
amount = amount.Mul(amount, big.NewInt(params.GWei))
|
amount = amount.Mul(amount, uint256.NewInt(params.GWei))
|
||||||
state.AddBalance(w.Address, amount)
|
state.AddBalance(w.Address, amount)
|
||||||
}
|
}
|
||||||
// No block reward which is issued by consensus layer instead.
|
// No block reward which is issued by consensus layer instead.
|
||||||
|
|
|
||||||
|
|
@ -33,16 +33,17 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ethash proof-of-work protocol constants.
|
// Ethash proof-of-work protocol constants.
|
||||||
var (
|
var (
|
||||||
FrontierBlockReward = big.NewInt(5e+18) // Block reward in wei for successfully mining a block
|
FrontierBlockReward = uint256.NewInt(5e+18) // Block reward in wei for successfully mining a block
|
||||||
ByzantiumBlockReward = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium
|
ByzantiumBlockReward = uint256.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium
|
||||||
ConstantinopleBlockReward = big.NewInt(2e+18) // Block reward in wei for successfully mining a block upward from Constantinople
|
ConstantinopleBlockReward = uint256.NewInt(2e+18) // Block reward in wei for successfully mining a block upward from Constantinople
|
||||||
maxUncles = 2 // Maximum number of uncles allowed in a single block
|
maxUncles = 2 // Maximum number of uncles allowed in a single block
|
||||||
allowedFutureBlockTimeSeconds = int64(15) // Max seconds from current time allowed for blocks, before they're considered future blocks
|
allowedFutureBlockTimeSeconds = int64(15) // Max seconds from current time allowed for blocks, before they're considered future blocks
|
||||||
|
|
||||||
// calcDifficultyEip5133 is the difficulty adjustment algorithm as specified by EIP 5133.
|
// calcDifficultyEip5133 is the difficulty adjustment algorithm as specified by EIP 5133.
|
||||||
// It offsets the bomb a total of 11.4M blocks.
|
// It offsets the bomb a total of 11.4M blocks.
|
||||||
|
|
@ -562,8 +563,8 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
|
||||||
|
|
||||||
// Some weird constants to avoid constant memory allocs for them.
|
// Some weird constants to avoid constant memory allocs for them.
|
||||||
var (
|
var (
|
||||||
big8 = big.NewInt(8)
|
u256_8 = uint256.NewInt(8)
|
||||||
big32 = big.NewInt(32)
|
u256_32 = uint256.NewInt(32)
|
||||||
)
|
)
|
||||||
|
|
||||||
// AccumulateRewards credits the coinbase of the given block with the mining
|
// AccumulateRewards credits the coinbase of the given block with the mining
|
||||||
|
|
@ -579,16 +580,18 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
|
||||||
blockReward = ConstantinopleBlockReward
|
blockReward = ConstantinopleBlockReward
|
||||||
}
|
}
|
||||||
// Accumulate the rewards for the miner and any included uncles
|
// Accumulate the rewards for the miner and any included uncles
|
||||||
reward := new(big.Int).Set(blockReward)
|
reward := new(uint256.Int).Set(blockReward)
|
||||||
r := new(big.Int)
|
r := new(uint256.Int)
|
||||||
|
hNum, _ := uint256.FromBig(header.Number)
|
||||||
for _, uncle := range uncles {
|
for _, uncle := range uncles {
|
||||||
r.Add(uncle.Number, big8)
|
uNum, _ := uint256.FromBig(uncle.Number)
|
||||||
r.Sub(r, header.Number)
|
r.AddUint64(uNum, 8)
|
||||||
|
r.Sub(r, hNum)
|
||||||
r.Mul(r, blockReward)
|
r.Mul(r, blockReward)
|
||||||
r.Div(r, big8)
|
r.Div(r, u256_8)
|
||||||
state.AddBalance(uncle.Coinbase, r)
|
state.AddBalance(uncle.Coinbase, r)
|
||||||
|
|
||||||
r.Div(blockReward, big32)
|
r.Div(blockReward, u256_32)
|
||||||
reward.Add(reward, r)
|
reward.Add(reward, r)
|
||||||
}
|
}
|
||||||
state.AddBalance(header.Coinbase, reward)
|
state.AddBalance(header.Coinbase, reward)
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -81,6 +82,6 @@ func ApplyDAOHardFork(statedb *state.StateDB) {
|
||||||
// Move every DAO account and extra-balance account funds into the refund contract
|
// Move every DAO account and extra-balance account funds into the refund contract
|
||||||
for _, addr := range params.DAODrainList() {
|
for _, addr := range params.DAODrainList() {
|
||||||
statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr))
|
statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr))
|
||||||
statedb.SetBalance(addr, new(big.Int))
|
statedb.SetBalance(addr, new(uint256.Int))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ func BenchmarkChainWrite_full_500k(b *testing.B) {
|
||||||
|
|
||||||
// makeChainForBench writes a given number of headers or empty blocks/receipts
|
// makeChainForBench writes a given number of headers or empty blocks/receipts
|
||||||
// into a database.
|
// 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
|
var hash common.Hash
|
||||||
for n := uint64(0); n < count; n++ {
|
for n := uint64(0); n < count; n++ {
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
|
|
@ -255,6 +255,9 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) {
|
||||||
TxHash: types.EmptyTxsHash,
|
TxHash: types.EmptyTxsHash,
|
||||||
ReceiptHash: types.EmptyReceiptsHash,
|
ReceiptHash: types.EmptyReceiptsHash,
|
||||||
}
|
}
|
||||||
|
if n == 0 {
|
||||||
|
header = genesis.ToBlock().Header()
|
||||||
|
}
|
||||||
hash = header.Hash()
|
hash = header.Hash()
|
||||||
|
|
||||||
rawdb.WriteHeader(db, header)
|
rawdb.WriteHeader(db, header)
|
||||||
|
|
@ -262,7 +265,7 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) {
|
||||||
rawdb.WriteTd(db, hash, n, big.NewInt(int64(n+1)))
|
rawdb.WriteTd(db, hash, n, big.NewInt(int64(n+1)))
|
||||||
|
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
rawdb.WriteChainConfig(db, hash, params.AllEthashProtocolChanges)
|
rawdb.WriteChainConfig(db, hash, genesis.Config)
|
||||||
}
|
}
|
||||||
rawdb.WriteHeadHeaderHash(db, hash)
|
rawdb.WriteHeadHeaderHash(db, hash)
|
||||||
|
|
||||||
|
|
@ -276,13 +279,14 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func benchWriteChain(b *testing.B, full bool, count uint64) {
|
func benchWriteChain(b *testing.B, full bool, count uint64) {
|
||||||
|
genesis := &Genesis{Config: params.AllEthashProtocolChanges}
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
dir := b.TempDir()
|
dir := b.TempDir()
|
||||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false)
|
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
makeChainForBench(db, full, count)
|
makeChainForBench(db, genesis, full, count)
|
||||||
db.Close()
|
db.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -294,7 +298,8 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
makeChainForBench(db, full, count)
|
genesis := &Genesis{Config: params.AllEthashProtocolChanges}
|
||||||
|
makeChainForBench(db, genesis, full, count)
|
||||||
db.Close()
|
db.Close()
|
||||||
cacheConfig := *defaultCacheConfig
|
cacheConfig := *defaultCacheConfig
|
||||||
cacheConfig.TrieDirtyDisabled = true
|
cacheConfig.TrieDirtyDisabled = true
|
||||||
|
|
@ -307,7 +312,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
chain, err := NewBlockChain(db, &cacheConfig, nil, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error creating chain: %v", err)
|
b.Fatalf("error creating chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,17 +192,6 @@ type txLookup struct {
|
||||||
transaction *types.Transaction
|
transaction *types.Transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 (prog TxIndexProgress) Done() bool {
|
|
||||||
return prog.Remaining == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlockChain represents the canonical chain given a database with a genesis
|
// BlockChain represents the canonical chain given a database with a genesis
|
||||||
// block. The Blockchain manages chain imports, reverts, chain reorganisations.
|
// block. The Blockchain manages chain imports, reverts, chain reorganisations.
|
||||||
//
|
//
|
||||||
|
|
@ -229,13 +218,7 @@ type BlockChain struct {
|
||||||
flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state
|
flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state
|
||||||
triedb *trie.Database // The database handler for maintaining trie nodes.
|
triedb *trie.Database // The database handler for maintaining trie nodes.
|
||||||
stateCache state.Database // State database to reuse between imports (contains state cache)
|
stateCache state.Database // State database to reuse between imports (contains state cache)
|
||||||
|
txIndexer *txIndexer // Transaction indexer, might be nil if not enabled
|
||||||
// txLookupLimit is the maximum number of blocks from head whose tx indices
|
|
||||||
// are reserved:
|
|
||||||
// * 0: means no limit and regenerate any missing indexes
|
|
||||||
// * N: means N block limit [HEAD-N+1, HEAD] and delete extra indexes
|
|
||||||
// * nil: disable tx reindexer/deleter, but still index new blocks
|
|
||||||
txLookupLimit uint64
|
|
||||||
|
|
||||||
hc *HeaderChain
|
hc *HeaderChain
|
||||||
rmLogsFeed event.Feed
|
rmLogsFeed event.Feed
|
||||||
|
|
@ -270,9 +253,6 @@ type BlockChain struct {
|
||||||
stopping atomic.Bool // false if chain is running, true when stopped
|
stopping atomic.Bool // false if chain is running, true when stopped
|
||||||
procInterrupt atomic.Bool // interrupt signaler for block processing
|
procInterrupt atomic.Bool // interrupt signaler for block processing
|
||||||
|
|
||||||
txIndexRunning bool // flag if the background tx indexer is activated
|
|
||||||
txIndexProgCh chan chan TxIndexProgress // chan for querying the progress of transaction indexing
|
|
||||||
|
|
||||||
engine consensus.Engine
|
engine consensus.Engine
|
||||||
validator Validator // Block and state validator interface
|
validator Validator // Block and state validator interface
|
||||||
prefetcher Prefetcher
|
prefetcher Prefetcher
|
||||||
|
|
@ -320,7 +300,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||||
blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit),
|
blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit),
|
||||||
txLookupCache: lru.NewCache[common.Hash, txLookup](txLookupCacheLimit),
|
txLookupCache: lru.NewCache[common.Hash, txLookup](txLookupCacheLimit),
|
||||||
futureBlocks: lru.NewCache[common.Hash, *types.Block](maxFutureBlocks),
|
futureBlocks: lru.NewCache[common.Hash, *types.Block](maxFutureBlocks),
|
||||||
txIndexProgCh: make(chan chan TxIndexProgress),
|
|
||||||
engine: engine,
|
engine: engine,
|
||||||
vmConfig: vmConfig,
|
vmConfig: vmConfig,
|
||||||
}
|
}
|
||||||
|
|
@ -485,13 +464,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||||
}
|
}
|
||||||
rawdb.WriteChainConfig(db, genesisHash, chainConfig)
|
rawdb.WriteChainConfig(db, genesisHash, chainConfig)
|
||||||
}
|
}
|
||||||
// Start tx indexer/unindexer if required.
|
// Start tx indexer if it's enabled.
|
||||||
if txLookupLimit != nil {
|
if txLookupLimit != nil {
|
||||||
bc.txLookupLimit = *txLookupLimit
|
bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
|
||||||
bc.txIndexRunning = true
|
|
||||||
|
|
||||||
bc.wg.Add(1)
|
|
||||||
go bc.maintainTxIndex()
|
|
||||||
}
|
}
|
||||||
return bc, nil
|
return bc, nil
|
||||||
}
|
}
|
||||||
|
|
@ -981,7 +956,10 @@ func (bc *BlockChain) stopWithoutSaving() {
|
||||||
if !bc.stopping.CompareAndSwap(false, true) {
|
if !bc.stopping.CompareAndSwap(false, true) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Signal shutdown tx indexer.
|
||||||
|
if bc.txIndexer != nil {
|
||||||
|
bc.txIndexer.close()
|
||||||
|
}
|
||||||
// Unsubscribe all subscriptions registered from blockchain.
|
// Unsubscribe all subscriptions registered from blockchain.
|
||||||
bc.scope.Close()
|
bc.scope.Close()
|
||||||
|
|
||||||
|
|
@ -2403,148 +2381,6 @@ func (bc *BlockChain) skipBlock(err error, it *insertIterator) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// indexBlocks reindexes or unindexes transactions depending on user configuration
|
|
||||||
func (bc *BlockChain) indexBlocks(tail *uint64, head uint64, done chan struct{}) {
|
|
||||||
defer func() { close(done) }()
|
|
||||||
|
|
||||||
// If head is 0, it means the chain is just initialized and no blocks are
|
|
||||||
// inserted, so don't need to index anything.
|
|
||||||
if head == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// The tail flag is not existent, it means the node is just initialized
|
|
||||||
// and all blocks in the chain (part of them may from ancient store) are
|
|
||||||
// not indexed yet, index the chain according to the configuration then.
|
|
||||||
if tail == nil {
|
|
||||||
from := uint64(0)
|
|
||||||
if bc.txLookupLimit != 0 && head >= bc.txLookupLimit {
|
|
||||||
from = head - bc.txLookupLimit + 1
|
|
||||||
}
|
|
||||||
rawdb.IndexTransactions(bc.db, from, head+1, bc.quit, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// The tail flag is existent (which means indexes in [tail, head] should be
|
|
||||||
// present), while the whole chain are requested for indexing.
|
|
||||||
if bc.txLookupLimit == 0 || head < bc.txLookupLimit {
|
|
||||||
if *tail > 0 {
|
|
||||||
// It can happen when chain is rewound to a historical point which
|
|
||||||
// is even lower than the indexes tail, recap the indexing target
|
|
||||||
// to new head to avoid reading non-existent block bodies.
|
|
||||||
end := *tail
|
|
||||||
if end > head+1 {
|
|
||||||
end = head + 1
|
|
||||||
}
|
|
||||||
rawdb.IndexTransactions(bc.db, 0, end, bc.quit, true)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// The tail flag is existent, adjust the index range according to configuration
|
|
||||||
// and latest head.
|
|
||||||
if head-bc.txLookupLimit+1 < *tail {
|
|
||||||
// Reindex a part of missing indices and rewind index tail to HEAD-limit
|
|
||||||
rawdb.IndexTransactions(bc.db, head-bc.txLookupLimit+1, *tail, bc.quit, true)
|
|
||||||
} else {
|
|
||||||
// Unindex a part of stale indices and forward index tail to HEAD-limit
|
|
||||||
rawdb.UnindexTransactions(bc.db, *tail, head-bc.txLookupLimit+1, bc.quit, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reportTxIndexProgress returns the tx indexing progress.
|
|
||||||
func (bc *BlockChain) reportTxIndexProgress(head uint64) TxIndexProgress {
|
|
||||||
var (
|
|
||||||
remaining uint64
|
|
||||||
tail = rawdb.ReadTxIndexTail(bc.db)
|
|
||||||
)
|
|
||||||
total := bc.txLookupLimit
|
|
||||||
if bc.txLookupLimit == 0 {
|
|
||||||
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.
|
|
||||||
if indexed < total {
|
|
||||||
remaining = total - indexed
|
|
||||||
}
|
|
||||||
return TxIndexProgress{
|
|
||||||
Indexed: indexed,
|
|
||||||
Remaining: remaining,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TxIndexProgress retrieves the tx indexing progress, or an error if the
|
|
||||||
// background tx indexer is not activated or already stopped.
|
|
||||||
func (bc *BlockChain) TxIndexProgress() (TxIndexProgress, error) {
|
|
||||||
if !bc.txIndexRunning {
|
|
||||||
return TxIndexProgress{}, errors.New("tx indexer is not activated")
|
|
||||||
}
|
|
||||||
ch := make(chan TxIndexProgress, 1)
|
|
||||||
select {
|
|
||||||
case bc.txIndexProgCh <- ch:
|
|
||||||
return <-ch, nil
|
|
||||||
case <-bc.quit:
|
|
||||||
return TxIndexProgress{}, errors.New("blockchain is closed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// maintainTxIndex is responsible for the construction and deletion of the
|
|
||||||
// transaction index.
|
|
||||||
//
|
|
||||||
// User can use flag `txlookuplimit` to specify a "recentness" block, below
|
|
||||||
// which ancient tx indices get deleted. If `txlookuplimit` is 0, it means
|
|
||||||
// all tx indices will be reserved.
|
|
||||||
//
|
|
||||||
// The user can adjust the txlookuplimit value for each launch after sync,
|
|
||||||
// Geth will automatically construct the missing indices or delete the extra
|
|
||||||
// indices.
|
|
||||||
func (bc *BlockChain) maintainTxIndex() {
|
|
||||||
defer bc.wg.Done()
|
|
||||||
|
|
||||||
// Listening to chain events and manipulate the transaction indexes.
|
|
||||||
var (
|
|
||||||
done chan struct{} // Non-nil if background unindexing or reindexing routine is active.
|
|
||||||
lastHead uint64 // The latest announced chain head (whose tx indexes are assumed created)
|
|
||||||
headCh = make(chan ChainHeadEvent, 1) // Buffered to avoid locking up the event feed
|
|
||||||
)
|
|
||||||
sub := bc.SubscribeChainHeadEvent(headCh)
|
|
||||||
if sub == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer sub.Unsubscribe()
|
|
||||||
log.Info("Initialized transaction indexer", "limit", bc.TxLookupLimit())
|
|
||||||
|
|
||||||
// Launch the initial processing if chain is not empty (head != genesis).
|
|
||||||
// This step is useful in these scenarios that chain has no progress and
|
|
||||||
// indexer is never triggered.
|
|
||||||
if head := rawdb.ReadHeadBlock(bc.db); head != nil && head.Number().Uint64() != 0 {
|
|
||||||
done = make(chan struct{})
|
|
||||||
lastHead = head.Number().Uint64()
|
|
||||||
go bc.indexBlocks(rawdb.ReadTxIndexTail(bc.db), head.NumberU64(), done)
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case head := <-headCh:
|
|
||||||
if done == nil {
|
|
||||||
done = make(chan struct{})
|
|
||||||
go bc.indexBlocks(rawdb.ReadTxIndexTail(bc.db), head.Block.NumberU64(), done)
|
|
||||||
}
|
|
||||||
lastHead = head.Block.NumberU64()
|
|
||||||
case <-done:
|
|
||||||
done = nil
|
|
||||||
case ch := <-bc.txIndexProgCh:
|
|
||||||
ch <- bc.reportTxIndexProgress(lastHead)
|
|
||||||
case <-bc.quit:
|
|
||||||
if done != nil {
|
|
||||||
log.Info("Waiting background transaction indexer to exit")
|
|
||||||
<-done
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reportBlock logs a bad block error.
|
// reportBlock logs a bad block error.
|
||||||
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) {
|
func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) {
|
||||||
rawdb.WriteBadBlock(bc.db, block)
|
rawdb.WriteBadBlock(bc.db, block)
|
||||||
|
|
|
||||||
|
|
@ -397,16 +397,12 @@ func (bc *BlockChain) GetVMConfig() *vm.Config {
|
||||||
return &bc.vmConfig
|
return &bc.vmConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTxLookupLimit is responsible for updating the txlookup limit to the
|
// TxIndexProgress returns the transaction indexing progress.
|
||||||
// original one stored in db if the new mismatches with the old one.
|
func (bc *BlockChain) TxIndexProgress() (TxIndexProgress, error) {
|
||||||
func (bc *BlockChain) SetTxLookupLimit(limit uint64) {
|
if bc.txIndexer == nil {
|
||||||
bc.txLookupLimit = limit
|
return TxIndexProgress{}, errors.New("tx indexer is not enabled")
|
||||||
}
|
}
|
||||||
|
return bc.txIndexer.txIndexProgress()
|
||||||
// TxLookupLimit retrieves the txlookup limit used by blockchain to prune
|
|
||||||
// stale transaction indices.
|
|
||||||
func (bc *BlockChain) TxLookupLimit() uint64 {
|
|
||||||
return bc.txLookupLimit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrieDB retrieves the low level trie database used for data storage.
|
// TrieDB retrieves the low level trie database used for data storage.
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// So we can deterministically seed different blockchains
|
// So we can deterministically seed different blockchains
|
||||||
|
|
@ -2722,106 +2723,6 @@ func testReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T, scheme strin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransactionIndices(t *testing.T) {
|
|
||||||
// Configure and generate a sample block chain
|
|
||||||
var (
|
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
|
||||||
funds = big.NewInt(100000000000000000)
|
|
||||||
gspec = &Genesis{
|
|
||||||
Config: params.TestChainConfig,
|
|
||||||
Alloc: GenesisAlloc{address: {Balance: funds}},
|
|
||||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
||||||
}
|
|
||||||
signer = types.LatestSigner(gspec.Config)
|
|
||||||
)
|
|
||||||
_, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 128, func(i int, block *BlockGen) {
|
|
||||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
block.AddTx(tx)
|
|
||||||
})
|
|
||||||
|
|
||||||
check := func(tail *uint64, chain *BlockChain) {
|
|
||||||
stored := rawdb.ReadTxIndexTail(chain.db)
|
|
||||||
if tail == nil && stored != nil {
|
|
||||||
t.Fatalf("Oldest indexded block mismatch, want nil, have %d", *stored)
|
|
||||||
}
|
|
||||||
if tail != nil && *stored != *tail {
|
|
||||||
t.Fatalf("Oldest indexded block mismatch, want %d, have %d", *tail, *stored)
|
|
||||||
}
|
|
||||||
if tail != nil {
|
|
||||||
for i := *tail; i <= chain.CurrentBlock().Number.Uint64(); i++ {
|
|
||||||
block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i)
|
|
||||||
if block.Transactions().Len() == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, tx := range block.Transactions() {
|
|
||||||
if index := rawdb.ReadTxLookupEntry(chain.db, tx.Hash()); index == nil {
|
|
||||||
t.Fatalf("Miss transaction indice, number %d hash %s", i, tx.Hash().Hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := uint64(0); i < *tail; i++ {
|
|
||||||
block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i)
|
|
||||||
if block.Transactions().Len() == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, tx := range block.Transactions() {
|
|
||||||
if index := rawdb.ReadTxLookupEntry(chain.db, tx.Hash()); index != nil {
|
|
||||||
t.Fatalf("Transaction indice should be deleted, number %d hash %s", i, tx.Hash().Hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Init block chain with external ancients, check all needed indices has been indexed.
|
|
||||||
limit := []uint64{0, 32, 64, 128}
|
|
||||||
for _, l := range limit {
|
|
||||||
frdir := t.TempDir()
|
|
||||||
ancientDb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
|
|
||||||
rawdb.WriteAncientBlocks(ancientDb, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0))
|
|
||||||
|
|
||||||
l := l
|
|
||||||
chain, err := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
|
||||||
}
|
|
||||||
chain.indexBlocks(rawdb.ReadTxIndexTail(ancientDb), 128, make(chan struct{}))
|
|
||||||
|
|
||||||
var tail uint64
|
|
||||||
if l != 0 {
|
|
||||||
tail = uint64(128) - l + 1
|
|
||||||
}
|
|
||||||
check(&tail, chain)
|
|
||||||
chain.Stop()
|
|
||||||
ancientDb.Close()
|
|
||||||
os.RemoveAll(frdir)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reconstruct a block chain which only reserves HEAD-64 tx indices
|
|
||||||
ancientDb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
|
|
||||||
defer ancientDb.Close()
|
|
||||||
|
|
||||||
rawdb.WriteAncientBlocks(ancientDb, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0))
|
|
||||||
limit = []uint64{0, 64 /* drop stale */, 32 /* shorten history */, 64 /* extend history */, 0 /* restore all */}
|
|
||||||
for _, l := range limit {
|
|
||||||
l := l
|
|
||||||
chain, err := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
|
||||||
}
|
|
||||||
var tail uint64
|
|
||||||
if l != 0 {
|
|
||||||
tail = uint64(128) - l + 1
|
|
||||||
}
|
|
||||||
chain.indexBlocks(rawdb.ReadTxIndexTail(ancientDb), 128, make(chan struct{}))
|
|
||||||
check(&tail, chain)
|
|
||||||
chain.Stop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Benchmarks large blocks with value transfers to non-existing accounts
|
// Benchmarks large blocks with value transfers to non-existing accounts
|
||||||
func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) {
|
func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) {
|
||||||
var (
|
var (
|
||||||
|
|
@ -3567,7 +3468,7 @@ func testInitThenFailCreateContract(t *testing.T, scheme string) {
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
statedb, _ := chain.State()
|
statedb, _ := chain.State()
|
||||||
if got, exp := statedb.GetBalance(aa), big.NewInt(100000); got.Cmp(exp) != 0 {
|
if got, exp := statedb.GetBalance(aa), uint256.NewInt(100000); got.Cmp(exp) != 0 {
|
||||||
t.Fatalf("Genesis err, got %v exp %v", got, exp)
|
t.Fatalf("Genesis err, got %v exp %v", got, exp)
|
||||||
}
|
}
|
||||||
// First block tries to create, but fails
|
// First block tries to create, but fails
|
||||||
|
|
@ -3577,7 +3478,7 @@ func testInitThenFailCreateContract(t *testing.T, scheme string) {
|
||||||
t.Fatalf("block %d: failed to insert into chain: %v", block.NumberU64(), err)
|
t.Fatalf("block %d: failed to insert into chain: %v", block.NumberU64(), err)
|
||||||
}
|
}
|
||||||
statedb, _ = chain.State()
|
statedb, _ = chain.State()
|
||||||
if got, exp := statedb.GetBalance(aa), big.NewInt(100000); got.Cmp(exp) != 0 {
|
if got, exp := statedb.GetBalance(aa), uint256.NewInt(100000); got.Cmp(exp) != 0 {
|
||||||
t.Fatalf("block %d: got %v exp %v", block.NumberU64(), got, exp)
|
t.Fatalf("block %d: got %v exp %v", block.NumberU64(), got, exp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3763,17 +3664,17 @@ func testEIP1559Transition(t *testing.T, scheme string) {
|
||||||
state, _ := chain.State()
|
state, _ := chain.State()
|
||||||
|
|
||||||
// 3: Ensure that miner received only the tx's tip.
|
// 3: Ensure that miner received only the tx's tip.
|
||||||
actual := state.GetBalance(block.Coinbase())
|
actual := state.GetBalance(block.Coinbase()).ToBig()
|
||||||
expected := new(big.Int).Add(
|
expected := new(big.Int).Add(
|
||||||
new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()),
|
new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()),
|
||||||
ethash.ConstantinopleBlockReward,
|
ethash.ConstantinopleBlockReward.ToBig(),
|
||||||
)
|
)
|
||||||
if actual.Cmp(expected) != 0 {
|
if actual.Cmp(expected) != 0 {
|
||||||
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
|
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
|
// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
|
||||||
actual = new(big.Int).Sub(funds, state.GetBalance(addr1))
|
actual = new(big.Int).Sub(funds, state.GetBalance(addr1).ToBig())
|
||||||
expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64()))
|
expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64()))
|
||||||
if actual.Cmp(expected) != 0 {
|
if actual.Cmp(expected) != 0 {
|
||||||
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
||||||
|
|
@ -3803,17 +3704,17 @@ func testEIP1559Transition(t *testing.T, scheme string) {
|
||||||
effectiveTip := block.Transactions()[0].GasTipCap().Uint64() - block.BaseFee().Uint64()
|
effectiveTip := block.Transactions()[0].GasTipCap().Uint64() - block.BaseFee().Uint64()
|
||||||
|
|
||||||
// 6+5: Ensure that miner received only the tx's effective tip.
|
// 6+5: Ensure that miner received only the tx's effective tip.
|
||||||
actual = state.GetBalance(block.Coinbase())
|
actual = state.GetBalance(block.Coinbase()).ToBig()
|
||||||
expected = new(big.Int).Add(
|
expected = new(big.Int).Add(
|
||||||
new(big.Int).SetUint64(block.GasUsed()*effectiveTip),
|
new(big.Int).SetUint64(block.GasUsed()*effectiveTip),
|
||||||
ethash.ConstantinopleBlockReward,
|
ethash.ConstantinopleBlockReward.ToBig(),
|
||||||
)
|
)
|
||||||
if actual.Cmp(expected) != 0 {
|
if actual.Cmp(expected) != 0 {
|
||||||
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
|
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4: Ensure the tx sender paid for the gasUsed * (effectiveTip + block baseFee).
|
// 4: Ensure the tx sender paid for the gasUsed * (effectiveTip + block baseFee).
|
||||||
actual = new(big.Int).Sub(funds, state.GetBalance(addr2))
|
actual = new(big.Int).Sub(funds, state.GetBalance(addr2).ToBig())
|
||||||
expected = new(big.Int).SetUint64(block.GasUsed() * (effectiveTip + block.BaseFee().Uint64()))
|
expected = new(big.Int).SetUint64(block.GasUsed() * (effectiveTip + block.BaseFee().Uint64()))
|
||||||
if actual.Cmp(expected) != 0 {
|
if actual.Cmp(expected) != 0 {
|
||||||
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
||||||
|
|
@ -4018,222 +3919,6 @@ func testCanonicalHashMarker(t *testing.T, scheme string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestTxIndexer tests the tx indexes are updated correctly.
|
|
||||||
func TestTxIndexer(t *testing.T) {
|
|
||||||
var (
|
|
||||||
testBankKey, _ = crypto.GenerateKey()
|
|
||||||
testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey)
|
|
||||||
testBankFunds = big.NewInt(1000000000000000000)
|
|
||||||
|
|
||||||
gspec = &Genesis{
|
|
||||||
Config: params.TestChainConfig,
|
|
||||||
Alloc: GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
|
|
||||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
||||||
}
|
|
||||||
engine = ethash.NewFaker()
|
|
||||||
nonce = uint64(0)
|
|
||||||
)
|
|
||||||
_, blocks, receipts := GenerateChainWithGenesis(gspec, engine, 128, func(i int, gen *BlockGen) {
|
|
||||||
tx, _ := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("0xdeadbeef"), big.NewInt(1000), params.TxGas, big.NewInt(10*params.InitialBaseFee), nil), types.HomesteadSigner{}, testBankKey)
|
|
||||||
gen.AddTx(tx)
|
|
||||||
nonce += 1
|
|
||||||
})
|
|
||||||
|
|
||||||
// verifyIndexes checks if the transaction indexes are present or not
|
|
||||||
// of the specified block.
|
|
||||||
verifyIndexes := func(db ethdb.Database, number uint64, exist bool) {
|
|
||||||
if number == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
block := blocks[number-1]
|
|
||||||
for _, tx := range block.Transactions() {
|
|
||||||
lookup := rawdb.ReadTxLookupEntry(db, tx.Hash())
|
|
||||||
if exist && lookup == nil {
|
|
||||||
t.Fatalf("missing %d %x", number, tx.Hash().Hex())
|
|
||||||
}
|
|
||||||
if !exist && lookup != nil {
|
|
||||||
t.Fatalf("unexpected %d %x", number, tx.Hash().Hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// verifyRange runs verifyIndexes for a range of blocks, from and to are included.
|
|
||||||
verifyRange := func(db ethdb.Database, from, to uint64, exist bool) {
|
|
||||||
for number := from; number <= to; number += 1 {
|
|
||||||
verifyIndexes(db, number, exist)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
verify := func(db ethdb.Database, expTail uint64) {
|
|
||||||
tail := rawdb.ReadTxIndexTail(db)
|
|
||||||
if tail == nil {
|
|
||||||
t.Fatal("Failed to write tx index tail")
|
|
||||||
}
|
|
||||||
if *tail != expTail {
|
|
||||||
t.Fatalf("Unexpected tx index tail, want %v, got %d", expTail, *tail)
|
|
||||||
}
|
|
||||||
if *tail != 0 {
|
|
||||||
verifyRange(db, 0, *tail-1, false)
|
|
||||||
}
|
|
||||||
verifyRange(db, *tail, 128, true)
|
|
||||||
}
|
|
||||||
verifyProgress := func(chain *BlockChain) {
|
|
||||||
prog := chain.reportTxIndexProgress(128)
|
|
||||||
if !prog.Done() {
|
|
||||||
t.Fatalf("Expect fully indexed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var cases = []struct {
|
|
||||||
limitA uint64
|
|
||||||
tailA uint64
|
|
||||||
limitB uint64
|
|
||||||
tailB uint64
|
|
||||||
limitC uint64
|
|
||||||
tailC uint64
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
// LimitA: 0
|
|
||||||
// TailA: 0
|
|
||||||
//
|
|
||||||
// all blocks are indexed
|
|
||||||
limitA: 0,
|
|
||||||
tailA: 0,
|
|
||||||
|
|
||||||
// LimitB: 1
|
|
||||||
// TailB: 128
|
|
||||||
//
|
|
||||||
// block-128 is indexed
|
|
||||||
limitB: 1,
|
|
||||||
tailB: 128,
|
|
||||||
|
|
||||||
// LimitB: 64
|
|
||||||
// TailB: 65
|
|
||||||
//
|
|
||||||
// block [65, 128] are indexed
|
|
||||||
limitC: 64,
|
|
||||||
tailC: 65,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// LimitA: 64
|
|
||||||
// TailA: 65
|
|
||||||
//
|
|
||||||
// block [65, 128] are indexed
|
|
||||||
limitA: 64,
|
|
||||||
tailA: 65,
|
|
||||||
|
|
||||||
// LimitB: 1
|
|
||||||
// TailB: 128
|
|
||||||
//
|
|
||||||
// block-128 is indexed
|
|
||||||
limitB: 1,
|
|
||||||
tailB: 128,
|
|
||||||
|
|
||||||
// LimitB: 64
|
|
||||||
// TailB: 65
|
|
||||||
//
|
|
||||||
// block [65, 128] are indexed
|
|
||||||
limitC: 64,
|
|
||||||
tailC: 65,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// LimitA: 127
|
|
||||||
// TailA: 2
|
|
||||||
//
|
|
||||||
// block [2, 128] are indexed
|
|
||||||
limitA: 127,
|
|
||||||
tailA: 2,
|
|
||||||
|
|
||||||
// LimitB: 1
|
|
||||||
// TailB: 128
|
|
||||||
//
|
|
||||||
// block-128 is indexed
|
|
||||||
limitB: 1,
|
|
||||||
tailB: 128,
|
|
||||||
|
|
||||||
// LimitB: 64
|
|
||||||
// TailB: 65
|
|
||||||
//
|
|
||||||
// block [65, 128] are indexed
|
|
||||||
limitC: 64,
|
|
||||||
tailC: 65,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// LimitA: 128
|
|
||||||
// TailA: 1
|
|
||||||
//
|
|
||||||
// block [2, 128] are indexed
|
|
||||||
limitA: 128,
|
|
||||||
tailA: 1,
|
|
||||||
|
|
||||||
// LimitB: 1
|
|
||||||
// TailB: 128
|
|
||||||
//
|
|
||||||
// block-128 is indexed
|
|
||||||
limitB: 1,
|
|
||||||
tailB: 128,
|
|
||||||
|
|
||||||
// LimitB: 64
|
|
||||||
// TailB: 65
|
|
||||||
//
|
|
||||||
// block [65, 128] are indexed
|
|
||||||
limitC: 64,
|
|
||||||
tailC: 65,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// LimitA: 129
|
|
||||||
// TailA: 0
|
|
||||||
//
|
|
||||||
// block [0, 128] are indexed
|
|
||||||
limitA: 129,
|
|
||||||
tailA: 0,
|
|
||||||
|
|
||||||
// LimitB: 1
|
|
||||||
// TailB: 128
|
|
||||||
//
|
|
||||||
// block-128 is indexed
|
|
||||||
limitB: 1,
|
|
||||||
tailB: 128,
|
|
||||||
|
|
||||||
// LimitB: 64
|
|
||||||
// TailB: 65
|
|
||||||
//
|
|
||||||
// block [65, 128] are indexed
|
|
||||||
limitC: 64,
|
|
||||||
tailC: 65,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, c := range cases {
|
|
||||||
frdir := t.TempDir()
|
|
||||||
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
|
|
||||||
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0))
|
|
||||||
|
|
||||||
// Index the initial blocks from ancient store
|
|
||||||
chain, _ := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, &c.limitA)
|
|
||||||
chain.indexBlocks(nil, 128, make(chan struct{}))
|
|
||||||
verify(db, c.tailA)
|
|
||||||
verifyProgress(chain)
|
|
||||||
|
|
||||||
chain.SetTxLookupLimit(c.limitB)
|
|
||||||
chain.indexBlocks(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}))
|
|
||||||
verify(db, c.tailB)
|
|
||||||
verifyProgress(chain)
|
|
||||||
|
|
||||||
chain.SetTxLookupLimit(c.limitC)
|
|
||||||
chain.indexBlocks(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}))
|
|
||||||
verify(db, c.tailC)
|
|
||||||
verifyProgress(chain)
|
|
||||||
|
|
||||||
// Recover all indexes
|
|
||||||
chain.SetTxLookupLimit(0)
|
|
||||||
chain.indexBlocks(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}))
|
|
||||||
verify(db, 0)
|
|
||||||
verifyProgress(chain)
|
|
||||||
|
|
||||||
chain.Stop()
|
|
||||||
db.Close()
|
|
||||||
os.RemoveAll(frdir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateThenDeletePreByzantium(t *testing.T) {
|
func TestCreateThenDeletePreByzantium(t *testing.T) {
|
||||||
// We use Ropsten chain config instead of Testchain config, this is
|
// We use Ropsten chain config instead of Testchain config, this is
|
||||||
// deliberate: we want to use pre-byz rules where we have intermediate state roots
|
// deliberate: we want to use pre-byz rules where we have intermediate state roots
|
||||||
|
|
@ -4628,14 +4313,14 @@ func TestEIP3651(t *testing.T) {
|
||||||
state, _ := chain.State()
|
state, _ := chain.State()
|
||||||
|
|
||||||
// 3: Ensure that miner received only the tx's tip.
|
// 3: Ensure that miner received only the tx's tip.
|
||||||
actual := state.GetBalance(block.Coinbase())
|
actual := state.GetBalance(block.Coinbase()).ToBig()
|
||||||
expected := new(big.Int).SetUint64(block.GasUsed() * block.Transactions()[0].GasTipCap().Uint64())
|
expected := new(big.Int).SetUint64(block.GasUsed() * block.Transactions()[0].GasTipCap().Uint64())
|
||||||
if actual.Cmp(expected) != 0 {
|
if actual.Cmp(expected) != 0 {
|
||||||
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
|
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
|
// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
|
||||||
actual = new(big.Int).Sub(funds, state.GetBalance(addr1))
|
actual = new(big.Int).Sub(funds, state.GetBalance(addr1).ToBig())
|
||||||
expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64()))
|
expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64()))
|
||||||
if actual.Cmp(expected) != 0 {
|
if actual.Cmp(expected) != 0 {
|
||||||
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BlockGen creates blocks for testing.
|
// BlockGen creates blocks for testing.
|
||||||
|
|
@ -157,7 +158,7 @@ func (b *BlockGen) AddTxWithVMConfig(tx *types.Transaction, config vm.Config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBalance returns the balance of the given address at the generated block.
|
// 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)
|
return b.statedb.GetBalance(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ChainContext supports retrieving headers and consensus parameters from the
|
// ChainContext supports retrieving headers and consensus parameters from the
|
||||||
|
|
@ -129,12 +130,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.
|
// 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.
|
// 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
|
return db.GetBalance(addr).Cmp(amount) >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transfer subtracts amount from sender and adds amount to recipient using the given Db
|
// 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.SubBalance(sender, amount)
|
||||||
db.AddBalance(recipient, amount)
|
db.AddBalance(recipient, amount)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||||
|
"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 Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
|
||||||
|
|
@ -142,7 +143,7 @@ func (ga *GenesisAlloc) hash(isVerkle bool) (common.Hash, error) {
|
||||||
}
|
}
|
||||||
for addr, account := range *ga {
|
for addr, account := range *ga {
|
||||||
if account.Balance != nil {
|
if account.Balance != nil {
|
||||||
statedb.AddBalance(addr, account.Balance)
|
statedb.AddBalance(addr, uint256.MustFromBig(account.Balance))
|
||||||
}
|
}
|
||||||
statedb.SetCode(addr, account.Code)
|
statedb.SetCode(addr, account.Code)
|
||||||
statedb.SetNonce(addr, account.Nonce)
|
statedb.SetNonce(addr, account.Nonce)
|
||||||
|
|
@ -163,7 +164,7 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas
|
||||||
}
|
}
|
||||||
for addr, account := range *ga {
|
for addr, account := range *ga {
|
||||||
if account.Balance != nil {
|
if account.Balance != nil {
|
||||||
statedb.AddBalance(addr, account.Balance)
|
statedb.AddBalance(addr, uint256.MustFromBig(account.Balance))
|
||||||
}
|
}
|
||||||
statedb.SetCode(addr, account.Code)
|
statedb.SetCode(addr, account.Code)
|
||||||
statedb.SetNonce(addr, account.Nonce)
|
statedb.SetNonce(addr, account.Nonce)
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,8 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// journalEntry is a modification entry in the state change journal that can be
|
// journalEntry is a modification entry in the state change journal that can be
|
||||||
|
|
@ -103,13 +102,13 @@ type (
|
||||||
selfDestructChange struct {
|
selfDestructChange struct {
|
||||||
account *common.Address
|
account *common.Address
|
||||||
prev bool // whether account had already self-destructed
|
prev bool // whether account had already self-destructed
|
||||||
prevbalance *big.Int
|
prevbalance *uint256.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes to individual accounts.
|
// Changes to individual accounts.
|
||||||
balanceChange struct {
|
balanceChange struct {
|
||||||
account *common.Address
|
account *common.Address
|
||||||
prev *big.Int
|
prev *uint256.Int
|
||||||
}
|
}
|
||||||
nonceChange struct {
|
nonceChange struct {
|
||||||
account *common.Address
|
account *common.Address
|
||||||
|
|
|
||||||
|
|
@ -27,17 +27,10 @@ import (
|
||||||
bloomfilter "github.com/holiman/bloomfilter/v2"
|
bloomfilter "github.com/holiman/bloomfilter/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// stateBloomHasher is a wrapper around a byte blob to satisfy the interface API
|
// stateBloomHash is used to convert a trie hash or contract code hash into a 64 bit mini hash.
|
||||||
// requirements of the bloom library used. It's used to convert a trie hash or
|
func stateBloomHash(f []byte) uint64 {
|
||||||
// contract code hash into a 64 bit mini hash.
|
return binary.BigEndian.Uint64(f)
|
||||||
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) }
|
|
||||||
|
|
||||||
// stateBloom is a bloom filter used during the state conversion(snapshot->state).
|
// 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
|
// The keys of all generated entries will be recorded here so that in the pruning
|
||||||
|
|
@ -113,10 +106,10 @@ func (bloom *stateBloom) Put(key []byte, value []byte) error {
|
||||||
if !isCode {
|
if !isCode {
|
||||||
return errors.New("invalid entry")
|
return errors.New("invalid entry")
|
||||||
}
|
}
|
||||||
bloom.bloom.Add(stateBloomHasher(codeKey))
|
bloom.bloom.AddHash(stateBloomHash(codeKey))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
bloom.bloom.Add(stateBloomHasher(key))
|
bloom.bloom.AddHash(stateBloomHash(key))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,5 +121,5 @@ func (bloom *stateBloom) Delete(key []byte) error { panic("not supported") }
|
||||||
// - If it says yes, the key may be contained
|
// - If it says yes, the key may be contained
|
||||||
// - If it says no, the key is definitely not contained.
|
// - If it says no, the key is definitely not contained.
|
||||||
func (bloom *stateBloom) Contain(key []byte) bool {
|
func (bloom *stateBloom) Contain(key []byte) bool {
|
||||||
return bloom.bloom.Contains(stateBloomHasher(key))
|
return bloom.bloom.ContainsHash(stateBloomHash(key))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,47 +124,20 @@ type diffLayer struct {
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// destructBloomHasher is a wrapper around a common.Hash to satisfy the interface
|
// destructBloomHash is used to convert a destruct event into a 64 bit mini hash.
|
||||||
// API requirements of the bloom library used. It's used to convert a destruct
|
func destructBloomHash(h common.Hash) uint64 {
|
||||||
// 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 {
|
|
||||||
return binary.BigEndian.Uint64(h[bloomDestructHasherOffset : bloomDestructHasherOffset+8])
|
return binary.BigEndian.Uint64(h[bloomDestructHasherOffset : bloomDestructHasherOffset+8])
|
||||||
}
|
}
|
||||||
|
|
||||||
// accountBloomHasher is a wrapper around a common.Hash to satisfy the interface
|
// accountBloomHash is used to convert an account hash into a 64 bit mini hash.
|
||||||
// API requirements of the bloom library used. It's used to convert an account
|
func accountBloomHash(h common.Hash) uint64 {
|
||||||
// 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 {
|
|
||||||
return binary.BigEndian.Uint64(h[bloomAccountHasherOffset : bloomAccountHasherOffset+8])
|
return binary.BigEndian.Uint64(h[bloomAccountHasherOffset : bloomAccountHasherOffset+8])
|
||||||
}
|
}
|
||||||
|
|
||||||
// storageBloomHasher is a wrapper around a [2]common.Hash to satisfy the interface
|
// storageBloomHash is used to convert an account hash and a storage hash into a 64 bit mini hash.
|
||||||
// API requirements of the bloom library used. It's used to convert an account
|
func storageBloomHash(h0, h1 common.Hash) uint64 {
|
||||||
// hash into a 64 bit mini hash.
|
return binary.BigEndian.Uint64(h0[bloomStorageHasherOffset:bloomStorageHasherOffset+8]) ^
|
||||||
type storageBloomHasher [2]common.Hash
|
binary.BigEndian.Uint64(h1[bloomStorageHasherOffset:bloomStorageHasherOffset+8])
|
||||||
|
|
||||||
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])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// newDiffLayer creates a new diff on top of an existing snapshot, whether that's a low
|
// newDiffLayer creates a new diff on top of an existing snapshot, whether that's a low
|
||||||
|
|
@ -233,14 +206,14 @@ func (dl *diffLayer) rebloom(origin *diskLayer) {
|
||||||
}
|
}
|
||||||
// Iterate over all the accounts and storage slots and index them
|
// Iterate over all the accounts and storage slots and index them
|
||||||
for hash := range dl.destructSet {
|
for hash := range dl.destructSet {
|
||||||
dl.diffed.Add(destructBloomHasher(hash))
|
dl.diffed.AddHash(destructBloomHash(hash))
|
||||||
}
|
}
|
||||||
for hash := range dl.accountData {
|
for hash := range dl.accountData {
|
||||||
dl.diffed.Add(accountBloomHasher(hash))
|
dl.diffed.AddHash(accountBloomHash(hash))
|
||||||
}
|
}
|
||||||
for accountHash, slots := range dl.storageData {
|
for accountHash, slots := range dl.storageData {
|
||||||
for storageHash := range slots {
|
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.
|
// Calculate the current false positive rate and update the error rate meter.
|
||||||
|
|
@ -301,9 +274,9 @@ func (dl *diffLayer) AccountRLP(hash common.Hash) ([]byte, error) {
|
||||||
}
|
}
|
||||||
// Check the bloom filter first whether there's even a point in reaching into
|
// Check the bloom filter first whether there's even a point in reaching into
|
||||||
// all the maps in all the layers below
|
// all the maps in all the layers below
|
||||||
hit := dl.diffed.Contains(accountBloomHasher(hash))
|
hit := dl.diffed.ContainsHash(accountBloomHash(hash))
|
||||||
if !hit {
|
if !hit {
|
||||||
hit = dl.diffed.Contains(destructBloomHasher(hash))
|
hit = dl.diffed.ContainsHash(destructBloomHash(hash))
|
||||||
}
|
}
|
||||||
var origin *diskLayer
|
var origin *diskLayer
|
||||||
if !hit {
|
if !hit {
|
||||||
|
|
@ -372,9 +345,9 @@ func (dl *diffLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro
|
||||||
dl.lock.RUnlock()
|
dl.lock.RUnlock()
|
||||||
return nil, ErrSnapshotStale
|
return nil, ErrSnapshotStale
|
||||||
}
|
}
|
||||||
hit := dl.diffed.Contains(storageBloomHasher{accountHash, storageHash})
|
hit := dl.diffed.ContainsHash(storageBloomHash(accountHash, storageHash))
|
||||||
if !hit {
|
if !hit {
|
||||||
hit = dl.diffed.Contains(destructBloomHasher(accountHash))
|
hit = dl.diffed.ContainsHash(destructBloomHash(accountHash))
|
||||||
}
|
}
|
||||||
var origin *diskLayer
|
var origin *diskLayer
|
||||||
if !hit {
|
if !hit {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package snapshot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -33,6 +32,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -58,9 +58,9 @@ func testGeneration(t *testing.T, scheme string) {
|
||||||
var helper = newHelper(scheme)
|
var helper = newHelper(scheme)
|
||||||
stRoot := helper.makeStorageTrie(common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, false)
|
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-1", &types.StateAccount{Balance: uint256.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-2", &types.StateAccount{Balance: uint256.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-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-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)
|
helper.makeStorageTrie(hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||||
|
|
@ -97,16 +97,16 @@ func testGenerateExistentState(t *testing.T, scheme string) {
|
||||||
var helper = newHelper(scheme)
|
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)
|
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-1", &types.StateAccount{Balance: uint256.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.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.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.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.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.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)
|
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.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.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.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"})
|
helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||||
|
|
||||||
root, snap := helper.CommitAndGenerate()
|
root, snap := helper.CommitAndGenerate()
|
||||||
|
|
@ -259,28 +259,28 @@ func testGenerateExistentStateWithWrongStorage(t *testing.T, scheme string) {
|
||||||
helper := newHelper(scheme)
|
helper := newHelper(scheme)
|
||||||
|
|
||||||
// Account one, empty root but non-empty database
|
// 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"})
|
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
|
// 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)
|
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
|
// Miss slots
|
||||||
{
|
{
|
||||||
// Account three, non empty root but misses slots in the beginning
|
// 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.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"})
|
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
|
// 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.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"})
|
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
|
// 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.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"})
|
helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -288,22 +288,22 @@ func testGenerateExistentStateWithWrongStorage(t *testing.T, scheme string) {
|
||||||
{
|
{
|
||||||
// Account six, non empty root but wrong slots in the beginning
|
// 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.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"})
|
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
|
// 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.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"})
|
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
|
// 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.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"})
|
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
|
// 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.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"})
|
helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -311,17 +311,17 @@ func testGenerateExistentStateWithWrongStorage(t *testing.T, scheme string) {
|
||||||
{
|
{
|
||||||
// Account 10, non empty root but extra slots in the beginning
|
// 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.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"})
|
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
|
// 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.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"})
|
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
|
// 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.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"})
|
helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -366,25 +366,25 @@ func testGenerateExistentStateWithWrongAccounts(t *testing.T, scheme string) {
|
||||||
|
|
||||||
// Missing accounts, only in the trie
|
// 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-1", &types.StateAccount{Balance: uint256.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-4", &types.StateAccount{Balance: uint256.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-6", &types.StateAccount{Balance: uint256.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // End
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrong accounts
|
// Wrong accounts
|
||||||
{
|
{
|
||||||
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
helper.addTrieAccount("acc-2", &types.StateAccount{Balance: uint256.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.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.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.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.addSnapAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra accounts, only in the snap
|
// 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-0", &types.StateAccount{Balance: uint256.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-5", &types.StateAccount{Balance: uint256.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-7", &types.StateAccount{Balance: uint256.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // after the end
|
||||||
}
|
}
|
||||||
|
|
||||||
root, snap := helper.CommitAndGenerate()
|
root, snap := helper.CommitAndGenerate()
|
||||||
|
|
@ -418,9 +418,9 @@ func testGenerateCorruptAccountTrie(t *testing.T, scheme string) {
|
||||||
// without any storage slots to keep the test smaller.
|
// without any storage slots to keep the test smaller.
|
||||||
helper := newHelper(scheme)
|
helper := newHelper(scheme)
|
||||||
|
|
||||||
helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074
|
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: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
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: big.NewInt(3), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4
|
helper.addTrieAccount("acc-3", &types.StateAccount{Balance: uint256.NewInt(3), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4
|
||||||
|
|
||||||
root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978
|
root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978
|
||||||
|
|
||||||
|
|
@ -462,11 +462,11 @@ func testGenerateMissingStorageTrie(t *testing.T, scheme string) {
|
||||||
acc3 = hashData([]byte("acc-3"))
|
acc3 = hashData([]byte("acc-3"))
|
||||||
helper = newHelper(scheme)
|
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
|
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-1", &types.StateAccount{Balance: uint256.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
|
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)
|
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()
|
root := helper.Commit()
|
||||||
|
|
||||||
|
|
@ -502,11 +502,11 @@ func testGenerateCorruptStorageTrie(t *testing.T, scheme string) {
|
||||||
// two of which also has the same 3-slot storage trie attached.
|
// two of which also has the same 3-slot storage trie attached.
|
||||||
helper := newHelper(scheme)
|
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
|
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-1", &types.StateAccount{Balance: uint256.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
|
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)
|
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()
|
root := helper.Commit()
|
||||||
|
|
||||||
|
|
@ -546,7 +546,7 @@ func testGenerateWithExtraAccounts(t *testing.T, scheme string) {
|
||||||
[]string{"val-1", "val-2", "val-3", "val-4", "val-5"},
|
[]string{"val-1", "val-2", "val-3", "val-4", "val-5"},
|
||||||
true,
|
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)
|
val, _ := rlp.EncodeToBytes(acc)
|
||||||
helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||||
|
|
||||||
|
|
@ -566,7 +566,7 @@ func testGenerateWithExtraAccounts(t *testing.T, scheme string) {
|
||||||
[]string{"val-1", "val-2", "val-3", "val-4", "val-5"},
|
[]string{"val-1", "val-2", "val-3", "val-4", "val-5"},
|
||||||
true,
|
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)
|
val, _ := rlp.EncodeToBytes(acc)
|
||||||
key := hashData([]byte("acc-2"))
|
key := hashData([]byte("acc-2"))
|
||||||
rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
|
rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
|
||||||
|
|
@ -622,7 +622,7 @@ func testGenerateWithManyExtraAccounts(t *testing.T, scheme string) {
|
||||||
[]string{"val-1", "val-2", "val-3"},
|
[]string{"val-1", "val-2", "val-3"},
|
||||||
true,
|
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)
|
val, _ := rlp.EncodeToBytes(acc)
|
||||||
helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||||
|
|
||||||
|
|
@ -636,7 +636,7 @@ func testGenerateWithManyExtraAccounts(t *testing.T, scheme string) {
|
||||||
{
|
{
|
||||||
// 100 accounts exist only in snapshot
|
// 100 accounts exist only in snapshot
|
||||||
for i := 0; i < 1000; i++ {
|
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)
|
val, _ := rlp.EncodeToBytes(acc)
|
||||||
key := hashData([]byte(fmt.Sprintf("acc-%d", i)))
|
key := hashData([]byte(fmt.Sprintf("acc-%d", i)))
|
||||||
rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
|
rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
|
||||||
|
|
@ -678,7 +678,7 @@ func testGenerateWithExtraBeforeAndAfter(t *testing.T, scheme string) {
|
||||||
}
|
}
|
||||||
helper := newHelper(scheme)
|
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)
|
val, _ := rlp.EncodeToBytes(acc)
|
||||||
helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val)
|
helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val)
|
||||||
helper.accTrie.MustUpdate(common.HexToHash("0x07").Bytes(), val)
|
helper.accTrie.MustUpdate(common.HexToHash("0x07").Bytes(), val)
|
||||||
|
|
@ -720,7 +720,7 @@ func testGenerateWithMalformedSnapdata(t *testing.T, scheme string) {
|
||||||
}
|
}
|
||||||
helper := newHelper(scheme)
|
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)
|
val, _ := rlp.EncodeToBytes(acc)
|
||||||
helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val)
|
helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val)
|
||||||
|
|
||||||
|
|
@ -764,7 +764,7 @@ func testGenerateFromEmptySnap(t *testing.T, scheme string) {
|
||||||
for i := 0; i < 400; i++ {
|
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)
|
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),
|
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()
|
root, snap := helper.CommitAndGenerate()
|
||||||
t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4
|
t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4
|
||||||
|
|
@ -806,7 +806,7 @@ func testGenerateWithIncompleteStorage(t *testing.T, scheme string) {
|
||||||
for i := 0; i < 8; i++ {
|
for i := 0; i < 8; i++ {
|
||||||
accKey := fmt.Sprintf("acc-%d", i)
|
accKey := fmt.Sprintf("acc-%d", i)
|
||||||
stRoot := helper.makeStorageTrie(hashData([]byte(accKey)), stKeys, stVals, true)
|
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 moddedKeys []string
|
||||||
var moddedVals []string
|
var moddedVals []string
|
||||||
for ii := 0; ii < 8; ii++ {
|
for ii := 0; ii < 8; ii++ {
|
||||||
|
|
@ -903,11 +903,11 @@ func testGenerateCompleteSnapshotWithDanglingStorage(t *testing.T, scheme string
|
||||||
var helper = newHelper(scheme)
|
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)
|
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-1", &types.StateAccount{Balance: uint256.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-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.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-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"})
|
helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||||
|
|
@ -943,11 +943,11 @@ func testGenerateBrokenSnapshotWithDanglingStorage(t *testing.T, scheme string)
|
||||||
var helper = newHelper(scheme)
|
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)
|
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-1", &types.StateAccount{Balance: uint256.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-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.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)
|
populateDangling(helper.diskdb)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import (
|
||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -30,6 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// randomHash generates a random blob of data and returns it as a hash.
|
// randomHash generates a random blob of data and returns it as a hash.
|
||||||
|
|
@ -44,7 +44,7 @@ func randomHash() common.Hash {
|
||||||
// randomAccount generates a random account and returns it RLP encoded.
|
// randomAccount generates a random account and returns it RLP encoded.
|
||||||
func randomAccount() []byte {
|
func randomAccount() []byte {
|
||||||
a := &types.StateAccount{
|
a := &types.StateAccount{
|
||||||
Balance: big.NewInt(rand.Int63()),
|
Balance: uint256.NewInt(rand.Uint64()),
|
||||||
Nonce: rand.Uint64(),
|
Nonce: rand.Uint64(),
|
||||||
Root: randomHash(),
|
Root: randomHash(),
|
||||||
CodeHash: types.EmptyCodeHash[:],
|
CodeHash: types.EmptyCodeHash[:],
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -29,6 +28,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Code []byte
|
type Code []byte
|
||||||
|
|
@ -405,7 +405,7 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) {
|
||||||
|
|
||||||
// AddBalance adds amount to s's balance.
|
// AddBalance adds amount to s's balance.
|
||||||
// It is used to add funds to the destination account of a transfer.
|
// 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
|
// EIP161: We must check emptiness for the objects such that the account
|
||||||
// clearing (0,0,0 objects) can take effect.
|
// clearing (0,0,0 objects) can take effect.
|
||||||
if amount.Sign() == 0 {
|
if amount.Sign() == 0 {
|
||||||
|
|
@ -414,27 +414,27 @@ func (s *stateObject) AddBalance(amount *big.Int) {
|
||||||
}
|
}
|
||||||
return
|
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.
|
// SubBalance removes amount from s's balance.
|
||||||
// It is used to remove funds from the origin account of a transfer.
|
// It is used to remove funds from the origin account of a transfer.
|
||||||
func (s *stateObject) SubBalance(amount *big.Int) {
|
func (s *stateObject) SubBalance(amount *uint256.Int) {
|
||||||
if amount.Sign() == 0 {
|
if amount.Sign() == 0 {
|
||||||
return
|
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{
|
s.db.journal.append(balanceChange{
|
||||||
account: &s.address,
|
account: &s.address,
|
||||||
prev: new(big.Int).Set(s.data.Balance),
|
prev: new(uint256.Int).Set(s.data.Balance),
|
||||||
})
|
})
|
||||||
s.setBalance(amount)
|
s.setBalance(amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateObject) setBalance(amount *big.Int) {
|
func (s *stateObject) setBalance(amount *uint256.Int) {
|
||||||
s.data.Balance = amount
|
s.data.Balance = amount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -533,7 +533,7 @@ func (s *stateObject) CodeHash() []byte {
|
||||||
return s.data.CodeHash
|
return s.data.CodeHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateObject) Balance() *big.Int {
|
func (s *stateObject) Balance() *uint256.Int {
|
||||||
return s.data.Balance
|
return s.data.Balance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ package state
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/big"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -28,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
type stateEnv struct {
|
type stateEnv struct {
|
||||||
|
|
@ -49,11 +49,11 @@ func TestDump(t *testing.T) {
|
||||||
|
|
||||||
// generate a few entries
|
// generate a few entries
|
||||||
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
||||||
obj1.AddBalance(big.NewInt(22))
|
obj1.AddBalance(uint256.NewInt(22))
|
||||||
obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
|
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})
|
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 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02}))
|
||||||
obj3.SetBalance(big.NewInt(44))
|
obj3.SetBalance(uint256.NewInt(44))
|
||||||
|
|
||||||
// write some of them to the trie
|
// write some of them to the trie
|
||||||
s.state.updateStateObject(obj1)
|
s.state.updateStateObject(obj1)
|
||||||
|
|
@ -106,13 +106,13 @@ func TestIterativeDump(t *testing.T) {
|
||||||
|
|
||||||
// generate a few entries
|
// generate a few entries
|
||||||
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
||||||
obj1.AddBalance(big.NewInt(22))
|
obj1.AddBalance(uint256.NewInt(22))
|
||||||
obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
|
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})
|
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 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02}))
|
||||||
obj3.SetBalance(big.NewInt(44))
|
obj3.SetBalance(uint256.NewInt(44))
|
||||||
obj4 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x00}))
|
obj4 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x00}))
|
||||||
obj4.AddBalance(big.NewInt(1337))
|
obj4.AddBalance(uint256.NewInt(1337))
|
||||||
|
|
||||||
// write some of them to the trie
|
// write some of them to the trie
|
||||||
s.state.updateStateObject(obj1)
|
s.state.updateStateObject(obj1)
|
||||||
|
|
@ -208,7 +208,7 @@ func TestSnapshot2(t *testing.T) {
|
||||||
|
|
||||||
// db, trie are already non-empty values
|
// db, trie are already non-empty values
|
||||||
so0 := state.getStateObject(stateobjaddr0)
|
so0 := state.getStateObject(stateobjaddr0)
|
||||||
so0.SetBalance(big.NewInt(42))
|
so0.SetBalance(uint256.NewInt(42))
|
||||||
so0.SetNonce(43)
|
so0.SetNonce(43)
|
||||||
so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
|
so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
|
||||||
so0.selfDestructed = false
|
so0.selfDestructed = false
|
||||||
|
|
@ -220,7 +220,7 @@ func TestSnapshot2(t *testing.T) {
|
||||||
|
|
||||||
// and one with deleted == true
|
// and one with deleted == true
|
||||||
so1 := state.getStateObject(stateobjaddr1)
|
so1 := state.getStateObject(stateobjaddr1)
|
||||||
so1.SetBalance(big.NewInt(52))
|
so1.SetBalance(uint256.NewInt(52))
|
||||||
so1.SetNonce(53)
|
so1.SetNonce(53)
|
||||||
so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'})
|
so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'})
|
||||||
so1.selfDestructed = true
|
so1.selfDestructed = true
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -34,6 +33,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
"github.com/ethereum/go-ethereum/trie/triestate"
|
"github.com/ethereum/go-ethereum/trie/triestate"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -280,12 +280,12 @@ func (s *StateDB) Empty(addr common.Address) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBalance retrieves the balance from the given address or 0 if object not found
|
// 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)
|
stateObject := s.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.Balance()
|
return stateObject.Balance()
|
||||||
}
|
}
|
||||||
return common.Big0
|
return common.U2560
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNonce retrieves the nonce from the given address or 0 if object not found
|
// GetNonce retrieves the nonce from the given address or 0 if object not found
|
||||||
|
|
@ -373,7 +373,7 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// AddBalance adds amount to the account associated with addr.
|
// AddBalance adds amount to the account associated with addr.
|
||||||
func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int) {
|
||||||
stateObject := s.getOrNewStateObject(addr)
|
stateObject := s.getOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.AddBalance(amount)
|
stateObject.AddBalance(amount)
|
||||||
|
|
@ -381,14 +381,14 @@ func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubBalance subtracts amount from the account associated with addr.
|
// SubBalance subtracts amount from the account associated with addr.
|
||||||
func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) {
|
func (s *StateDB) SubBalance(addr common.Address, amount *uint256.Int) {
|
||||||
stateObject := s.getOrNewStateObject(addr)
|
stateObject := s.getOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.SubBalance(amount)
|
stateObject.SubBalance(amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) SetBalance(addr common.Address, amount *big.Int) {
|
func (s *StateDB) SetBalance(addr common.Address, amount *uint256.Int) {
|
||||||
stateObject := s.getOrNewStateObject(addr)
|
stateObject := s.getOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.SetBalance(amount)
|
stateObject.SetBalance(amount)
|
||||||
|
|
@ -450,10 +450,10 @@ func (s *StateDB) SelfDestruct(addr common.Address) {
|
||||||
s.journal.append(selfDestructChange{
|
s.journal.append(selfDestructChange{
|
||||||
account: &addr,
|
account: &addr,
|
||||||
prev: stateObject.selfDestructed,
|
prev: stateObject.selfDestructed,
|
||||||
prevbalance: new(big.Int).Set(stateObject.Balance()),
|
prevbalance: new(uint256.Int).Set(stateObject.Balance()),
|
||||||
})
|
})
|
||||||
stateObject.markSelfdestructed()
|
stateObject.markSelfdestructed()
|
||||||
stateObject.data.Balance = new(big.Int)
|
stateObject.data.Balance = new(uint256.Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) Selfdestruct6780(addr common.Address) {
|
func (s *StateDB) Selfdestruct6780(addr common.Address) {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -38,6 +37,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||||
"github.com/ethereum/go-ethereum/trie/triestate"
|
"github.com/ethereum/go-ethereum/trie/triestate"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A stateTest checks that the state changes are correctly captured. Instances
|
// A stateTest checks that the state changes are correctly captured. Instances
|
||||||
|
|
@ -60,7 +60,7 @@ func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction
|
||||||
{
|
{
|
||||||
name: "SetBalance",
|
name: "SetBalance",
|
||||||
fn: func(a testAction, s *StateDB) {
|
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),
|
args: make([]int64, 1),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -56,7 +55,7 @@ func TestUpdateLeaks(t *testing.T) {
|
||||||
// Update it with some accounts
|
// Update it with some accounts
|
||||||
for i := byte(0); i < 255; i++ {
|
for i := byte(0); i < 255; i++ {
|
||||||
addr := common.BytesToAddress([]byte{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))
|
state.SetNonce(addr, uint64(42*i))
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i}))
|
state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i}))
|
||||||
|
|
@ -91,7 +90,7 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||||
finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil)
|
finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil)
|
||||||
|
|
||||||
modify := func(state *StateDB, addr common.Address, i, tweak byte) {
|
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))
|
state.SetNonce(addr, uint64(42*i+tweak))
|
||||||
if i%2 == 0 {
|
if i%2 == 0 {
|
||||||
state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{})
|
state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{})
|
||||||
|
|
@ -167,7 +166,7 @@ func TestCopy(t *testing.T) {
|
||||||
|
|
||||||
for i := byte(0); i < 255; i++ {
|
for i := byte(0); i < 255; i++ {
|
||||||
obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||||
obj.AddBalance(big.NewInt(int64(i)))
|
obj.AddBalance(uint256.NewInt(uint64(i)))
|
||||||
orig.updateStateObject(obj)
|
orig.updateStateObject(obj)
|
||||||
}
|
}
|
||||||
orig.Finalise(false)
|
orig.Finalise(false)
|
||||||
|
|
@ -184,9 +183,9 @@ func TestCopy(t *testing.T) {
|
||||||
copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||||
ccopyObj := ccopy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
ccopyObj := ccopy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||||
|
|
||||||
origObj.AddBalance(big.NewInt(2 * int64(i)))
|
origObj.AddBalance(uint256.NewInt(2 * uint64(i)))
|
||||||
copyObj.AddBalance(big.NewInt(3 * int64(i)))
|
copyObj.AddBalance(uint256.NewInt(3 * uint64(i)))
|
||||||
ccopyObj.AddBalance(big.NewInt(4 * int64(i)))
|
ccopyObj.AddBalance(uint256.NewInt(4 * uint64(i)))
|
||||||
|
|
||||||
orig.updateStateObject(origObj)
|
orig.updateStateObject(origObj)
|
||||||
copy.updateStateObject(copyObj)
|
copy.updateStateObject(copyObj)
|
||||||
|
|
@ -212,13 +211,13 @@ func TestCopy(t *testing.T) {
|
||||||
copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||||
ccopyObj := ccopy.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)
|
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)
|
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)
|
t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, ccopyObj.Balance(), want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -266,14 +265,14 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
|
||||||
{
|
{
|
||||||
name: "SetBalance",
|
name: "SetBalance",
|
||||||
fn: func(a testAction, s *StateDB) {
|
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),
|
args: make([]int64, 1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "AddBalance",
|
name: "AddBalance",
|
||||||
fn: func(a testAction, s *StateDB) {
|
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),
|
args: make([]int64, 1),
|
||||||
},
|
},
|
||||||
|
|
@ -536,7 +535,7 @@ func TestTouchDelete(t *testing.T) {
|
||||||
s.state, _ = New(root, s.state.db, s.state.snaps)
|
s.state, _ = New(root, s.state.db, s.state.snaps)
|
||||||
|
|
||||||
snapshot := s.state.Snapshot()
|
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 {
|
if len(s.state.journal.dirties) != 1 {
|
||||||
t.Fatal("expected one dirty state object")
|
t.Fatal("expected one dirty state object")
|
||||||
|
|
@ -552,7 +551,7 @@ func TestTouchDelete(t *testing.T) {
|
||||||
func TestCopyOfCopy(t *testing.T) {
|
func TestCopyOfCopy(t *testing.T) {
|
||||||
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||||
addr := common.HexToAddress("aaaa")
|
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 {
|
if got := state.Copy().GetBalance(addr).Uint64(); got != 42 {
|
||||||
t.Fatalf("1st copy fail, expected 42, got %v", got)
|
t.Fatalf("1st copy fail, expected 42, got %v", got)
|
||||||
|
|
@ -575,11 +574,11 @@ func TestCopyCommitCopy(t *testing.T) {
|
||||||
skey := common.HexToHash("aaa")
|
skey := common.HexToHash("aaa")
|
||||||
sval := common.HexToHash("bbb")
|
sval := common.HexToHash("bbb")
|
||||||
|
|
||||||
state.SetBalance(addr, big.NewInt(42)) // Change the account trie
|
state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie
|
||||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||||
state.SetState(addr, skey, sval) // Change the storage trie
|
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)
|
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
|
||||||
}
|
}
|
||||||
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||||
|
|
@ -593,7 +592,7 @@ func TestCopyCommitCopy(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Copy the non-committed state database and check pre/post commit balance
|
// Copy the non-committed state database and check pre/post commit balance
|
||||||
copyOne := state.Copy()
|
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)
|
t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42)
|
||||||
}
|
}
|
||||||
if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||||
|
|
@ -607,7 +606,7 @@ func TestCopyCommitCopy(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Copy the copy and check the balance once more
|
// Copy the copy and check the balance once more
|
||||||
copyTwo := copyOne.Copy()
|
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)
|
t.Fatalf("second copy balance mismatch: have %v, want %v", balance, 42)
|
||||||
}
|
}
|
||||||
if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||||
|
|
@ -622,7 +621,7 @@ func TestCopyCommitCopy(t *testing.T) {
|
||||||
// Commit state, ensure states can be loaded from disk
|
// Commit state, ensure states can be loaded from disk
|
||||||
root, _ := state.Commit(0, false)
|
root, _ := state.Commit(0, false)
|
||||||
state, _ = New(root, tdb, nil)
|
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)
|
t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42)
|
||||||
}
|
}
|
||||||
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||||
|
|
@ -648,11 +647,11 @@ func TestCopyCopyCommitCopy(t *testing.T) {
|
||||||
skey := common.HexToHash("aaa")
|
skey := common.HexToHash("aaa")
|
||||||
sval := common.HexToHash("bbb")
|
sval := common.HexToHash("bbb")
|
||||||
|
|
||||||
state.SetBalance(addr, big.NewInt(42)) // Change the account trie
|
state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie
|
||||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||||
state.SetState(addr, skey, sval) // Change the storage trie
|
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)
|
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
|
||||||
}
|
}
|
||||||
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||||
|
|
@ -666,7 +665,7 @@ func TestCopyCopyCommitCopy(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Copy the non-committed state database and check pre/post commit balance
|
// Copy the non-committed state database and check pre/post commit balance
|
||||||
copyOne := state.Copy()
|
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)
|
t.Fatalf("first copy balance mismatch: have %v, want %v", balance, 42)
|
||||||
}
|
}
|
||||||
if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||||
|
|
@ -680,7 +679,7 @@ func TestCopyCopyCommitCopy(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Copy the copy and check the balance once more
|
// Copy the copy and check the balance once more
|
||||||
copyTwo := copyOne.Copy()
|
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)
|
t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42)
|
||||||
}
|
}
|
||||||
if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||||
|
|
@ -694,7 +693,7 @@ func TestCopyCopyCommitCopy(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Copy the copy-copy and check the balance once more
|
// Copy the copy-copy and check the balance once more
|
||||||
copyThree := copyTwo.Copy()
|
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)
|
t.Fatalf("third copy balance mismatch: have %v, want %v", balance, 42)
|
||||||
}
|
}
|
||||||
if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||||
|
|
@ -717,11 +716,11 @@ func TestCommitCopy(t *testing.T) {
|
||||||
skey := common.HexToHash("aaa")
|
skey := common.HexToHash("aaa")
|
||||||
sval := common.HexToHash("bbb")
|
sval := common.HexToHash("bbb")
|
||||||
|
|
||||||
state.SetBalance(addr, big.NewInt(42)) // Change the account trie
|
state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie
|
||||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||||
state.SetState(addr, skey, sval) // Change the storage trie
|
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)
|
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
|
||||||
}
|
}
|
||||||
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
|
||||||
|
|
@ -736,7 +735,7 @@ func TestCommitCopy(t *testing.T) {
|
||||||
// Copy the committed state database, the copied one is not functional.
|
// Copy the committed state database, the copied one is not functional.
|
||||||
state.Commit(0, true)
|
state.Commit(0, true)
|
||||||
copied := state.Copy()
|
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)
|
t.Fatalf("unexpected balance: have %v", balance)
|
||||||
}
|
}
|
||||||
if code := copied.GetCode(addr); code != nil {
|
if code := copied.GetCode(addr); code != nil {
|
||||||
|
|
@ -766,7 +765,7 @@ func TestDeleteCreateRevert(t *testing.T) {
|
||||||
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||||
|
|
||||||
addr := common.BytesToAddress([]byte("so"))
|
addr := common.BytesToAddress([]byte("so"))
|
||||||
state.SetBalance(addr, big.NewInt(1))
|
state.SetBalance(addr, uint256.NewInt(1))
|
||||||
|
|
||||||
root, _ := state.Commit(0, false)
|
root, _ := state.Commit(0, false)
|
||||||
state, _ = New(root, state.db, state.snaps)
|
state, _ = New(root, state.db, state.snaps)
|
||||||
|
|
@ -776,7 +775,7 @@ func TestDeleteCreateRevert(t *testing.T) {
|
||||||
state.Finalise(true)
|
state.Finalise(true)
|
||||||
|
|
||||||
id := state.Snapshot()
|
id := state.Snapshot()
|
||||||
state.SetBalance(addr, big.NewInt(2))
|
state.SetBalance(addr, uint256.NewInt(2))
|
||||||
state.RevertToSnapshot(id)
|
state.RevertToSnapshot(id)
|
||||||
|
|
||||||
// Commit the entire state and make sure we don't crash and have the correct state
|
// Commit the entire state and make sure we don't crash and have the correct state
|
||||||
|
|
@ -818,10 +817,10 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
|
||||||
state, _ := New(types.EmptyRootHash, db, nil)
|
state, _ := New(types.EmptyRootHash, db, nil)
|
||||||
addr := common.BytesToAddress([]byte("so"))
|
addr := common.BytesToAddress([]byte("so"))
|
||||||
{
|
{
|
||||||
state.SetBalance(addr, big.NewInt(1))
|
state.SetBalance(addr, uint256.NewInt(1))
|
||||||
state.SetCode(addr, []byte{1, 2, 3})
|
state.SetCode(addr, []byte{1, 2, 3})
|
||||||
a2 := common.BytesToAddress([]byte("another"))
|
a2 := common.BytesToAddress([]byte("another"))
|
||||||
state.SetBalance(a2, big.NewInt(100))
|
state.SetBalance(a2, uint256.NewInt(100))
|
||||||
state.SetCode(a2, []byte{1, 2, 4})
|
state.SetCode(a2, []byte{1, 2, 4})
|
||||||
root, _ = state.Commit(0, false)
|
root, _ = state.Commit(0, false)
|
||||||
t.Logf("root: %x", root)
|
t.Logf("root: %x", root)
|
||||||
|
|
@ -846,7 +845,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
|
||||||
t.Errorf("expected %d, got %d", exp, got)
|
t.Errorf("expected %d, got %d", exp, got)
|
||||||
}
|
}
|
||||||
// Modify the state
|
// Modify the state
|
||||||
state.SetBalance(addr, big.NewInt(2))
|
state.SetBalance(addr, uint256.NewInt(2))
|
||||||
root, err := state.Commit(0, false)
|
root, err := state.Commit(0, false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected error, got root :%x", root)
|
t.Fatalf("expected error, got root :%x", root)
|
||||||
|
|
@ -1114,13 +1113,13 @@ func TestResetObject(t *testing.T) {
|
||||||
slotB = common.HexToHash("0x2")
|
slotB = common.HexToHash("0x2")
|
||||||
)
|
)
|
||||||
// Initialize account with balance and storage in first transaction.
|
// 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.SetState(addr, slotA, common.BytesToHash([]byte{0x1}))
|
||||||
state.IntermediateRoot(true)
|
state.IntermediateRoot(true)
|
||||||
|
|
||||||
// Reset account and mutate balance and storages
|
// Reset account and mutate balance and storages
|
||||||
state.CreateAccount(addr)
|
state.CreateAccount(addr)
|
||||||
state.SetBalance(addr, big.NewInt(2))
|
state.SetBalance(addr, uint256.NewInt(2))
|
||||||
state.SetState(addr, slotB, common.BytesToHash([]byte{0x2}))
|
state.SetState(addr, slotB, common.BytesToHash([]byte{0x2}))
|
||||||
root, _ := state.Commit(0, true)
|
root, _ := state.Commit(0, true)
|
||||||
|
|
||||||
|
|
@ -1146,7 +1145,7 @@ func TestDeleteStorage(t *testing.T) {
|
||||||
addr = common.HexToAddress("0x1")
|
addr = common.HexToAddress("0x1")
|
||||||
)
|
)
|
||||||
// Initialize account and populate storage
|
// Initialize account and populate storage
|
||||||
state.SetBalance(addr, big.NewInt(1))
|
state.SetBalance(addr, uint256.NewInt(1))
|
||||||
state.CreateAccount(addr)
|
state.CreateAccount(addr)
|
||||||
for i := 0; i < 1000; i++ {
|
for i := 0; i < 1000; i++ {
|
||||||
slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32())
|
slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32())
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"math/big"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -30,12 +29,13 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// testAccount is the data associated with an account used by the state tests.
|
// testAccount is the data associated with an account used by the state tests.
|
||||||
type testAccount struct {
|
type testAccount struct {
|
||||||
address common.Address
|
address common.Address
|
||||||
balance *big.Int
|
balance *uint256.Int
|
||||||
nonce uint64
|
nonce uint64
|
||||||
code []byte
|
code []byte
|
||||||
}
|
}
|
||||||
|
|
@ -60,8 +60,8 @@ func makeTestState(scheme string) (ethdb.Database, Database, *trie.Database, com
|
||||||
obj := state.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
obj := state.getOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||||
acc := &testAccount{address: common.BytesToAddress([]byte{i})}
|
acc := &testAccount{address: common.BytesToAddress([]byte{i})}
|
||||||
|
|
||||||
obj.AddBalance(big.NewInt(int64(11 * i)))
|
obj.AddBalance(uint256.NewInt(uint64(11 * i)))
|
||||||
acc.balance = big.NewInt(int64(11 * i))
|
acc.balance = uint256.NewInt(uint64(11 * i))
|
||||||
|
|
||||||
obj.SetNonce(uint64(42 * i))
|
obj.SetNonce(uint64(42 * i))
|
||||||
acc.nonce = uint64(42 * i)
|
acc.nonce = uint64(42 * i)
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
func filledStateDB() *StateDB {
|
func filledStateDB() *StateDB {
|
||||||
|
|
@ -34,9 +35,9 @@ func filledStateDB() *StateDB {
|
||||||
skey := common.HexToHash("aaa")
|
skey := common.HexToHash("aaa")
|
||||||
sval := common.HexToHash("bbb")
|
sval := common.HexToHash("bbb")
|
||||||
|
|
||||||
state.SetBalance(addr, big.NewInt(42)) // Change the account trie
|
state.SetBalance(addr, uint256.NewInt(42)) // Change the account trie
|
||||||
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
state.SetCode(addr, []byte("hello")) // Change an external metadata
|
||||||
state.SetState(addr, skey, sval) // Change the storage trie
|
state.SetState(addr, skey, sval) // Change the storage trie
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
sk := common.BigToHash(big.NewInt(int64(i)))
|
sk := common.BigToHash(big.NewInt(int64(i)))
|
||||||
state.SetState(addr, sk, sk) // Change the storage trie
|
state.SetState(addr, sk, sk) // Change the storage trie
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,6 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
|
||||||
}
|
}
|
||||||
vmenv.Reset(NewEVMTxContext(msg), statedb)
|
vmenv.Reset(NewEVMTxContext(msg), statedb)
|
||||||
statedb.AddAddressToAccessList(params.BeaconRootsStorageAddress)
|
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)
|
statedb.Finalise(true)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
mkDynamicTx(0, common.Address{}, params.TxGas, bigNumber, bigNumber),
|
mkDynamicTx(0, common.Address{}, params.TxGas, bigNumber, bigNumber),
|
||||||
},
|
},
|
||||||
want: "could not apply tx 0 [0xd82a0c2519acfeac9a948258c47e784acd20651d9d80f9a1c67b4137651c3a24]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 2431633873983640103894990685182446064918669677978451844828609264166175722438635000",
|
want: "could not apply tx 0 [0xd82a0c2519acfeac9a948258c47e784acd20651d9d80f9a1c67b4137651c3a24]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 required balance exceeds 256 bits",
|
||||||
},
|
},
|
||||||
{ // ErrMaxInitCodeSizeExceeded
|
{ // ErrMaxInitCodeSizeExceeded
|
||||||
txs: []*types.Transaction{
|
txs: []*types.Transaction{
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExecutionResult includes all output after executing given evm
|
// ExecutionResult includes all output after executing given evm
|
||||||
|
|
@ -252,7 +253,11 @@ func (st *StateTransition) buyGas() error {
|
||||||
mgval.Add(mgval, blobFee)
|
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)
|
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 {
|
if err := st.gp.SubGas(st.msg.GasLimit); err != nil {
|
||||||
|
|
@ -261,7 +266,8 @@ func (st *StateTransition) buyGas() error {
|
||||||
st.gasRemaining += st.msg.GasLimit
|
st.gasRemaining += st.msg.GasLimit
|
||||||
|
|
||||||
st.initialGas = 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -399,7 +405,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
st.gasRemaining -= gas
|
st.gasRemaining -= gas
|
||||||
|
|
||||||
// Check clause 6
|
// 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())
|
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -418,11 +428,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
|
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
|
||||||
)
|
)
|
||||||
if contractCreation {
|
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 {
|
} else {
|
||||||
// Increment the nonce for the next transaction
|
// Increment the nonce for the next transaction
|
||||||
st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1)
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
var gasRefund uint64
|
var gasRefund uint64
|
||||||
|
|
@ -437,14 +447,15 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
if rules.IsLondon {
|
if rules.IsLondon {
|
||||||
effectiveTip = cmath.BigMin(msg.GasTipCap, new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee))
|
effectiveTip = cmath.BigMin(msg.GasTipCap, new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee))
|
||||||
}
|
}
|
||||||
|
effectiveTipU256, _ := uint256.FromBig(effectiveTip)
|
||||||
|
|
||||||
if st.evm.Config.NoBaseFee && msg.GasFeeCap.Sign() == 0 && msg.GasTipCap.Sign() == 0 {
|
if st.evm.Config.NoBaseFee && msg.GasFeeCap.Sign() == 0 && msg.GasTipCap.Sign() == 0 {
|
||||||
// Skip fee payment when NoBaseFee is set and the fee fields
|
// Skip fee payment when NoBaseFee is set and the fee fields
|
||||||
// are 0. This avoids a negative effectiveTip being applied to
|
// are 0. This avoids a negative effectiveTip being applied to
|
||||||
// the coinbase when simulating calls.
|
// the coinbase when simulating calls.
|
||||||
} else {
|
} else {
|
||||||
fee := new(big.Int).SetUint64(st.gasUsed())
|
fee := new(uint256.Int).SetUint64(st.gasUsed())
|
||||||
fee.Mul(fee, effectiveTip)
|
fee.Mul(fee, effectiveTipU256)
|
||||||
st.state.AddBalance(st.evm.Context.Coinbase, fee)
|
st.state.AddBalance(st.evm.Context.Coinbase, fee)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -465,7 +476,8 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 {
|
||||||
st.gasRemaining += refund
|
st.gasRemaining += refund
|
||||||
|
|
||||||
// Return ETH for remaining gas, exchanged at the original rate.
|
// 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)
|
st.state.AddBalance(st.msg.From, remaining)
|
||||||
|
|
||||||
// Also return remaining gas to the block gas counter so it is
|
// Also return remaining gas to the block gas counter so it is
|
||||||
|
|
|
||||||
220
core/txindexer.go
Normal file
220
core/txindexer.go
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
// 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 (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/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{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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{}),
|
||||||
|
}
|
||||||
|
go 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{}) {
|
||||||
|
defer func() { close(done) }()
|
||||||
|
|
||||||
|
// Short circuit if chain is empty and nothing to index.
|
||||||
|
if head == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// The tail flag is not existent, it means the node is just initialized
|
||||||
|
// and all blocks in the chain (part of them may from ancient store) are
|
||||||
|
// not indexed yet, index the chain according to the configured limit.
|
||||||
|
if tail == nil {
|
||||||
|
from := uint64(0)
|
||||||
|
if indexer.limit != 0 && head >= indexer.limit {
|
||||||
|
from = head - indexer.limit + 1
|
||||||
|
}
|
||||||
|
rawdb.IndexTransactions(indexer.db, from, head+1, stop, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// The tail flag is existent (which means indexes in [tail, head] should be
|
||||||
|
// present), while the whole chain are requested for indexing.
|
||||||
|
if indexer.limit == 0 || head < indexer.limit {
|
||||||
|
if *tail > 0 {
|
||||||
|
// It can happen when chain is rewound to a historical point which
|
||||||
|
// is even lower than the indexes tail, recap the indexing target
|
||||||
|
// to new head to avoid reading non-existent block bodies.
|
||||||
|
end := *tail
|
||||||
|
if end > head+1 {
|
||||||
|
end = head + 1
|
||||||
|
}
|
||||||
|
rawdb.IndexTransactions(indexer.db, 0, end, stop, true)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// The tail flag is existent, adjust the index range according to configured
|
||||||
|
// limit and the latest chain head.
|
||||||
|
if head-indexer.limit+1 < *tail {
|
||||||
|
// Reindex a part of missing indices and rewind index tail to HEAD-limit
|
||||||
|
rawdb.IndexTransactions(indexer.db, head-indexer.limit+1, *tail, stop, true)
|
||||||
|
} else {
|
||||||
|
// Unindex a part of stale indices and forward index tail to HEAD-limit
|
||||||
|
rawdb.UnindexTransactions(indexer.db, *tail, 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 ChainHeadEvent)
|
||||||
|
sub = chain.SubscribeChainHeadEvent(headCh)
|
||||||
|
)
|
||||||
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
|
// 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 := rawdb.ReadHeadBlock(indexer.db); head != nil && head.Number().Uint64() != 0 {
|
||||||
|
stop = make(chan struct{})
|
||||||
|
done = make(chan struct{})
|
||||||
|
lastHead = head.Number().Uint64()
|
||||||
|
go indexer.run(rawdb.ReadTxIndexTail(indexer.db), head.NumberU64(), stop, done)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case head := <-headCh:
|
||||||
|
if done == nil {
|
||||||
|
stop = make(chan struct{})
|
||||||
|
done = make(chan struct{})
|
||||||
|
go indexer.run(rawdb.ReadTxIndexTail(indexer.db), head.Block.NumberU64(), stop, done)
|
||||||
|
}
|
||||||
|
lastHead = head.Block.NumberU64()
|
||||||
|
case <-done:
|
||||||
|
stop = nil
|
||||||
|
done = nil
|
||||||
|
case ch := <-indexer.progress:
|
||||||
|
ch <- indexer.report(lastHead)
|
||||||
|
case ch := <-indexer.term:
|
||||||
|
if stop != nil {
|
||||||
|
close(stop)
|
||||||
|
}
|
||||||
|
if done != nil {
|
||||||
|
log.Info("Waiting background transaction indexer to exit")
|
||||||
|
<-done
|
||||||
|
}
|
||||||
|
close(ch)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// report returns the tx indexing progress.
|
||||||
|
func (indexer *txIndexer) report(head uint64) TxIndexProgress {
|
||||||
|
var (
|
||||||
|
remaining uint64
|
||||||
|
tail = rawdb.ReadTxIndexTail(indexer.db)
|
||||||
|
)
|
||||||
|
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.
|
||||||
|
if indexed < total {
|
||||||
|
remaining = total - indexed
|
||||||
|
}
|
||||||
|
return TxIndexProgress{
|
||||||
|
Indexed: indexed,
|
||||||
|
Remaining: remaining,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// txIndexProgress retrieves the tx indexing progress, or an error if the
|
||||||
|
// background tx indexer is already stopped.
|
||||||
|
func (indexer *txIndexer) txIndexProgress() (TxIndexProgress, error) {
|
||||||
|
ch := make(chan TxIndexProgress, 1)
|
||||||
|
select {
|
||||||
|
case indexer.progress <- ch:
|
||||||
|
return <-ch, nil
|
||||||
|
case <-indexer.closed:
|
||||||
|
return TxIndexProgress{}, errors.New("indexer is closed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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:
|
||||||
|
}
|
||||||
|
}
|
||||||
243
core/txindexer_test.go
Normal file
243
core/txindexer_test.go
Normal file
|
|
@ -0,0 +1,243 @@
|
||||||
|
// 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 (
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestTxIndexer tests the functionalities for managing transaction indexes.
|
||||||
|
func TestTxIndexer(t *testing.T) {
|
||||||
|
var (
|
||||||
|
testBankKey, _ = crypto.GenerateKey()
|
||||||
|
testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey)
|
||||||
|
testBankFunds = big.NewInt(1000000000000000000)
|
||||||
|
|
||||||
|
gspec = &Genesis{
|
||||||
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
|
||||||
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||||
|
}
|
||||||
|
engine = ethash.NewFaker()
|
||||||
|
nonce = uint64(0)
|
||||||
|
chainHead = uint64(128)
|
||||||
|
)
|
||||||
|
_, blocks, receipts := GenerateChainWithGenesis(gspec, engine, int(chainHead), func(i int, gen *BlockGen) {
|
||||||
|
tx, _ := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("0xdeadbeef"), big.NewInt(1000), params.TxGas, big.NewInt(10*params.InitialBaseFee), nil), types.HomesteadSigner{}, testBankKey)
|
||||||
|
gen.AddTx(tx)
|
||||||
|
nonce += 1
|
||||||
|
})
|
||||||
|
|
||||||
|
// verifyIndexes checks if the transaction indexes are present or not
|
||||||
|
// of the specified block.
|
||||||
|
verifyIndexes := func(db ethdb.Database, number uint64, exist bool) {
|
||||||
|
if number == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
block := blocks[number-1]
|
||||||
|
for _, tx := range block.Transactions() {
|
||||||
|
lookup := rawdb.ReadTxLookupEntry(db, tx.Hash())
|
||||||
|
if exist && lookup == nil {
|
||||||
|
t.Fatalf("missing %d %x", number, tx.Hash().Hex())
|
||||||
|
}
|
||||||
|
if !exist && lookup != nil {
|
||||||
|
t.Fatalf("unexpected %d %x", number, tx.Hash().Hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
verify := func(db ethdb.Database, expTail uint64, indexer *txIndexer) {
|
||||||
|
tail := rawdb.ReadTxIndexTail(db)
|
||||||
|
if tail == nil {
|
||||||
|
t.Fatal("Failed to write tx index tail")
|
||||||
|
}
|
||||||
|
if *tail != expTail {
|
||||||
|
t.Fatalf("Unexpected tx index tail, want %v, got %d", expTail, *tail)
|
||||||
|
}
|
||||||
|
if *tail != 0 {
|
||||||
|
for number := uint64(0); number < *tail; number += 1 {
|
||||||
|
verifyIndexes(db, number, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for number := *tail; number <= chainHead; number += 1 {
|
||||||
|
verifyIndexes(db, number, true)
|
||||||
|
}
|
||||||
|
progress := indexer.report(chainHead)
|
||||||
|
if !progress.Done() {
|
||||||
|
t.Fatalf("Expect fully indexed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var cases = []struct {
|
||||||
|
limitA uint64
|
||||||
|
tailA uint64
|
||||||
|
limitB uint64
|
||||||
|
tailB uint64
|
||||||
|
limitC uint64
|
||||||
|
tailC uint64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// LimitA: 0
|
||||||
|
// TailA: 0
|
||||||
|
//
|
||||||
|
// all blocks are indexed
|
||||||
|
limitA: 0,
|
||||||
|
tailA: 0,
|
||||||
|
|
||||||
|
// LimitB: 1
|
||||||
|
// TailB: 128
|
||||||
|
//
|
||||||
|
// block-128 is indexed
|
||||||
|
limitB: 1,
|
||||||
|
tailB: 128,
|
||||||
|
|
||||||
|
// LimitB: 64
|
||||||
|
// TailB: 65
|
||||||
|
//
|
||||||
|
// block [65, 128] are indexed
|
||||||
|
limitC: 64,
|
||||||
|
tailC: 65,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// LimitA: 64
|
||||||
|
// TailA: 65
|
||||||
|
//
|
||||||
|
// block [65, 128] are indexed
|
||||||
|
limitA: 64,
|
||||||
|
tailA: 65,
|
||||||
|
|
||||||
|
// LimitB: 1
|
||||||
|
// TailB: 128
|
||||||
|
//
|
||||||
|
// block-128 is indexed
|
||||||
|
limitB: 1,
|
||||||
|
tailB: 128,
|
||||||
|
|
||||||
|
// LimitB: 64
|
||||||
|
// TailB: 65
|
||||||
|
//
|
||||||
|
// block [65, 128] are indexed
|
||||||
|
limitC: 64,
|
||||||
|
tailC: 65,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// LimitA: 127
|
||||||
|
// TailA: 2
|
||||||
|
//
|
||||||
|
// block [2, 128] are indexed
|
||||||
|
limitA: 127,
|
||||||
|
tailA: 2,
|
||||||
|
|
||||||
|
// LimitB: 1
|
||||||
|
// TailB: 128
|
||||||
|
//
|
||||||
|
// block-128 is indexed
|
||||||
|
limitB: 1,
|
||||||
|
tailB: 128,
|
||||||
|
|
||||||
|
// LimitB: 64
|
||||||
|
// TailB: 65
|
||||||
|
//
|
||||||
|
// block [65, 128] are indexed
|
||||||
|
limitC: 64,
|
||||||
|
tailC: 65,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// LimitA: 128
|
||||||
|
// TailA: 1
|
||||||
|
//
|
||||||
|
// block [2, 128] are indexed
|
||||||
|
limitA: 128,
|
||||||
|
tailA: 1,
|
||||||
|
|
||||||
|
// LimitB: 1
|
||||||
|
// TailB: 128
|
||||||
|
//
|
||||||
|
// block-128 is indexed
|
||||||
|
limitB: 1,
|
||||||
|
tailB: 128,
|
||||||
|
|
||||||
|
// LimitB: 64
|
||||||
|
// TailB: 65
|
||||||
|
//
|
||||||
|
// block [65, 128] are indexed
|
||||||
|
limitC: 64,
|
||||||
|
tailC: 65,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// LimitA: 129
|
||||||
|
// TailA: 0
|
||||||
|
//
|
||||||
|
// block [0, 128] are indexed
|
||||||
|
limitA: 129,
|
||||||
|
tailA: 0,
|
||||||
|
|
||||||
|
// LimitB: 1
|
||||||
|
// TailB: 128
|
||||||
|
//
|
||||||
|
// block-128 is indexed
|
||||||
|
limitB: 1,
|
||||||
|
tailB: 128,
|
||||||
|
|
||||||
|
// LimitB: 64
|
||||||
|
// TailB: 65
|
||||||
|
//
|
||||||
|
// block [65, 128] are indexed
|
||||||
|
limitC: 64,
|
||||||
|
tailC: 65,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
frdir := t.TempDir()
|
||||||
|
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
|
||||||
|
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0))
|
||||||
|
|
||||||
|
// Index the initial blocks from ancient store
|
||||||
|
indexer := &txIndexer{
|
||||||
|
limit: c.limitA,
|
||||||
|
db: db,
|
||||||
|
progress: make(chan chan TxIndexProgress),
|
||||||
|
}
|
||||||
|
indexer.run(nil, 128, make(chan struct{}), make(chan struct{}))
|
||||||
|
verify(db, c.tailA, indexer)
|
||||||
|
|
||||||
|
indexer.limit = c.limitB
|
||||||
|
indexer.run(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}), make(chan struct{}))
|
||||||
|
verify(db, c.tailB, indexer)
|
||||||
|
|
||||||
|
indexer.limit = c.limitC
|
||||||
|
indexer.run(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}), make(chan struct{}))
|
||||||
|
verify(db, c.tailC, indexer)
|
||||||
|
|
||||||
|
// Recover all indexes
|
||||||
|
indexer.limit = 0
|
||||||
|
indexer.run(rawdb.ReadTxIndexTail(db), 128, make(chan struct{}), make(chan struct{}))
|
||||||
|
verify(db, 0, indexer)
|
||||||
|
|
||||||
|
db.Close()
|
||||||
|
os.RemoveAll(frdir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -632,7 +632,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
|
// Ensure that there's no over-draft, this is expected to happen when some
|
||||||
// transactions get included without publishing on the network
|
// transactions get included without publishing on the network
|
||||||
var (
|
var (
|
||||||
balance = uint256.MustFromBig(p.state.GetBalance(addr))
|
balance = p.state.GetBalance(addr)
|
||||||
spent = p.spent[addr]
|
spent = p.spent[addr]
|
||||||
)
|
)
|
||||||
if spent.Cmp(balance) > 0 {
|
if spent.Cmp(balance) > 0 {
|
||||||
|
|
|
||||||
|
|
@ -500,17 +500,17 @@ func TestOpenDrops(t *testing.T) {
|
||||||
|
|
||||||
// Create a blob pool out of the pre-seeded data
|
// Create a blob pool out of the pre-seeded data
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
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(gapper.PublicKey), uint256.NewInt(1000000))
|
||||||
statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000))
|
statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000))
|
||||||
statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000))
|
statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000))
|
||||||
statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3)
|
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.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2)
|
||||||
statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000))
|
statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000))
|
||||||
statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000))
|
statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000))
|
||||||
statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000))
|
statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000))
|
||||||
statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000))
|
statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), uint256.NewInt(1000000))
|
||||||
statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000))
|
statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000))
|
||||||
statedb.Commit(0, true)
|
statedb.Commit(0, true)
|
||||||
|
|
||||||
chain := &testBlockChain{
|
chain := &testBlockChain{
|
||||||
|
|
@ -625,7 +625,7 @@ func TestOpenIndex(t *testing.T) {
|
||||||
|
|
||||||
// Create a blob pool out of the pre-seeded data
|
// Create a blob pool out of the pre-seeded data
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
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)
|
statedb.Commit(0, true)
|
||||||
|
|
||||||
chain := &testBlockChain{
|
chain := &testBlockChain{
|
||||||
|
|
@ -725,9 +725,9 @@ func TestOpenHeap(t *testing.T) {
|
||||||
|
|
||||||
// Create a blob pool out of the pre-seeded data
|
// Create a blob pool out of the pre-seeded data
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
||||||
statedb.AddBalance(addr1, big.NewInt(1_000_000_000))
|
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000))
|
||||||
statedb.AddBalance(addr2, big.NewInt(1_000_000_000))
|
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000))
|
||||||
statedb.AddBalance(addr3, big.NewInt(1_000_000_000))
|
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000))
|
||||||
statedb.Commit(0, true)
|
statedb.Commit(0, true)
|
||||||
|
|
||||||
chain := &testBlockChain{
|
chain := &testBlockChain{
|
||||||
|
|
@ -805,9 +805,9 @@ func TestOpenCap(t *testing.T) {
|
||||||
for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} {
|
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
|
// 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, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
||||||
statedb.AddBalance(addr1, big.NewInt(1_000_000_000))
|
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000))
|
||||||
statedb.AddBalance(addr2, big.NewInt(1_000_000_000))
|
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000))
|
||||||
statedb.AddBalance(addr3, big.NewInt(1_000_000_000))
|
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000))
|
||||||
statedb.Commit(0, true)
|
statedb.Commit(0, true)
|
||||||
|
|
||||||
chain := &testBlockChain{
|
chain := &testBlockChain{
|
||||||
|
|
@ -1198,7 +1198,7 @@ func TestAdd(t *testing.T) {
|
||||||
addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey)
|
addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey)
|
||||||
|
|
||||||
// Seed the state database with this acocunt
|
// Seed the state database with this acocunt
|
||||||
statedb.AddBalance(addrs[acc], new(big.Int).SetUint64(seed.balance))
|
statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance))
|
||||||
statedb.SetNonce(addrs[acc], seed.nonce)
|
statedb.SetNonce(addrs[acc], seed.nonce)
|
||||||
|
|
||||||
// Sign the seed transactions and store them in the data store
|
// Sign the seed transactions and store them in the data store
|
||||||
|
|
|
||||||
|
|
@ -1441,7 +1441,7 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T
|
||||||
}
|
}
|
||||||
log.Trace("Removed old queued transactions", "count", len(forwards))
|
log.Trace("Removed old queued transactions", "count", len(forwards))
|
||||||
// Drop all transactions that are too costly (low balance or out of gas)
|
// Drop all transactions that are too costly (low balance or out of gas)
|
||||||
drops, _ := list.Filter(pool.currentState.GetBalance(addr), gasLimit)
|
drops, _ := list.Filter(pool.currentState.GetBalance(addr).ToBig(), gasLimit)
|
||||||
for _, tx := range drops {
|
for _, tx := range drops {
|
||||||
hash := tx.Hash()
|
hash := tx.Hash()
|
||||||
pool.all.Remove(hash)
|
pool.all.Remove(hash)
|
||||||
|
|
@ -1642,7 +1642,7 @@ func (pool *LegacyPool) demoteUnexecutables() {
|
||||||
log.Trace("Removed old pending transaction", "hash", hash)
|
log.Trace("Removed old pending transaction", "hash", hash)
|
||||||
}
|
}
|
||||||
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
|
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
|
||||||
drops, invalids := list.Filter(pool.currentState.GetBalance(addr), gasLimit)
|
drops, invalids := list.Filter(pool.currentState.GetBalance(addr).ToBig(), gasLimit)
|
||||||
for _, tx := range drops {
|
for _, tx := range drops {
|
||||||
hash := tx.Hash()
|
hash := tx.Hash()
|
||||||
log.Trace("Removed unpayable pending transaction", "hash", hash)
|
log.Trace("Removed unpayable pending transaction", "hash", hash)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"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 {
|
func pricedValuedTransaction(nonce uint64, value int64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
|
||||||
|
|
@ -49,7 +50,7 @@ func fillPool(t testing.TB, pool *LegacyPool) {
|
||||||
nonExecutableTxs := types.Transactions{}
|
nonExecutableTxs := types.Transactions{}
|
||||||
for i := 0; i < 384; i++ {
|
for i := 0; i < 384; i++ {
|
||||||
key, _ := crypto.GenerateKey()
|
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
|
// Add executable ones
|
||||||
for j := 0; j < int(pool.config.AccountSlots); j++ {
|
for j := 0; j < int(pool.config.AccountSlots); j++ {
|
||||||
executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key))
|
executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key))
|
||||||
|
|
@ -91,7 +92,7 @@ func TestTransactionFutureAttack(t *testing.T) {
|
||||||
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||||
{
|
{
|
||||||
key, _ := crypto.GenerateKey()
|
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{}
|
futureTxs := types.Transactions{}
|
||||||
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
||||||
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key))
|
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key))
|
||||||
|
|
@ -128,7 +129,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
|
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||||
{
|
{
|
||||||
key, _ := crypto.GenerateKey()
|
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{}
|
futureTxs := types.Transactions{}
|
||||||
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
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))
|
futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key))
|
||||||
|
|
@ -161,7 +162,7 @@ func TestTransactionZAttack(t *testing.T) {
|
||||||
var ivpendingNum int
|
var ivpendingNum int
|
||||||
pendingtxs, _ := pool.Content()
|
pendingtxs, _ := pool.Content()
|
||||||
for account, txs := range pendingtxs {
|
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 {
|
for _, tx := range txs {
|
||||||
if cur_balance.Cmp(tx.Value()) <= 0 {
|
if cur_balance.Cmp(tx.Value()) <= 0 {
|
||||||
ivpendingNum++
|
ivpendingNum++
|
||||||
|
|
@ -182,7 +183,7 @@ func TestTransactionZAttack(t *testing.T) {
|
||||||
for j := 0; j < int(pool.config.GlobalQueue); j++ {
|
for j := 0; j < int(pool.config.GlobalQueue); j++ {
|
||||||
futureTxs := types.Transactions{}
|
futureTxs := types.Transactions{}
|
||||||
key, _ := crypto.GenerateKey()
|
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))
|
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key))
|
||||||
pool.addRemotesSync(futureTxs)
|
pool.addRemotesSync(futureTxs)
|
||||||
}
|
}
|
||||||
|
|
@ -190,7 +191,7 @@ func TestTransactionZAttack(t *testing.T) {
|
||||||
overDraftTxs := types.Transactions{}
|
overDraftTxs := types.Transactions{}
|
||||||
{
|
{
|
||||||
key, _ := crypto.GenerateKey()
|
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++ {
|
for j := 0; j < int(pool.config.GlobalSlots); j++ {
|
||||||
overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key))
|
overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key))
|
||||||
}
|
}
|
||||||
|
|
@ -227,7 +228,7 @@ func BenchmarkFutureAttack(b *testing.B) {
|
||||||
fillPool(b, pool)
|
fillPool(b, pool)
|
||||||
|
|
||||||
key, _ := crypto.GenerateKey()
|
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{}
|
futureTxs := types.Transactions{}
|
||||||
|
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -255,7 +256,7 @@ func (c *testChain) State() (*state.StateDB, error) {
|
||||||
c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||||
// simulate that the new head block included tx0 and tx1
|
// simulate that the new head block included tx0 and tx1
|
||||||
c.statedb.SetNonce(c.address, 2)
|
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
|
*c.trigger = false
|
||||||
}
|
}
|
||||||
return stdb, nil
|
return stdb, nil
|
||||||
|
|
@ -275,7 +276,7 @@ func TestStateChangeDuringReset(t *testing.T) {
|
||||||
)
|
)
|
||||||
|
|
||||||
// setup pool with 2 transaction in it
|
// 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}
|
blockchain := &testChain{newTestBlockChain(params.TestChainConfig, 1000000000, statedb, new(event.Feed)), address, &trigger}
|
||||||
|
|
||||||
tx0 := transaction(0, 100000, key)
|
tx0 := transaction(0, 100000, key)
|
||||||
|
|
@ -309,7 +310,7 @@ func TestStateChangeDuringReset(t *testing.T) {
|
||||||
|
|
||||||
func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) {
|
func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) {
|
||||||
pool.mu.Lock()
|
pool.mu.Lock()
|
||||||
pool.currentState.AddBalance(addr, amount)
|
pool.currentState.AddBalance(addr, uint256.MustFromBig(amount))
|
||||||
pool.mu.Unlock()
|
pool.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -470,7 +471,7 @@ func TestChainFork(t *testing.T) {
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
resetState := func() {
|
resetState := func() {
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
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.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
|
||||||
<-pool.requestReset(nil, nil)
|
<-pool.requestReset(nil, nil)
|
||||||
|
|
@ -499,7 +500,7 @@ func TestDoubleNonce(t *testing.T) {
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
resetState := func() {
|
resetState := func() {
|
||||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
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.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
|
||||||
<-pool.requestReset(nil, nil)
|
<-pool.requestReset(nil, nil)
|
||||||
|
|
@ -2662,7 +2663,7 @@ func BenchmarkMultiAccountBatchInsert(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
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)
|
tx := transaction(uint64(0), 100000, key)
|
||||||
batches[i] = tx
|
batches[i] = tx
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,9 @@ type TxPool struct {
|
||||||
|
|
||||||
subs event.SubscriptionScope // Subscription scope to unsubscribe all on shutdown
|
subs event.SubscriptionScope // Subscription scope to unsubscribe all on shutdown
|
||||||
quit chan chan error // Quit channel to tear down the head updater
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new transaction pool to gather, sort and filter inbound
|
// New creates a new transaction pool to gather, sort and filter inbound
|
||||||
|
|
@ -86,6 +89,8 @@ func New(gasTip *big.Int, chain BlockChain, subpools []SubPool) (*TxPool, error)
|
||||||
subpools: subpools,
|
subpools: subpools,
|
||||||
reservations: make(map[common.Address]SubPool),
|
reservations: make(map[common.Address]SubPool),
|
||||||
quit: make(chan chan error),
|
quit: make(chan chan error),
|
||||||
|
term: make(chan struct{}),
|
||||||
|
sync: make(chan chan error),
|
||||||
}
|
}
|
||||||
for i, subpool := range subpools {
|
for i, subpool := range subpools {
|
||||||
if err := subpool.Init(gasTip, head, pool.reserver(i, subpool)); err != nil {
|
if err := subpool.Init(gasTip, head, pool.reserver(i, subpool)); err != nil {
|
||||||
|
|
@ -174,6 +179,9 @@ func (p *TxPool) Close() error {
|
||||||
// outside blockchain events as well as for various reporting and transaction
|
// outside blockchain events as well as for various reporting and transaction
|
||||||
// eviction events.
|
// eviction events.
|
||||||
func (p *TxPool) loop(head *types.Header, chain BlockChain) {
|
func (p *TxPool) loop(head *types.Header, chain BlockChain) {
|
||||||
|
// Close the termination marker when the pool stops
|
||||||
|
defer close(p.term)
|
||||||
|
|
||||||
// Subscribe to chain head events to trigger subpool resets
|
// Subscribe to chain head events to trigger subpool resets
|
||||||
var (
|
var (
|
||||||
newHeadCh = make(chan core.ChainHeadEvent)
|
newHeadCh = make(chan core.ChainHeadEvent)
|
||||||
|
|
@ -190,13 +198,23 @@ func (p *TxPool) loop(head *types.Header, chain BlockChain) {
|
||||||
var (
|
var (
|
||||||
resetBusy = make(chan struct{}, 1) // Allow 1 reset to run concurrently
|
resetBusy = make(chan struct{}, 1) // Allow 1 reset to run concurrently
|
||||||
resetDone = make(chan *types.Header)
|
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
|
var errc chan error
|
||||||
for errc == nil {
|
for errc == nil {
|
||||||
// Something interesting might have happened, run a reset if there is
|
// Something interesting might have happened, run a reset if there is
|
||||||
// one needed but none is running. The resetter will run on its own
|
// one needed but none is running. The resetter will run on its own
|
||||||
// goroutine to allow chain head events to be consumed contiguously.
|
// 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
|
// Try to inject a busy marker and start a reset if successful
|
||||||
select {
|
select {
|
||||||
case resetBusy <- struct{}{}:
|
case resetBusy <- struct{}{}:
|
||||||
|
|
@ -208,8 +226,17 @@ func (p *TxPool) loop(head *types.Header, chain BlockChain) {
|
||||||
resetDone <- newHead
|
resetDone <- newHead
|
||||||
}(oldHead, 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:
|
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
|
// Wait for the next chain head event or a previous reset finish
|
||||||
|
|
@ -223,8 +250,26 @@ func (p *TxPool) loop(head *types.Header, chain BlockChain) {
|
||||||
oldHead = head
|
oldHead = head
|
||||||
<-resetBusy
|
<-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:
|
case errc = <-p.quit:
|
||||||
// Termination requested, break out on the next loop round
|
// 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)
|
// Notify the closer of termination (no error possible for now)
|
||||||
|
|
@ -415,3 +460,20 @@ func (p *TxPool) Status(hash common.Hash) TxStatus {
|
||||||
}
|
}
|
||||||
return TxStatusUnknown
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, op
|
||||||
}
|
}
|
||||||
// Ensure the transactor has enough funds to cover the transaction costs
|
// Ensure the transactor has enough funds to cover the transaction costs
|
||||||
var (
|
var (
|
||||||
balance = opts.State.GetBalance(from)
|
balance = opts.State.GetBalance(from).ToBig()
|
||||||
cost = tx.Cost()
|
cost = tx.Cost()
|
||||||
)
|
)
|
||||||
if balance.Cmp(cost) < 0 {
|
if balance.Cmp(cost) < 0 {
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,7 @@ func (obj *StateAccount) EncodeRLP(_w io.Writer) error {
|
||||||
if obj.Balance == nil {
|
if obj.Balance == nil {
|
||||||
w.Write(rlp.EmptyString)
|
w.Write(rlp.EmptyString)
|
||||||
} else {
|
} else {
|
||||||
if obj.Balance.Sign() == -1 {
|
w.WriteUint256(obj.Balance)
|
||||||
return rlp.ErrNegativeBigInt
|
|
||||||
}
|
|
||||||
w.WriteBigInt(obj.Balance)
|
|
||||||
}
|
}
|
||||||
w.WriteBytes(obj.Root[:])
|
w.WriteBytes(obj.Root[:])
|
||||||
w.WriteBytes(obj.CodeHash)
|
w.WriteBytes(obj.CodeHash)
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,10 @@ package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run ../../rlp/rlpgen -type StateAccount -out gen_account_rlp.go
|
//go:generate go run ../../rlp/rlpgen -type StateAccount -out gen_account_rlp.go
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
// These objects are stored in the main account trie.
|
// These objects are stored in the main account trie.
|
||||||
type StateAccount struct {
|
type StateAccount struct {
|
||||||
Nonce uint64
|
Nonce uint64
|
||||||
Balance *big.Int
|
Balance *uint256.Int
|
||||||
Root common.Hash // merkle root of the storage trie
|
Root common.Hash // merkle root of the storage trie
|
||||||
CodeHash []byte
|
CodeHash []byte
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +38,7 @@ type StateAccount struct {
|
||||||
// NewEmptyStateAccount constructs an empty state account.
|
// NewEmptyStateAccount constructs an empty state account.
|
||||||
func NewEmptyStateAccount() *StateAccount {
|
func NewEmptyStateAccount() *StateAccount {
|
||||||
return &StateAccount{
|
return &StateAccount{
|
||||||
Balance: new(big.Int),
|
Balance: new(uint256.Int),
|
||||||
Root: EmptyRootHash,
|
Root: EmptyRootHash,
|
||||||
CodeHash: EmptyCodeHash.Bytes(),
|
CodeHash: EmptyCodeHash.Bytes(),
|
||||||
}
|
}
|
||||||
|
|
@ -46,9 +46,9 @@ func NewEmptyStateAccount() *StateAccount {
|
||||||
|
|
||||||
// Copy returns a deep-copied state account object.
|
// Copy returns a deep-copied state account object.
|
||||||
func (acct *StateAccount) Copy() *StateAccount {
|
func (acct *StateAccount) Copy() *StateAccount {
|
||||||
var balance *big.Int
|
var balance *uint256.Int
|
||||||
if acct.Balance != nil {
|
if acct.Balance != nil {
|
||||||
balance = new(big.Int).Set(acct.Balance)
|
balance = new(uint256.Int).Set(acct.Balance)
|
||||||
}
|
}
|
||||||
return &StateAccount{
|
return &StateAccount{
|
||||||
Nonce: acct.Nonce,
|
Nonce: acct.Nonce,
|
||||||
|
|
@ -63,7 +63,7 @@ func (acct *StateAccount) Copy() *StateAccount {
|
||||||
// or slim format which replaces the empty root and code hash as nil byte slice.
|
// or slim format which replaces the empty root and code hash as nil byte slice.
|
||||||
type SlimAccount struct {
|
type SlimAccount struct {
|
||||||
Nonce uint64
|
Nonce uint64
|
||||||
Balance *big.Int
|
Balance *uint256.Int
|
||||||
Root []byte // Nil if root equals to types.EmptyRootHash
|
Root []byte // Nil if root equals to types.EmptyRootHash
|
||||||
CodeHash []byte // Nil if hash equals to types.EmptyCodeHash
|
CodeHash []byte // Nil if hash equals to types.EmptyCodeHash
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
@ -59,11 +57,11 @@ type Contract struct {
|
||||||
Input []byte
|
Input []byte
|
||||||
|
|
||||||
Gas uint64
|
Gas uint64
|
||||||
value *big.Int
|
value *uint256.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContract returns a new contract environment for the execution of EVM.
|
// 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}
|
c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object}
|
||||||
|
|
||||||
if parent, ok := caller.(*Contract); ok {
|
if parent, ok := caller.(*Contract); ok {
|
||||||
|
|
@ -173,7 +171,7 @@ func (c *Contract) Address() common.Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value returns the contract's value (sent to it from it's caller)
|
// 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
|
return c.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,6 @@ type bigModExp struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
big0 = big.NewInt(0)
|
|
||||||
big1 = big.NewInt(1)
|
big1 = big.NewInt(1)
|
||||||
big3 = big.NewInt(3)
|
big3 = big.NewInt(3)
|
||||||
big4 = big.NewInt(4)
|
big4 = big.NewInt(4)
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ func enable1884(jt *JumpTable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
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)
|
scope.Stack.push(balance)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ import (
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// CanTransferFunc is the signature of a transfer guard function
|
// 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 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
|
// GetHashFunc returns the n'th block hash in the blockchain
|
||||||
// and is used by the BLOCKHASH EVM op code.
|
// and is used by the BLOCKHASH EVM op code.
|
||||||
GetHashFunc func(uint64) common.Hash
|
GetHashFunc func(uint64) common.Hash
|
||||||
|
|
@ -176,7 +176,7 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
|
||||||
// parameters. It also handles any necessary value transfer required and takes
|
// 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
|
// the necessary steps to create accounts and reverses the state in case of an
|
||||||
// execution error or failed value transfer.
|
// 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
|
// Fail if we're trying to execute above the call depth limit
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
return nil, gas, ErrDepth
|
return nil, gas, ErrDepth
|
||||||
|
|
@ -194,10 +194,10 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||||
// Calling a non existing account, don't do anything, but ping the tracer
|
// Calling a non existing account, don't do anything, but ping the tracer
|
||||||
if debug {
|
if debug {
|
||||||
if evm.depth == 0 {
|
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)
|
evm.Config.Tracer.CaptureEnd(ret, 0, nil)
|
||||||
} else {
|
} 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)
|
evm.Config.Tracer.CaptureExit(ret, 0, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -210,13 +210,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||||
// Capture the tracer start/end events in debug mode
|
// Capture the tracer start/end events in debug mode
|
||||||
if debug {
|
if debug {
|
||||||
if evm.depth == 0 {
|
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
|
defer func(startGas uint64) { // Lazy evaluation of the parameters
|
||||||
evm.Config.Tracer.CaptureEnd(ret, startGas-gas, err)
|
evm.Config.Tracer.CaptureEnd(ret, startGas-gas, err)
|
||||||
}(gas)
|
}(gas)
|
||||||
} else {
|
} else {
|
||||||
// Handle tracer events for entering and exiting a call frame
|
// 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) {
|
defer func(startGas uint64) {
|
||||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||||
}(gas)
|
}(gas)
|
||||||
|
|
@ -263,7 +263,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'
|
// CallCode differs from Call in the sense that it executes the given address'
|
||||||
// code with the caller as context.
|
// 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
|
// Fail if we're trying to execute above the call depth limit
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
return nil, gas, ErrDepth
|
return nil, gas, ErrDepth
|
||||||
|
|
@ -279,7 +279,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||||
|
|
||||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||||
if evm.Config.Tracer != nil {
|
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) {
|
defer func(startGas uint64) {
|
||||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||||
}(gas)
|
}(gas)
|
||||||
|
|
@ -324,7 +324,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||||
// that caller is something other than a Contract.
|
// that caller is something other than a Contract.
|
||||||
parent := caller.(*Contract)
|
parent := caller.(*Contract)
|
||||||
// DELEGATECALL inherits value from parent call
|
// 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) {
|
defer func(startGas uint64) {
|
||||||
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
|
||||||
}(gas)
|
}(gas)
|
||||||
|
|
@ -370,7 +370,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,
|
// 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
|
// but is the correct thing to do and matters on other networks, in tests, and potential
|
||||||
// future scenarios
|
// future scenarios
|
||||||
evm.StateDB.AddBalance(addr, big0)
|
evm.StateDB.AddBalance(addr, new(uint256.Int))
|
||||||
|
|
||||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||||
if evm.Config.Tracer != nil {
|
if evm.Config.Tracer != nil {
|
||||||
|
|
@ -389,7 +389,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||||
addrCopy := addr
|
addrCopy := addr
|
||||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
// 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.
|
// 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))
|
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
|
// 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
|
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||||
|
|
@ -419,7 +419,7 @@ func (c *codeAndHash) Hash() common.Hash {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create creates a new contract using code as deployment code.
|
// 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
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
// limit.
|
// limit.
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
|
|
@ -458,9 +458,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
|
|
||||||
if evm.Config.Tracer != nil {
|
if evm.Config.Tracer != nil {
|
||||||
if evm.depth == 0 {
|
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 {
|
} 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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -510,7 +510,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new contract using code as deployment code.
|
// 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()))
|
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))
|
||||||
return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE)
|
return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE)
|
||||||
}
|
}
|
||||||
|
|
@ -519,7 +519,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:]
|
// 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.
|
// 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}
|
codeAndHash := &codeAndHash{code: code}
|
||||||
contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes())
|
contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes())
|
||||||
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)
|
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMemoryGasCost(t *testing.T) {
|
func TestMemoryGasCost(t *testing.T) {
|
||||||
|
|
@ -91,12 +92,12 @@ func TestEIP2200(t *testing.T) {
|
||||||
statedb.Finalise(true) // Push the state into the "original" slot
|
statedb.Finalise(true) // Push the state into the "original" slot
|
||||||
|
|
||||||
vmctx := BlockContext{
|
vmctx := BlockContext{
|
||||||
CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true },
|
CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true },
|
||||||
Transfer: func(StateDB, common.Address, common.Address, *big.Int) {},
|
Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {},
|
||||||
}
|
}
|
||||||
vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}})
|
vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, 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 {
|
if err != tt.failure {
|
||||||
t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure)
|
t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure)
|
||||||
}
|
}
|
||||||
|
|
@ -141,8 +142,8 @@ func TestCreateGas(t *testing.T) {
|
||||||
statedb.SetCode(address, hexutil.MustDecode(tt.code))
|
statedb.SetCode(address, hexutil.MustDecode(tt.code))
|
||||||
statedb.Finalise(true)
|
statedb.Finalise(true)
|
||||||
vmctx := BlockContext{
|
vmctx := BlockContext{
|
||||||
CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true },
|
CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true },
|
||||||
Transfer: func(StateDB, common.Address, common.Address, *big.Int) {},
|
Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {},
|
||||||
BlockNumber: big.NewInt(0),
|
BlockNumber: big.NewInt(0),
|
||||||
}
|
}
|
||||||
config := Config{}
|
config := Config{}
|
||||||
|
|
@ -152,7 +153,7 @@ func TestCreateGas(t *testing.T) {
|
||||||
|
|
||||||
vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, config)
|
vmenv := NewEVM(vmctx, TxContext{}, statedb, params.AllEthashProtocolChanges, config)
|
||||||
var startGas = uint64(testGas)
|
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 {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -260,7 +260,7 @@ func opAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
||||||
func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
slot := scope.Stack.peek()
|
slot := scope.Stack.peek()
|
||||||
address := common.Address(slot.Bytes20())
|
address := common.Address(slot.Bytes20())
|
||||||
slot.SetFromBig(interpreter.evm.StateDB.GetBalance(address))
|
slot.Set(interpreter.evm.StateDB.GetBalance(address))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,8 +275,7 @@ func opCaller(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallValue(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opCallValue(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
v, _ := uint256.FromBig(scope.Contract.value)
|
scope.Stack.push(scope.Contract.value)
|
||||||
scope.Stack.push(v)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -592,13 +591,8 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
stackvalue := size
|
stackvalue := size
|
||||||
|
|
||||||
scope.Contract.UseGas(gas)
|
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
|
// Push item on the stack based on the returned error. If the ruleset is
|
||||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
// rule) and treat as an error, if the ruleset is frontier we must
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
|
|
@ -637,13 +631,8 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
||||||
scope.Contract.UseGas(gas)
|
scope.Contract.UseGas(gas)
|
||||||
// reuse size int for stackvalue
|
// reuse size int for stackvalue
|
||||||
stackvalue := size
|
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,
|
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.
|
// Push item on the stack based on the returned error.
|
||||||
if suberr != nil {
|
if suberr != nil {
|
||||||
stackvalue.Clear()
|
stackvalue.Clear()
|
||||||
|
|
@ -676,16 +665,10 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
|
||||||
if interpreter.readOnly && !value.IsZero() {
|
if interpreter.readOnly && !value.IsZero() {
|
||||||
return nil, ErrWriteProtection
|
return nil, 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() {
|
if !value.IsZero() {
|
||||||
gas += params.CallStipend
|
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 {
|
if err != nil {
|
||||||
temp.Clear()
|
temp.Clear()
|
||||||
|
|
@ -714,14 +697,11 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
||||||
// Get arguments from the memory.
|
// Get arguments from the memory.
|
||||||
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
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() {
|
if !value.IsZero() {
|
||||||
gas += params.CallStipend
|
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 {
|
if err != nil {
|
||||||
temp.Clear()
|
temp.Clear()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -825,7 +805,7 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
||||||
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
|
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
|
||||||
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
|
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
|
||||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
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)
|
tracer.CaptureExit([]byte{}, 0, nil)
|
||||||
}
|
}
|
||||||
return nil, errStopToken
|
return nil, errStopToken
|
||||||
|
|
@ -841,7 +821,7 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
|
||||||
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
|
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
|
||||||
interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address())
|
interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address())
|
||||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
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)
|
tracer.CaptureExit([]byte{}, 0, nil)
|
||||||
}
|
}
|
||||||
return nil, errStopToken
|
return nil, errStopToken
|
||||||
|
|
|
||||||
|
|
@ -590,7 +590,7 @@ func TestOpTstore(t *testing.T) {
|
||||||
caller = common.Address{}
|
caller = common.Address{}
|
||||||
to = common.Address{1}
|
to = common.Address{1}
|
||||||
contractRef = contractRef{caller}
|
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}
|
scopeContext = ScopeContext{mem, stack, contract}
|
||||||
value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700")
|
value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700")
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -22,15 +22,16 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StateDB is an EVM database for full state querying.
|
// StateDB is an EVM database for full state querying.
|
||||||
type StateDB interface {
|
type StateDB interface {
|
||||||
CreateAccount(common.Address)
|
CreateAccount(common.Address)
|
||||||
|
|
||||||
SubBalance(common.Address, *big.Int)
|
SubBalance(common.Address, *uint256.Int)
|
||||||
AddBalance(common.Address, *big.Int)
|
AddBalance(common.Address, *uint256.Int)
|
||||||
GetBalance(common.Address) *big.Int
|
GetBalance(common.Address) *uint256.Int
|
||||||
|
|
||||||
GetNonce(common.Address) uint64
|
GetNonce(common.Address) uint64
|
||||||
SetNonce(common.Address, uint64)
|
SetNonce(common.Address, uint64)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -27,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
var loopInterruptTests = []string{
|
var loopInterruptTests = []string{
|
||||||
|
|
@ -39,7 +39,7 @@ var loopInterruptTests = []string{
|
||||||
func TestLoopInterrupt(t *testing.T) {
|
func TestLoopInterrupt(t *testing.T) {
|
||||||
address := common.BytesToAddress([]byte("contract"))
|
address := common.BytesToAddress([]byte("contract"))
|
||||||
vmctx := BlockContext{
|
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 {
|
for i, tt := range loopInterruptTests {
|
||||||
|
|
@ -54,7 +54,7 @@ func TestLoopInterrupt(t *testing.T) {
|
||||||
timeout := make(chan bool)
|
timeout := make(chan bool)
|
||||||
|
|
||||||
go func(evm *EVM) {
|
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
|
errChannel <- err
|
||||||
}(evm)
|
}(evm)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ func newLondonInstructionSet() JumpTable {
|
||||||
// constantinople, istanbul, petersburg and berlin instructions.
|
// constantinople, istanbul, petersburg and berlin instructions.
|
||||||
func newBerlinInstructionSet() JumpTable {
|
func newBerlinInstructionSet() JumpTable {
|
||||||
instructionSet := newIstanbulInstructionSet()
|
instructionSet := newIstanbulInstructionSet()
|
||||||
enable2929(&instructionSet) // Access lists for trie accesses https://eips.ethereum.org/EIPS/eip-2929
|
enable2929(&instructionSet) // Gas cost increases for state access opcodes https://eips.ethereum.org/EIPS/eip-2929
|
||||||
return validate(instructionSet)
|
return validate(instructionSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config is a basic type specifying certain configuration flags for running
|
// Config is a basic type specifying certain configuration flags for running
|
||||||
|
|
@ -135,7 +136,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
||||||
common.BytesToAddress([]byte("contract")),
|
common.BytesToAddress([]byte("contract")),
|
||||||
input,
|
input,
|
||||||
cfg.GasLimit,
|
cfg.GasLimit,
|
||||||
cfg.Value,
|
uint256.MustFromBig(cfg.Value),
|
||||||
)
|
)
|
||||||
return ret, cfg.State, err
|
return ret, cfg.State, err
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +165,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
||||||
sender,
|
sender,
|
||||||
input,
|
input,
|
||||||
cfg.GasLimit,
|
cfg.GasLimit,
|
||||||
cfg.Value,
|
uint256.MustFromBig(cfg.Value),
|
||||||
)
|
)
|
||||||
return code, address, leftOverGas, err
|
return code, address, leftOverGas, err
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +195,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
|
||||||
address,
|
address,
|
||||||
input,
|
input,
|
||||||
cfg.GasLimit,
|
cfg.GasLimit,
|
||||||
cfg.Value,
|
uint256.MustFromBig(cfg.Value),
|
||||||
)
|
)
|
||||||
return ret, leftOverGas, err
|
return ret, leftOverGas, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import (
|
||||||
|
|
||||||
// force-load js tracers to trigger registration
|
// force-load js tracers to trigger registration
|
||||||
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
|
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDefaults(t *testing.T) {
|
func TestDefaults(t *testing.T) {
|
||||||
|
|
@ -362,12 +363,12 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
|
||||||
//cfg.State.CreateAccount(cfg.Origin)
|
//cfg.State.CreateAccount(cfg.Origin)
|
||||||
// set the receiver's (the executing contract) code for execution.
|
// set the receiver's (the executing contract) code for execution.
|
||||||
cfg.State.SetCode(destination, code)
|
cfg.State.SetCode(destination, code)
|
||||||
vmenv.Call(sender, destination, nil, gas, cfg.Value)
|
vmenv.Call(sender, destination, nil, gas, uint256.MustFromBig(cfg.Value))
|
||||||
|
|
||||||
b.Run(name, func(b *testing.B) {
|
b.Run(name, func(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
vmenv.Call(sender, destination, nil, gas, cfg.Value)
|
vmenv.Call(sender, destination, nil, gas, uint256.MustFromBig(cfg.Value))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ package eth
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -31,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -73,7 +73,7 @@ func TestAccountRange(t *testing.T) {
|
||||||
hash := common.HexToHash(fmt.Sprintf("%x", i))
|
hash := common.HexToHash(fmt.Sprintf("%x", i))
|
||||||
addr := common.BytesToAddress(crypto.Keccak256Hash(hash.Bytes()).Bytes())
|
addr := common.BytesToAddress(crypto.Keccak256Hash(hash.Bytes()).Bytes())
|
||||||
addrs[i] = addr
|
addrs[i] = addr
|
||||||
sdb.SetBalance(addrs[i], big.NewInt(1))
|
sdb.SetBalance(addrs[i], uint256.NewInt(1))
|
||||||
if _, ok := m[addr]; ok {
|
if _, ok := m[addr]; ok {
|
||||||
t.Fatalf("bad")
|
t.Fatalf("bad")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ package catalyst
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -34,6 +33,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -180,54 +180,50 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, pa
|
||||||
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("forkChoiceUpdateV1 called post-shanghai"))
|
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("forkChoiceUpdateV1 called post-shanghai"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return api.forkchoiceUpdated(update, payloadAttributes)
|
return api.forkchoiceUpdated(update, payloadAttributes, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes.
|
// ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes.
|
||||||
func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
||||||
if payloadAttributes != nil {
|
if params != nil {
|
||||||
if err := api.verifyPayloadAttributes(payloadAttributes); err != nil {
|
if params.Withdrawals == nil {
|
||||||
return engine.STATUS_INVALID, engine.InvalidParams.With(err)
|
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("missing withdrawals"))
|
||||||
|
}
|
||||||
|
if params.BeaconRoot != nil {
|
||||||
|
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("unexpected beacon root"))
|
||||||
|
}
|
||||||
|
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Shanghai {
|
||||||
|
return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV2 must only be called for shanghai payloads"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return api.forkchoiceUpdated(update, payloadAttributes)
|
return api.forkchoiceUpdated(update, params, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForkchoiceUpdatedV3 is equivalent to V2 with the addition of parent beacon block root in the payload attributes.
|
// ForkchoiceUpdatedV3 is equivalent to V2 with the addition of parent beacon block root in the payload attributes.
|
||||||
func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
||||||
if payloadAttributes != nil {
|
if params != nil {
|
||||||
if err := api.verifyPayloadAttributes(payloadAttributes); err != nil {
|
// TODO(matt): according to https://github.com/ethereum/execution-apis/pull/498,
|
||||||
return engine.STATUS_INVALID, engine.InvalidParams.With(err)
|
// payload attributes that are invalid should return error
|
||||||
|
// engine.InvalidPayloadAttributes. Once hive updates this, we should update
|
||||||
|
// on our end.
|
||||||
|
if params.Withdrawals == nil {
|
||||||
|
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("missing withdrawals"))
|
||||||
|
}
|
||||||
|
if params.BeaconRoot == nil {
|
||||||
|
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("missing beacon root"))
|
||||||
|
}
|
||||||
|
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun {
|
||||||
|
return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return api.forkchoiceUpdated(update, payloadAttributes)
|
// TODO(matt): the spec requires that fcu is applied when called on a valid
|
||||||
|
// hash, even if params are wrong. To do this we need to split up
|
||||||
|
// forkchoiceUpdate into a function that only updates the head and then a
|
||||||
|
// function that kicks off block construction.
|
||||||
|
return api.forkchoiceUpdated(update, params, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *ConsensusAPI) verifyPayloadAttributes(attr *engine.PayloadAttributes) error {
|
func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes, simulatorMode bool) (engine.ForkChoiceResponse, error) {
|
||||||
c := api.eth.BlockChain().Config()
|
|
||||||
|
|
||||||
// Verify withdrawals attribute for Shanghai.
|
|
||||||
if err := checkAttribute(c.IsShanghai, attr.Withdrawals != nil, c.LondonBlock, attr.Timestamp); err != nil {
|
|
||||||
return fmt.Errorf("invalid withdrawals: %w", err)
|
|
||||||
}
|
|
||||||
// Verify beacon root attribute for Cancun.
|
|
||||||
if err := checkAttribute(c.IsCancun, attr.BeaconRoot != nil, c.LondonBlock, attr.Timestamp); err != nil {
|
|
||||||
return fmt.Errorf("invalid parent beacon block root: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkAttribute(active func(*big.Int, uint64) bool, exists bool, block *big.Int, time uint64) error {
|
|
||||||
if active(block, time) && !exists {
|
|
||||||
return errors.New("fork active, missing expected attribute")
|
|
||||||
}
|
|
||||||
if !active(block, time) && exists {
|
|
||||||
return errors.New("fork inactive, unexpected attribute set")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payloadAttributes *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
|
|
||||||
api.forkchoiceLock.Lock()
|
api.forkchoiceLock.Lock()
|
||||||
defer api.forkchoiceLock.Unlock()
|
defer api.forkchoiceLock.Unlock()
|
||||||
|
|
||||||
|
|
@ -334,7 +330,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
||||||
if merger := api.eth.Merger(); !merger.PoSFinalized() {
|
if merger := api.eth.Merger(); !merger.PoSFinalized() {
|
||||||
merger.FinalizePoS()
|
merger.FinalizePoS()
|
||||||
}
|
}
|
||||||
// If the finalized block is not in our canonical tree, somethings wrong
|
// If the finalized block is not in our canonical tree, something is wrong
|
||||||
finalBlock := api.eth.BlockChain().GetBlockByHash(update.FinalizedBlockHash)
|
finalBlock := api.eth.BlockChain().GetBlockByHash(update.FinalizedBlockHash)
|
||||||
if finalBlock == nil {
|
if finalBlock == nil {
|
||||||
log.Warn("Final block not available in database", "hash", update.FinalizedBlockHash)
|
log.Warn("Final block not available in database", "hash", update.FinalizedBlockHash)
|
||||||
|
|
@ -346,7 +342,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
||||||
// Set the finalized block
|
// Set the finalized block
|
||||||
api.eth.BlockChain().SetFinalized(finalBlock.Header())
|
api.eth.BlockChain().SetFinalized(finalBlock.Header())
|
||||||
}
|
}
|
||||||
// Check if the safe block hash is in our canonical tree, if not somethings wrong
|
// Check if the safe block hash is in our canonical tree, if not something is wrong
|
||||||
if update.SafeBlockHash != (common.Hash{}) {
|
if update.SafeBlockHash != (common.Hash{}) {
|
||||||
safeBlock := api.eth.BlockChain().GetBlockByHash(update.SafeBlockHash)
|
safeBlock := api.eth.BlockChain().GetBlockByHash(update.SafeBlockHash)
|
||||||
if safeBlock == nil {
|
if safeBlock == nil {
|
||||||
|
|
@ -378,6 +374,19 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
||||||
if api.localBlocks.has(id) {
|
if api.localBlocks.has(id) {
|
||||||
return valid(&id), nil
|
return valid(&id), nil
|
||||||
}
|
}
|
||||||
|
// If the beacon chain is ran by a simulator, then transaction insertion,
|
||||||
|
// block insertion and block production will happen without any timing
|
||||||
|
// delay between them. This will cause flaky simulator executions due to
|
||||||
|
// the transaction pool running its internal reset operation on a back-
|
||||||
|
// ground thread. To avoid the racey behavior - in simulator mode - the
|
||||||
|
// pool will be explicitly blocked on its reset before continuing to the
|
||||||
|
// block production below.
|
||||||
|
if simulatorMode {
|
||||||
|
if err := api.eth.TxPool().Sync(); err != nil {
|
||||||
|
log.Error("Failed to sync transaction pool", "err", err)
|
||||||
|
return valid(nil), engine.InvalidPayloadAttributes.With(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
payload, err := api.eth.Miner().BuildPayload(args)
|
payload, err := api.eth.Miner().BuildPayload(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to build payload", "err", err)
|
log.Error("Failed to build payload", "err", err)
|
||||||
|
|
@ -457,27 +466,39 @@ func (api *ConsensusAPI) NewPayloadV1(params engine.ExecutableData) (engine.Payl
|
||||||
|
|
||||||
// NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
// NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
||||||
func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.PayloadStatusV1, error) {
|
func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.PayloadStatusV1, error) {
|
||||||
if api.eth.BlockChain().Config().IsShanghai(new(big.Int).SetUint64(params.Number), params.Timestamp) {
|
if api.eth.BlockChain().Config().IsCancun(api.eth.BlockChain().Config().LondonBlock, params.Timestamp) {
|
||||||
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("can't use new payload v2 post-shanghai"))
|
||||||
|
}
|
||||||
|
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) == forks.Shanghai {
|
||||||
if params.Withdrawals == nil {
|
if params.Withdrawals == nil {
|
||||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai"))
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai"))
|
||||||
}
|
}
|
||||||
} else if params.Withdrawals != nil {
|
} else {
|
||||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil withdrawals pre-shanghai"))
|
if params.Withdrawals != nil {
|
||||||
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil withdrawals pre-shanghai"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if api.eth.BlockChain().Config().IsCancun(new(big.Int).SetUint64(params.Number), params.Timestamp) {
|
if params.ExcessBlobGas != nil {
|
||||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("newPayloadV2 called post-cancun"))
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil excessBlobGas pre-cancun"))
|
||||||
|
}
|
||||||
|
if params.BlobGasUsed != nil {
|
||||||
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("non-nil params.BlobGasUsed pre-cancun"))
|
||||||
}
|
}
|
||||||
return api.newPayload(params, nil, nil)
|
return api.newPayload(params, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayloadV3 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
// NewPayloadV3 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
||||||
func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) {
|
func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (engine.PayloadStatusV1, error) {
|
||||||
|
if params.Withdrawals == nil {
|
||||||
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai"))
|
||||||
|
}
|
||||||
if params.ExcessBlobGas == nil {
|
if params.ExcessBlobGas == nil {
|
||||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil excessBlobGas post-cancun"))
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil excessBlobGas post-cancun"))
|
||||||
}
|
}
|
||||||
if params.BlobGasUsed == nil {
|
if params.BlobGasUsed == nil {
|
||||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil params.BlobGasUsed post-cancun"))
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil params.BlobGasUsed post-cancun"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if versionedHashes == nil {
|
if versionedHashes == nil {
|
||||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil versionedHashes post-cancun"))
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil versionedHashes post-cancun"))
|
||||||
}
|
}
|
||||||
|
|
@ -485,10 +506,9 @@ func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHas
|
||||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil parentBeaconBlockRoot post-cancun"))
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil parentBeaconBlockRoot post-cancun"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !api.eth.BlockChain().Config().IsCancun(new(big.Int).SetUint64(params.Number), params.Timestamp) {
|
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun {
|
||||||
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV3 called pre-cancun"))
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV3 must only be called for cancun payloads"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.newPayload(params, versionedHashes, beaconRoot)
|
return api.newPayload(params, versionedHashes, beaconRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1237,7 +1237,15 @@ func TestNilWithdrawals(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
_, err := api.ForkchoiceUpdatedV2(fcState, &test.blockParams)
|
var (
|
||||||
|
err error
|
||||||
|
shanghai = genesis.Config.IsShanghai(genesis.Config.LondonBlock, test.blockParams.Timestamp)
|
||||||
|
)
|
||||||
|
if !shanghai {
|
||||||
|
_, err = api.ForkchoiceUpdatedV1(fcState, &test.blockParams)
|
||||||
|
} else {
|
||||||
|
_, err = api.ForkchoiceUpdatedV2(fcState, &test.blockParams)
|
||||||
|
}
|
||||||
if test.wantErr {
|
if test.wantErr {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("wanted error on fcuv2 with invalid withdrawals")
|
t.Fatal("wanted error on fcuv2 with invalid withdrawals")
|
||||||
|
|
@ -1254,14 +1262,19 @@ func TestNilWithdrawals(t *testing.T) {
|
||||||
Timestamp: test.blockParams.Timestamp,
|
Timestamp: test.blockParams.Timestamp,
|
||||||
FeeRecipient: test.blockParams.SuggestedFeeRecipient,
|
FeeRecipient: test.blockParams.SuggestedFeeRecipient,
|
||||||
Random: test.blockParams.Random,
|
Random: test.blockParams.Random,
|
||||||
BeaconRoot: test.blockParams.BeaconRoot,
|
|
||||||
}).Id()
|
}).Id()
|
||||||
execData, err := api.GetPayloadV2(payloadID)
|
execData, err := api.GetPayloadV2(payloadID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error getting payload, err=%v", err)
|
t.Fatalf("error getting payload, err=%v", err)
|
||||||
}
|
}
|
||||||
if status, err := api.NewPayloadV2(*execData.ExecutionPayload); err != nil {
|
var status engine.PayloadStatusV1
|
||||||
t.Fatalf("error validating payload: %v", err)
|
if !shanghai {
|
||||||
|
status, err = api.NewPayloadV1(*execData.ExecutionPayload)
|
||||||
|
} else {
|
||||||
|
status, err = api.NewPayloadV2(*execData.ExecutionPayload)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error validating payload: %v", err.(*engine.EngineAPIError).ErrorData())
|
||||||
} else if status.Status != engine.VALID {
|
} else if status.Status != engine.VALID {
|
||||||
t.Fatalf("invalid payload")
|
t.Fatalf("invalid payload")
|
||||||
}
|
}
|
||||||
|
|
@ -1587,7 +1600,7 @@ func TestParentBeaconBlockRoot(t *testing.T) {
|
||||||
fcState := engine.ForkchoiceStateV1{
|
fcState := engine.ForkchoiceStateV1{
|
||||||
HeadBlockHash: parent.Hash(),
|
HeadBlockHash: parent.Hash(),
|
||||||
}
|
}
|
||||||
resp, err := api.ForkchoiceUpdatedV2(fcState, &blockParams)
|
resp, err := api.ForkchoiceUpdatedV3(fcState, &blockParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error preparing payload, err=%v", err.(*engine.EngineAPIError).ErrorData())
|
t.Fatalf("error preparing payload, err=%v", err.(*engine.EngineAPIError).ErrorData())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,12 +155,12 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
|
||||||
|
|
||||||
var random [32]byte
|
var random [32]byte
|
||||||
rand.Read(random[:])
|
rand.Read(random[:])
|
||||||
fcResponse, err := c.engineAPI.ForkchoiceUpdatedV2(c.curForkchoiceState, &engine.PayloadAttributes{
|
fcResponse, err := c.engineAPI.forkchoiceUpdated(c.curForkchoiceState, &engine.PayloadAttributes{
|
||||||
Timestamp: timestamp,
|
Timestamp: timestamp,
|
||||||
SuggestedFeeRecipient: feeRecipient,
|
SuggestedFeeRecipient: feeRecipient,
|
||||||
Withdrawals: withdrawals,
|
Withdrawals: withdrawals,
|
||||||
Random: random,
|
Random: random,
|
||||||
})
|
}, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,9 +71,9 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
|
||||||
}
|
}
|
||||||
// Recap the highest gas limit with account's available balance.
|
// Recap the highest gas limit with account's available balance.
|
||||||
if feeCap.BitLen() != 0 {
|
if feeCap.BitLen() != 0 {
|
||||||
balance := opts.State.GetBalance(call.From)
|
balance := opts.State.GetBalance(call.From).ToBig()
|
||||||
|
|
||||||
available := new(big.Int).Set(balance)
|
available := balance
|
||||||
if call.Value != nil {
|
if call.Value != nil {
|
||||||
if call.Value.Cmp(available) >= 0 {
|
if call.Value.Cmp(available) >= 0 {
|
||||||
return 0, nil, core.ErrInsufficientFundsForTransfer
|
return 0, nil, core.ErrInsufficientFundsForTransfer
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie/testutil"
|
"github.com/ethereum/go-ethereum/trie/testutil"
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
@ -1510,7 +1511,7 @@ func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv)
|
||||||
for i := uint64(1); i <= uint64(n); i++ {
|
for i := uint64(1); i <= uint64(n); i++ {
|
||||||
value, _ := rlp.EncodeToBytes(&types.StateAccount{
|
value, _ := rlp.EncodeToBytes(&types.StateAccount{
|
||||||
Nonce: i,
|
Nonce: i,
|
||||||
Balance: big.NewInt(int64(i)),
|
Balance: uint256.NewInt(i),
|
||||||
Root: types.EmptyRootHash,
|
Root: types.EmptyRootHash,
|
||||||
CodeHash: getCodeHash(i),
|
CodeHash: getCodeHash(i),
|
||||||
})
|
})
|
||||||
|
|
@ -1561,7 +1562,7 @@ func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) {
|
||||||
for i := 0; i < len(boundaries); i++ {
|
for i := 0; i < len(boundaries); i++ {
|
||||||
value, _ := rlp.EncodeToBytes(&types.StateAccount{
|
value, _ := rlp.EncodeToBytes(&types.StateAccount{
|
||||||
Nonce: uint64(0),
|
Nonce: uint64(0),
|
||||||
Balance: big.NewInt(int64(i)),
|
Balance: uint256.NewInt(uint64(i)),
|
||||||
Root: types.EmptyRootHash,
|
Root: types.EmptyRootHash,
|
||||||
CodeHash: getCodeHash(uint64(i)),
|
CodeHash: getCodeHash(uint64(i)),
|
||||||
})
|
})
|
||||||
|
|
@ -1573,7 +1574,7 @@ func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) {
|
||||||
for i := uint64(1); i <= uint64(n); i++ {
|
for i := uint64(1); i <= uint64(n); i++ {
|
||||||
value, _ := rlp.EncodeToBytes(&types.StateAccount{
|
value, _ := rlp.EncodeToBytes(&types.StateAccount{
|
||||||
Nonce: i,
|
Nonce: i,
|
||||||
Balance: big.NewInt(int64(i)),
|
Balance: uint256.NewInt(i),
|
||||||
Root: types.EmptyRootHash,
|
Root: types.EmptyRootHash,
|
||||||
CodeHash: getCodeHash(i),
|
CodeHash: getCodeHash(i),
|
||||||
})
|
})
|
||||||
|
|
@ -1617,7 +1618,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots
|
||||||
|
|
||||||
value, _ := rlp.EncodeToBytes(&types.StateAccount{
|
value, _ := rlp.EncodeToBytes(&types.StateAccount{
|
||||||
Nonce: i,
|
Nonce: i,
|
||||||
Balance: big.NewInt(int64(i)),
|
Balance: uint256.NewInt(i),
|
||||||
Root: stRoot,
|
Root: stRoot,
|
||||||
CodeHash: codehash,
|
CodeHash: codehash,
|
||||||
})
|
})
|
||||||
|
|
@ -1683,7 +1684,7 @@ func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, bounda
|
||||||
|
|
||||||
value, _ := rlp.EncodeToBytes(&types.StateAccount{
|
value, _ := rlp.EncodeToBytes(&types.StateAccount{
|
||||||
Nonce: i,
|
Nonce: i,
|
||||||
Balance: big.NewInt(int64(i)),
|
Balance: uint256.NewInt(i),
|
||||||
Root: stRoot,
|
Root: stRoot,
|
||||||
CodeHash: codehash,
|
CodeHash: codehash,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
type account struct{}
|
type account struct{}
|
||||||
|
|
@ -37,9 +38,9 @@ func (account) SubBalance(amount *big.Int) {}
|
||||||
func (account) AddBalance(amount *big.Int) {}
|
func (account) AddBalance(amount *big.Int) {}
|
||||||
func (account) SetAddress(common.Address) {}
|
func (account) SetAddress(common.Address) {}
|
||||||
func (account) Value() *big.Int { return nil }
|
func (account) Value() *big.Int { return nil }
|
||||||
func (account) SetBalance(*big.Int) {}
|
func (account) SetBalance(*uint256.Int) {}
|
||||||
func (account) SetNonce(uint64) {}
|
func (account) SetNonce(uint64) {}
|
||||||
func (account) Balance() *big.Int { return nil }
|
func (account) Balance() *uint256.Int { return nil }
|
||||||
func (account) Address() common.Address { return common.Address{} }
|
func (account) Address() common.Address { return common.Address{} }
|
||||||
func (account) SetCode(common.Hash, []byte) {}
|
func (account) SetCode(common.Hash, []byte) {}
|
||||||
func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
|
func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
|
||||||
|
|
@ -48,8 +49,8 @@ type dummyStatedb struct {
|
||||||
state.StateDB
|
state.StateDB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*dummyStatedb) GetRefund() uint64 { return 1337 }
|
func (*dummyStatedb) GetRefund() uint64 { return 1337 }
|
||||||
func (*dummyStatedb) GetBalance(addr common.Address) *big.Int { return new(big.Int) }
|
func (*dummyStatedb) GetBalance(addr common.Address) *uint256.Int { return new(uint256.Int) }
|
||||||
|
|
||||||
type vmContext struct {
|
type vmContext struct {
|
||||||
blockCtx vm.BlockContext
|
blockCtx vm.BlockContext
|
||||||
|
|
@ -65,7 +66,7 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon
|
||||||
env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer})
|
env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer})
|
||||||
gasLimit uint64 = 31000
|
gasLimit uint64 = 31000
|
||||||
startGas uint64 = 10000
|
startGas uint64 = 10000
|
||||||
value = big.NewInt(0)
|
value = uint256.NewInt(0)
|
||||||
contract = vm.NewContract(account{}, account{}, value, startGas)
|
contract = vm.NewContract(account{}, account{}, value, startGas)
|
||||||
)
|
)
|
||||||
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
|
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
|
||||||
|
|
@ -74,7 +75,7 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon
|
||||||
}
|
}
|
||||||
|
|
||||||
tracer.CaptureTxStart(gasLimit)
|
tracer.CaptureTxStart(gasLimit)
|
||||||
tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value)
|
tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value.ToBig())
|
||||||
ret, err := env.Interpreter().Run(contract, []byte{}, false)
|
ret, err := env.Interpreter().Run(contract, []byte{}, false)
|
||||||
tracer.CaptureEnd(ret, startGas-contract.Gas, err)
|
tracer.CaptureEnd(ret, startGas-contract.Gas, err)
|
||||||
// Rest gas assumes no refund
|
// Rest gas assumes no refund
|
||||||
|
|
@ -182,7 +183,7 @@ func TestHaltBetweenSteps(t *testing.T) {
|
||||||
}
|
}
|
||||||
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer})
|
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer})
|
||||||
scope := &vm.ScopeContext{
|
scope := &vm.ScopeContext{
|
||||||
Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0),
|
Contract: vm.NewContract(&account{}, &account{}, uint256.NewInt(0), 0),
|
||||||
}
|
}
|
||||||
tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 0, big.NewInt(0))
|
tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 0, big.NewInt(0))
|
||||||
tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil)
|
tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil)
|
||||||
|
|
@ -273,7 +274,7 @@ func TestEnterExit(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
scope := &vm.ScopeContext{
|
scope := &vm.ScopeContext{
|
||||||
Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0),
|
Contract: vm.NewContract(&account{}, &account{}, uint256.NewInt(0), 0),
|
||||||
}
|
}
|
||||||
tracer.CaptureEnter(vm.CALL, scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int))
|
tracer.CaptureEnter(vm.CALL, scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int))
|
||||||
tracer.CaptureExit([]byte{}, 400, nil)
|
tracer.CaptureExit([]byte{}, 400, nil)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dummyContractRef struct {
|
type dummyContractRef struct {
|
||||||
|
|
@ -56,7 +57,7 @@ func TestStoreCapture(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
logger = NewStructLogger(nil)
|
logger = NewStructLogger(nil)
|
||||||
env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger})
|
env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger})
|
||||||
contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 100000)
|
contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(uint256.Int), 100000)
|
||||||
)
|
)
|
||||||
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)}
|
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)}
|
||||||
var index common.Hash
|
var index common.Hash
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ func (t *prestateTracer) CaptureTxEnd(restGas uint64) {
|
||||||
}
|
}
|
||||||
modified := false
|
modified := false
|
||||||
postAccount := &account{Storage: make(map[common.Hash]common.Hash)}
|
postAccount := &account{Storage: make(map[common.Hash]common.Hash)}
|
||||||
newBalance := t.env.StateDB.GetBalance(addr)
|
newBalance := t.env.StateDB.GetBalance(addr).ToBig()
|
||||||
newNonce := t.env.StateDB.GetNonce(addr)
|
newNonce := t.env.StateDB.GetNonce(addr)
|
||||||
newCode := t.env.StateDB.GetCode(addr)
|
newCode := t.env.StateDB.GetCode(addr)
|
||||||
|
|
||||||
|
|
@ -279,7 +279,7 @@ func (t *prestateTracer) lookupAccount(addr common.Address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
t.pre[addr] = &account{
|
t.pre[addr] = &account{
|
||||||
Balance: t.env.StateDB.GetBalance(addr),
|
Balance: t.env.StateDB.GetBalance(addr).ToBig(),
|
||||||
Nonce: t.env.StateDB.GetNonce(addr),
|
Nonce: t.env.StateDB.GetNonce(addr),
|
||||||
Code: t.env.StateDB.GetCode(addr),
|
Code: t.env.StateDB.GetCode(addr),
|
||||||
Storage: make(map[common.Hash]common.Hash),
|
Storage: make(map[common.Hash]common.Hash),
|
||||||
|
|
|
||||||
4
go.mod
4
go.mod
|
|
@ -65,7 +65,7 @@ require (
|
||||||
golang.org/x/crypto v0.17.0
|
golang.org/x/crypto v0.17.0
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
||||||
golang.org/x/sync v0.5.0
|
golang.org/x/sync v0.5.0
|
||||||
golang.org/x/sys v0.15.0
|
golang.org/x/sys v0.16.0
|
||||||
golang.org/x/text v0.14.0
|
golang.org/x/text v0.14.0
|
||||||
golang.org/x/time v0.3.0
|
golang.org/x/time v0.3.0
|
||||||
golang.org/x/tools v0.15.0
|
golang.org/x/tools v0.15.0
|
||||||
|
|
@ -101,7 +101,7 @@ require (
|
||||||
github.com/deepmap/oapi-codegen v1.6.0 // indirect
|
github.com/deepmap/oapi-codegen v1.6.0 // indirect
|
||||||
github.com/dlclark/regexp2 v1.7.0 // indirect
|
github.com/dlclark/regexp2 v1.7.0 // indirect
|
||||||
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect
|
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
|
|
||||||
5
go.sum
5
go.sum
|
|
@ -223,6 +223,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
|
||||||
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||||
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
|
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
|
||||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
|
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
|
||||||
|
|
@ -771,11 +773,14 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ func (a *Account) Balance(ctx context.Context) (hexutil.Big, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hexutil.Big{}, err
|
return hexutil.Big{}, err
|
||||||
}
|
}
|
||||||
balance := state.GetBalance(a.address)
|
balance := state.GetBalance(a.address).ToBig()
|
||||||
if balance == nil {
|
if balance == nil {
|
||||||
return hexutil.Big{}, fmt.Errorf("failed to load balance %x", a.address)
|
return hexutil.Big{}, fmt.Errorf("failed to load balance %x", a.address)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"github.com/tyler-smith/go-bip39"
|
"github.com/tyler-smith/go-bip39"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -650,7 +651,8 @@ func (s *BlockChainAPI) GetBalance(ctx context.Context, address common.Address,
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
|
b := state.GetBalance(address).ToBig()
|
||||||
|
return (*hexutil.Big)(b), state.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result structs for GetProof
|
// Result structs for GetProof
|
||||||
|
|
@ -748,10 +750,11 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st
|
||||||
if err := tr.Prove(crypto.Keccak256(address.Bytes()), &accountProof); err != nil {
|
if err := tr.Prove(crypto.Keccak256(address.Bytes()), &accountProof); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
balance := statedb.GetBalance(address).ToBig()
|
||||||
return &AccountResult{
|
return &AccountResult{
|
||||||
Address: address,
|
Address: address,
|
||||||
AccountProof: accountProof,
|
AccountProof: accountProof,
|
||||||
Balance: (*hexutil.Big)(statedb.GetBalance(address)),
|
Balance: (*hexutil.Big)(balance),
|
||||||
CodeHash: codeHash,
|
CodeHash: codeHash,
|
||||||
Nonce: hexutil.Uint64(statedb.GetNonce(address)),
|
Nonce: hexutil.Uint64(statedb.GetNonce(address)),
|
||||||
StorageHash: storageRoot,
|
StorageHash: storageRoot,
|
||||||
|
|
@ -974,7 +977,8 @@ func (diff *StateOverride) Apply(state *state.StateDB) error {
|
||||||
}
|
}
|
||||||
// Override account balance.
|
// Override account balance.
|
||||||
if account.Balance != nil {
|
if account.Balance != nil {
|
||||||
state.SetBalance(addr, (*big.Int)(*account.Balance))
|
u256Balance, _ := uint256.FromBig((*big.Int)(*account.Balance))
|
||||||
|
state.SetBalance(addr, u256Balance)
|
||||||
}
|
}
|
||||||
if account.State != nil && account.StateDiff != nil {
|
if account.State != nil && account.StateDiff != nil {
|
||||||
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
|
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ func (e *TxIndexingError) Error() string {
|
||||||
// ErrorCode returns the JSON error code for a revert.
|
// ErrorCode returns the JSON error code for a revert.
|
||||||
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
|
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
|
||||||
func (e *TxIndexingError) ErrorCode() int {
|
func (e *TxIndexingError) ErrorCode() int {
|
||||||
return 3 // TODO tbd
|
return -32000 // to be decided
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrorData returns the hex encoded revert reason.
|
// ErrorData returns the hex encoded revert reason.
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -228,7 +229,7 @@ func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consens
|
||||||
taskCh := make(chan struct{}, 2)
|
taskCh := make(chan struct{}, 2)
|
||||||
checkEqual := func(t *testing.T, task *task) {
|
checkEqual := func(t *testing.T, task *task) {
|
||||||
// The work should contain 1 tx
|
// The work should contain 1 tx
|
||||||
receiptLen, balance := 1, big.NewInt(1000)
|
receiptLen, balance := 1, uint256.NewInt(1000)
|
||||||
if len(task.receipts) != receiptLen {
|
if len(task.receipts) != receiptLen {
|
||||||
t.Fatalf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen)
|
t.Fatalf("receipt number mismatch: have %d, want %d", len(task.receipts), receiptLen)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Genesis hashes to enforce below configs on.
|
// Genesis hashes to enforce below configs on.
|
||||||
|
|
@ -750,6 +751,23 @@ func (c *ChainConfig) ElasticityMultiplier() uint64 {
|
||||||
return DefaultElasticityMultiplier
|
return DefaultElasticityMultiplier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LatestFork returns the latest time-based fork that would be active for the given time.
|
||||||
|
func (c *ChainConfig) LatestFork(time uint64) forks.Fork {
|
||||||
|
// Assume last non-time-based fork has passed.
|
||||||
|
london := c.LondonBlock
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case c.IsPrague(london, time):
|
||||||
|
return forks.Prague
|
||||||
|
case c.IsCancun(london, time):
|
||||||
|
return forks.Cancun
|
||||||
|
case c.IsShanghai(london, time):
|
||||||
|
return forks.Shanghai
|
||||||
|
default:
|
||||||
|
return forks.Paris
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// isForkBlockIncompatible returns true if a fork scheduled at block s1 cannot be
|
// isForkBlockIncompatible returns true if a fork scheduled at block s1 cannot be
|
||||||
// rescheduled to block s2 because head is already past the fork.
|
// rescheduled to block s2 because head is already past the fork.
|
||||||
func isForkBlockIncompatible(s1, s2, head *big.Int) bool {
|
func isForkBlockIncompatible(s1, s2, head *big.Int) bool {
|
||||||
|
|
|
||||||
42
params/forks/forks.go
Normal file
42
params/forks/forks.go
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package forks
|
||||||
|
|
||||||
|
// Fork is a numerical identifier of specific network upgrades (forks).
|
||||||
|
type Fork int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Frontier = iota
|
||||||
|
FrontierThawing
|
||||||
|
Homestead
|
||||||
|
DAO
|
||||||
|
TangerineWhistle
|
||||||
|
SpuriousDragon
|
||||||
|
Byzantium
|
||||||
|
Constantinople
|
||||||
|
Petersburg
|
||||||
|
Istanbul
|
||||||
|
MuirGlacier
|
||||||
|
Berlin
|
||||||
|
London
|
||||||
|
ArrowGlacier
|
||||||
|
GrayGlacier
|
||||||
|
Paris
|
||||||
|
Shanghai
|
||||||
|
Cancun
|
||||||
|
Prague
|
||||||
|
)
|
||||||
|
|
@ -328,7 +328,7 @@ func (t *BlockTest) validatePostState(statedb *state.StateDB) error {
|
||||||
for addr, acct := range t.json.Post {
|
for addr, acct := range t.json.Post {
|
||||||
// address is indirectly verified by the other fields, as it's the db key
|
// address is indirectly verified by the other fields, as it's the db key
|
||||||
code2 := statedb.GetCode(addr)
|
code2 := statedb.GetCode(addr)
|
||||||
balance2 := statedb.GetBalance(addr)
|
balance2 := statedb.GetBalance(addr).ToBig()
|
||||||
nonce2 := statedb.GetNonce(addr)
|
nonce2 := statedb.GetNonce(addr)
|
||||||
if !bytes.Equal(code2, acct.Code) {
|
if !bytes.Equal(code2, acct.Code) {
|
||||||
return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2))
|
return fmt.Errorf("account code mismatch for addr: %s want: %v have: %s", addr, acct.Code, hex.EncodeToString(code2))
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestState(t *testing.T) {
|
func TestState(t *testing.T) {
|
||||||
|
|
@ -279,7 +280,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
// Execute the message.
|
// Execute the message.
|
||||||
_, leftOverGas, err := evm.Call(sender, *msg.To, msg.Data, msg.GasLimit, msg.Value)
|
_, leftOverGas, err := evm.Call(sender, *msg.To, msg.Data, msg.GasLimit, uint256.MustFromBig(msg.Value))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Error(err)
|
b.Error(err)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -315,7 +316,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
// - the coinbase self-destructed, or
|
// - the coinbase self-destructed, or
|
||||||
// - there are only 'bad' transactions, which aren't executed. In those cases,
|
// - there are only 'bad' transactions, which aren't executed. In those cases,
|
||||||
// the coinbase gets no txfee, so isn't created, and thus needs to be touched
|
// the coinbase gets no txfee, so isn't created, and thus needs to be touched
|
||||||
statedb.AddBalance(block.Coinbase(), new(big.Int))
|
statedb.AddBalance(block.Coinbase(), new(uint256.Int))
|
||||||
|
|
||||||
// Commit state mutations into database.
|
// Commit state mutations into database.
|
||||||
root, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number()))
|
root, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number()))
|
||||||
|
|
@ -339,7 +340,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter boo
|
||||||
for addr, a := range accounts {
|
for addr, a := range accounts {
|
||||||
statedb.SetCode(addr, a.Code)
|
statedb.SetCode(addr, a.Code)
|
||||||
statedb.SetNonce(addr, a.Nonce)
|
statedb.SetNonce(addr, a.Nonce)
|
||||||
statedb.SetBalance(addr, a.Balance)
|
statedb.SetBalance(addr, uint256.MustFromBig(a.Balance))
|
||||||
for k, v := range a.Storage {
|
for k, v := range a.Storage {
|
||||||
statedb.SetState(addr, k, v)
|
statedb.SetState(addr, k, v)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -37,6 +36,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -796,7 +796,7 @@ func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) {
|
||||||
numBytes := random.Uint32() % 33 // [0, 32] bytes
|
numBytes := random.Uint32() % 33 // [0, 32] bytes
|
||||||
balanceBytes := make([]byte, numBytes)
|
balanceBytes := make([]byte, numBytes)
|
||||||
random.Read(balanceBytes)
|
random.Read(balanceBytes)
|
||||||
balance := new(big.Int).SetBytes(balanceBytes)
|
balance := new(uint256.Int).SetBytes(balanceBytes)
|
||||||
data, _ := rlp.EncodeToBytes(&types.StateAccount{Nonce: nonce, Balance: balance, Root: root, CodeHash: code})
|
data, _ := rlp.EncodeToBytes(&types.StateAccount{Nonce: nonce, Balance: balance, Root: root, CodeHash: code})
|
||||||
accounts[i] = data
|
accounts[i] = data
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -32,6 +31,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie/testutil"
|
"github.com/ethereum/go-ethereum/trie/testutil"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
"github.com/ethereum/go-ethereum/trie/triestate"
|
"github.com/ethereum/go-ethereum/trie/triestate"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[common.Hash][]byte) (common.Hash, *trienode.NodeSet) {
|
func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[common.Hash][]byte) (common.Hash, *trienode.NodeSet) {
|
||||||
|
|
@ -53,7 +53,7 @@ func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[comm
|
||||||
func generateAccount(storageRoot common.Hash) types.StateAccount {
|
func generateAccount(storageRoot common.Hash) types.StateAccount {
|
||||||
return types.StateAccount{
|
return types.StateAccount{
|
||||||
Nonce: uint64(rand.Intn(100)),
|
Nonce: uint64(rand.Intn(100)),
|
||||||
Balance: big.NewInt(rand.Int63()),
|
Balance: uint256.NewInt(rand.Uint64()),
|
||||||
CodeHash: testutil.RandBytes(32),
|
CodeHash: testutil.RandBytes(32),
|
||||||
Root: storageRoot,
|
Root: storageRoot,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
@ -108,7 +107,7 @@ func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error
|
||||||
for i := 0; i < len(balance)/2; i++ {
|
for i := 0; i < len(balance)/2; i++ {
|
||||||
balance[len(balance)-i-1], balance[i] = balance[i], balance[len(balance)-i-1]
|
balance[len(balance)-i-1], balance[i] = balance[i], balance[len(balance)-i-1]
|
||||||
}
|
}
|
||||||
acc.Balance = new(big.Int).SetBytes(balance[:])
|
acc.Balance = new(uint256.Int).SetBytes32(balance[:])
|
||||||
|
|
||||||
// Decode codehash
|
// Decode codehash
|
||||||
acc.CodeHash = values[utils.CodeKeccakLeafKey]
|
acc.CodeHash = values[utils.CodeKeccakLeafKey]
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package trie
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"math/big"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -27,18 +26,19 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
"github.com/ethereum/go-ethereum/trie/triedb/pathdb"
|
||||||
"github.com/ethereum/go-ethereum/trie/utils"
|
"github.com/ethereum/go-ethereum/trie/utils"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
accounts = map[common.Address]*types.StateAccount{
|
accounts = map[common.Address]*types.StateAccount{
|
||||||
{1}: {
|
{1}: {
|
||||||
Nonce: 100,
|
Nonce: 100,
|
||||||
Balance: big.NewInt(100),
|
Balance: uint256.NewInt(100),
|
||||||
CodeHash: common.Hash{0x1}.Bytes(),
|
CodeHash: common.Hash{0x1}.Bytes(),
|
||||||
},
|
},
|
||||||
{2}: {
|
{2}: {
|
||||||
Nonce: 200,
|
Nonce: 200,
|
||||||
Balance: big.NewInt(200),
|
Balance: uint256.NewInt(200),
|
||||||
CodeHash: common.Hash{0x2}.Bytes(),
|
CodeHash: common.Hash{0x2}.Bytes(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue