diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index 573431065e..fc73486ec6 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -881,3 +881,37 @@ func TestSettingGingerbreadOnGenesisBlock(t *testing.T) { require.Greater(t, block.BaseFee().Uint64(), uint64(0)) require.Greater(t, block.GasLimit(), uint64(0)) } + +// This test checks that retreiveing the "finalized" block results in the same response as retrieving the "latest" block. +func TestGetFinalizedBlock(t *testing.T) { + ac := test.AccountConfig(2, 2) + gingerbreadBlock := common.Big0 + gc, ec, err := test.BuildConfig(ac, gingerbreadBlock) + require.NoError(t, err) + network, shutdown, err := test.NewNetwork(ac, gc, ec) + require.NoError(t, err) + defer shutdown() + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + + // Wait for at least one block to be built. + err = network.AwaitBlock(ctx, 1) + require.NoError(t, err) + + // Stop one of the two validators, so no more blocks can be created. + err = network[1].Close() + require.NoError(t, err) + + c := network[0].WsClient.GetRPCClient() + h := types.Header{} + err = c.CallContext(ctx, &h, "eth_getHeaderByNumber", "latest") + require.NoError(t, err) + require.GreaterOrEqual(t, h.Number.Uint64(), uint64(1)) + + h2 := types.Header{} + err = c.CallContext(ctx, &h2, "eth_getHeaderByNumber", "finalized") + require.NoError(t, err) + + // Check latest and finalzed block are the same + require.Equal(t, h.Hash(), h2.Hash()) +} diff --git a/internal/jsre/deps/web3.js b/internal/jsre/deps/web3.js index 950576f4d9..522002bff6 100644 --- a/internal/jsre/deps/web3.js +++ b/internal/jsre/deps/web3.js @@ -3696,7 +3696,7 @@ var outputBigNumberFormatter = function (number) { }; var isPredefinedBlockNumber = function (blockNumber) { - return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest'; + return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest' || blockNumber === 'finalized'; }; var inputDefaultBlockNumberFormatter = function (blockNumber) { diff --git a/rpc/types.go b/rpc/types.go index 23f645911d..49e988c336 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -84,8 +84,10 @@ type RPCTransaction struct { EthCompatible bool `json:"ethCompatible"` } -// UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: -// - "latest", "earliest" or "pending" as string arguments +// UnmarshalJSON parses the given JSON fragment into a BlockNumber. It +// supports: - "finalized", latest", "earliest" or "pending" as string +// arguments where finalized is equivalent to latest since all blocks are final +// in celo. // - the block number // Returned errors: // - an invalid block number error when the given argument isn't a known strings @@ -106,6 +108,9 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { case "pending": *bn = PendingBlockNumber return nil + case "finalized": + *bn = LatestBlockNumber + return nil } blckNum, err := hexutil.DecodeUint64(input) @@ -172,6 +177,10 @@ func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error { bn := LatestBlockNumber bnh.BlockNumber = &bn return nil + case "finalized": + bn := LatestBlockNumber + bnh.BlockNumber = &bn + return nil case "pending": bn := PendingBlockNumber bnh.BlockNumber = &bn diff --git a/rpc/types_test.go b/rpc/types_test.go index ec80a14f35..8958b79018 100644 --- a/rpc/types_test.go +++ b/rpc/types_test.go @@ -45,9 +45,10 @@ func TestBlockNumberJSONUnmarshal(t *testing.T) { 11: {`"pending"`, false, PendingBlockNumber}, 12: {`"latest"`, false, LatestBlockNumber}, 13: {`"earliest"`, false, EarliestBlockNumber}, - 14: {`someString`, true, BlockNumber(0)}, - 15: {`""`, true, BlockNumber(0)}, - 16: {``, true, BlockNumber(0)}, + 14: {`"finalized"`, false, LatestBlockNumber}, + 15: {`someString`, true, BlockNumber(0)}, + 16: {`""`, true, BlockNumber(0)}, + 17: {``, true, BlockNumber(0)}, } for i, test := range tests { @@ -87,18 +88,20 @@ func TestBlockNumberOrHash_UnmarshalJSON(t *testing.T) { 11: {`"pending"`, false, BlockNumberOrHashWithNumber(PendingBlockNumber)}, 12: {`"latest"`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, 13: {`"earliest"`, false, BlockNumberOrHashWithNumber(EarliestBlockNumber)}, - 14: {`someString`, true, BlockNumberOrHash{}}, - 15: {`""`, true, BlockNumberOrHash{}}, - 16: {``, true, BlockNumberOrHash{}}, - 17: {`"0x0000000000000000000000000000000000000000000000000000000000000000"`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, - 18: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, - 19: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":false}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, - 20: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":true}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), true)}, - 21: {`{"blockNumber":"0x1"}`, false, BlockNumberOrHashWithNumber(1)}, - 22: {`{"blockNumber":"pending"}`, false, BlockNumberOrHashWithNumber(PendingBlockNumber)}, - 23: {`{"blockNumber":"latest"}`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, - 24: {`{"blockNumber":"earliest"}`, false, BlockNumberOrHashWithNumber(EarliestBlockNumber)}, - 25: {`{"blockNumber":"0x1", "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, true, BlockNumberOrHash{}}, + 14: {`"finalized"`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, + 15: {`someString`, true, BlockNumberOrHash{}}, + 16: {`""`, true, BlockNumberOrHash{}}, + 17: {``, true, BlockNumberOrHash{}}, + 18: {`"0x0000000000000000000000000000000000000000000000000000000000000000"`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, + 19: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, + 20: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":false}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, + 21: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":true}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), true)}, + 22: {`{"blockNumber":"0x1"}`, false, BlockNumberOrHashWithNumber(1)}, + 23: {`{"blockNumber":"pending"}`, false, BlockNumberOrHashWithNumber(PendingBlockNumber)}, + 24: {`{"blockNumber":"latest"}`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, + 25: {`{"blockNumber":"earliest"}`, false, BlockNumberOrHashWithNumber(EarliestBlockNumber)}, + 26: {`{"blockNumber":"finalized"}`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, + 27: {`{"blockNumber":"0x1", "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, true, BlockNumberOrHash{}}, } for i, test := range tests {