Commit 790fccd4 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge pull request #5188 from ethereum-optimism/find-sync-start-cache-improvements

op-node: make find-sync-start more resilient against errors by improving cache usage
parents 6233248f affa066f
...@@ -216,17 +216,17 @@ func TestEngineQueue_Finalize(t *testing.T) { ...@@ -216,17 +216,17 @@ func TestEngineQueue_Finalize(t *testing.T) {
eng.ExpectL2BlockRefByHash(refF0.ParentHash, refE1, nil) eng.ExpectL2BlockRefByHash(refF0.ParentHash, refE1, nil)
// meet previous safe, counts 1/2 // meet previous safe, counts 1/2
l1F.ExpectL1BlockRefByNumber(refE.Number, refE, nil) l1F.ExpectL1BlockRefByHash(refE.Hash, refE, nil)
eng.ExpectL2BlockRefByHash(refE1.ParentHash, refE0, nil) eng.ExpectL2BlockRefByHash(refE1.ParentHash, refE0, nil)
eng.ExpectL2BlockRefByHash(refE0.ParentHash, refD1, nil) eng.ExpectL2BlockRefByHash(refE0.ParentHash, refD1, nil)
// now full seq window, inclusive // now full seq window, inclusive
l1F.ExpectL1BlockRefByNumber(refD.Number, refD, nil) l1F.ExpectL1BlockRefByHash(refD.Hash, refD, nil)
eng.ExpectL2BlockRefByHash(refD1.ParentHash, refD0, nil) eng.ExpectL2BlockRefByHash(refD1.ParentHash, refD0, nil)
eng.ExpectL2BlockRefByHash(refD0.ParentHash, refC1, nil) eng.ExpectL2BlockRefByHash(refD0.ParentHash, refC1, nil)
// now one more L1 origin // now one more L1 origin
l1F.ExpectL1BlockRefByNumber(refC.Number, refC, nil) l1F.ExpectL1BlockRefByHash(refC.Hash, refC, nil)
eng.ExpectL2BlockRefByHash(refC1.ParentHash, refC0, nil) eng.ExpectL2BlockRefByHash(refC1.ParentHash, refC0, nil)
// parent of that origin will be considered safe // parent of that origin will be considered safe
eng.ExpectL2BlockRefByHash(refC0.ParentHash, refB1, nil) eng.ExpectL2BlockRefByHash(refC0.ParentHash, refB1, nil)
...@@ -450,17 +450,17 @@ func TestEngineQueue_ResetWhenUnsafeOriginNotCanonical(t *testing.T) { ...@@ -450,17 +450,17 @@ func TestEngineQueue_ResetWhenUnsafeOriginNotCanonical(t *testing.T) {
eng.ExpectL2BlockRefByHash(refF0.ParentHash, refE1, nil) eng.ExpectL2BlockRefByHash(refF0.ParentHash, refE1, nil)
// meet previous safe, counts 1/2 // meet previous safe, counts 1/2
l1F.ExpectL1BlockRefByNumber(refE.Number, refE, nil) l1F.ExpectL1BlockRefByHash(refE.Hash, refE, nil)
eng.ExpectL2BlockRefByHash(refE1.ParentHash, refE0, nil) eng.ExpectL2BlockRefByHash(refE1.ParentHash, refE0, nil)
eng.ExpectL2BlockRefByHash(refE0.ParentHash, refD1, nil) eng.ExpectL2BlockRefByHash(refE0.ParentHash, refD1, nil)
// now full seq window, inclusive // now full seq window, inclusive
l1F.ExpectL1BlockRefByNumber(refD.Number, refD, nil) l1F.ExpectL1BlockRefByHash(refD.Hash, refD, nil)
eng.ExpectL2BlockRefByHash(refD1.ParentHash, refD0, nil) eng.ExpectL2BlockRefByHash(refD1.ParentHash, refD0, nil)
eng.ExpectL2BlockRefByHash(refD0.ParentHash, refC1, nil) eng.ExpectL2BlockRefByHash(refD0.ParentHash, refC1, nil)
// now one more L1 origin // now one more L1 origin
l1F.ExpectL1BlockRefByNumber(refC.Number, refC, nil) l1F.ExpectL1BlockRefByHash(refC.Hash, refC, nil)
eng.ExpectL2BlockRefByHash(refC1.ParentHash, refC0, nil) eng.ExpectL2BlockRefByHash(refC1.ParentHash, refC0, nil)
// parent of that origin will be considered safe // parent of that origin will be considered safe
eng.ExpectL2BlockRefByHash(refC0.ParentHash, refB1, nil) eng.ExpectL2BlockRefByHash(refC0.ParentHash, refB1, nil)
...@@ -782,17 +782,17 @@ func TestVerifyNewL1Origin(t *testing.T) { ...@@ -782,17 +782,17 @@ func TestVerifyNewL1Origin(t *testing.T) {
} }
// meet previous safe, counts 1/2 // meet previous safe, counts 1/2
l1F.ExpectL1BlockRefByNumber(refE.Number, refE, nil) l1F.ExpectL1BlockRefByHash(refE.Hash, refE, nil)
eng.ExpectL2BlockRefByHash(refE1.ParentHash, refE0, nil) eng.ExpectL2BlockRefByHash(refE1.ParentHash, refE0, nil)
eng.ExpectL2BlockRefByHash(refE0.ParentHash, refD1, nil) eng.ExpectL2BlockRefByHash(refE0.ParentHash, refD1, nil)
// now full seq window, inclusive // now full seq window, inclusive
l1F.ExpectL1BlockRefByNumber(refD.Number, refD, nil) l1F.ExpectL1BlockRefByHash(refD.Hash, refD, nil)
eng.ExpectL2BlockRefByHash(refD1.ParentHash, refD0, nil) eng.ExpectL2BlockRefByHash(refD1.ParentHash, refD0, nil)
eng.ExpectL2BlockRefByHash(refD0.ParentHash, refC1, nil) eng.ExpectL2BlockRefByHash(refD0.ParentHash, refC1, nil)
// now one more L1 origin // now one more L1 origin
l1F.ExpectL1BlockRefByNumber(refC.Number, refC, nil) l1F.ExpectL1BlockRefByHash(refC.Hash, refC, nil)
eng.ExpectL2BlockRefByHash(refC1.ParentHash, refC0, nil) eng.ExpectL2BlockRefByHash(refC1.ParentHash, refC0, nil)
// parent of that origin will be considered safe // parent of that origin will be considered safe
eng.ExpectL2BlockRefByHash(refC0.ParentHash, refB1, nil) eng.ExpectL2BlockRefByHash(refC0.ParentHash, refB1, nil)
......
...@@ -126,8 +126,17 @@ func FindL2Heads(ctx context.Context, cfg *rollup.Config, l1 L1Chain, l2 L2Chain ...@@ -126,8 +126,17 @@ func FindL2Heads(ctx context.Context, cfg *rollup.Config, l1 L1Chain, l2 L2Chain
// then we return the last L2 block of the epoch before that as safe head. // then we return the last L2 block of the epoch before that as safe head.
// Each loop iteration we traverse a single L2 block, and we check if the L1 origins are consistent. // Each loop iteration we traverse a single L2 block, and we check if the L1 origins are consistent.
for { for {
// Fetch L1 information if we never had it, or if we do not have it for the current origin // Fetch L1 information if we never had it, or if we do not have it for the current origin.
if l1Block == (eth.L1BlockRef{}) || n.L1Origin.Hash != l1Block.Hash { // Optimization: as soon as we have a previous L1 block, try to traverse L1 by hash instead of by number, to fill the cache.
if n.L1Origin.Hash == l1Block.ParentHash {
b, err := l1.L1BlockRefByHash(ctx, n.L1Origin.Hash)
if err != nil {
// Exit, find-sync start should start over, to move to an available L1 chain with block-by-number / not-found case.
return nil, fmt.Errorf("failed to retrieve L1 block: %w", err)
}
l1Block = b
ahead = false
} else if l1Block == (eth.L1BlockRef{}) || n.L1Origin.Hash != l1Block.Hash {
b, err := l1.L1BlockRefByNumber(ctx, n.L1Origin.Number) b, err := l1.L1BlockRefByNumber(ctx, n.L1Origin.Number)
// if L2 is ahead of L1 view, then consider it a "plausible" head // if L2 is ahead of L1 view, then consider it a "plausible" head
notFound := errors.Is(err, ethereum.NotFound) notFound := errors.Is(err, ethereum.NotFound)
......
...@@ -24,6 +24,7 @@ type L1ClientConfig struct { ...@@ -24,6 +24,7 @@ type L1ClientConfig struct {
func L1ClientDefaultConfig(config *rollup.Config, trustRPC bool, kind RPCProviderKind) *L1ClientConfig { func L1ClientDefaultConfig(config *rollup.Config, trustRPC bool, kind RPCProviderKind) *L1ClientConfig {
// Cache 3/2 worth of sequencing window of receipts and txs // Cache 3/2 worth of sequencing window of receipts and txs
span := int(config.SeqWindowSize) * 3 / 2 span := int(config.SeqWindowSize) * 3 / 2
fullSpan := span
if span > 1000 { // sanity cap. If a large sequencing window is configured, do not make the cache too large if span > 1000 { // sanity cap. If a large sequencing window is configured, do not make the cache too large
span = 1000 span = 1000
} }
...@@ -40,7 +41,8 @@ func L1ClientDefaultConfig(config *rollup.Config, trustRPC bool, kind RPCProvide ...@@ -40,7 +41,8 @@ func L1ClientDefaultConfig(config *rollup.Config, trustRPC bool, kind RPCProvide
MustBePostMerge: false, MustBePostMerge: false,
RPCProviderKind: kind, RPCProviderKind: kind,
}, },
L1BlockRefsCacheSize: span, // Not bounded by span, to cover find-sync-start range fully for speedy recovery after errors.
L1BlockRefsCacheSize: fullSpan,
} }
} }
......
...@@ -34,6 +34,7 @@ func L2ClientDefaultConfig(config *rollup.Config, trustRPC bool) *L2ClientConfig ...@@ -34,6 +34,7 @@ func L2ClientDefaultConfig(config *rollup.Config, trustRPC bool) *L2ClientConfig
span *= 12 span *= 12
span /= int(config.BlockTime) span /= int(config.BlockTime)
} }
fullSpan := span
if span > 1000 { // sanity cap. If a large sequencing window is configured, do not make the cache too large if span > 1000 { // sanity cap. If a large sequencing window is configured, do not make the cache too large
span = 1000 span = 1000
} }
...@@ -50,7 +51,8 @@ func L2ClientDefaultConfig(config *rollup.Config, trustRPC bool) *L2ClientConfig ...@@ -50,7 +51,8 @@ func L2ClientDefaultConfig(config *rollup.Config, trustRPC bool) *L2ClientConfig
MustBePostMerge: true, MustBePostMerge: true,
RPCProviderKind: RPCKindBasic, RPCProviderKind: RPCKindBasic,
}, },
L2BlockRefsCacheSize: span, // Not bounded by span, to cover find-sync-start range fully for speedy recovery after errors.
L2BlockRefsCacheSize: fullSpan,
L1ConfigsCacheSize: span, L1ConfigsCacheSize: span,
RollupCfg: config, RollupCfg: config,
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment