mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 14:16:44 +00:00
accounts/abi/bind: call gas limit and transact gas tuning
This commit is contained in:
parent
2c6be49d20
commit
77d47ce651
2 changed files with 84 additions and 5 deletions
|
|
@ -33,9 +33,15 @@ import (
|
||||||
// sign the transaction before submission.
|
// sign the transaction before submission.
|
||||||
type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error)
|
type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error)
|
||||||
|
|
||||||
|
// GasTunerFn is a callback function to modify the gas limit of a transaction
|
||||||
|
// estimated by the backend node. It's purpose is to allow providing some wiggle
|
||||||
|
// room for approximate estimations and/or concurrent state changes.
|
||||||
|
type GasTunerFn func(gas *big.Int) *big.Int
|
||||||
|
|
||||||
// CallOpts is the collection of options to fine tune a contract call request.
|
// CallOpts is the collection of options to fine tune a contract call request.
|
||||||
type CallOpts struct {
|
type CallOpts struct {
|
||||||
Pending bool // Whether to operate on the pending state or the last known one
|
Pending bool // Whether to operate on the pending state or the last known one
|
||||||
|
GasLimit *big.Int // Gas limit allowance of the call operation (nil = use backend default)
|
||||||
|
|
||||||
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
||||||
}
|
}
|
||||||
|
|
@ -47,9 +53,10 @@ type TransactOpts struct {
|
||||||
Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state)
|
Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state)
|
||||||
Signer SignerFn // Method to use for signing the transaction (mandatory)
|
Signer SignerFn // Method to use for signing the transaction (mandatory)
|
||||||
|
|
||||||
Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds)
|
Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds)
|
||||||
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
|
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
|
||||||
GasLimit *big.Int // Gas limit to set for the transaction execution (nil = estimate + 10%)
|
GasLimit *big.Int // Gas limit to set for the transaction execution (nil = estimate)
|
||||||
|
GasTuner GasTunerFn // Modifier for the gas limit estimated by the node (nil = identity)
|
||||||
|
|
||||||
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +115,7 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
msg = ethereum.CallMsg{To: &c.address, Data: input}
|
msg = ethereum.CallMsg{To: &c.address, Data: input, Gas: opts.GasLimit}
|
||||||
ctx = ensureContext(opts.Context)
|
ctx = ensureContext(opts.Context)
|
||||||
code []byte
|
code []byte
|
||||||
output []byte
|
output []byte
|
||||||
|
|
@ -203,6 +210,12 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to estimate gas needed: %v", err)
|
return nil, fmt.Errorf("failed to estimate gas needed: %v", err)
|
||||||
}
|
}
|
||||||
|
// If custom gas estimation post-processing was requested, execute it
|
||||||
|
if opts.GasTuner != nil {
|
||||||
|
if gasLimit = opts.GasTuner(gasLimit); gasLimit == nil {
|
||||||
|
return nil, fmt.Errorf("gas tuner returned nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Create the transaction, sign it and schedule it for execution
|
// Create the transaction, sign it and schedule it for execution
|
||||||
var rawTx *types.Transaction
|
var rawTx *types.Transaction
|
||||||
|
|
|
||||||
|
|
@ -365,6 +365,72 @@ var bindTests = []struct {
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
// Tests that gas limits can be configured for calls, transacts and also estimation tunings
|
||||||
|
{
|
||||||
|
`GasLimiter`,
|
||||||
|
`
|
||||||
|
contract GasLimiter {
|
||||||
|
string public field;
|
||||||
|
|
||||||
|
function SetField(string value) {
|
||||||
|
// This check will screw gas estimation! Good, good!
|
||||||
|
if (msg.gas < 100000) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
field = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
`606060405261021c806100126000396000f3606060405260e060020a600035046323fcf32a81146100265780634f28bf0e1461007b575b005b6040805160206004803580820135601f8101849004840285018401909552848452610024949193602493909291840191908190840183828082843750949650505050505050620186a05a101561014e57610002565b6100db60008054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281529291908301828280156102145780601f106101e957610100808354040283529160200191610214565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561013b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b505050565b8060006000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106101b557805160ff19168380011785555b506101499291505b808211156101e557600081556001016101a1565b82800160010185558215610199579182015b828111156101995782518260005055916020019190600101906101c7565b5090565b820191906000526020600020905b8154815290600101906020018083116101f757829003601f168201915b50505050508156`,
|
||||||
|
`[{"constant":false,"inputs":[{"name":"value","type":"string"}],"name":"SetField","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"field","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
|
||||||
|
`
|
||||||
|
// Generate a new random account and a funded simulator
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
auth := bind.NewKeyedTransactor(key)
|
||||||
|
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)})
|
||||||
|
|
||||||
|
// Deploy a gas limiter contract and check that estimation fails miserably indeed
|
||||||
|
_, _, limiter, err := DeployGasLimiter(auth, sim)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to deploy limiter contract: %v", err)
|
||||||
|
}
|
||||||
|
sim.Commit()
|
||||||
|
|
||||||
|
if _, err := limiter.SetField(auth, "abc"); err != nil {
|
||||||
|
t.Fatalf("Failed to call bad gased transaction: %v", err)
|
||||||
|
}
|
||||||
|
sim.Commit()
|
||||||
|
|
||||||
|
if field, _ := limiter.Field(nil); field != "" {
|
||||||
|
t.Fatalf("Field mismatch: have %v, want %v", field, "")
|
||||||
|
}
|
||||||
|
// Set the field with a manual high gas limit and check that it succeeds
|
||||||
|
auth.GasLimit = big.NewInt(200000)
|
||||||
|
if _, err := limiter.SetField(auth, "manual"); err != nil {
|
||||||
|
t.Fatalf("Failed to call bad gased transaction: %v", err)
|
||||||
|
}
|
||||||
|
sim.Commit()
|
||||||
|
|
||||||
|
if field, _ := limiter.Field(nil); field != "manual" {
|
||||||
|
t.Fatalf("Field mismatch: have %v, want %v", field, "manual")
|
||||||
|
}
|
||||||
|
// Set the field with a tuned estimation and chck that it succeeds
|
||||||
|
auth.GasLimit = nil
|
||||||
|
auth.GasTuner = func(gas *big.Int) *big.Int { return new(big.Int).Add(gas, big.NewInt(100000)) }
|
||||||
|
if _, err := limiter.SetField(auth, "tuned"); err != nil {
|
||||||
|
t.Fatalf("Failed to call bad gased transaction: %v", err)
|
||||||
|
}
|
||||||
|
sim.Commit()
|
||||||
|
|
||||||
|
if field, _ := limiter.Field(nil); field != "tuned" {
|
||||||
|
t.Fatalf("Field mismatch: have %v, want %v", field, "tuned")
|
||||||
|
}
|
||||||
|
// Check that manual CALL limiting also works
|
||||||
|
if _, err := limiter.Field(&bind.CallOpts{GasLimit: big.NewInt(21000)}); err == nil {
|
||||||
|
t.Fatalf("Gas limited CALL didn't go out of gas")
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that packages generated by the binder can be successfully compiled and
|
// Tests that packages generated by the binder can be successfully compiled and
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue