Merge tag 'v1.10.13' into HEAD
This commit is contained in:
+8
-8
@@ -296,7 +296,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||
if diskRoot != (common.Hash{}) {
|
||||
log.Warn("Head state missing, repairing", "number", head.Number(), "hash", head.Hash(), "snaproot", diskRoot)
|
||||
|
||||
snapDisk, err := bc.SetHeadBeyondRoot(head.NumberU64(), diskRoot)
|
||||
snapDisk, err := bc.setHeadBeyondRoot(head.NumberU64(), diskRoot, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -306,7 +306,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||
}
|
||||
} else {
|
||||
log.Warn("Head state missing, repairing", "number", head.Number(), "hash", head.Hash())
|
||||
if err := bc.SetHead(head.NumberU64()); err != nil {
|
||||
if _, err := bc.setHeadBeyondRoot(head.NumberU64(), common.Hash{}, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -482,11 +482,11 @@ func (bc *BlockChain) loadLastState() error {
|
||||
// was fast synced or full synced and in which state, the method will try to
|
||||
// delete minimal data from disk whilst retaining chain consistency.
|
||||
func (bc *BlockChain) SetHead(head uint64) error {
|
||||
_, err := bc.SetHeadBeyondRoot(head, common.Hash{})
|
||||
_, err := bc.setHeadBeyondRoot(head, common.Hash{}, false)
|
||||
return err
|
||||
}
|
||||
|
||||
// SetHeadBeyondRoot rewinds the local chain to a new head with the extra condition
|
||||
// setHeadBeyondRoot rewinds the local chain to a new head with the extra condition
|
||||
// that the rewind must pass the specified state root. This method is meant to be
|
||||
// used when rewinding with snapshots enabled to ensure that we go back further than
|
||||
// persistent disk layer. Depending on whether the node was fast synced or full, and
|
||||
@@ -494,7 +494,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
|
||||
// retaining chain consistency.
|
||||
//
|
||||
// The method returns the block number where the requested root cap was found.
|
||||
func (bc *BlockChain) SetHeadBeyondRoot(head uint64, root common.Hash) (uint64, error) {
|
||||
func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bool) (uint64, error) {
|
||||
if !bc.chainmu.TryLock() {
|
||||
return 0, errChainStopped
|
||||
}
|
||||
@@ -509,7 +509,7 @@ func (bc *BlockChain) SetHeadBeyondRoot(head uint64, root common.Hash) (uint64,
|
||||
frozen, _ := bc.db.Ancients()
|
||||
|
||||
updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (uint64, bool) {
|
||||
// Rewind the block chain, ensuring we don't end up with a stateless head
|
||||
// Rewind the blockchain, ensuring we don't end up with a stateless head
|
||||
// block. Note, depth equality is permitted to allow using SetHead as a
|
||||
// chain reparation mechanism without deleting any data!
|
||||
if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() <= currentBlock.NumberU64() {
|
||||
@@ -610,8 +610,8 @@ func (bc *BlockChain) SetHeadBeyondRoot(head uint64, root common.Hash) (uint64,
|
||||
}
|
||||
// If SetHead was only called as a chain reparation method, try to skip
|
||||
// touching the header chain altogether, unless the freezer is broken
|
||||
if block := bc.CurrentBlock(); block.NumberU64() == head {
|
||||
if target, force := updateFn(bc.db, block.Header()); force {
|
||||
if repair {
|
||||
if target, force := updateFn(bc.db, bc.CurrentBlock().Header()); force {
|
||||
bc.hc.SetHead(target, updateFn, delFn)
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -51,6 +51,10 @@ var (
|
||||
// next one expected based on the local chain.
|
||||
ErrNonceTooHigh = errors.New("nonce too high")
|
||||
|
||||
// ErrNonceMax is returned if the nonce of a transaction sender account has
|
||||
// maximum allowed value and would become invalid if incremented.
|
||||
ErrNonceMax = errors.New("nonce has max value")
|
||||
|
||||
// ErrGasLimitReached is returned by the gas pool if the amount of gas required
|
||||
// by a transaction is higher than what's left in the block.
|
||||
ErrGasLimitReached = errors.New("gas limit reached")
|
||||
|
||||
+2
-2
@@ -416,7 +416,7 @@ func DefaultSepoliaGenesisBlock() *Genesis {
|
||||
}
|
||||
|
||||
// DeveloperGenesisBlock returns the 'geth --dev' genesis block.
|
||||
func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis {
|
||||
func DeveloperGenesisBlock(period uint64, gasLimit uint64, faucet common.Address) *Genesis {
|
||||
// Override the default period to the user requested one
|
||||
config := *params.AllCliqueProtocolChanges
|
||||
config.Clique = ¶ms.CliqueConfig{
|
||||
@@ -428,7 +428,7 @@ func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis {
|
||||
return &Genesis{
|
||||
Config: &config,
|
||||
ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, crypto.SignatureLength)...),
|
||||
GasLimit: 11500000,
|
||||
GasLimit: gasLimit,
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Difficulty: big.NewInt(1),
|
||||
Alloc: map[common.Address]GenesisAccount{
|
||||
|
||||
@@ -669,7 +669,7 @@ func deriveLogFields(receipts []*receiptLogs, hash common.Hash, number uint64, t
|
||||
// ReadLogs retrieves the logs for all transactions in a block. The log fields
|
||||
// are populated with metadata. In case the receipts or the block body
|
||||
// are not found, a nil is returned.
|
||||
func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64) [][]*types.Log {
|
||||
func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64, config *params.ChainConfig) [][]*types.Log {
|
||||
// Retrieve the flattened receipt slice
|
||||
data := ReadReceiptsRLP(db, hash, number)
|
||||
if len(data) == 0 {
|
||||
@@ -677,7 +677,12 @@ func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64) [][]*types.Log {
|
||||
}
|
||||
receipts := []*receiptLogs{}
|
||||
if err := rlp.DecodeBytes(data, &receipts); err != nil {
|
||||
log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
|
||||
// Receipts might be in the legacy format, try decoding that.
|
||||
// TODO: to be removed after users migrated
|
||||
if logs := readLegacyLogs(db, hash, number, config); logs != nil {
|
||||
return logs
|
||||
}
|
||||
log.Error("Invalid receipt array RLP", "hash", "err", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -697,6 +702,21 @@ func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64) [][]*types.Log {
|
||||
return logs
|
||||
}
|
||||
|
||||
// readLegacyLogs is a temporary workaround for when trying to read logs
|
||||
// from a block which has its receipt stored in the legacy format. It'll
|
||||
// be removed after users have migrated their freezer databases.
|
||||
func readLegacyLogs(db ethdb.Reader, hash common.Hash, number uint64, config *params.ChainConfig) [][]*types.Log {
|
||||
receipts := ReadReceipts(db, hash, number, config)
|
||||
if receipts == nil {
|
||||
return nil
|
||||
}
|
||||
logs := make([][]*types.Log, len(receipts))
|
||||
for i, receipt := range receipts {
|
||||
logs[i] = receipt.Logs
|
||||
}
|
||||
return logs
|
||||
}
|
||||
|
||||
// ReadBlock retrieves an entire block corresponding to the hash, assembling it
|
||||
// back from the stored header and body. If either the header or body could not
|
||||
// be retrieved nil is returned.
|
||||
|
||||
@@ -744,7 +744,7 @@ func TestReadLogs(t *testing.T) {
|
||||
// Insert the receipt slice into the database and check presence
|
||||
WriteReceipts(db, hash, 0, receipts)
|
||||
|
||||
logs := ReadLogs(db, hash, 0)
|
||||
logs := ReadLogs(db, hash, 0, params.TestChainConfig)
|
||||
if len(logs) == 0 {
|
||||
t.Fatalf("no logs returned")
|
||||
}
|
||||
|
||||
@@ -44,24 +44,29 @@ func InitDatabaseFromFreezer(db ethdb.Database) {
|
||||
logged = start.Add(-7 * time.Second) // Unindex during import is fast, don't double log
|
||||
hash common.Hash
|
||||
)
|
||||
for i := uint64(0); i < frozen; i++ {
|
||||
// Since the freezer has all data in sequential order on a file,
|
||||
// it would be 'neat' to read more data in one go, and let the
|
||||
// freezerdb return N items (e.g up to 1000 items per go)
|
||||
// That would require an API change in Ancients though
|
||||
if h, err := db.Ancient(freezerHashTable, i); err != nil {
|
||||
for i := uint64(0); i < frozen; {
|
||||
// We read 100K hashes at a time, for a total of 3.2M
|
||||
count := uint64(100_000)
|
||||
if i+count > frozen {
|
||||
count = frozen - i
|
||||
}
|
||||
data, err := db.AncientRange(freezerHashTable, i, count, 32*count)
|
||||
if err != nil {
|
||||
log.Crit("Failed to init database from freezer", "err", err)
|
||||
} else {
|
||||
}
|
||||
for j, h := range data {
|
||||
number := i + uint64(j)
|
||||
hash = common.BytesToHash(h)
|
||||
}
|
||||
WriteHeaderNumber(batch, hash, i)
|
||||
// If enough data was accumulated in memory or we're at the last block, dump to disk
|
||||
if batch.ValueSize() > ethdb.IdealBatchSize {
|
||||
if err := batch.Write(); err != nil {
|
||||
log.Crit("Failed to write data to db", "err", err)
|
||||
WriteHeaderNumber(batch, hash, number)
|
||||
// If enough data was accumulated in memory or we're at the last block, dump to disk
|
||||
if batch.ValueSize() > ethdb.IdealBatchSize {
|
||||
if err := batch.Write(); err != nil {
|
||||
log.Crit("Failed to write data to db", "err", err)
|
||||
}
|
||||
batch.Reset()
|
||||
}
|
||||
batch.Reset()
|
||||
}
|
||||
i += uint64(len(data))
|
||||
// If we've spent too much time already, notify the user of what we're doing
|
||||
if time.Since(logged) > 8*time.Second {
|
||||
log.Info("Initializing database from freezer", "total", frozen, "number", i, "hash", hash, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
|
||||
@@ -118,7 +118,7 @@ func (batch *freezerTableBatch) reset() {
|
||||
// existing data.
|
||||
func (batch *freezerTableBatch) Append(item uint64, data interface{}) error {
|
||||
if item != batch.curItem {
|
||||
return errOutOrderInsertion
|
||||
return fmt.Errorf("%w: have %d want %d", errOutOrderInsertion, item, batch.curItem)
|
||||
}
|
||||
|
||||
// Encode the item.
|
||||
@@ -138,7 +138,7 @@ func (batch *freezerTableBatch) Append(item uint64, data interface{}) error {
|
||||
// existing data.
|
||||
func (batch *freezerTableBatch) AppendRaw(item uint64, blob []byte) error {
|
||||
if item != batch.curItem {
|
||||
return errOutOrderInsertion
|
||||
return fmt.Errorf("%w: have %d want %d", errOutOrderInsertion, item, batch.curItem)
|
||||
}
|
||||
|
||||
encItem := blob
|
||||
|
||||
@@ -246,7 +246,7 @@ func TestFreezerConcurrentModifyTruncate(t *testing.T) {
|
||||
if truncateErr != nil {
|
||||
t.Fatal("concurrent truncate failed:", err)
|
||||
}
|
||||
if !(modifyErr == nil || modifyErr == errOutOrderInsertion) {
|
||||
if !(errors.Is(modifyErr, nil) || errors.Is(modifyErr, errOutOrderInsertion)) {
|
||||
t.Fatal("wrong error from concurrent modify:", modifyErr)
|
||||
}
|
||||
checkAncientCount(t, f, "test", 10)
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
@@ -54,11 +56,12 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||
LondonBlock: big.NewInt(0),
|
||||
Ethash: new(params.EthashConfig),
|
||||
}
|
||||
signer = types.LatestSigner(config)
|
||||
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
signer = types.LatestSigner(config)
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
key2, _ = crypto.HexToECDSA("0202020202020202020202020202020202020202020202020202002020202020")
|
||||
)
|
||||
var makeTx = func(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction {
|
||||
tx, _ := types.SignTx(types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data), signer, testKey)
|
||||
var makeTx = func(key *ecdsa.PrivateKey, nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction {
|
||||
tx, _ := types.SignTx(types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data), signer, key)
|
||||
return tx
|
||||
}
|
||||
var mkDynamicTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int) *types.Transaction {
|
||||
@@ -69,7 +72,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||
Gas: gasLimit,
|
||||
To: &to,
|
||||
Value: big.NewInt(0),
|
||||
}), signer, testKey)
|
||||
}), signer, key1)
|
||||
return tx
|
||||
}
|
||||
{ // Tests against a 'recent' chain definition
|
||||
@@ -82,6 +85,10 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||
Balance: big.NewInt(1000000000000000000), // 1 ether
|
||||
Nonce: 0,
|
||||
},
|
||||
common.HexToAddress("0xfd0810DD14796680f72adf1a371963d0745BCc64"): GenesisAccount{
|
||||
Balance: big.NewInt(1000000000000000000), // 1 ether
|
||||
Nonce: math.MaxUint64,
|
||||
},
|
||||
},
|
||||
}
|
||||
genesis = gspec.MustCommit(db)
|
||||
@@ -97,32 +104,38 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||
}{
|
||||
{ // ErrNonceTooLow
|
||||
txs: []*types.Transaction{
|
||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||
},
|
||||
want: "could not apply tx 1 [0x0026256b3939ed97e2c4a6f3fce8ecf83bdcfa6d507c47838c308a1fb0436f62]: nonce too low: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1",
|
||||
},
|
||||
{ // ErrNonceTooHigh
|
||||
txs: []*types.Transaction{
|
||||
makeTx(100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||
makeTx(key1, 100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||
},
|
||||
want: "could not apply tx 0 [0xdebad714ca7f363bd0d8121c4518ad48fa469ca81b0a081be3d10c17460f751b]: nonce too high: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0",
|
||||
},
|
||||
{ // ErrNonceMax
|
||||
txs: []*types.Transaction{
|
||||
makeTx(key2, math.MaxUint64, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil),
|
||||
},
|
||||
want: "could not apply tx 0 [0x84ea18d60eb2bb3b040e3add0eb72f757727122cc257dd858c67cb6591a85986]: nonce has max value: address 0xfd0810DD14796680f72adf1a371963d0745BCc64, nonce: 18446744073709551615",
|
||||
},
|
||||
{ // ErrGasLimitReached
|
||||
txs: []*types.Transaction{
|
||||
makeTx(0, common.Address{}, big.NewInt(0), 21000000, big.NewInt(875000000), nil),
|
||||
makeTx(key1, 0, common.Address{}, big.NewInt(0), 21000000, big.NewInt(875000000), nil),
|
||||
},
|
||||
want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached",
|
||||
},
|
||||
{ // ErrInsufficientFundsForTransfer
|
||||
txs: []*types.Transaction{
|
||||
makeTx(0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(875000000), nil),
|
||||
makeTx(key1, 0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(875000000), nil),
|
||||
},
|
||||
want: "could not apply tx 0 [0x98c796b470f7fcab40aaef5c965a602b0238e1034cce6fb73823042dd0638d74]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 1000018375000000000",
|
||||
},
|
||||
{ // ErrInsufficientFunds
|
||||
txs: []*types.Transaction{
|
||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil),
|
||||
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil),
|
||||
},
|
||||
want: "could not apply tx 0 [0x4a69690c4b0cd85e64d0d9ea06302455b01e10a83db964d60281739752003440]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 18900000000000000000000",
|
||||
},
|
||||
@@ -132,13 +145,13 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||
// multiplication len(data) +gas_per_byte overflows uint64. Not testable at the moment
|
||||
{ // ErrIntrinsicGas
|
||||
txs: []*types.Transaction{
|
||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(875000000), nil),
|
||||
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(875000000), nil),
|
||||
},
|
||||
want: "could not apply tx 0 [0xcf3b049a0b516cb4f9274b3e2a264359e2ba53b2fb64b7bda2c634d5c9d01fca]: intrinsic gas too low: have 20000, want 21000",
|
||||
},
|
||||
{ // ErrGasLimitReached
|
||||
txs: []*types.Transaction{
|
||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas*1000, big.NewInt(875000000), nil),
|
||||
makeTx(key1, 0, common.Address{}, big.NewInt(0), params.TxGas*1000, big.NewInt(875000000), nil),
|
||||
},
|
||||
want: "could not apply tx 0 [0xbd49d8dadfd47fb846986695f7d4da3f7b2c48c8da82dbc211a26eb124883de9]: gas limit reached",
|
||||
},
|
||||
|
||||
@@ -222,6 +222,9 @@ func (st *StateTransition) preCheck() error {
|
||||
} else if stNonce > msgNonce {
|
||||
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
|
||||
st.msg.From().Hex(), msgNonce, stNonce)
|
||||
} else if stNonce+1 < stNonce {
|
||||
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
|
||||
st.msg.From().Hex(), stNonce)
|
||||
}
|
||||
// Make sure the sender is an EOA
|
||||
if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
|
||||
|
||||
+3
-2
@@ -621,8 +621,9 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
|
||||
if err != nil {
|
||||
return ErrInvalidSender
|
||||
}
|
||||
// Drop non-local transactions under our own minimal accepted gas price or tip
|
||||
if !local && tx.GasTipCapIntCmp(pool.gasPrice) < 0 {
|
||||
// Drop non-local transactions under our own minimal accepted gas price or tip.
|
||||
pendingBaseFee := pool.priced.urgent.baseFee
|
||||
if !local && tx.EffectiveGasTipIntCmp(pool.gasPrice, pendingBaseFee) < 0 {
|
||||
return ErrUnderpriced
|
||||
}
|
||||
// Ensure the transaction adheres to nonce ordering
|
||||
|
||||
@@ -141,7 +141,7 @@ func (a *AccessListTracer) CaptureStart(env *EVM, from common.Address, to common
|
||||
}
|
||||
|
||||
// CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist.
|
||||
func (a *AccessListTracer) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||
func (a *AccessListTracer) CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||
stack := scope.Stack
|
||||
if (op == SLOAD || op == SSTORE) && stack.len() >= 1 {
|
||||
slot := common.Hash(stack.data[stack.len()-1].Bytes32())
|
||||
@@ -161,7 +161,7 @@ func (a *AccessListTracer) CaptureState(env *EVM, pc uint64, op OpCode, gas, cos
|
||||
}
|
||||
}
|
||||
|
||||
func (*AccessListTracer) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
||||
func (*AccessListTracer) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
||||
}
|
||||
|
||||
func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {}
|
||||
|
||||
@@ -35,6 +35,7 @@ var (
|
||||
ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
|
||||
ErrGasUintOverflow = errors.New("gas uint64 overflow")
|
||||
ErrInvalidCode = errors.New("invalid code: must not begin with 0xef")
|
||||
ErrNonceUintOverflow = errors.New("nonce uint64 overflow")
|
||||
)
|
||||
|
||||
// ErrStackUnderflow wraps an evm error when the items on the stack less
|
||||
|
||||
@@ -424,6 +424,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||
return nil, common.Address{}, gas, ErrInsufficientBalance
|
||||
}
|
||||
nonce := evm.StateDB.GetNonce(caller.Address())
|
||||
if nonce+1 < nonce {
|
||||
return nil, common.Address{}, gas, ErrNonceUintOverflow
|
||||
}
|
||||
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
||||
// We add this to the access list _before_ taking a snapshot. Even if the creation fails,
|
||||
// the access-list change should not be rolled back
|
||||
|
||||
@@ -169,9 +169,9 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if !logged {
|
||||
in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
|
||||
in.cfg.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
|
||||
} else {
|
||||
in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err)
|
||||
in.cfg.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -253,7 +253,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||
}
|
||||
|
||||
if in.cfg.Debug {
|
||||
in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
|
||||
in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
|
||||
logged = true
|
||||
}
|
||||
|
||||
|
||||
+14
-10
@@ -105,10 +105,10 @@ func (s *StructLog) ErrorString() string {
|
||||
// if you need to retain them beyond the current call.
|
||||
type EVMLogger interface {
|
||||
CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int)
|
||||
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error)
|
||||
CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error)
|
||||
CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
|
||||
CaptureExit(output []byte, gasUsed uint64, err error)
|
||||
CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error)
|
||||
CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error)
|
||||
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error)
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ type EVMLogger interface {
|
||||
// contract their storage.
|
||||
type StructLogger struct {
|
||||
cfg LogConfig
|
||||
env *EVM
|
||||
|
||||
storage map[common.Address]Storage
|
||||
logs []StructLog
|
||||
@@ -147,12 +148,13 @@ func (l *StructLogger) Reset() {
|
||||
|
||||
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
|
||||
func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||
l.env = env
|
||||
}
|
||||
|
||||
// CaptureState logs a new structured log message and pushes it out to the environment
|
||||
//
|
||||
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
|
||||
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||
func (l *StructLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||
memory := scope.Memory
|
||||
stack := scope.Stack
|
||||
contract := scope.Contract
|
||||
@@ -186,7 +188,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
|
||||
if op == SLOAD && stack.len() >= 1 {
|
||||
var (
|
||||
address = common.Hash(stack.data[stack.len()-1].Bytes32())
|
||||
value = env.StateDB.GetState(contract.Address(), address)
|
||||
value = l.env.StateDB.GetState(contract.Address(), address)
|
||||
)
|
||||
l.storage[contract.Address()][address] = value
|
||||
storage = l.storage[contract.Address()].Copy()
|
||||
@@ -206,13 +208,13 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
|
||||
copy(rdata, rData)
|
||||
}
|
||||
// create a new snapshot of the EVM.
|
||||
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, env.StateDB.GetRefund(), err}
|
||||
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err}
|
||||
l.logs = append(l.logs, log)
|
||||
}
|
||||
|
||||
// CaptureFault implements the EVMLogger interface to trace an execution fault
|
||||
// while running an opcode.
|
||||
func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
||||
func (l *StructLogger) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
||||
}
|
||||
|
||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||
@@ -291,12 +293,13 @@ func WriteLogs(writer io.Writer, logs []*types.Log) {
|
||||
type mdLogger struct {
|
||||
out io.Writer
|
||||
cfg *LogConfig
|
||||
env *EVM
|
||||
}
|
||||
|
||||
// NewMarkdownLogger creates a logger which outputs information in a format adapted
|
||||
// for human readability, and is also a valid markdown table
|
||||
func NewMarkdownLogger(cfg *LogConfig, writer io.Writer) *mdLogger {
|
||||
l := &mdLogger{writer, cfg}
|
||||
l := &mdLogger{out: writer, cfg: cfg}
|
||||
if l.cfg == nil {
|
||||
l.cfg = &LogConfig{}
|
||||
}
|
||||
@@ -304,6 +307,7 @@ func NewMarkdownLogger(cfg *LogConfig, writer io.Writer) *mdLogger {
|
||||
}
|
||||
|
||||
func (t *mdLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||
t.env = env
|
||||
if !create {
|
||||
fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n",
|
||||
from.String(), to.String(),
|
||||
@@ -321,7 +325,7 @@ func (t *mdLogger) CaptureStart(env *EVM, from common.Address, to common.Address
|
||||
}
|
||||
|
||||
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
|
||||
func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||
func (t *mdLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||
stack := scope.Stack
|
||||
fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost)
|
||||
|
||||
@@ -334,14 +338,14 @@ func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64
|
||||
b := fmt.Sprintf("[%v]", strings.Join(a, ","))
|
||||
fmt.Fprintf(t.out, "%10v |", b)
|
||||
}
|
||||
fmt.Fprintf(t.out, "%10v |", env.StateDB.GetRefund())
|
||||
fmt.Fprintf(t.out, "%10v |", t.env.StateDB.GetRefund())
|
||||
fmt.Fprintln(t.out, "")
|
||||
if err != nil {
|
||||
fmt.Fprintf(t.out, "Error: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *mdLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
||||
func (t *mdLogger) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
|
||||
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,12 +29,13 @@ import (
|
||||
type JSONLogger struct {
|
||||
encoder *json.Encoder
|
||||
cfg *LogConfig
|
||||
env *EVM
|
||||
}
|
||||
|
||||
// NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects
|
||||
// into the provided stream.
|
||||
func NewJSONLogger(cfg *LogConfig, writer io.Writer) *JSONLogger {
|
||||
l := &JSONLogger{json.NewEncoder(writer), cfg}
|
||||
l := &JSONLogger{encoder: json.NewEncoder(writer), cfg: cfg}
|
||||
if l.cfg == nil {
|
||||
l.cfg = &LogConfig{}
|
||||
}
|
||||
@@ -42,12 +43,13 @@ func NewJSONLogger(cfg *LogConfig, writer io.Writer) *JSONLogger {
|
||||
}
|
||||
|
||||
func (l *JSONLogger) CaptureStart(env *EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||
l.env = env
|
||||
}
|
||||
|
||||
func (l *JSONLogger) CaptureFault(*EVM, uint64, OpCode, uint64, uint64, *ScopeContext, int, error) {}
|
||||
func (l *JSONLogger) CaptureFault(uint64, OpCode, uint64, uint64, *ScopeContext, int, error) {}
|
||||
|
||||
// CaptureState outputs state information on the logger.
|
||||
func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||
func (l *JSONLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||
memory := scope.Memory
|
||||
stack := scope.Stack
|
||||
|
||||
@@ -58,7 +60,7 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint
|
||||
GasCost: cost,
|
||||
MemorySize: memory.Len(),
|
||||
Depth: depth,
|
||||
RefundCounter: env.StateDB.GetRefund(),
|
||||
RefundCounter: l.env.StateDB.GetRefund(),
|
||||
Err: err,
|
||||
}
|
||||
if l.cfg.EnableMemory {
|
||||
|
||||
@@ -62,7 +62,8 @@ func TestStoreCapture(t *testing.T) {
|
||||
scope.Stack.push(uint256.NewInt(1))
|
||||
scope.Stack.push(new(uint256.Int))
|
||||
var index common.Hash
|
||||
logger.CaptureState(env, 0, SSTORE, 0, 0, scope, nil, 0, nil)
|
||||
logger.CaptureStart(env, common.Address{}, contract.Address(), false, nil, 0, nil)
|
||||
logger.CaptureState(0, SSTORE, 0, 0, scope, nil, 0, nil)
|
||||
if len(logger.storage[contract.Address()]) == 0 {
|
||||
t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(),
|
||||
len(logger.storage[contract.Address()]))
|
||||
|
||||
+66
-57
@@ -39,68 +39,68 @@ func (op OpCode) IsStaticJump() bool {
|
||||
|
||||
// 0x0 range - arithmetic ops.
|
||||
const (
|
||||
STOP OpCode = iota
|
||||
ADD
|
||||
MUL
|
||||
SUB
|
||||
DIV
|
||||
SDIV
|
||||
MOD
|
||||
SMOD
|
||||
ADDMOD
|
||||
MULMOD
|
||||
EXP
|
||||
SIGNEXTEND
|
||||
STOP OpCode = 0x0
|
||||
ADD OpCode = 0x1
|
||||
MUL OpCode = 0x2
|
||||
SUB OpCode = 0x3
|
||||
DIV OpCode = 0x4
|
||||
SDIV OpCode = 0x5
|
||||
MOD OpCode = 0x6
|
||||
SMOD OpCode = 0x7
|
||||
ADDMOD OpCode = 0x8
|
||||
MULMOD OpCode = 0x9
|
||||
EXP OpCode = 0xa
|
||||
SIGNEXTEND OpCode = 0xb
|
||||
)
|
||||
|
||||
// 0x10 range - comparison ops.
|
||||
const (
|
||||
LT OpCode = iota + 0x10
|
||||
GT
|
||||
SLT
|
||||
SGT
|
||||
EQ
|
||||
ISZERO
|
||||
AND
|
||||
OR
|
||||
XOR
|
||||
NOT
|
||||
BYTE
|
||||
SHL
|
||||
SHR
|
||||
SAR
|
||||
LT OpCode = 0x10
|
||||
GT OpCode = 0x11
|
||||
SLT OpCode = 0x12
|
||||
SGT OpCode = 0x13
|
||||
EQ OpCode = 0x14
|
||||
ISZERO OpCode = 0x15
|
||||
AND OpCode = 0x16
|
||||
OR OpCode = 0x17
|
||||
XOR OpCode = 0x18
|
||||
NOT OpCode = 0x19
|
||||
BYTE OpCode = 0x1a
|
||||
SHL OpCode = 0x1b
|
||||
SHR OpCode = 0x1c
|
||||
SAR OpCode = 0x1d
|
||||
|
||||
SHA3 OpCode = 0x20
|
||||
)
|
||||
|
||||
// 0x30 range - closure state.
|
||||
const (
|
||||
ADDRESS OpCode = 0x30 + iota
|
||||
BALANCE
|
||||
ORIGIN
|
||||
CALLER
|
||||
CALLVALUE
|
||||
CALLDATALOAD
|
||||
CALLDATASIZE
|
||||
CALLDATACOPY
|
||||
CODESIZE
|
||||
CODECOPY
|
||||
GASPRICE
|
||||
EXTCODESIZE
|
||||
EXTCODECOPY
|
||||
RETURNDATASIZE
|
||||
RETURNDATACOPY
|
||||
EXTCODEHASH
|
||||
ADDRESS OpCode = 0x30
|
||||
BALANCE OpCode = 0x31
|
||||
ORIGIN OpCode = 0x32
|
||||
CALLER OpCode = 0x33
|
||||
CALLVALUE OpCode = 0x34
|
||||
CALLDATALOAD OpCode = 0x35
|
||||
CALLDATASIZE OpCode = 0x36
|
||||
CALLDATACOPY OpCode = 0x37
|
||||
CODESIZE OpCode = 0x38
|
||||
CODECOPY OpCode = 0x39
|
||||
GASPRICE OpCode = 0x3a
|
||||
EXTCODESIZE OpCode = 0x3b
|
||||
EXTCODECOPY OpCode = 0x3c
|
||||
RETURNDATASIZE OpCode = 0x3d
|
||||
RETURNDATACOPY OpCode = 0x3e
|
||||
EXTCODEHASH OpCode = 0x3f
|
||||
)
|
||||
|
||||
// 0x40 range - block operations.
|
||||
const (
|
||||
BLOCKHASH OpCode = 0x40 + iota
|
||||
COINBASE
|
||||
TIMESTAMP
|
||||
NUMBER
|
||||
DIFFICULTY
|
||||
GASLIMIT
|
||||
BLOCKHASH OpCode = 0x40
|
||||
COINBASE OpCode = 0x41
|
||||
TIMESTAMP OpCode = 0x42
|
||||
NUMBER OpCode = 0x43
|
||||
DIFFICULTY OpCode = 0x44
|
||||
GASLIMIT OpCode = 0x45
|
||||
CHAINID OpCode = 0x46
|
||||
SELFBALANCE OpCode = 0x47
|
||||
BASEFEE OpCode = 0x48
|
||||
@@ -122,7 +122,7 @@ const (
|
||||
JUMPDEST OpCode = 0x5b
|
||||
)
|
||||
|
||||
// 0x60 range.
|
||||
// 0x60 range - pushes.
|
||||
const (
|
||||
PUSH1 OpCode = 0x60 + iota
|
||||
PUSH2
|
||||
@@ -156,7 +156,11 @@ const (
|
||||
PUSH30
|
||||
PUSH31
|
||||
PUSH32
|
||||
DUP1
|
||||
)
|
||||
|
||||
// 0x80 range - dups.
|
||||
const (
|
||||
DUP1 = 0x80 + iota
|
||||
DUP2
|
||||
DUP3
|
||||
DUP4
|
||||
@@ -172,7 +176,11 @@ const (
|
||||
DUP14
|
||||
DUP15
|
||||
DUP16
|
||||
SWAP1
|
||||
)
|
||||
|
||||
// 0x90 range - swaps.
|
||||
const (
|
||||
SWAP1 = 0x90 + iota
|
||||
SWAP2
|
||||
SWAP3
|
||||
SWAP4
|
||||
@@ -208,12 +216,13 @@ const (
|
||||
|
||||
// 0xf0 range - closures.
|
||||
const (
|
||||
CREATE OpCode = 0xf0 + iota
|
||||
CALL
|
||||
CALLCODE
|
||||
RETURN
|
||||
DELEGATECALL
|
||||
CREATE2
|
||||
CREATE OpCode = 0xf0
|
||||
CALL OpCode = 0xf1
|
||||
CALLCODE OpCode = 0xf2
|
||||
RETURN OpCode = 0xf3
|
||||
DELEGATECALL OpCode = 0xf4
|
||||
CREATE2 OpCode = 0xf5
|
||||
|
||||
STATICCALL OpCode = 0xfa
|
||||
REVERT OpCode = 0xfd
|
||||
SELFDESTRUCT OpCode = 0xff
|
||||
|
||||
@@ -35,6 +35,9 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
||||
// force-load js tracers to trigger registration
|
||||
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
|
||||
)
|
||||
|
||||
func TestDefaults(t *testing.T) {
|
||||
@@ -330,12 +333,12 @@ type stepCounter struct {
|
||||
func (s *stepCounter) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||
}
|
||||
|
||||
func (s *stepCounter) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
|
||||
func (s *stepCounter) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
|
||||
}
|
||||
|
||||
func (s *stepCounter) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {}
|
||||
|
||||
func (s *stepCounter) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||
func (s *stepCounter) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||
s.steps++
|
||||
// Enable this for more output
|
||||
//s.inner.CaptureState(env, pc, op, gas, cost, memory, stack, rStack, contract, depth, err)
|
||||
@@ -511,7 +514,7 @@ func BenchmarkSimpleLoop(b *testing.B) {
|
||||
// TestEip2929Cases contains various testcases that are used for
|
||||
// EIP-2929 about gas repricings
|
||||
func TestEip2929Cases(t *testing.T) {
|
||||
|
||||
t.Skip("Test only useful for generating documentation")
|
||||
id := 1
|
||||
prettyPrint := func(comment string, code []byte) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user