rpc: geth v1.10.9 changes (#624)

* rpc: geth v1.10.9 changes

* updates

* suggestGasTipCap

* update gRPC

* resend

* fixes

* rm unused func

* address TODO
This commit is contained in:
Federico Kunze Küllmer
2021-10-06 11:22:32 +00:00
committed by GitHub
parent 202bc5f1cd
commit bcdb982886
17 changed files with 427 additions and 221 deletions
+161 -13
View File
@@ -8,6 +8,7 @@ import (
"strings"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/rpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@@ -45,6 +46,7 @@ type PublicAPI struct {
logger log.Logger
backend backend.Backend
nonceLock *rpctypes.AddrLocker
signer ethtypes.Signer
}
// NewPublicAPI creates an instance of the public ETH Web3 API.
@@ -76,6 +78,10 @@ func NewPublicAPI(
clientCtx = clientCtx.WithKeyring(kr)
}
// The signer used by the API should always be the 'latest' known one because we expect
// signers to be backwards-compatible with old transactions.
signer := ethtypes.LatestSigner(backend.ChainConfig())
api := &PublicAPI{
ctx: context.Background(),
clientCtx: clientCtx,
@@ -84,6 +90,7 @@ func NewPublicAPI(
logger: logger.With("client", "json-rpc"),
backend: backend,
nonceLock: nonceLock,
signer: signer,
}
return api
@@ -108,14 +115,30 @@ func (e *PublicAPI) ProtocolVersion() hexutil.Uint {
return hexutil.Uint(ethermint.ProtocolVersion)
}
// ChainId returns the chain's identifier in hex format
func (e *PublicAPI) ChainId() (hexutil.Uint, error) { // nolint
// ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config.
func (e *PublicAPI) ChainId() (*hexutil.Big, error) { // nolint
e.logger.Debug("eth_chainId")
return hexutil.Uint(uint(e.chainIDEpoch.Uint64())), nil
// if current block is at or past the EIP-155 replay-protection fork block, return chainID from config
bn, err := e.backend.BlockNumber()
if err != nil {
e.logger.Debug("failed to fetch latest block number", "error", err.Error())
return (*hexutil.Big)(e.chainIDEpoch), nil
}
if config := e.backend.ChainConfig(); config.IsEIP155(new(big.Int).SetUint64(uint64(bn))) {
return (*hexutil.Big)(config.ChainID), nil
}
return nil, fmt.Errorf("chain not synced beyond EIP-155 replay-protection fork block")
}
// Syncing returns whether or not the current node is syncing with other peers. Returns false if not, or a struct
// outlining the state of the sync if it is.
// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not
// yet received the latest block headers from its pears. In case it is synchronizing:
// - startingBlock: block number this node started to synchronize from
// - currentBlock: block number this node is currently importing
// - highestBlock: block number of the highest block header this node has received from peers
// - pulledStates: number of state entries processed until now
// - knownStates: number of known state entries that still need to be pulled
func (e *PublicAPI) Syncing() (interface{}, error) {
e.logger.Debug("eth_syncing")
@@ -129,8 +152,8 @@ func (e *PublicAPI) Syncing() (interface{}, error) {
}
return map[string]interface{}{
// "startingBlock": nil, // NA
"currentBlock": hexutil.Uint64(status.SyncInfo.LatestBlockHeight),
"startingBlock": hexutil.Uint64(status.SyncInfo.EarliestBlockHeight),
"currentBlock": hexutil.Uint64(status.SyncInfo.LatestBlockHeight),
// "highestBlock": nil, // NA
// "pulledStates": nil, // NA
// "knownStates": nil, // NA
@@ -162,10 +185,35 @@ func (e *PublicAPI) Hashrate() hexutil.Uint64 {
}
// GasPrice returns the current gas price based on Ethermint's gas price oracle.
func (e *PublicAPI) GasPrice() *hexutil.Big {
func (e *PublicAPI) GasPrice() (*hexutil.Big, error) {
e.logger.Debug("eth_gasPrice")
out := new(big.Int).SetInt64(e.backend.RPCMinGasPrice())
return (*hexutil.Big)(out)
tipcap, err := e.backend.SuggestGasTipCap()
if err != nil {
return nil, err
}
if head := e.backend.CurrentHeader(); head.BaseFee != nil {
tipcap.Add(tipcap, head.BaseFee)
}
return (*hexutil.Big)(tipcap), nil
}
// MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions.
func (e *PublicAPI) MaxPriorityFeePerGas() (*hexutil.Big, error) {
e.logger.Debug("eth_maxPriorityFeePerGas")
tipcap, err := e.backend.SuggestGasTipCap()
if err != nil {
return nil, err
}
return (*hexutil.Big)(tipcap), nil
}
func (e *PublicAPI) FeeHistory(blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*rpctypes.FeeHistoryResult, error) {
e.logger.Debug("eth_feeHistory")
return nil, fmt.Errorf("eth_feeHistory not implemented")
}
// Accounts returns the list of accounts available to this node.
@@ -355,6 +403,29 @@ func (e *PublicAPI) SendTransaction(args evmtypes.TransactionArgs) (common.Hash,
return e.backend.SendTransaction(args)
}
// FillTransaction fills the defaults (nonce, gas, gasPrice or 1559 fields)
// on a given unsigned transaction, and returns it to the caller for further
// processing (signing + broadcast).
func (e *PublicAPI) FillTransaction(args evmtypes.TransactionArgs) (*rpctypes.SignTransactionResult, error) {
// Set some sanity defaults and terminate on failure
args, err := e.backend.SetTxDefaults(args)
if err != nil {
return nil, err
}
// Assemble the transaction and obtain rlp
tx := args.ToTransaction().AsTransaction()
data, err := tx.MarshalBinary()
if err != nil {
return nil, err
}
return &rpctypes.SignTransactionResult{
Raw: data,
Tx: tx,
}, nil
}
// SendRawTransaction send a raw Ethereum transaction.
func (e *PublicAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) {
e.logger.Debug("eth_sendRawTransaction", "length", len(data))
@@ -407,7 +478,12 @@ func (e *PublicAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error)
return common.Hash{}, err
}
fees := sdk.Coins{sdk.NewCoin(res.Params.EvmDenom, sdk.NewIntFromBigInt(txData.Fee()))}
fees := sdk.Coins{
{
Denom: res.Params.EvmDenom,
Amount: sdk.NewIntFromBigInt(txData.Fee()),
},
}
builder.SetFeeAmount(fees)
builder.SetGasLimit(ethereumTx.GetGas())
@@ -433,6 +509,57 @@ func (e *PublicAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error)
return txHash, 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) {
e.logger.Debug("eth_resend", "args", args.String())
if args.Nonce == nil {
return common.Hash{}, fmt.Errorf("missing transaction nonce in transaction spec")
}
args, err := e.backend.SetTxDefaults(args)
if err != nil {
return common.Hash{}, err
}
matchTx := args.ToTransaction().AsTransaction()
pending, err := e.backend.PendingTransactions()
if err != nil {
return common.Hash{}, err
}
for _, tx := range pending {
p, err := evmtypes.UnwrapEthereumMsg(tx)
if err != nil {
// not valid ethereum tx
continue
}
pTx := p.AsTransaction()
wantSigHash := e.signer.Hash(matchTx)
pFrom, err := ethtypes.Sender(e.signer, pTx)
if err != nil {
continue
}
if pFrom == *args.From && e.signer.Hash(pTx) == wantSigHash {
// Match. Re-sign and send the transaction.
if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 {
args.GasPrice = gasPrice
}
if gasLimit != nil && *gasLimit != 0 {
args.Gas = gasLimit
}
return e.backend.SendTransaction(args) // TODO: this calls SetTxDefaults again, refactor to avoid calling it twice
}
}
return common.Hash{}, fmt.Errorf("transaction %#x not found", matchTx.Hash())
}
// Call performs a raw contract call.
func (e *PublicAPI) Call(args evmtypes.TransactionArgs, blockNrOrHash rpctypes.BlockNumberOrHash, _ *rpctypes.StateOverride) (hexutil.Bytes, error) {
e.logger.Debug("eth_call", "args", args.String(), "block number or hash", blockNrOrHash)
@@ -458,7 +585,23 @@ func (e *PublicAPI) doCall(
if err != nil {
return nil, err
}
req := evmtypes.EthCallRequest{Args: bz, GasCap: e.backend.RPCGasCap()}
baseFee, err := e.backend.BaseFee()
if err != nil {
return nil, err
}
var bf *sdk.Int
if baseFee != nil {
aux := sdk.NewIntFromBigInt(baseFee)
bf = &aux
}
req := evmtypes.EthCallRequest{
Args: bz,
GasCap: e.backend.RPCGasCap(),
BaseFee: bf,
}
// From ContextWithHeight: if the provided height is 0,
// it will return an empty context and the gRPC query will use
@@ -536,12 +679,17 @@ func (e *PublicAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexu
return nil, err
}
baseFee, err := e.backend.BaseFee()
if err != nil {
return nil, err
}
return rpctypes.NewTransactionFromMsg(
msg,
hash,
uint64(resBlock.Block.Height),
uint64(idx),
e.chainIDEpoch,
baseFee,
)
}
+10 -2
View File
@@ -3,6 +3,7 @@ package filters
import (
"context"
"fmt"
"math/big"
"sync"
"time"
@@ -17,6 +18,7 @@ import (
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
@@ -223,6 +225,9 @@ func (api *PublicFilterAPI) NewBlockFilter() rpc.ID {
return rpc.ID(fmt.Sprintf("error creating block filter: %s", err.Error()))
}
// TODO: use events to get the base fee amount
baseFee := big.NewInt(params.InitialBaseFee)
api.filtersMu.Lock()
api.filters[headerSub.ID()] = &filter{typ: filters.BlocksSubscription, deadline: time.NewTimer(deadline), hashes: []common.Hash{}, s: headerSub}
api.filtersMu.Unlock()
@@ -246,7 +251,7 @@ func (api *PublicFilterAPI) NewBlockFilter() rpc.ID {
continue
}
header := types.EthHeaderFromTendermint(data.Header)
header := types.EthHeaderFromTendermint(data.Header, baseFee)
api.filtersMu.Lock()
if f, found := api.filters[headerSub.ID()]; found {
f.hashes = append(f.hashes, header.Hash())
@@ -279,6 +284,9 @@ func (api *PublicFilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, er
return &rpc.Subscription{}, err
}
// TODO: use events to get the base fee amount
baseFee := big.NewInt(params.InitialBaseFee)
go func(headersCh <-chan coretypes.ResultEvent) {
defer cancelSubs()
@@ -296,7 +304,7 @@ func (api *PublicFilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, er
continue
}
header := types.EthHeaderFromTendermint(data.Header)
header := types.EthHeaderFromTendermint(data.Header, baseFee)
err = notifier.Notify(rpcSub.ID, header)
if err != nil {
headersSub.err <- err
+2 -2
View File
@@ -150,7 +150,7 @@ func (api *PrivateAccountAPI) UnlockAccount(_ context.Context, addr common.Addre
// SendTransaction will create a transaction from the given arguments and
// tries to sign it with the key associated with args.To. If the given password isn't
// able to decrypt the key it fails.
func (api *PrivateAccountAPI) SendTransaction(_ context.Context, args evmtypes.TransactionArgs, pwrd string) (common.Hash, error) {
func (api *PrivateAccountAPI) SendTransaction(_ context.Context, args evmtypes.TransactionArgs, _ string) (common.Hash, error) {
api.logger.Debug("personal_sendTransaction", "address", args.To.String())
if args.From == nil {
@@ -177,7 +177,7 @@ func (api *PrivateAccountAPI) SendTransaction(_ context.Context, args evmtypes.T
// The key used to calculate the signature is decrypted with the given password.
//
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign
func (api *PrivateAccountAPI) Sign(_ context.Context, data hexutil.Bytes, addr common.Address, pwrd string) (hexutil.Bytes, error) {
func (api *PrivateAccountAPI) Sign(_ context.Context, data hexutil.Bytes, addr common.Address, _ string) (hexutil.Bytes, error) {
api.logger.Debug("personal_sign", "data", data, "address", addr.String())
cosmosAddr := sdk.AccAddress(addr.Bytes())