feat: eth: support "safe" and "finalized" for eth_getBlockByNumber (#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>
This commit is contained in:
parent
c87e2f2a64
commit
6408709018
@ -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) {
|
||||
|
@ -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"
|
||||
@ -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)
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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 + `"`))
|
||||
|
Loading…
Reference in New Issue
Block a user