Skip to content

Commit

Permalink
feat: eth: support "safe" and "finalized" for eth_getBlockByNumber (#…
Browse files Browse the repository at this point in the history
…12110)

* add support for eth_getBlockByNumber to accept the term safe which we are using as 30 blocks

* fix lint catch of unnecessary cast

* add finalized to get block by number

* Update chain/types/ethtypes/eth_types.go

Co-authored-by: Rod Vagg <rod@vagg.org>

* add test for eth get block by number to accept latest and safe and finalized as arguments

---------

Co-authored-by: Rod Vagg <rod@vagg.org>
  • Loading branch information
snissn and rvagg committed Jul 10, 2024
1 parent fcec558 commit 6891f56
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 0 deletions.
6 changes: 6 additions & 0 deletions chain/types/ethtypes/eth_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ import (

var ErrInvalidAddress = errors.New("invalid Filecoin Eth address")

// Research into Filecoin chain behaviour suggests that probabilistic finality
// generally approaches the intended stability guarantee at, or near, 30 epochs.
// Although a strictly "finalized" safe recommendation remains 900 epochs.
// See https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0089.md
const SafeEpochDelay = abi.ChainEpoch(30)

type EthUint64 uint64

func (e EthUint64) MarshalJSON() ([]byte, error) {
Expand Down
5 changes: 5 additions & 0 deletions gateway/proxy_eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/filecoin-project/go-state-types/big"

"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/events/filter"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
Expand Down Expand Up @@ -142,6 +143,10 @@ func (gw *Node) checkBlkParam(ctx context.Context, blkParam string, lookback eth
break
}
num = ethtypes.EthUint64(head.Height()) - lookback
case "safe":
num = ethtypes.EthUint64(head.Height()) - lookback - ethtypes.EthUint64(ethtypes.SafeEpochDelay)
case "finalized":
num = ethtypes.EthUint64(head.Height()) - lookback - ethtypes.EthUint64(build.Finality)
default:
if err := num.UnmarshalJSON([]byte(`"` + blkParam + `"`)); err != nil {
return fmt.Errorf("cannot parse block number: %v", err)
Expand Down
36 changes: 36 additions & 0 deletions itests/eth_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,39 @@ func TestNetVersion(t *testing.T) {
require.NoError(t, err)
require.Equal(t, strconv.Itoa(build.Eip155ChainId), version)
}

func TestEthBlockNumberAliases(t *testing.T) {
blockTime := 2 * time.Millisecond
kit.QuietMiningLogs()
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime)
ens.Start()

build.Clock.Sleep(time.Second)

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

head := client.WaitTillChain(ctx, kit.HeightAtLeast(build.Finality+100))

// latest should be head-1 (parents)
latestEthBlk, err := client.EVM().EthGetBlockByNumber(ctx, "latest", true)
require.NoError(t, err)
diff := int64(latestEthBlk.Number) - int64(head.Height()-1)
require.GreaterOrEqual(t, diff, int64(0))
require.LessOrEqual(t, diff, int64(2))

// safe should be latest-30
safeEthBlk, err := client.EVM().EthGetBlockByNumber(ctx, "safe", true)
require.NoError(t, err)
diff = int64(latestEthBlk.Number-30) - int64(safeEthBlk.Number)
require.GreaterOrEqual(t, diff, int64(0))
require.LessOrEqual(t, diff, int64(2))

// finalized should be Finality blocks behind latest
finalityEthBlk, err := client.EVM().EthGetBlockByNumber(ctx, "finalized", true)
require.NoError(t, err)
diff = int64(latestEthBlk.Number) - int64(build.Finality) - int64(finalityEthBlk.Number)
require.GreaterOrEqual(t, diff, int64(0))
require.LessOrEqual(t, diff, int64(2))
}
16 changes: 16 additions & 0 deletions node/impl/full/eth_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,22 @@ func getTipsetByBlockNumber(ctx context.Context, chain *store.ChainStore, blkPar
return nil, fmt.Errorf("cannot get parent tipset")
}
return parent, nil
case "safe":
latestHeight := head.Height() - 1
safeHeight := latestHeight - ethtypes.SafeEpochDelay
ts, err := chain.GetTipsetByHeight(ctx, safeHeight, head, true)
if err != nil {
return nil, fmt.Errorf("cannot get tipset at height: %v", safeHeight)
}
return ts, nil
case "finalized":
latestHeight := head.Height() - 1
safeHeight := latestHeight - build.Finality
ts, err := chain.GetTipsetByHeight(ctx, safeHeight, head, true)
if err != nil {
return nil, fmt.Errorf("cannot get tipset at height: %v", safeHeight)
}
return ts, nil
default:
var num ethtypes.EthUint64
err := num.UnmarshalJSON([]byte(`"` + blkParam + `"`))
Expand Down

0 comments on commit 6891f56

Please sign in to comment.