Skip to content

Commit

Permalink
Merge pull request #10427 from filecoin-project/raulk/fix-eth-parseBl…
Browse files Browse the repository at this point in the history
…kParam

fix: Eth API: make block parameter parsing sounder.
  • Loading branch information
jennijuju authored Mar 9, 2023
2 parents 9fa8167 + 3d21d71 commit 1096ead
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 9 deletions.
5 changes: 5 additions & 0 deletions itests/eth_block_hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package itests
import (
"context"
"fmt"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -55,6 +56,10 @@ func TestEthBlockHashesCorrect_MultiBlockTipset(t *testing.T) {
hex := fmt.Sprintf("0x%x", i)

ethBlockA, err := n2.EthGetBlockByNumber(ctx, hex, true)
// Cannot use static ErrFullRound error for comparison since it gets reserialized as a JSON RPC error.
if err != nil && strings.Contains(err.Error(), "null round") {
continue
}
require.NoError(t, err)

ethBlockB, err := n2.EthGetBlockByHash(ctx, ethBlockA.Hash, true)
Expand Down
52 changes: 52 additions & 0 deletions itests/eth_transactions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/itests/kit"
Expand Down Expand Up @@ -270,6 +271,57 @@ func TestContractInvocation(t *testing.T) {
require.EqualValues(t, ethtypes.EthUint64(0x1), receipt.Status)
}

func TestGetBlockByNumber(t *testing.T) {
blockTime := 100 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())

bms := ens.InterconnectAll().BeginMining(blockTime)

ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()

// create a new Ethereum account
_, ethAddr, filAddr := client.EVM().NewAccount()
// send some funds to the f410 address
kit.SendFunds(ctx, t, client, filAddr, types.FromFil(10))

latest, err := client.EthBlockNumber(ctx)
require.NoError(t, err)

// can get the latest block
_, err = client.EthGetBlockByNumber(ctx, latest.Hex(), true)
require.NoError(t, err)

// fail to get a future block
_, err = client.EthGetBlockByNumber(ctx, (latest + 10000).Hex(), true)
require.Error(t, err)

// inject 10 null rounds
bms[0].InjectNulls(10)

// wait until we produce blocks again
tctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
ch, err := client.ChainNotify(tctx)
require.NoError(t, err)
<-ch // current
hc := <-ch // wait for next block
require.Equal(t, store.HCApply, hc[0].Type)

afterNullHeight := hc[0].Val.Height()

// Fail when trying to fetch a null round.
_, err = client.EthGetBlockByNumber(ctx, (ethtypes.EthUint64(afterNullHeight - 1)).Hex(), true)
require.Error(t, err)

// Fetch balance on a null round; should not fail and should return previous balance.
// Should be lower than original balance.
bal, err := client.EthGetBalance(ctx, ethAddr, (ethtypes.EthUint64(afterNullHeight - 1)).Hex())
require.NoError(t, err)
require.NotEqual(t, big.Zero(), bal)
require.Equal(t, types.FromFil(10).Int, bal.Int)
}

func deployContractTx(ctx context.Context, client *kit.TestFullNode, ethAddr ethtypes.EthAddress, contract []byte) (*ethtypes.EthTxArgs, error) {
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
From: &ethAddr,
Expand Down
26 changes: 17 additions & 9 deletions node/impl/full/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ type EthAPI struct {
EthEventAPI
}

var ErrNullRound = errors.New("requested epoch was a null round")

func (a *EthModule) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) {
return stmgr.GetNetworkName(ctx, a.StateManager, a.Chain.GetHeaviestTipSet().ParentState())
}
Expand Down Expand Up @@ -231,7 +233,7 @@ func (a *EthModule) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthH
return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.StateAPI)
}

func (a *EthModule) parseBlkParam(ctx context.Context, blkParam string) (tipset *types.TipSet, err error) {
func (a *EthModule) parseBlkParam(ctx context.Context, blkParam string, strict bool) (tipset *types.TipSet, err error) {
if blkParam == "earliest" {
return nil, fmt.Errorf("block param \"earliest\" is not supported")
}
Expand All @@ -252,16 +254,22 @@ func (a *EthModule) parseBlkParam(ctx context.Context, blkParam string) (tipset
if err != nil {
return nil, fmt.Errorf("cannot parse block number: %v", err)
}
ts, err := a.Chain.GetTipsetByHeight(ctx, abi.ChainEpoch(num), nil, true)
if abi.ChainEpoch(num) > head.Height()-1 {
return nil, fmt.Errorf("requested a future epoch (beyond 'latest')")
}
ts, err := a.ChainAPI.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(num), head.Key())
if err != nil {
return nil, fmt.Errorf("cannot get tipset at height: %v", num)
}
if strict && ts.Height() != abi.ChainEpoch(num) {
return nil, ErrNullRound
}
return ts, nil
}
}

func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkParam string, fullTxInfo bool) (ethtypes.EthBlock, error) {
ts, err := a.parseBlkParam(ctx, blkParam)
ts, err := a.parseBlkParam(ctx, blkParam, true)
if err != nil {
return ethtypes.EthBlock{}, err
}
Expand Down Expand Up @@ -367,7 +375,7 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.
return ethtypes.EthUint64(0), nil
}

ts, err := a.parseBlkParam(ctx, blkParam)
ts, err := a.parseBlkParam(ctx, blkParam, false)
if err != nil {
return ethtypes.EthUint64(0), xerrors.Errorf("cannot parse block param: %s", blkParam)
}
Expand Down Expand Up @@ -456,7 +464,7 @@ func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress,
return nil, xerrors.Errorf("cannot get Filecoin address: %w", err)
}

ts, err := a.parseBlkParam(ctx, blkParam)
ts, err := a.parseBlkParam(ctx, blkParam, false)
if err != nil {
return nil, xerrors.Errorf("cannot parse block param: %s", blkParam)
}
Expand Down Expand Up @@ -535,7 +543,7 @@ func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress,
}

func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) {
ts, err := a.parseBlkParam(ctx, blkParam)
ts, err := a.parseBlkParam(ctx, blkParam, false)
if err != nil {
return nil, xerrors.Errorf("cannot parse block param: %s", blkParam)
}
Expand Down Expand Up @@ -631,7 +639,7 @@ func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddre
return ethtypes.EthBigInt{}, err
}

ts, err := a.parseBlkParam(ctx, blkParam)
ts, err := a.parseBlkParam(ctx, blkParam, false)
if err != nil {
return ethtypes.EthBigInt{}, xerrors.Errorf("cannot parse block param: %s", blkParam)
}
Expand Down Expand Up @@ -676,7 +684,7 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth
}
}

ts, err := a.parseBlkParam(ctx, params.NewestBlkNum)
ts, err := a.parseBlkParam(ctx, params.NewestBlkNum, false)
if err != nil {
return ethtypes.EthFeeHistory{}, fmt.Errorf("bad block parameter %s: %s", params.NewestBlkNum, err)
}
Expand Down Expand Up @@ -1067,7 +1075,7 @@ func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam s
return nil, xerrors.Errorf("failed to convert ethcall to filecoin message: %w", err)
}

ts, err := a.parseBlkParam(ctx, blkParam)
ts, err := a.parseBlkParam(ctx, blkParam, false)
if err != nil {
return nil, xerrors.Errorf("cannot parse block param: %s", blkParam)
}
Expand Down

0 comments on commit 1096ead

Please sign in to comment.