|
| 1 | +## Preamble |
| 2 | + |
| 3 | +``` |
| 4 | +CAP: 0083 |
| 5 | +Title: Add StellarValue type representing a skipped ledger |
| 6 | +Working Group: |
| 7 | + Owner: Brett Boston <@bboston7> |
| 8 | + Authors: Brett Boston <@bboston7> |
| 9 | + Consulted: Nicolas Barry <@MonsieurNicolas>, Giuliano Losa <@nano-o>, Marta Lokhova <@marta-lokhova> |
| 10 | +Status: Draft |
| 11 | +Created: 2026-03-31 |
| 12 | +Discussion: https://github.com/orgs/stellar/discussions/1865 |
| 13 | +Protocol version: TBD |
| 14 | +``` |
| 15 | + |
| 16 | +## Simple Summary |
| 17 | + |
| 18 | +This CAP introduces a new `StellarValue` type to allow validators to explicitly |
| 19 | +skip the ledger that is being voted on. |
| 20 | + |
| 21 | +## Working Group |
| 22 | + |
| 23 | +As specified in the preamble. |
| 24 | + |
| 25 | +## Motivation |
| 26 | + |
| 27 | +Providing a mechanism for validators to explicitly vote to skip ledgers allows |
| 28 | +them to conduct some SCP voting prior to receiving a transaction set. This will |
| 29 | +improve SCP performance, as transaction set dissemination is costly and |
| 30 | +validators can safely make initial progress on consensus while waiting for |
| 31 | +transaction sets. |
| 32 | + |
| 33 | +If, during the PREPARE phase of balloting, a validator has not received the |
| 34 | +transaction set being voted on within a reasonable amount of time, or the |
| 35 | +transaction set is invalid, they may vote to skip the current ledger. This |
| 36 | +prevents consensus from getting stuck waiting for a transaction set that may |
| 37 | +never arrive, as a valid transaction set is required before moving on to the |
| 38 | +CONFIRM phase of balloting. |
| 39 | + |
| 40 | +### Goals Alignment |
| 41 | + |
| 42 | +This CAP is aligned with the following Stellar Network Goal: |
| 43 | + |
| 44 | +* The Stellar Network should run at scale and at low cost to all participants of the network. |
| 45 | + |
| 46 | +## Abstract |
| 47 | + |
| 48 | +This CAP introduces a new `StellarValue` extension type `STELLAR_VALUE_SKIP`. |
| 49 | +With this change, validators may switch their ballot to a `STELLAR_VALUE_SKIP` |
| 50 | +during the PREPARE phase of balloting prior to setting `c`[^1]. |
| 51 | +`STELLAR_VALUE_SKIP` includes information about the value that a validator was |
| 52 | +considering before switching to voting to skip the ledger. |
| 53 | + |
| 54 | +## Specification |
| 55 | + |
| 56 | +### XDR changes |
| 57 | + |
| 58 | +To enable ledger skipping, this CAP proposes the following change to |
| 59 | +`Stellar-ledger.x`: |
| 60 | + |
| 61 | +```diff mddiffcheck.base=0a621ec7811db000a60efae5b35f78dee3aa2533 |
| 62 | +diff --git a/Stellar-ledger.x b/Stellar-ledger.x |
| 63 | +index a17036b..667f8e7 100644 |
| 64 | +--- a/Stellar-ledger.x |
| 65 | ++++ b/Stellar-ledger.x |
| 66 | +@@ -13,7 +13,8 @@ typedef opaque UpgradeType<128>; |
| 67 | + enum StellarValueType |
| 68 | + { |
| 69 | + STELLAR_VALUE_BASIC = 0, |
| 70 | +- STELLAR_VALUE_SIGNED = 1 |
| 71 | ++ STELLAR_VALUE_SIGNED = 1, |
| 72 | ++ STELLAR_VALUE_SKIP = 2 |
| 73 | + }; |
| 74 | + |
| 75 | + struct LedgerCloseValueSignature |
| 76 | +@@ -43,6 +44,14 @@ struct StellarValue |
| 77 | + void; |
| 78 | + case STELLAR_VALUE_SIGNED: |
| 79 | + LedgerCloseValueSignature lcValueSignature; |
| 80 | ++ case STELLAR_VALUE_SKIP: |
| 81 | ++ struct |
| 82 | ++ { |
| 83 | ++ Hash txSetHash; |
| 84 | ++ Hash previousLedgerHash; |
| 85 | ++ uint32 previousLedgerVersion; |
| 86 | ++ LedgerCloseValueSignature lcValueSignature; |
| 87 | ++ } proposedValue; |
| 88 | + } |
| 89 | + ext; |
| 90 | + }; |
| 91 | +``` |
| 92 | + |
| 93 | + |
| 94 | +With this change, the full `StellarValue` struct becomes: |
| 95 | +```xdr |
| 96 | +/* StellarValue is the value used by SCP to reach consensus on a given ledger |
| 97 | + */ |
| 98 | +struct StellarValue |
| 99 | +{ |
| 100 | + Hash txSetHash; // transaction set to apply to previous ledger |
| 101 | + TimePoint closeTime; // network close time |
| 102 | + |
| 103 | + // upgrades to apply to the previous ledger (usually empty) |
| 104 | + // this is a vector of encoded 'LedgerUpgrade' so that nodes can drop |
| 105 | + // unknown steps during consensus if needed. |
| 106 | + // see notes below on 'LedgerUpgrade' for more detail |
| 107 | + // max size is dictated by number of upgrade types (+ room for future) |
| 108 | + UpgradeType upgrades<6>; |
| 109 | + |
| 110 | + // reserved for future use |
| 111 | + union switch (StellarValueType v) |
| 112 | + { |
| 113 | + case STELLAR_VALUE_BASIC: |
| 114 | + void; |
| 115 | + case STELLAR_VALUE_SIGNED: |
| 116 | + LedgerCloseValueSignature lcValueSignature; |
| 117 | + case STELLAR_VALUE_SKIP: |
| 118 | + struct |
| 119 | + { |
| 120 | + Hash txSetHash; |
| 121 | + Hash previousLedgerHash; |
| 122 | + uint32 previousLedgerVersion; |
| 123 | + LedgerCloseValueSignature lcValueSignature; |
| 124 | + } proposedValue; |
| 125 | + } |
| 126 | + ext; |
| 127 | +}; |
| 128 | +``` |
| 129 | + |
| 130 | + |
| 131 | +#### XDR Example |
| 132 | +TBD |
| 133 | + |
| 134 | +### Semantics |
| 135 | + |
| 136 | +#### Skip Value Representation |
| 137 | + |
| 138 | +When the network votes to skip the ledger, validators will externalize a `StellarValue` with fields set as follows: |
| 139 | + |
| 140 | +* `txSetHash` : Set to `0x0` |
| 141 | +* `closeTime` : Set as usual |
| 142 | +* `upgrades` : Set as usual |
| 143 | +* `ext` : Set to `STELLAR_VALUE_SKIP` |
| 144 | + * `proposedValue` : Details about the original `StellarValue` that a quorum of validators decided to skip. |
| 145 | + * `proposedValue.txSetHash` : The hash of the transaction set that was insufficiently disseminated or invalid. |
| 146 | + * `proposedValue.previousLedgerHash` : The hash of the ledger prior to this one. Used to construct an empty transaction set corresponding to this skip value. |
| 147 | + * `proposedValue.previousLedgerVersion` : The ledger version of the previous ledger. Used to construct an empty transaction set corresponding to this skip value. |
| 148 | + * `proposedValue.lcValueSignature` : The signature from the original `StellarValue`. Can be used to determine which validator proposed the original `StellarValue`. |
| 149 | + |
| 150 | +#### Skip Value Application |
| 151 | + |
| 152 | +At apply time, ledgers containing a skip value should be treated as ledgers with |
| 153 | +empty transaction sets. In every other way, they should be treated as normal |
| 154 | +`STELLAR_VALUE_SIGNED` ledgers. |
| 155 | + |
| 156 | +## Design Rationale |
| 157 | + |
| 158 | +We considered a few alternative methods to achieve parallel downloading of transaction sets before landing on this protocol change: |
| 159 | + |
| 160 | +* Rather than skipping a ledger on failure to download a transaction set, we looked into rolling back SCP to an earlier phase. However, this would be a large change to SCP, which was not designed to ever step backwards. We decided it was cleaner, and easier to verify the change if validators instead voted to skip the current ledger. |
| 161 | +* We analyzed how far along consensus a validator could safely proceed without a transaction set if there was no skip or rollback mechanism, and decided that the lack of such a mechanism was too limiting. Without some method for validators to agree that a transaction set is unavailable, it is only safe to proceed with early nomination voting. |
| 162 | + |
| 163 | +## Protocol Upgrade Transition |
| 164 | + |
| 165 | +`STELLAR_VALUE_SKIP` values will become valid on the network at the protocol boundary. However, validators will not generate them unless they have enabled parallel transaction set downloading. Parallel transaction set downloading will initially be disabled by default, and we would like to gradually enable it across the validator network. |
| 166 | + |
| 167 | + |
| 168 | +### Downstream Impact |
| 169 | + |
| 170 | +Downstream consumers of `StellarValue`s may require modification. Specifically, those that reason about `txSetHash` will need to handle the new `0x0` value, and those that reason about `ext` will need to handle the new `STELLAR_VALUE_SKIP` extension. |
| 171 | + |
| 172 | +To help determine if you depend on something that contains a `StellarValue`, transitive dependencies on `StellarValue` are as follows: |
| 173 | +``` |
| 174 | +StellarValue |
| 175 | + │ |
| 176 | + ├──► LedgerHeader.scpValue |
| 177 | + │ │ |
| 178 | + │ └──► LedgerHeaderHistoryEntry.header |
| 179 | + │ │ |
| 180 | + │ ├──► LedgerCloseMetaV0.ledgerHeader |
| 181 | + │ ├──► LedgerCloseMetaV1.ledgerHeader |
| 182 | + │ └──► LedgerCloseMetaV2.ledgerHeader |
| 183 | + │ │ |
| 184 | + │ └──► LedgerCloseMeta (union) |
| 185 | + │ │ |
| 186 | + │ └──► LedgerCloseMetaBatch.ledgerCloseMetas |
| 187 | + │ |
| 188 | + └──► StoredDebugTransactionSet.scpValue |
| 189 | +``` |
| 190 | + |
| 191 | +Downstream consumers of `StellarValue`s should treat skipped ledgers as empty ledgers. |
| 192 | + |
| 193 | +### Backwards Incompatibilities |
| 194 | +As detailed in the previous section, downstream consumers of `StellarValue`s may require modification. |
| 195 | + |
| 196 | +### Resource Utilization |
| 197 | +We expect this change to increase throughput on validators by expediting consensus. Simulation has shown this to be manageable. However, we will rollout the parallel downloading portion of this change slowly to ensure that real-world performance data matches simulation. |
| 198 | + |
| 199 | +## Security Concerns |
| 200 | +This CAP introduces a new method by which malicious validators could negatively impact the network. A malicious validator could introduce bad transaction set hashes, which then force the network to skip a ledger after some delay. However, this attack is mitigated by the following factors: |
| 201 | + |
| 202 | +* The attacker would have to win leader election to propose the bad value. This limits the frequency with which this attack can be pulled off. |
| 203 | +* By design, we include the original value that was skipped in the `STELLAR_VALUE_SKIP` struct, including the signature for the value. This enables node operators to easily determine which validators are misbehaving and remove them from their quorum sets. |
| 204 | + |
| 205 | +## Test Cases |
| 206 | +TBD |
| 207 | + |
| 208 | +## Implementation |
| 209 | +TBD |
| 210 | + |
| 211 | +[^1]: See the [SCP IETF draft](https://www.ietf.org/archive/id/draft-mazieres-dinrg-scp-05.txt) for a complete semantics of `c` |
0 commit comments