Skip to content

Commit 1276961

Browse files
authored
Merge pull request #728 from onflow/mpeter/poc-index-finalized-block-results
Implement the `RPCBlockHeaderSubscriber` for indexing finalized results
2 parents 9245cc6 + 76070d4 commit 1276961

24 files changed

Lines changed: 1356 additions & 124 deletions

Makefile

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,8 @@ e2e-test:
8080

8181
.PHONY: check-tidy
8282
check-tidy:
83-
go mod tidy
84-
git diff --exit-code
85-
cd tests
86-
go mod tidy
83+
go mod tidy -v
84+
cd tests; go mod tidy -v
8785
git diff --exit-code
8886

8987
.PHONY: build

api/api.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ func (b *BlockChainAPI) GetBalance(
206206
return nil, err
207207
}
208208

209-
height, err := resolveBlockTag(&blockNumberOrHash, b.blocks, b.logger)
209+
height, err := resolveBlockTag(&blockNumberOrHash, b.blocks)
210210
if err != nil {
211211
return handleError[*hexutil.Big](err, l, b.collector)
212212
}
@@ -436,7 +436,7 @@ func (b *BlockChainAPI) GetBlockReceipts(
436436
return nil, err
437437
}
438438

439-
height, err := resolveBlockTag(&blockNumberOrHash, b.blocks, b.logger)
439+
height, err := resolveBlockTag(&blockNumberOrHash, b.blocks)
440440
if err != nil {
441441
return handleError[[]map[string]any](err, l, b.collector)
442442
}
@@ -567,7 +567,7 @@ func (b *BlockChainAPI) Call(
567567
return handleError[hexutil.Bytes](err, l, b.collector)
568568
}
569569

570-
height, err := resolveBlockTag(blockNumberOrHash, b.blocks, b.logger)
570+
height, err := resolveBlockTag(blockNumberOrHash, b.blocks)
571571
if err != nil {
572572
return handleError[hexutil.Bytes](err, l, b.collector)
573573
}
@@ -689,7 +689,7 @@ func (b *BlockChainAPI) GetTransactionCount(
689689
return nil, err
690690
}
691691

692-
height, err := resolveBlockTag(&blockNumberOrHash, b.blocks, b.logger)
692+
height, err := resolveBlockTag(&blockNumberOrHash, b.blocks)
693693
if err != nil {
694694
return handleError[*hexutil.Uint64](err, l, b.collector)
695695
}
@@ -756,7 +756,7 @@ func (b *BlockChainAPI) EstimateGas(
756756
from = *args.From
757757
}
758758

759-
height, err := resolveBlockTag(blockNumberOrHash, b.blocks, b.logger)
759+
height, err := resolveBlockTag(blockNumberOrHash, b.blocks)
760760
if err != nil {
761761
return handleError[hexutil.Uint64](err, l, b.collector)
762762
}
@@ -791,7 +791,7 @@ func (b *BlockChainAPI) GetCode(
791791
return nil, err
792792
}
793793

794-
height, err := resolveBlockTag(&blockNumberOrHash, b.blocks, b.logger)
794+
height, err := resolveBlockTag(&blockNumberOrHash, b.blocks)
795795
if err != nil {
796796
return handleError[hexutil.Bytes](err, l, b.collector)
797797
}
@@ -912,7 +912,7 @@ func (b *BlockChainAPI) GetStorageAt(
912912
)
913913
}
914914

915-
height, err := resolveBlockTag(&blockNumberOrHash, b.blocks, b.logger)
915+
height, err := resolveBlockTag(&blockNumberOrHash, b.blocks)
916916
if err != nil {
917917
return handleError[hexutil.Bytes](err, l, b.collector)
918918
}

api/debug.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ func (d *DebugAPI) TraceCall(
154154
return nil, err
155155
}
156156

157-
height, err := resolveBlockTag(&blockNrOrHash, d.blocks, d.logger)
157+
height, err := resolveBlockTag(&blockNrOrHash, d.blocks)
158158
if err != nil {
159159
return nil, err
160160
}
@@ -258,7 +258,7 @@ func (d *DebugAPI) FlowHeightByBlock(
258258
return 0, err
259259
}
260260

261-
height, err := resolveBlockTag(&blockNrOrHash, d.blocks, d.logger)
261+
height, err := resolveBlockTag(&blockNrOrHash, d.blocks)
262262
if err != nil {
263263
return 0, err
264264
}

