Skip to content

Latest commit

 

History

History
618 lines (518 loc) · 37.4 KB

cap-0034.md

File metadata and controls

618 lines (518 loc) · 37.4 KB

CAP-0034: Preserve Transaction-Set/Close-Time Affinity During Nomination

Preamble

CAP: 0034
Title: Preserve Transaction-Set/Close-Time Affinity During Nomination
Authors: Terence Rokop, Nicolas Barry
Status: Final
Created: 2020-07-06
Discussion: https://github.com/stellar/stellar-protocol/issues/622
Protocol version: 14

Simple Summary

Make the nomination protocol select the close time from the single candidate whose transaction set it selects (rather than the current protocol's selection of the maximum close time of all candidates), and preserve the signature of the chosen <close time, transaction set> pair.

Motivation

The most severe problem addressed by the CAP is a race condition which means that smart contracts can not, with the current protocol, safely be written as chains of dependent transactions with incrementing sequence numbers, because there is no way for a client to guarantee that a transaction will succeed if it consumes a sequence number. There is always a possibility that it will return txTOO_LATE. But returning txTOO_LATE while consuming a sequence number (and being charged a fee) violates our API documentation, which states that "If the transaction is invalid, it will be immediately rejected by stellar-core based on the validity rules of a transaction, the account’s sequence number will not be incremented, and no fee will be consumed from the source account", where the referenced "validity rules of a transaction" include "The transaction must be submitted within the set time bounds of the transaction, otherwise it will be considered invalid". There may therefore be smart contracts which are structured this way, and are allowed to be structured this way according to our published API, yet are vulnerable to inconsistencies because of this race.

A less catastrophic problem, but an inefficiency, is that externalizing transaction sets that contain significant numbers of transactions that are doomed to return txTOO_LATE during ledger close might mean that we're choosing sets that we would have not have chosen over other available candidates if we had taken into account that those transactions were doomed.

More cosmetically, it might also come across as unfair, or at least counterintuitive, considering that getting into a transaction set is what a client pays a fee for, that the occasional transaction might be charged a fee despite being rejected for not having made it into a transaction set in time. Although this race is different from the perspective of stellar-core from the usual case of txTOO_LATE in which the transaction is discovered to have expired before being accepted into the transaction set, the race looks the same from the client's perspective as any other txTOO_LATE -- except that when the race is the cause, the client is, inexplicably from its perspective, charged a fee.

Closing the race that leads to a transaction returning txTOO_LATE while being charged a fee and consuming a sequence number may therefore be viewed as having desirable effects on both good-faith transactions and bad-faith (spam) transactions:

  • Good-faith transactions should not be charged a fee without being included in a ledger, and should certainly not be subject to potential inconsistencies when part of smart contracts that depend upon sequence numbers to manage dependencies.

  • Bad-faith transactions should not be allowed into fill up ledgers, starving out good-faith transactions. This CAP ensures that consensus gets the opportunity to select transaction sets from among transactions that would be guaranteed not to return txTOO_LATE if they were externalized, so ledgers would only be filled by transactions that could actually be applied.

Goals Alignment

This CAP is aligned with the following Stellar Network Goals:

  • The Stellar Network should be secure and reliable.

  • The Stellar Network should run at scale and at low cost to all users.

It also aligns with the following Stellar Network Value:

  • The protocol should bias toward simplicity.

Abstract

Currently, the nomination protocol produces, from a set of candidate StellarValues, a nominated StellarValue comprising the composited transaction set (as selected by a deterministic heuristic which chooses one particular input set and favors larger sets), the maximum closeTime of any candidate, and a set of "maximal" ledger upgrades from all candidates.

We propose to change the protocol to take the closeTime from the same candidate StellarValue as the chosen transaction set (the heuristic which decides which transaction set to choose does not change; nor does the method of generating upgrades). The protocol would then validate all transaction sets against their associated closeTimes, and could use SIGNED StellarValues throughout the ballot protocol as well as the nomination protocol.

The effect is that all trimming and validating of transaction sets during the nomination and ballot protocols use the exact same conditions as the validation of transactions does during ledger close. (Today, they differ: the nomination and ballot protocols use the last ledger close time, whereas ledger close uses the new ledger close time. This CAP allows this precise alignment because it allows the nomination and ballot protocols to predict exactly what the next ledger close time will be if the transaction set that they are validating is ultimately externalized.)

In particular, this affects how soon the core notices when transactions expire.

Specification

There are no changes to any XDR in this CAP. The treatment of the closeTime in the StellarValue XDR in some code paths changes, as does the use of SIGNED StellarValues in some places where BASIC ones are currently used, but the XDR itself does not change.

This CAP proposes to change the compositing function, which chooses a StellarValue to start the ballot protocol on, to remove the current combining of closetimes and simply select the one from the same StellarValue as the selected transaction set. (This CAP proposes to preserve the existing selection heuristic for "composited transaction set" unchanged.)

This CAP also proposes to trim and validate transaction sets in StellarValues (in all places where such trimming or validating is currently done) against the closeTime in the same StellarValue. The closeTime affects whether a transaction with an upper time bound (maxTime) returns txTOO_LATE, and whether a transaction with a lower time bound (minTime) returns txTOO_EARLY. Those are therefore the two transaction-validity tests which are affected by the change in which closeTime is used to validate transactions.

This CAP also proposes to make the nomination protocol produce a signed value (currently we nominate an unsigned, or "basic", value, because, as a combination of candidate values, it may not be equal to any one candidate value for which we have a signature). It does not propose any specific use of that signature yet, but preserving the signature as part of the same protocol change that allows it to be preserved will allow us to use it in the future if we discover a way to do so.

As with any protocol change, the new code must remember and maintain older protocols' behavior, and continue to use old behavior until after the network externalizes the ledger upgrade to the new protocol, through consensus.

The changes in this CAP build upon changes already made (without a CAP, since they were not protocol changes, but changes to the heuristics that a node uses to decide which transactions to flood and which to include in its first nominated transaction set in a new ledger) in PR 2608. Those changes already reduce the potential network burden of flooding transactions that appear likely to expire before getting into transaction sets, and they introduce some interfaces into the code which the code for this CAP can naturally re-use.

Therefore, we present the semantics in three stages: the behavior as released, the latest unreleased behavior (which contains heuristic but no protocol changes, and therefore involved no CAP), and the behavior as proposed in this CAP. Bold text indicates a semantic change from the previous stage. The proposal in this CAP embodies the bold semantics in the last column only; the bold semantics in the middle column are for context.

Index (for later reference) Decision point Released behavior Latest unreleased behavior (PR 2608) CAP behavior
1 Which transactions to flood? Valid with respect to last ledger close Valid with respect to last ledger close; unexpired with respect to estimate of next ledger close Valid with respect to last ledger close; unexpired with respect to estimate of next ledger close
2 Which time bounds to require for transactions to be included (not trimmed) in the StellarValue a node votes to nominate? Valid with respect to last ledger close Valid with respect to last ledger close; unexpired with respect to estimate of next ledger close Valid with respect to closeTime to nominate in same StellarValue
3 Which close time to validate transaction sets against in nomination and ballot protocols? Last ledger close time Last ledger close time closeTime in same StellarValue as transaction set
4 Which close time to produce in composite value? maximum of all candidates' closeTimes maximum of all candidates' closeTimes closeTime in same StellarValue as chosen ("composited") transaction set
5 Expect BASIC or SIGNED StellarValue in a composite value to be used in the ballot protocol? BASIC BASIC SIGNED

Design Rationale

It has seemed from the beginning that the problem could be addressed only through a CAP: it is a question of what relationships to maintain among the payment of fees, the consumption of sequence numbers, and the validity of transactions, that also leads to a question of what value to nominate given a set of candidates, and all of those questions must be answered by the Core through consensus.

  1. The proposal prevents the race that motivated the CAP; it ensures in all cases that a transaction that returns txTOO_LATE does not consume a sequence number and does not pay a fee. This is ensured because before a transaction set gets to the point of having its transaction fees paid (which happens when a ledger is closing), we composite the candidate <txSet,closeTime> pairs into one, and with the CAP behavior we do so by simply selecting one candidate. And every candidate has by the time of compositing been validated, including against the new condition that it contains no transactions that are expired with respect to its closeTime.

  2. The proposal prevents an ill-behaved validator from intentionally triggering the race that motivated the CAP through what we shall call "maximum closeTime injection": the ill-behaved validator could previously try to force transactions in transaction sets proposed by other nodes to fail during ledger close by proposing as large a closeTime as allowed (the maximum time slip is currently one minute).

  3. This proposal refines PR 2608's trimming of transactions prior to initial nomination by changing the next-ledger-closeTime estimate (which PR2608 itself had changed from last-ledger-closeTime) to closeTime-within-StellarValue. Given this CAP's semantics, we know at this point that that closeTime is the exact one that will be chosen as the ledger close time if the transaction set is ultimately externalized, so we can trim precisely the most efficient set of transactions: we trim all of those which would have later returned txTOO_LATE if the transaction set were ultimately externalized, and we are guaranteed that none of those which survives trimming will return txTOO_LATE if the transaction set is ultimately externalized.

  4. This CAP in general makes changes to transaction set composition and validity in the earliest protocol phases possible, making use of knowledge as soon as we have it. The previous point is an example -- we trim a transaction set prior to first nomination precisely when we decide on which closeTime to nominate in the same StellarValue with it, which also tells us precisely which transactions we may as well trim because they'll be expired at ledger close time if that StellarValue is ultimately externalized. The change in the validation of transaction sets in the nomination and ballot protocols is a similar example; we can do more accurate validation than we could before this CAP, when all we could validate against was the last ledger close time.

  5. This CAP makes the closeTime-related transaction validity checks (the tests for txTOO_EARLY and txTOO_LATE) throughout consensus exactly equivalent to those used during ledger close. Previously, the tests used during consensus (which this CAP changes to align with those used during ledger close) were weaker than the tests used during ledger close with respect to maxTime/txTOO_LATE (the consensus checks could admit transactions which, if they were ultimately externalized, ledger close would later reject with txTOO_LATE), and stronger than the tests used during ledger close with respect to minTime/txTOO_EARLY (the consensus checks could reject transactions with txTOO_EARLY which, had they been allowed and ultimately externalized, would not have been rejected with txTOO_EARLY during ledger close).

  6. This CAP, in both the change it proposes to protocol semantics and the changes it would induce in the code structure, facilitates the option to perform a follow-on change to the work done in PR 2608 which would further refine our heuristic for choosing which transactions to flood by allowing some transactions to be flooded which would be txTOO_EARLY if the next ledger were to close immediately, but which we estimate will no longer be txTOO_EARLY by the time the next ledger actually does close. (That would not introduce any race analogous to the one that this CAP fixes with respect to txTOO_LATE, because the nomination and ballot protocols would still discover that a transaction would be invalid with txTOO_EARLY before it reached the point of being in a closing ledger and therefore failing validation while nevertheless consuming a sequence number and being charged a fee.)

  7. This CAP has had a modest "test" in that it is the third proposal that we have considered, and appears not to suffer from any of the weaknesses which led us to reject the first two; see "Rejected alternatives" below for details.

Detailed illustration of failure mode with current protocol

With the current protocol, the following sequence of events can occur:

  1. A smart-contract client submits a series of transactions T1, T2 with T2's sequence number one greater than T1's. T2 is intended have its operations applied if and only if T1's are applied first; the smart contract is depending upon T2 having the wrong sequence number if T1's operations are not applied (in which case the smart contract expects that T1 will not have consumed a sequence number). The smart contract sets an expiration time on T1 (as our documentation "highly advises" that clients do).

  2. The ledger happens first to have capacity to accept T1 into a transaction set between T1's expiration time and the time at which it will turn out (of course the network can not foresee that this will eventually be the case) that the next ledger will close.

  3. T1 happens at that point to be in the transaction queue of the validator who (though again this is not predictable yet) will turn out to nominate the StellarValue that will ultimately be externalized. That node builds a transaction set that contains T1.

  4. The transaction set containing T1 is externalized, but (at least) one of the candidate closeTimes is greater than T1's expiration time.

  5. Transactions are applied using the maximum of all candidate closeTimes as the new last ledger close time. T1 therefore returns txTOO_LATE, and its operations are not applied. However, as it reached ledger close before being failed, it consumes a sequence number (and is charged a fee).

  6. T2 gets into an externalized transaction set (possibly, but not necessarily, the same one that T1 got into) before it too expires. It has the correct sequence number, because T1 consumed a sequence number. T2's operations are therefore applied -- even though its preconditions were intended to include guarantees that T1's operations had ensured, so the actual postconditions of T2 could violate any of the smart contract's intended invariants which had depended upon T1's operations having succeeded before T2's operations could be applied.

So T consumes a sequence number (and is charged a fee) but is never applied. There is a design pattern in some smart contracts which breaks, allowing inconsistent transactions to be committed, if it encounters this race: a smart contract might submit a chain of transactions, with incrementing sequence numbers, each intended to be applied only if the previous ones succeeded. If there were transactions that were intended to be constrained by the incrementing sequence numbers only to be applied if T succeeded, they could do so because T had consumed its sequence number, even though it was never applied. The dependent transactions would then perform operations which the smart contract had intended to be performed only if T had succeeded. This would potentially be arbitrarily bad for the smart contract.

With the behavior proposed in this CAP, step #3 -- a node building a transaction set containing T1 -- would only occur if T1 were not expired with respect to the closeTime in the same proposed StellarValue as that transaction set. Otherwise, T1 would not make it into a transaction set, and would therefore never consume a sequence number (or be charged a fee), and T2 would fail validation with a bad sequence number, as the smart contract intended in that case. If T1 did make it into a transaction set, then, under the new behavior in this CAP, step #5 would change -- if the transaction set containing T1 won nomination, then the closeTime of the new ledger would be the closeTime from the same StellarValue as T1, with respect to which T1 is in this case not expired. Hence, T1 would be applied during ledger close; it would not return txTOO_LATE. T2 would therefore have the opportunity to be applied (assuming it was valid in the other respects in addition to its sequence number), and in this case that would be as expected, as T1 had previously succeeded.

Note that the duration that this race window in the current protocol remains open can be lengthened (up to one minute) by the increase of any one candidate closeTime, since the current protocol combines candidate closeTimes by choosing the maximum. That means in particular that a single bad validator can open this race window significantly, with the consequences including both the failure of more transactions with txTOO_LATE and the potential for inconsistent smart contract behavior. This reflects that the current protocol's choice of the maximum candidate closeTime is, in a sense, too sensitive: it can externalize a value that could have been manipulated by a single bad actor. We refer to such manipulation as "maximum closeTime injection". The proposal in this CAP is less sensitive: a node can affect the composite closeTime only if it manages to provide a transaction set that the network as a whole selects as a composited one for the ballot protocol. We force a node to do a "good deed" (putting together a transaction set which the compositing function selects over any other node's candidate) for the network's clients in order to influence the eventual externalized closeTime. In the presence of this CAP, one node's increasing the closeTime significantly no longer triggers the smart-contract race because that is closed completely by this CAP, and it no longer reduces the number of applicable transactions in a ledger because the high closeTime provided by the bad actor does not affect the validity of transactions in transaction sets proposed by other nodes.

