Documentation
¶
Overview ¶
Package rcl implements the Ripple Consensus Ledger algorithm. This is the default consensus algorithm used by the XRP Ledger.
Index ¶
- func IsCurrent(now, signTime, seenTime time.Time) bool
- type AncestryProvider
- type Config
- type Engine
- func (e *Engine) BuildingLedgerSeq() uint32
- func (e *Engine) CanAcceptLedger(id consensus.LedgerID) (bool, error)
- func (e *Engine) CurrentRound() (consensus.RoundID, bool)
- func (e *Engine) Done() <-chan error
- func (e *Engine) GetJSON(full bool) map[string]any
- func (e *Engine) GetLastCloseInfo() (proposers int, convergeTime time.Duration)
- func (e *Engine) IsProposing() bool
- func (e *Engine) IsValidating() bool
- func (e *Engine) Mode() consensus.Mode
- func (e *Engine) OnLedgerAcquireFailed(id consensus.LedgerID)
- func (e *Engine) OnProposal(proposal *consensus.Proposal, originPeer uint64) error
- func (e *Engine) OnTxSet(id consensus.TxSetID, txs [][]byte) error
- func (e *Engine) OnValidation(validation *consensus.Validation, originPeer uint64) error
- func (e *Engine) Phase() consensus.Phase
- func (e *Engine) ProcessVerifiedValidation(validation *consensus.Validation, origin consensus.ValidationOrigin) (consensus.ValidationDisposition, error)
- func (e *Engine) RestartRound(proposing bool) error
- func (e *Engine) SetArchive(a ValidationArchive)
- func (e *Engine) SetInMemoryLedgers(n uint32)
- func (e *Engine) SetLedgerAncestryProvider(p LedgerAncestryProvider)
- func (e *Engine) SetStallPing(ping func())
- func (e *Engine) Start(ctx context.Context) error
- func (e *Engine) StartRound(round consensus.RoundID, proposing bool) error
- func (e *Engine) Stop() error
- func (e *Engine) Subscribe(sub consensus.EventSubscriber)
- func (e *Engine) TimerEntry()
- func (e *Engine) TrySwitchToLedger(id consensus.LedgerID) (consensus.LedgerSwitchResult, error)
- type LedgerAncestryProvider
- type ValidationArchive
- type ValidationTracker
- func (vt *ValidationTracker) Add(validation *consensus.Validation) bool
- func (vt *ValidationTracker) ExpireOld(minSeq uint32)
- func (vt *ValidationTracker) GetJSONTrie() map[string]any
- func (vt *ValidationTracker) GetPreferred(largestIssued uint32) (consensus.LedgerID, uint32, bool)
- func (vt *ValidationTracker) GetTrustedFullValidations(ledgerID consensus.LedgerID, ledgerSeq uint32) []*consensus.Validation
- func (vt *ValidationTracker) PreferredFromValidations(minSeq uint32) (consensus.LedgerID, uint32, bool)
- func (vt *ValidationTracker) RecheckFullyValidated(ledgerID consensus.LedgerID, seq uint32) ([]*consensus.Validation, int, bool)
- func (vt *ValidationTracker) SetFullyValidatedCallback(fn func(ledgerID consensus.LedgerID, ledgerSeq uint32))
- func (vt *ValidationTracker) SetNow(fn func() time.Time)
- func (vt *ValidationTracker) SetOnStale(fn func(*consensus.Validation))
- func (vt *ValidationTracker) SetSeqToKeep(low, high uint32)
- func (vt *ValidationTracker) SetTrustedAndQuorum(nodes []consensus.NodeID, quorum int)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsCurrent ¶
IsCurrent reports whether a validation's sign-time and seen-time are close enough to now to be considered "current" in rippled's sense. Exact mirror of Validations.h:148-166 isCurrent:
signTime > (now - validationCURRENT_EARLY) && signTime < (now + validationCURRENT_WALL) && (seenTime == 0 || seenTime < (now + validationCURRENT_LOCAL))
Note on constant names: rippled's EARLY bounds the PAST on signTime (not "early" in the usual sense of future-side); WALL bounds the FUTURE on signTime. The prior go-xrpl implementation had the two swapped and used a past-bound on seenTime — three wire-parity bugs that would desync freshness decisions between Go and rippled peers under clock skew.
`now` is the network-adjusted time from the adaptor so the freshness window honors the close-offset consensus has converged on.
Types ¶
type AncestryProvider ¶
type AncestryProvider struct {
// contains filtered or unexported fields
}
AncestryProvider satisfies LedgerAncestryProvider. It materialises a ledger's ancestor slice once per LedgerID and caches it in an LRU, avoiding O(depth²) ParentHash walks across the trie's many Ancestor(s) calls. Partial chains carry a retry marker and are rechecked before reuse so acquisition can repair them in place.
func NewAncestryProvider ¶
func NewAncestryProvider(svc *service.Service) *AncestryProvider
NewAncestryProvider wraps the ledger service. A nil svc returns a disabled provider that always reports (nil, false).
func (*AncestryProvider) LedgerByID ¶
func (p *AncestryProvider) LedgerByID(id consensus.LedgerID) (ledgertrie.Ledger, bool)
LedgerByID implements LedgerAncestryProvider.
type Config ¶
type Config struct {
Timing consensus.Timing
Thresholds consensus.Thresholds
// Clock overrides the wall-clock source for duration metrics. Nil means
// time.Now; csf injects a virtual clock for deterministic runs.
Clock func() time.Time
// ManualTick disables the heartbeat goroutine; the caller drives ticks
// via TimerEntry. Used by csf.
ManualTick bool
}
Config holds RCL engine configuration.
func DefaultConfig ¶
func DefaultConfig() Config
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine implements the RCL consensus algorithm.
func (*Engine) BuildingLedgerSeq ¶
BuildingLedgerSeq returns the ledger sequence being built after the open phase, or zero when no ledger build is active.
func (*Engine) CanAcceptLedger ¶
func (*Engine) CurrentRound ¶
CurrentRound returns the selected round without exposing mutable engine state.
func (*Engine) GetJSON ¶
GetJSON returns the consensus-round state as a JSON map. Backs the consensus_info RPC (always full).
func (*Engine) GetLastCloseInfo ¶
GetLastCloseInfo returns the proposer count and convergence time for server_info.last_close: the last accepted round's snapshot, or — before any round is accepted — a freshness-bounded count of recent trusted proposers so a cold start doesn't report 0 while peers propose.
func (*Engine) IsProposing ¶
IsProposing reports whether we're actively proposing (lock-free atomic read; called on the RPC hot path under ledger.service.s.mu — see modeAtomic).
func (*Engine) IsValidating ¶
IsValidating reports whether the node is eligible to issue validations in this round. Sync state only determines whether those validations are full or partial. Takes no engine lock, safe on the server_info hot path.
func (*Engine) Mode ¶
Mode returns the current consensus mode via the lock-free atomic mirror (see modeAtomic).
func (*Engine) OnLedgerAcquireFailed ¶
OnLedgerAcquireFailed reports that an acquisition was invalidated by a topology change. If pinned in wrongLedger on id, un-pin so the router can re-resolve and retry without resuming consensus on the stale LCL.
func (*Engine) OnProposal ¶
OnProposal handles an incoming proposal. originPeer (0 = self) is excluded from the RelayProposal gossip forward.
func (*Engine) OnValidation ¶
func (e *Engine) OnValidation(validation *consensus.Validation, originPeer uint64) error
OnValidation is the synchronous compatibility path used by direct engine callers. The network router verifies validations on its worker queues and calls ProcessVerifiedValidation instead.
func (*Engine) ProcessVerifiedValidation ¶
func (e *Engine) ProcessVerifiedValidation( validation *consensus.Validation, origin consensus.ValidationOrigin, ) (consensus.ValidationDisposition, error)
ProcessVerifiedValidation applies a signature-verified validation to local consensus state. It deliberately performs no network I/O; the router acts on the returned disposition after this method releases the engine lock.
func (*Engine) RestartRound ¶
RestartRound starts a fresh round from the adaptor's current LCL after re-evaluating the trusted-validation preference. It is used by externally driven consensus loops that stop their timer between bounded runs.
func (*Engine) SetArchive ¶
func (e *Engine) SetArchive(a ValidationArchive)
SetArchive wires (or, with nil, detaches) the validation archive. Detach clears the onStale callback so the archive can be Close()d without a use-after-close send. Safe before or after Start; callers must not replace the owned archive concurrently with Start or Stop.
func (*Engine) SetInMemoryLedgers ¶
SetInMemoryLedgers sets how many fully-validated ledgers of validation history the tracker keeps; older validations are evicted to the archive. Zero disables auto-eviction.
func (*Engine) SetLedgerAncestryProvider ¶
func (e *Engine) SetLedgerAncestryProvider(p LedgerAncestryProvider)
SetLedgerAncestryProvider installs the trie's ancestry provider. Safe before or after Start; nil reverts to flat-count support.
func (*Engine) SetStallPing ¶
func (e *Engine) SetStallPing(ping func())
SetStallPing installs the stall watchdog's heartbeat callback, invoked once per run-loop iteration. Nil disables. Must be cheap and non-blocking — it runs inside the consensus loop.
func (*Engine) StartRound ¶
func (*Engine) Stop ¶
Stop shuts down the engine. A wired archive is drained and committed before return, and any terminal durability failure is returned.
func (*Engine) Subscribe ¶
func (e *Engine) Subscribe(sub consensus.EventSubscriber)
func (*Engine) TimerEntry ¶
func (e *Engine) TimerEntry()
TimerEntry runs one heartbeat dispatch synchronously. For ManualTick mode: an external driver (csf) advances the state machine.
func (*Engine) TrySwitchToLedger ¶
TrySwitchToLedger synchronously evaluates and adopts a locally-held ledger selected by consensus recovery, validation, or the current network view.
type LedgerAncestryProvider ¶
type LedgerAncestryProvider interface {
LedgerByID(id consensus.LedgerID) (ledgertrie.Ledger, bool)
}
LedgerAncestryProvider resolves a LedgerID to a ledgertrie.Ledger carrying its ancestry. Returns (nil, false) when the ledger's history is not locally known.
type ValidationArchive ¶
type ValidationArchive interface {
OnStale(*consensus.Validation)
NoteFullyValidated(seq uint32)
Close(ctx context.Context) error
}
ValidationArchive is the archive API subset the engine consumes, decoupling rcl from the concrete archive type.
type ValidationTracker ¶
type ValidationTracker struct {
// contains filtered or unexported fields
}
ValidationTracker tracks validations and determines ledger finality.
func NewValidationTracker ¶
func NewValidationTracker(quorum int) *ValidationTracker
NewValidationTracker creates a new validation tracker. The tracker's freshness clock defaults to time.Now; wire it to adaptor.Now via SetNow before use so isCurrent honors the network close-time offset.
func (*ValidationTracker) Add ¶
func (vt *ValidationTracker) Add(validation *consensus.Validation) bool
Add adds a validation to the tracker. Returns true if this is a new validation (not duplicate).
func (*ValidationTracker) ExpireOld ¶
func (vt *ValidationTracker) ExpireOld(minSeq uint32)
ExpireOld drops validations below minSeq from every index and fires onStale outside the mutex. Trie tips for dropped validators are also removed so phantom branchSupport doesn't linger on stale ancestors.
A set created or read within validationSetExpires is retained even below the sequence floor — rippled's access-age expiry (validationSET_EXPIRES with byLedger touch) — so hot ledgers stay queryable for RPC and late peers. Memory stays bounded: Add rejects below the engine's minSeq gate, so a below-floor set cannot reheat from the network, and it drops on the first ExpireOld after going cold. The seq floor coarsely protects the recent (negative-UNL voting) window, but is anchored at the validated tip; SetSeqToKeep pins the exact flag-ledger window so a fast-advancing tip can't outrun the vote's read.
func (*ValidationTracker) GetJSONTrie ¶
func (vt *ValidationTracker) GetJSONTrie() map[string]any
GetJSONTrie returns a JSON-serializable snapshot of the ancestry trie's support state for diagnosing preferred-ledger divergence. Returns nil when the trie is disabled (no ancestry provider wired) or a serialization panic is trapped. Guarded by vt.mu.
func (*ValidationTracker) GetPreferred ¶
GetPreferred returns the network-preferred ledger ID and sequence as decided by the ancestry trie. Parked validations whose ledger has been acquired since the last poll are replayed into the trie first, so the trie decides unconditionally (rippled getPreferred via withTrie, Validations.h:849-879). When the trie yields no tip at all, falls back to the majority over still-acquiring ledgers; ok is false only when the trie is unwired or both sources are empty. largestIssued is the highest sequence this node has validated; it seeds uncommitted support from earlier seqs.
func (*ValidationTracker) GetTrustedFullValidations ¶
func (vt *ValidationTracker) GetTrustedFullValidations( ledgerID consensus.LedgerID, ledgerSeq uint32, ) []*consensus.Validation
GetTrustedFullValidations returns deep-cloned trusted full validations for exactly (ledgerID, ledgerSeq). The sequence filter is deliberately enforced inside the tracker so every protocol voting caller sees the same evidence.
func (*ValidationTracker) PreferredFromValidations ¶
func (vt *ValidationTracker) PreferredFromValidations(minSeq uint32) (consensus.LedgerID, uint32, bool)
PreferredFromValidations returns the most-popular trusted-validator tip at seq >= minSeq, ignoring local ancestry — the no-trie fallback for GetPreferred during deep catch-up. negUNL validators are counted, matching the trie-backed GetPreferred (rippled steers on trusted() alone). Ties resolved by higher seq then lexicographic ID.
func (*ValidationTracker) RecheckFullyValidated ¶
func (vt *ValidationTracker) RecheckFullyValidated( ledgerID consensus.LedgerID, seq uint32, ) ([]*consensus.Validation, int, bool)
RecheckFullyValidated returns the validations that currently count toward finality for ledgerID together with the quorum from the same tracker state. When the set no longer reaches quorum it removes the prior firing marker before unlocking, so a concurrent or later validation can notify again.
func (*ValidationTracker) SetFullyValidatedCallback ¶
func (vt *ValidationTracker) SetFullyValidatedCallback(fn func(ledgerID consensus.LedgerID, ledgerSeq uint32))
SetFullyValidatedCallback sets the callback for when a ledger is fully validated. Fired once per ledger the first time trusted-validation count crosses the quorum threshold. Seq is passed alongside the ledger ID so the callee can look up or stamp the ledger without a secondary map lookup.
func (*ValidationTracker) SetNow ¶
func (vt *ValidationTracker) SetNow(fn func() time.Time)
SetNow replaces the clock used by isCurrent for freshness checks. Production use: wire to adaptor.Now so the freshness window honors the network-adjusted close offset (matches rippled's app_.timeKeeper().closeTime() usage in Validations.h). Tests pass fixed-time functions to get deterministic accept/reject behavior. Passing nil resets to time.Now.
func (*ValidationTracker) SetOnStale ¶
func (vt *ValidationTracker) SetOnStale(fn func(*consensus.Validation))
SetOnStale installs a callback invoked once per validation dropped by ExpireOld. Mirrors rippled's Validations<Adaptor>::onStale contract — consumed by the on-disk validation archive to persist stale validations before they leave memory. Callback runs outside the tracker's mutex so it may do blocking work (channel send to a batched writer); callers must ensure it does not call back into the tracker. Pass nil to disable.
func (*ValidationTracker) SetSeqToKeep ¶
func (vt *ValidationTracker) SetSeqToKeep(low, high uint32)
SetSeqToKeep pins validations in [low, high) so ExpireOld will not drop them, even once the retention floor advances past them. The negative-UNL vote calls this before scanning the flag-ledger window so a fast-advancing tip can't prune its low end mid-scan. Unlike the seq floor — which is anchored at the validated tip — the pin is anchored at the flag ledger, so it holds regardless of how far the tip has raced ahead or how small the configured retention is. Mirrors rippled's setSeqToKeep; a range with high <= low clears the pin.
func (*ValidationTracker) SetTrustedAndQuorum ¶
func (vt *ValidationTracker) SetTrustedAndQuorum(nodes []consensus.NodeID, quorum int)
SetTrustedAndQuorum updates the trusted set and its quorum atomically.