From f15c2ef93cbf2eedfa3100365df20f906fa40548 Mon Sep 17 00:00:00 2001 From: Mikers Date: Tue, 18 Jun 2024 12:07:48 -1000 Subject: [PATCH 1/5] add support for eth_getBlockByNumber to accept the term safe which we are using as 30 blocks --- gateway/proxy_eth.go | 3 +++ node/impl/full/eth_utils.go | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/gateway/proxy_eth.go b/gateway/proxy_eth.go index eca6ae2bf41..a1211649fcb 100644 --- a/gateway/proxy_eth.go +++ b/gateway/proxy_eth.go @@ -142,6 +142,9 @@ func (gw *Node) checkBlkParam(ctx context.Context, blkParam string, lookback eth break } num = ethtypes.EthUint64(head.Height()) - lookback + case "safe": + safeEpochDelay := 30 // https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0089.md + num = ethtypes.EthUint64(head.Height()) - lookback - ethtypes.EthUint64(safeEpochDelay) default: if err := num.UnmarshalJSON([]byte(`"` + blkParam + `"`)); err != nil { return fmt.Errorf("cannot parse block number: %v", err) diff --git a/node/impl/full/eth_utils.go b/node/impl/full/eth_utils.go index 56cc1e094e2..0df32f762eb 100644 --- a/node/impl/full/eth_utils.go +++ b/node/impl/full/eth_utils.go @@ -57,6 +57,15 @@ func getTipsetByBlockNumber(ctx context.Context, chain *store.ChainStore, blkPar return nil, fmt.Errorf("cannot get parent tipset") } return parent, nil + case "safe": + safeEpochDelay := abi.ChainEpoch(30) // https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0089.md + latestHeight := head.Height() - 1 + safeHeight := latestHeight - safeEpochDelay + ts, err := chain.GetTipsetByHeight(ctx, abi.ChainEpoch(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 + `"`)) From c1eb71a764749b126ea7937b8661e427c83c27a0 Mon Sep 17 00:00:00 2001 From: Mikers Date: Tue, 18 Jun 2024 13:13:00 -1000 Subject: [PATCH 2/5] fix lint catch of unnecessary cast --- node/impl/full/eth_utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/impl/full/eth_utils.go b/node/impl/full/eth_utils.go index 0df32f762eb..9b86fee14d2 100644 --- a/node/impl/full/eth_utils.go +++ b/node/impl/full/eth_utils.go @@ -61,7 +61,7 @@ func getTipsetByBlockNumber(ctx context.Context, chain *store.ChainStore, blkPar safeEpochDelay := abi.ChainEpoch(30) // https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0089.md latestHeight := head.Height() - 1 safeHeight := latestHeight - safeEpochDelay - ts, err := chain.GetTipsetByHeight(ctx, abi.ChainEpoch(safeHeight), head, true) + ts, err := chain.GetTipsetByHeight(ctx, safeHeight, head, true) if err != nil { return nil, fmt.Errorf("cannot get tipset at height: %v", safeHeight) } From 3404bb8c8716c4a9d667c60dc85607a2d1235bb7 Mon Sep 17 00:00:00 2001 From: Mikers Date: Wed, 19 Jun 2024 18:29:37 -1000 Subject: [PATCH 3/5] add finalized to get block by number --- chain/types/ethtypes/eth_types.go | 4 ++++ gateway/proxy_eth.go | 6 ++++-- node/impl/full/eth_utils.go | 11 +++++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/chain/types/ethtypes/eth_types.go b/chain/types/ethtypes/eth_types.go index 3c2b9bec031..92fe0366508 100644 --- a/chain/types/ethtypes/eth_types.go +++ b/chain/types/ethtypes/eth_types.go @@ -28,6 +28,10 @@ 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) { diff --git a/gateway/proxy_eth.go b/gateway/proxy_eth.go index a1211649fcb..55780c53a20 100644 --- a/gateway/proxy_eth.go +++ b/gateway/proxy_eth.go @@ -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" @@ -143,8 +144,9 @@ func (gw *Node) checkBlkParam(ctx context.Context, blkParam string, lookback eth } num = ethtypes.EthUint64(head.Height()) - lookback case "safe": - safeEpochDelay := 30 // https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0089.md - num = ethtypes.EthUint64(head.Height()) - lookback - ethtypes.EthUint64(safeEpochDelay) + 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) diff --git a/node/impl/full/eth_utils.go b/node/impl/full/eth_utils.go index 9b86fee14d2..a5799b0dda4 100644 --- a/node/impl/full/eth_utils.go +++ b/node/impl/full/eth_utils.go @@ -58,9 +58,16 @@ func getTipsetByBlockNumber(ctx context.Context, chain *store.ChainStore, blkPar } return parent, nil case "safe": - safeEpochDelay := abi.ChainEpoch(30) // https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0089.md latestHeight := head.Height() - 1 - safeHeight := latestHeight - safeEpochDelay + 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) From bde6ad7059f7228fd839781cf13015099c66baf9 Mon Sep 17 00:00:00 2001 From: Mikers Date: Thu, 20 Jun 2024 12:53:42 -1000 Subject: [PATCH 4/5] Update chain/types/ethtypes/eth_types.go Co-authored-by: Rod Vagg --- chain/types/ethtypes/eth_types.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chain/types/ethtypes/eth_types.go b/chain/types/ethtypes/eth_types.go index 92fe0366508..251d8d501e9 100644 --- a/chain/types/ethtypes/eth_types.go +++ b/chain/types/ethtypes/eth_types.go @@ -28,7 +28,9 @@ 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. +// 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) From fca5823c9b13558c02b26b137c8f6ad519d77b86 Mon Sep 17 00:00:00 2001 From: Mikers Date: Thu, 20 Jun 2024 14:47:40 -1000 Subject: [PATCH 5/5] add test for eth get block by number to accept latest and safe and finalized as arguments --- itests/eth_api_test.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/itests/eth_api_test.go b/itests/eth_api_test.go index 43b4b526674..7b9f61662a7 100644 --- a/itests/eth_api_test.go +++ b/itests/eth_api_test.go @@ -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)) +}