diff --git a/cmd/keeper/go.sum b/cmd/keeper/go.sum index e67813369a..43778f130f 100644 --- a/cmd/keeper/go.sum +++ b/cmd/keeper/go.sum @@ -165,11 +165,11 @@ golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= diff --git a/consensus/bor/abi/common.go b/consensus/bor/abi/common.go new file mode 100644 index 0000000000..60d82b3b7e --- /dev/null +++ b/consensus/bor/abi/common.go @@ -0,0 +1,31 @@ +package abi + +import ( + "math" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +// SystemTxGas is gas limit for system txs/calls (which happen within consensus) +// and should not be limited to the local rpc gas cap or tx gas cap. +var SystemTxGas = (hexutil.Uint64)(math.MaxUint64 / 2) + +var ( + vABI, _ = abi.JSON(strings.NewReader(validatorsetABI)) + sABI, _ = abi.JSON(strings.NewReader(stateReceiverABI)) +) + +func ValidatorSet() abi.ABI { + return vABI +} + +func StateReceiver() abi.ABI { + return sABI +} + +const ( + validatorsetABI = `[{"constant":true,"inputs":[],"name":"SPRINT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CHAIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FIRST_END_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"producers","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ROUND_TYPE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"BOR_ID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spanNumbers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"VOTE_TYPE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"validators","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spans","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"startBlock","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"endBlock","type":"uint256"}],"name":"NewSpan","type":"event"},{"constant":true,"inputs":[],"name":"currentSprint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNextSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getSpanByBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentSpanNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getValidatorsTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getProducersTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"getValidatorBySigner","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct BorValidatorSet.Validator","name":"result","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getBorValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitialValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newSpan","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"},{"internalType":"bytes","name":"validatorBytes","type":"bytes"},{"internalType":"bytes","name":"producerBytes","type":"bytes"}],"name":"commitSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"bytes32","name":"dataHash","type":"bytes32"},{"internalType":"bytes","name":"sigs","type":"bytes"}],"name":"getStakePowerBySigs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"bytes32","name":"leaf","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"d","type":"bytes32"}],"name":"leafNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"left","type":"bytes32"},{"internalType":"bytes32","name":"right","type":"bytes32"}],"name":"innerNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"}]` + stateReceiverABI = `[{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastStateId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"syncTime","type":"uint256"},{"internalType":"bytes","name":"recordBytes","type":"bytes"}],"name":"commitState","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]` +) diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go index 2b0ca4fcb7..d64ea7a237 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -245,6 +245,7 @@ func BorRLP(header *types.Header, c *params.BorConfig) []byte { type Bor struct { chainConfig *params.ChainConfig // Chain config config *params.BorConfig // Consensus engine configuration parameters for bor consensus + vmConfig vm.Config // VM config (optional) for system transactions db ethdb.Database // Database to store and retrieve snapshot checkpoints recents *ttlcache.Cache[common.Hash, *Snapshot] // Snapshots for recent block to speed up reorgs @@ -327,6 +328,7 @@ func New( c := &Bor{ chainConfig: chainConfig, config: borConfig, + vmConfig: vm.Config{}, db: db, ethAPI: ethAPI, recents: recents, @@ -366,6 +368,10 @@ func New( return c } +func (c *Bor) SetVMConfig(vmCfg vm.Config) { + c.vmConfig = vmCfg +} + // Author implements consensus.Engine, returning the Ethereum address recovered // from the signature in the header's extra-data section. func (c *Bor) Author(header *types.Header) (common.Address, error) { @@ -1694,7 +1700,7 @@ func (c *Bor) FetchAndCommitSpan( ) } - return c.spanner.CommitSpan(ctx, minSpan, validators, producers, state, header, chain) + return c.spanner.CommitSpan(ctx, minSpan, validators, producers, state, header, chain, c.vmConfig) } // CommitStates commit states @@ -1815,7 +1821,7 @@ func (c *Bor) CommitStates( // we expect that this call MUST emit an event, otherwise we wouldn't make a receipt // if the receiver address is not a contract then we'll skip the most of the execution and emitting an event as well // https://github.com/0xPolygon/genesis-contracts/blob/master/contracts/StateReceiver.sol#L27 - gasUsed, err = c.GenesisContractsClient.CommitState(eventRecord, state, header, chain) + gasUsed, err = c.GenesisContractsClient.CommitState(eventRecord, state, header, chain, c.vmConfig) if err != nil { return nil, err } diff --git a/consensus/bor/bor_test.go b/consensus/bor/bor_test.go index 4db081af2c..fa077cb125 100644 --- a/consensus/bor/bor_test.go +++ b/consensus/bor/bor_test.go @@ -67,7 +67,7 @@ func (s *fakeSpanner) GetCurrentValidatorsByHash(ctx context.Context, headerHash func (s *fakeSpanner) GetCurrentValidatorsByBlockNrOrHash(ctx context.Context, _ rpc.BlockNumberOrHash, _ uint64) ([]*valset.Validator, error) { return s.vals, nil } -func (s *fakeSpanner) CommitSpan(ctx context.Context, _ borTypes.Span, _ []stakeTypes.MinimalVal, _ []stakeTypes.MinimalVal, _ vm.StateDB, _ *types.Header, _ core.ChainContext) error { +func (s *fakeSpanner) CommitSpan(ctx context.Context, _ borTypes.Span, _ []stakeTypes.MinimalVal, _ []stakeTypes.MinimalVal, _ vm.StateDB, _ *types.Header, _ core.ChainContext, _ vm.Config) error { if s.shouldFailCommit { return errors.New("span commit failed") } @@ -80,7 +80,7 @@ type failingHeimdallClient struct{} // failingGenesisContract simulates GenesisContract failures type failingGenesisContract struct{} -func (f *failingGenesisContract) CommitState(event *clerk.EventRecordWithTime, state vm.StateDB, header *types.Header, chCtx statefull.ChainContext) (uint64, error) { +func (f *failingGenesisContract) CommitState(event *clerk.EventRecordWithTime, state vm.StateDB, header *types.Header, chCtx statefull.ChainContext, vmCfg vm.Config) (uint64, error) { return 0, errors.New("commit state failed") } @@ -3302,7 +3302,7 @@ type mockGenesisContractForCommitStatesIndore struct { gasUsed uint64 } -func (m *mockGenesisContractForCommitStatesIndore) CommitState(event *clerk.EventRecordWithTime, state vm.StateDB, header *types.Header, chCtx statefull.ChainContext) (uint64, error) { +func (m *mockGenesisContractForCommitStatesIndore) CommitState(event *clerk.EventRecordWithTime, state vm.StateDB, header *types.Header, chCtx statefull.ChainContext, vmCfg vm.Config) (uint64, error) { return m.gasUsed, nil } diff --git a/consensus/bor/contract/client.go b/consensus/bor/contract/client.go index 1ab8a9a754..ab57a7ad15 100644 --- a/consensus/bor/contract/client.go +++ b/consensus/bor/contract/client.go @@ -2,13 +2,12 @@ package contract import ( "context" - "math" "math/big" - "strings" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + borabi "github.com/ethereum/go-ethereum/consensus/bor/abi" "github.com/ethereum/go-ethereum/consensus/bor/api" "github.com/ethereum/go-ethereum/consensus/bor/clerk" "github.com/ethereum/go-ethereum/consensus/bor/statefull" @@ -22,23 +21,6 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -// SystemTxGas is gas limit for system txs/calls (which happen within consensus) -// and should not be limited to the local rpc gas cap or tx gas cap. -var SystemTxGas = (hexutil.Uint64)(math.MaxUint64 / 2) - -var ( - vABI, _ = abi.JSON(strings.NewReader(validatorsetABI)) - sABI, _ = abi.JSON(strings.NewReader(stateReceiverABI)) -) - -func ValidatorSet() abi.ABI { - return vABI -} - -func StateReceiver() abi.ABI { - return sABI -} - type GenesisContractsClient struct { validatorSetABI abi.ABI stateReceiverABI abi.ABI @@ -48,11 +30,6 @@ type GenesisContractsClient struct { ethAPI api.Caller } -const ( - validatorsetABI = `[{"constant":true,"inputs":[],"name":"SPRINT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CHAIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FIRST_END_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"producers","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ROUND_TYPE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"BOR_ID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spanNumbers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"VOTE_TYPE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"validators","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spans","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"startBlock","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"endBlock","type":"uint256"}],"name":"NewSpan","type":"event"},{"constant":true,"inputs":[],"name":"currentSprint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNextSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getSpanByBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentSpanNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getValidatorsTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getProducersTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"getValidatorBySigner","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct BorValidatorSet.Validator","name":"result","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getBorValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitialValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newSpan","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"},{"internalType":"bytes","name":"validatorBytes","type":"bytes"},{"internalType":"bytes","name":"producerBytes","type":"bytes"}],"name":"commitSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"bytes32","name":"dataHash","type":"bytes32"},{"internalType":"bytes","name":"sigs","type":"bytes"}],"name":"getStakePowerBySigs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"bytes32","name":"leaf","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"d","type":"bytes32"}],"name":"leafNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"left","type":"bytes32"},{"internalType":"bytes32","name":"right","type":"bytes32"}],"name":"innerNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"}]` - stateReceiverABI = `[{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastStateId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"syncTime","type":"uint256"},{"internalType":"bytes","name":"recordBytes","type":"bytes"}],"name":"commitState","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]` -) - func NewGenesisContractsClient( chainConfig *params.ChainConfig, validatorContract, @@ -60,8 +37,8 @@ func NewGenesisContractsClient( ethAPI api.Caller, ) *GenesisContractsClient { return &GenesisContractsClient{ - validatorSetABI: ValidatorSet(), - stateReceiverABI: StateReceiver(), + validatorSetABI: borabi.ValidatorSet(), + stateReceiverABI: borabi.StateReceiver(), ValidatorContract: validatorContract, StateReceiverContract: stateReceiverContract, chainConfig: chainConfig, @@ -74,6 +51,7 @@ func (gc *GenesisContractsClient) CommitState( state vm.StateDB, header *types.Header, chCtx statefull.ChainContext, + vmCfg vm.Config, ) (uint64, error) { eventRecord := event.BuildEventRecord() @@ -96,7 +74,7 @@ func (gc *GenesisContractsClient) CommitState( log.Info("→ committing new state", "eventRecord", event.ID) - gasUsed, err := statefull.ApplyMessage(context.Background(), msg, state, header, gc.chainConfig, chCtx) + gasUsed, err := statefull.ApplyMessage(context.Background(), msg, state, header, gc.chainConfig, chCtx, vmCfg) // Logging event log with time and individual gasUsed log.Info("→ committed new state", "eventRecord", event.String(gasUsed)) @@ -126,7 +104,7 @@ func (gc *GenesisContractsClient) LastStateId(state *state.StateDB, number uint6 // BOR: Do a 'CallWithState' so that we can fetch the last state ID from a given (incoming) // state instead of local(canonical) chain's state. result, err := gc.ethAPI.CallWithState(context.Background(), ethapi.TransactionArgs{ - Gas: &SystemTxGas, + Gas: &borabi.SystemTxGas, To: &toAddress, Data: &msgData, }, &rpc.BlockNumberOrHash{BlockNumber: &blockNr, BlockHash: &hash}, state, nil, nil) diff --git a/consensus/bor/genesis.go b/consensus/bor/genesis.go index 31c46ee2be..3d4757df2a 100644 --- a/consensus/bor/genesis.go +++ b/consensus/bor/genesis.go @@ -13,6 +13,6 @@ import ( //go:generate mockgen -destination=./genesis_contract_mock.go -package=bor . GenesisContract type GenesisContract interface { - CommitState(event *clerk.EventRecordWithTime, state vm.StateDB, header *types.Header, chCtx statefull.ChainContext) (uint64, error) + CommitState(event *clerk.EventRecordWithTime, state vm.StateDB, header *types.Header, chCtx statefull.ChainContext, vmCfg vm.Config) (uint64, error) LastStateId(state *state.StateDB, number uint64, hash common.Hash) (*big.Int, error) } diff --git a/consensus/bor/genesis_contract_mock.go b/consensus/bor/genesis_contract_mock.go index a95129d61a..3bd1b76cf8 100644 --- a/consensus/bor/genesis_contract_mock.go +++ b/consensus/bor/genesis_contract_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: GenesisContract) +// +// Generated by this command: +// +// mockgen -destination=./genesis_contract_mock.go -package=bor . GenesisContract +// // Package bor is a generated GoMock package. package bor @@ -8,20 +13,20 @@ import ( big "math/big" reflect "reflect" - gomock "go.uber.org/mock/gomock" - common "github.com/ethereum/go-ethereum/common" clerk "github.com/ethereum/go-ethereum/consensus/bor/clerk" statefull "github.com/ethereum/go-ethereum/consensus/bor/statefull" state "github.com/ethereum/go-ethereum/core/state" types "github.com/ethereum/go-ethereum/core/types" vm "github.com/ethereum/go-ethereum/core/vm" + gomock "go.uber.org/mock/gomock" ) // MockGenesisContract is a mock of GenesisContract interface. type MockGenesisContract struct { ctrl *gomock.Controller recorder *MockGenesisContractMockRecorder + isgomock struct{} } // MockGenesisContractMockRecorder is the mock recorder for MockGenesisContract. @@ -42,31 +47,31 @@ func (m *MockGenesisContract) EXPECT() *MockGenesisContractMockRecorder { } // CommitState mocks base method. -func (m *MockGenesisContract) CommitState(arg0 *clerk.EventRecordWithTime, arg1 vm.StateDB, arg2 *types.Header, arg3 statefull.ChainContext) (uint64, error) { +func (m *MockGenesisContract) CommitState(event *clerk.EventRecordWithTime, arg1 vm.StateDB, header *types.Header, chCtx statefull.ChainContext, vmCfg vm.Config) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CommitState", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "CommitState", event, arg1, header, chCtx, vmCfg) ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } // CommitState indicates an expected call of CommitState. -func (mr *MockGenesisContractMockRecorder) CommitState(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockGenesisContractMockRecorder) CommitState(event, arg1, header, chCtx, vmCfg any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitState", reflect.TypeOf((*MockGenesisContract)(nil).CommitState), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitState", reflect.TypeOf((*MockGenesisContract)(nil).CommitState), event, arg1, header, chCtx, vmCfg) } // LastStateId mocks base method. -func (m *MockGenesisContract) LastStateId(arg0 *state.StateDB, arg1 uint64, arg2 common.Hash) (*big.Int, error) { +func (m *MockGenesisContract) LastStateId(arg0 *state.StateDB, number uint64, hash common.Hash) (*big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LastStateId", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "LastStateId", arg0, number, hash) ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } // LastStateId indicates an expected call of LastStateId. -func (mr *MockGenesisContractMockRecorder) LastStateId(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockGenesisContractMockRecorder) LastStateId(arg0, number, hash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastStateId", reflect.TypeOf((*MockGenesisContract)(nil).LastStateId), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastStateId", reflect.TypeOf((*MockGenesisContract)(nil).LastStateId), arg0, number, hash) } diff --git a/consensus/bor/heimdall/span/spanner.go b/consensus/bor/heimdall/span/spanner.go index f63da09638..8723b62282 100644 --- a/consensus/bor/heimdall/span/spanner.go +++ b/consensus/bor/heimdall/span/spanner.go @@ -12,7 +12,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/bor/abi" "github.com/ethereum/go-ethereum/consensus/bor/api" - "github.com/ethereum/go-ethereum/consensus/bor/contract" "github.com/ethereum/go-ethereum/consensus/bor/statefull" "github.com/ethereum/go-ethereum/consensus/bor/valset" "github.com/ethereum/go-ethereum/core" @@ -70,7 +69,7 @@ func (c *ChainSpanner) GetCurrentSpan(ctx context.Context, headerHash common.Has toAddress := c.validatorContractAddress result, err := c.ethAPI.CallWithState(ctx, ethapi.TransactionArgs{ - Gas: &contract.SystemTxGas, + Gas: &abi.SystemTxGas, To: &toAddress, Data: &msgData, }, &blockNr, state, nil, nil) @@ -169,7 +168,7 @@ func (c *ChainSpanner) getSpanByBlock(ctx context.Context, blockNrOrHash rpc.Blo spanMsgData := (hexutil.Bytes)(spanData) spanResult, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{ - Gas: &contract.SystemTxGas, + Gas: &abi.SystemTxGas, To: &toAddress, Data: &spanMsgData, }, &blockNrOrHash, nil, nil) @@ -195,7 +194,7 @@ func (c *ChainSpanner) getProducersBySpanAndIndexMethod(ctx context.Context, blo producerMsgData := (hexutil.Bytes)(producerData) result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{ - Gas: &contract.SystemTxGas, + Gas: &abi.SystemTxGas, To: &toAddress, Data: &producerMsgData, }, &blockNrOrHash, nil, nil) @@ -221,7 +220,7 @@ func (c *ChainSpanner) getFirstEndBlock(ctx context.Context, blockNrOrHash rpc.B firstEndBlockMsgData := (hexutil.Bytes)(firstEndBlockData) firstEndBlockResult, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{ - Gas: &contract.SystemTxGas, + Gas: &abi.SystemTxGas, To: &toAddress, Data: &firstEndBlockMsgData, }, &blockNrOrHash, nil, nil) @@ -250,7 +249,7 @@ func (c *ChainSpanner) getBorValidatorsWithoutId(ctx context.Context, blockNrOrH msgData := (hexutil.Bytes)(data) result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{ - Gas: &contract.SystemTxGas, + Gas: &abi.SystemTxGas, To: &toAddress, Data: &msgData, }, &blockNrOrHash, nil, nil) @@ -291,7 +290,7 @@ func (c *ChainSpanner) GetCurrentValidatorsByHash(ctx context.Context, headerHas const method = "commitSpan" -func (c *ChainSpanner) CommitSpan(ctx context.Context, minimalSpan borTypes.Span, validators, producers []stakeTypes.MinimalVal, state vm.StateDB, header *types.Header, chainContext core.ChainContext) error { +func (c *ChainSpanner) CommitSpan(ctx context.Context, minimalSpan borTypes.Span, validators, producers []stakeTypes.MinimalVal, state vm.StateDB, header *types.Header, chainContext core.ChainContext, vmCfg vm.Config) error { // get validators bytes validatorBytes, err := rlp.EncodeToBytes(validators) if err != nil { @@ -329,7 +328,7 @@ func (c *ChainSpanner) CommitSpan(ctx context.Context, minimalSpan borTypes.Span msg := statefull.GetSystemMessage(c.validatorContractAddress, data) // apply message - _, err = statefull.ApplyMessage(ctx, msg, state, header, c.chainConfig, chainContext) + _, err = statefull.ApplyMessage(ctx, msg, state, header, c.chainConfig, chainContext, vmCfg) return err } diff --git a/consensus/bor/span.go b/consensus/bor/span.go index 06f2673894..3680381c75 100644 --- a/consensus/bor/span.go +++ b/consensus/bor/span.go @@ -20,5 +20,5 @@ type Spanner interface { GetCurrentSpan(ctx context.Context, headerHash common.Hash, state *state.StateDB) (*borTypes.Span, error) GetCurrentValidatorsByHash(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) GetCurrentValidatorsByBlockNrOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, blockNumber uint64) ([]*valset.Validator, error) - CommitSpan(ctx context.Context, minimalSpan borTypes.Span, validators, producers []stakeTypes.MinimalVal, state vm.StateDB, header *types.Header, chainContext core.ChainContext) error + CommitSpan(ctx context.Context, minimalSpan borTypes.Span, validators, producers []stakeTypes.MinimalVal, state vm.StateDB, header *types.Header, chainContext core.ChainContext, vmCfg vm.Config) error } diff --git a/consensus/bor/span_mock.go b/consensus/bor/span_mock.go index f9d0f3f316..4e3fde9ef0 100644 --- a/consensus/bor/span_mock.go +++ b/consensus/bor/span_mock.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: Spanner) +// +// Generated by this command: +// +// mockgen -destination=./span_mock.go -package=bor . Spanner +// // Package bor is a generated GoMock package. package bor @@ -8,8 +13,6 @@ import ( context "context" reflect "reflect" - gomock "go.uber.org/mock/gomock" - types "github.com/0xPolygon/heimdall-v2/x/bor/types" types0 "github.com/0xPolygon/heimdall-v2/x/stake/types" common "github.com/ethereum/go-ethereum/common" @@ -19,12 +22,14 @@ import ( types1 "github.com/ethereum/go-ethereum/core/types" vm "github.com/ethereum/go-ethereum/core/vm" rpc "github.com/ethereum/go-ethereum/rpc" + gomock "go.uber.org/mock/gomock" ) // MockSpanner is a mock of Spanner interface. type MockSpanner struct { ctrl *gomock.Controller recorder *MockSpannerMockRecorder + isgomock struct{} } // MockSpannerMockRecorder is the mock recorder for MockSpanner. @@ -45,60 +50,60 @@ func (m *MockSpanner) EXPECT() *MockSpannerMockRecorder { } // CommitSpan mocks base method. -func (m *MockSpanner) CommitSpan(arg0 context.Context, arg1 types.Span, arg2, arg3 []types0.MinimalVal, arg4 vm.StateDB, arg5 *types1.Header, arg6 core.ChainContext) error { +func (m *MockSpanner) CommitSpan(ctx context.Context, minimalSpan types.Span, validators, producers []types0.MinimalVal, arg4 vm.StateDB, header *types1.Header, chainContext core.ChainContext, vmCfg vm.Config) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CommitSpan", arg0, arg1, arg2, arg3, arg4, arg5, arg6) + ret := m.ctrl.Call(m, "CommitSpan", ctx, minimalSpan, validators, producers, arg4, header, chainContext, vmCfg) ret0, _ := ret[0].(error) return ret0 } // CommitSpan indicates an expected call of CommitSpan. -func (mr *MockSpannerMockRecorder) CommitSpan(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call { +func (mr *MockSpannerMockRecorder) CommitSpan(ctx, minimalSpan, validators, producers, arg4, header, chainContext, vmCfg any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitSpan", reflect.TypeOf((*MockSpanner)(nil).CommitSpan), arg0, arg1, arg2, arg3, arg4, arg5, arg6) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitSpan", reflect.TypeOf((*MockSpanner)(nil).CommitSpan), ctx, minimalSpan, validators, producers, arg4, header, chainContext, vmCfg) } // GetCurrentSpan mocks base method. -func (m *MockSpanner) GetCurrentSpan(arg0 context.Context, arg1 common.Hash, arg2 *state.StateDB) (*types.Span, error) { +func (m *MockSpanner) GetCurrentSpan(ctx context.Context, headerHash common.Hash, arg2 *state.StateDB) (*types.Span, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCurrentSpan", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetCurrentSpan", ctx, headerHash, arg2) ret0, _ := ret[0].(*types.Span) ret1, _ := ret[1].(error) return ret0, ret1 } // GetCurrentSpan indicates an expected call of GetCurrentSpan. -func (mr *MockSpannerMockRecorder) GetCurrentSpan(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockSpannerMockRecorder) GetCurrentSpan(ctx, headerHash, arg2 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentSpan", reflect.TypeOf((*MockSpanner)(nil).GetCurrentSpan), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentSpan", reflect.TypeOf((*MockSpanner)(nil).GetCurrentSpan), ctx, headerHash, arg2) } // GetCurrentValidatorsByBlockNrOrHash mocks base method. -func (m *MockSpanner) GetCurrentValidatorsByBlockNrOrHash(arg0 context.Context, arg1 rpc.BlockNumberOrHash, arg2 uint64) ([]*valset.Validator, error) { +func (m *MockSpanner) GetCurrentValidatorsByBlockNrOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, blockNumber uint64) ([]*valset.Validator, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCurrentValidatorsByBlockNrOrHash", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetCurrentValidatorsByBlockNrOrHash", ctx, blockNrOrHash, blockNumber) ret0, _ := ret[0].([]*valset.Validator) ret1, _ := ret[1].(error) return ret0, ret1 } // GetCurrentValidatorsByBlockNrOrHash indicates an expected call of GetCurrentValidatorsByBlockNrOrHash. -func (mr *MockSpannerMockRecorder) GetCurrentValidatorsByBlockNrOrHash(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockSpannerMockRecorder) GetCurrentValidatorsByBlockNrOrHash(ctx, blockNrOrHash, blockNumber any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidatorsByBlockNrOrHash", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidatorsByBlockNrOrHash), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidatorsByBlockNrOrHash", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidatorsByBlockNrOrHash), ctx, blockNrOrHash, blockNumber) } // GetCurrentValidatorsByHash mocks base method. -func (m *MockSpanner) GetCurrentValidatorsByHash(arg0 context.Context, arg1 common.Hash, arg2 uint64) ([]*valset.Validator, error) { +func (m *MockSpanner) GetCurrentValidatorsByHash(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCurrentValidatorsByHash", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetCurrentValidatorsByHash", ctx, headerHash, blockNumber) ret0, _ := ret[0].([]*valset.Validator) ret1, _ := ret[1].(error) return ret0, ret1 } // GetCurrentValidatorsByHash indicates an expected call of GetCurrentValidatorsByHash. -func (mr *MockSpannerMockRecorder) GetCurrentValidatorsByHash(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockSpannerMockRecorder) GetCurrentValidatorsByHash(ctx, headerHash, blockNumber any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidatorsByHash", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidatorsByHash), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidatorsByHash", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidatorsByHash), ctx, headerHash, blockNumber) } diff --git a/consensus/bor/statefull/processor.go b/consensus/bor/statefull/processor.go index 2e714d0e56..cb885f5502 100644 --- a/consensus/bor/statefull/processor.go +++ b/consensus/bor/statefull/processor.go @@ -3,6 +3,7 @@ package statefull import ( "bytes" "context" + "fmt" "math/big" "github.com/holiman/uint256" @@ -10,15 +11,16 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/bor/abi" + "github.com/ethereum/go-ethereum/consensus/bor/clerk" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rlp" ) -var systemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE") - type ChainContext struct { Chain consensus.ChainHeaderReader Bor consensus.Engine @@ -70,7 +72,7 @@ func (m Callmsg) Data() []byte { return m.CallMsg.Data } func GetSystemMessage(toAddress common.Address, data []byte) Callmsg { return Callmsg{ ethereum.CallMsg{ - From: systemAddress, + From: params.BorSystemAddress, Gas: params.MaxTxGas, // should be more than enough for state-sync related syscalls GasPrice: big.NewInt(0), Value: big.NewInt(0), @@ -88,6 +90,7 @@ func ApplyMessage( header *types.Header, chainConfig *params.ChainConfig, chainContext core.ChainContext, + vmConfig vm.Config, ) (uint64, error) { initialGas := msg.Gas() @@ -96,7 +99,7 @@ func ApplyMessage( // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. - vmenv := vm.NewEVM(blockContext, state, chainConfig, vm.Config{}) + vmenv := vm.NewEVM(blockContext, state, chainConfig, vmConfig) // nolint : contextcheck // Apply the transaction to the current state (included in the env) @@ -157,3 +160,67 @@ func ApplyBorMessage(vmenv *vm.EVM, msg Callmsg) (*core.ExecutionResult, error) ReturnData: ret, }, nil } + +// ApplyStateSyncEvents replays all state-sync events from a StateSyncTx against the EVM. This +// method is generally used for tracing. It tries to mimic the exact things which happen when +// a state-sync is processed in a live network (via CommitState). +func ApplyStateSyncEvents(vmenv *vm.EVM, tx *types.Transaction, message *core.Message, stateReceiverContract common.Address) (*core.ExecutionResult, error) { + events := tx.GetStateSyncData() + if len(events) == 0 { + return &core.ExecutionResult{UsedGas: 0, ReturnData: nil}, nil + } + + // Set tx context so that opcodes like GASPRICE don't panic. + vmenv.SetTxContext(core.NewEVMTxContext(message)) + + stateReceiverABI := abi.StateReceiver() + const method = "commitState" + var ( + totalGasUsed uint64 + // The actual state-sync transaction uses event time but because we don't have + // it here, we use the block time. The calldata will be different than what + // was constructed while executing the transaction but it'll be deterministic + // in every run. + now = vmenv.Context.Time + ) + + for _, event := range events { + // Convert StateSyncData to EventRecord (matching CommitState's BuildEventRecord) + record := &clerk.EventRecord{ + ID: event.ID, + Contract: event.Contract, + Data: event.Data, + TxHash: event.TxHash, + // Dummy fields, not really needed for execution but required for encoding + LogIndex: 0, + ChainID: "", + } + + recordBytes, err := rlp.EncodeToBytes(record) + if err != nil { + return nil, fmt.Errorf("failed to RLP encode state-sync event %d: %w", event.ID, err) + } + + // ABI-pack commitState(uint256 syncTime, bytes recordBytes) + data, err := stateReceiverABI.Pack(method, big.NewInt(0).SetUint64(now), recordBytes) + if err != nil { + return nil, fmt.Errorf("failed to ABI pack commitState for event %d: %w", event.ID, err) + } + + // Build system message with proper gas and target contract + msg := GetSystemMessage(stateReceiverContract, data) + + // Execute + result, err := ApplyBorMessage(vmenv, msg) + if err != nil { + return nil, fmt.Errorf("state-sync event %d execution failed: %w", event.ID, err) + } + + totalGasUsed += result.UsedGas + } + + return &core.ExecutionResult{ + UsedGas: totalGasUsed, + Err: nil, + }, nil +} diff --git a/core/parallel_state_processor.go b/core/parallel_state_processor.go index 2e5bfceb52..78ca054692 100644 --- a/core/parallel_state_processor.go +++ b/core/parallel_state_processor.go @@ -331,7 +331,8 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat ProcessParentBlockHash(block.ParentHash(), vmenv) } // Iterate over and process the individual transactions - for i, tx := range block.Transactions() { + txs := block.Transactions() + for i, tx := range txs { if tx.Type() == types.StateSyncTxType { continue } @@ -421,6 +422,12 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat return nil, err } + if len(txs) > 0 && txs[len(txs)-1].Type() == types.StateSyncTxType { + if hooks := vmenv.Config.Tracer; hooks != nil && hooks.OnTxStart != nil { + hooks.OnTxStart(vmenv.GetVMContext(), txs[len(txs)-1], params.BorSystemAddress) + } + } + // Polygon/bor: EIP-6110, EIP-7002, and EIP-7251 are not supported var requests [][]byte @@ -440,6 +447,9 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat if appliedNewStateSyncReceipt { allLogs = append(allLogs, receipts[len(receipts)-1].Logs...) + if hooks := vmenv.Config.Tracer; hooks != nil && hooks.OnTxEnd != nil { + hooks.OnTxEnd(receipts[len(receipts)-1], nil) + } } } diff --git a/core/state_processor.go b/core/state_processor.go index 4c6bd9d181..a1662b08d5 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -105,7 +105,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Iterate over and process the individual transactions - for i, tx := range block.Transactions() { + txs := block.Transactions() + for i, tx := range txs { // Check if execution should be cancelled or not select { case <-interruptCtx.Done(): @@ -151,10 +152,17 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } } + // Trace state-sync transaction (if present and if tracer is enabled) + if len(txs) > 0 && txs[len(txs)-1].Type() == types.StateSyncTxType { + if hooks := evm.Config.Tracer; hooks != nil && hooks.OnTxStart != nil { + hooks.OnTxStart(evm.GetVMContext(), txs[len(txs)-1], params.BorSystemAddress) + } + } + // Finalize the block, applying any consensus engine specific extras (e.g. block rewards), apply // state sync event (if any), and append the receipt. receiptsCountBeforeFinalize := len(receipts) - receipts = p.chain.Engine().Finalize(p.chain, header, statedb, block.Body(), receipts) + receipts = p.chain.Engine().Finalize(p.chain, header, tracingStateDB, block.Body(), receipts) // apply state sync logs if p.chainConfig().Bor != nil && p.chainConfig().Bor.IsMadhugiri(block.Number()) { @@ -167,6 +175,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if appliedNewStateSyncReceipt { allLogs = append(allLogs, receipts[len(receipts)-1].Logs...) + if hooks := evm.Config.Tracer; hooks != nil && hooks.OnTxEnd != nil { + hooks.OnTxEnd(receipts[len(receipts)-1], nil) + } } } diff --git a/core/types/bor_receipt.go b/core/types/bor_receipt.go index 29c84f8a68..176b748282 100644 --- a/core/types/bor_receipt.go +++ b/core/types/bor_receipt.go @@ -15,12 +15,7 @@ import ( // Sorted using ( blockNumber * (10 ** 5) + logIndex ) const TenToTheFive uint64 = 100000 -var ( - borReceiptPrefix = []byte("matic-bor-receipt-") // borReceiptPrefix + number + block hash -> bor block receipt - - // SystemAddress address for system sender - SystemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE") -) +var borReceiptPrefix = []byte("matic-bor-receipt-") // borReceiptPrefix + number + block hash -> bor block receipt // BorReceiptKey = borReceiptPrefix + num (uint64 big endian) + hash func BorReceiptKey(number uint64, hash common.Hash) []byte { diff --git a/core/types/transaction.go b/core/types/transaction.go index 07cdc5040c..3c198205b5 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -636,6 +636,15 @@ func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, e return &Transaction{inner: cpy, time: tx.time}, nil } +// GetStateSyncData returns the underlying bridge event data used for state-sync +// transactions. +func (tx *Transaction) GetStateSyncData() []*StateSyncData { + if tx.Type() != StateSyncTxType { + return nil + } + return tx.inner.(*StateSyncTx).StateSyncData +} + // Transactions implements DerivableList for transactions. type Transactions []*Transaction diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index e9cf0d4232..be60f1d25f 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -364,7 +364,7 @@ func (s eip2930Signer) Equal(s2 Signer) bool { func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) { if tx.Type() == StateSyncTxType { - return common.Address{}, nil + return params.BorSystemAddress, nil } V, R, S := tx.RawSignatureValues() diff --git a/docs/cli/default_config.toml b/docs/cli/default_config.toml index 022a277ef1..4f8295412a 100644 --- a/docs/cli/default_config.toml +++ b/docs/cli/default_config.toml @@ -3,7 +3,7 @@ identity = "" verbosity = 3 vmdebug = false vmtrace = "" -"vmtrace.jsonconfig" = "" +"vmtrace.jsonconfig" = "{}" evm-switch-dispatch = false "state.size-tracking" = false datadir = "/var/lib/bor" diff --git a/docs/cli/example_config.toml b/docs/cli/example_config.toml index 33b6249046..de93bf5b22 100644 --- a/docs/cli/example_config.toml +++ b/docs/cli/example_config.toml @@ -21,6 +21,10 @@ ethstats = "" # Reporting URL of a ethstats service (nodename: witnessprotocol = false # Enables the wit/0 protocol devfakeauthor = false # Run miner without validator set authorization [dev mode] : Use with '--bor.withoutheimdall' (default: false) +# VM tracing +vmtrace = "supply" # Name of a tracer to record internal VM operations during blockchain synchronization (costly) +"vmtrace.jsonconfig" = '{"path": "output"}' # Tracer configuration (JSON) + ["eth.requiredblocks"] # Comma separated block number-to-hash mappings to require for peering (=) (default = empty map) "31000000" = "0x2087b9e2b353209c2c21e370c82daa12278efd0fe5f0febe6c29035352cf050e" "32000000" = "0x875500011e5eecc0c554f95d07b31cf59df4ca2505f4dbbfffa7d4e4da917c68" @@ -31,11 +35,11 @@ enable-private-tx = true # Enable private transaction relay bp-rpc-endpoints = [ ] # Comma separated rpc endpoints of all block producers [log] - vmodule = "" # Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4) - json = false # Format logs with JSON - backtrace = "" # Request a stack trace at a specific logging statement (e.g. "block.go:271") - debug = true # Prepends log messages with call-site location (file and line number) - enable-block-tracking = false # Enables additional logging of information collected while tracking block lifecycle + vmodule = "" # Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4) + json = false # Format logs with JSON + backtrace = "" # Request a stack trace at a specific logging statement (e.g. "block.go:271") + debug = true # Prepends log messages with call-site location (file and line number) + enable-block-tracking = false # Enables additional logging of information collected while tracking block lifecycle [p2p] maxpeers = 50 # Maximum number of network peers (network disabled if set to 0) diff --git a/docs/cli/server.md b/docs/cli/server.md index 1aafb9f5e9..fe4a7e3afe 100644 --- a/docs/cli/server.md +++ b/docs/cli/server.md @@ -112,9 +112,9 @@ The ```bor server``` command runs the Bor client. - ```vmdebug```: Record information useful for VM and contract debugging (default: false) -- ```vmtrace```: Name of tracer which should observe internal VM operations (e.g. 'json') +- ```vmtrace```: Name of a tracer to record internal VM operations during blockchain synchronization (costly) (e.g. 'json') -- ```vmtrace.jsonconfig```: Tracer configuration (JSON) +- ```vmtrace.jsonconfig```: Tracer configuration (JSON) (default: {}) - ```witness.enable```: Enable witness protocol (default: false) diff --git a/eth/backend.go b/eth/backend.go index 1b51bfde4d..70a0722f0a 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -311,6 +311,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { return nil, fmt.Errorf("failed to create tracer %s: %v", config.VMTrace, err) } options.VmConfig.Tracer = t + if borEngine, ok := eth.engine.(*bor.Bor); ok { + borEngine.SetVMConfig(options.VmConfig) + } } checker := whitelist.NewService(chainDb, config.DisableBlindForkValidation, config.MaxBlindForkValidationLimit) diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index a1d42d7b57..bf5a2019bf 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/bor" + borabi "github.com/ethereum/go-ethereum/consensus/bor/abi" "github.com/ethereum/go-ethereum/consensus/bor/contract" "github.com/ethereum/go-ethereum/consensus/bor/heimdall" //nolint:typecheck "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" @@ -340,7 +341,7 @@ func CreateConsensusEngine(chainConfig *params.ChainConfig, ethConfig *Config, d // In order to pass the ethereum transaction tests, we need to set the burn contract which is in the bor config // Then, bor != nil will also be enabled for ethash and clique. Only enable Bor for real if there is a validator contract present. genesisContractsClient := contract.NewGenesisContractsClient(chainConfig, chainConfig.Bor.ValidatorContract, chainConfig.Bor.StateReceiverContract, blockchainAPI) - spanner := span.NewChainSpanner(blockchainAPI, contract.ValidatorSet(), chainConfig, common.HexToAddress(chainConfig.Bor.ValidatorContract)) + spanner := span.NewChainSpanner(blockchainAPI, borabi.ValidatorSet(), chainConfig, common.HexToAddress(chainConfig.Bor.ValidatorContract)) log.Info("Creating consensus engine", "withoutHeimdall", ethConfig.WithoutHeimdall) log.Info("Using custom miner block time", "blockTime", ethConfig.Miner.BlockTime) diff --git a/eth/filters/IBackend.go b/eth/filters/IBackend.go index 7a0bc7565a..31690bd877 100644 --- a/eth/filters/IBackend.go +++ b/eth/filters/IBackend.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ethereum/go-ethereum/internal/ethapi (interfaces: Backend) +// +// Generated by this command: +// +// mockgen -destination=../../eth/filters/IBackend.go -package=filters . Backend +// // Package filters is a generated GoMock package. package filters @@ -10,8 +15,6 @@ import ( reflect "reflect" time "time" - gomock "go.uber.org/mock/gomock" - ethereum "github.com/ethereum/go-ethereum" accounts "github.com/ethereum/go-ethereum/accounts" common "github.com/ethereum/go-ethereum/common" @@ -21,18 +24,21 @@ import ( filtermaps "github.com/ethereum/go-ethereum/core/filtermaps" state "github.com/ethereum/go-ethereum/core/state" stateless "github.com/ethereum/go-ethereum/core/stateless" + txpool "github.com/ethereum/go-ethereum/core/txpool" types "github.com/ethereum/go-ethereum/core/types" vm "github.com/ethereum/go-ethereum/core/vm" ethdb "github.com/ethereum/go-ethereum/ethdb" event "github.com/ethereum/go-ethereum/event" params "github.com/ethereum/go-ethereum/params" rpc "github.com/ethereum/go-ethereum/rpc" + gomock "go.uber.org/mock/gomock" ) // MockBackend is a mock of Backend interface. type MockBackend struct { ctrl *gomock.Controller recorder *MockBackendMockRecorder + isgomock struct{} } // MockBackendMockRecorder is the mock recorder for MockBackend. @@ -52,6 +58,34 @@ func (m *MockBackend) EXPECT() *MockBackendMockRecorder { return m.recorder } +// AcceptPreconfTxs mocks base method. +func (m *MockBackend) AcceptPreconfTxs() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AcceptPreconfTxs") + ret0, _ := ret[0].(bool) + return ret0 +} + +// AcceptPreconfTxs indicates an expected call of AcceptPreconfTxs. +func (mr *MockBackendMockRecorder) AcceptPreconfTxs() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptPreconfTxs", reflect.TypeOf((*MockBackend)(nil).AcceptPreconfTxs)) +} + +// AcceptPrivateTxs mocks base method. +func (m *MockBackend) AcceptPrivateTxs() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AcceptPrivateTxs") + ret0, _ := ret[0].(bool) + return ret0 +} + +// AcceptPrivateTxs indicates an expected call of AcceptPrivateTxs. +func (mr *MockBackendMockRecorder) AcceptPrivateTxs() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptPrivateTxs", reflect.TypeOf((*MockBackend)(nil).AcceptPrivateTxs)) +} + // AccountManager mocks base method. func (m *MockBackend) AccountManager() *accounts.Manager { m.ctrl.T.Helper() @@ -67,62 +101,62 @@ func (mr *MockBackendMockRecorder) AccountManager() *gomock.Call { } // BlobBaseFee mocks base method. -func (m *MockBackend) BlobBaseFee(arg0 context.Context) *big.Int { +func (m *MockBackend) BlobBaseFee(ctx context.Context) *big.Int { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlobBaseFee", arg0) + ret := m.ctrl.Call(m, "BlobBaseFee", ctx) ret0, _ := ret[0].(*big.Int) return ret0 } // BlobBaseFee indicates an expected call of BlobBaseFee. -func (mr *MockBackendMockRecorder) BlobBaseFee(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) BlobBaseFee(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlobBaseFee", reflect.TypeOf((*MockBackend)(nil).BlobBaseFee), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlobBaseFee", reflect.TypeOf((*MockBackend)(nil).BlobBaseFee), ctx) } // BlockByHash mocks base method. -func (m *MockBackend) BlockByHash(arg0 context.Context, arg1 common.Hash) (*types.Block, error) { +func (m *MockBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockByHash", arg0, arg1) + ret := m.ctrl.Call(m, "BlockByHash", ctx, hash) ret0, _ := ret[0].(*types.Block) ret1, _ := ret[1].(error) return ret0, ret1 } // BlockByHash indicates an expected call of BlockByHash. -func (mr *MockBackendMockRecorder) BlockByHash(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) BlockByHash(ctx, hash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHash", reflect.TypeOf((*MockBackend)(nil).BlockByHash), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByHash", reflect.TypeOf((*MockBackend)(nil).BlockByHash), ctx, hash) } // BlockByNumber mocks base method. -func (m *MockBackend) BlockByNumber(arg0 context.Context, arg1 rpc.BlockNumber) (*types.Block, error) { +func (m *MockBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockByNumber", arg0, arg1) + ret := m.ctrl.Call(m, "BlockByNumber", ctx, number) ret0, _ := ret[0].(*types.Block) ret1, _ := ret[1].(error) return ret0, ret1 } // BlockByNumber indicates an expected call of BlockByNumber. -func (mr *MockBackendMockRecorder) BlockByNumber(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) BlockByNumber(ctx, number any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumber", reflect.TypeOf((*MockBackend)(nil).BlockByNumber), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumber", reflect.TypeOf((*MockBackend)(nil).BlockByNumber), ctx, number) } // BlockByNumberOrHash mocks base method. -func (m *MockBackend) BlockByNumberOrHash(arg0 context.Context, arg1 rpc.BlockNumberOrHash) (*types.Block, error) { +func (m *MockBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockByNumberOrHash", arg0, arg1) + ret := m.ctrl.Call(m, "BlockByNumberOrHash", ctx, blockNrOrHash) ret0, _ := ret[0].(*types.Block) ret1, _ := ret[1].(error) return ret0, ret1 } // BlockByNumberOrHash indicates an expected call of BlockByNumberOrHash. -func (mr *MockBackendMockRecorder) BlockByNumberOrHash(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) BlockByNumberOrHash(ctx, blockNrOrHash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).BlockByNumberOrHash), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).BlockByNumberOrHash), ctx, blockNrOrHash) } // ChainConfig mocks base method. @@ -153,6 +187,21 @@ func (mr *MockBackendMockRecorder) ChainDb() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainDb", reflect.TypeOf((*MockBackend)(nil).ChainDb)) } +// CheckPreconfStatus mocks base method. +func (m *MockBackend) CheckPreconfStatus(hash common.Hash) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CheckPreconfStatus", hash) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CheckPreconfStatus indicates an expected call of CheckPreconfStatus. +func (mr *MockBackendMockRecorder) CheckPreconfStatus(hash any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckPreconfStatus", reflect.TypeOf((*MockBackend)(nil).CheckPreconfStatus), hash) +} + // CurrentBlock mocks base method. func (m *MockBackend) CurrentBlock() *types.Header { m.ctrl.T.Helper() @@ -253,9 +302,9 @@ func (mr *MockBackendMockRecorder) ExtRPCEnabled() *gomock.Call { } // FeeHistory mocks base method. -func (m *MockBackend) FeeHistory(arg0 context.Context, arg1 uint64, arg2 rpc.BlockNumber, arg3 []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) { +func (m *MockBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FeeHistory", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "FeeHistory", ctx, blockCount, lastBlock, rewardPercentiles) ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].([][]*big.Int) ret2, _ := ret[2].([]*big.Int) @@ -267,60 +316,60 @@ func (m *MockBackend) FeeHistory(arg0 context.Context, arg1 uint64, arg2 rpc.Blo } // FeeHistory indicates an expected call of FeeHistory. -func (mr *MockBackendMockRecorder) FeeHistory(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FeeHistory", reflect.TypeOf((*MockBackend)(nil).FeeHistory), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FeeHistory", reflect.TypeOf((*MockBackend)(nil).FeeHistory), ctx, blockCount, lastBlock, rewardPercentiles) } // GetBody mocks base method. -func (m *MockBackend) GetBody(arg0 context.Context, arg1 common.Hash, arg2 rpc.BlockNumber) (*types.Body, error) { +func (m *MockBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBody", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetBody", ctx, hash, number) ret0, _ := ret[0].(*types.Body) ret1, _ := ret[1].(error) return ret0, ret1 } // GetBody indicates an expected call of GetBody. -func (mr *MockBackendMockRecorder) GetBody(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetBody(ctx, hash, number any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBody", reflect.TypeOf((*MockBackend)(nil).GetBody), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBody", reflect.TypeOf((*MockBackend)(nil).GetBody), ctx, hash, number) } // GetBorBlockLogs mocks base method. -func (m *MockBackend) GetBorBlockLogs(arg0 context.Context, arg1 common.Hash) ([]*types.Log, error) { +func (m *MockBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBorBlockLogs", arg0, arg1) + ret := m.ctrl.Call(m, "GetBorBlockLogs", ctx, hash) ret0, _ := ret[0].([]*types.Log) ret1, _ := ret[1].(error) return ret0, ret1 } // GetBorBlockLogs indicates an expected call of GetBorBlockLogs. -func (mr *MockBackendMockRecorder) GetBorBlockLogs(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetBorBlockLogs(ctx, hash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockLogs", reflect.TypeOf((*MockBackend)(nil).GetBorBlockLogs), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockLogs", reflect.TypeOf((*MockBackend)(nil).GetBorBlockLogs), ctx, hash) } // GetBorBlockReceipt mocks base method. -func (m *MockBackend) GetBorBlockReceipt(arg0 context.Context, arg1 common.Hash) (*types.Receipt, error) { +func (m *MockBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBorBlockReceipt", arg0, arg1) + ret := m.ctrl.Call(m, "GetBorBlockReceipt", ctx, hash) ret0, _ := ret[0].(*types.Receipt) ret1, _ := ret[1].(error) return ret0, ret1 } // GetBorBlockReceipt indicates an expected call of GetBorBlockReceipt. -func (mr *MockBackendMockRecorder) GetBorBlockReceipt(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetBorBlockReceipt(ctx, hash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockReceipt", reflect.TypeOf((*MockBackend)(nil).GetBorBlockReceipt), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockReceipt", reflect.TypeOf((*MockBackend)(nil).GetBorBlockReceipt), ctx, hash) } // GetBorBlockTransaction mocks base method. -func (m *MockBackend) GetBorBlockTransaction(arg0 context.Context, arg1 common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { +func (m *MockBackend) GetBorBlockTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBorBlockTransaction", arg0, arg1) + ret := m.ctrl.Call(m, "GetBorBlockTransaction", ctx, txHash) ret0, _ := ret[0].(*types.Transaction) ret1, _ := ret[1].(common.Hash) ret2, _ := ret[2].(uint64) @@ -330,15 +379,15 @@ func (m *MockBackend) GetBorBlockTransaction(arg0 context.Context, arg1 common.H } // GetBorBlockTransaction indicates an expected call of GetBorBlockTransaction. -func (mr *MockBackendMockRecorder) GetBorBlockTransaction(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetBorBlockTransaction(ctx, txHash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockTransaction", reflect.TypeOf((*MockBackend)(nil).GetBorBlockTransaction), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockTransaction", reflect.TypeOf((*MockBackend)(nil).GetBorBlockTransaction), ctx, txHash) } // GetBorBlockTransactionWithBlockHash mocks base method. -func (m *MockBackend) GetBorBlockTransactionWithBlockHash(arg0 context.Context, arg1, arg2 common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { +func (m *MockBackend) GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBorBlockTransactionWithBlockHash", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetBorBlockTransactionWithBlockHash", ctx, txHash, blockHash) ret0, _ := ret[0].(*types.Transaction) ret1, _ := ret[1].(common.Hash) ret2, _ := ret[2].(uint64) @@ -348,30 +397,30 @@ func (m *MockBackend) GetBorBlockTransactionWithBlockHash(arg0 context.Context, } // GetBorBlockTransactionWithBlockHash indicates an expected call of GetBorBlockTransactionWithBlockHash. -func (mr *MockBackendMockRecorder) GetBorBlockTransactionWithBlockHash(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetBorBlockTransactionWithBlockHash(ctx, txHash, blockHash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockTransactionWithBlockHash", reflect.TypeOf((*MockBackend)(nil).GetBorBlockTransactionWithBlockHash), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockTransactionWithBlockHash", reflect.TypeOf((*MockBackend)(nil).GetBorBlockTransactionWithBlockHash), ctx, txHash, blockHash) } // GetCanonicalReceipt mocks base method. -func (m *MockBackend) GetCanonicalReceipt(arg0 *types.Transaction, arg1 common.Hash, arg2, arg3 uint64) (*types.Receipt, error) { +func (m *MockBackend) GetCanonicalReceipt(tx *types.Transaction, blockHash common.Hash, blockNumber, blockIndex uint64) (*types.Receipt, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCanonicalReceipt", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "GetCanonicalReceipt", tx, blockHash, blockNumber, blockIndex) ret0, _ := ret[0].(*types.Receipt) ret1, _ := ret[1].(error) return ret0, ret1 } // GetCanonicalReceipt indicates an expected call of GetCanonicalReceipt. -func (mr *MockBackendMockRecorder) GetCanonicalReceipt(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetCanonicalReceipt(tx, blockHash, blockNumber, blockIndex any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCanonicalReceipt", reflect.TypeOf((*MockBackend)(nil).GetCanonicalReceipt), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCanonicalReceipt", reflect.TypeOf((*MockBackend)(nil).GetCanonicalReceipt), tx, blockHash, blockNumber, blockIndex) } // GetCanonicalTransaction mocks base method. -func (m *MockBackend) GetCanonicalTransaction(arg0 common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) { +func (m *MockBackend) GetCanonicalTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCanonicalTransaction", arg0) + ret := m.ctrl.Call(m, "GetCanonicalTransaction", txHash) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(*types.Transaction) ret2, _ := ret[2].(common.Hash) @@ -381,82 +430,82 @@ func (m *MockBackend) GetCanonicalTransaction(arg0 common.Hash) (bool, *types.Tr } // GetCanonicalTransaction indicates an expected call of GetCanonicalTransaction. -func (mr *MockBackendMockRecorder) GetCanonicalTransaction(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetCanonicalTransaction(txHash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCanonicalTransaction", reflect.TypeOf((*MockBackend)(nil).GetCanonicalTransaction), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCanonicalTransaction", reflect.TypeOf((*MockBackend)(nil).GetCanonicalTransaction), txHash) } // GetEVM mocks base method. -func (m *MockBackend) GetEVM(arg0 context.Context, arg1 *state.StateDB, arg2 *types.Header, arg3 *vm.Config, arg4 *vm.BlockContext) *vm.EVM { +func (m *MockBackend) GetEVM(ctx context.Context, arg1 *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEVM", arg0, arg1, arg2, arg3, arg4) + ret := m.ctrl.Call(m, "GetEVM", ctx, arg1, header, vmConfig, blockCtx) ret0, _ := ret[0].(*vm.EVM) return ret0 } // GetEVM indicates an expected call of GetEVM. -func (mr *MockBackendMockRecorder) GetEVM(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetEVM(ctx, arg1, header, vmConfig, blockCtx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEVM", reflect.TypeOf((*MockBackend)(nil).GetEVM), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEVM", reflect.TypeOf((*MockBackend)(nil).GetEVM), ctx, arg1, header, vmConfig, blockCtx) } // GetFinalizedBlockNumber mocks base method. -func (m *MockBackend) GetFinalizedBlockNumber(arg0 context.Context) (uint64, error) { +func (m *MockBackend) GetFinalizedBlockNumber(ctx context.Context) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFinalizedBlockNumber", arg0) + ret := m.ctrl.Call(m, "GetFinalizedBlockNumber", ctx) ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } // GetFinalizedBlockNumber indicates an expected call of GetFinalizedBlockNumber. -func (mr *MockBackendMockRecorder) GetFinalizedBlockNumber(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetFinalizedBlockNumber(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFinalizedBlockNumber", reflect.TypeOf((*MockBackend)(nil).GetFinalizedBlockNumber), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFinalizedBlockNumber", reflect.TypeOf((*MockBackend)(nil).GetFinalizedBlockNumber), ctx) } // GetLogs mocks base method. -func (m *MockBackend) GetLogs(arg0 context.Context, arg1 common.Hash, arg2 uint64) ([][]*types.Log, error) { +func (m *MockBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetLogs", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetLogs", ctx, blockHash, number) ret0, _ := ret[0].([][]*types.Log) ret1, _ := ret[1].(error) return ret0, ret1 } // GetLogs indicates an expected call of GetLogs. -func (mr *MockBackendMockRecorder) GetLogs(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetLogs(ctx, blockHash, number any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogs", reflect.TypeOf((*MockBackend)(nil).GetLogs), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogs", reflect.TypeOf((*MockBackend)(nil).GetLogs), ctx, blockHash, number) } // GetPoolNonce mocks base method. -func (m *MockBackend) GetPoolNonce(arg0 context.Context, arg1 common.Address) (uint64, error) { +func (m *MockBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPoolNonce", arg0, arg1) + ret := m.ctrl.Call(m, "GetPoolNonce", ctx, addr) ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } // GetPoolNonce indicates an expected call of GetPoolNonce. -func (mr *MockBackendMockRecorder) GetPoolNonce(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetPoolNonce(ctx, addr any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPoolNonce", reflect.TypeOf((*MockBackend)(nil).GetPoolNonce), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPoolNonce", reflect.TypeOf((*MockBackend)(nil).GetPoolNonce), ctx, addr) } // GetPoolTransaction mocks base method. -func (m *MockBackend) GetPoolTransaction(arg0 common.Hash) *types.Transaction { +func (m *MockBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPoolTransaction", arg0) + ret := m.ctrl.Call(m, "GetPoolTransaction", txHash) ret0, _ := ret[0].(*types.Transaction) return ret0 } // GetPoolTransaction indicates an expected call of GetPoolTransaction. -func (mr *MockBackendMockRecorder) GetPoolTransaction(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetPoolTransaction(txHash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPoolTransaction", reflect.TypeOf((*MockBackend)(nil).GetPoolTransaction), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPoolTransaction", reflect.TypeOf((*MockBackend)(nil).GetPoolTransaction), txHash) } // GetPoolTransactions mocks base method. @@ -475,76 +524,76 @@ func (mr *MockBackendMockRecorder) GetPoolTransactions() *gomock.Call { } // GetReceipts mocks base method. -func (m *MockBackend) GetReceipts(arg0 context.Context, arg1 common.Hash) (types.Receipts, error) { +func (m *MockBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetReceipts", arg0, arg1) + ret := m.ctrl.Call(m, "GetReceipts", ctx, hash) ret0, _ := ret[0].(types.Receipts) ret1, _ := ret[1].(error) return ret0, ret1 } // GetReceipts indicates an expected call of GetReceipts. -func (mr *MockBackendMockRecorder) GetReceipts(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetReceipts(ctx, hash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReceipts", reflect.TypeOf((*MockBackend)(nil).GetReceipts), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReceipts", reflect.TypeOf((*MockBackend)(nil).GetReceipts), ctx, hash) } // GetRootHash mocks base method. -func (m *MockBackend) GetRootHash(arg0 context.Context, arg1, arg2 uint64) (string, error) { +func (m *MockBackend) GetRootHash(ctx context.Context, starBlockNr, endBlockNr uint64) (string, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetRootHash", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetRootHash", ctx, starBlockNr, endBlockNr) ret0, _ := ret[0].(string) ret1, _ := ret[1].(error) return ret0, ret1 } // GetRootHash indicates an expected call of GetRootHash. -func (mr *MockBackendMockRecorder) GetRootHash(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetRootHash(ctx, starBlockNr, endBlockNr any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRootHash", reflect.TypeOf((*MockBackend)(nil).GetRootHash), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRootHash", reflect.TypeOf((*MockBackend)(nil).GetRootHash), ctx, starBlockNr, endBlockNr) } // GetTd mocks base method. -func (m *MockBackend) GetTd(arg0 context.Context, arg1 common.Hash) *big.Int { +func (m *MockBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTd", arg0, arg1) + ret := m.ctrl.Call(m, "GetTd", ctx, hash) ret0, _ := ret[0].(*big.Int) return ret0 } // GetTd indicates an expected call of GetTd. -func (mr *MockBackendMockRecorder) GetTd(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetTd(ctx, hash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTd", reflect.TypeOf((*MockBackend)(nil).GetTd), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTd", reflect.TypeOf((*MockBackend)(nil).GetTd), ctx, hash) } // GetTdByNumber mocks base method. -func (m *MockBackend) GetTdByNumber(arg0 context.Context, arg1 rpc.BlockNumber) *big.Int { +func (m *MockBackend) GetTdByNumber(ctx context.Context, blockNr rpc.BlockNumber) *big.Int { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTdByNumber", arg0, arg1) + ret := m.ctrl.Call(m, "GetTdByNumber", ctx, blockNr) ret0, _ := ret[0].(*big.Int) return ret0 } // GetTdByNumber indicates an expected call of GetTdByNumber. -func (mr *MockBackendMockRecorder) GetTdByNumber(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetTdByNumber(ctx, blockNr any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTdByNumber", reflect.TypeOf((*MockBackend)(nil).GetTdByNumber), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTdByNumber", reflect.TypeOf((*MockBackend)(nil).GetTdByNumber), ctx, blockNr) } // GetVoteOnHash mocks base method. -func (m *MockBackend) GetVoteOnHash(arg0 context.Context, arg1, arg2 uint64, arg3, arg4 string) (bool, error) { +func (m *MockBackend) GetVoteOnHash(ctx context.Context, startBlockNumber, endBlockNumber uint64, hash, milestoneID string) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetVoteOnHash", arg0, arg1, arg2, arg3, arg4) + ret := m.ctrl.Call(m, "GetVoteOnHash", ctx, startBlockNumber, endBlockNumber, hash, milestoneID) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } // GetVoteOnHash indicates an expected call of GetVoteOnHash. -func (mr *MockBackendMockRecorder) GetVoteOnHash(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetVoteOnHash(ctx, startBlockNumber, endBlockNumber, hash, milestoneID any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVoteOnHash", reflect.TypeOf((*MockBackend)(nil).GetVoteOnHash), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVoteOnHash", reflect.TypeOf((*MockBackend)(nil).GetVoteOnHash), ctx, startBlockNumber, endBlockNumber, hash, milestoneID) } // GetWhitelistedCheckpoint mocks base method. @@ -580,18 +629,18 @@ func (mr *MockBackendMockRecorder) GetWhitelistedMilestone() *gomock.Call { } // GetWitnesses mocks base method. -func (m *MockBackend) GetWitnesses(arg0 context.Context, arg1, arg2 uint64) ([]*stateless.Witness, error) { +func (m *MockBackend) GetWitnesses(ctx context.Context, originBlock, totalBlocks uint64) ([]*stateless.Witness, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetWitnesses", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "GetWitnesses", ctx, originBlock, totalBlocks) ret0, _ := ret[0].([]*stateless.Witness) ret1, _ := ret[1].(error) return ret0, ret1 } // GetWitnesses indicates an expected call of GetWitnesses. -func (mr *MockBackendMockRecorder) GetWitnesses(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) GetWitnesses(ctx, originBlock, totalBlocks any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWitnesses", reflect.TypeOf((*MockBackend)(nil).GetWitnesses), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWitnesses", reflect.TypeOf((*MockBackend)(nil).GetWitnesses), ctx, originBlock, totalBlocks) } // GetWork mocks base method. @@ -625,48 +674,48 @@ func (mr *MockBackendMockRecorder) Hashrate() *gomock.Call { } // HeaderByHash mocks base method. -func (m *MockBackend) HeaderByHash(arg0 context.Context, arg1 common.Hash) (*types.Header, error) { +func (m *MockBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeaderByHash", arg0, arg1) + ret := m.ctrl.Call(m, "HeaderByHash", ctx, hash) ret0, _ := ret[0].(*types.Header) ret1, _ := ret[1].(error) return ret0, ret1 } // HeaderByHash indicates an expected call of HeaderByHash. -func (mr *MockBackendMockRecorder) HeaderByHash(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) HeaderByHash(ctx, hash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHash", reflect.TypeOf((*MockBackend)(nil).HeaderByHash), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHash", reflect.TypeOf((*MockBackend)(nil).HeaderByHash), ctx, hash) } // HeaderByNumber mocks base method. -func (m *MockBackend) HeaderByNumber(arg0 context.Context, arg1 rpc.BlockNumber) (*types.Header, error) { +func (m *MockBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeaderByNumber", arg0, arg1) + ret := m.ctrl.Call(m, "HeaderByNumber", ctx, number) ret0, _ := ret[0].(*types.Header) ret1, _ := ret[1].(error) return ret0, ret1 } // HeaderByNumber indicates an expected call of HeaderByNumber. -func (mr *MockBackendMockRecorder) HeaderByNumber(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) HeaderByNumber(ctx, number any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumber", reflect.TypeOf((*MockBackend)(nil).HeaderByNumber), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumber", reflect.TypeOf((*MockBackend)(nil).HeaderByNumber), ctx, number) } // HeaderByNumberOrHash mocks base method. -func (m *MockBackend) HeaderByNumberOrHash(arg0 context.Context, arg1 rpc.BlockNumberOrHash) (*types.Header, error) { +func (m *MockBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeaderByNumberOrHash", arg0, arg1) + ret := m.ctrl.Call(m, "HeaderByNumberOrHash", ctx, blockNrOrHash) ret0, _ := ret[0].(*types.Header) ret1, _ := ret[1].(error) return ret0, ret1 } // HeaderByNumberOrHash indicates an expected call of HeaderByNumberOrHash. -func (mr *MockBackendMockRecorder) HeaderByNumberOrHash(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) HeaderByNumberOrHash(ctx, blockNrOrHash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).HeaderByNumberOrHash), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).HeaderByNumberOrHash), ctx, blockNrOrHash) } // HistoryPruningCutoff mocks base method. @@ -727,10 +776,10 @@ func (mr *MockBackendMockRecorder) NewMatcherBackend() *gomock.Call { } // PeerStats mocks base method. -func (m *MockBackend) PeerStats() interface{} { +func (m *MockBackend) PeerStats() any { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PeerStats") - ret0, _ := ret[0].(interface{}) + ret0, _ := ret[0].(any) return ret0 } @@ -756,6 +805,34 @@ func (mr *MockBackendMockRecorder) Pending() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Pending", reflect.TypeOf((*MockBackend)(nil).Pending)) } +// PreconfEnabled mocks base method. +func (m *MockBackend) PreconfEnabled() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PreconfEnabled") + ret0, _ := ret[0].(bool) + return ret0 +} + +// PreconfEnabled indicates an expected call of PreconfEnabled. +func (mr *MockBackendMockRecorder) PreconfEnabled() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PreconfEnabled", reflect.TypeOf((*MockBackend)(nil).PreconfEnabled)) +} + +// PrivateTxEnabled mocks base method. +func (m *MockBackend) PrivateTxEnabled() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PrivateTxEnabled") + ret0, _ := ret[0].(bool) + return ret0 +} + +// PrivateTxEnabled indicates an expected call of PrivateTxEnabled. +func (mr *MockBackendMockRecorder) PrivateTxEnabled() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrivateTxEnabled", reflect.TypeOf((*MockBackend)(nil).PrivateTxEnabled)) +} + // ProtocolVersion mocks base method. func (m *MockBackend) ProtocolVersion() uint { m.ctrl.T.Helper() @@ -770,6 +847,18 @@ func (mr *MockBackendMockRecorder) ProtocolVersion() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProtocolVersion", reflect.TypeOf((*MockBackend)(nil).ProtocolVersion)) } +// PurgePrivateTx mocks base method. +func (m *MockBackend) PurgePrivateTx(hash common.Hash) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "PurgePrivateTx", hash) +} + +// PurgePrivateTx indicates an expected call of PurgePrivateTx. +func (mr *MockBackendMockRecorder) PurgePrivateTx(hash any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PurgePrivateTx", reflect.TypeOf((*MockBackend)(nil).PurgePrivateTx), hash) +} + // PurgeWhitelistedCheckpoint mocks base method. func (m *MockBackend) PurgeWhitelistedCheckpoint() { m.ctrl.T.Helper() @@ -878,36 +967,48 @@ func (mr *MockBackendMockRecorder) RPCTxSyncMaxTimeout() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RPCTxSyncMaxTimeout", reflect.TypeOf((*MockBackend)(nil).RPCTxSyncMaxTimeout)) } +// RecordPrivateTx mocks base method. +func (m *MockBackend) RecordPrivateTx(hash common.Hash) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RecordPrivateTx", hash) +} + +// RecordPrivateTx indicates an expected call of RecordPrivateTx. +func (mr *MockBackendMockRecorder) RecordPrivateTx(hash any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordPrivateTx", reflect.TypeOf((*MockBackend)(nil).RecordPrivateTx), hash) +} + // SendTx mocks base method. -func (m *MockBackend) SendTx(arg0 context.Context, arg1 *types.Transaction) error { +func (m *MockBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SendTx", arg0, arg1) + ret := m.ctrl.Call(m, "SendTx", ctx, signedTx) ret0, _ := ret[0].(error) return ret0 } // SendTx indicates an expected call of SendTx. -func (mr *MockBackendMockRecorder) SendTx(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SendTx(ctx, signedTx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTx", reflect.TypeOf((*MockBackend)(nil).SendTx), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendTx", reflect.TypeOf((*MockBackend)(nil).SendTx), ctx, signedTx) } // SetHead mocks base method. -func (m *MockBackend) SetHead(arg0 uint64) { +func (m *MockBackend) SetHead(number uint64) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetHead", arg0) + m.ctrl.Call(m, "SetHead", number) } // SetHead indicates an expected call of SetHead. -func (mr *MockBackendMockRecorder) SetHead(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SetHead(number any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHead", reflect.TypeOf((*MockBackend)(nil).SetHead), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHead", reflect.TypeOf((*MockBackend)(nil).SetHead), number) } // StateAndHeaderByNumber mocks base method. -func (m *MockBackend) StateAndHeaderByNumber(arg0 context.Context, arg1 rpc.BlockNumber) (*state.StateDB, *types.Header, error) { +func (m *MockBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StateAndHeaderByNumber", arg0, arg1) + ret := m.ctrl.Call(m, "StateAndHeaderByNumber", ctx, number) ret0, _ := ret[0].(*state.StateDB) ret1, _ := ret[1].(*types.Header) ret2, _ := ret[2].(error) @@ -915,15 +1016,15 @@ func (m *MockBackend) StateAndHeaderByNumber(arg0 context.Context, arg1 rpc.Bloc } // StateAndHeaderByNumber indicates an expected call of StateAndHeaderByNumber. -func (mr *MockBackendMockRecorder) StateAndHeaderByNumber(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) StateAndHeaderByNumber(ctx, number any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAndHeaderByNumber", reflect.TypeOf((*MockBackend)(nil).StateAndHeaderByNumber), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAndHeaderByNumber", reflect.TypeOf((*MockBackend)(nil).StateAndHeaderByNumber), ctx, number) } // StateAndHeaderByNumberOrHash mocks base method. -func (m *MockBackend) StateAndHeaderByNumberOrHash(arg0 context.Context, arg1 rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { +func (m *MockBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StateAndHeaderByNumberOrHash", arg0, arg1) + ret := m.ctrl.Call(m, "StateAndHeaderByNumberOrHash", ctx, blockNrOrHash) ret0, _ := ret[0].(*state.StateDB) ret1, _ := ret[1].(*types.Header) ret2, _ := ret[2].(error) @@ -931,9 +1032,9 @@ func (m *MockBackend) StateAndHeaderByNumberOrHash(arg0 context.Context, arg1 rp } // StateAndHeaderByNumberOrHash indicates an expected call of StateAndHeaderByNumberOrHash. -func (mr *MockBackendMockRecorder) StateAndHeaderByNumberOrHash(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) StateAndHeaderByNumberOrHash(ctx, blockNrOrHash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAndHeaderByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).StateAndHeaderByNumberOrHash), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAndHeaderByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).StateAndHeaderByNumberOrHash), ctx, blockNrOrHash) } // Stats mocks base method. @@ -952,103 +1053,131 @@ func (mr *MockBackendMockRecorder) Stats() *gomock.Call { } // StoreWitness mocks base method. -func (m *MockBackend) StoreWitness(arg0 context.Context, arg1 common.Hash, arg2 *stateless.Witness) error { +func (m *MockBackend) StoreWitness(ctx context.Context, blockHash common.Hash, witness *stateless.Witness) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StoreWitness", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "StoreWitness", ctx, blockHash, witness) ret0, _ := ret[0].(error) return ret0 } // StoreWitness indicates an expected call of StoreWitness. -func (mr *MockBackendMockRecorder) StoreWitness(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) StoreWitness(ctx, blockHash, witness any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreWitness", reflect.TypeOf((*MockBackend)(nil).StoreWitness), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoreWitness", reflect.TypeOf((*MockBackend)(nil).StoreWitness), ctx, blockHash, witness) } // SubmitHashrate mocks base method. -func (m *MockBackend) SubmitHashrate(arg0 hexutil.Uint64, arg1 common.Hash) (bool, error) { +func (m *MockBackend) SubmitHashrate(rate hexutil.Uint64, id common.Hash) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubmitHashrate", arg0, arg1) + ret := m.ctrl.Call(m, "SubmitHashrate", rate, id) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } // SubmitHashrate indicates an expected call of SubmitHashrate. -func (mr *MockBackendMockRecorder) SubmitHashrate(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SubmitHashrate(rate, id any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitHashrate", reflect.TypeOf((*MockBackend)(nil).SubmitHashrate), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitHashrate", reflect.TypeOf((*MockBackend)(nil).SubmitHashrate), rate, id) +} + +// SubmitPrivateTx mocks base method. +func (m *MockBackend) SubmitPrivateTx(tx *types.Transaction) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubmitPrivateTx", tx) + ret0, _ := ret[0].(error) + return ret0 +} + +// SubmitPrivateTx indicates an expected call of SubmitPrivateTx. +func (mr *MockBackendMockRecorder) SubmitPrivateTx(tx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitPrivateTx", reflect.TypeOf((*MockBackend)(nil).SubmitPrivateTx), tx) +} + +// SubmitTxForPreconf mocks base method. +func (m *MockBackend) SubmitTxForPreconf(tx *types.Transaction) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubmitTxForPreconf", tx) + ret0, _ := ret[0].(error) + return ret0 +} + +// SubmitTxForPreconf indicates an expected call of SubmitTxForPreconf. +func (mr *MockBackendMockRecorder) SubmitTxForPreconf(tx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitTxForPreconf", reflect.TypeOf((*MockBackend)(nil).SubmitTxForPreconf), tx) } // SubmitWork mocks base method. -func (m *MockBackend) SubmitWork(arg0 types.BlockNonce, arg1, arg2 common.Hash) (bool, error) { +func (m *MockBackend) SubmitWork(nonce types.BlockNonce, hash, digest common.Hash) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubmitWork", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "SubmitWork", nonce, hash, digest) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } // SubmitWork indicates an expected call of SubmitWork. -func (mr *MockBackendMockRecorder) SubmitWork(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SubmitWork(nonce, hash, digest any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitWork", reflect.TypeOf((*MockBackend)(nil).SubmitWork), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitWork", reflect.TypeOf((*MockBackend)(nil).SubmitWork), nonce, hash, digest) } // SubscribeChain2HeadEvent mocks base method. -func (m *MockBackend) SubscribeChain2HeadEvent(arg0 chan<- core.Chain2HeadEvent) event.Subscription { +func (m *MockBackend) SubscribeChain2HeadEvent(ch chan<- core.Chain2HeadEvent) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeChain2HeadEvent", arg0) + ret := m.ctrl.Call(m, "SubscribeChain2HeadEvent", ch) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeChain2HeadEvent indicates an expected call of SubscribeChain2HeadEvent. -func (mr *MockBackendMockRecorder) SubscribeChain2HeadEvent(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeChain2HeadEvent(ch any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChain2HeadEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChain2HeadEvent), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChain2HeadEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChain2HeadEvent), ch) } // SubscribeChainEvent mocks base method. -func (m *MockBackend) SubscribeChainEvent(arg0 chan<- core.ChainEvent) event.Subscription { +func (m *MockBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeChainEvent", arg0) + ret := m.ctrl.Call(m, "SubscribeChainEvent", ch) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeChainEvent indicates an expected call of SubscribeChainEvent. -func (mr *MockBackendMockRecorder) SubscribeChainEvent(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeChainEvent(ch any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChainEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChainEvent), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChainEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChainEvent), ch) } // SubscribeChainHeadEvent mocks base method. -func (m *MockBackend) SubscribeChainHeadEvent(arg0 chan<- core.ChainHeadEvent) event.Subscription { +func (m *MockBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeChainHeadEvent", arg0) + ret := m.ctrl.Call(m, "SubscribeChainHeadEvent", ch) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeChainHeadEvent indicates an expected call of SubscribeChainHeadEvent. -func (mr *MockBackendMockRecorder) SubscribeChainHeadEvent(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeChainHeadEvent(ch any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChainHeadEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChainHeadEvent), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChainHeadEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChainHeadEvent), ch) } // SubscribeLogsEvent mocks base method. -func (m *MockBackend) SubscribeLogsEvent(arg0 chan<- []*types.Log) event.Subscription { +func (m *MockBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeLogsEvent", arg0) + ret := m.ctrl.Call(m, "SubscribeLogsEvent", ch) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeLogsEvent indicates an expected call of SubscribeLogsEvent. -func (mr *MockBackendMockRecorder) SubscribeLogsEvent(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeLogsEvent(ch any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeLogsEvent), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeLogsEvent), ch) } // SubscribeNewTxsEvent mocks base method. @@ -1060,80 +1189,80 @@ func (m *MockBackend) SubscribeNewTxsEvent(arg0 chan<- core.NewTxsEvent) event.S } // SubscribeNewTxsEvent indicates an expected call of SubscribeNewTxsEvent. -func (mr *MockBackendMockRecorder) SubscribeNewTxsEvent(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeNewTxsEvent(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeNewTxsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeNewTxsEvent), arg0) } // SubscribePendingLogsEvent mocks base method. -func (m *MockBackend) SubscribePendingLogsEvent(arg0 chan<- []*types.Log) event.Subscription { +func (m *MockBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribePendingLogsEvent", arg0) + ret := m.ctrl.Call(m, "SubscribePendingLogsEvent", ch) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribePendingLogsEvent indicates an expected call of SubscribePendingLogsEvent. -func (mr *MockBackendMockRecorder) SubscribePendingLogsEvent(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribePendingLogsEvent(ch any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribePendingLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribePendingLogsEvent), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribePendingLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribePendingLogsEvent), ch) } // SubscribeRemovedLogsEvent mocks base method. -func (m *MockBackend) SubscribeRemovedLogsEvent(arg0 chan<- core.RemovedLogsEvent) event.Subscription { +func (m *MockBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeRemovedLogsEvent", arg0) + ret := m.ctrl.Call(m, "SubscribeRemovedLogsEvent", ch) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeRemovedLogsEvent indicates an expected call of SubscribeRemovedLogsEvent. -func (mr *MockBackendMockRecorder) SubscribeRemovedLogsEvent(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeRemovedLogsEvent(ch any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeRemovedLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeRemovedLogsEvent), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeRemovedLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeRemovedLogsEvent), ch) } // SubscribeStateSyncEvent mocks base method. -func (m *MockBackend) SubscribeStateSyncEvent(arg0 chan<- core.StateSyncEvent) event.Subscription { +func (m *MockBackend) SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SubscribeStateSyncEvent", arg0) + ret := m.ctrl.Call(m, "SubscribeStateSyncEvent", ch) ret0, _ := ret[0].(event.Subscription) return ret0 } // SubscribeStateSyncEvent indicates an expected call of SubscribeStateSyncEvent. -func (mr *MockBackendMockRecorder) SubscribeStateSyncEvent(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SubscribeStateSyncEvent(ch any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeStateSyncEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeStateSyncEvent), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeStateSyncEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeStateSyncEvent), ch) } // SuggestGasTipCap mocks base method. -func (m *MockBackend) SuggestGasTipCap(arg0 context.Context) (*big.Int, error) { +func (m *MockBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SuggestGasTipCap", arg0) + ret := m.ctrl.Call(m, "SuggestGasTipCap", ctx) ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } // SuggestGasTipCap indicates an expected call of SuggestGasTipCap. -func (mr *MockBackendMockRecorder) SuggestGasTipCap(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SuggestGasTipCap(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SuggestGasTipCap", reflect.TypeOf((*MockBackend)(nil).SuggestGasTipCap), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SuggestGasTipCap", reflect.TypeOf((*MockBackend)(nil).SuggestGasTipCap), ctx) } // SyncProgress mocks base method. -func (m *MockBackend) SyncProgress(arg0 context.Context) ethereum.SyncProgress { +func (m *MockBackend) SyncProgress(ctx context.Context) ethereum.SyncProgress { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SyncProgress", arg0) + ret := m.ctrl.Call(m, "SyncProgress", ctx) ret0, _ := ret[0].(ethereum.SyncProgress) return ret0 } // SyncProgress indicates an expected call of SyncProgress. -func (mr *MockBackendMockRecorder) SyncProgress(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) SyncProgress(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncProgress", reflect.TypeOf((*MockBackend)(nil).SyncProgress), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncProgress", reflect.TypeOf((*MockBackend)(nil).SyncProgress), ctx) } // TxIndexDone mocks base method. @@ -1166,18 +1295,32 @@ func (mr *MockBackendMockRecorder) TxPoolContent() *gomock.Call { } // TxPoolContentFrom mocks base method. -func (m *MockBackend) TxPoolContentFrom(arg0 common.Address) ([]*types.Transaction, []*types.Transaction) { +func (m *MockBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TxPoolContentFrom", arg0) + ret := m.ctrl.Call(m, "TxPoolContentFrom", addr) ret0, _ := ret[0].([]*types.Transaction) ret1, _ := ret[1].([]*types.Transaction) return ret0, ret1 } // TxPoolContentFrom indicates an expected call of TxPoolContentFrom. -func (mr *MockBackendMockRecorder) TxPoolContentFrom(arg0 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) TxPoolContentFrom(addr any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxPoolContentFrom", reflect.TypeOf((*MockBackend)(nil).TxPoolContentFrom), addr) +} + +// TxStatus mocks base method. +func (m *MockBackend) TxStatus(hash common.Hash) txpool.TxStatus { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TxStatus", hash) + ret0, _ := ret[0].(txpool.TxStatus) + return ret0 +} + +// TxStatus indicates an expected call of TxStatus. +func (mr *MockBackendMockRecorder) TxStatus(hash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxPoolContentFrom", reflect.TypeOf((*MockBackend)(nil).TxPoolContentFrom), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxStatus", reflect.TypeOf((*MockBackend)(nil).TxStatus), hash) } // UnprotectedAllowed mocks base method. @@ -1195,46 +1338,46 @@ func (mr *MockBackendMockRecorder) UnprotectedAllowed() *gomock.Call { } // WitnessByHash mocks base method. -func (m *MockBackend) WitnessByHash(arg0 context.Context, arg1 common.Hash) (*stateless.Witness, error) { +func (m *MockBackend) WitnessByHash(ctx context.Context, hash common.Hash) (*stateless.Witness, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WitnessByHash", arg0, arg1) + ret := m.ctrl.Call(m, "WitnessByHash", ctx, hash) ret0, _ := ret[0].(*stateless.Witness) ret1, _ := ret[1].(error) return ret0, ret1 } // WitnessByHash indicates an expected call of WitnessByHash. -func (mr *MockBackendMockRecorder) WitnessByHash(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) WitnessByHash(ctx, hash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByHash", reflect.TypeOf((*MockBackend)(nil).WitnessByHash), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByHash", reflect.TypeOf((*MockBackend)(nil).WitnessByHash), ctx, hash) } // WitnessByNumber mocks base method. -func (m *MockBackend) WitnessByNumber(arg0 context.Context, arg1 rpc.BlockNumber) (*stateless.Witness, error) { +func (m *MockBackend) WitnessByNumber(ctx context.Context, number rpc.BlockNumber) (*stateless.Witness, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WitnessByNumber", arg0, arg1) + ret := m.ctrl.Call(m, "WitnessByNumber", ctx, number) ret0, _ := ret[0].(*stateless.Witness) ret1, _ := ret[1].(error) return ret0, ret1 } // WitnessByNumber indicates an expected call of WitnessByNumber. -func (mr *MockBackendMockRecorder) WitnessByNumber(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) WitnessByNumber(ctx, number any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByNumber", reflect.TypeOf((*MockBackend)(nil).WitnessByNumber), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByNumber", reflect.TypeOf((*MockBackend)(nil).WitnessByNumber), ctx, number) } // WitnessByNumberOrHash mocks base method. -func (m *MockBackend) WitnessByNumberOrHash(arg0 context.Context, arg1 rpc.BlockNumberOrHash) (*stateless.Witness, error) { +func (m *MockBackend) WitnessByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*stateless.Witness, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WitnessByNumberOrHash", arg0, arg1) + ret := m.ctrl.Call(m, "WitnessByNumberOrHash", ctx, blockNrOrHash) ret0, _ := ret[0].(*stateless.Witness) ret1, _ := ret[1].(error) return ret0, ret1 } // WitnessByNumberOrHash indicates an expected call of WitnessByNumberOrHash. -func (mr *MockBackendMockRecorder) WitnessByNumberOrHash(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBackendMockRecorder) WitnessByNumberOrHash(ctx, blockNrOrHash any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).WitnessByNumberOrHash), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WitnessByNumberOrHash", reflect.TypeOf((*MockBackend)(nil).WitnessByNumberOrHash), ctx, blockNrOrHash) } diff --git a/eth/filters/IBatch.go b/eth/filters/IBatch.go index 433cda017b..b2bf9aa3d2 100644 --- a/eth/filters/IBatch.go +++ b/eth/filters/IBatch.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ethereum/go-ethereum/ethdb (interfaces: Batch) +// +// Generated by this command: +// +// mockgen -destination=../eth/filters/IBatch.go -package=filters . Batch +// // Package filters is a generated GoMock package. package filters @@ -7,15 +12,15 @@ package filters import ( reflect "reflect" - gomock "go.uber.org/mock/gomock" - ethdb "github.com/ethereum/go-ethereum/ethdb" + gomock "go.uber.org/mock/gomock" ) // MockBatch is a mock of Batch interface. type MockBatch struct { ctrl *gomock.Controller recorder *MockBatchMockRecorder + isgomock struct{} } // MockBatchMockRecorder is the mock recorder for MockBatch. @@ -36,59 +41,59 @@ func (m *MockBatch) EXPECT() *MockBatchMockRecorder { } // Delete mocks base method. -func (m *MockBatch) Delete(arg0 []byte) error { +func (m *MockBatch) Delete(key []byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", arg0) + ret := m.ctrl.Call(m, "Delete", key) ret0, _ := ret[0].(error) return ret0 } // Delete indicates an expected call of Delete. -func (mr *MockBatchMockRecorder) Delete(arg0 interface{}) *gomock.Call { +func (mr *MockBatchMockRecorder) Delete(key any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockBatch)(nil).Delete), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockBatch)(nil).Delete), key) } // DeleteRange mocks base method. -func (m *MockBatch) DeleteRange(arg0, arg1 []byte) error { +func (m *MockBatch) DeleteRange(start, end []byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteRange", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteRange", start, end) ret0, _ := ret[0].(error) return ret0 } // DeleteRange indicates an expected call of DeleteRange. -func (mr *MockBatchMockRecorder) DeleteRange(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBatchMockRecorder) DeleteRange(start, end any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRange", reflect.TypeOf((*MockBatch)(nil).DeleteRange), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRange", reflect.TypeOf((*MockBatch)(nil).DeleteRange), start, end) } // Put mocks base method. -func (m *MockBatch) Put(arg0, arg1 []byte) error { +func (m *MockBatch) Put(key, value []byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Put", arg0, arg1) + ret := m.ctrl.Call(m, "Put", key, value) ret0, _ := ret[0].(error) return ret0 } // Put indicates an expected call of Put. -func (mr *MockBatchMockRecorder) Put(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockBatchMockRecorder) Put(key, value any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockBatch)(nil).Put), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockBatch)(nil).Put), key, value) } // Replay mocks base method. -func (m *MockBatch) Replay(arg0 ethdb.KeyValueWriter) error { +func (m *MockBatch) Replay(w ethdb.KeyValueWriter) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Replay", arg0) + ret := m.ctrl.Call(m, "Replay", w) ret0, _ := ret[0].(error) return ret0 } // Replay indicates an expected call of Replay. -func (mr *MockBatchMockRecorder) Replay(arg0 interface{}) *gomock.Call { +func (mr *MockBatchMockRecorder) Replay(w any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Replay", reflect.TypeOf((*MockBatch)(nil).Replay), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Replay", reflect.TypeOf((*MockBatch)(nil).Replay), w) } // Reset mocks base method. diff --git a/eth/filters/IDatabase.go b/eth/filters/IDatabase.go index 221e4649f2..82da0237e8 100644 --- a/eth/filters/IDatabase.go +++ b/eth/filters/IDatabase.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ethereum/go-ethereum/ethdb (interfaces: Database) +// +// Generated by this command: +// +// mockgen -destination=../eth/filters/IDatabase.go -package=filters . Database +// // Package filters is a generated GoMock package. package filters @@ -7,15 +12,15 @@ package filters import ( reflect "reflect" - gomock "go.uber.org/mock/gomock" - ethdb "github.com/ethereum/go-ethereum/ethdb" + gomock "go.uber.org/mock/gomock" ) // MockDatabase is a mock of Database interface. type MockDatabase struct { ctrl *gomock.Controller recorder *MockDatabaseMockRecorder + isgomock struct{} } // MockDatabaseMockRecorder is the mock recorder for MockDatabase. @@ -36,33 +41,33 @@ func (m *MockDatabase) EXPECT() *MockDatabaseMockRecorder { } // Ancient mocks base method. -func (m *MockDatabase) Ancient(arg0 string, arg1 uint64) ([]byte, error) { +func (m *MockDatabase) Ancient(kind string, number uint64) ([]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Ancient", arg0, arg1) + ret := m.ctrl.Call(m, "Ancient", kind, number) ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(error) return ret0, ret1 } // Ancient indicates an expected call of Ancient. -func (mr *MockDatabaseMockRecorder) Ancient(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) Ancient(kind, number any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ancient", reflect.TypeOf((*MockDatabase)(nil).Ancient), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ancient", reflect.TypeOf((*MockDatabase)(nil).Ancient), kind, number) } // AncientBytes mocks base method. -func (m *MockDatabase) AncientBytes(arg0 string, arg1, arg2, arg3 uint64) ([]byte, error) { +func (m *MockDatabase) AncientBytes(kind string, id, offset, length uint64) ([]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AncientBytes", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "AncientBytes", kind, id, offset, length) ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(error) return ret0, ret1 } // AncientBytes indicates an expected call of AncientBytes. -func (mr *MockDatabaseMockRecorder) AncientBytes(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) AncientBytes(kind, id, offset, length any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AncientBytes", reflect.TypeOf((*MockDatabase)(nil).AncientBytes), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AncientBytes", reflect.TypeOf((*MockDatabase)(nil).AncientBytes), kind, id, offset, length) } // AncientDatadir mocks base method. @@ -95,33 +100,33 @@ func (mr *MockDatabaseMockRecorder) AncientOffSet() *gomock.Call { } // AncientRange mocks base method. -func (m *MockDatabase) AncientRange(arg0 string, arg1, arg2, arg3 uint64) ([][]byte, error) { +func (m *MockDatabase) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AncientRange", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "AncientRange", kind, start, count, maxBytes) ret0, _ := ret[0].([][]byte) ret1, _ := ret[1].(error) return ret0, ret1 } // AncientRange indicates an expected call of AncientRange. -func (mr *MockDatabaseMockRecorder) AncientRange(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) AncientRange(kind, start, count, maxBytes any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AncientRange", reflect.TypeOf((*MockDatabase)(nil).AncientRange), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AncientRange", reflect.TypeOf((*MockDatabase)(nil).AncientRange), kind, start, count, maxBytes) } // AncientSize mocks base method. -func (m *MockDatabase) AncientSize(arg0 string) (uint64, error) { +func (m *MockDatabase) AncientSize(kind string) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AncientSize", arg0) + ret := m.ctrl.Call(m, "AncientSize", kind) ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } // AncientSize indicates an expected call of AncientSize. -func (mr *MockDatabaseMockRecorder) AncientSize(arg0 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) AncientSize(kind any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AncientSize", reflect.TypeOf((*MockDatabase)(nil).AncientSize), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AncientSize", reflect.TypeOf((*MockDatabase)(nil).AncientSize), kind) } // Ancients mocks base method. @@ -154,75 +159,75 @@ func (mr *MockDatabaseMockRecorder) Close() *gomock.Call { } // Compact mocks base method. -func (m *MockDatabase) Compact(arg0, arg1 []byte) error { +func (m *MockDatabase) Compact(start, limit []byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Compact", arg0, arg1) + ret := m.ctrl.Call(m, "Compact", start, limit) ret0, _ := ret[0].(error) return ret0 } // Compact indicates an expected call of Compact. -func (mr *MockDatabaseMockRecorder) Compact(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) Compact(start, limit any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Compact", reflect.TypeOf((*MockDatabase)(nil).Compact), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Compact", reflect.TypeOf((*MockDatabase)(nil).Compact), start, limit) } // Delete mocks base method. -func (m *MockDatabase) Delete(arg0 []byte) error { +func (m *MockDatabase) Delete(key []byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", arg0) + ret := m.ctrl.Call(m, "Delete", key) ret0, _ := ret[0].(error) return ret0 } // Delete indicates an expected call of Delete. -func (mr *MockDatabaseMockRecorder) Delete(arg0 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) Delete(key any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDatabase)(nil).Delete), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDatabase)(nil).Delete), key) } // DeleteRange mocks base method. -func (m *MockDatabase) DeleteRange(arg0, arg1 []byte) error { +func (m *MockDatabase) DeleteRange(start, end []byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteRange", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteRange", start, end) ret0, _ := ret[0].(error) return ret0 } // DeleteRange indicates an expected call of DeleteRange. -func (mr *MockDatabaseMockRecorder) DeleteRange(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) DeleteRange(start, end any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRange", reflect.TypeOf((*MockDatabase)(nil).DeleteRange), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRange", reflect.TypeOf((*MockDatabase)(nil).DeleteRange), start, end) } // Get mocks base method. -func (m *MockDatabase) Get(arg0 []byte) ([]byte, error) { +func (m *MockDatabase) Get(key []byte) ([]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", arg0) + ret := m.ctrl.Call(m, "Get", key) ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(error) return ret0, ret1 } // Get indicates an expected call of Get. -func (mr *MockDatabaseMockRecorder) Get(arg0 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) Get(key any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDatabase)(nil).Get), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDatabase)(nil).Get), key) } // Has mocks base method. -func (m *MockDatabase) Has(arg0 []byte) (bool, error) { +func (m *MockDatabase) Has(key []byte) (bool, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Has", arg0) + ret := m.ctrl.Call(m, "Has", key) ret0, _ := ret[0].(bool) ret1, _ := ret[1].(error) return ret0, ret1 } // Has indicates an expected call of Has. -func (mr *MockDatabaseMockRecorder) Has(arg0 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) Has(key any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Has", reflect.TypeOf((*MockDatabase)(nil).Has), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Has", reflect.TypeOf((*MockDatabase)(nil).Has), key) } // ItemAmountInAncient mocks base method. @@ -250,7 +255,7 @@ func (m *MockDatabase) ModifyAncients(arg0 func(ethdb.AncientWriteOp) error) (in } // ModifyAncients indicates an expected call of ModifyAncients. -func (mr *MockDatabaseMockRecorder) ModifyAncients(arg0 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) ModifyAncients(arg0 any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyAncients", reflect.TypeOf((*MockDatabase)(nil).ModifyAncients), arg0) } @@ -270,59 +275,59 @@ func (mr *MockDatabaseMockRecorder) NewBatch() *gomock.Call { } // NewBatchWithSize mocks base method. -func (m *MockDatabase) NewBatchWithSize(arg0 int) ethdb.Batch { +func (m *MockDatabase) NewBatchWithSize(size int) ethdb.Batch { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NewBatchWithSize", arg0) + ret := m.ctrl.Call(m, "NewBatchWithSize", size) ret0, _ := ret[0].(ethdb.Batch) return ret0 } // NewBatchWithSize indicates an expected call of NewBatchWithSize. -func (mr *MockDatabaseMockRecorder) NewBatchWithSize(arg0 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) NewBatchWithSize(size any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewBatchWithSize", reflect.TypeOf((*MockDatabase)(nil).NewBatchWithSize), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewBatchWithSize", reflect.TypeOf((*MockDatabase)(nil).NewBatchWithSize), size) } // NewIterator mocks base method. -func (m *MockDatabase) NewIterator(arg0, arg1 []byte) ethdb.Iterator { +func (m *MockDatabase) NewIterator(prefix, start []byte) ethdb.Iterator { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "NewIterator", arg0, arg1) + ret := m.ctrl.Call(m, "NewIterator", prefix, start) ret0, _ := ret[0].(ethdb.Iterator) return ret0 } // NewIterator indicates an expected call of NewIterator. -func (mr *MockDatabaseMockRecorder) NewIterator(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) NewIterator(prefix, start any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewIterator", reflect.TypeOf((*MockDatabase)(nil).NewIterator), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewIterator", reflect.TypeOf((*MockDatabase)(nil).NewIterator), prefix, start) } // Put mocks base method. -func (m *MockDatabase) Put(arg0, arg1 []byte) error { +func (m *MockDatabase) Put(key, value []byte) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Put", arg0, arg1) + ret := m.ctrl.Call(m, "Put", key, value) ret0, _ := ret[0].(error) return ret0 } // Put indicates an expected call of Put. -func (mr *MockDatabaseMockRecorder) Put(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) Put(key, value any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockDatabase)(nil).Put), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockDatabase)(nil).Put), key, value) } // ReadAncients mocks base method. -func (m *MockDatabase) ReadAncients(arg0 func(ethdb.AncientReaderOp) error) error { +func (m *MockDatabase) ReadAncients(fn func(ethdb.AncientReaderOp) error) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReadAncients", arg0) + ret := m.ctrl.Call(m, "ReadAncients", fn) ret0, _ := ret[0].(error) return ret0 } // ReadAncients indicates an expected call of ReadAncients. -func (mr *MockDatabaseMockRecorder) ReadAncients(arg0 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) ReadAncients(fn any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadAncients", reflect.TypeOf((*MockDatabase)(nil).ReadAncients), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadAncients", reflect.TypeOf((*MockDatabase)(nil).ReadAncients), fn) } // Stat mocks base method. @@ -384,31 +389,31 @@ func (mr *MockDatabaseMockRecorder) Tail() *gomock.Call { } // TruncateHead mocks base method. -func (m *MockDatabase) TruncateHead(arg0 uint64) (uint64, error) { +func (m *MockDatabase) TruncateHead(n uint64) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TruncateHead", arg0) + ret := m.ctrl.Call(m, "TruncateHead", n) ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } // TruncateHead indicates an expected call of TruncateHead. -func (mr *MockDatabaseMockRecorder) TruncateHead(arg0 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) TruncateHead(n any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TruncateHead", reflect.TypeOf((*MockDatabase)(nil).TruncateHead), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TruncateHead", reflect.TypeOf((*MockDatabase)(nil).TruncateHead), n) } // TruncateTail mocks base method. -func (m *MockDatabase) TruncateTail(arg0 uint64) (uint64, error) { +func (m *MockDatabase) TruncateTail(n uint64) (uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TruncateTail", arg0) + ret := m.ctrl.Call(m, "TruncateTail", n) ret0, _ := ret[0].(uint64) ret1, _ := ret[1].(error) return ret0, ret1 } // TruncateTail indicates an expected call of TruncateTail. -func (mr *MockDatabaseMockRecorder) TruncateTail(arg0 interface{}) *gomock.Call { +func (mr *MockDatabaseMockRecorder) TruncateTail(n any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TruncateTail", reflect.TypeOf((*MockDatabase)(nil).TruncateTail), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TruncateTail", reflect.TypeOf((*MockDatabase)(nil).TruncateTail), n) } diff --git a/eth/filters/IIterator.go b/eth/filters/IIterator.go index 0dbf504414..e4e4bdcf22 100644 --- a/eth/filters/IIterator.go +++ b/eth/filters/IIterator.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/ethereum/go-ethereum/ethdb (interfaces: Iterator) +// +// Generated by this command: +// +// mockgen -destination=../eth/filters/IIterator.go -package=filters . Iterator +// // Package filters is a generated GoMock package. package filters @@ -14,6 +19,7 @@ import ( type MockIterator struct { ctrl *gomock.Controller recorder *MockIteratorMockRecorder + isgomock struct{} } // MockIteratorMockRecorder is the mock recorder for MockIterator. diff --git a/eth/state_accessor.go b/eth/state_accessor.go index d7f755c5ab..7b3c3b4d03 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -241,6 +241,10 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, if block.NumberU64() == 0 { return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis") } + // Avoid doing any extra work if the transaction index is out of range for the block. + if txIndex > 0 && txIndex >= len(block.Transactions()) { + return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) + } // Create the parent state database parent := eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) if parent == nil { diff --git a/eth/tracers/api.go b/eth/tracers/api.go index b0f15b6e5c..fd5bb85b58 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -19,20 +19,16 @@ package tracers import ( "bufio" "context" - "encoding/hex" "encoding/json" "errors" "fmt" "math/big" "os" - "path/filepath" "runtime" + "sort" "sync" "time" - "github.com/holiman/uint256" - - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" @@ -40,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" @@ -74,22 +69,14 @@ const ( // for tracing. The creation of trace state will be paused if the unused // trace states exceed this limit. maximumPendingTraceStates = 128 - - defaultPath = string(".") - - defaultIOFlag = false ) -var defaultBorTraceEnabled = newBoolPtr(false) - var errTxNotFound = errors.New("transaction not found") // StateReleaseFunc is used to deallocate resources held by constructing a // historical state for tracing purposes. type StateReleaseFunc func() -var allowIOTracing = false // Change this to true to enable IO tracing for debugging - // Backend interface provides the common API services (that are provided by // both full and light clients) with access to necessary functions. type Backend interface { @@ -106,9 +93,6 @@ type Backend interface { ChainDb() ethdb.Database StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) - - // Bor related APIs - GetBorBlockTransactionWithBlockHash(ctx context.Context, txHash common.Hash, blockHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) } // API is the collection of tracing APIs exposed over the private debugging endpoint. @@ -175,38 +159,6 @@ func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber return api.blockByHash(ctx, hash) } -// getAllBlockTransactions returns all blocks transactions including state-sync transaction if present -// along with a flag and it's hash (which is calculated differently than regular transactions) -func (api *API) getAllBlockTransactions(ctx context.Context, block *types.Block) (types.Transactions, bool, common.Hash) { - var ( - txs types.Transactions = block.Transactions() - stateSyncPresent bool - stateSyncHash common.Hash - ) - - isMadhugiri := api.backend.ChainConfig().Bor != nil && api.backend.ChainConfig().Bor.IsMadhugiri(block.Number()) - if isMadhugiri { - if len(txs) > 0 && txs[len(txs)-1].Type() == types.StateSyncTxType { - stateSyncPresent = true - stateSyncHash = txs[len(txs)-1].Hash() - } - return txs, stateSyncPresent, stateSyncHash - } - - borReceipt := rawdb.ReadBorReceipt(api.backend.ChainDb(), block.Hash(), block.NumberU64(), api.backend.ChainConfig()) - if borReceipt != nil { - txHash := types.GetDerivedBorTxHash(types.BorReceiptKey(block.Number().Uint64(), block.Hash())) - if txHash != (common.Hash{}) { - borTx, _, _, _, _ := api.backend.GetBorBlockTransactionWithBlockHash(ctx, txHash, block.Hash()) - txs = append(txs, borTx) - stateSyncPresent = true - stateSyncHash = txHash - } - } - - return txs, stateSyncPresent, stateSyncHash -} - // TraceConfig holds extra parameters to trace functions. type TraceConfig struct { *logger.Config @@ -217,29 +169,7 @@ type TraceConfig struct { IOFlag *bool // Config specific to given tracer. Note struct logger // config are historically embedded in main object. - TracerConfig json.RawMessage - BorTraceEnabled *bool - BorTx *bool -} - -// deepCopyTraceConfig returns a deep copy of the given TraceConfig so that -// each goroutine can safely mutate its own copy without racing. -func deepCopyTraceConfig(config *TraceConfig) TraceConfig { - cpy := *config - if config.Config != nil { - loggerCfg := *config.Config - cpy.Config = &loggerCfg - } - if config.BorTx != nil { - cpy.BorTx = newBoolPtr(*config.BorTx) - } - if config.BorTraceEnabled != nil { - cpy.BorTraceEnabled = newBoolPtr(*config.BorTraceEnabled) - } - if config.TracerConfig != nil { - cpy.TracerConfig = append(json.RawMessage{}, config.TracerConfig...) - } - return cpy + TracerConfig json.RawMessage } // TraceCallConfig is the config for traceCall API. It holds one more @@ -254,9 +184,8 @@ type TraceCallConfig struct { // StdTraceConfig holds extra parameters to standard-json trace functions. type StdTraceConfig struct { logger.Config - Reexec *uint64 - TxHash common.Hash - BorTraceEnabled *bool + Reexec *uint64 + TxHash common.Hash } // txTraceResult is the result of a single transaction trace. @@ -333,17 +262,6 @@ func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, conf // The tracing procedure should be aborted in case the closed signal is received. // nolint:gocognit func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed <-chan error) chan *blockTraceResult { - if config == nil { - config = &TraceConfig{ - BorTraceEnabled: defaultBorTraceEnabled, - BorTx: newBoolPtr(false), - } - } - - if config.BorTraceEnabled == nil { - config.BorTraceEnabled = defaultBorTraceEnabled - } - reexec := defaultTraceReexec if config != nil && config.Reexec != nil { reexec = *config.Reexec @@ -351,7 +269,6 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed blocks := int(end.NumberU64() - start.NumberU64()) threads := runtime.NumCPU() - if threads > blocks { threads = blocks } @@ -373,50 +290,28 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed // Fetch and execute the block trace taskCh for task := range taskCh { var ( - signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time()) - blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil) + signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time()) + blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil) + cumulativeGasUsed uint64 ) - // Trace all the transactions contained within - txs, stateSyncPresent, stateSyncHash := api.getAllBlockTransactions(ctx, task.block) - // Include state sync tx if canonical (post-Madhugiri) or BorTraceEnabled (pre-Madhugiri). - isMadhugiri := api.backend.ChainConfig().Bor != nil && api.backend.ChainConfig().Bor.IsMadhugiri(task.block.Number()) - includeStateSyncTx := isMadhugiri || *config.BorTraceEnabled - if stateSyncPresent && !includeStateSyncTx { - txs = txs[:len(txs)-1] - stateSyncPresent = false - } - - for i, tx := range txs { + for i, tx := range task.block.Transactions() { msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee()) - txHash := tx.Hash() - if stateSyncPresent && i == len(txs)-1 { - txHash = stateSyncHash - } txctx := &Context{ - BlockHash: task.block.Hash(), - BlockNumber: task.block.Number(), - TxIndex: i, - TxHash: txHash, - } - - var res interface{} - - var err error - - // Deep copy config for this transaction to avoid race conditions - txConfig := deepCopyTraceConfig(config) - if stateSyncPresent && i == len(txs)-1 && includeStateSyncTx { - txConfig.BorTx = newBoolPtr(true) + BlockHash: task.block.Hash(), + BlockNumber: task.block.Number(), + TxIndex: i, + TxHash: tx.Hash(), + CumulativeGasUsed: cumulativeGasUsed, + LogIndex: len(task.statedb.Logs()), } - - res, err = api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, &txConfig, nil) + res, gasUsed, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config, nil) if err != nil { - task.results[i] = &txTraceResult{TxHash: txHash, Error: err.Error()} - log.Warn("Tracing failed", "hash", txHash, "block", task.block.NumberU64(), "err", err) - + task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()} + log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err) break } - task.results[i] = &txTraceResult{TxHash: txHash, Result: res} + cumulativeGasUsed += gasUsed + task.results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res} } // Tracing state is used up, queue it for de-referencing. Note the // state is the parent state of trace block, use block.number-1 as @@ -582,11 +477,6 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed return retCh } -func newBoolPtr(bb bool) *bool { - b := bb - return &b -} - // TraceBlockByNumber returns the structured logs created during the execution of // EVM and returns them as a JSON object. func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) { @@ -655,35 +545,9 @@ func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, return api.standardTraceBlockToFile(ctx, block, config) } -func prepareCallMessage(msg core.Message) statefull.Callmsg { - return statefull.Callmsg{ - CallMsg: ethereum.CallMsg{ - From: msg.From, - To: msg.To, - Gas: msg.GasLimit, - GasPrice: msg.GasPrice, - GasFeeCap: msg.GasFeeCap, - GasTipCap: msg.GasTipCap, - Value: msg.Value, - Data: msg.Data, - AccessList: msg.AccessList, - }} -} - // IntermediateRoots executes a block (bad- or canon- or side-), and returns a list // of intermediate roots: the stateroot after each transaction. func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) { - if config == nil { - config = &TraceConfig{ - BorTraceEnabled: defaultBorTraceEnabled, - BorTx: newBoolPtr(false), - } - } - - if config.BorTraceEnabled == nil { - config.BorTraceEnabled = defaultBorTraceEnabled - } - block, _ := api.blockByHash(ctx, hash) if block == nil { // Check in the bad blocks @@ -729,54 +593,35 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config core.ProcessParentBlockHash(block.ParentHash(), evm) } - txs, stateSyncPresent, stateSyncHash := api.getAllBlockTransactions(ctx, block) - // Include state sync tx if canonical (post-Madhugiri) or BorTraceEnabled (pre-Madhugiri). - isMadhugiri := chainConfig.Bor != nil && chainConfig.Bor.IsMadhugiri(block.Number()) - includeStateSyncTx := isMadhugiri || *config.BorTraceEnabled - for i, tx := range txs { + for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { return nil, err } - msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) - - //nolint:nestif - if stateSyncPresent && i == len(txs)-1 { - if includeStateSyncTx { - callmsg := prepareCallMessage(*msg) - statedb.SetTxContext(stateSyncHash, i) - if _, err := statefull.ApplyMessage(ctx, callmsg, statedb, block.Header(), api.backend.ChainConfig(), api.chainContext(ctx)); err != nil { - log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", stateSyncHash, "err", err) - // We intentionally don't return the error here: if we do, then the RPC server will not - // return the roots. Most likely, the caller already knows that a certain transaction fails to - // be included, but still want the intermediate roots that led to that point. - // It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be - // executable. - // N.B: This should never happen while tracing canon blocks, only when tracing bad blocks. - return roots, nil - } - } else { - break - } + statedb.SetTxContext(tx.Hash(), i) + var err error + if tx.Type() == types.StateSyncTxType { + // State sync transactions are processed differently than normal transactions + stateReceiverAddress := api.backend.ChainConfig().Bor.StateReceiverContract + _, err = statefull.ApplyStateSyncEvents(evm, tx, msg, common.HexToAddress(stateReceiverAddress)) } else { - statedb.SetTxContext(tx.Hash(), i) - if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { - log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) - // We intentionally don't return the error here: if we do, then the RPC server will not - // return the roots. Most likely, the caller already knows that a certain transaction fails to - // be included, but still want the intermediate roots that led to that point. - // It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be - // executable. - // N.B: This should never happen while tracing canon blocks, only when tracing bad blocks. - return roots, nil - } + _, err = core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) } + if err != nil { + log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) + // We intentionally don't return the error here: if we do, then the RPC server will not + // return the roots. Most likely, the caller already knows that a certain transaction fails to + // be included, but still want the intermediate roots that led to that point. + // It may happen the tx_N causes an erroneous state, which in turn causes tx_N+M to not be + // executable. + // N.B: This should never happen while tracing canon blocks, only when tracing bad blocks. + return roots, nil + } // calling IntermediateRoot will internally call Finalize on the state // so any modifications are written to the trie roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects)) } - return roots, nil } @@ -795,21 +640,7 @@ func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Has // traceBlock configures a new tracer according to the provided configuration, and // executes all the transactions contained within. The return value will be one item // per transaction, dependent on the requested tracer. -// We always run parallel execution -// One thread runs along and executes txs without tracing enabled to generate their prestate. -// Worker threads take the tasks and the prestate and trace them. func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) { - if config == nil { - config = &TraceConfig{ - BorTraceEnabled: defaultBorTraceEnabled, - BorTx: newBoolPtr(false), - } - } - - if config.BorTraceEnabled == nil { - config.BorTraceEnabled = defaultBorTraceEnabled - } - if block.NumberU64() == 0 { return nil, errors.New("genesis is not traceable") } @@ -818,134 +649,131 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac if err != nil { return nil, err } - reexec := defaultTraceReexec if config != nil && config.Reexec != nil { reexec = *config.Reexec } - - path := defaultPath - if config != nil && config.Path != nil { - path = *config.Path - } - - ioflag := defaultIOFlag - if allowIOTracing && config != nil && config.IOFlag != nil { - ioflag = *config.IOFlag - } - statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) if err != nil { return nil, err } - defer release() - // create and add empty mvHashMap in statedb as StateAtBlock does not have mvHashmap in it. - if ioflag { - statedb.AddEmptyMVHashMap() + blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + evm := vm.NewEVM(blockCtx, statedb, api.backend.ChainConfig(), vm.Config{}) + if beaconRoot := block.BeaconRoot(); beaconRoot != nil { + core.ProcessBeaconBlockRoot(*beaconRoot, evm) + } + if api.backend.ChainConfig().IsPrague(block.Number()) { + core.ProcessParentBlockHash(block.ParentHash(), evm) + } + + // JS tracers have high overhead. In this case run a parallel + // process that generates states in one thread and traces txes + // in separate worker threads. + if config != nil && config.Tracer != nil && *config.Tracer != "" { + if isJS := DefaultDirectory.IsJS(*config.Tracer); isJS { + return api.traceBlockParallel(ctx, block, statedb, config) + } + } + + // As state-sync transactions before Madhugiri don't have event data within, we can't replay them. Only + // those post Madhugiri have data to be replayed and are part of block body. If there's a state-sync + // transaction, it should be included in the `block.Transactions()` list below. + // Native tracers have low overhead + var ( + txs = block.Transactions() + blockHash = block.Hash() + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) + results = make([]*txTraceResult, len(txs)) + cumulativeGasUsed uint64 + ) + for i, tx := range txs { + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) + txctx := &Context{ + BlockHash: blockHash, + BlockNumber: block.Number(), + TxIndex: i, + TxHash: tx.Hash(), + CumulativeGasUsed: cumulativeGasUsed, + LogIndex: len(statedb.Logs()), + } + res, gasUsed, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config, nil) + if err != nil { + return nil, err + } + cumulativeGasUsed += gasUsed + results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res} } + return results, nil +} - // Execute all the transaction contained within the block concurrently +// traceBlockParallel is for tracers that have a high overhead (read JS tracers). One thread +// runs along and executes txes without tracing enabled to generate their prestate. +// Worker threads take the tasks and the prestate and trace them. +// State-sync transactions (if present) are traced sequentially after all regular transactions +// complete, so that the statedb has the correct accumulated state for log index and cumulative gas. +func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, statedb *state.StateDB, config *TraceConfig) ([]*txTraceResult, error) { var ( - txs, stateSyncPresent, stateSyncHash = api.getAllBlockTransactions(ctx, block) - blockHash = block.Hash() - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) - results = make([]*txTraceResult, len(txs)) - pend sync.WaitGroup + txs = block.Transactions() + isStateSyncPresent bool + blockHash = block.Hash() + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) + results = make([]*txTraceResult, len(txs)) + pend sync.WaitGroup ) threads := runtime.NumCPU() if threads > len(txs) { threads = len(txs) } - + if threads == 0 { + threads = 1 + } jobs := make(chan *txTraceTask, threads) - for th := 0; th < threads; th++ { pend.Add(1) - go func() { defer pend.Done() // Fetch and execute the next transaction trace tasks for task := range jobs { msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee()) - txHash := txs[task.index].Hash() - if stateSyncPresent && task.index == len(txs)-1 { - txHash = stateSyncHash - } txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), TxIndex: task.index, - TxHash: txHash, + TxHash: txs[task.index].Hash(), } - - var res interface{} - - var err error - - // Deep copy config for this transaction to avoid race conditions - txConfig := deepCopyTraceConfig(config) - // Include state sync tx if canonical (post-Madhugiri) or BorTraceEnabled (pre-Madhugiri). - if stateSyncPresent && task.index == len(txs)-1 { - isMadhugiri := api.backend.ChainConfig().Bor != nil && api.backend.ChainConfig().Bor.IsMadhugiri(block.Number()) - if isMadhugiri || *config.BorTraceEnabled { - txConfig.BorTx = newBoolPtr(true) - } - } - // Reconstruct the block context for each transaction // as the GetHash function of BlockContext is not safe for // concurrent use. // See: https://github.com/ethereum/go-ethereum/issues/29114 blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - res, err = api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, &txConfig, nil) + res, _, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config, nil) if err != nil { - results[task.index] = &txTraceResult{TxHash: txHash, Error: err.Error()} + results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()} continue } - results[task.index] = &txTraceResult{TxHash: txHash, Result: res} + results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Result: res} } }() } - var IOdump string - - var RWstruct []state.DumpStruct - - var london bool - - if ioflag { - IOdump = "TransactionIndex, Incarnation, VersionTxIdx, VersionInc, Path, Operation\n" - RWstruct = []state.DumpStruct{} - } // Feed the transactions into the tracers and return var failed error - - if ioflag { - london = api.backend.ChainConfig().IsLondon(block.Number()) - } - blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) evm := vm.NewEVM(blockCtx, statedb, api.backend.ChainConfig(), vm.Config{}) - // Process beacon block root (EIP-4788) and parent block hash (EIP-2935) - // before executing transactions, matching stateAtTransaction behavior. - if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm) - } - if api.backend.ChainConfig().IsPrague(block.Number()) { - core.ProcessParentBlockHash(block.ParentHash(), evm) - } + // Track cumulative gas used to populate state-sync receipt at the very end (if it exists) + var cumulativeGasUsed uint64 txloop: for i, tx := range txs { - if ioflag { - // copy of statedb - statedb = statedb.Copy() + // Skip process state-sync tx in parallel. + if tx.Type() == types.StateSyncTxType { + isStateSyncPresent = true + continue } - // Send the trace task over for execution task := &txTraceTask{statedb: statedb.Copy(), index: i} select { @@ -958,87 +786,15 @@ txloop: // Generate the next state snapshot fast without tracing msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) statedb.SetTxContext(tx.Hash(), i) - - // nolint:nestif - if !ioflag { - //nolint:nestif - if stateSyncPresent && i == len(txs)-1 { - if *config.BorTraceEnabled { - callmsg := prepareCallMessage(*msg) - // nolint : contextcheck - if _, err := statefull.ApplyBorMessage(evm, callmsg); err != nil { - failed = err - break txloop - } - } else { - break txloop - } - } else { - // nolint : contextcheck - if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { - failed = err - break txloop - } - // Finalize the state so any modifications are written to the trie - // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) - } - } else { - coinbaseBalance := big.NewInt(statedb.GetBalance(blockCtx.Coinbase).ToBig().Int64()) - // nolint : contextcheck - result, err := core.ApplyMessageNoFeeBurnOrTip(evm, *msg, new(core.GasPool).AddGas(msg.GasLimit)) - - if err != nil { - failed = err - break - } - - if london { - statedb.AddBalance(result.BurntContractAddress, uint256.NewInt(result.FeeBurnt.Uint64()), tracing.BalanceChangeTransfer) - } - - statedb.AddBalance(blockCtx.Coinbase, uint256.NewInt(result.FeeTipped.Uint64()), tracing.BalanceChangeTransfer) - output1 := new(big.Int).SetBytes(result.SenderInitBalance.Bytes()) - output2 := new(big.Int).SetBytes(coinbaseBalance.Bytes()) - - // Deprecating transfer log and will be removed in future fork. PLEASE DO NOT USE this transfer log going forward. Parameters won't get updated as expected going forward with EIP1559 - // add transfer log - core.AddFeeTransferLog( - statedb, - - msg.From, - blockCtx.Coinbase, - - result.FeeTipped, - result.SenderInitBalance, - coinbaseBalance, - output1.Sub(output1, result.FeeTipped), - output2.Add(output2, result.FeeTipped), - ) - - // Finalize the state so any modifications are written to the trie - // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) - statedb.FlushMVWriteSet() - - structRead := statedb.GetReadMapDump() - structWrite := statedb.GetWriteMapDump() - - RWstruct = append(RWstruct, structRead...) - RWstruct = append(RWstruct, structWrite...) - } - } - - if ioflag { - for _, val := range RWstruct { - IOdump += fmt.Sprintf("%v , %v, %v , %v, ", val.TxIdx, val.TxInc, val.VerIdx, val.VerInc) + hex.EncodeToString(val.Path) + ", " + val.Op - } - - // make sure that the file exists and write IOdump - err = os.WriteFile(filepath.Join(path, "data.csv"), []byte(fmt.Sprint(IOdump)), 0600) + res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { - return nil, err + failed = err + break txloop } + cumulativeGasUsed += res.UsedGas + // Finalize the state so any modifications are written to the trie + // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect + statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) } close(jobs) @@ -1049,11 +805,23 @@ txloop: return nil, failed } - // Include state sync tx if canonical (post-Madhugiri) or BorTraceEnabled (pre-Madhugiri). - isMadhugiri := api.backend.ChainConfig().Bor != nil && api.backend.ChainConfig().Bor.IsMadhugiri(block.Number()) - includeStateSyncTx := isMadhugiri || *config.BorTraceEnabled - if stateSyncPresent && !includeStateSyncTx { - return results[:len(results)-1], nil + if isStateSyncPresent { + tx := txs[len(txs)-1] + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) + txctx := &Context{ + BlockHash: blockHash, + BlockNumber: block.Number(), + TxIndex: len(txs) - 1, + TxHash: tx.Hash(), + CumulativeGasUsed: cumulativeGasUsed, + LogIndex: len(statedb.Logs()), + } + res, _, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config, nil) + if err != nil { + results[txctx.TxIndex] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()} + } else { + results[txctx.TxIndex] = &txTraceResult{TxHash: tx.Hash(), Result: res} + } } return results, nil @@ -1063,18 +831,9 @@ txloop: // and traces either a full block or an individual transaction. The return value will // be one filename per transaction traced. func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block, config *StdTraceConfig) ([]string, error) { - if config == nil { - config = &StdTraceConfig{ - BorTraceEnabled: defaultBorTraceEnabled, - } - } - - if config.BorTraceEnabled == nil { - config.BorTraceEnabled = defaultBorTraceEnabled - } // If we're tracing a single transaction, make sure it's present if config != nil && config.TxHash != (common.Hash{}) { - if !api.containsTx(ctx, block, config.TxHash) { + if !containsTx(block, config.TxHash) { return nil, fmt.Errorf("transaction %#x not found in block", config.TxHash) } } @@ -1128,15 +887,6 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block chainConfig, canon = overrideConfig(chainConfig, config.Overrides) } - txs, stateSyncPresent, stateSyncHash := api.getAllBlockTransactions(ctx, block) - // Include state sync tx if canonical (post-Madhugiri) or BorTraceEnabled (pre-Madhugiri). - isMadhugiri := api.backend.ChainConfig().Bor != nil && api.backend.ChainConfig().Bor.IsMadhugiri(block.Number()) - includeStateSyncTx := isMadhugiri || *config.BorTraceEnabled - if stateSyncPresent && !includeStateSyncTx { - txs = txs[:len(txs)-1] - stateSyncPresent = false - } - evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { core.ProcessBeaconBlockRoot(*beaconRoot, evm) @@ -1144,12 +894,18 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block if chainConfig.IsPrague(block.Number()) { core.ProcessParentBlockHash(block.ParentHash(), evm) } - for i, tx := range txs { + for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) - if txHash != (common.Hash{}) && tx.Hash() != txHash && txHash != stateSyncHash { + if txHash != (common.Hash{}) && tx.Hash() != txHash { // Process the tx to update state, but don't trace it. - _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) + var err error + if tx.Type() == types.StateSyncTxType { + stateReceiverAddress := api.backend.ChainConfig().Bor.StateReceiverContract + _, err = statefull.ApplyStateSyncEvents(evm, tx, msg, common.HexToAddress(stateReceiverAddress)) + } else { + _, err = core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) + } if err != nil { return dumps, err } @@ -1172,40 +928,54 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block dumps = append(dumps, dump.Name()) // Set up the tracer and EVM for the transaction. var ( - writer = bufio.NewWriter(dump) - tracer = logger.NewJSONLogger(&logConfig, writer) - evm = vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{ - Tracer: tracer, - NoBaseFee: true, - }) + writer = bufio.NewWriter(dump) + hooks = logger.NewJSONLogger(&logConfig, writer) + evmHooks = hooks ) + // Wrap the tracer for state-sync transactions (post Madhugiri) to handle + // multiple independent EVM calls within a single transaction. + var wrappedTracer *Tracer + if tx.Type() == types.StateSyncTxType && chainConfig.Bor != nil && chainConfig.Bor.IsMadhugiri(block.Number()) { + stateReceiverAddress := common.HexToAddress(chainConfig.Bor.StateReceiverContract) + wrappedTracer = NewStateSyncTxnTracer(&Tracer{Hooks: hooks}, stateReceiverAddress) + evmHooks = wrappedTracer.Hooks + } + evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{ + Tracer: evmHooks, + NoBaseFee: true, + }) // Execute the transaction and flush any traces to disk - // Include state sync tx if canonical (post-Madhugiri) or BorTraceEnabled (pre-Madhugiri). - //nolint:nestif - if stateSyncPresent && i == len(txs)-1 && includeStateSyncTx { - callmsg := prepareCallMessage(*msg) - statedb.SetTxContext(stateSyncHash, i) - _, err = statefull.ApplyBorMessage(evm, callmsg) - - if writer != nil { - _ = writer.Flush() + statedb.SetTxContext(tx.Hash(), i) + var vmResult *core.ExecutionResult + if wrappedTracer != nil { + stateReceiverAddress := common.HexToAddress(chainConfig.Bor.StateReceiverContract) + if wrappedTracer.OnTxStart != nil { + wrappedTracer.OnTxStart(evm.GetVMContext(), tx, params.BorSystemAddress) } - } else if !(stateSyncPresent && i == len(txs)-1) { - statedb.SetTxContext(tx.Hash(), i) - if tracer.OnTxStart != nil { - tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) + vmResult, err = statefull.ApplyStateSyncEvents(evm, tx, msg, stateReceiverAddress) + if wrappedTracer.OnTxEnd != nil { + var receipt *types.Receipt + if vmResult != nil { + receipt = &types.Receipt{GasUsed: vmResult.UsedGas} + } + wrappedTracer.OnTxEnd(receipt, err) } - - // nolint : contextcheck - vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) - if tracer.OnTxEnd != nil { - tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) + } else { + if hooks.OnTxStart != nil { + hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) } - if writer != nil { - _ = writer.Flush() + vmResult, err = core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) + if hooks.OnTxEnd != nil { + var receipt *types.Receipt + if vmResult != nil { + receipt = &types.Receipt{GasUsed: vmResult.UsedGas} + } + hooks.OnTxEnd(receipt, err) } } - + if writer != nil { + _ = writer.Flush() + } if dump != nil { dump.Close() log.Info("Wrote standard trace", "file", dump.Name()) @@ -1229,58 +999,35 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // containsTx reports whether the transaction with a certain hash // is contained within the specified block. -func (api *API) containsTx(ctx context.Context, block *types.Block, hash common.Hash) bool { - txs, _, stateSyncHash := api.getAllBlockTransactions(ctx, block) - for _, tx := range txs { - if tx.Hash() == hash || stateSyncHash == hash { +func containsTx(block *types.Block, hash common.Hash) bool { + for _, tx := range block.Transactions() { + if tx.Hash() == hash { return true } } - return false } // TraceTransaction returns the structured logs created during the execution of EVM // and returns them as a JSON object. func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { - if config == nil { - config = &TraceConfig{ - BorTraceEnabled: defaultBorTraceEnabled, - BorTx: newBoolPtr(false), - } - } - - if config.BorTraceEnabled == nil { - config.BorTraceEnabled = defaultBorTraceEnabled - } - found, _, blockHash, blockNumber, index := api.backend.GetCanonicalTransaction(hash) if !found { - // For BorTransaction, there will be no trace available - tx, _, _, _ := rawdb.ReadBorTransaction(api.backend.ChainDb(), hash) - if tx != nil { - return &logger.ExecutionResult{ - StructLogs: make([]json.RawMessage, 0), - }, nil - } else { - // Warn in case tx indexer is not done. - if !api.backend.TxIndexDone() { - return nil, ethapi.NewTxIndexingError() - } - // Only mined txes are supported - return nil, errTxNotFound + // Warn in case tx indexer is not done. + if !api.backend.TxIndexDone() { + return nil, ethapi.NewTxIndexingError() } + // Only mined txes are supported + return nil, errTxNotFound } // It shouldn't happen in practice. if blockNumber == 0 { return nil, errors.New("genesis is not traceable") } - reexec := defaultTraceReexec if config != nil && config.Reexec != nil { reexec = *config.Reexec } - block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash) if err != nil { return nil, err @@ -1289,20 +1036,25 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * if err != nil { return nil, err } - defer release() - msg, err := core.TransactionToMessage(tx, types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()), block.BaseFee()) - if err != nil { - return nil, err - } txctx := &Context{ BlockHash: blockHash, BlockNumber: block.Number(), TxIndex: int(index), TxHash: hash, + // This field is only used for bor transactions. Use block gas used as state-sync is + // always the last tx. + CumulativeGasUsed: block.GasUsed(), + LogIndex: len(statedb.Logs()), + } + + msg, err := core.TransactionToMessage(tx, types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()), block.BaseFee()) + if err != nil { + return nil, err } - return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config, nil) + res, _, err := api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config, nil) + return res, err } // TraceCall lets you trace a given eth_call. It collects the structured logs @@ -1405,31 +1157,21 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc if config != nil { traceConfig = &config.TraceConfig } - return api.traceTx(ctx, tx, msg, new(Context), blockContext, statedb, traceConfig, precompiles) + res, _, err := api.traceTx(ctx, tx, msg, new(Context), blockContext, statedb, traceConfig, precompiles) + return res, err } // traceTx configures a new tracer according to the provided configuration, and // executes the given message in the provided environment. The return value will -// be tracer dependent. -func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig, precompiles vm.PrecompiledContracts) (interface{}, error) { - if config == nil { - config = &TraceConfig{ - BorTraceEnabled: defaultBorTraceEnabled, - BorTx: newBoolPtr(false), - } - } - - if config.BorTraceEnabled == nil { - config.BorTraceEnabled = defaultBorTraceEnabled - } - +// be tracer dependent. For state-sync transactions, it only supports transactions +// which are post Madhugiri HF. +func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig, precompiles vm.PrecompiledContracts) (interface{}, uint64, error) { var ( tracer *Tracer err error timeout = defaultTraceTimeout usedGas uint64 ) - if config == nil { config = &TraceConfig{} } @@ -1444,9 +1186,22 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor } else { tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig, api.backend.ChainConfig()) if err != nil { - return nil, err + return nil, 0, err } } + // Wrap the tracer for state-sync transactions (post Madhugiri) to handle multiple + // independent EVM calls within a single transaction. This injects a synthetic root + // call frame so tracers like callTracer (which expect a single root) work correctly. + var ( + isStateSyncTx bool + stateReceiverAddress common.Address + ) + if tx.Type() == types.StateSyncTxType && api.backend.ChainConfig().Bor != nil && api.backend.ChainConfig().Bor.IsMadhugiri(txctx.BlockNumber) { + isStateSyncTx = true + stateReceiverAddress = common.HexToAddress(api.backend.ChainConfig().Bor.StateReceiverContract) + tracer = NewStateSyncTxnTracer(tracer, stateReceiverAddress) + } + tracingStateDB := state.NewHookedState(statedb, tracer.Hooks) evm := vm.NewEVM(vmctx, tracingStateDB, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) if precompiles != nil { @@ -1456,47 +1211,75 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { if timeout, err = time.ParseDuration(*config.Timeout); err != nil { - return nil, err + return nil, 0, err } } - deadlineCtx, cancel := context.WithTimeout(ctx, timeout) - go func() { <-deadlineCtx.Done() - if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) { tracer.Stop(errors.New("execution timeout")) // Stop evm execution. Note cancellation is not necessarily immediate. evm.Cancel() } }() - defer cancel() // Call Prepare to clear out the statedb access list statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) - if config.BorTx == nil { - config.BorTx = newBoolPtr(false) - } - - if *config.BorTx { - callmsg := prepareCallMessage(*message) - // nolint : contextcheck - if _, err := statefull.ApplyBorMessage(evm, callmsg); err != nil { - return nil, fmt.Errorf("tracing failed: %w", err) + // Handle state-sync transactions separately. They're part of block body post Madhugiri + // so we can replay them and gather traces. + if isStateSyncTx { + if tracer.OnTxStart != nil { + tracer.OnTxStart(evm.GetVMContext(), tx, params.BorSystemAddress) } - } else { - // Call Prepare to clear out the statedb access list - statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) - _, err = core.ApplyTransactionWithEVM(message, new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, vmctx.Time, tx, &usedGas, evm) + res, err := statefull.ApplyStateSyncEvents(evm, tx, message, stateReceiverAddress) if err != nil { - return nil, fmt.Errorf("tracing failed: %w", err) + if tracer.OnTxEnd != nil { + tracer.OnTxEnd(nil, err) + } + return nil, 0, fmt.Errorf("tracing failed: %w", err) } + if tracer.OnTxEnd != nil { + // Generate a receipt on the fly for tracing. Use LogIndex and CumulativeGasUsed + // from txctx which are populated by the caller based on prior transactions. + allLogs := tracingStateDB.Logs() + sort.SliceStable(allLogs, func(i, j int) bool { + return allLogs[i].Index < allLogs[j].Index + }) + stateSyncLogs := allLogs[txctx.LogIndex:] + for _, l := range stateSyncLogs { + l.TxIndex = uint(txctx.TxIndex) + } + receipt := &types.Receipt{ + Type: types.StateSyncTxType, + Status: types.ReceiptStatusSuccessful, + // During actual execution, we don't add the state-sync gas in cumulative gas used. To + // keep the same semantics, we skip adding it here as well. For state-sync gas, users + // can refer to the `GasUsed` field in the receipt. + CumulativeGasUsed: txctx.CumulativeGasUsed, + Logs: stateSyncLogs, + GasUsed: res.UsedGas, + TxHash: tx.Hash(), + BlockNumber: txctx.BlockNumber, + BlockHash: txctx.BlockHash, + TransactionIndex: uint(txctx.TxIndex), + } + tracer.OnTxEnd(receipt, nil) + } + + result, err := tracer.GetResult() + return result, res.UsedGas, err } - return tracer.GetResult() + // Handle normal transactions + _, err = core.ApplyTransactionWithEVM(message, new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, vmctx.Time, tx, &usedGas, evm) + if err != nil { + return nil, 0, fmt.Errorf("tracing failed: %w", err) + } + result, err := tracer.GetResult() + return result, usedGas, err } // APIs return the collection of RPC services the tracer package offers. diff --git a/eth/tracers/api_bor.go b/eth/tracers/api_bor.go deleted file mode 100644 index d7542f9831..0000000000 --- a/eth/tracers/api_bor.go +++ /dev/null @@ -1,160 +0,0 @@ -package tracers - -import ( - "context" - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/bor/statefull" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers/logger" - "github.com/ethereum/go-ethereum/internal/ethapi" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" -) - -type BlockTraceResult struct { - // Trace of each transaction executed - Transactions []*TxTraceResult `json:"transactions,omitempty"` - - // Block that we are executing on the trace - Block interface{} `json:"block"` -} - -type TxTraceResult struct { - // Trace results produced by the tracer - Result interface{} `json:"result,omitempty"` - - // Trace failure produced by the tracer - Error string `json:"error,omitempty"` - - // IntermediateHash of the execution if succeeds - IntermediateHash common.Hash `json:"intermediatehash"` -} - -func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *TraceConfig) (*BlockTraceResult, error) { - if block.NumberU64() == 0 { - return nil, fmt.Errorf("genesis is not traceable") - } - - res := &BlockTraceResult{ - Block: block, - } - - // block object cannot be converted to JSON since much of the fields are non-public - blockFields := ethapi.RPCMarshalBlock(block, true, true, api.backend.ChainConfig(), api.backend.ChainDb()) - - res.Block = blockFields - - parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) - if err != nil { - return nil, err - } - - reexec := defaultTraceReexec - if config != nil && config.Reexec != nil { - reexec = *config.Reexec - } - - // TODO: discuss consequences of setting preferDisk false. - statedb, release, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, false) - if err != nil { - return nil, err - } - - defer release() - - // Execute all the transaction contained within the block concurrently - var ( - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) - txs, stateSyncPresent, stateSyncHash = api.getAllBlockTransactions(ctx, block) - deleteEmptyObjects = api.backend.ChainConfig().IsEIP158(block.Number()) - ) - - blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - - traceTxn := func(indx int, tx *types.Transaction, borTx bool, stateSyncHash common.Hash) *TxTraceResult { - message, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) - txHash := tx.Hash() - if borTx { - txHash = stateSyncHash - } - - tracer := logger.NewStructLogger(config.Config) - - // Run the transaction with tracing enabled. - vmenv := vm.NewEVM(blockCtx, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true}) - - // Call Prepare to clear out the statedb access list - // Not sure if we need to do this - statedb.SetTxContext(txHash, indx) - - var execRes *core.ExecutionResult - - if borTx { - callmsg := prepareCallMessage(*message) - execRes, err = statefull.ApplyBorMessage(vmenv, callmsg) - } else { - execRes, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)) - } - - if err != nil { - return &TxTraceResult{ - Error: err.Error(), - } - } - - result := &logger.ExecutionResult{ - Gas: execRes.UsedGas, - Failed: execRes.Failed(), - ReturnValue: execRes.Return(), - StructLogs: tracer.StructLogs(), - } - res := &TxTraceResult{ - Result: result, - IntermediateHash: statedb.IntermediateRoot(deleteEmptyObjects), - } - - return res - } - - for indx, tx := range txs { - if stateSyncPresent && indx == len(txs)-1 { - res.Transactions = append(res.Transactions, traceTxn(indx, tx, true, stateSyncHash)) - } else { - res.Transactions = append(res.Transactions, traceTxn(indx, tx, false, stateSyncHash)) - } - } - - return res, nil -} - -type TraceBlockRequest struct { - Number int64 - Hash string - IsBadBlock bool - Config *TraceConfig -} - -// If you use context as first parameter this function gets exposed automatically on rpc endpoint -func (api *API) TraceBorBlock(req *TraceBlockRequest) (*BlockTraceResult, error) { - ctx := context.Background() - - var blockNumber rpc.BlockNumber - if req.Number == -1 { - blockNumber = rpc.LatestBlockNumber - } else { - blockNumber = rpc.BlockNumber(req.Number) - } - - log.Debug("Tracing Bor Block", "block number", blockNumber) - - block, err := api.blockByNumber(ctx, blockNumber) - if err != nil { - return nil, err - } - - return api.traceBorBlock(ctx, block, req.Config) -} diff --git a/eth/tracers/api_statesync_test.go b/eth/tracers/api_statesync_test.go index 4eac709a34..e9fd86d3e1 100644 --- a/eth/tracers/api_statesync_test.go +++ b/eth/tracers/api_statesync_test.go @@ -2,11 +2,14 @@ package tracers import ( "context" + "encoding/json" + "fmt" "math/big" "testing" "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -14,8 +17,45 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" + "github.com/stretchr/testify/require" ) +var ( + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + + // State receiver address from BorConfig — must match what the tracer reads + stateReceiverAddr = common.HexToAddress("0x0000000000000000000000000000000000001001") + + // Target contract that the state receiver forwards calls to. + // Bytecode: PUSH1(0) PUSH1(0) LOG0 STOP — emits an empty LOG0 on any call. + targetAddr = common.HexToAddress("0x0000000000000000000000000000000000002000") + targetCode = []byte{0x60, 0x00, 0x60, 0x00, 0xa0, 0x00} + + // The state receiver contract bytecode which can be used for processing state sync events. It + // forwards calls via: call(txGas, receiver, 0, add(data, 0x20), mload(data), 0, 0) to the + // child chain contract. + stateReceiverCode = common.FromHex("0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e961047a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610492565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4e6f742053797374656d2041646465737321000000000000000000000000000081525060200191505060405180910390fd5b606061025761025285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610498565b6104c6565b905060006102788260008151811061026b57fe5b60200260200101516105a3565b905080600160005401146102f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006103248360018151811061031757fe5b6020026020010151610614565b905060606103458460028151811061033857fe5b6020026020010151610637565b9050610350826106c3565b1561046f576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103aa57808201518184015260208101905061038f565b50505050905090810190601f1680156103d75780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104a0610943565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606104d1826106dc565b6104da57600080fd5b60006104e58361072a565b905060608160405190808252806020026020018201604052801561052357816020015b61051061095d565b8152602001906001900390816105085790505b5090506000610535856020015161079b565b8560200151019050600080600090505b848110156105965761055683610824565b915060405180604001604052808381526020018481525084828151811061057957fe5b602002602001018190525081830192508080600101915050610545565b5082945050505050919050565b60008082600001511180156105bd57506021826000015111155b6105c657600080fd5b60006105d5836020015161079b565b9050600081846000015103905060008083866020015101905080519150602083101561060857826020036101000a820491505b81945050505050919050565b6000601582600001511461062757600080fd5b610630826105a3565b9050919050565b6060600082600001511161064a57600080fd5b6000610659836020015161079b565b905060008184600001510390506060816040519080825280601f01601f19166020018201604052801561069b5781602001600182028038833980820191505090505b50905060008160200190506106b78487602001510182856108dc565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b600080826000015114156106f35760009050610725565b60008083602001519050805160001a915060c060ff168260ff16101561071e57600092505050610725565b6001925050505b919050565b600080826000015114156107415760009050610796565b60008090506000610755846020015161079b565b84602001510190506000846000015185602001510190505b8082101561078f5761077e82610824565b82019150828060010193505061076d565b8293505050505b919050565b600080825160001a9050608060ff168110156107bb57600091505061081f565b60b860ff168110806107e0575060c060ff1681101580156107df575060f860ff1681105b5b156107ef57600191505061081f565b60c060ff1681101561080f5760018060b80360ff1682030191505061081f565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561084557600191506108d2565b60b860ff16811015610862576001608060ff1682030191506108d1565b60c060ff168110156108925760b78103600185019450806020036101000a855104600182018101935050506108d0565b60f860ff168110156108af57600160c060ff1682030191506108cf565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156108ea5761093e565b5b602060ff16811061091a5782518252602060ff1683019250602060ff1682019150602060ff16810390506108eb565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a7231582083fbdacb76f32b4112d0f7db9a596937925824798a0026ba0232322390b5263764736f6c634300050b0032") +) + +// callTraceLog represents a log entry captured by callTracer with withLog enabled. +type callTraceLog struct { + Address common.Address `json:"address"` + Topics []common.Hash `json:"topics"` + Data hexutil.Bytes `json:"data"` + Position hexutil.Uint `json:"position"` +} + +// callTraceFrame represents a call frame in callTracer output. The struct is recursive: +// each frame can contain sub-calls and logs. +type callTraceFrame struct { + Type string `json:"type"` + From common.Address `json:"from"` + To common.Address `json:"to"` + Calls []callTraceFrame `json:"calls,omitempty"` + Logs []callTraceLog `json:"logs,omitempty"` +} + // borTestBackend extends testBackend with Bor-specific configuration for testing // state sync transaction handling across the Madhugiri hardfork. type borTestBackend struct { @@ -67,7 +107,7 @@ func (b *borTestBackend) BlockByHash(ctx context.Context, hash common.Hash) (*ty } // newBorChainConfig creates a chain config suitable for Bor state sync testing. -func newBorChainConfig(madhugiriBlock *big.Int) *params.ChainConfig { +func newBorChainConfig() *params.ChainConfig { return ¶ms.ChainConfig{ ChainID: big.NewInt(137), HomesteadBlock: big.NewInt(0), @@ -84,105 +124,38 @@ func newBorChainConfig(madhugiriBlock *big.Int) *params.ChainConfig { BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), Bor: ¶ms.BorConfig{ - JaipurBlock: big.NewInt(0), - DelhiBlock: big.NewInt(0), - IndoreBlock: big.NewInt(0), - AhmedabadBlock: big.NewInt(0), - BhilaiBlock: big.NewInt(0), - RioBlock: big.NewInt(0), - MadhugiriBlock: madhugiriBlock, - MadhugiriProBlock: madhugiriBlock, - DandeliBlock: big.NewInt(0), - Period: map[string]uint64{ - "0": 2, - }, - ProducerDelay: map[string]uint64{ - "0": 2, - }, - Sprint: map[string]uint64{ - "0": 16, - }, - BackupMultiplier: map[string]uint64{ - "0": 2, - }, + JaipurBlock: big.NewInt(0), + DelhiBlock: big.NewInt(0), + IndoreBlock: big.NewInt(0), + AhmedabadBlock: big.NewInt(0), + BhilaiBlock: big.NewInt(0), + RioBlock: big.NewInt(0), + MadhugiriBlock: big.NewInt(0), + MadhugiriProBlock: big.NewInt(0), + DandeliBlock: big.NewInt(0), + Period: map[string]uint64{"0": 2}, + ProducerDelay: map[string]uint64{"0": 2}, + Sprint: map[string]uint64{"0": 16}, + BackupMultiplier: map[string]uint64{"0": 2}, ValidatorContract: "0x0000000000000000000000000000000000001000", StateReceiverContract: "0x0000000000000000000000000000000000001001", - BurntContract: map[string]string{ - "0": "0x000000000000000000000000000000000000dead", - }, - Coinbase: map[string]string{ - "0": "0x0000000000000000000000000000000000000000", - }, + BurntContract: map[string]string{"0": "0x000000000000000000000000000000000000dead"}, + Coinbase: map[string]string{"0": "0x0000000000000000000000000000000000000000"}, }, } } -// newBorChainConfigForInsertion creates a chain config with Bor settings but without Madhugiri -// for block insertion. This allows transaction execution (which needs BorConfig for burnt contract) -// while avoiding state-sync validation during insertion. -func newBorChainConfigForInsertion() *params.ChainConfig { - return ¶ms.ChainConfig{ - ChainID: big.NewInt(137), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: big.NewInt(0), - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(0), - MuirGlacierBlock: big.NewInt(0), - BerlinBlock: big.NewInt(0), - LondonBlock: big.NewInt(0), - Bor: ¶ms.BorConfig{ - JaipurBlock: big.NewInt(0), - DelhiBlock: big.NewInt(0), - IndoreBlock: big.NewInt(0), - AhmedabadBlock: big.NewInt(0), - BhilaiBlock: big.NewInt(0), - RioBlock: big.NewInt(0), - MadhugiriBlock: nil, // No Madhugiri - disables state-sync validation - MadhugiriProBlock: nil, - DandeliBlock: big.NewInt(0), - Period: map[string]uint64{ - "0": 2, - }, - ProducerDelay: map[string]uint64{ - "0": 2, - }, - Sprint: map[string]uint64{ - "0": 16, - }, - BackupMultiplier: map[string]uint64{ - "0": 2, - }, - ValidatorContract: "0x0000000000000000000000000000000000001000", - StateReceiverContract: "0x0000000000000000000000000000000000001001", - BurntContract: map[string]string{ - "0": "0x000000000000000000000000000000000000dead", - }, - Coinbase: map[string]string{ - "0": "0x0000000000000000000000000000000000000000", - }, - }, - } -} +// newBorTestBackend creates a test backend with Bor chain config, ethash consensus +// (to avoid Bor-specific validation), and the given number of blocks. +func newBorTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *borTestBackend { + t.Helper() -// newBorTestBackend creates a test backend that: -// 1. Inserts blocks without Bor validation (to avoid state-sync processing issues) -// 2. Exposes a Bor chain config to the tracer API (to test Madhugiri logic) -// 3. Allows manual injection of state-sync txs into block bodies after insertion -func newBorTestBackend(t *testing.T, n int, gspec *core.Genesis, madhugiriBlock *big.Int, generator func(i int, b *core.BlockGen)) *borTestBackend { - // Use config without Bor for block insertion - insertionConfig := newBorChainConfigForInsertion() - gspec.Config = insertionConfig + borCfg := newBorChainConfig() + gspec.Config = borCfg backend := &borTestBackend{ testBackend: testBackend{ - // Use Bor config for API queries (this is what the tracer API sees) - chainConfig: newBorChainConfig(madhugiriBlock), + chainConfig: borCfg, engine: ethash.NewFaker(), chaindb: rawdb.NewMemoryDatabase(), }, @@ -190,20 +163,15 @@ func newBorTestBackend(t *testing.T, n int, gspec *core.Genesis, madhugiriBlock modifiedHashes: make(map[common.Hash]uint64), } - // Generate blocks with insertion config (no Bor) _, blocks, _ := core.GenerateChainWithGenesis(gspec, backend.engine, n, generator) - // Import the canonical chain - options := &core.BlockChainConfig{ + chain, err := core.NewBlockChain(backend.chaindb, gspec, backend.engine, &core.BlockChainConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, ArchiveMode: true, - } - - // Create chain with insertion config (no Bor validation) - chain, err := core.NewBlockChain(backend.chaindb, gspec, backend.engine, options) + }) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -226,154 +194,50 @@ func (b *borTestBackend) injectStateSyncTx(blockNum uint64, stateSyncTx *types.T return nil } - // Read existing body and append state-sync tx existingBody := block.Body() newTxs := make([]*types.Transaction, len(existingBody.Transactions)+1) copy(newTxs, existingBody.Transactions) newTxs[len(newTxs)-1] = stateSyncTx - newBody := &types.Body{ + rawdb.WriteBody(b.chaindb, block.Hash(), blockNum, &types.Body{ Transactions: newTxs, Uncles: existingBody.Uncles, Withdrawals: existingBody.Withdrawals, - } - - // Write modified body back to database - rawdb.WriteBody(b.chaindb, block.Hash(), blockNum, newBody) + }) - // Track this block as modified so BlockByNumber/BlockByHash reads from DB b.modifiedBlocks[blockNum] = true b.modifiedHashes[block.Hash()] = blockNum return nil } -// createStateSyncTx creates a state sync transaction for testing. -func createStateSyncTx(id uint64) *types.Transaction { - return types.NewTx(&types.StateSyncTx{ - StateSyncData: []*types.StateSyncData{ - { - ID: id, - Contract: common.HexToAddress("0x0000000000000000000000000000000000001001"), - Data: []byte{0x01, 0x02, 0x03}, - TxHash: common.HexToHash("0x0000dead"), - }, - }, - }) -} - -// TestTraceBlockStateSyncPostMadhugiri verifies that post-Madhugiri blocks -// include state sync transactions in trace results regardless of BorTraceEnabled. -// This is the core fix for the tx count mismatch bug (PIP-74). -func TestTraceBlockStateSyncPostMadhugiri(t *testing.T) { - t.Parallel() - - var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - gspec = &core.Genesis{ - Alloc: types.GenesisAlloc{ - address: {Balance: big.NewInt(params.Ether)}, - }, - } - ) - - // Madhugiri at block 5 - test block 10 which is post-fork - madhugiriBlock := big.NewInt(5) - genBlocks := 10 - - backend := newBorTestBackend(t, genBlocks, gspec, madhugiriBlock, func(i int, b *core.BlockGen) { - tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ - Nonce: uint64(i), - To: &address, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasPrice: new(big.Int).Mul(b.BaseFee(), big.NewInt(2)), - }), b.Signer(), key) - b.AddTx(tx) - }) - defer backend.chain.Stop() - - // Inject state-sync tx into post-Madhugiri blocks (block 6+) - for i := uint64(6); i <= 10; i++ { - stateSyncTx := createStateSyncTx(i) - if err := backend.injectStateSyncTx(i, stateSyncTx); err != nil { - t.Fatalf("failed to inject state-sync tx: %v", err) +// newStateSyncEvents creates numEvents state-sync events targeting targetAddr. +func newStateSyncEvents(numEvents int) []*types.StateSyncData { + events := make([]*types.StateSyncData, numEvents) + for i := range events { + events[i] = &types.StateSyncData{ + ID: uint64(i + 1), + Contract: targetAddr, + Data: []byte(fmt.Sprintf("event-%d", i+1)), + TxHash: common.BigToHash(big.NewInt(int64(0xaaa0 + i + 1))), } } - - api := NewAPI(backend) - - // Test post-Madhugiri block (block 10) with BorTraceEnabled=false (default) - t.Run("PostMadhugiri_BorTraceDisabled", func(t *testing.T) { - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(10)) - if block == nil { - t.Fatal("block 10 not found") - } - - expectedTxCount := len(block.Transactions()) - if expectedTxCount != 2 { - t.Fatalf("expected 2 txs in block (1 regular + 1 state sync), got %d", expectedTxCount) - } - - // Verify last tx is state sync - lastTx := block.Transactions()[expectedTxCount-1] - if lastTx.Type() != types.StateSyncTxType { - t.Fatalf("expected last tx to be StateSyncTxType, got %d", lastTx.Type()) - } - - // Trace with default config (BorTraceEnabled=false) - results, err := api.TraceBlockByNumber(context.Background(), rpc.BlockNumber(10), nil) - if err != nil { - t.Fatalf("TraceBlockByNumber failed: %v", err) - } - - // Post-Madhugiri: trace count MUST match block tx count - if len(results) != expectedTxCount { - t.Errorf("tx count mismatch: block has %d txs, trace returned %d results (expected match post-Madhugiri)", - expectedTxCount, len(results)) - } - }) - - // Test post-Madhugiri block with BorTraceEnabled=true - t.Run("PostMadhugiri_BorTraceEnabled", func(t *testing.T) { - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(10)) - expectedTxCount := len(block.Transactions()) - - borTraceEnabled := true - config := &TraceConfig{BorTraceEnabled: &borTraceEnabled} - - results, err := api.TraceBlockByNumber(context.Background(), rpc.BlockNumber(10), config) - if err != nil { - t.Fatalf("TraceBlockByNumber failed: %v", err) - } - - if len(results) != expectedTxCount { - t.Errorf("tx count mismatch with BorTraceEnabled=true: block has %d txs, trace returned %d results", - expectedTxCount, len(results)) - } - }) + return events } -// TestTraceBlockStateSyncPreMadhugiri verifies legacy behavior is preserved -// for pre-Madhugiri blocks where state sync was not canonical. -func TestTraceBlockStateSyncPreMadhugiri(t *testing.T) { - t.Parallel() +// newStateSyncTestSetup creates a common test setup: a chain of numBlocks blocks (each with +// one normal tx), a state-sync tx with numEvents events injected into block 2, and the API. +func newStateSyncTestSetup(t *testing.T, numBlocks, numEvents int) (*borTestBackend, *API, uint64) { + t.Helper() - var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - gspec = &core.Genesis{ - Alloc: types.GenesisAlloc{ - address: {Balance: big.NewInt(params.Ether)}, - }, - } - ) - - // Madhugiri at block 100 - all test blocks are pre-fork - madhugiriBlock := big.NewInt(100) - genBlocks := 10 + gspec := &core.Genesis{ + Alloc: types.GenesisAlloc{ + address: {Balance: big.NewInt(params.Ether)}, + stateReceiverAddr: {Code: stateReceiverCode, Balance: big.NewInt(0)}, + targetAddr: {Code: targetCode, Balance: big.NewInt(0)}, + }, + } - backend := newBorTestBackend(t, genBlocks, gspec, madhugiriBlock, func(i int, b *core.BlockGen) { + backend := newBorTestBackend(t, numBlocks, gspec, func(i int, b *core.BlockGen) { tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ Nonce: uint64(i), To: &address, @@ -383,568 +247,213 @@ func TestTraceBlockStateSyncPreMadhugiri(t *testing.T) { }), b.Signer(), key) b.AddTx(tx) }) - defer backend.chain.Stop() - - api := NewAPI(backend) - - // Pre-Madhugiri block without state sync tx in body - t.Run("PreMadhugiri_NoStateSyncInBody", func(t *testing.T) { - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(5)) - if block == nil { - t.Fatal("block 5 not found") - } - - blockTxCount := len(block.Transactions()) - if blockTxCount != 1 { - t.Fatalf("expected 1 tx in pre-Madhugiri block, got %d", blockTxCount) - } - - results, err := api.TraceBlockByNumber(context.Background(), rpc.BlockNumber(5), nil) - if err != nil { - t.Fatalf("TraceBlockByNumber failed: %v", err) - } - - // Pre-Madhugiri without state sync: trace count should match block body - if len(results) != blockTxCount { - t.Errorf("expected %d trace results, got %d", blockTxCount, len(results)) - } - }) -} -// TestTraceBlockMadhugiriForkBoundary tests edge cases at the exact fork boundary. -func TestTraceBlockMadhugiriForkBoundary(t *testing.T) { - t.Parallel() - - var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - gspec = &core.Genesis{ - Alloc: types.GenesisAlloc{ - address: {Balance: big.NewInt(params.Ether)}, - }, - } - ) - - // Madhugiri at block 5 - madhugiriBlock := big.NewInt(5) - genBlocks := 10 - - backend := newBorTestBackend(t, genBlocks, gspec, madhugiriBlock, func(i int, b *core.BlockGen) { - tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ - Nonce: uint64(i), - To: &address, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasPrice: new(big.Int).Mul(b.BaseFee(), big.NewInt(2)), - }), b.Signer(), key) - b.AddTx(tx) + stateSyncTx := types.NewTx(&types.StateSyncTx{ + StateSyncData: newStateSyncEvents(numEvents), }) - defer backend.chain.Stop() - // Inject state-sync tx starting at Madhugiri block (block 5+) - for i := uint64(5); i <= 10; i++ { - stateSyncTx := createStateSyncTx(i) - if err := backend.injectStateSyncTx(i, stateSyncTx); err != nil { - t.Fatalf("failed to inject state-sync tx: %v", err) - } - } + stateSyncBlock := uint64(2) + err := backend.injectStateSyncTx(stateSyncBlock, stateSyncTx) + require.NoError(t, err, "failed to inject state-sync tx") api := NewAPI(backend) - - // Test block just before Madhugiri (block 4) - t.Run("BlockBeforeFork", func(t *testing.T) { - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(4)) - if block == nil { - t.Fatal("block 4 not found") - } - - blockTxCount := len(block.Transactions()) - results, err := api.TraceBlockByNumber(context.Background(), rpc.BlockNumber(4), nil) - if err != nil { - t.Fatalf("TraceBlockByNumber failed: %v", err) - } - - // Block 4 is pre-Madhugiri, no state sync in body - if len(results) != blockTxCount { - t.Errorf("block 4 (pre-fork): expected %d results, got %d", blockTxCount, len(results)) - } - }) - - // Test exact Madhugiri fork block (block 5) - t.Run("ExactForkBlock", func(t *testing.T) { - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(5)) - if block == nil { - t.Fatal("block 5 not found") - } - - blockTxCount := len(block.Transactions()) - results, err := api.TraceBlockByNumber(context.Background(), rpc.BlockNumber(5), nil) - if err != nil { - t.Fatalf("TraceBlockByNumber failed: %v", err) - } - - // Block 5 is Madhugiri block - state sync should be included - if len(results) != blockTxCount { - t.Errorf("block 5 (fork block): expected %d results, got %d", blockTxCount, len(results)) - } - }) - - // Test block just after Madhugiri (block 6) - t.Run("BlockAfterFork", func(t *testing.T) { - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(6)) - if block == nil { - t.Fatal("block 6 not found") - } - - blockTxCount := len(block.Transactions()) - results, err := api.TraceBlockByNumber(context.Background(), rpc.BlockNumber(6), nil) - if err != nil { - t.Fatalf("TraceBlockByNumber failed: %v", err) - } - - // Block 6 is post-Madhugiri - state sync should be included - if len(results) != blockTxCount { - t.Errorf("block 6 (post-fork): expected %d results, got %d", blockTxCount, len(results)) - } - }) + return backend, api, stateSyncBlock } -// TestTraceBlockByHashStateSyncPostMadhugiri tests TraceBlockByHash endpoint. -func TestTraceBlockByHashStateSyncPostMadhugiri(t *testing.T) { - t.Parallel() - - var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - gspec = &core.Genesis{ - Alloc: types.GenesisAlloc{ - address: {Balance: big.NewInt(params.Ether)}, - }, - } - ) - - madhugiriBlock := big.NewInt(5) - genBlocks := 10 - - backend := newBorTestBackend(t, genBlocks, gspec, madhugiriBlock, func(i int, b *core.BlockGen) { - tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ - Nonce: uint64(i), - To: &address, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasPrice: new(big.Int).Mul(b.BaseFee(), big.NewInt(2)), - }), b.Signer(), key) - b.AddTx(tx) - }) - defer backend.chain.Stop() - - // Inject state-sync tx into post-Madhugiri blocks - for i := uint64(6); i <= 10; i++ { - stateSyncTx := createStateSyncTx(i) - if err := backend.injectStateSyncTx(i, stateSyncTx); err != nil { - t.Fatalf("failed to inject state-sync tx: %v", err) - } - } - - api := NewAPI(backend) - - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(10)) - if block == nil { - t.Fatal("block 10 not found") - } - - expectedTxCount := len(block.Transactions()) - - results, err := api.TraceBlockByHash(context.Background(), block.Hash(), nil) - if err != nil { - t.Fatalf("TraceBlockByHash failed: %v", err) - } - - if len(results) != expectedTxCount { - t.Errorf("TraceBlockByHash: tx count mismatch: block has %d txs, trace returned %d results", - expectedTxCount, len(results)) - } +// callTracerConfig returns a TraceConfig that uses callTracer with log collection enabled. +func callTracerConfig() *TraceConfig { + name := "callTracer" + cfg := json.RawMessage(`{"withLog": true}`) + return &TraceConfig{Tracer: &name, TracerConfig: cfg} } -// TestTraceChainStateSyncPostMadhugiri tests traceChain across fork boundary. -func TestTraceChainStateSyncPostMadhugiri(t *testing.T) { - t.Parallel() - - var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - gspec = &core.Genesis{ - Alloc: types.GenesisAlloc{ - address: {Balance: big.NewInt(params.Ether)}, - }, - } - ) - - madhugiriBlock := big.NewInt(5) - genBlocks := 10 - - backend := newBorTestBackend(t, genBlocks, gspec, madhugiriBlock, func(i int, b *core.BlockGen) { - tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ - Nonce: uint64(i), - To: &address, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasPrice: new(big.Int).Mul(b.BaseFee(), big.NewInt(2)), - }), b.Signer(), key) - b.AddTx(tx) - }) - defer backend.chain.Stop() - - // Inject state-sync tx into post-Madhugiri blocks - for i := uint64(5); i <= 10; i++ { - stateSyncTx := createStateSyncTx(i) - if err := backend.injectStateSyncTx(i, stateSyncTx); err != nil { - t.Fatalf("failed to inject state-sync tx: %v", err) - } - } - - api := NewAPI(backend) - - // Use internal traceChain method (like existing tests do) - from, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(4)) - to, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(7)) - resCh := api.traceChain(from, to, nil, nil) - - // Verify trace count for each block - nextBlock := uint64(5) // traceChain starts from start+1 - for result := range resCh { - blockNum := uint64(result.Block) - if blockNum != nextBlock { - t.Errorf("unexpected block number: got %d, want %d", blockNum, nextBlock) - } - - // Get expected tx count from actual block - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(blockNum)) - if block == nil { - t.Errorf("block %d not found", blockNum) - nextBlock++ - continue - } - - expectedTxCount := len(block.Transactions()) - if len(result.Traces) != expectedTxCount { - t.Errorf("block %d: trace count mismatch: expected %d, got %d", - blockNum, expectedTxCount, len(result.Traces)) - } - - nextBlock++ - } - - // Verify we processed all expected blocks - if nextBlock != 8 { // Should have processed blocks 5, 6, 7 - t.Errorf("did not process all blocks: stopped at %d", nextBlock) +// validateStateSyncCallTrace unmarshals a callTracer result and validates the full trace +// structure for a state-sync transaction with expectedEvents bridge events. +func validateStateSyncCallTrace(t *testing.T, raw json.RawMessage, expectedEvents int) { + t.Helper() + + var trace callTraceFrame + require.NoError(t, json.Unmarshal(raw, &trace), "failed to unmarshal call trace") + + // Synthetic root frame: CALL from BorSystemAddress to StateReceiverContract. + require.Equal(t, "CALL", trace.Type, "invalid root frame type (expected CALL)") + require.Equal(t, params.BorSystemAddress, trace.From, "invalid root frame from (expected BorSystemAddress)") + require.Equal(t, stateReceiverAddr, trace.To, "invalid root frame to (expected StateReceiverContract)") + + // One sub-call per state-sync event (each is a commitState call). + require.Equal(t, expectedEvents, len(trace.Calls), + "expected %d sub-calls (one per state-sync event), got %d", expectedEvents, len(trace.Calls)) + + for i, call := range trace.Calls { + // Each commitState: CALL from BorSystemAddress to StateReceiverContract. + require.Equal(t, "CALL", call.Type, "invalid sub-call[%d] type (expected CALL)", i) + require.Equal(t, params.BorSystemAddress, call.From, "invalid sub-call[%d] from (expected BorSystemAddress)", i) + require.Equal(t, stateReceiverAddr, call.To, "invalid sub-call[%d] to (expected StateReceiverContract)", i) + + // Inside commitState, StateReceiver forwards to targetAddr via low-level call. + // Find the nested call to targetAddr and validate it emitted LOG0. + target := findCallTo(call.Calls, targetAddr) + require.NotNil(t, target, "sub-call[%d]: expected nested call to target %s", i, targetAddr) + require.NotEmpty(t, target.Logs, "sub-call[%d]: target call should have logs", i) + require.Equal(t, targetAddr, target.Logs[0].Address, "sub-call[%d]: log address", i) + require.Empty(t, target.Logs[0].Topics, "sub-call[%d]: log should have no topics (LOG0)", i) + require.Empty(t, target.Logs[0].Data, "sub-call[%d]: log should have empty data", i) } } -// TestIntermediateRootsStateSyncPostMadhugiri tests IntermediateRoots endpoint. -func TestIntermediateRootsStateSyncPostMadhugiri(t *testing.T) { - t.Parallel() - - var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - gspec = &core.Genesis{ - Alloc: types.GenesisAlloc{ - address: {Balance: big.NewInt(params.Ether)}, - }, +// findCallTo recursively searches call frames for a CALL to the given address. +func findCallTo(calls []callTraceFrame, addr common.Address) *callTraceFrame { + for i, call := range calls { + if call.To == addr { + return &calls[i] } - ) - - madhugiriBlock := big.NewInt(5) - genBlocks := 10 - - backend := newBorTestBackend(t, genBlocks, gspec, madhugiriBlock, func(i int, b *core.BlockGen) { - tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ - Nonce: uint64(i), - To: &address, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasPrice: new(big.Int).Mul(b.BaseFee(), big.NewInt(2)), - }), b.Signer(), key) - b.AddTx(tx) - }) - defer backend.chain.Stop() - - // Inject state-sync tx into post-Madhugiri blocks - for i := uint64(6); i <= 10; i++ { - stateSyncTx := createStateSyncTx(i) - if err := backend.injectStateSyncTx(i, stateSyncTx); err != nil { - t.Fatalf("failed to inject state-sync tx: %v", err) + if found := findCallTo(call.Calls, addr); found != nil { + return found } } - - api := NewAPI(backend) - - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(10)) - if block == nil { - t.Fatal("block 10 not found") - } - - expectedTxCount := len(block.Transactions()) - - roots, err := api.IntermediateRoots(context.Background(), block.Hash(), nil) - if err != nil { - t.Fatalf("IntermediateRoots failed: %v", err) - } - - // Each tx should produce an intermediate root - if len(roots) != expectedTxCount { - t.Errorf("IntermediateRoots: expected %d roots (one per tx), got %d", - expectedTxCount, len(roots)) - } + return nil } -// TestStateSyncTxTypeDetection verifies correct detection of state sync tx type. -func TestStateSyncTxTypeDetection(t *testing.T) { +// TestTraceBlockByNumber_WithStateSyncTx tests end-to-end state-sync tracing using the actual +// StateReceiver contract bytecode and mirrors what happens in actual networks. During the test +// we do the following things: +// +// 1. Deploy StateReceiver at 0x1001 with mainnet bytecode (which has `stateReceive` method). +// 2. A simple "target" contract is deployed at a separate address — it just emits LOG0 on any call. +// 3. A StateSyncTx carries bridge events whose Contract field points to the target is injected. +// 4. callTracer with logs is used to generate a trace in which the bridge events are executed inside +// EVM calling the StateReceiver contract. +// 5. Verify if the output trace matches the expected output of call trace. While tracing state-sync +// transactions, a synthetic root call frame is injected under which all bridge events are +// executed as sub-calls. This is needed to satisfy callTracer's invariant of having a single +// root frame per transaction. +func TestTraceBlockByNumber_WithStateSyncTx(t *testing.T) { t.Parallel() - stateSyncTx := createStateSyncTx(1) - - if stateSyncTx.Type() != types.StateSyncTxType { - t.Errorf("expected tx type %d (StateSyncTxType), got %d", - types.StateSyncTxType, stateSyncTx.Type()) + tests := []struct { + name string + numEvents int + }{ + {"single event", 1}, + {"multiple events", 3}, } - // Verify properties of state sync tx - if stateSyncTx.Gas() != 0 { - t.Errorf("state sync tx should have 0 gas, got %d", stateSyncTx.Gas()) - } - if stateSyncTx.GasPrice().Cmp(big.NewInt(0)) != 0 { - t.Errorf("state sync tx should have 0 gas price") - } - if stateSyncTx.Value().Cmp(big.NewInt(0)) != 0 { - t.Errorf("state sync tx should have 0 value") - } -} - -// TestNoMadhugiriFork tests behavior when Madhugiri fork is not configured. -func TestNoMadhugiriFork(t *testing.T) { - t.Parallel() + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() - var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - gspec = &core.Genesis{ - Alloc: types.GenesisAlloc{ - address: {Balance: big.NewInt(params.Ether)}, - }, - } - ) + backend, api, stateSyncBlock := newStateSyncTestSetup(t, 3, tt.numEvents) + defer backend.chain.Stop() - // nil = no Madhugiri fork - genBlocks := 10 + block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(stateSyncBlock)) + require.NotNil(t, block) + txs := block.Transactions() + require.Equal(t, 2, len(txs), "expected 2 transactions (1 normal + 1 state-sync)") - backend := newBorTestBackend(t, genBlocks, gspec, nil, func(i int, b *core.BlockGen) { - tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ - Nonce: uint64(i), - To: &address, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasPrice: new(big.Int).Mul(b.BaseFee(), big.NewInt(2)), - }), b.Signer(), key) - b.AddTx(tx) - }) - defer backend.chain.Stop() - - api := NewAPI(backend) - - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(5)) - if block == nil { - t.Fatal("block 5 not found") - } - - results, err := api.TraceBlockByNumber(context.Background(), rpc.BlockNumber(5), nil) - if err != nil { - t.Fatalf("TraceBlockByNumber failed: %v", err) - } + results, err := api.TraceBlockByNumber(context.Background(), rpc.BlockNumber(stateSyncBlock), callTracerConfig()) + require.NoError(t, err) + require.Equal(t, len(txs), len(results)) + for i, result := range results { + require.Empty(t, result.Error, "trace result[%d] error", i) + require.Equal(t, txs[i].Hash(), result.TxHash, "trace result[%d] tx hash", i) + } - // Without Madhugiri fork, trace count should match block body - expectedCount := len(block.Transactions()) - if len(results) != expectedCount { - t.Errorf("without Madhugiri fork: expected %d results, got %d", expectedCount, len(results)) + raw, ok := results[1].Result.(json.RawMessage) + require.True(t, ok, "expected json.RawMessage, got %T", results[1].Result) + validateStateSyncCallTrace(t, raw, tt.numEvents) + }) } } -// TestMadhugiriAtGenesis tests edge case where Madhugiri is active from genesis. -func TestMadhugiriAtGenesis(t *testing.T) { +// TestTraceBlockByHash_WithStateSyncTx tests end-to-end state-sync tracing using the actual +// StateReceiver contract bytecode and mirrors what happens in actual networks. Follows same +// steps as trace by block. +func TestTraceBlockByHash_WithStateSyncTx(t *testing.T) { t.Parallel() - var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - gspec = &core.Genesis{ - Alloc: types.GenesisAlloc{ - address: {Balance: big.NewInt(params.Ether)}, - }, - } - ) - - // Madhugiri at block 0 = active from genesis - madhugiriBlock := big.NewInt(0) - genBlocks := 5 - - backend := newBorTestBackend(t, genBlocks, gspec, madhugiriBlock, func(i int, b *core.BlockGen) { - // Use dynamic fee tx with proper fee caps - baseFee := b.BaseFee() - tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{ - Nonce: uint64(i), - To: &address, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasFeeCap: new(big.Int).Mul(baseFee, big.NewInt(2)), - GasTipCap: big.NewInt(1), - }), b.Signer(), key) - b.AddTx(tx) - }) + numOfStateSyncEvents := 2 + backend, api, stateSyncBlock := newStateSyncTestSetup(t, 3, numOfStateSyncEvents) defer backend.chain.Stop() - // Inject state-sync tx into all blocks (Madhugiri active from genesis) - for i := uint64(1); i <= 5; i++ { - stateSyncTx := createStateSyncTx(i) - if err := backend.injectStateSyncTx(i, stateSyncTx); err != nil { - t.Fatalf("failed to inject state-sync tx: %v", err) - } - } - - api := NewAPI(backend) + block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(stateSyncBlock)) + require.NotNil(t, block) + txs := block.Transactions() + require.Equal(t, 2, len(txs)) - // Test block 1 (all blocks are post-Madhugiri) - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(1)) - if block == nil { - t.Fatal("block 1 not found") + results, err := api.TraceBlockByHash(context.Background(), block.Hash(), callTracerConfig()) + require.NoError(t, err) + require.Equal(t, len(txs), len(results)) + for i, result := range results { + require.Empty(t, result.Error, "trace result[%d] error", i) + require.Equal(t, txs[i].Hash(), result.TxHash, "trace result[%d] tx hash", i) } - expectedTxCount := len(block.Transactions()) - if expectedTxCount != 2 { - t.Fatalf("expected 2 txs, got %d", expectedTxCount) - } - - results, err := api.TraceBlockByNumber(context.Background(), rpc.BlockNumber(1), nil) - if err != nil { - t.Fatalf("TraceBlockByNumber failed: %v", err) - } - - if len(results) != expectedTxCount { - t.Errorf("Madhugiri from genesis: expected %d results, got %d", expectedTxCount, len(results)) - } + raw, ok := results[1].Result.(json.RawMessage) + require.True(t, ok, "expected json.RawMessage, got %T", results[1].Result) + validateStateSyncCallTrace(t, raw, numOfStateSyncEvents) } -// TestMultipleStateSyncEvents tests blocks with multiple state sync events bundled. -func TestMultipleStateSyncEvents(t *testing.T) { +// TestTraceBlockByHash_WithStateSyncTx tests end-to-end state-sync tracing using the actual +// StateReceiver contract bytecode and mirrors what happens in actual networks. Follows same +// steps as trace by block but for a range of blocks. +func TestTraceChain_WithStateSyncTx(t *testing.T) { t.Parallel() - var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - gspec = &core.Genesis{ - Alloc: types.GenesisAlloc{ - address: {Balance: big.NewInt(params.Ether)}, - }, - } - ) - - madhugiriBlock := big.NewInt(0) - genBlocks := 5 - - backend := newBorTestBackend(t, genBlocks, gspec, madhugiriBlock, func(i int, b *core.BlockGen) { - tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ - Nonce: uint64(i), - To: &address, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasPrice: new(big.Int).Mul(b.BaseFee(), big.NewInt(2)), - }), b.Signer(), key) - b.AddTx(tx) - }) + numOfStateSyncEvents := 2 + backend, api, stateSyncBlock := newStateSyncTestSetup(t, 3, numOfStateSyncEvents) defer backend.chain.Stop() - // Inject state-sync tx with multiple events into block 3 - stateSyncTx := types.NewTx(&types.StateSyncTx{ - StateSyncData: []*types.StateSyncData{ - {ID: 31, Contract: common.HexToAddress("0x1001"), Data: []byte{0x01}}, - {ID: 32, Contract: common.HexToAddress("0x1001"), Data: []byte{0x02}}, - {ID: 33, Contract: common.HexToAddress("0x1001"), Data: []byte{0x03}}, - }, - }) - if err := backend.injectStateSyncTx(3, stateSyncTx); err != nil { - t.Fatalf("failed to inject state-sync tx: %v", err) - } + from, err := backend.BlockByNumber(context.Background(), rpc.BlockNumber(0)) + require.NoError(t, err) + to, err := backend.BlockByNumber(context.Background(), rpc.BlockNumber(3)) + require.NoError(t, err) - api := NewAPI(backend) + // traceChain traces the range (from, to] — excludes start, includes end. + results := api.traceChain(from, to, callTracerConfig(), nil) + require.NotNil(t, results) - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(3)) - if block == nil { - t.Fatal("block 3 not found") - } + for res := range results { + block, err := backend.BlockByNumber(context.Background(), rpc.BlockNumber(uint64(res.Block))) + require.NoError(t, err) + txs := block.Transactions() + require.Equal(t, len(txs), len(res.Traces), "block %d trace count", res.Block) - // Should have 2 txs: 1 regular + 1 state sync (with 3 events bundled) - expectedTxCount := len(block.Transactions()) - if expectedTxCount != 2 { - t.Fatalf("expected 2 txs, got %d", expectedTxCount) - } - - results, err := api.TraceBlockByNumber(context.Background(), rpc.BlockNumber(3), nil) - if err != nil { - t.Fatalf("TraceBlockByNumber failed: %v", err) - } + for i, result := range res.Traces { + require.Empty(t, result.Error, "block %d trace[%d] error", res.Block, i) + require.Equal(t, txs[i].Hash(), result.TxHash, "block %d trace[%d] tx hash", res.Block, i) + } - // Multiple events in one state sync tx = still 1 tx in trace results - if len(results) != expectedTxCount { - t.Errorf("multiple state sync events: expected %d results, got %d", expectedTxCount, len(results)) + if res.Block == hexutil.Uint64(stateSyncBlock) { + raw, ok := res.Traces[1].Result.(json.RawMessage) + require.True(t, ok, "expected json.RawMessage, got %T", res.Traces[1].Result) + validateStateSyncCallTrace(t, raw, numOfStateSyncEvents) + } } } -// TestEmptyBlockWithStateSyncOnly tests blocks containing only state sync tx. -func TestEmptyBlockWithStateSyncOnly(t *testing.T) { +// TestIntermediateRoots_WithStateSyncTx verifies that intermediate state roots are correctly +// computed for blocks containing state-sync transactions. This test doesn't use a tracer. It +// validates execution correctness rather than trace output. +func TestIntermediateRoots_WithStateSyncTx(t *testing.T) { t.Parallel() - var ( - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - gspec = &core.Genesis{ - Alloc: types.GenesisAlloc{ - crypto.PubkeyToAddress(key.PublicKey): {Balance: big.NewInt(params.Ether)}, - }, - } - ) - - madhugiriBlock := big.NewInt(0) - genBlocks := 5 - - // Generate empty blocks (no regular txs) - backend := newBorTestBackend(t, genBlocks, gspec, madhugiriBlock, func(i int, b *core.BlockGen) { - // No transactions added - }) + backend, api, stateSyncBlock := newStateSyncTestSetup(t, 3, 2) defer backend.chain.Stop() - // Inject state-sync tx into block 3 (which is otherwise empty) - stateSyncTx := createStateSyncTx(3) - if err := backend.injectStateSyncTx(3, stateSyncTx); err != nil { - t.Fatalf("failed to inject state-sync tx: %v", err) - } - - api := NewAPI(backend) + block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(stateSyncBlock)) + require.NotNil(t, block) + txs := block.Transactions() + require.Equal(t, 2, len(txs)) - block, _ := backend.BlockByNumber(context.Background(), rpc.BlockNumber(3)) - if block == nil { - t.Fatal("block 3 not found") - } + results, err := api.IntermediateRoots(context.Background(), block.Hash(), nil) + require.NoError(t, err) + require.Equal(t, 2, len(results), "expected 2 intermediate roots (one per tx)") - expectedTxCount := len(block.Transactions()) - if expectedTxCount != 1 { - t.Fatalf("expected 1 tx (state-sync only), got %d", expectedTxCount) + expectedStateRoots := []common.Hash{ + common.HexToHash("0x23eda0b1dbe747a8daedaf94b811a393de400047812394476dac190a5e9a8fd4"), + common.HexToHash("0x1b5bcf33b31f2d38b498594a348bc176b9e05b46cba3ed3701ba739c012bc757"), } - - results, err := api.TraceBlockByNumber(context.Background(), rpc.BlockNumber(3), nil) - if err != nil { - t.Fatalf("TraceBlockByNumber failed: %v", err) - } - - if len(results) != expectedTxCount { - t.Errorf("block with only state sync: expected %d results, got %d", expectedTxCount, len(results)) + for i, result := range results { + require.Equal(t, expectedStateRoots[i], result, "state root mismatch at index %d", i) } } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 21060124d8..aac650ae24 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -706,100 +706,6 @@ func TestTraceBlock(t *testing.T) { } } -// txTraceResult is the result of a single transaction trace. -type txTraceResultTest struct { - Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer - Error string `json:"error,omitempty"` // Trace failure produced by the tracer -} - -func TestIOdump(t *testing.T) { - t.Parallel() - - // Initialize test accounts - accounts := newAccounts(5) - genesis := &core.Genesis{Alloc: types.GenesisAlloc{ - accounts[0].addr: {Balance: big.NewInt(params.Ether)}, - accounts[1].addr: {Balance: big.NewInt(params.Ether)}, - accounts[2].addr: {Balance: big.NewInt(params.Ether)}, - accounts[3].addr: {Balance: big.NewInt(params.Ether)}, - accounts[4].addr: {Balance: big.NewInt(params.Ether)}, - }} - genBlocks := 1 - signer := types.HomesteadSigner{} - api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { - // Transfer from account[0] to account[1], account[1] to account[2], account[2] to account[3], account[3] to account[4], account[4] to account[0] - // value: 1000 wei - // fee: 0 wei - for j := 0; j < 5; j++ { - tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[(j+1)%5].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[j].key) - b.AddTx(tx) - } - })) - - allowIOTracing = true - - ioflag := new(bool) - - *ioflag = true - - var testSuite = []struct { - blockNumber rpc.BlockNumber - config *TraceConfig - want string - expectErr error - }{ - // Trace head block - { - config: &TraceConfig{ - IOFlag: ioflag, - }, - blockNumber: rpc.BlockNumber(genBlocks), - want: `[{"result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}},{"result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}},{"result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}},{"result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}},{"result":{"gas":21000,"failed":false,"returnValue":"0x","structLogs":[]}}]`, - }, - } - - for i, tc := range testSuite { - result, err := api.TraceBlockByNumber(t.Context(), tc.blockNumber, tc.config) - if tc.expectErr != nil { - if err == nil { - t.Errorf("test %d, want error %v", i, tc.expectErr) - continue - } - - if !reflect.DeepEqual(err, tc.expectErr) { - t.Errorf("test %d: error mismatch, want %v, get %v", i, tc.expectErr, err) - } - - continue - } - - // Done As txTraceResult struct was changed during Cancun changes - resArr := make([]*txTraceResultTest, 0) - for _, res := range result { - res := &txTraceResultTest{ - Result: res.Result, - Error: res.Error, - } - resArr = append(resArr, res) - } - - if err != nil { - t.Errorf("test %d, want no error, have %v", i, err) - continue - } - - have, err := json.Marshal(resArr) - if err != nil { - t.Errorf("Error in Marshal: %v", err) - } - - want := tc.want - if string(have) != want { - t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, string(have), want) - } - } -} - // nolint:typecheck func TestTracingWithOverrides(t *testing.T) { t.Parallel() diff --git a/eth/tracers/dir.go b/eth/tracers/dir.go index 05c76bceb7..cfb4fec0e0 100644 --- a/eth/tracers/dir.go +++ b/eth/tracers/dir.go @@ -32,6 +32,10 @@ type Context struct { BlockNumber *big.Int // Number of the block the tx is contained within (zero if dangling tx or call) TxIndex int // Index of the transaction within a block (zero if dangling tx or call) TxHash common.Hash // Hash of the transaction being traced (zero if dangling call) + + // Bor specific fields used for state-sync transaction tracing + CumulativeGasUsed uint64 // Cumulative gas used by all prior txs in the block + LogIndex int // Number of logs emitted by all prior txs in the block } // Tracer represents the set of methods that must be exposed by a tracer diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 7d6325646e..1811c3809b 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -142,6 +142,9 @@ func TestSupplyRewards(t *testing.T) { ) expected := supplyInfo{ + Issuance: &supplyInfoIssuance{ + Reward: (*hexutil.Big)(ethash.ConstantinopleBlockReward.ToBig()), + }, Number: 1, Hash: common.HexToHash("0xcbb08370505be503dafedc4e96d139ea27aba3cbc580148568b8a307b3f51052"), ParentHash: common.HexToHash("0xadeda0a83e337b6c073e3f0e9a17531a04009b397a9588c093b628f21b8bc5a3"), @@ -251,6 +254,9 @@ func TestSupplyEip1559Burn(t *testing.T) { head = chain.CurrentBlock() burn = new(big.Int).Mul(big.NewInt(21000), head.BaseFee) expected = supplyInfo{ + Issuance: &supplyInfoIssuance{ + Reward: (*hexutil.Big)(ethash.ConstantinopleBlockReward.ToBig()), + }, Burn: &supplyInfoBurn{ EIP1559: (*hexutil.Big)(burn), }, diff --git a/eth/tracers/register_native_test.go b/eth/tracers/register_native_test.go new file mode 100644 index 0000000000..5d8b0d9244 --- /dev/null +++ b/eth/tracers/register_native_test.go @@ -0,0 +1,6 @@ +package tracers_test + +// Blank import registers native tracers (callTracer, etc.) so they are available +// to internal (package tracers) tests. This file must use the external test package +// to avoid a cyclic dependency: eth/tracers/native imports eth/tracers. +import _ "github.com/ethereum/go-ethereum/eth/tracers/native" diff --git a/eth/tracers/state_sync_txn_tracer.go b/eth/tracers/state_sync_txn_tracer.go new file mode 100644 index 0000000000..82f9237c53 --- /dev/null +++ b/eth/tracers/state_sync_txn_tracer.go @@ -0,0 +1,154 @@ +package tracers + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" +) + +// NewStateSyncTxnTracer wraps any tracer to make it compatible with bor state-sync transactions. +// +// State-sync transactions contain multiple independent bridge events, each of which produces its own +// top-level EVM call (OnEnter at depth 0). This breaks tracers like callTracer that expect exactly +// one root call frame per transaction. +// +// The wrapper fixes this by: +// 1. Injecting a synthetic top-level CALL (depth 0) from BorSystemAddress to the StateReceiverContract +// on the first OnEnter, so there is a single root frame. +// 2. Shifting all real EVM depths by +1, making the actual top-level calls appear as sub-calls. +// 3. Closing the synthetic root frame via OnExit(depth=0) in OnTxEnd. +func NewStateSyncTxnTracer(tracer *Tracer, stateReceiverContractAddress common.Address) *Tracer { + t := &stateSyncTxnTracer{ + tracer: tracer, + stateReceiverContractAddress: stateReceiverContractAddress, + } + return &Tracer{ + Hooks: &tracing.Hooks{ + OnTxStart: t.OnTxStart, + OnTxEnd: t.OnTxEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, + OnGasChange: t.OnGasChange, + OnBalanceChange: t.OnBalanceChange, + OnNonceChange: t.OnNonceChange, + OnCodeChange: t.OnCodeChange, + OnStorageChange: t.OnStorageChange, + OnLog: t.OnLog, + }, + GetResult: t.GetResult, + Stop: t.Stop, + } +} + +// stateSyncTxnTracer wraps another tracer and tricks it into seeing a single root call frame +// for state-sync transactions that contain multiple independent EVM calls. +type stateSyncTxnTracer struct { + tracer *Tracer + stateReceiverContractAddress common.Address + createdTopLevel bool +} + +func (t *stateSyncTxnTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { + if t.tracer.OnTxStart != nil { + t.tracer.OnTxStart(env, tx, from) + } +} + +func (t *stateSyncTxnTracer) OnTxEnd(receipt *types.Receipt, err error) { + // Close the synthetic top-level call frame before forwarding OnTxEnd, + // but only if it was actually created (i.e., at least one OnEnter occurred). + if t.createdTopLevel && t.tracer.OnExit != nil { + t.tracer.OnExit(0, nil, 0, err, err != nil) + } + + if t.tracer.OnTxEnd != nil { + t.tracer.OnTxEnd(receipt, err) + } +} + +func (t *stateSyncTxnTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if t.tracer.OnEnter != nil { + if !t.createdTopLevel { + // Inject a synthetic root CALL at depth 0 from BorSystemAddress to StateReceiverContract. + t.tracer.OnEnter(0, byte(vm.CALL), params.BorSystemAddress, t.stateReceiverContractAddress, nil, 0, big.NewInt(0)) + t.createdTopLevel = true + } + + // Shift all real calls one level deeper so they appear as sub-calls of the synthetic root. + t.tracer.OnEnter(depth+1, typ, from, to, input, gas, value) + } +} + +func (t *stateSyncTxnTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if t.tracer.OnExit != nil { + t.tracer.OnExit(depth+1, output, gasUsed, err, reverted) + } +} + +func (t *stateSyncTxnTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + if t.tracer.OnOpcode != nil { + t.tracer.OnOpcode(pc, op, gas, cost, scope, rData, depth+1, err) + } +} + +func (t *stateSyncTxnTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { + if t.tracer.OnFault != nil { + t.tracer.OnFault(pc, op, gas, cost, scope, depth+1, err) + } +} + +func (t *stateSyncTxnTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) { + if t.tracer.OnGasChange != nil { + t.tracer.OnGasChange(old, new, reason) + } +} + +func (t *stateSyncTxnTracer) OnBalanceChange(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { + if t.tracer.OnBalanceChange != nil { + t.tracer.OnBalanceChange(addr, prev, new, reason) + } +} + +func (t *stateSyncTxnTracer) OnNonceChange(addr common.Address, prev, new uint64) { + if t.tracer.OnNonceChange != nil { + t.tracer.OnNonceChange(addr, prev, new) + } +} + +func (t *stateSyncTxnTracer) OnCodeChange(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) { + if t.tracer.OnCodeChange != nil { + t.tracer.OnCodeChange(addr, prevCodeHash, prevCode, codeHash, code) + } +} + +func (t *stateSyncTxnTracer) OnStorageChange(addr common.Address, slot common.Hash, prev, new common.Hash) { + if t.tracer.OnStorageChange != nil { + t.tracer.OnStorageChange(addr, slot, prev, new) + } +} + +func (t *stateSyncTxnTracer) OnLog(log *types.Log) { + if t.tracer.OnLog != nil { + t.tracer.OnLog(log) + } +} + +func (t *stateSyncTxnTracer) GetResult() (json.RawMessage, error) { + if t.tracer.GetResult != nil { + return t.tracer.GetResult() + } + return json.RawMessage{}, nil +} + +func (t *stateSyncTxnTracer) Stop(err error) { + if t.tracer.Stop != nil { + t.tracer.Stop(err) + } +} diff --git a/internal/cli/server/config.go b/internal/cli/server/config.go index dd55aa98bb..7b0b600bf2 100644 --- a/internal/cli/server/config.go +++ b/internal/cli/server/config.go @@ -810,6 +810,7 @@ type RelayConfig struct { func DefaultConfig() *Config { return &Config{ Chain: "mainnet", + Ethstats: "", Identity: Hostname(), RequiredBlocks: map[string]string{}, Verbosity: 3, @@ -822,6 +823,17 @@ func DefaultConfig() *Config { KeyStoreDir: "", DisableBlindForkValidation: false, MaxBlindForkValidationLimit: whitelist.DefaultMaxForkCorrectnessLimit, + VMTrace: "", + VMTraceJsonConfig: "{}", + BatchRequestLimit: node.DefaultConfig.BatchRequestLimit, + BatchResponseMaxSize: node.DefaultConfig.BatchResponseMaxSize, + RPCReturnDataLimit: 100000, + SyncMode: "full", + GcMode: "full", + StateScheme: "path", + Snapshot: true, + BorLogs: false, + DevFakeAuthor: false, Logging: &LoggingConfig{ Vmodule: "", Json: false, @@ -829,9 +841,6 @@ func DefaultConfig() *Config { Debug: false, EnableBlockTracking: false, }, - BatchRequestLimit: node.DefaultConfig.BatchRequestLimit, - BatchResponseMaxSize: node.DefaultConfig.BatchResponseMaxSize, - RPCReturnDataLimit: 100000, P2P: &P2PConfig{ MaxPeers: 50, MaxPendPeers: 50, @@ -861,12 +870,6 @@ func DefaultConfig() *Config { GRPCAddress: "", WSAddress: "", }, - SyncMode: "full", - GcMode: "full", - StateScheme: "path", - Snapshot: true, - BorLogs: false, - TxPool: &TxPoolConfig{ Locals: []string{}, NoLocals: false, @@ -967,7 +970,6 @@ func DefaultConfig() *Config { VHosts: node.DefaultAuthVhosts, }, }, - Ethstats: "", Telemetry: &TelemetryConfig{ Enabled: false, Expensive: false, @@ -1027,7 +1029,6 @@ func DefaultConfig() *Config { Period: 0, GasLimit: 11500000, }, - DevFakeAuthor: false, Pprof: &PprofConfig{ Enabled: false, Port: 6060, diff --git a/internal/cli/server/flags.go b/internal/cli/server/flags.go index 270d9f6bde..f32e3a8f03 100644 --- a/internal/cli/server/flags.go +++ b/internal/cli/server/flags.go @@ -53,7 +53,7 @@ func (c *Command) Flags(config *Config) *flagset.Flagset { }) f.StringFlag(&flagset.StringFlag{ Name: "vmtrace", - Usage: "Name of tracer which should observe internal VM operations (e.g. 'json')", + Usage: "Name of a tracer to record internal VM operations during blockchain synchronization (costly) (e.g. 'json')", Value: &c.cliConfig.VMTrace, Default: c.cliConfig.VMTrace, }) diff --git a/internal/cli/server/service.go b/internal/cli/server/service.go index a63736e5da..99e5779dde 100644 --- a/internal/cli/server/service.go +++ b/internal/cli/server/service.go @@ -20,6 +20,7 @@ import ( "github.com/ethereum/go-ethereum/internal/cli/server/proto" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/rpc" ) const chunkSize = 1024 * 1024 * 1024 @@ -229,16 +230,13 @@ func headerToProtoHeader(h *types.Header) *proto.Header { } func (s *Server) DebugBlock(req *proto.DebugBlockRequest, stream proto.Bor_DebugBlockServer) error { - traceReq := &tracers.TraceBlockRequest{ - Number: req.Number, - Config: &tracers.TraceConfig{ - Config: &logger.Config{ - EnableMemory: true, - }, + config := &tracers.TraceConfig{ + Config: &logger.Config{ + EnableMemory: true, }, } - res, err := s.tracerAPI.TraceBorBlock(traceReq) + res, err := s.tracerAPI.TraceBlockByNumber(stream.Context(), rpc.BlockNumber(req.Number), config) if err != nil { return err } diff --git a/params/protocol_params.go b/params/protocol_params.go index 17d9fafae8..494f926f11 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -219,6 +219,10 @@ var ( DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not. ) +// BorSystemAddress is used for doing system transactions for processing bor bridge events +// i.e. state-sync events. +var BorSystemAddress = common.HexToAddress("0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE") + // System contracts. var ( // SystemAddress is where the system-transaction is sent from as per EIP-4788 diff --git a/tests/bor/bor_test.go b/tests/bor/bor_test.go index a7eac3e37f..85114579b7 100644 --- a/tests/bor/bor_test.go +++ b/tests/bor/bor_test.go @@ -2928,7 +2928,7 @@ func getMockedSpannerWithSpanRotation(t *testing.T, validator1, validator2 commo } spanner.EXPECT().GetCurrentSpan(gomock.Any(), gomock.Any(), gomock.Any()).Return(span1Mock, nil).AnyTimes() - spanner.EXPECT().CommitSpan(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + spanner.EXPECT().CommitSpan(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() return spanner } diff --git a/tests/bor/helper.go b/tests/bor/helper.go index 81df9ab851..3eae031097 100644 --- a/tests/bor/helper.go +++ b/tests/bor/helper.go @@ -495,7 +495,7 @@ func getMockedSpanner(t *testing.T, validators []*valset.Validator) *bor.MockSpa spanner.EXPECT().GetCurrentValidatorsByHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(validators, nil).AnyTimes() spanner.EXPECT().GetCurrentValidatorsByBlockNrOrHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(validators, nil).AnyTimes() spanner.EXPECT().GetCurrentSpan(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSpan, nil).AnyTimes() - spanner.EXPECT().CommitSpan(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + spanner.EXPECT().CommitSpan(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() return spanner } diff --git a/tests/bor/mocks/IHeimdallClient.go b/tests/bor/mocks/IHeimdallClient.go index 3608823bd4..f6f178f981 100644 --- a/tests/bor/mocks/IHeimdallClient.go +++ b/tests/bor/mocks/IHeimdallClient.go @@ -1,5 +1,10 @@ // Code generated by MockGen. DO NOT EDIT. // Source: heimdall.go +// +// Generated by this command: +// +// mockgen -source=heimdall.go -destination=../../tests/bor/mocks/IHeimdallClient.go -package=mocks +// // Package mocks is a generated GoMock package. package mocks @@ -8,19 +13,19 @@ import ( context "context" reflect "reflect" - gomock "go.uber.org/mock/gomock" - types "github.com/0xPolygon/heimdall-v2/x/bor/types" coretypes "github.com/cometbft/cometbft/rpc/core/types" clerk "github.com/ethereum/go-ethereum/consensus/bor/clerk" checkpoint "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint" milestone "github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone" + gomock "go.uber.org/mock/gomock" ) // MockIHeimdallClient is a mock of IHeimdallClient interface. type MockIHeimdallClient struct { ctrl *gomock.Controller recorder *MockIHeimdallClientMockRecorder + isgomock struct{} } // MockIHeimdallClientMockRecorder is the mock recorder for MockIHeimdallClient. @@ -62,7 +67,7 @@ func (m *MockIHeimdallClient) FetchCheckpoint(ctx context.Context, number int64) } // FetchCheckpoint indicates an expected call of FetchCheckpoint. -func (mr *MockIHeimdallClientMockRecorder) FetchCheckpoint(ctx, number interface{}) *gomock.Call { +func (mr *MockIHeimdallClientMockRecorder) FetchCheckpoint(ctx, number any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchCheckpoint", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchCheckpoint), ctx, number) } @@ -77,7 +82,7 @@ func (m *MockIHeimdallClient) FetchCheckpointCount(ctx context.Context) (int64, } // FetchCheckpointCount indicates an expected call of FetchCheckpointCount. -func (mr *MockIHeimdallClientMockRecorder) FetchCheckpointCount(ctx interface{}) *gomock.Call { +func (mr *MockIHeimdallClientMockRecorder) FetchCheckpointCount(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchCheckpointCount", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchCheckpointCount), ctx) } @@ -92,7 +97,7 @@ func (m *MockIHeimdallClient) FetchMilestone(ctx context.Context) (*milestone.Mi } // FetchMilestone indicates an expected call of FetchMilestone. -func (mr *MockIHeimdallClientMockRecorder) FetchMilestone(ctx interface{}) *gomock.Call { +func (mr *MockIHeimdallClientMockRecorder) FetchMilestone(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchMilestone", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchMilestone), ctx) } @@ -107,7 +112,7 @@ func (m *MockIHeimdallClient) FetchMilestoneCount(ctx context.Context) (int64, e } // FetchMilestoneCount indicates an expected call of FetchMilestoneCount. -func (mr *MockIHeimdallClientMockRecorder) FetchMilestoneCount(ctx interface{}) *gomock.Call { +func (mr *MockIHeimdallClientMockRecorder) FetchMilestoneCount(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchMilestoneCount", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchMilestoneCount), ctx) } @@ -122,7 +127,7 @@ func (m *MockIHeimdallClient) FetchStatus(ctx context.Context) (*coretypes.SyncI } // FetchStatus indicates an expected call of FetchStatus. -func (mr *MockIHeimdallClientMockRecorder) FetchStatus(ctx interface{}) *gomock.Call { +func (mr *MockIHeimdallClientMockRecorder) FetchStatus(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchStatus", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchStatus), ctx) } @@ -137,7 +142,7 @@ func (m *MockIHeimdallClient) GetLatestSpan(ctx context.Context) (*types.Span, e } // GetLatestSpan indicates an expected call of GetLatestSpan. -func (mr *MockIHeimdallClientMockRecorder) GetLatestSpan(ctx interface{}) *gomock.Call { +func (mr *MockIHeimdallClientMockRecorder) GetLatestSpan(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestSpan", reflect.TypeOf((*MockIHeimdallClient)(nil).GetLatestSpan), ctx) } @@ -152,7 +157,7 @@ func (m *MockIHeimdallClient) GetSpan(ctx context.Context, spanID uint64) (*type } // GetSpan indicates an expected call of GetSpan. -func (mr *MockIHeimdallClientMockRecorder) GetSpan(ctx, spanID interface{}) *gomock.Call { +func (mr *MockIHeimdallClientMockRecorder) GetSpan(ctx, spanID any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSpan", reflect.TypeOf((*MockIHeimdallClient)(nil).GetSpan), ctx, spanID) } @@ -167,7 +172,7 @@ func (m *MockIHeimdallClient) StateSyncEvents(ctx context.Context, fromID uint64 } // StateSyncEvents indicates an expected call of StateSyncEvents. -func (mr *MockIHeimdallClientMockRecorder) StateSyncEvents(ctx, fromID, to interface{}) *gomock.Call { +func (mr *MockIHeimdallClientMockRecorder) StateSyncEvents(ctx, fromID, to any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateSyncEvents", reflect.TypeOf((*MockIHeimdallClient)(nil).StateSyncEvents), ctx, fromID, to) } @@ -176,6 +181,7 @@ func (mr *MockIHeimdallClientMockRecorder) StateSyncEvents(ctx, fromID, to inter type MockIHeimdallWSClient struct { ctrl *gomock.Controller recorder *MockIHeimdallWSClientMockRecorder + isgomock struct{} } // MockIHeimdallWSClientMockRecorder is the mock recorder for MockIHeimdallWSClient. @@ -218,7 +224,7 @@ func (m *MockIHeimdallWSClient) SubscribeMilestoneEvents(ctx context.Context) <- } // SubscribeMilestoneEvents indicates an expected call of SubscribeMilestoneEvents. -func (mr *MockIHeimdallWSClientMockRecorder) SubscribeMilestoneEvents(ctx interface{}) *gomock.Call { +func (mr *MockIHeimdallWSClientMockRecorder) SubscribeMilestoneEvents(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeMilestoneEvents", reflect.TypeOf((*MockIHeimdallWSClient)(nil).SubscribeMilestoneEvents), ctx) } @@ -232,7 +238,7 @@ func (m *MockIHeimdallWSClient) Unsubscribe(ctx context.Context) error { } // Unsubscribe indicates an expected call of Unsubscribe. -func (mr *MockIHeimdallWSClientMockRecorder) Unsubscribe(ctx interface{}) *gomock.Call { +func (mr *MockIHeimdallWSClientMockRecorder) Unsubscribe(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unsubscribe", reflect.TypeOf((*MockIHeimdallWSClient)(nil).Unsubscribe), ctx) }