diff --git a/cmd/XDC/main.go b/cmd/XDC/main.go index 7169f1decd92..92b131ee003e 100644 --- a/cmd/XDC/main.go +++ b/cmd/XDC/main.go @@ -161,6 +161,7 @@ var ( utils.IPCDisabledFlag, utils.IPCPathFlag, utils.RPCGlobalTxFeeCap, + utils.AllowUnprotectedTxs, } metricsFlags = []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 97b2490270fa..3f31900ac445 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -546,6 +546,11 @@ var ( Usage: "Comma separated list of JavaScript files to preload into the console", Category: flags.APICategory, } + AllowUnprotectedTxs = &cli.BoolFlag{ + Name: "rpc.allow-unprotected-txs", + Usage: "Allow for unprotected (non EIP155 signed) transactions to be submitted via RPC", + Category: flags.APICategory, + } // Network Settings MaxPeersFlag = &cli.IntFlag{ @@ -1014,6 +1019,9 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) { if ctx.IsSet(HTTPIdleTimeoutFlag.Name) { cfg.HTTPTimeouts.IdleTimeout = ctx.Duration(HTTPIdleTimeoutFlag.Name) } + if ctx.IsSet(AllowUnprotectedTxs.Name) { + cfg.AllowUnprotectedTxs = ctx.Bool(AllowUnprotectedTxs.Name) + } cfg.HTTPCors = SplitAndTrim(ctx.String(HTTPCORSDomainFlag.Name)) cfg.HTTPModules = SplitAndTrim(ctx.String(HTTPApiFlag.Name)) cfg.HTTPVirtualHosts = SplitAndTrim(ctx.String(HTTPVirtualHostsFlag.Name)) diff --git a/eth/api_backend.go b/eth/api_backend.go index f549ddafd636..36394ce24fda 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -54,9 +54,10 @@ import ( // EthAPIBackend implements ethapi.Backend for full nodes type EthAPIBackend struct { - eth *Ethereum - gpo *gasprice.Oracle - XDPoS *XDPoS.XDPoS + allowUnprotectedTxs bool + eth *Ethereum + gpo *gasprice.Oracle + XDPoS *XDPoS.XDPoS } func (b *EthAPIBackend) ChainConfig() *params.ChainConfig { @@ -369,6 +370,10 @@ func (b *EthAPIBackend) EventMux() *event.TypeMux { return b.eth.EventMux() } +func (b *EthAPIBackend) UnprotectedAllowed() bool { + return b.allowUnprotectedTxs +} + func (b *EthAPIBackend) RPCGasCap() uint64 { return b.eth.config.RPCGasCap } diff --git a/eth/backend.go b/eth/backend.go index e7f459916bb7..9fb7db42e57f 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -244,10 +244,19 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine, stack.Config().AnnounceTxs) eth.miner.SetExtra(makeExtraData(config.ExtraData)) + var xdPoS *XDPoS.XDPoS = nil if eth.chainConfig.XDPoS != nil { - eth.ApiBackend = &EthAPIBackend{eth, nil, eth.engine.(*XDPoS.XDPoS)} - } else { - eth.ApiBackend = &EthAPIBackend{eth, nil, nil} + xdPoS = eth.engine.(*XDPoS.XDPoS) + } + eth.ApiBackend = &EthAPIBackend{ + allowUnprotectedTxs: stack.Config().AllowUnprotectedTxs, + eth: eth, + gpo: nil, + XDPoS: xdPoS, + } + + if eth.ApiBackend.allowUnprotectedTxs { + log.Info("Unprotected transactions allowed") } eth.ApiBackend.gpo = gasprice.NewOracle(eth.ApiBackend, config.GPO, config.GasPrice) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 3ea76f261456..26f4e108971f 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -2304,6 +2304,10 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c if err := checkTxFee(tx.GasPrice(), tx.Gas(), b.RPCTxFeeCap()); err != nil { return common.Hash{}, err } + if !b.UnprotectedAllowed() && !tx.Protected() { + // Ensure only eip155 signed transactions are submitted if EIP155Required is set. + return common.Hash{}, errors.New("only replay-protected (EIP-155) transactions allowed over RPC") + } if err := b.SendTx(ctx, tx); err != nil { return common.Hash{}, err } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index b1d81e64e7b4..5fe84d22227a 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -51,8 +51,10 @@ type Backend interface { BlobBaseFee(ctx context.Context) *big.Int ChainDb() ethdb.Database AccountManager() *accounts.Manager - RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection - RPCTxFeeCap() float64 // global tx fee cap for all transaction related APIs + RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection + RPCTxFeeCap() float64 // global tx fee cap for all transaction related APIs + UnprotectedAllowed() bool // allows only for EIP155 transactions. + XDCxService() *XDCx.XDCX LendingService() *XDCxlending.Lending diff --git a/node/config.go b/node/config.go index fafccf3eb49b..7ea8e4d35eb0 100644 --- a/node/config.go +++ b/node/config.go @@ -171,6 +171,9 @@ type Config struct { oldGethResourceWarning bool AnnounceTxs bool `toml:",omitempty"` + + // AllowUnprotectedTxs allows non EIP-155 protected transactions to be send over RPC. + AllowUnprotectedTxs bool `toml:",omitempty"` } // IPCEndpoint resolves an IPC endpoint based on a configured value, taking into diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go index e4245f420daf..5166f648ec69 100644 --- a/node/rpcstack_test.go +++ b/node/rpcstack_test.go @@ -258,7 +258,7 @@ func baseRpcRequest(t *testing.T, url, bodyStr string, extraHeaders ...string) * // Create the request. body := bytes.NewReader([]byte(bodyStr)) - req, err := http.NewRequest("POST", url, body) + req, err := http.NewRequest(http.MethodPost, url, body) if err != nil { t.Fatal("could not create http request:", err) }