cmd, eth, internal, les: add txfee cap (#21212)

* cmd, eth, internal, les: add gasprice cap

* cmd/utils, eth: add default value for gasprice cap

* all: use txfee cap

* cmd, eth: add fix

* cmd, internal: address comments
This commit is contained in:
gary rong 2020-06-17 15:46:31 +08:00 committed by GitHub
parent bcf19bc4be
commit 56a319b9da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 44 additions and 5 deletions

View File

@ -186,6 +186,7 @@ var (
utils.IPCPathFlag, utils.IPCPathFlag,
utils.InsecureUnlockAllowedFlag, utils.InsecureUnlockAllowedFlag,
utils.RPCGlobalGasCap, utils.RPCGlobalGasCap,
utils.RPCGlobalTxFeeCap,
} }
whisperFlags = []cli.Flag{ whisperFlags = []cli.Flag{

View File

@ -176,6 +176,7 @@ var AppHelpFlagGroups = []flagGroup{
utils.GraphQLCORSDomainFlag, utils.GraphQLCORSDomainFlag,
utils.GraphQLVirtualHostsFlag, utils.GraphQLVirtualHostsFlag,
utils.RPCGlobalGasCap, utils.RPCGlobalGasCap,
utils.RPCGlobalTxFeeCap,
utils.JSpathFlag, utils.JSpathFlag,
utils.ExecFlag, utils.ExecFlag,
utils.PreloadJSFlag, utils.PreloadJSFlag,

View File

@ -478,6 +478,11 @@ var (
Name: "rpc.gascap", Name: "rpc.gascap",
Usage: "Sets a cap on gas that can be used in eth_call/estimateGas", Usage: "Sets a cap on gas that can be used in eth_call/estimateGas",
} }
RPCGlobalTxFeeCap = cli.Float64Flag{
Name: "rpc.txfeecap",
Usage: "Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)",
Value: eth.DefaultConfig.RPCTxFeeCap,
}
// Logging and debug settings // Logging and debug settings
EthStatsURLFlag = cli.StringFlag{ EthStatsURLFlag = cli.StringFlag{
Name: "ethstats", Name: "ethstats",
@ -1560,6 +1565,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
if ctx.GlobalIsSet(RPCGlobalGasCap.Name) { if ctx.GlobalIsSet(RPCGlobalGasCap.Name) {
cfg.RPCGasCap = new(big.Int).SetUint64(ctx.GlobalUint64(RPCGlobalGasCap.Name)) cfg.RPCGasCap = new(big.Int).SetUint64(ctx.GlobalUint64(RPCGlobalGasCap.Name))
} }
if ctx.GlobalIsSet(RPCGlobalTxFeeCap.Name) {
cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCap.Name)
}
if ctx.GlobalIsSet(DNSDiscoveryFlag.Name) { if ctx.GlobalIsSet(DNSDiscoveryFlag.Name) {
urls := ctx.GlobalString(DNSDiscoveryFlag.Name) urls := ctx.GlobalString(DNSDiscoveryFlag.Name)
if urls == "" { if urls == "" {

View File

@ -293,6 +293,10 @@ func (b *EthAPIBackend) RPCGasCap() *big.Int {
return b.eth.config.RPCGasCap return b.eth.config.RPCGasCap
} }
func (b *EthAPIBackend) RPCTxFeeCap() float64 {
return b.eth.config.RPCTxFeeCap
}
func (b *EthAPIBackend) BloomStatus() (uint64, uint64) { func (b *EthAPIBackend) BloomStatus() (uint64, uint64) {
sections, _, _ := b.eth.bloomIndexer.Sections() sections, _, _ := b.eth.bloomIndexer.Sections()
return params.BloomBitsBlocks, sections return params.BloomBitsBlocks, sections

View File

@ -64,6 +64,7 @@ var DefaultConfig = Config{
Blocks: 20, Blocks: 20,
Percentile: 60, Percentile: 60,
}, },
RPCTxFeeCap: 1, // 1 ether
} }
func init() { func init() {
@ -159,6 +160,10 @@ type Config struct {
// RPCGasCap is the global gas cap for eth-call variants. // RPCGasCap is the global gas cap for eth-call variants.
RPCGasCap *big.Int `toml:",omitempty"` RPCGasCap *big.Int `toml:",omitempty"`
// RPCTxFeeCap is the global transaction fee(price * gaslimit) cap for
// send-transction variants. The unit is ether.
RPCTxFeeCap float64 `toml:",omitempty"`
// Checkpoint is a hardcoded checkpoint which can be nil. // Checkpoint is a hardcoded checkpoint which can be nil.
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`

View File

@ -40,6 +40,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
TrieCleanCache int TrieCleanCache int
TrieDirtyCache int TrieDirtyCache int
TrieTimeout time.Duration TrieTimeout time.Duration
SnapshotCache int
Miner miner.Config Miner miner.Config
Ethash ethash.Config Ethash ethash.Config
TxPool core.TxPoolConfig TxPool core.TxPoolConfig
@ -49,10 +50,9 @@ func (c Config) MarshalTOML() (interface{}, error) {
EWASMInterpreter string EWASMInterpreter string
EVMInterpreter string EVMInterpreter string
RPCGasCap *big.Int `toml:",omitempty"` RPCGasCap *big.Int `toml:",omitempty"`
RPCTxFeeCap float64 `toml:",omitempty"`
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
OverrideIstanbul *big.Int `toml:",omitempty"`
OverrideMuirGlacier *big.Int `toml:",omitempty"`
} }
var enc Config var enc Config
enc.Genesis = c.Genesis enc.Genesis = c.Genesis
@ -77,6 +77,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.TrieCleanCache = c.TrieCleanCache enc.TrieCleanCache = c.TrieCleanCache
enc.TrieDirtyCache = c.TrieDirtyCache enc.TrieDirtyCache = c.TrieDirtyCache
enc.TrieTimeout = c.TrieTimeout enc.TrieTimeout = c.TrieTimeout
enc.SnapshotCache = c.SnapshotCache
enc.Miner = c.Miner enc.Miner = c.Miner
enc.Ethash = c.Ethash enc.Ethash = c.Ethash
enc.TxPool = c.TxPool enc.TxPool = c.TxPool
@ -86,6 +87,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.EWASMInterpreter = c.EWASMInterpreter enc.EWASMInterpreter = c.EWASMInterpreter
enc.EVMInterpreter = c.EVMInterpreter enc.EVMInterpreter = c.EVMInterpreter
enc.RPCGasCap = c.RPCGasCap enc.RPCGasCap = c.RPCGasCap
enc.RPCTxFeeCap = c.RPCTxFeeCap
enc.Checkpoint = c.Checkpoint enc.Checkpoint = c.Checkpoint
enc.CheckpointOracle = c.CheckpointOracle enc.CheckpointOracle = c.CheckpointOracle
return &enc, nil return &enc, nil
@ -116,6 +118,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
TrieCleanCache *int TrieCleanCache *int
TrieDirtyCache *int TrieDirtyCache *int
TrieTimeout *time.Duration TrieTimeout *time.Duration
SnapshotCache *int
Miner *miner.Config Miner *miner.Config
Ethash *ethash.Config Ethash *ethash.Config
TxPool *core.TxPoolConfig TxPool *core.TxPoolConfig
@ -125,10 +128,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
EWASMInterpreter *string EWASMInterpreter *string
EVMInterpreter *string EVMInterpreter *string
RPCGasCap *big.Int `toml:",omitempty"` RPCGasCap *big.Int `toml:",omitempty"`
RPCTxFeeCap *float64 `toml:",omitempty"`
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
OverrideIstanbul *big.Int `toml:",omitempty"`
OverrideMuirGlacier *big.Int `toml:",omitempty"`
} }
var dec Config var dec Config
if err := unmarshal(&dec); err != nil { if err := unmarshal(&dec); err != nil {
@ -200,6 +202,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.TrieTimeout != nil { if dec.TrieTimeout != nil {
c.TrieTimeout = *dec.TrieTimeout c.TrieTimeout = *dec.TrieTimeout
} }
if dec.SnapshotCache != nil {
c.SnapshotCache = *dec.SnapshotCache
}
if dec.Miner != nil { if dec.Miner != nil {
c.Miner = *dec.Miner c.Miner = *dec.Miner
} }
@ -227,6 +232,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.RPCGasCap != nil { if dec.RPCGasCap != nil {
c.RPCGasCap = dec.RPCGasCap c.RPCGasCap = dec.RPCGasCap
} }
if dec.RPCTxFeeCap != nil {
c.RPCTxFeeCap = *dec.RPCTxFeeCap
}
if dec.Checkpoint != nil { if dec.Checkpoint != nil {
c.Checkpoint = dec.Checkpoint c.Checkpoint = dec.Checkpoint
} }

View File

@ -1520,6 +1520,13 @@ func (args *SendTxArgs) toTransaction() *types.Transaction {
// SubmitTransaction is a helper function that submits tx to txPool and logs a message. // SubmitTransaction is a helper function that submits tx to txPool and logs a message.
func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) { func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) {
// If the transaction fee cap is already specified, ensure the
// fee of the given transaction is _reasonable_.
feeEth := new(big.Float).Quo(new(big.Float).SetInt(new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas()))), new(big.Float).SetInt(big.NewInt(params.Ether)))
feeFloat, _ := feeEth.Float64()
if b.RPCTxFeeCap() != 0 && feeFloat > b.RPCTxFeeCap() {
return common.Hash{}, fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, b.RPCTxFeeCap())
}
if err := b.SendTx(ctx, tx); err != nil { if err := b.SendTx(ctx, tx); err != nil {
return common.Hash{}, err return common.Hash{}, err
} }

View File

@ -45,7 +45,8 @@ type Backend interface {
ChainDb() ethdb.Database ChainDb() ethdb.Database
AccountManager() *accounts.Manager AccountManager() *accounts.Manager
ExtRPCEnabled() bool ExtRPCEnabled() bool
RPCGasCap() *big.Int // global gas cap for eth_call over rpc: DoS protection RPCGasCap() *big.Int // global gas cap for eth_call over rpc: DoS protection
RPCTxFeeCap() float64 // global tx fee cap for all transaction related APIs
// Blockchain API // Blockchain API
SetHead(number uint64) SetHead(number uint64)

View File

@ -262,6 +262,10 @@ func (b *LesApiBackend) RPCGasCap() *big.Int {
return b.eth.config.RPCGasCap return b.eth.config.RPCGasCap
} }
func (b *LesApiBackend) RPCTxFeeCap() float64 {
return b.eth.config.RPCTxFeeCap
}
func (b *LesApiBackend) BloomStatus() (uint64, uint64) { func (b *LesApiBackend) BloomStatus() (uint64, uint64) {
if b.eth.bloomIndexer == nil { if b.eth.bloomIndexer == nil {
return 0, 0 return 0, 0