diff --git a/CHANGELOG.md b/CHANGELOG.md index 72678d207..6cd497cdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,13 +12,14 @@ ## Improvements -# v1.28.0-rc4 / 2024-07-04 +# v1.28.0-rc5 / 2024-07-11 -This is the fourth release candidate of the upcoming MANDATORY Lotus v1.28.0 release, which will deliver the Filecoin network version 23, codenamed Waffle 🧇. +This is the fifth release candidate of the upcoming MANDATORY Lotus v1.28.0 release, which will deliver the Filecoin network version 23, codenamed Waffle 🧇. **This release candidate sets the calibration network to upgrade at epoch 1779094, corresponding to 2024-07-11T12:00:00Z.** This release does NOT set the mainnet upgrade epoch yet, in which will be updated in the final release. -Compared to `Lotus v1.28.0-rc3`, the `Lotus v1.28.0-rc4` release addresses an issue that allows us to publish Docker builds. +Compared to `Lotus v1.28.0-rc4`, the `Lotus v1.28.0-rc5` release addresses some performance problems in the `eth_getLogs` API. +It also addresses a bug in the `eth_getLogs` API around handling null blocks. ☢️ Upgrade Warnings ☢️ @@ -94,6 +95,7 @@ For certain node operators, such as full archival nodes or systems that need to - rename `Actor.Address` to `Actor.DelegatedAddress` and only use it for f4 addresses (https://github.com/filecoin-project/lotus/pull/12155) - feat:ec: integrate F3 dynamic manifest #12185 - fix: f3: Fix F3 build parameters for testground target (#12189) ([filecoin-project/lotus#12189](https://github.com/filecoin-project/lotus/pull/12189)) +- fix: eth_getLogs: https://github.com/filecoin-project/lotus/pull/12212 # v1.27.1 / 2024-06-24 diff --git a/build/openrpc/full.json b/build/openrpc/full.json index 97904162c..4446b43b2 100644 --- a/build/openrpc/full.json +++ b/build/openrpc/full.json @@ -2,7 +2,7 @@ "openrpc": "1.2.6", "info": { "title": "Lotus RPC API", - "version": "1.28.0-rc4" + "version": "1.28.0-rc5" }, "methods": [ { diff --git a/build/openrpc/gateway.json b/build/openrpc/gateway.json index 0b9236bf2..8a6bd0762 100644 --- a/build/openrpc/gateway.json +++ b/build/openrpc/gateway.json @@ -2,7 +2,7 @@ "openrpc": "1.2.6", "info": { "title": "Lotus RPC API", - "version": "1.28.0-rc4" + "version": "1.28.0-rc5" }, "methods": [ { diff --git a/build/openrpc/miner.json b/build/openrpc/miner.json index 02096c1dc..9f6448612 100644 --- a/build/openrpc/miner.json +++ b/build/openrpc/miner.json @@ -2,7 +2,7 @@ "openrpc": "1.2.6", "info": { "title": "Lotus RPC API", - "version": "1.28.0-rc4" + "version": "1.28.0-rc5" }, "methods": [ { diff --git a/build/openrpc/worker.json b/build/openrpc/worker.json index 0dba09490..2b891057b 100644 --- a/build/openrpc/worker.json +++ b/build/openrpc/worker.json @@ -2,7 +2,7 @@ "openrpc": "1.2.6", "info": { "title": "Lotus RPC API", - "version": "1.28.0-rc4" + "version": "1.28.0-rc5" }, "methods": [ { diff --git a/build/version.go b/build/version.go index de9c90d19..195658084 100644 --- a/build/version.go +++ b/build/version.go @@ -39,7 +39,7 @@ func BuildTypeString() string { } // NodeBuildVersion is the local build version of the Lotus daemon -const NodeBuildVersion string = "1.28.0-rc4" +const NodeBuildVersion string = "1.28.0-rc5" func NodeUserVersion() BuildVersion { if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" { @@ -50,7 +50,7 @@ func NodeUserVersion() BuildVersion { } // MinerBuildVersion is the local build version of the Lotus miner -const MinerBuildVersion = "1.28.0-rc4" +const MinerBuildVersion = "1.28.0-rc5" func MinerUserVersion() BuildVersion { if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" { diff --git a/chain/events/filter/index.go b/chain/events/filter/index.go index fed6c42eb..d18563a94 100644 --- a/chain/events/filter/index.go +++ b/chain/events/filter/index.go @@ -698,11 +698,12 @@ func (ei *EventIndex) GetMaxHeightInIndex(ctx context.Context) (uint64, error) { return maxHeight, err } -func (ei *EventIndex) IsHeightProcessed(ctx context.Context, height uint64) (bool, error) { - row := ei.stmtIsHeightProcessed.QueryRowContext(ctx, height) - var exists bool - err := row.Scan(&exists) - return exists, err +func (ei *EventIndex) IsHeightPast(ctx context.Context, height uint64) (bool, error) { + maxHeight, err := ei.GetMaxHeightInIndex(ctx) + if err != nil { + return false, err + } + return height <= maxHeight, nil } func (ei *EventIndex) IsTipsetProcessed(ctx context.Context, tipsetKeyCid []byte) (bool, error) { diff --git a/chain/events/filter/index_test.go b/chain/events/filter/index_test.go index 10b3eb577..8aa3d51bb 100644 --- a/chain/events/filter/index_test.go +++ b/chain/events/filter/index_test.go @@ -94,17 +94,21 @@ func TestEventIndexPrefillFilter(t *testing.T) { require.NoError(t, err) require.Equal(t, uint64(14000), mh) - b, err := ei.IsHeightProcessed(context.Background(), 14000) + b, err := ei.IsHeightPast(context.Background(), 14000) require.NoError(t, err) require.True(t, b) - b, err = ei.IsHeightProcessed(context.Background(), 14001) + b, err = ei.IsHeightPast(context.Background(), 14001) require.NoError(t, err) require.False(t, b) - b, err = ei.IsHeightProcessed(context.Background(), 13000) + b, err = ei.IsHeightPast(context.Background(), 13000) require.NoError(t, err) - require.False(t, b) + require.True(t, b) + + b, err = ei.IsHeightPast(context.Background(), 13001) + require.NoError(t, err) + require.True(t, b) tsKey := events14000.msgTs.Key() tsKeyCid, err := tsKey.Cid() diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index ddc4ac968..c64630cad 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -7,7 +7,7 @@ USAGE: lotus-miner [global options] command [command options] [arguments...] VERSION: - 1.28.0-rc4 + 1.28.0-rc5 COMMANDS: init Initialize a lotus miner repo diff --git a/documentation/en/cli-lotus-worker.md b/documentation/en/cli-lotus-worker.md index bbdce5c12..bbb791e92 100644 --- a/documentation/en/cli-lotus-worker.md +++ b/documentation/en/cli-lotus-worker.md @@ -7,7 +7,7 @@ USAGE: lotus-worker [global options] command [command options] [arguments...] VERSION: - 1.28.0-rc4 + 1.28.0-rc5 COMMANDS: run Start lotus worker diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index d097733d8..7dda936c1 100644 --- a/documentation/en/cli-lotus.md +++ b/documentation/en/cli-lotus.md @@ -7,7 +7,7 @@ USAGE: lotus [global options] command [command options] [arguments...] VERSION: - 1.28.0-rc4 + 1.28.0-rc5 COMMANDS: daemon Start a lotus daemon process diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index c8052f67d..a7c1975f5 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -255,7 +255,6 @@ func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkParam string, fu func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) { return a.EthGetTransactionByHashLimited(ctx, txHash, api.LookbackNoLimit) - } func (a *EthModule) EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) { @@ -1276,9 +1275,17 @@ func (e *EthEventHandler) EthGetLogs(ctx context.Context, filterSpec *ethtypes.E if pf.tipsetCid == cid.Undef { maxHeight := pf.maxHeight if maxHeight == -1 { - maxHeight = e.Chain.GetHeaviestTipSet().Height() + // heaviest tipset doesn't have events because its messages haven't been executed yet + maxHeight = e.Chain.GetHeaviestTipSet().Height() - 1 } - if maxHeight > e.Chain.GetHeaviestTipSet().Height() { + + if maxHeight < 0 { + return nil, xerrors.Errorf("maxHeight requested is less than 0") + } + + // we can't return events for the heaviest tipset as the transactions in that tipset will be executed + // in the next non null tipset (because of Filecoin's "deferred execution" model) + if maxHeight > e.Chain.GetHeaviestTipSet().Height()-1 { return nil, xerrors.Errorf("maxHeight requested is greater than the heaviest tipset") } @@ -1286,13 +1293,13 @@ func (e *EthEventHandler) EthGetLogs(ctx context.Context, filterSpec *ethtypes.E if err != nil { return nil, err } - - // should also have the minHeight in the filter indexed - if b, err := e.EventFilterManager.EventIndex.IsHeightProcessed(ctx, uint64(pf.minHeight)); err != nil { - return nil, xerrors.Errorf("failed to check if event index has events for the minHeight: %w", err) - } else if !b { - return nil, xerrors.Errorf("event index does not have event for epoch %d", pf.minHeight) - } + // TODO: Ideally we should also check that events for the epoch at `pf.minheight` have been indexed + // However, it is currently tricky to check/guarantee this for two reasons: + // a) Event Index is not aware of null-blocks. This means that the Event Index wont be able to say whether the block at + // `pf.minheight` is a null block or whether it has no events + // b) There can be holes in the index where events at certain epoch simply haven't been indexed because of edge cases around + // node restarts while indexing. This needs a long term "auto-repair"/"automated-backfilling" implementation in the index + // So, for now, the best we can do is ensure that the event index has evenets for events at height >= `pf.maxHeight` } else { ts, err := e.Chain.GetTipSetByCid(ctx, pf.tipsetCid) if err != nil { @@ -1324,6 +1331,8 @@ func (e *EthEventHandler) EthGetLogs(ctx context.Context, filterSpec *ethtypes.E return ethFilterResultFromEvents(ctx, ces, e.SubManager.StateAPI) } +// note that we can have null blocks at the given height and the event Index is not null block aware +// so, what we do here is wait till we see the event index contain a block at a height greater than the given height func (e *EthEventHandler) waitForHeightProcessed(ctx context.Context, height abi.ChainEpoch) error { ei := e.EventFilterManager.EventIndex if height > e.Chain.GetHeaviestTipSet().Height() { @@ -1334,7 +1343,7 @@ func (e *EthEventHandler) waitForHeightProcessed(ctx context.Context, height abi defer cancel() // if the height we're interested in has already been indexed -> there's nothing to do here - if b, err := ei.IsHeightProcessed(ctx, uint64(height)); err != nil { + if b, err := ei.IsHeightPast(ctx, uint64(height)); err != nil { return xerrors.Errorf("failed to check if event index has events for given height: %w", err) } else if b { return nil @@ -1345,7 +1354,7 @@ func (e *EthEventHandler) waitForHeightProcessed(ctx context.Context, height abi defer unSubscribeF() // it could be that the event index was update while the subscription was being processed -> check if index has what we need now - if b, err := ei.IsHeightProcessed(ctx, uint64(height)); err != nil { + if b, err := ei.IsHeightPast(ctx, uint64(height)); err != nil { return xerrors.Errorf("failed to check if event index has events for given height: %w", err) } else if b { return nil @@ -1354,7 +1363,7 @@ func (e *EthEventHandler) waitForHeightProcessed(ctx context.Context, height abi for { select { case <-subCh: - if b, err := ei.IsHeightProcessed(ctx, uint64(height)); err != nil { + if b, err := ei.IsHeightPast(ctx, uint64(height)); err != nil { return xerrors.Errorf("failed to check if event index has events for given height: %w", err) } else if b { return nil