Detailed argument in favor of this proposal

Here we argue that this CAP would represent a clear improvement in behavior by arguing individually for each of the semantic changes in the table above, in the order presented (we shall use the "index" column for reference), so that the desirability of the first change depends only on the state of the current protocol and code, and the desirability of each further change may depend upon that of earlier changes as well, in effect assuming that they have been made because they are desirable (thus constructing an inductive argument for the desirability of the whole CAP).

  1. The first listed change was one of the optimizations made in PR 2608, without requiring a protocol change (or, therefore, CAP), so we do not need to argue for it in this CAP, but we explain it for context: by estimating when the next ledger will close and avoiding flooding any transactions which will have expired by that time, we can save the network and memory resources that we might have spent on behalf of transactions which were unlikely ever to be applied anyway. This CAP could be seen in part as propagating a similar style of change to some later stages in the protocol; those changes do require a protocol upgrade.

  2. The second listed decision point was changed in PR 2608, and we propose to refine it further in this CAP. The PR 2608 change was similar to the one made in the first decision point 1, at a different place: when we trim transactions before choosing which StellarValue to nominate first when triggering a new ledger. The change had the same idea as the aforementioned one, to minimize the use of resources on behalf of likely-useless transactions. In this CAP, we propose changing this decision point further to do the trimming based on the exact closeTime that we are nominating. Since the CAP behavior would allow us to know that that would be the exact externalized closeTime if the transaction set that we nominate were to be externalized, we know that that closeTime is optimal to use for trimming against. Knowing the optimal value, we no longer need an estimate. (The first decision point does not change because at that point we do not yet know the rest of the StellarValue that we will end up nominating -- in particular we do not yet know the closeTime -- so an estimate is the best that we can do.) And because that value is optimal -- all the transactions that it leads to being trimmed would have been guaranteed to have returned txTOO_EARLY/txTOO_LATE if the transaction set had been externalized, and all the transactions that it leads to not being trimmed are guaranteed not to return txTOO_EARLY/txTOO_LATE if the transaction set is ultimately externalized -- it is clearly desirable to use it.

  3. In the presence of change #2, which trims any premature/expired transactions before nominating a StellarValue, it is only an ill-behaved node that would nominate a StellarValue containing a transaction which is premature/expired with respect to its own closeTime, so it becomes sensible for such a value to fail validation. There is no loss in this, since we would not want to accept a StellarValue from an ill-behaved node in any case; this change (given change #2) simply represents a strict improvement in our ability to detect a particular incorrect behavior.

  4. In the presence of change #3, any candidate transaction set passed in to the compositing function consists only of transactions which are valid with respect to the closeTime in the same StellarValue as the transaction set. Therefore, once the compositing function has chosen one of the candidate transaction sets, the choice of a composited closeTime equal to the closeTime in the same StellarValue as the chosen transaction set becomes optimal in the following sense: it is precisely the latest closeTime with respect to which all of the transactions in the chosen transaction set are valid (unexpired). By comparison, the old protocol's choice of the maximal closeTime of all candidates' is simply a loss:

    • It might render some of the transactions in the composited set expired, which is the txTOO_LATE race that motivated this CAP.

    • It might render some transactions still in the memory pools of some nodes expired, when they might have had a chance of getting into a future ledger if the closeTime had not been needlessly increased.

    • It makes the ledger close time more sensitive to the choice of a large closeTime by a single bad actor, which we have called the "maximum closeTime injection" problem, and discussed above in the "Detailed illustration of failure mode".

  5. Given the ability to preserve the signature (since it is on a nominated <txSet,closeTime> pair, of which we now choose a specific one rather than combining multiple ones in producing the closeTime) in the output of the compositing function, there is little cost to doing so (we have the signature in memory and have already checked it), so we may as well lose as little information as possible. And given that we have preserved the signature on StellarValues throughout the nomination protocol and into the ballot protocol, we must expect SIGNED StellarValues in the ballot protocol, and we must check the signatures again in the ballot protocol, to make sure that the additional information that we are preserving is correct information. The additional signature-checking, however, will be on a signature that we just checked during the preceding nomination round, so we will likely simply hit in cache nearly all the time, and not have to do significantly more signature checks.