api/utils.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
func resolveBlockTag(
1919
blockNumberOrHash *rpc.BlockNumberOrHash,
2020
blocksDB storage.BlockIndexer,
21-
logger zerolog.Logger,
2221
) (uint64, error) {
2322
if blockNumberOrHash == nil {
2423
return 0, fmt.Errorf(
@@ -29,9 +28,6 @@ func resolveBlockTag(
2928
if number, ok := blockNumberOrHash.Number(); ok {
3029
height, err := resolveBlockNumber(number, blocksDB)
3130
if err != nil {
32-
logger.Error().Err(err).
33-
Stringer("block_number", number).
34-
Msg("failed to resolve block by number")
3531
return 0, err
3632
}
3733
return height, nil
@@ -40,9 +36,6 @@ func resolveBlockTag(
4036
if hash, ok := blockNumberOrHash.Hash(); ok {
4137
height, err := blocksDB.GetHeightByID(hash)
4238
if err != nil {
43-
logger.Error().Err(err).
44-
Stringer("block_hash", hash).
45-
Msg("failed to resolve block by hash")
4639
return 0, err
4740
}
4841
return height, nil

bootstrap/bootstrap.go

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ type Storages struct {
5757
Transactions storage.TransactionIndexer
5858
Receipts storage.ReceiptIndexer
5959
Traces storage.TraceIndexer
60+
EventsHash *pebble.EventsHash
6061
}
6162

6263
type Publishers struct {
@@ -159,14 +160,37 @@ func (b *Bootstrap) StartEventIngestion(ctx context.Context) error {
159160
nextCadenceHeight -= 1
160161
}
161162

162-
// create EVM event subscriber
163-
subscriber := ingestion.NewRPCEventSubscriber(
164-
b.logger,
165-
b.client,
166-
chainID,
167-
b.keystore,
168-
nextCadenceHeight,
169-
)
163+
// create event subscriber
164+
var subscriber ingestion.EventSubscriber
165+
if b.config.ExperimentalSoftFinalityEnabled {
166+
var verifier *ingestion.SealingVerifier
167+
if b.config.ExperimentalSealingVerificationEnabled {
168+
verifier = ingestion.NewSealingVerifier(
169+
b.logger,
170+
b.client,
171+
chainID,
172+
b.storages.EventsHash,
173+
nextCadenceHeight,
174+
)
175+
}
176+
177+
subscriber = ingestion.NewRPCBlockTrackingSubscriber(
178+
b.logger,
179+
b.client,
180+
chainID,
181+
b.keystore,
182+
nextCadenceHeight,
183+
verifier,
184+
)
185+
} else {
186+
subscriber = ingestion.NewRPCEventSubscriber(
187+
b.logger,
188+
b.client,
189+
chainID,
190+
b.keystore,
191+
nextCadenceHeight,
192+
)
193+
}
170194

171195
blocksProvider := replayer.NewBlocksProvider(
172196
b.storages.Blocks,
@@ -603,6 +627,7 @@ func setupStorage(
603627
blocks := pebble.NewBlocks(store, config.FlowNetworkID)
604628
storageAddress := evm.StorageAccountAddress(config.FlowNetworkID)
605629
registerStore := pebble.NewRegisterStorage(store, storageAddress)
630+
eventsHash := pebble.NewEventsHash(store)
606631

607632
batch := store.NewBatch()
608633
defer func() {
@@ -617,7 +642,20 @@ func setupStorage(
617642
if config.ForceStartCadenceHeight != 0 {
618643
logger.Warn().Uint64("height", config.ForceStartCadenceHeight).Msg("force setting starting Cadence height!!!")
619644
if err := blocks.SetLatestCadenceHeight(config.ForceStartCadenceHeight, batch); err != nil {
620-
return nil, nil, err
645+
return nil, nil, fmt.Errorf("failed to set latest cadence height: %w", err)
646+
}
647+
648+
verifiedHeight, err := eventsHash.ProcessedSealedHeight()
649+
if err != nil && !errors.Is(err, errs.ErrStorageNotInitialized) {
650+
return nil, nil, fmt.Errorf("failed to get latest verified sealed height: %w", err)
651+
}
652+
if verifiedHeight > config.ForceStartCadenceHeight {
653+
if err := eventsHash.BatchSetProcessedSealedHeight(config.ForceStartCadenceHeight, batch); err != nil {
654+
return nil, nil, fmt.Errorf("failed to set latest verified sealed height: %w", err)
655+
}
656+
if err := eventsHash.BatchRemoveAboveHeight(config.ForceStartCadenceHeight, batch); err != nil {
657+
return nil, nil, fmt.Errorf("failed to reset events hash above height: %w", err)
658+
}
621659
}
622660
}
623661

@@ -682,6 +720,7 @@ func setupStorage(
682720
Transactions: pebble.NewTransactions(store),
683721
Receipts: pebble.NewReceipts(store),
684722
Traces: pebble.NewTraces(store),
723+
EventsHash: eventsHash,
685724
}, nil
686725
}
687726

cmd/run/cmd.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ func parseConfigFromFlags() error {
254254
}
255255
}
256256

257+
if !cfg.ExperimentalSoftFinalityEnabled && cfg.ExperimentalSealingVerificationEnabled {
258+
return fmt.Errorf("experimental-sealing-verification-enabled should be enabled only when experimental-soft-finality-enabled=true")
259+
}
260+
257261
return nil
258262
}
259263

@@ -318,6 +322,8 @@ func init() {
318322
Cmd.Flags().BoolVar(&cfg.TxBatchMode, "tx-batch-mode", false, "Enable batch transaction submission, to avoid nonce mismatch issues for high-volume EOAs.")
319323
Cmd.Flags().DurationVar(&cfg.TxBatchInterval, "tx-batch-interval", time.Millisecond*1200, "Time interval upon which to submit the transaction batches to the Flow network.")
320324
Cmd.Flags().DurationVar(&cfg.EOAActivityCacheTTL, "eoa-activity-cache-ttl", time.Second*10, "Time interval used to track EOA activity. Tx send more frequently than this interval will be batched. Useful only when batch transaction submission is enabled.")
325+
Cmd.Flags().BoolVar(&cfg.ExperimentalSoftFinalityEnabled, "experimental-soft-finality-enabled", false, "Sets whether the gateway should use the experimental soft finality feature. This results in faster indexing time, because EVM state is fetched from finalized, instead of sealed Flow blocks.")
326+
Cmd.Flags().BoolVar(&cfg.ExperimentalSealingVerificationEnabled, "experimental-sealing-verification-enabled", false, "Sets whether the gateway should use the experimental soft finality sealing verification feature. This is an extra safety check for --experimental-soft-finality-enabled=true, which verifies that all finalized Flow blocks that were indexed, have eventually been sealed. The ingestion will halt, even if a single Flow block was not found to be sealed.")
321327
Cmd.Flags().BoolVar(&cfg.TxMemPoolMode, "tx-mempool-mode", false, "Enable the transaction mempool: expected-nonce transactions are submitted immediately, out-of-order transactions are held until their nonce gap fills. Mutually exclusive with --tx-batch-mode and requires --tx-state-validation=local-index.")
322328
Cmd.Flags().DurationVar(&cfg.TxCollectionWindow, "tx-collection-window", 300*time.Millisecond, "Per-EOA sliding collection window for the transaction mempool. Resets on each arrival from the same EOA.")
323329
Cmd.Flags().DurationVar(&cfg.TxSubmissionSpacing, "tx-submission-spacing", 1200*time.Millisecond, "Minimum gap between consecutive Cadence submissions for the same EOA in the transaction mempool; also serves as the flush deadline for a continuously-fed collection window. Recommended ~1.5x the block production rate.")

config/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,15 @@ type Config struct {
124124
// frequently than this interval will be batched.
125125
// Useful only when batch transaction submission is enabled.
126126
EOAActivityCacheTTL time.Duration
127+
// ExperimentalSoftFinalityEnabled enables the experimental soft finality feature which syncs
128+
// EVM block and transaction data from the upstream Access node before the block is sealed.
129+
// CAUTION: This feature is experimental and may return incorrect data in certain circumstances.
130+
ExperimentalSoftFinalityEnabled bool
131+
// ExperimentalSealingVerificationEnabled enables the experimental sealing verification feature
132+
// which verifies the hash of the EVM events ingested by the requester engine match the hash
133+
// of the events from the sealed block in the Flow network.
134+
// CAUTION: This feature is experimental and will cause the node to halt if the events don't match.
135+
ExperimentalSealingVerificationEnabled bool
127136
// TxMemPoolMode configures the gateway to use the transaction mempool:
128137
// transactions carrying the expected next nonce (with nothing in flight)
129138
// are submitted immediately, out-of-order transactions are held until their

models/events.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,11 @@ func decodeCadenceEvents(events flow.BlockEvents) (*CadenceEvents, error) {
155155
return e, nil
156156
}
157157

158+
// BlockEvents returns the Flow block events.
159+
func (c *CadenceEvents) BlockEvents() flow.BlockEvents {
160+
return c.events
161+
}
162+
158163
// Block evm block. If event doesn't contain EVM block the return value is nil.
159164
func (c *CadenceEvents) Block() *Block {
160165
return c.block

0 commit comments

Comments
 (0)