diff --git a/node/config/doc_gen.go b/node/config/doc_gen.go index 5a5bd4a8c..41466919e 100644 --- a/node/config/doc_gen.go +++ b/node/config/doc_gen.go @@ -383,6 +383,21 @@ this time become eligible for automatic deletion.`, Comment: `MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying the entire chain)`, + }, + { + Name: "FilterThresholdSet", + Type: "bool", + + Comment: `FilterThresholdSet signals whether a FilterThresholdEpoch is set. If it is it will be used instead of +MaxFilterHeightRange to define the supported range.`, + }, + { + Name: "FilterThresholdEpoch", + Type: "uint64", + + Comment: `FilterThresholdEpoch specifies an epoch above which the node will support returning filtered logs. +This is useful for setting a static start epoch for support, rather than a static window size with a start epoch +that shifts as the chain progresses.`, }, { Name: "DatabasePath", diff --git a/node/config/types.go b/node/config/types.go index 013e2db1a..5c4ca4b56 100644 --- a/node/config/types.go +++ b/node/config/types.go @@ -717,6 +717,16 @@ type Events struct { // the entire chain) MaxFilterHeightRange uint64 + // FilterThresholdSet signals whether a FilterThresholdEpoch is set. If it is it will be used instead of + // MaxFilterHeightRange to define the supported range. + FilterThresholdSet bool + + // FilterThresholdEpoch specifies an epoch above which the node will support returning filtered logs. + // This is useful for setting a static start epoch for support, rather than a static window size with a start epoch + // that shifts as the chain progresses. + FilterThresholdEpoch uint64 + + // DatabasePath is the full path to a sqlite database that will be used to index actor events to // support the historic filter APIs. If the database does not exist it will be created. The directory containing // the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index a051b49b1..799ae4ffe 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -143,6 +143,8 @@ type EthEvent struct { FilterStore filter.FilterStore SubManager *EthSubscriptionManager MaxFilterHeightRange abi.ChainEpoch + FilterThresholdSet bool + FilterThresholdEpoch abi.ChainEpoch SubscribtionCtx context.Context } @@ -1292,27 +1294,53 @@ func (e *EthEvent) installEthFilterSpec(ctx context.Context, filterSpec *ethtype } // Validate height ranges are within limits set by node operator - if minHeight == -1 && maxHeight > 0 { - // Here the client is looking for events between the head and some future height - ts := e.Chain.GetHeaviestTipSet() - if maxHeight-ts.Height() > e.MaxFilterHeightRange { - return nil, xerrors.Errorf("invalid epoch range: to block is too far in the future (maximum: %d)", e.MaxFilterHeightRange) - } - } else if minHeight >= 0 && maxHeight == -1 { - // Here the client is looking for events between some time in the past and the current head - ts := e.Chain.GetHeaviestTipSet() - if ts.Height()-minHeight > e.MaxFilterHeightRange { - return nil, xerrors.Errorf("invalid epoch range: from block is too far in the past (maximum: %d)", e.MaxFilterHeightRange) + if e.FilterThresholdSet { + if minHeight == -1 && maxHeight > 0 { + // Here the client is looking for events between the head and some future height + ts := e.Chain.GetHeaviestTipSet() + if maxHeight < ts.Height() { + return nil, xerrors.Errorf("invalid epoch range: to block (%d) must be after from block (%d)", maxHeight, ts.Height()) + } + if ts.Height() < e.FilterThresholdEpoch { + return nil, xerrors.Errorf("invalid epoch range: from block (%d) is below the set FilterThresholdEpoch (%d)", ts.Height(), e.FilterThresholdEpoch) + } + } else if minHeight >= 0 && maxHeight == -1 { + // Here the client is looking for events between some time in the past and the current head + if minHeight < e.FilterThresholdEpoch { + return nil, xerrors.Errorf("invalid epoch range: from block is too far in the past (minimum from epoch: %d)", e.FilterThresholdEpoch) + } + } else if minHeight >= 0 && maxHeight >= 0 { + if minHeight > maxHeight { + return nil, xerrors.Errorf("invalid epoch range: to block (%d) must be after from block (%d)", maxHeight, minHeight) + } else if minHeight < e.FilterThresholdEpoch { + return nil, xerrors.Errorf("invalid epoch range: from block (%d) is below the set FilterThresholdEpoch (%d)", minHeight, e.FilterThresholdEpoch) + } } + } else { + if minHeight == -1 && maxHeight > 0 { + // Here the client is looking for events between the head and some future height + ts := e.Chain.GetHeaviestTipSet() + if maxHeight < ts.Height() { + return nil, xerrors.Errorf("invalid epoch range: to block (%d) must be after from block (%d)", maxHeight, ts.Height()) + } + if maxHeight-ts.Height() > e.MaxFilterHeightRange { + return nil, xerrors.Errorf("invalid epoch range: to block is too far in the future (maximum: %d)", e.MaxFilterHeightRange) + } + } else if minHeight >= 0 && maxHeight == -1 { + // Here the client is looking for events between some time in the past and the current head + ts := e.Chain.GetHeaviestTipSet() + if ts.Height()-minHeight > e.MaxFilterHeightRange { + return nil, xerrors.Errorf("invalid epoch range: from block is too far in the past (maximum: %d)", e.MaxFilterHeightRange) + } - } else if minHeight >= 0 && maxHeight >= 0 { - if minHeight > maxHeight { - return nil, xerrors.Errorf("invalid epoch range: to block (%d) must be after from block (%d)", minHeight, maxHeight) - } else if maxHeight-minHeight > e.MaxFilterHeightRange { - return nil, xerrors.Errorf("invalid epoch range: range between to and from blocks is too large (maximum: %d)", e.MaxFilterHeightRange) + } else if minHeight >= 0 && maxHeight >= 0 { + if minHeight > maxHeight { + return nil, xerrors.Errorf("invalid epoch range: to block (%d) must be after from block (%d)", maxHeight, minHeight) + } else if maxHeight-minHeight > e.MaxFilterHeightRange { + return nil, xerrors.Errorf("invalid epoch range: range between to and from blocks is too large (maximum: %d)", e.MaxFilterHeightRange) + } } } - } // Convert all addresses to filecoin f4 addresses diff --git a/node/modules/actorevent.go b/node/modules/actorevent.go index 4ce04cefd..400203849 100644 --- a/node/modules/actorevent.go +++ b/node/modules/actorevent.go @@ -40,6 +40,8 @@ func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo ee := &full.EthEvent{ Chain: cs, MaxFilterHeightRange: abi.ChainEpoch(cfg.Events.MaxFilterHeightRange), + FilterThresholdSet: cfg.Events.FilterThresholdSet, + FilterThresholdEpoch: abi.ChainEpoch(cfg.Events.FilterThresholdEpoch), SubscribtionCtx: ctx, }