Skip to content

Latest commit

 

History

History
223 lines (179 loc) · 8.11 KB

cap-0001.md

File metadata and controls

223 lines (179 loc) · 8.11 KB

Preamble

CAP: 0001
Title: Bump Sequence
Author: Nicolas Barry, David Mazieres, Jeremy Rubin
Status: Final
Created: 2018-02-08
Discussion: https://github.com/stellar/stellar-protocol/issues/53
Protocol version: 10

Simple Summary

The Bump Sequence operation allows you to bump forward the sequence number of the source account of the operation.

If the specified bumpTo sequence number is greater than the source account's sequence number, the account's sequence number is updated with that value, otherwise it's not modified.

Abstract

The Bump sequence operation allows you to bump forward the sequence number of the source account of the operation.

Motivation

Addresses a need when dealing with a large number of pre-signed transactions where there is a need to invalidate an execution branch. The problem is solved by allowing the branches of pre-signed transactions to have non-overlapping sequence numbers and creating a new operation to change the sequence number of the account to an arbitrary number.

Specification

The Bump Sequence operation allows you to bump forward the sequence number of the source account of the operation.

If the specified bumpTo sequence number is greater than the source account's sequence number, the account's sequence number is updated with that value, otherwise it's not modified.

Threshold is "Low", in line with the weight required by a signer for the source account to update the sequence number for all transactions.

Note: This operation only allows bumping the sequence number up to (current_ledger_number<<32) - 1.

BumpSequenceOp specification:

struct BumpSequenceOp
{
    SequenceNumber bumpTo;
};

/******* BumpSequence Result ********/

enum BumpSequenceResultCode
{
    // codes considered as "success" for the operation
    BUMP_SEQUENCE_SUCCESS = 0,
    // codes considered as "failure" for the operation
    BUMP_SEQUENCE_BAD_SEQ = -1 // `bumpTo` is not within bounds
};

union BumpSequenceResult switch (BumpSequenceResultCode code)
{
case BUMP_SEQUENCE_SUCCESS:
    void;
default:
    void;
};

New error code for AccountMerge:

/******* AccountMerge Result ********/

enum AccountMergeResultCode
{
    // codes considered as "success" for the operation
    ACCOUNT_MERGE_SUCCESS = 0,
    // codes considered as "failure" for the operation
    ACCOUNT_MERGE_MALFORMED = -1,       // can't merge onto itself
    ACCOUNT_MERGE_NO_ACCOUNT = -2,      // destination does not exist
    ACCOUNT_MERGE_IMMUTABLE_SET = -3,   // source account has AUTH_IMMUTABLE set
    ACCOUNT_MERGE_HAS_SUB_ENTRIES = -4, // account has trust lines/offers
    ACCOUNT_MERGE_SEQNUM_TOO_FAR = -5   // sequence number is over max allowed
};

New error code at the operation level:

enum OperationResultCode
{
    opINNER = 0, // inner object result is valid

    opBAD_AUTH = -1,     // too few valid signatures / wrong network
    opNO_ACCOUNT = -2,   // source account was not found
    opNOT_SUPPORTED = -3 // operation not supported at this time
};

Updated meta data format: Transactions now update the sequence number right before applying their operations.

struct TransactionMetaV1
{
    LedgerEntryChanges txChanges; // tx level changes if any
    OperationMeta operations<>; // meta for each operation
};

// this is the meta produced when applying transactions
// it does not include pre-apply updates such as fees
union TransactionMeta switch (int v)
{
case 0:
    OperationMeta operations<>;
case 1:
    TransactionMetaV1 v1;
};

Finally this change also switches SequenceNumber to be a signed integer:

typedef int64 SequenceNumber;

Rationale

BumpSequenceOp is a new operation, in order to properly reject the use of this new operation from nodes that understand the xdr but with the network still running an older protocol version, a new return value is added to operation result to communicate the failure. Note that this error code should never appear in results processed post consensus as operations failing that way are deemed "invalid".

In addition, to avoid sequence number reuse by re-creating an account that was merged, AccountMerge is modified to not allow merging the account if it would open the possibility of the account being re-created with a smaller sequence number.

The move to signed integers for SequenceNumber was driven by the same rationale than for why amounts are modeled as signed integers and the fact that BumpSeqOp makes it a lot likier to have sequence numbers in the high 64 bit range: many languages and systems (SQL) do not support unsigned integers properly which may lead to crashes or unexpected behaviors.

Considerations on how transaction sets are applied to ledgers

pre v10 implementation

Currently a transaction set is processed in two phases:

  • fees and sequence numbers are collected globally
  • transactions (and their operations) are applied

The problem with this approach is that with the introduction of an operation like BumpSequenceOp, we have some inconsistencies in the way transactions are processed:

if a transaction bumps the sequence number of an account used in a later transaction, the second transaction is expected to fail but with the current implementation, it won't (as sequence number checks are performed while collecting fees).

One the reasons that BumpSequenceOp is introduced is to invalidate ranges of transactions, and with the current behavior it would make it difficult to reason about the correctness of sequence of transactions.

Updated sequence number processing

Only process fees first:

  • fees are collected globally as they are now
  • transactions are applied, before applying individual transactions:
    • numbers are checked for validity
    • if the sequence number was valid, update the account's sequence number

We would not change the logic to construct or validate a transaction set: a transaction set would still be built with transactions that have consecutive sequence numbers.

The difference is that in the event that a transaction is invalidated by an operation from a different transaction, it would fail (collecting fees), which allows for transactions that make use of BumpSequenceOp to be able to make clean assumptions for any operations scheduled for after the bump.

This change will require a new meta data format that can represent transaction level changes when applying the transaction and its operations.

Backwards Compatibility

As the sequence number is updated as part of the regular processing of operations, it requires to emit transaction level meta data, which only existed as part of the fee processing (included in the txfeehistory table). The implementation will switch to using the new meta format for all transactions, including the ones for older versions of the protocol (which will not emit any transaction level meta data as expected). While this is not strictly necessary, it's safer as it makes it obvious that downstream systems (such as Horizon) need to be updated to support the new meta data format; the alternative would have been to change the meta data format with the protocol version, but as protocol version upgrades are not necessarily managed by the node operators it ends up being less safe.

The shift to signed sequence numbers is backward compatible from a data point of view as the top 32 bits of sequence numbers are seeded with the legder sequence number in older versions of the protocol. Some SDKs may have to be slightly updated if they enforce strong typing. In addition, existing code even with the updated range will continue to work as sequence numbers are within a subset of the range that was supported before.

Test Cases

  • BumpSequenceOp rejected on older versions of the protocol
  • bumps to a small number passed the current sequence number
  • bumps to MAX_INT64, at which point the account cannot be used as transaction source account
  • bumps to a number smaller than the current sequence number (should no op)
  • bumps to a sequence number that is negative
  • don't allow merge when the account sequence number is too high

Implementation

stellar/stellar-core#1533

Corresponding commit is git: 7767d3ef44e9e409fb17dd68f62c276bc0086726