Therefore, we argue that each successive change represents a clear improvement, given the previous one (and the first represents a clear improvement over the existing implementation).

Rejected alternatives

The proposal in this CAP is the third that we have considered as a means of fixing the problems described in the "Motivation" section. We record them here to motivate the proposal that we later settled on for this CAP.

Deferring ledger time update until after applying transactions

The first idea was to change the point at which the current ledger header's closeTime was updated from before transactions are applied to afterwards. (Ledger upgrades are already performed after transaction applies.) This would prevent an increase in the closeTime brought about by candidates other than the one whose transaction set was selected from causing transactions to fail (it would not occur until after they had been applied). However, this raised the concern that sometimes transactions would be applied despite having expiration times earlier than the close time of the ledger in which they were committed -- and there would not even be any bound on how large the gap between those times might be. This CAP maintains the invariant that if a transaction is applied, the close time of the ledger in which it is applied falls within the time bounds of the transaction.

Trimming transactions rendered expired by combining nominated candidates

The second idea was to remove transactions from the composited transaction set selected by the combine-candidates code in the nomination protocol, based on the (maximal) closeTime just selected by that code. However, that would seem to have opened up a new denial-of-service attack on the ledger: an attacker could create large numbers of transactions with very high fees, making it likely that they would be accepted into transaction sets, but with extremely short expiration times, that would almost certainly come before the next ledger close. They could therefore fill up the transaction sets with such transactions, yet avoid the transaction fees (the transactions would be trimmed by the new code before fees were charged), leaving the transaction sets produced by the nomination protocol with little or no room for legitimate transactions.

