Repository navigation
Conversation
Rebuild historical SectionBloom indexes from retained transaction results with engine detection, persisted-head bounds, and failure reporting. Share bloom encoding with the node while preserving the database format. Validate engine handling, index compatibility, reruns, and error paths in the consolidated backfill suite; document operation and known limitations.
|
The output info likes this: |
sunny-tron
left a comment
There was a problem hiding this comment.
The known-limitation note in the description is accurate, but "sections covered by retained checkpoints" is hard for an operator to map to their own node. It might help to spell out when it actually applies: only when the node is stopped for the backfill shortly after upgrading to 4.8.1+, before its flushed blocks have moved past the section where the hole ends (at most ~1.7 h of blocks). Nodes that have been on 4.8.1+ for a while, or that are still on the old version, are not affected. The way to avoid it is simple too: let the node run a few minutes past that section boundary before stopping it for the backfill. With those two points, the note would tell operators both whether they need to care and what to do about it.
@sunny-tron Thanks for the suggestion. The tool targets nodes that have already upgraded to v4.8.2 or later and have been running normally. Their historical index gaps are outside the checkpoint replay window, while recent sections already have complete indexes. I've removed the limitation note from the PR description to reflect this intended usage |
| additions.or(existing); | ||
| } | ||
|
|
||
| putSectionBloomBitSet(section, bitIndex, additions, sectionBloomDb); |
There was a problem hiding this comment.
[MUST] The next node start replays the checkpoint over base and silently reverts the backfilled bits of any section the checkpoint still holds, and a rerun is reverted again until the running node has flushed past that section (on checkpoint v2, also until its newest checkpoint is more than 120 s newer than the last one holding it).
Mechanism: the tool reads and writes section-bloom only in base (L466, L475, L502-509) and never looks at the node checkpoint (v1 tmp, v2 checkpoint/<ts>). On every start the node replays the retained checkpoint(s) over base with full values, and the last writer wins (Manager L497-498 → SnapshotManager.check() → recover() L522-550). Section-bloom entries in the checkpoint are full bitsets (SectionBloomStore.write L96-114), so any key the checkpoint also holds loses the bits the tool added for blocks the node never indexed.
Sequence, reproduced at 3851a25 on RocksDB for checkpoint v1 and v2, with a plugins test that drives the production SnapshotManager, SectionBloomStore and TransactionRetStore in Manager's startup/apply/flush order (not a full FullNode; the pre-v4.8.1 phase is simulated by skipping SectionBloomStore.write) and runs the tool via Toolkit db backfill-bloom:
- A node on < v4.8.1 with filtering off applies part of section S and writes no section-bloom for it.
- It is upgraded to ≥ v4.8.1 and started, and indexes the blocks of S it applies from then on.
- It is stopped (a clean stop is enough) while its last flushed block is still in S.
tmp(v1), or on v2 the checkpoints named within 120000 ms of the newest checkpoint name, now hold the node's full-value section-S bitsets for every bit index those flushed blocks set. db backfill-bloomORs in the missing bits, exits 0 and prints "Backfill completed successfully!".- On the next start,
recover()writes the checkpoint values back. In my run, on both v1 and v2, all 68 blocks of S were fully indexed after the backfill and only the 8 blocks indexed after the upgrade were after the restart (every test block has a USDT Transfer log, so the shared address/topic keys decide each block). - A stop and rerun gives the same result, both right away and after 126 s with the node stopped: on v1,
tmpis cleared and rewritten only by the next flush (L336-339), not at startup (L486-495), andcheckV2measures 120 s against the newest checkpoint name (L508-511), not the clock. A rerun only helps once the running node has flushed past S and, on v2, written a checkpoint more than 120 s newer (by name) than the last one holding S; after that, every backfilled bit survived the restart on both versions.
There was a problem hiding this comment.
Thanks for the detailed reproduction. I've clarified the prerequisites in the README in f92e30d.
This command targets databases from fully synchronized nodes that have been running v4.8.1 or later with unconditional SectionBloom generation for a sustained period, or recent snapshots produced by such nodes. Sections containing pre-upgrade indexing gaps must already be outside the checkpoint replay range.
Under these prerequisites, recent sections covered by checkpoints are already indexed, and checkpoint replay does not undo the historical bits added by backfill.
The reproduced immediate-upgrade scenario is valid but falls outside this supported scope. The README now explicitly documents that limitation, including that the command does not inspect or update checkpoints and that waiting with the node stopped does not advance them.
With this prerequisite documented, I do not consider checkpoint reconciliation a [MUST] requirement for this PR.
There was a problem hiding this comment.
Thanks. With the prerequisites now in the README, I agree this case is outside the supported scope and not a merge blocker.
One small follow-up, non-blocking: the help text (L33-35) still says "The same block range can be safely rerun after interruption." without the condition, and DbBackfillBloomTest L125 pins that wording, while README L167 now says it holds "under these prerequisites". Could the help text carry the same qualifier, e.g. "Within the README prerequisites, the same block range can be safely rerun after interruption."?
Optional: "for a sustained period" is hard for an operator to check. A rough rule would help, e.g. the node has stayed in sync on v4.8.1+ for about two hours after the upgrade (2048 blocks × 3 s ≈ 1.7 h for the head to leave the section, plus solidification lag, plus the 120 s checkpoint-v2 window).
* release_v4.8.3: feat(framework): remove --keystore-factory support from FullNode (tronprotocol#6978) refactor(proto): remove unused proto discover definition (tronprotocol#7014) fix(config): close resource streams (tronprotocol#7002) refactor(crypto): remove unused SM2 and SM3 (tronprotocol#6999) feat(plugins): backfill section bloom (tronprotocol#6973) refactor(api): remove dead WalletExtension gRPC service and config (tronprotocol#6975) refactor(framework): decouple Manager from TronJsonRpcImpl (tronprotocol#6990) refactor(api): replace response copy wrappers with Jetty content count (tronprotocol#6982) update a new version. version name:GreatVoyage-v4.8.2.2-1-gf3e81404fe,version code:18830 (tronprotocol#7008) feat: improve node stability and execution efficiency (tronprotocol#7007)
What does this PR do?
Adds an offline Toolkit command to rebuild missing historical SectionBloom indexes from retained transaction results:
The command reads
transactionRetStoreand creates or updatessection-bloom. see this issue: #6958. It supports:latest_block_header_numberinproperties). Earlier starts are raised to the first available block; later ends are capped at the persisted header. Negative bounds and inverted ranges are rejected.section-bloom, or fromtransactionRetStorewhen creating it. Missing engine metadata retains the legacy LevelDB default. ARM64 rejects LevelDB before opening or creating databases.Usage and operational requirements are documented in
plugins/README.md.Bloom encoding is shared through
BloomUtilsin the existingcryptomodule. The node'sBloomclass delegates to this utility while retaining its public API. Toolkit decodesTransactionRetdirectly from Protobuf, so the command needs nochainbaseruntime dependency. Keccak hashing, bloom bit ordering, section keys, and the compressed database format remain compatible with the node.Why are these changes required?
Historical blocks processed before v4.8.1 with
isJsonRpcFilterEnableddisabled may lack SectionBloom indexes. Since v4.8.1, index generation is independent of this setting. This command rebuilds missing indexes from retained transaction results for address/topic filtering byeth_getLogs, without replaying the blockchain.This PR has been tested by:
DbBackfillBloomTestpassed, with no failures or skips. Coverage includes engine selection, ARM rejection, persisted-head bounds, explicit zero bounds, validation, progress reporting, and failure summaries, including workerErrorpropagation and original exception causes. Additional tests verify one read/write per changed index per section, zero writes on complete reruns, and recovery after partial section read/write failures.SectionBloomStore, covering the 2047/2048 boundary, concurrent sections, missing target creation, existing bits, repeated runs, empty/missing transaction results, empty bloom values, and malformed Protobuf.BloomUtilsTest,BloomTest,SectionBloomStoreTest,LogBlockQueryTest, andLogsFilterCapsuleTest. Shared encoder tests use an independent Keccak digest and integer-based bit representation.chainbaseand its excluded transitive dependencies are absent.checkstyleMain checkstyleTestandgit diff --checkpassed after the final changes. Encoder validation also includedjavac --release 8forBloomUtilsand the delegatingBloomclass.Automated local validation used macOS ARM64/JDK 17. The standalone command was also validated on Ubuntu x86 with real node data and
-c 16, including an initially emptysection-bloomdatabase. The full repository test suite was not run locally.Benchmark
Measured performance on Ubuntu x86 with 16 workers, using the same block range:
section-bloomdatabasesection-bloomindexesBoth runs processed 3,182 sections, found 6,508,186 blocks with logs, and completed with zero reported errors. The empty-database run wrote exactly
3,182 × 2,048 = 6,516,736index records. With existing indexes, all required bits were already present, so no records were rewritten. These are observed results; throughput depends on the workload, hardware, and cache state.Follow up
None.
Extra details
Stop the node and any other process accessing the database before running the command. The directory must contain
propertiesandtransactionRetStore, with at least one non-zero transaction-result block.storage.transHistory.switchmust have been enabled when the target blocks were processed, and those results must still be present; the tool cannot recover missing transaction results.The command can be rerun after interruption. Multiple backfill processes must not operate on the same database concurrently.