feat: ethrpc: implement call, estimateGas, getTransactionCount (#9306)

This commit is contained in:
Kevin Li
2022-11-09 19:25:40 +02:00
committed by vyzo
parent e5bb5b7430
commit b53d5924a1
7 changed files with 352 additions and 90 deletions
+142 -23
View File
@@ -8,11 +8,17 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/exitcode"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/messagepool"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/modules/dtypes"
)
type EthModuleAPI interface {
@@ -24,7 +30,7 @@ type EthModuleAPI interface {
EthGetBlockByNumber(ctx context.Context, blkNum api.EthInt, fullTxInfo bool) (api.EthBlock, error)
EthGetTransactionByHash(ctx context.Context, txHash api.EthHash) (api.EthTx, error)
EthGetTransactionCount(ctx context.Context, sender api.EthAddress, blkOpt string) (api.EthInt, error)
EthGetTransactionReceipt(ctx context.Context, blkHash api.EthHash) (api.EthTxReceipt, error)
EthGetTransactionReceipt(ctx context.Context, txHash api.EthHash) (api.EthTxReceipt, error)
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash api.EthHash, txIndex api.EthInt) (api.EthTx, error)
EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum api.EthInt, txIndex api.EthInt) (api.EthTx, error)
EthGetCode(ctx context.Context, address api.EthAddress) (string, error)
@@ -34,11 +40,11 @@ type EthModuleAPI interface {
NetVersion(ctx context.Context) (string, error)
NetListening(ctx context.Context) (bool, error)
EthProtocolVersion(ctx context.Context) (api.EthInt, error)
EthGasPrice(ctx context.Context) (api.EthInt, error)
EthGasPrice(ctx context.Context) (api.EthBigInt, error)
EthEstimateGas(ctx context.Context, tx api.EthCall, blkParam string) (api.EthInt, error)
EthCall(ctx context.Context, tx api.EthCall, blkParam string) (string, error)
EthMaxPriorityFeePerGas(ctx context.Context) (api.EthInt, error)
// EthSendRawTransaction(ctx context.Context, tx api.EthTx) (api.EthHash, error)
EthCall(ctx context.Context, tx api.EthCall, blkParam string) (api.EthBytes, error)
EthMaxPriorityFeePerGas(ctx context.Context) (api.EthBigInt, error)
EthSendRawTransaction(ctx context.Context, rawTx api.EthBytes) (api.EthHash, error)
}
var _ EthModuleAPI = *new(api.FullNode)
@@ -49,9 +55,12 @@ var _ EthModuleAPI = *new(api.FullNode)
type EthModule struct {
fx.In
Chain *store.ChainStore
Chain *store.ChainStore
Mpool *messagepool.MessagePool
StateManager *stmgr.StateManager
ChainAPI
MpoolAPI
StateAPI
}
@@ -65,6 +74,10 @@ type EthAPI struct {
EthModuleAPI
}
func (a *EthModule) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) {
return stmgr.GetNetworkName(ctx, a.StateManager, a.Chain.GetHeaviestTipSet().ParentState())
}
func (a *EthModule) EthBlockNumber(context.Context) (api.EthInt, error) {
height := a.Chain.GetHeaviestTipSet().Height()
return api.EthInt(height), nil
@@ -140,11 +153,40 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash api.EthH
}
func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender api.EthAddress, blkParam string) (api.EthInt, error) {
return api.EthInt(0), nil
addr, err := sender.ToFilecoinAddress()
if err != nil {
return api.EthInt(0), err
}
nonce, err := a.Mpool.GetNonce(ctx, addr, types.EmptyTSK)
if err != nil {
return api.EthInt(0), err
}
return api.EthInt(nonce), nil
}
func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, blkHash api.EthHash) (api.EthTxReceipt, error) {
return api.EthTxReceipt{}, nil
func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash api.EthHash) (api.EthTxReceipt, error) {
cid := txHash.ToCid()
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, cid, api.LookbackNoLimit, true)
if err != nil {
return api.EthTxReceipt{}, err
}
tx, err := a.ethTxFromFilecoinMessageLookup(ctx, msgLookup)
if err != nil {
return api.EthTxReceipt{}, err
}
replay, err := a.StateAPI.StateReplay(ctx, types.EmptyTSK, cid)
if err != nil {
return api.EthTxReceipt{}, err
}
receipt, err := api.NewEthTxReceipt(tx, msgLookup, replay)
if err != nil {
return api.EthTxReceipt{}, err
}
return receipt, nil
}
func (a *EthModule) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash api.EthHash, txIndex api.EthInt) (api.EthTx, error) {
@@ -196,27 +238,98 @@ func (a *EthModule) NetListening(ctx context.Context) (bool, error) {
}
func (a *EthModule) EthProtocolVersion(ctx context.Context) (api.EthInt, error) {
return api.EthInt(0), nil
height := a.Chain.GetHeaviestTipSet().Height()
return api.EthInt(a.StateManager.GetNetworkVersion(ctx, height)), nil
}
func (a *EthModule) EthMaxPriorityFeePerGas(ctx context.Context) (api.EthInt, error) {
return api.EthInt(0), nil
func (a *EthModule) EthMaxPriorityFeePerGas(ctx context.Context) (api.EthBigInt, error) {
gasPremium, err := a.GasAPI.GasEstimateGasPremium(ctx, 0, builtin.SystemActorAddr, 10000, types.EmptyTSK)
if err != nil {
return api.EthBigInt(big.Zero()), err
}
return api.EthBigInt(gasPremium), nil
}
func (a *EthModule) EthGasPrice(ctx context.Context) (api.EthInt, error) {
return api.EthInt(0), nil
func (a *EthModule) EthGasPrice(ctx context.Context) (api.EthBigInt, error) {
// According to Geth's implementation, eth_gasPrice should return base + tip
// Ref: https://github.com/ethereum/pm/issues/328#issuecomment-853234014
ts := a.Chain.GetHeaviestTipSet()
baseFee := ts.Blocks()[0].ParentBaseFee
premium, err := a.EthMaxPriorityFeePerGas(ctx)
if err != nil {
return api.EthBigInt(big.Zero()), nil
}
gasPrice := big.Add(baseFee, big.Int(premium))
return api.EthBigInt(gasPrice), nil
}
// func (a *EthModule) EthSendRawTransaction(ctx context.Context tx api.EthTx) (api.EthHash, error) {
// return api.EthHash{}, nil
// }
func (a *EthModule) EthSendRawTransaction(ctx context.Context, rawTx api.EthBytes) (api.EthHash, error) {
return api.EthHash{}, nil
}
func (a *EthModule) applyEvmMsg(ctx context.Context, tx api.EthCall) (*api.InvocResult, error) {
from, err := tx.From.ToFilecoinAddress()
if err != nil {
return nil, err
}
to, err := tx.To.ToFilecoinAddress()
if err != nil {
return nil, xerrors.Errorf("cannot get Filecoin address: %w", err)
}
msg := &types.Message{
From: from,
To: to,
Value: big.Int(tx.Value),
Method: abi.MethodNum(2),
Params: tx.Data,
GasLimit: build.BlockGasLimit,
GasFeeCap: big.Zero(),
GasPremium: big.Zero(),
}
ts := a.Chain.GetHeaviestTipSet()
// Try calling until we find a height with no migration.
var res *api.InvocResult
for {
res, err = a.StateManager.CallWithGas(ctx, msg, []types.ChainMsg{}, ts)
if err != stmgr.ErrExpensiveFork {
break
}
ts, err = a.Chain.GetTipSetFromKey(ctx, ts.Parents())
if err != nil {
return nil, xerrors.Errorf("getting parent tipset: %w", err)
}
}
if err != nil {
return nil, xerrors.Errorf("CallWithGas failed: %w", err)
}
if res.MsgRct.ExitCode != exitcode.Ok {
return nil, xerrors.Errorf("message execution failed: exit %s, reason: %s", res.MsgRct.ExitCode, res.Error)
}
return res, nil
}
func (a *EthModule) EthEstimateGas(ctx context.Context, tx api.EthCall, blkParam string) (api.EthInt, error) {
return api.EthInt(0), nil
invokeResult, err := a.applyEvmMsg(ctx, tx)
if err != nil {
return api.EthInt(0), err
}
ret := invokeResult.MsgRct.GasUsed
return api.EthInt(ret), nil
}
func (a *EthModule) EthCall(ctx context.Context, tx api.EthCall, blkParam string) (string, error) {
return "", nil
func (a *EthModule) EthCall(ctx context.Context, tx api.EthCall, blkParam string) (api.EthBytes, error) {
invokeResult, err := a.applyEvmMsg(ctx, tx)
if err != nil {
return nil, err
}
if len(invokeResult.MsgRct.Return) > 0 {
return api.EthBytes(invokeResult.MsgRct.Return), nil
}
return api.EthBytes{}, nil
}
func (a *EthModule) ethBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTxInfo bool) (api.EthBlock, error) {
@@ -306,7 +419,7 @@ func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLooku
return api.EthTx{}, err
}
toFilAddr, err := a.StateAPI.StateLookupID(ctx, msg.From, types.EmptyTSK)
toFilAddr, err := a.StateAPI.StateLookupID(ctx, msg.To, types.EmptyTSK)
if err != nil {
return api.EthTx{}, err
}
@@ -316,13 +429,19 @@ func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLooku
return api.EthTx{}, err
}
toAddr := &toEthAddr
_, err = api.CheckContractCreation(msgLookup)
if err == nil {
toAddr = nil
}
tx := api.EthTx{
ChainID: api.EthInt(build.Eip155ChainId),
Hash: txHash,
BlockHash: blkHash,
BlockNumber: api.EthInt(msgLookup.Height),
From: fromEthAddr,
To: toEthAddr,
To: toAddr,
Value: api.EthBigInt(msg.Value),
Type: api.EthInt(2),
Gas: api.EthInt(msg.GasLimit),
@@ -331,7 +450,7 @@ func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLooku
V: api.EthBigIntZero,
R: api.EthBigIntZero,
S: api.EthBigIntZero,
// TODO: Input:
Input: msg.Params,
}
return tx, nil
}