Reflections on rejected alternatives

Regarding the claim in the "Design Rationale" that "this CAP in general makes changes to transaction set composition and validity in the earliest protocol phases possible", note that from the first rejected alternative, to the second rejected alternative, to the proposal in this CAP, the phase of the protocol at which we have considered placing the new trimming and validating code has moved earlier at each step. The "detailed argument in favor" of this CAP also proceeded change-by-change in order from earlier to later phases of the consensus protocol.

Aside: Changing the combining of upgrades is feasible, but unnecessary

Considering the closeTime-related changes in this CAP also raised a further discussion: because the SIGNED StellarValue, besides the transaction set and close time, also contains a set of ledger upgrades, we could choose additionally to change upgrades to come from the single selected StellarValue rather than being combined in a way similar to the closeTimes, as they are in the current protocol.

Upgrades do happen independently of the transactions: we could view the ledger closes as an optimization of alternating transaction set applies and ledger upgrades. So we did have a free choice between proposing to change upgrades in the same way as we were proposing to change closetime, or not doing so and letting them work differently (single-candidate-selection for closetimes and txsets, candidate-combination for upgrades).

There isn't any correlation that we've found among the different upgrades that we combine, in the sense that today, if changing any given parameter A from 1 to 2 and changing any given parameter B from 1 to 2 would each be sensible individually, then it would also be sensible to make both changes at once. But if the type of possible upgrades could expand to one in which certain combinations of parameter changes would be insensible, then it might no longer make sense just to combine each parameter individually -- the simple union of individual changes could produce a result which was inconsistent. In that case, the right way to combine them consistently would become ambiguous; there could be multiple options of which none would include all candidate parameter changes. Choosing the best single nominated set of upgrades might be the simplest way of choosing a consistent composite of all candidate upgrades.

