forked from cerc-io/laconicd-deprecated
imp(rpc): restrict unprotected txs on the node RPC (#1143)
* imp(rpc): restrict unprotected txs on the node RPC * lint * send raw transaction * c++
This commit is contained in:
+19
-14
@@ -44,16 +44,21 @@ const (
|
||||
)
|
||||
|
||||
// APICreator creates the JSON-RPC API implementations.
|
||||
type APICreator = func(*server.Context, client.Context, *rpcclient.WSClient) []rpc.API
|
||||
type APICreator = func(
|
||||
ctx *server.Context,
|
||||
clientCtx client.Context,
|
||||
tendermintWebsocketClient *rpcclient.WSClient,
|
||||
allowUnprotectedTxs bool,
|
||||
) []rpc.API
|
||||
|
||||
// apiCreators defines the JSON-RPC API namespaces.
|
||||
var apiCreators map[string]APICreator
|
||||
|
||||
func init() {
|
||||
apiCreators = map[string]APICreator{
|
||||
EthNamespace: func(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.API {
|
||||
EthNamespace: func(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, allowUnprotectedTxs bool) []rpc.API {
|
||||
nonceLock := new(types.AddrLocker)
|
||||
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx)
|
||||
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs)
|
||||
return []rpc.API{
|
||||
{
|
||||
Namespace: EthNamespace,
|
||||
@@ -69,7 +74,7 @@ func init() {
|
||||
},
|
||||
}
|
||||
},
|
||||
Web3Namespace: func(*server.Context, client.Context, *rpcclient.WSClient) []rpc.API {
|
||||
Web3Namespace: func(*server.Context, client.Context, *rpcclient.WSClient, bool) []rpc.API {
|
||||
return []rpc.API{
|
||||
{
|
||||
Namespace: Web3Namespace,
|
||||
@@ -79,7 +84,7 @@ func init() {
|
||||
},
|
||||
}
|
||||
},
|
||||
NetNamespace: func(_ *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
|
||||
NetNamespace: func(_ *server.Context, clientCtx client.Context, _ *rpcclient.WSClient, _ bool) []rpc.API {
|
||||
return []rpc.API{
|
||||
{
|
||||
Namespace: NetNamespace,
|
||||
@@ -89,8 +94,8 @@ func init() {
|
||||
},
|
||||
}
|
||||
},
|
||||
PersonalNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
|
||||
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx)
|
||||
PersonalNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient, allowUnprotectedTxs bool) []rpc.API {
|
||||
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs)
|
||||
return []rpc.API{
|
||||
{
|
||||
Namespace: PersonalNamespace,
|
||||
@@ -100,7 +105,7 @@ func init() {
|
||||
},
|
||||
}
|
||||
},
|
||||
TxPoolNamespace: func(ctx *server.Context, _ client.Context, _ *rpcclient.WSClient) []rpc.API {
|
||||
TxPoolNamespace: func(ctx *server.Context, _ client.Context, _ *rpcclient.WSClient, _ bool) []rpc.API {
|
||||
return []rpc.API{
|
||||
{
|
||||
Namespace: TxPoolNamespace,
|
||||
@@ -110,8 +115,8 @@ func init() {
|
||||
},
|
||||
}
|
||||
},
|
||||
DebugNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
|
||||
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx)
|
||||
DebugNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient, allowUnprotectedTxs bool) []rpc.API {
|
||||
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs)
|
||||
return []rpc.API{
|
||||
{
|
||||
Namespace: DebugNamespace,
|
||||
@@ -121,8 +126,8 @@ func init() {
|
||||
},
|
||||
}
|
||||
},
|
||||
MinerNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
|
||||
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx)
|
||||
MinerNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient, allowUnprotectedTxs bool) []rpc.API {
|
||||
evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs)
|
||||
return []rpc.API{
|
||||
{
|
||||
Namespace: MinerNamespace,
|
||||
@@ -136,12 +141,12 @@ func init() {
|
||||
}
|
||||
|
||||
// GetRPCAPIs returns the list of all APIs
|
||||
func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, selectedAPIs []string) []rpc.API {
|
||||
func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, allowUnprotectedTxs bool, selectedAPIs []string) []rpc.API {
|
||||
var apis []rpc.API
|
||||
|
||||
for _, ns := range selectedAPIs {
|
||||
if creator, ok := apiCreators[ns]; ok {
|
||||
apis = append(apis, creator(ctx, clientCtx, tmWSClient)...)
|
||||
apis = append(apis, creator(ctx, clientCtx, tmWSClient, allowUnprotectedTxs)...)
|
||||
} else {
|
||||
ctx.Logger.Error("invalid namespace value", "namespace", ns)
|
||||
}
|
||||
|
||||
+16
-13
@@ -44,6 +44,7 @@ type EVMBackend interface {
|
||||
RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
|
||||
RPCEVMTimeout() time.Duration // global timeout for eth_call over rpc: DoS protection
|
||||
RPCTxFeeCap() float64 // RPCTxFeeCap is the global transaction fee(price * gaslimit) cap for send-transaction variants. The unit is ether.
|
||||
UnprotectedAllowed() bool
|
||||
|
||||
RPCMinGasPrice() int64
|
||||
SuggestGasTipCap(baseFee *big.Int) (*big.Int, error)
|
||||
@@ -86,16 +87,17 @@ var _ BackendI = (*Backend)(nil)
|
||||
|
||||
// Backend implements the BackendI interface
|
||||
type Backend struct {
|
||||
ctx context.Context
|
||||
clientCtx client.Context
|
||||
queryClient *types.QueryClient // gRPC query client
|
||||
logger log.Logger
|
||||
chainID *big.Int
|
||||
cfg config.Config
|
||||
ctx context.Context
|
||||
clientCtx client.Context
|
||||
queryClient *types.QueryClient // gRPC query client
|
||||
logger log.Logger
|
||||
chainID *big.Int
|
||||
cfg config.Config
|
||||
allowUnprotectedTxs bool
|
||||
}
|
||||
|
||||
// NewBackend creates a new Backend instance for cosmos and ethereum namespaces
|
||||
func NewBackend(ctx *server.Context, logger log.Logger, clientCtx client.Context) *Backend {
|
||||
func NewBackend(ctx *server.Context, logger log.Logger, clientCtx client.Context, allowUnprotectedTxs bool) *Backend {
|
||||
chainID, err := ethermint.ParseChainID(clientCtx.ChainID)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -104,11 +106,12 @@ func NewBackend(ctx *server.Context, logger log.Logger, clientCtx client.Context
|
||||
appConf := config.GetConfig(ctx.Viper)
|
||||
|
||||
return &Backend{
|
||||
ctx: context.Background(),
|
||||
clientCtx: clientCtx,
|
||||
queryClient: types.NewQueryClient(clientCtx),
|
||||
logger: logger.With("module", "backend"),
|
||||
chainID: chainID,
|
||||
cfg: appConf,
|
||||
ctx: context.Background(),
|
||||
clientCtx: clientCtx,
|
||||
queryClient: types.NewQueryClient(clientCtx),
|
||||
logger: logger.With("module", "backend"),
|
||||
chainID: chainID,
|
||||
cfg: appConf,
|
||||
allowUnprotectedTxs: allowUnprotectedTxs,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -638,7 +638,15 @@ func (b *Backend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, e
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
txHash := msg.AsTransaction().Hash()
|
||||
ethTx := msg.AsTransaction()
|
||||
|
||||
// check the local node config in case unprotected txs are disabled
|
||||
if !b.UnprotectedAllowed() && !ethTx.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")
|
||||
}
|
||||
|
||||
txHash := ethTx.Hash()
|
||||
|
||||
// Broadcast transaction in sync mode (default)
|
||||
// NOTE: If error is encountered on the node, the broadcast will not return an error
|
||||
@@ -956,3 +964,9 @@ func (b *Backend) GetEthereumMsgsFromTendermintBlock(resBlock *tmrpctypes.Result
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// UnprotectedAllowed returns the node configuration value for allowing
|
||||
// unprotected transactions (i.e not replay-protected)
|
||||
func (b Backend) UnprotectedAllowed() bool {
|
||||
return b.allowUnprotectedTxs
|
||||
}
|
||||
|
||||
@@ -525,6 +525,12 @@ func (e *PublicAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error)
|
||||
return common.Hash{}, err
|
||||
}
|
||||
|
||||
// check the local node config in case unprotected txs are disabled
|
||||
if !e.backend.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")
|
||||
}
|
||||
|
||||
ethereumTx := &evmtypes.MsgEthereumTx{}
|
||||
if err := ethereumTx.FromEthereumTx(tx); err != nil {
|
||||
e.logger.Error("transaction converting failed", "error", err.Error())
|
||||
|
||||
Reference in New Issue
Block a user