diff --git a/cmd/rpcdaemon/cli/config.go b/cmd/rpcdaemon/cli/config.go index e0130874f..b96952ff5 100644 --- a/cmd/rpcdaemon/cli/config.go +++ b/cmd/rpcdaemon/cli/config.go @@ -126,7 +126,7 @@ func RootCommand() (*cobra.Command, *httpcfg.HttpCfg) { rootCmd.PersistentFlags().DurationVar(&cfg.EvmCallTimeout, "rpc.evmtimeout", rpccfg.DefaultEvmCallTimeout, "Maximum amount of time to wait for the answer from EVM call.") rootCmd.PersistentFlags().IntVar(&cfg.BatchLimit, utils.RpcBatchLimit.Name, utils.RpcBatchLimit.Value, utils.RpcBatchLimit.Usage) rootCmd.PersistentFlags().IntVar(&cfg.ReturnDataLimit, utils.RpcReturnDataLimit.Name, utils.RpcReturnDataLimit.Value, utils.RpcReturnDataLimit.Usage) - + rootCmd.PersistentFlags().BoolVar(&cfg.AllowUnprotectedTxs, utils.AllowUnprotectedTxs.Name, utils.AllowUnprotectedTxs.Value, utils.AllowUnprotectedTxs.Usage) rootCmd.PersistentFlags().Uint64Var(&cfg.OtsMaxPageSize, utils.OtsSearchMaxCapFlag.Name, utils.OtsSearchMaxCapFlag.Value, utils.OtsSearchMaxCapFlag.Usage) if err := rootCmd.MarkPersistentFlagFilename("rpc.accessList", "json"); err != nil { diff --git a/cmd/rpcdaemon/cli/httpcfg/http_cfg.go b/cmd/rpcdaemon/cli/httpcfg/http_cfg.go index a41f56234..63d4cb6a0 100644 --- a/cmd/rpcdaemon/cli/httpcfg/http_cfg.go +++ b/cmd/rpcdaemon/cli/httpcfg/http_cfg.go @@ -61,8 +61,9 @@ type HttpCfg struct { LogDirVerbosity string LogDirPath string - BatchLimit int // Maximum number of requests in a batch - ReturnDataLimit int // Maximum number of bytes returned from calls (like eth_call) + BatchLimit int // Maximum number of requests in a batch + ReturnDataLimit int // Maximum number of bytes returned from calls (like eth_call) + AllowUnprotectedTxs bool // Whether to allow non EIP-155 protected transactions txs over RPC // Ots API OtsMaxPageSize uint64 diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5d5f559b6..38e93e2ca 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -478,7 +478,7 @@ var ( } AllowUnprotectedTxs = cli.BoolFlag{ Name: "rpc.allow-unprotected-txs", - Usage: "Allow for unprotected (non EIP155 signed) transactions to be submitted via RPC", + Usage: "Allow for unprotected (non-EIP155 signed) transactions to be submitted via RPC", } StateCacheFlag = cli.StringFlag{ Name: "state.cache", diff --git a/node/nodecfg/config.go b/node/nodecfg/config.go index 42e8e18a8..698f2d71f 100644 --- a/node/nodecfg/config.go +++ b/node/nodecfg/config.go @@ -155,10 +155,9 @@ type Config struct { TLSConnection bool TLSCertFile string - // AllowUnprotectedTxs allows non EIP-155 protected transactions to be send over RPC. - AllowUnprotectedTxs bool `toml:",omitempty"` - TLSKeyFile string - TLSCACert string + + TLSKeyFile string + TLSCACert string MdbxPageSize datasize.ByteSize MdbxDBSizeLimit datasize.ByteSize diff --git a/turbo/cli/default_flags.go b/turbo/cli/default_flags.go index a6daf1cbf..40fad68e1 100644 --- a/turbo/cli/default_flags.go +++ b/turbo/cli/default_flags.go @@ -74,6 +74,7 @@ var DefaultFlags = []cli.Flag{ &utils.RpcGasCapFlag, &utils.RpcBatchLimit, &utils.RpcReturnDataLimit, + &utils.AllowUnprotectedTxs, &utils.RPCGlobalTxFeeCapFlag, &utils.TxpoolApiAddrFlag, &utils.TraceMaxtracesFlag, diff --git a/turbo/cli/flags.go b/turbo/cli/flags.go index 471e891e9..e8edff7a4 100644 --- a/turbo/cli/flags.go +++ b/turbo/cli/flags.go @@ -396,6 +396,7 @@ func setEmbeddedRpcDaemon(ctx *cli.Context, cfg *nodecfg.Config, logger log.Logg TraceCompatibility: ctx.Bool(utils.RpcTraceCompatFlag.Name), BatchLimit: ctx.Int(utils.RpcBatchLimit.Name), ReturnDataLimit: ctx.Int(utils.RpcReturnDataLimit.Name), + AllowUnprotectedTxs: ctx.Bool(utils.AllowUnprotectedTxs.Name), OtsMaxPageSize: ctx.Uint64(utils.OtsSearchMaxCapFlag.Name), diff --git a/turbo/engineapi/engine_server.go b/turbo/engineapi/engine_server.go index 8f43722b3..7bcaccd67 100644 --- a/turbo/engineapi/engine_server.go +++ b/turbo/engineapi/engine_server.go @@ -81,7 +81,7 @@ func (e *EngineServer) Start(httpConfig httpcfg.HttpCfg, db kv.RoDB, blockReader eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient) { base := jsonrpc.NewBaseApi(filters, stateCache, blockReader, agg, httpConfig.WithDatadir, httpConfig.EvmCallTimeout, engineReader, httpConfig.Dirs) - ethImpl := jsonrpc.NewEthAPI(base, db, eth, txPool, mining, httpConfig.Gascap, httpConfig.ReturnDataLimit, e.logger) + ethImpl := jsonrpc.NewEthAPI(base, db, eth, txPool, mining, httpConfig.Gascap, httpConfig.ReturnDataLimit, httpConfig.AllowUnprotectedTxs, e.logger) // engineImpl := NewEngineAPI(base, db, engineBackend) // e.startEngineMessageHandler() diff --git a/turbo/jsonrpc/corner_cases_support_test.go b/turbo/jsonrpc/corner_cases_support_test.go index 4c259b1a2..4a98e7c34 100644 --- a/turbo/jsonrpc/corner_cases_support_test.go +++ b/turbo/jsonrpc/corner_cases_support_test.go @@ -18,7 +18,7 @@ func TestNotFoundMustReturnNil(t *testing.T) { require := require.New(t) m, _, _ := rpcdaemontest.CreateTestSentry(t) api := NewEthAPI(newBaseApiForTest(m), - m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) ctx := context.Background() a, err := api.GetTransactionByBlockNumberAndIndex(ctx, 10_000, 1) diff --git a/turbo/jsonrpc/daemon.go b/turbo/jsonrpc/daemon.go index 55546377b..35a0f744c 100644 --- a/turbo/jsonrpc/daemon.go +++ b/turbo/jsonrpc/daemon.go @@ -22,7 +22,7 @@ func APIList(db kv.RoDB, eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, m logger log.Logger, ) (list []rpc.API) { base := NewBaseApi(filters, stateCache, blockReader, agg, cfg.WithDatadir, cfg.EvmCallTimeout, engine, cfg.Dirs) - ethImpl := NewEthAPI(base, db, eth, txPool, mining, cfg.Gascap, cfg.ReturnDataLimit, logger) + ethImpl := NewEthAPI(base, db, eth, txPool, mining, cfg.Gascap, cfg.ReturnDataLimit, cfg.AllowUnprotectedTxs, logger) erigonImpl := NewErigonAPI(base, db, eth) txpoolImpl := NewTxPoolAPI(base, db, txPool) netImpl := NewNetAPIImpl(eth) diff --git a/turbo/jsonrpc/debug_api_test.go b/turbo/jsonrpc/debug_api_test.go index e25f6b102..33ea0e579 100644 --- a/turbo/jsonrpc/debug_api_test.go +++ b/turbo/jsonrpc/debug_api_test.go @@ -53,7 +53,7 @@ func TestTraceBlockByNumber(t *testing.T) { agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) baseApi := NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) - ethApi := NewEthAPI(baseApi, m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + ethApi := NewEthAPI(baseApi, m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) api := NewPrivateDebugAPI(baseApi, m.DB, 0) for _, tt := range debugTraceTransactionTests { var buf bytes.Buffer @@ -98,7 +98,7 @@ func TestTraceBlockByNumber(t *testing.T) { func TestTraceBlockByHash(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) - ethApi := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + ethApi := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) api := NewPrivateDebugAPI(newBaseApiForTest(m), m.DB, 0) for _, tt := range debugTraceTransactionTests { var buf bytes.Buffer diff --git a/turbo/jsonrpc/erigon_receipts_test.go b/turbo/jsonrpc/erigon_receipts_test.go index aa82a4223..c40811b4e 100644 --- a/turbo/jsonrpc/erigon_receipts_test.go +++ b/turbo/jsonrpc/erigon_receipts_test.go @@ -29,7 +29,7 @@ func TestGetLogs(t *testing.T) { assert := assert.New(t) m, _, _ := rpcdaemontest.CreateTestSentry(t) { - ethApi := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + ethApi := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) logs, err := ethApi.GetLogs(context.Background(), filters.FilterCriteria{FromBlock: big.NewInt(0), ToBlock: big.NewInt(10)}) assert.NoError(err) diff --git a/turbo/jsonrpc/eth_api.go b/turbo/jsonrpc/eth_api.go index 518918e19..51c2b1cf0 100644 --- a/turbo/jsonrpc/eth_api.go +++ b/turbo/jsonrpc/eth_api.go @@ -318,32 +318,34 @@ func (api *BaseAPI) pruneMode(tx kv.Tx) (*prune.Mode, error) { // APIImpl is implementation of the EthAPI interface based on remote Db access type APIImpl struct { *BaseAPI - ethBackend rpchelper.ApiBackend - txPool txpool.TxpoolClient - mining txpool.MiningClient - gasCache *GasPriceCache - db kv.RoDB - GasCap uint64 - ReturnDataLimit int - logger log.Logger + ethBackend rpchelper.ApiBackend + txPool txpool.TxpoolClient + mining txpool.MiningClient + gasCache *GasPriceCache + db kv.RoDB + GasCap uint64 + ReturnDataLimit int + AllowUnprotectedTxs bool + logger log.Logger } // NewEthAPI returns APIImpl instance -func NewEthAPI(base *BaseAPI, db kv.RoDB, eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, gascap uint64, returnDataLimit int, logger log.Logger) *APIImpl { +func NewEthAPI(base *BaseAPI, db kv.RoDB, eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, gascap uint64, returnDataLimit int, allowUnprotectedTxs bool, logger log.Logger) *APIImpl { if gascap == 0 { gascap = uint64(math.MaxUint64 / 2) } return &APIImpl{ - BaseAPI: base, - db: db, - ethBackend: eth, - txPool: txPool, - mining: mining, - gasCache: NewGasPriceCache(), - GasCap: gascap, - ReturnDataLimit: returnDataLimit, - logger: logger, + BaseAPI: base, + db: db, + ethBackend: eth, + txPool: txPool, + mining: mining, + gasCache: NewGasPriceCache(), + GasCap: gascap, + AllowUnprotectedTxs: allowUnprotectedTxs, + ReturnDataLimit: returnDataLimit, + logger: logger, } } diff --git a/turbo/jsonrpc/eth_api_test.go b/turbo/jsonrpc/eth_api_test.go index 6f508ab70..90b7b7c99 100644 --- a/turbo/jsonrpc/eth_api_test.go +++ b/turbo/jsonrpc/eth_api_test.go @@ -54,7 +54,7 @@ func TestGetTransactionReceipt(t *testing.T) { db := m.DB agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), db, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), db, nil, nil, nil, 5000000, 100_000, false, log.New()) // Call GetTransactionReceipt for transaction which is not in the database if _, err := api.GetTransactionReceipt(context.Background(), common.Hash{}); err != nil { t.Errorf("calling GetTransactionReceipt with empty hash: %v", err) @@ -63,7 +63,7 @@ func TestGetTransactionReceipt(t *testing.T) { func TestGetTransactionReceiptUnprotected(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) // Call GetTransactionReceipt for un-protected transaction if _, err := api.GetTransactionReceipt(context.Background(), common.HexToHash("0x3f3cb8a0e13ed2481f97f53f7095b9cbc78b6ffb779f2d3e565146371a8830ea")); err != nil { t.Errorf("calling GetTransactionReceipt for unprotected tx: %v", err) @@ -75,7 +75,7 @@ func TestGetTransactionReceiptUnprotected(t *testing.T) { func TestGetStorageAt_ByBlockNumber_WithRequireCanonicalDefault(t *testing.T) { assert := assert.New(t) m, _, _ := rpcdaemontest.CreateTestSentry(t) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") result, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithNumber(0)) @@ -89,7 +89,7 @@ func TestGetStorageAt_ByBlockNumber_WithRequireCanonicalDefault(t *testing.T) { func TestGetStorageAt_ByBlockHash_WithRequireCanonicalDefault(t *testing.T) { assert := assert.New(t) m, _, _ := rpcdaemontest.CreateTestSentry(t) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") result, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithHash(m.Genesis.Hash(), false)) @@ -103,7 +103,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalDefault(t *testing.T) { func TestGetStorageAt_ByBlockHash_WithRequireCanonicalTrue(t *testing.T) { assert := assert.New(t) m, _, _ := rpcdaemontest.CreateTestSentry(t) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") result, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithHash(m.Genesis.Hash(), true)) @@ -116,7 +116,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalTrue(t *testing.T) { func TestGetStorageAt_ByBlockHash_WithRequireCanonicalDefault_BlockNotFoundError(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") offChain, err := core.GenerateChain(m.ChainConfig, m.Genesis, m.Engine, m.DB, 1, func(i int, block *core.BlockGen) { @@ -137,7 +137,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalDefault_BlockNotFoundError func TestGetStorageAt_ByBlockHash_WithRequireCanonicalTrue_BlockNotFoundError(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") offChain, err := core.GenerateChain(m.ChainConfig, m.Genesis, m.Engine, m.DB, 1, func(i int, block *core.BlockGen) { @@ -159,7 +159,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalTrue_BlockNotFoundError(t func TestGetStorageAt_ByBlockHash_WithRequireCanonicalDefault_NonCanonicalBlock(t *testing.T) { assert := assert.New(t) m, _, orphanedChain := rpcdaemontest.CreateTestSentry(t) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") orphanedBlock := orphanedChain[0].Blocks[0] @@ -178,7 +178,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalDefault_NonCanonicalBlock( func TestGetStorageAt_ByBlockHash_WithRequireCanonicalTrue_NonCanonicalBlock(t *testing.T) { m, _, orphanedChain := rpcdaemontest.CreateTestSentry(t) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") orphanedBlock := orphanedChain[0].Blocks[0] @@ -194,7 +194,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalTrue_NonCanonicalBlock(t * func TestCall_ByBlockHash_WithRequireCanonicalDefault_NonCanonicalBlock(t *testing.T) { m, _, orphanedChain := rpcdaemontest.CreateTestSentry(t) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) from := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") to := common.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e") @@ -217,7 +217,7 @@ func TestCall_ByBlockHash_WithRequireCanonicalDefault_NonCanonicalBlock(t *testi func TestCall_ByBlockHash_WithRequireCanonicalTrue_NonCanonicalBlock(t *testing.T) { m, _, orphanedChain := rpcdaemontest.CreateTestSentry(t) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) from := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") to := common.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e") diff --git a/turbo/jsonrpc/eth_block_test.go b/turbo/jsonrpc/eth_block_test.go index 9ae61196b..60d048de2 100644 --- a/turbo/jsonrpc/eth_block_test.go +++ b/turbo/jsonrpc/eth_block_test.go @@ -25,7 +25,7 @@ import ( // Gets the latest block number with the latest tag func TestGetBlockByNumberWithLatestTag(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) b, err := api.GetBlockByNumber(context.Background(), rpc.LatestBlockNumber, false) expected := common.HexToHash("0x5883164d4100b95e1d8e931b8b9574586a1dea7507941e6ad3c1e3a2591485fd") if err != nil { @@ -55,7 +55,7 @@ func TestGetBlockByNumberWithLatestTag_WithHeadHashInDb(t *testing.T) { } tx.Commit() - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) block, err := api.GetBlockByNumber(ctx, rpc.LatestBlockNumber, false) if err != nil { t.Errorf("error retrieving block by number: %s", err) @@ -86,7 +86,7 @@ func TestGetBlockByNumberWithPendingTag(t *testing.T) { RplBlock: rlpBlock, }) - api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) b, err := api.GetBlockByNumber(context.Background(), rpc.PendingBlockNumber, false) if err != nil { t.Errorf("error getting block number with pending tag: %s", err) @@ -97,7 +97,7 @@ func TestGetBlockByNumberWithPendingTag(t *testing.T) { func TestGetBlockByNumber_WithFinalizedTag_NoFinalizedBlockInDb(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) ctx := context.Background() - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) if _, err := api.GetBlockByNumber(ctx, rpc.FinalizedBlockNumber, false); err != nil { assert.ErrorIs(t, rpchelper.UnknownBlockError, err) } @@ -124,7 +124,7 @@ func TestGetBlockByNumber_WithFinalizedTag_WithFinalizedBlockInDb(t *testing.T) } tx.Commit() - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) block, err := api.GetBlockByNumber(ctx, rpc.FinalizedBlockNumber, false) if err != nil { t.Errorf("error retrieving block by number: %s", err) @@ -136,7 +136,7 @@ func TestGetBlockByNumber_WithFinalizedTag_WithFinalizedBlockInDb(t *testing.T) func TestGetBlockByNumber_WithSafeTag_NoSafeBlockInDb(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) ctx := context.Background() - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) if _, err := api.GetBlockByNumber(ctx, rpc.SafeBlockNumber, false); err != nil { assert.ErrorIs(t, rpchelper.UnknownBlockError, err) } @@ -163,7 +163,7 @@ func TestGetBlockByNumber_WithSafeTag_WithSafeBlockInDb(t *testing.T) { } tx.Commit() - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) block, err := api.GetBlockByNumber(ctx, rpc.SafeBlockNumber, false) if err != nil { t.Errorf("error retrieving block by number: %s", err) @@ -176,7 +176,7 @@ func TestGetBlockTransactionCountByHash(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) ctx := context.Background() - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) blockHash := common.HexToHash("0x6804117de2f3e6ee32953e78ced1db7b20214e0d8c745a03b8fecf7cc8ee76ef") tx, err := m.DB.BeginRw(ctx) @@ -208,7 +208,7 @@ func TestGetBlockTransactionCountByHash(t *testing.T) { func TestGetBlockTransactionCountByHash_ZeroTx(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) ctx := context.Background() - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) blockHash := common.HexToHash("0x5883164d4100b95e1d8e931b8b9574586a1dea7507941e6ad3c1e3a2591485fd") tx, err := m.DB.BeginRw(ctx) @@ -240,7 +240,7 @@ func TestGetBlockTransactionCountByHash_ZeroTx(t *testing.T) { func TestGetBlockTransactionCountByNumber(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) ctx := context.Background() - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) blockHash := common.HexToHash("0x6804117de2f3e6ee32953e78ced1db7b20214e0d8c745a03b8fecf7cc8ee76ef") tx, err := m.DB.BeginRw(ctx) @@ -272,7 +272,7 @@ func TestGetBlockTransactionCountByNumber(t *testing.T) { func TestGetBlockTransactionCountByNumber_ZeroTx(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) ctx := context.Background() - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) blockHash := common.HexToHash("0x5883164d4100b95e1d8e931b8b9574586a1dea7507941e6ad3c1e3a2591485fd") diff --git a/turbo/jsonrpc/eth_callMany_test.go b/turbo/jsonrpc/eth_callMany_test.go index 4ef58d7b8..9a129c5cc 100644 --- a/turbo/jsonrpc/eth_callMany_test.go +++ b/turbo/jsonrpc/eth_callMany_test.go @@ -84,7 +84,7 @@ func TestCallMany(t *testing.T) { db := contractBackend.DB() engine := contractBackend.Engine() api := NewEthAPI(NewBaseApi(nil, stateCache, contractBackend.BlockReader(), contractBackend.Agg(), false, rpccfg.DefaultEvmCallTimeout, engine, - datadir.New(t.TempDir())), db, nil, nil, nil, 5000000, 100_000, log.New()) + datadir.New(t.TempDir())), db, nil, nil, nil, 5000000, 100_000, false, log.New()) callArgAddr1 := ethapi.CallArgs{From: &address, To: &tokenAddr, Nonce: &nonce, MaxPriorityFeePerGas: (*hexutil.Big)(big.NewInt(1e9)), diff --git a/turbo/jsonrpc/eth_call_test.go b/turbo/jsonrpc/eth_call_test.go index ae6b3edb4..7c3a62b30 100644 --- a/turbo/jsonrpc/eth_call_test.go +++ b/turbo/jsonrpc/eth_call_test.go @@ -42,7 +42,7 @@ func TestEstimateGas(t *testing.T) { ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, mock.Mock(t)) mining := txpool.NewMiningClient(conn) ff := rpchelper.New(ctx, nil, nil, mining, func() {}, m.Log) - api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) var from = libcommon.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") var to = libcommon.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e") if _, err := api.EstimateGas(context.Background(), ðapi.CallArgs{ @@ -57,7 +57,7 @@ func TestEthCallNonCanonical(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) var from = libcommon.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") var to = libcommon.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e") if _, err := api.Call(context.Background(), ethapi.CallArgs{ @@ -76,7 +76,7 @@ func TestEthCallToPrunedBlock(t *testing.T) { m, bankAddress, contractAddress := chainWithDeployedContract(t) doPrune(t, m.DB, pruneTo) - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) callData := hexutil.MustDecode("0x2e64cec1") callDataBytes := hexutility.Bytes(callData) @@ -97,7 +97,7 @@ func TestGetProof(t *testing.T) { if m.HistoryV3 { t.Skip("not supported by Erigon3") } - api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) key := func(b byte) libcommon.Hash { result := libcommon.Hash{} diff --git a/turbo/jsonrpc/eth_filters_test.go b/turbo/jsonrpc/eth_filters_test.go index 636e77192..8c78713b6 100644 --- a/turbo/jsonrpc/eth_filters_test.go +++ b/turbo/jsonrpc/eth_filters_test.go @@ -30,7 +30,7 @@ func TestNewFilters(t *testing.T) { ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, mock.Mock(t)) mining := txpool.NewMiningClient(conn) ff := rpchelper.New(ctx, nil, nil, mining, func() {}, m.Log) - api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) ptf, err := api.NewPendingTransactionFilter(ctx) assert.Nil(err) diff --git a/turbo/jsonrpc/eth_mining_test.go b/turbo/jsonrpc/eth_mining_test.go index 86f86b40e..6a29d8539 100644 --- a/turbo/jsonrpc/eth_mining_test.go +++ b/turbo/jsonrpc/eth_mining_test.go @@ -27,7 +27,7 @@ func TestPendingBlock(t *testing.T) { stateCache := kvcache.New(kvcache.DefaultCoherentConfig) engine := ethash.NewFaker() api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, nil, false, rpccfg.DefaultEvmCallTimeout, engine, - m.Dirs), nil, nil, nil, mining, 5000000, 100_000, log.New()) + m.Dirs), nil, nil, nil, mining, 5000000, 100_000, false, log.New()) expect := uint64(12345) b, err := rlp.EncodeToBytes(types.NewBlockWithHeader(&types.Header{Number: big.NewInt(int64(expect))})) require.NoError(t, err) diff --git a/turbo/jsonrpc/eth_system_test.go b/turbo/jsonrpc/eth_system_test.go index 5d261812d..6cf1d36ae 100644 --- a/turbo/jsonrpc/eth_system_test.go +++ b/turbo/jsonrpc/eth_system_test.go @@ -40,7 +40,7 @@ func TestGasPrice(t *testing.T) { t.Run(testCase.description, func(t *testing.T) { m := createGasPriceTestKV(t, testCase.chainSize) defer m.DB.Close() - eth := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, log.New()) + eth := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, log.New()) ctx := context.Background() result, err := eth.GasPrice(ctx) diff --git a/turbo/jsonrpc/send_transaction.go b/turbo/jsonrpc/send_transaction.go index ffdfa2e21..c30869f19 100644 --- a/turbo/jsonrpc/send_transaction.go +++ b/turbo/jsonrpc/send_transaction.go @@ -27,7 +27,7 @@ func (api *APIImpl) SendRawTransaction(ctx context.Context, encodedTx hexutility if err := checkTxFee(txn.GetPrice().ToBig(), txn.GetGas(), ethconfig.Defaults.RPCTxFeeCap); err != nil { return common.Hash{}, err } - if !txn.Protected() { + if !txn.Protected() && !api.AllowUnprotectedTxs { return common.Hash{}, errors.New("only replay-protected (EIP-155) transactions allowed over RPC") } @@ -48,7 +48,7 @@ func (api *APIImpl) SendRawTransaction(ctx context.Context, encodedTx hexutility txnChainId := txn.GetChainID() chainId := cc.ChainID - if chainId.Cmp(txnChainId.ToBig()) != 0 { + if (txn.Protected() || !api.AllowUnprotectedTxs) && chainId.Cmp(txnChainId.ToBig()) != 0 { return common.Hash{}, fmt.Errorf("invalid chain id, expected: %d got: %d", chainId, *txnChainId) } diff --git a/turbo/jsonrpc/send_transaction_test.go b/turbo/jsonrpc/send_transaction_test.go index 847ee34bf..2549f5830 100644 --- a/turbo/jsonrpc/send_transaction_test.go +++ b/turbo/jsonrpc/send_transaction_test.go @@ -8,6 +8,8 @@ import ( "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/txpool/txpoolcfg" + "github.com/ledgerwatch/erigon-lib/gointerfaces/sentry" "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" "github.com/ledgerwatch/erigon-lib/kv/kvcache" @@ -16,6 +18,8 @@ import ( "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" "github.com/ledgerwatch/erigon/common/u256" + + txpool_proto "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/eth/protocols/eth" @@ -34,53 +38,56 @@ func newBaseApiForTest(m *mock.MockSentry) *jsonrpc.BaseAPI { return jsonrpc.NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) } -func TestSendRawTransaction(t *testing.T) { - t.Skip("Flaky test") - m, require := mock.Mock(t), require.New(t) - logger := log.New() - - chain, err := core.GenerateChain(m.ChainConfig, m.Genesis, m.Engine, m.DB, 1, func(i int, b *core.BlockGen) { +// Do 1 step to start txPool +func oneBlockStep(mockSentry *mock.MockSentry, require *require.Assertions, t *testing.T) { + chain, err := core.GenerateChain(mockSentry.ChainConfig, mockSentry.Genesis, mockSentry.Engine, mockSentry.DB, 1 /*number of blocks:*/, func(i int, b *core.BlockGen) { b.SetCoinbase(common.Address{1}) }) require.NoError(err) - { // Do 1 step to start txPool - // Send NewBlock message - b, err := rlp.EncodeToBytes(ð.NewBlockPacket{ - Block: chain.TopBlock, - TD: big.NewInt(1), // This is ignored anyway - }) - require.NoError(err) - m.ReceiveWg.Add(1) - for _, err = range m.Send(&sentry.InboundMessage{Id: sentry.MessageId_NEW_BLOCK_66, Data: b, PeerId: m.PeerId}) { - require.NoError(err) - } - // Send all the headers - b, err = rlp.EncodeToBytes(ð.BlockHeadersPacket66{ - RequestId: 1, - BlockHeadersPacket: chain.Headers, - }) - require.NoError(err) - m.ReceiveWg.Add(1) - for _, err = range m.Send(&sentry.InboundMessage{Id: sentry.MessageId_BLOCK_HEADERS_66, Data: b, PeerId: m.PeerId}) { - require.NoError(err) - } - m.ReceiveWg.Wait() // Wait for all messages to be processed before we proceed - - initialCycle := mock.MockInsertAsInitialCycle - if err := stages.StageLoopIteration(m.Ctx, m.DB, nil, m.Sync, initialCycle, logger, m.BlockReader, nil, false); err != nil { - t.Fatal(err) - } - } - - expectValue := uint64(1234) - txn, err := types.SignTx(types.NewTransaction(0, common.Address{1}, uint256.NewInt(expectValue), params.TxGas, uint256.NewInt(10*params.GWei), nil), *types.LatestSignerForChainID(m.ChainConfig.ChainID), m.Key) + // Send NewBlock message + b, err := rlp.EncodeToBytes(ð.NewBlockPacket{ + Block: chain.TopBlock, + TD: big.NewInt(1), // This is ignored anyway + }) require.NoError(err) - ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, m) + mockSentry.ReceiveWg.Add(1) + for _, err = range mockSentry.Send(&sentry.InboundMessage{Id: sentry.MessageId_NEW_BLOCK_66, Data: b, PeerId: mockSentry.PeerId}) { + require.NoError(err) + } + // Send all the headers + b, err = rlp.EncodeToBytes(ð.BlockHeadersPacket66{ + RequestId: 1, + BlockHeadersPacket: chain.Headers, + }) + require.NoError(err) + mockSentry.ReceiveWg.Add(1) + for _, err = range mockSentry.Send(&sentry.InboundMessage{Id: sentry.MessageId_BLOCK_HEADERS_66, Data: b, PeerId: mockSentry.PeerId}) { + require.NoError(err) + } + mockSentry.ReceiveWg.Wait() // Wait for all messages to be processed before we proceed + + initialCycle := mock.MockInsertAsInitialCycle + if err := stages.StageLoopIteration(mockSentry.Ctx, mockSentry.DB, nil, mockSentry.Sync, initialCycle, log.New(), mockSentry.BlockReader, nil, false); err != nil { + t.Fatal(err) + } +} + +func TestSendRawTransaction(t *testing.T) { + mockSentry, require := mock.MockWithTxPool(t), require.New(t) + logger := log.New() + + oneBlockStep(mockSentry, require, t) + + expectValue := uint64(1234) + txn, err := types.SignTx(types.NewTransaction(0, common.Address{1}, uint256.NewInt(expectValue), params.TxGas, uint256.NewInt(10*params.GWei), nil), *types.LatestSignerForChainID(mockSentry.ChainConfig.ChainID), mockSentry.Key) + require.NoError(err) + + ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, mockSentry) txPool := txpool.NewTxpoolClient(conn) - ff := rpchelper.New(ctx, nil, txPool, txpool.NewMiningClient(conn), func() {}, m.Log) - api := jsonrpc.NewEthAPI(newBaseApiForTest(m), m.DB, nil, txPool, nil, 5000000, 100_000, logger) + ff := rpchelper.New(ctx, nil, txPool, txpool.NewMiningClient(conn), func() {}, mockSentry.Log) + api := jsonrpc.NewEthAPI(newBaseApiForTest(mockSentry), mockSentry.DB, nil, txPool, nil, 5000000, 100_000, false, logger) buf := bytes.NewBuffer(nil) err = txn.MarshalBinary(buf) @@ -98,8 +105,9 @@ func TestSendRawTransaction(t *testing.T) { //send same tx second time and expect error _, err = api.SendRawTransaction(ctx, buf.Bytes()) require.NotNil(err) - require.Equal("ALREADY_EXISTS: already known", err.Error()) - m.ReceiveWg.Wait() + expectedErr := txpool_proto.ImportResult_name[int32(txpool_proto.ImportResult_ALREADY_EXISTS)] + ": " + txpoolcfg.AlreadyKnown.String() + require.Equal(expectedErr, err.Error()) + mockSentry.ReceiveWg.Wait() //TODO: make propagation easy to test - now race //time.Sleep(time.Second) @@ -107,6 +115,42 @@ func TestSendRawTransaction(t *testing.T) { //require.Equal(eth.ToProto[m.MultiClient.Protocol()][eth.NewPooledTransactionHashesMsg], sent.Id) } +func TestSendRawTransactionUnprotected(t *testing.T) { + mockSentry, require := mock.MockWithTxPool(t), require.New(t) + logger := log.New() + + oneBlockStep(mockSentry, require, t) + + expectedTxValue := uint64(4444) + + // Create a legacy signer pre-155 + unprotectedSigner := types.MakeFrontierSigner() + + txn, err := types.SignTx(types.NewTransaction(0, common.Address{1}, uint256.NewInt(expectedTxValue), params.TxGas, uint256.NewInt(10*params.GWei), nil), *unprotectedSigner, mockSentry.Key) + require.NoError(err) + + ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, mockSentry) + txPool := txpool.NewTxpoolClient(conn) + ff := rpchelper.New(ctx, nil, txPool, txpool.NewMiningClient(conn), func() {}, mockSentry.Log) + api := jsonrpc.NewEthAPI(newBaseApiForTest(mockSentry), mockSentry.DB, nil, txPool, nil, 5000000, 100_000, false, logger) + + // Enable unproteced txs flag + api.AllowUnprotectedTxs = true + + buf := bytes.NewBuffer(nil) + err = txn.MarshalBinary(buf) + require.NoError(err) + + txsCh, id := ff.SubscribePendingTxs(1) + defer ff.UnsubscribePendingTxs(id) + + _, err = api.SendRawTransaction(ctx, buf.Bytes()) + require.NoError(err) + + got := <-txsCh + require.Equal(expectedTxValue, got[0].GetValue().Uint64()) +} + func transaction(nonce uint64, gaslimit uint64, key *ecdsa.PrivateKey) types.Transaction { return pricedTransaction(nonce, gaslimit, u256.Num1, key) }