-
Notifications
You must be signed in to change notification settings - Fork 59
feat(dashmate): state sync configuration for tenderdash and drive snapshots #4521
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v4.2-dev
Are you sure you want to change the base?
Changes from 9 commits
61ae581
0ccf084
3991c40
f5cbbed
04e2b0f
0ab4b99
1d9a47a
e6ed7e2
428052c
11a3582
781b8f4
b0db723
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1087,9 +1087,37 @@ export default { | |
| required: ['txProcessingTimeLimit'], | ||
| additionalProperties: false, | ||
| }, | ||
| stateSync: { | ||
| type: 'object', | ||
| properties: { | ||
| snapshots: { | ||
| type: 'object', | ||
| properties: { | ||
| enabled: { | ||
| type: 'boolean', | ||
| description: 'Take state sync snapshots (GroveDB checkpoints) and serve them to peers', | ||
| }, | ||
| frequencySeconds: { | ||
| type: 'integer', | ||
| minimum: 60, | ||
| description: 'How often to take a snapshot, in seconds', | ||
| }, | ||
| maxCount: { | ||
| type: 'integer', | ||
| minimum: 2, | ||
| description: 'How many snapshots to keep before pruning the oldest', | ||
| }, | ||
| }, | ||
| required: ['enabled', 'frequencySeconds', 'maxCount'], | ||
| additionalProperties: false, | ||
| }, | ||
| }, | ||
| required: ['snapshots'], | ||
| additionalProperties: false, | ||
| }, | ||
| }, | ||
| additionalProperties: false, | ||
| required: ['docker', 'logs', 'tokioConsole', 'validatorSet', 'chainLock', 'epochTime', 'metrics', 'grovedbVisualizer', 'proposer'], | ||
| required: ['docker', 'logs', 'tokioConsole', 'validatorSet', 'chainLock', 'epochTime', 'metrics', 'grovedbVisualizer', 'proposer', 'stateSync'], | ||
| }, | ||
| tenderdash: { | ||
| type: 'object', | ||
|
|
@@ -1337,8 +1365,45 @@ export default { | |
| genesis: { | ||
| type: 'object', | ||
| }, | ||
| stateSync: { | ||
| type: 'object', | ||
| properties: { | ||
| enabled: { | ||
| type: 'boolean', | ||
| description: 'Bootstrap a fresh node from a state sync snapshot instead of replaying' | ||
| + ' all blocks. Ignored once the node has local state', | ||
| }, | ||
| retries: { | ||
| type: 'integer', | ||
| minimum: 0, | ||
| description: 'How many times to retry state sync before falling back to block sync.' | ||
| + ' 0 disables retries', | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Blocking: A retry count of zero prevents fallback instead of disabling retries The schema accepts source: ['claude']
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolved in Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread. |
||
| }, | ||
| chunkRequestTimeout: { | ||
| description: 'Timeout before re-requesting a snapshot chunk. Tenderdash requires at least 5s', | ||
| allOf: [ | ||
| { | ||
| $ref: '#/definitions/duration', | ||
| }, | ||
| { | ||
| type: 'string', | ||
| // At least 5 seconds: 5s+, 5000ms+, or minutes/hours down to 0.1 | ||
| pattern: '^(([5-9]|[1-9][0-9]+)(\\.[0-9]+)?s|([5-9][0-9]{3}|[1-9][0-9]{4,})(\\.[0-9]+)?ms|([1-9][0-9]*(\\.[0-9]+)?|0\\.[1-9][0-9]*)[mh])$', | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: Timeout schema rejects valid durations above five seconds The minutes/hours branch permits fractional values only from source: ['claude'] |
||
| }, | ||
| ], | ||
| }, | ||
| fetchersCount: { | ||
| type: 'integer', | ||
| minimum: 1, | ||
| maximum: 64, | ||
| description: 'Number of concurrent snapshot chunk fetchers', | ||
| }, | ||
| }, | ||
| required: ['enabled', 'retries', 'chunkRequestTimeout', 'fetchersCount'], | ||
| additionalProperties: false, | ||
| }, | ||
| }, | ||
| required: ['mode', 'docker', 'p2p', 'mempool', 'consensus', 'log', 'rpc', 'pprof', 'node', 'moniker', 'genesis', 'metrics'], | ||
| required: ['mode', 'docker', 'p2p', 'mempool', 'consensus', 'log', 'rpc', 'pprof', 'node', 'moniker', 'genesis', 'metrics', 'stateSync'], | ||
| additionalProperties: false, | ||
| }, | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -22,6 +22,14 @@ export default function analyseSystemResourcesFactory(verifySystemRequirements) | |||||||||||
| diskIO, | ||||||||||||
| } = samples.getSystemInfo(); | ||||||||||||
|
|
||||||||||||
| let stateSyncSnapshotsEnabled = false; | ||||||||||||
| try { | ||||||||||||
| stateSyncSnapshotsEnabled = samples.getDashmateConfig() | ||||||||||||
| .get('platform.drive.abci.stateSync.snapshots.enabled') === true; | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: Snapshot headroom is applied when Platform is disabled The snapshot flag is derived without checking
Suggested change
source: ['claude'] |
||||||||||||
| } catch { | ||||||||||||
| // A config collected by an older dashmate has no state sync options | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // System requirements | ||||||||||||
| const problems = verifySystemRequirements( | ||||||||||||
| { | ||||||||||||
|
|
@@ -33,6 +41,7 @@ export default function analyseSystemResourcesFactory(verifySystemRequirements) | |||||||||||
| samples.getDashmateConfig().get('platform.enable'), | ||||||||||||
| { | ||||||||||||
| diskSpace: 5, | ||||||||||||
| stateSyncSnapshotsEnabled, | ||||||||||||
| }, | ||||||||||||
| ); | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -81,7 +81,7 @@ filter-peers = false | |
| # Example for routed multi-app setup: | ||
| # abci = "routed" | ||
| # address = "Info:socket:unix:///tmp/socket.1,Info:socket:unix:///tmp/socket.2,CheckTx:socket:unix:///tmp/socket.1,*:socket:unix:///tmp/socket.3" | ||
| address = "CheckTx:grpc:drive_abci:26670,*:socket:tcp://drive_abci:26658" | ||
| address = "CheckTx:grpc:drive_abci:26670,ListSnapshots:grpc:drive_abci:26670,LoadSnapshotChunk:grpc:drive_abci:26670,*:socket:tcp://drive_abci:26658" | ||
| # Transport mechanism to connect to the ABCI application: socket | grpc | routed | ||
| transport = "routed" | ||
| # Maximum number of simultaneous connections to the ABCI application | ||
|
|
@@ -97,6 +97,10 @@ transport = "routed" | |
| #] | ||
| grpc-concurrency = [ | ||
| { "check_tx" = {{= it.platform.drive.tenderdash.mempool.maxConcurrentCheckTx }} }, | ||
| # Snapshot serving: discovery is one request per peer, chunk downloads run | ||
| # several concurrent fetchers per syncing peer. | ||
| { "list_snapshots" = 10 }, | ||
| { "load_snapshot_chunk" = 100 }, | ||
| ] | ||
|
Comment on lines
98
to
111
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: Routed transport drops the new gRPC concurrency limits These snapshot limits are not applied when source: ['claude']
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolved in Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread. |
||
|
|
||
|
|
||
|
|
@@ -418,40 +422,38 @@ ttl-num-blocks = {{=it.platform.drive.tenderdash.mempool.ttlNumBlocks}} | |
| # the network to take and serve state machine snapshots. State sync is not attempted if the node | ||
| # has any local state (LastBlockHeight > 0). The node will have a truncated block history, | ||
| # starting from the height of the snapshot. | ||
| enable = false | ||
| enable = {{? it.platform.drive.tenderdash.stateSync.enabled }}true{{??}}false{{?}} | ||
|
|
||
| # State sync uses light client verification to verify state. This can be done either through the | ||
| # P2P layer or RPC layer. Set this to true to use the P2P layer. If false (default), RPC layer | ||
| # will be used. | ||
| use-p2p = false | ||
| # P2P layer or RPC layer. Set this to true to use the P2P layer. | ||
| # Hardcoded to P2P: the RPC mode needs at least two reachable RPC servers, but dashmate | ||
| # publishes the Tenderdash RPC on loopback only and does not proxy it through the gateway | ||
| # (no TLS or auth), so the RPC state provider is not viable here. | ||
| use-p2p = true | ||
|
|
||
| # If using RPC, at least two addresses need to be provided. They should be compatible with net.Dial, | ||
| # for example: "host.example.com:2125" | ||
| rpc-servers = "" | ||
|
|
||
| # The hash and height of a trusted block. Must be within the trust-period. | ||
| trust-height = 0 | ||
| trust-hash = "" | ||
|
|
||
| # The trust period should be set so that Tendermint can detect and gossip misbehavior before | ||
| # it is considered expired. For chains based on the Cosmos SDK, one day less than the unbonding | ||
| # period should suffice. | ||
| trust-period = "168h0m0s" | ||
|
|
||
| # Time to spend discovering snapshots before initiating a restore. | ||
| discovery-time = "15s" | ||
|
|
||
| # The number of times to retry state sync. When retries are exhausted, the node falls back | ||
| # to block sync. Set to 0 to disable retries. In the pessimistic case it takes at least | ||
| # discovery-time * retries before falling back. | ||
| retries = {{= it.platform.drive.tenderdash.stateSync.retries }} | ||
|
|
||
| # Temporary directory for state sync snapshot chunks, defaults to os.TempDir(). | ||
| # The synchronizer will create a new, randomly named directory within this directory | ||
| # and remove it when the sync is complete. | ||
| temp-dir = "" | ||
|
|
||
| # The timeout duration before re-requesting a chunk, possibly from a different | ||
| # peer (default: 15 seconds). | ||
| chunk-request-timeout = "15s" | ||
| chunk-request-timeout = "{{= it.platform.drive.tenderdash.stateSync.chunkRequestTimeout }}" | ||
|
|
||
| # The number of concurrent chunk and block fetchers to run (default: 4). | ||
| fetchers = "4" | ||
| fetchers = "{{= it.platform.drive.tenderdash.stateSync.fetchersCount }}" | ||
|
|
||
| ####################################################### | ||
| ### Consensus Configuration Options ### | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 Blocking: Default snapshot serving exposes unbounded remote checkpoint retention
This default is migrated into existing non-local configurations and exported as
SNAPSHOTS_ENABLED=true, exposing the companion Drive snapshot handler to unauthenticated P2P chunk requests. Tenderdash forwards arbitrary peer-supplied snapshot heights, versions, and chunk IDs directly toLoadSnapshotChunk. Drive resolves checkpoints from either the normal registry or its serving-pin map, refreshes the pin before fetching the requested chunk, and retains pins using only a refreshable 600-second inactivity timeout with no absolute lifetime or count bound. A peer can pin each advertised checkpoint before normal pruning and periodically submit malformed chunk requests for every retained height; the request refreshes the pin before fetching fails, and Tenderdash logs the ABCI error without penalizing the peer. The configuredmaxCount: 6therefore does not bound checkpoint disk usage, allowing stale RocksDB files to accumulate until disk exhaustion. Keep snapshot serving disabled by default until Drive enforces a hard lifetime, count, or disk bound and cannot refresh retired snapshots through arbitrary requests.source: ['claude']