forked from ethereum-optimism/op-geth
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
eth_estimateGas
CIP-64 and CIP-66 compatibility (#91)
* rpc: include feeCurrency in transaction-args This commit fixes wrong gas calculation in `eth_estimateGas` calls, when the additional `feeCurrency` parameter is used. The TransactionArgs struct is used in transaction related endpoints like `eth_sendTransaction`, `eth_signTransaction`, `eth_estimateGas` and many more. CIP-64 and CIP-66 transaction types make use of an additional transaction parameter `feeCurrency` and some client libraries are already sending this in the RPC request body, however the remote procedures omitted this during unmarshaling and the value was never passed to the EVM. Now the TransactionArgs struct includes an optional FeeCurrency field for correct unmarshaling, and the field is passed along downstream when constructing EVM messages out of the struct. This e.g. allows gas estimation to consider the different intrinsic gas for transactions paid in non-native token. * Rename celoapi file * Add Backend wrapper for Celo functionality * Make transaction-args CIP-64/66 compatible * Make eth_estimateGas CIP64 and CIP66 compatible * Move error message inside function
- Loading branch information
Showing
15 changed files
with
410 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package celoapi | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"math/big" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/common/exchange" | ||
"github.com/ethereum/go-ethereum/common/hexutil" | ||
"github.com/ethereum/go-ethereum/contracts" | ||
"github.com/ethereum/go-ethereum/core" | ||
"github.com/ethereum/go-ethereum/internal/ethapi" | ||
) | ||
|
||
type Ethereum interface { | ||
BlockChain() *core.BlockChain | ||
} | ||
|
||
type CeloAPI struct { | ||
ethAPI *ethapi.EthereumAPI | ||
eth Ethereum | ||
} | ||
|
||
func NewCeloAPI(e Ethereum, b ethapi.CeloBackend) *CeloAPI { | ||
return &CeloAPI{ | ||
ethAPI: ethapi.NewEthereumAPI(b), | ||
eth: e, | ||
} | ||
} | ||
|
||
func (c *CeloAPI) convertedCurrencyValue(v *hexutil.Big, feeCurrency *common.Address) (*hexutil.Big, error) { | ||
if feeCurrency != nil { | ||
convertedTipCap, err := c.convertCeloToCurrency(v.ToInt(), feeCurrency) | ||
if err != nil { | ||
return nil, fmt.Errorf("convert to feeCurrency: %w", err) | ||
} | ||
v = (*hexutil.Big)(convertedTipCap) | ||
} | ||
return v, nil | ||
} | ||
|
||
func (c *CeloAPI) celoBackendCurrentState() (*contracts.CeloBackend, error) { | ||
state, err := c.eth.BlockChain().State() | ||
if err != nil { | ||
return nil, fmt.Errorf("retrieve HEAD blockchain state': %w", err) | ||
} | ||
|
||
cb := &contracts.CeloBackend{ | ||
ChainConfig: c.eth.BlockChain().Config(), | ||
State: state, | ||
} | ||
return cb, nil | ||
} | ||
|
||
func (c *CeloAPI) convertCeloToCurrency(nativePrice *big.Int, feeCurrency *common.Address) (*big.Int, error) { | ||
cb, err := c.celoBackendCurrentState() | ||
if err != nil { | ||
return nil, err | ||
} | ||
er, err := contracts.GetExchangeRates(cb) | ||
if err != nil { | ||
return nil, fmt.Errorf("retrieve exchange rates from current state: %w", err) | ||
} | ||
return exchange.ConvertCeloToCurrency(er, feeCurrency, nativePrice) | ||
} | ||
|
||
// GasPrice wraps the original JSON RPC `eth_gasPrice` and adds an additional | ||
// optional parameter `feeCurrency` for fee-currency conversion. | ||
// When `feeCurrency` is not given, then the original JSON RPC method is called without conversion. | ||
func (c *CeloAPI) GasPrice(ctx context.Context, feeCurrency *common.Address) (*hexutil.Big, error) { | ||
tipcap, err := c.ethAPI.GasPrice(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// Between the call to `ethapi.GasPrice` and the call to fetch and convert the rates, | ||
// there is a chance of a state-change. This means that gas-price suggestion is calculated | ||
// based on state of block x, while the currency conversion could be calculated based on block | ||
// x+1. | ||
// However, a similar race condition is present in the `ethapi.GasPrice` method itself. | ||
return c.convertedCurrencyValue(tipcap, feeCurrency) | ||
} | ||
|
||
// MaxPriorityFeePerGas wraps the original JSON RPC `eth_maxPriorityFeePerGas` and adds an additional | ||
// optional parameter `feeCurrency` for fee-currency conversion. | ||
// When `feeCurrency` is not given, then the original JSON RPC method is called without conversion. | ||
func (c *CeloAPI) MaxPriorityFeePerGas(ctx context.Context, feeCurrency *common.Address) (*hexutil.Big, error) { | ||
tipcap, err := c.ethAPI.MaxPriorityFeePerGas(ctx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// Between the call to `ethapi.MaxPriorityFeePerGas` and the call to fetch and convert the rates, | ||
// there is a chance of a state-change. This means that gas-price suggestion is calculated | ||
// based on state of block x, while the currency conversion could be calculated based on block | ||
// x+1. | ||
return c.convertedCurrencyValue(tipcap, feeCurrency) | ||
} |
Oops, something went wrong.