Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Commit

Permalink
rpc: eth_resend (#684)
Browse files Browse the repository at this point in the history
* Problem: missing json rpc for eth_resend #675

add unit test

restore

Update server/start.go

thanks~

Co-authored-by: Federico Kunze Küllmer <[email protected]>

tidy up checkTxFee

change comments

* fix lint

* Apply suggestions from code review

Co-authored-by: Federico Kunze Küllmer <[email protected]>
  • Loading branch information
leejw51crypto and fedekunze authored Oct 20, 2021
1 parent 40b3b9a commit f70e4c1
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 5 deletions.
9 changes: 8 additions & 1 deletion rpc/ethereum/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ import (
// Implemented by EVMBackend.
type Backend interface {
// General Ethereum API
RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
RPCTxFeeCap() float64 // RPCTxFeeCap is the global transaction fee(price * gaslimit) cap for, // send-transction variants. The unit is ether.

RPCMinGasPrice() int64
SuggestGasTipCap() (*big.Int, error)

Expand Down Expand Up @@ -779,6 +781,11 @@ func (e *EVMBackend) RPCGasCap() uint64 {
return e.cfg.JSONRPC.GasCap
}

// RPCGasCap is the global gas cap for eth-call variants.
func (e *EVMBackend) RPCTxFeeCap() float64 {
return e.cfg.JSONRPC.TxFeeCap
}

// RPCFilterCap is the limit for total number of filters that can be created
func (e *EVMBackend) RPCFilterCap() int32 {
return e.cfg.JSONRPC.FilterCap
Expand Down
35 changes: 35 additions & 0 deletions rpc/ethereum/namespaces/eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"

"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down Expand Up @@ -416,6 +417,7 @@ func (e *PublicAPI) FillTransaction(args evmtypes.TransactionArgs) (*rpctypes.Si

// Assemble the transaction and obtain rlp
tx := args.ToTransaction().AsTransaction()

data, err := tx.MarshalBinary()
if err != nil {
return nil, err
Expand Down Expand Up @@ -510,6 +512,26 @@ func (e *PublicAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error)
return txHash, nil
}

// checkTxFee is an internal function used to check whether the fee of
// the given transaction is _reasonable_(under the cap).
func checkTxFee(gasPrice *big.Int, gas uint64, cap float64) error {
// Short circuit if there is no cap for transaction fee at all.
if cap == 0 {
return nil
}
totalfee := new(big.Float).SetInt(new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(gas)))
// 1 photon in 10^18 aphoton
oneToken := new(big.Float).SetInt(big.NewInt(params.Ether))
// quo = rounded(x/y)
feeEth := new(big.Float).Quo(totalfee, oneToken)
// no need to check error from parsing
feeFloat, _ := feeEth.Float64()
if feeFloat > cap {
return fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, cap)
}
return nil
}

// Resend accepts an existing transaction and a new gas price and limit. It will remove
// the given transaction from the pool and reinsert it with the new gas price and limit.
func (e *PublicAPI) Resend(ctx context.Context, args evmtypes.TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) {
Expand All @@ -525,6 +547,19 @@ func (e *PublicAPI) Resend(ctx context.Context, args evmtypes.TransactionArgs, g

matchTx := args.ToTransaction().AsTransaction()

// Before replacing the old transaction, ensure the _new_ transaction fee is reasonable.
price := matchTx.GasPrice()
if gasPrice != nil {
price = gasPrice.ToInt()
}
gas := matchTx.Gas()
if gasLimit != nil {
gas = uint64(*gasLimit)
}
if err := checkTxFee(price, gas, e.backend.RPCTxFeeCap()); err != nil {
return common.Hash{}, err
}

pending, err := e.backend.PendingTransactions()
if err != nil {
return common.Hash{}, err
Expand Down
5 changes: 5 additions & 0 deletions server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const (
DefaultGasCap uint64 = 25000000

DefaultFilterCap int32 = 200

// default 1.0 eth
DefaultTxFeeCap float64 = 1.0
)

var evmTracers = []string{DefaultEVMTracer, "markdown", "struct", "access_list"}
Expand Down Expand Up @@ -61,6 +64,8 @@ type JSONRPCConfig struct {
WsAddress string `mapstructure:"ws-address"`
// GasCap is the global gas cap for eth-call variants.
GasCap uint64 `mapstructure:"gas-cap"`
// TxFeeCap is the global tx-fee cap for send transaction
TxFeeCap float64 `mapstructure:"txfee-cap"`
// FilterCap is the global cap for total number of filters that can be created.
FilterCap int32 `mapstructure:"filter-cap"`
// Enable defines if the EVM RPC server should be enabled.
Expand Down
1 change: 1 addition & 0 deletions server/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const (
JSONRPCAddress = "json-rpc.address"
JSONWsAddress = "json-rpc.ws-address"
JSONRPCGasCap = "json-rpc.gas-cap"
JSONRPCTxFeeCap = "json-rpc.txfee-cap"
JSONRPCFilterCap = "json-rpc.filter-cap"
)

Expand Down
5 changes: 3 additions & 2 deletions server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ which accepts a path for the resulting pprof file.
cmd.Flags().String(srvflags.Address, "tcp://0.0.0.0:26658", "Listen address")
cmd.Flags().String(srvflags.Transport, "socket", "Transport protocol: socket, grpc")
cmd.Flags().String(srvflags.TraceStore, "", "Enable KVStore tracing to an output file")
cmd.Flags().String(server.FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)")
cmd.Flags().String(server.FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photon;0.0001stake)")
cmd.Flags().IntSlice(server.FlagUnsafeSkipUpgrades, []int{}, "Skip a set of upgrade heights to continue the old binary")
cmd.Flags().Uint64(server.FlagHaltHeight, 0, "Block height at which to gracefully halt the chain and shutdown the node")
cmd.Flags().Uint64(server.FlagHaltTime, 0, "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node")
Expand All @@ -155,7 +155,8 @@ which accepts a path for the resulting pprof file.
cmd.Flags().StringSlice(srvflags.JSONRPCAPI, config.GetDefaultAPINamespaces(), "Defines a list of JSON-RPC namespaces that should be enabled")
cmd.Flags().String(srvflags.JSONRPCAddress, config.DefaultJSONRPCAddress, "the JSON-RPC server address to listen on")
cmd.Flags().String(srvflags.JSONWsAddress, config.DefaultJSONRPCWsAddress, "the JSON-RPC WS server address to listen on")
cmd.Flags().Uint64(srvflags.JSONRPCGasCap, config.DefaultGasCap, "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)")
cmd.Flags().Uint64(srvflags.JSONRPCGasCap, config.DefaultGasCap, "Sets a cap on gas that can be used in eth_call/estimateGas unit is aphoton (0=infinite)")
cmd.Flags().Float64(srvflags.JSONRPCTxFeeCap, config.DefaultTxFeeCap, "Sets a cap on transaction fee that can be sent via the RPC APIs (1 = default 1 photon)")
cmd.Flags().Int32(srvflags.JSONRPCFilterCap, config.DefaultFilterCap, "Sets the global cap for total number of filters that can be created")

cmd.Flags().String(srvflags.EVMTracer, config.DefaultEVMTracer, "the EVM tracer type to collect execution traces from the EVM transaction execution (json|struct|access_list|markdown)")
Expand Down
15 changes: 13 additions & 2 deletions tests/rpc/rpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,6 @@ func TestEth_GetStorageAt(t *testing.T) {
}

func TestEth_GetProof(t *testing.T) {

rpcRes := call(t, "eth_sendTransaction", makeEthTxParam())

var hash hexutil.Bytes
Expand Down Expand Up @@ -401,7 +400,6 @@ func TestEth_GetCode(t *testing.T) {
}

func TestEth_SendTransaction_Transfer(t *testing.T) {

rpcRes := call(t, "eth_sendTransaction", makeEthTxParam())

var hash hexutil.Bytes
Expand Down Expand Up @@ -1027,3 +1025,16 @@ func makeEthTxParam() []map[string]string {

return param
}

func TestEth_EthResend(t *testing.T) {
tx := make(map[string]string)
tx["from"] = "0x" + fmt.Sprintf("%x", from)
tx["to"] = "0x0000000000000000000000000000000012341234"
tx["value"] = "0x16345785d8a0000"
tx["nonce"] = "0x2"
tx["gasLimit"] = "0x5208"
tx["gasPrice"] = "0x55ae82600"
param := []interface{}{tx, "0x1", "0x2"}
_, rpcerror := callWithError("eth_resend", param)
require.Equal(t, "transaction 0x3bf28b46ee1bb3925e50ec6003f899f95913db4b0f579c4e7e887efebf9ecd1b not found", fmt.Sprintf("%s", rpcerror))
}

0 comments on commit f70e4c1

Please sign in to comment.