Overall, changing the selection of upgrades to match that of closeTime could be said to make the resulting protocol simpler -- but it would make the change for the CAP more complicated, and we haven't found any clear benefit to making that further change. (We did start with and do some testing of an implementation that also changed upgrades selection, but in the latest implementation we have undone that part and are changing only closeTime.)

Backwards Incompatibilities

Semantic changes resulting from this CAP we hope to be limited to the correction of undesirable aspects of the current protocol, such as the potential inconsistency of smart contract behavior described in the "Motivation", and not on any aspects of the protocol that well-behaved clients could be relying on (a well-behaved client should not rely on a potentially harmful race happening!).

Security Concerns

So far, we have not found new potential issues with safety or denial-of-service introduced by the proposal in this CAP, as we did with earlier ideas that we then rejected, as described above in the "Design Rationale".

Test Cases

  • A test is added to confirm that when a node selects a StellarValue to nominate, it trims from the selected transaction set precisely those transactions which would be invalid according to the closeTime in that StellarValue, and no others (in previous protocol versions, it should continue to trim those which are invalid according to the last ledger close time).

  • A test is added to confirm that nominated StellarValues are checked for internal consistency between their close times and transaction sets -- that is, that they contain no transactions which are invalid according to their own close times (a nominated StellarValue that does not meet that condition should be rejected by other nodes). (In old protocols, transactions in a nominated StellarValue are checked for validity against the last ledger close time.)

  • A test is added to confirm that the new code which builds upon PR 2608 to allow a client to choose the closeTime to compare with a transaction's minTime correctly alters which transactions are considered txTOO_EARLY and which are not. (PR 2608 introduced the option for clients to choose a closeTime other than the last ledger close time to compare with a transaction's maxTime when determining which transactions are considered txTOO_LATE.)

  • The existing test for the compositing/combining function, which confirms that a set of candidate StellarValues produces the expected composited closeTime, changes in three ways:

    • It tests that old protocols continue to behave the same way, but that in new protocol versions, the composited closeTime is simply that of the StellarValue containing the best transaction set, not the maximum closeTime of all candidates.

    • It is enhanced to test for expected upgrades as well (but these should behave the same between old and new protocols; it just checks that the new protocol doesn't accidentally change this).

    • It tests that old nomination protocols produce BASIC StellarValues, but new nomination protocols produce SIGNED ones.

  • The existing tests which check that the StellarValue produced by the nomination protocol has the correct type changes to expect BASIC StellarValues in old protocol versions, but SIGNED StellarValues in new protocols.

Implementation

An implementation of this protocol has been written, which as far as the author knows is complete and correct in its semantics; it will certainly need refactoring, but it might constitute a demonstration of the practicality of implementing this proposal, and of a bound on the scope of the changes required, as well as a way of experimenting with its consequences:

Closetime change branch

The changes therein are limited to stellar-core, and comprise the following:

  • The protocol version is bumped (currently anticipated to be to 14).

  • The herder's choice of which transactions to include in the transaction set that it is going to nominate to depend, in new protocols only, on the close time that it is going to nominate, rather than (as in the current unreleased code) an estimate of when the next ledger is likely to close or (as in the released code) the last ledger close time.

  • The herder's validation of StellarValues nominated by other nodes changes to expect, in new protocols only, that values used by the ballot protocol are SIGNED.

  • The herder's validation of StellarValues nominated by other nodes changes which closeTime to validate the transactions in the StellarValue against from the last ledger close time to the closeTime in the StellarValue.

  • The herder's compositing of candidate StellarValues into a single value to nominate, in new protocols only (it preserves its old behavior in old protocols), changes in the following ways:

    • It chooses a composited closeTime directly from the StellarValue containing the selected transaction set. In particular, it does not need any trimming of the selected transaction set. (That set should already be consistent with closeTime, since it came from one nominated StellarValue, which the herder has already validated by the time it composites them.)

    • It returns SIGNED StellarValues.

  • Tests are modified and extended as described above under "Test Cases".