Implement enhanced Ticket support:

Tickets are a mechanism to allow for the "out-of-order" execution of
transactions on the XRP Ledger.

This commit, if merged, reworks the existing support for tickets and
introduces support for 'ticket batching', completing the feature set
needed for tickets.

The code is gated under the newly-introduced `TicketBatch` amendment
and the `Tickets` amendment, which is not presently active on the
network, is being removed.

The specification for this change can be found at:
https://github.com/xrp-community/standards-drafts/issues/16
This commit is contained in:
Scott Schurr
2018-10-18 18:43:02 -07:00
committed by Nik Bougalis
parent 01bd5a2646
commit 7724cca384
101 changed files with 6337 additions and 2287 deletions

View File

@@ -70,8 +70,7 @@ namespace detail {
class FeatureCollections
{
static constexpr char const* const featureNames[] = {
"MultiSign", // Unconditionally supported.
"Tickets",
"MultiSign", // Unconditionally supported.
"TrustSetAuth", // Unconditionally supported.
"FeeEscalation", // Unconditionally supported.
"OwnerPaysFee",
@@ -113,7 +112,9 @@ class FeatureCollections
// payment check
"HardenedValidations",
"fixAmendmentMajorityCalc", // Fix Amendment majority calculation
"NegativeUNL"};
"NegativeUNL",
"TicketBatch"};
std::vector<uint256> features;
boost::container::flat_map<uint256, std::size_t> featureToIndex;
boost::container::flat_map<std::string, uint256> nameToFeature;
@@ -343,7 +344,6 @@ foreachFeature(FeatureBitset bs, F&& f)
f(bitsetIndexToFeature(i));
}
extern uint256 const featureTickets;
extern uint256 const featureOwnerPaysFee;
extern uint256 const featureFlow;
extern uint256 const featureCompareTakerFlowCross;
@@ -370,6 +370,7 @@ extern uint256 const fix1781;
extern uint256 const featureHardenedValidations;
extern uint256 const fixAmendmentMajorityCalc;
extern uint256 const featureNegativeUNL;
extern uint256 const featureTicketBatch;
} // namespace ripple

View File

@@ -32,6 +32,7 @@
namespace ripple {
class SeqProxy;
/** Keylet computation funclets.
Entries in the ledger are located using 256-bit locators. The locators are
@@ -152,7 +153,10 @@ struct ticket_t
explicit ticket_t() = default;
Keylet
operator()(AccountID const& id, std::uint32_t seq) const;
operator()(AccountID const& id, std::uint32_t ticketSeq) const;
Keylet
operator()(AccountID const& id, SeqProxy ticketSeq) const;
Keylet
operator()(uint256 const& key) const
@@ -238,6 +242,9 @@ getQuality(uint256 const& uBase);
uint256
getTicketIndex(AccountID const& account, std::uint32_t uSequence);
uint256
getTicketIndex(AccountID const& account, SeqProxy ticketSeq);
} // namespace ripple
#endif

View File

@@ -390,6 +390,8 @@ extern SF_U32 const sfCancelAfter;
extern SF_U32 const sfFinishAfter;
extern SF_U32 const sfSignerListID;
extern SF_U32 const sfSettleDelay;
extern SF_U32 const sfTicketCount;
extern SF_U32 const sfTicketSequence;
// 64-bit integers
extern SF_U64 const sfIndexNext;
@@ -429,7 +431,6 @@ extern SF_U256 const sfBookDirectory;
extern SF_U256 const sfInvoiceID;
extern SF_U256 const sfNickname;
extern SF_U256 const sfAmendment;
extern SF_U256 const sfTicketID;
extern SF_U256 const sfDigest;
extern SF_U256 const sfPayChannel;
extern SF_U256 const sfConsensusHash;

View File

@@ -199,6 +199,13 @@ private:
return !(lhs == rhs);
}
// Emulate boost::optional::value_or
value_type
value_or(value_type val) const
{
return engaged() ? this->value() : val;
}
OptionalProxy&
operator=(boost::none_t const&);
OptionalProxy&

View File

@@ -23,9 +23,9 @@
#include <ripple/protocol/PublicKey.h>
#include <ripple/protocol/STObject.h>
#include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/SeqProxy.h>
#include <ripple/protocol/TxFormats.h>
#include <boost/container/flat_set.hpp>
#include <boost/logic/tribool.hpp>
#include <functional>
namespace ripple {
@@ -113,16 +113,8 @@ public:
return getFieldVL(sfSigningPubKey);
}
std::uint32_t
getSequence() const
{
return getFieldU32(sfSequence);
}
void
setSequence(std::uint32_t seq)
{
return setFieldU32(sfSequence, seq);
}
SeqProxy
getSeqProxy() const;
boost::container::flat_set<AccountID>
getMentionedAccounts() const;

View File

@@ -0,0 +1,170 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2018 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_PROTOCOL_SEQ_PROXY_H_INCLUDED
#define RIPPLE_PROTOCOL_SEQ_PROXY_H_INCLUDED
#include <cstdint>
#include <ostream>
namespace ripple {
/** A type that represents either a sequence value or a ticket value.
We use the value() of a SeqProxy in places where a sequence was used
before. An example of this is the sequence of an Offer stored in the
ledger. We do the same thing with the in-ledger identifier of a
Check, Payment Channel, and Escrow.
Why is this safe? If we use the SeqProxy::value(), how do we know that
each ledger entry will be unique?
There are two components that make this safe:
1. A "TicketCreate" transaction carefully avoids creating a ticket
that corresponds with an already used Sequence or Ticket value.
The transactor does this by referring to the account root's
sequence number. Creating the ticket advances the account root's
sequence number so the same ticket (or sequence) value cannot be
used again.
2. When a "TicketCreate" transaction creates a batch of tickets it advances
the account root sequence to one past the largest created ticket.
Therefore all tickets in a batch other than the first may never have
the same value as a sequence on that same account. And since a ticket
may only be used once there will never be any duplicates within this
account.
*/
class SeqProxy
{
public:
enum Type : std::uint8_t { seq = 0, ticket };
private:
std::uint32_t value_;
Type type_;
public:
constexpr explicit SeqProxy(Type t, std::uint32_t v) : value_{v}, type_{t}
{
}
SeqProxy(SeqProxy const& other) = default;
SeqProxy&
operator=(SeqProxy const& other) = default;
/** Factory function to return a sequence-based SeqProxy */
static constexpr SeqProxy
sequence(std::uint32_t v)
{
return SeqProxy{Type::seq, v};
}
constexpr std::uint32_t
value() const
{
return value_;
}
constexpr bool
isSeq() const
{
return type_ == seq;
}
constexpr bool
isTicket() const
{
return type_ == ticket;
}
// Occasionally it is convenient to be able to increase the value_
// of a SeqProxy. But it's unusual. So, rather than putting in an
// addition operator, you must invoke the method by name. That makes
// if more difficult to invoke accidentally.
SeqProxy&
advanceBy(std::uint32_t amount)
{
value_ += amount;
return *this;
}
// Comparison
//
// The comparison is designed specifically so _all_ Sequence
// representations sort in front of Ticket representations. This
// is true even if the Ticket value() is less that the Sequence
// value().
//
// This somewhat surprising sort order has benefits for transaction
// processing. It guarantees that transactions creating Tickets are
// sorted in from of transactions that consume Tickets.
friend constexpr bool
operator==(SeqProxy lhs, SeqProxy rhs)
{
if (lhs.type_ != rhs.type_)
return false;
return (lhs.value() == rhs.value());
}
friend constexpr bool
operator!=(SeqProxy lhs, SeqProxy rhs)
{
return !(lhs == rhs);
}
friend constexpr bool
operator<(SeqProxy lhs, SeqProxy rhs)
{
if (lhs.type_ != rhs.type_)
return lhs.type_ < rhs.type_;
return lhs.value() < rhs.value();
}
friend constexpr bool
operator>(SeqProxy lhs, SeqProxy rhs)
{
return rhs < lhs;
}
friend constexpr bool
operator>=(SeqProxy lhs, SeqProxy rhs)
{
return !(lhs < rhs);
}
friend constexpr bool
operator<=(SeqProxy lhs, SeqProxy rhs)
{
return !(lhs > rhs);
}
friend std::ostream&
operator<<(std::ostream& os, SeqProxy seqProx)
{
os << (seqProx.isSeq() ? "sequence " : "ticket ");
os << seqProx.value();
return os;
}
};
} // namespace ripple
#endif

View File

@@ -60,7 +60,7 @@ enum TELcodes : TERUnderlyingType {
telCAN_NOT_QUEUE_BLOCKS,
telCAN_NOT_QUEUE_BLOCKED,
telCAN_NOT_QUEUE_FEE,
telCAN_NOT_QUEUE_FULL
telCAN_NOT_QUEUE_FULL,
};
//------------------------------------------------------------------------------
@@ -113,10 +113,11 @@ enum TEMcodes : TERUnderlyingType {
temBAD_TICK_SIZE,
temINVALID_ACCOUNT_ID,
temCANNOT_PREAUTH_SELF,
temINVALID_COUNT,
// An intermediate result used internally, should never be returned.
temUNCERTAIN,
temUNKNOWN
temUNKNOWN,
};
//------------------------------------------------------------------------------
@@ -158,6 +159,7 @@ enum TEFcodes : TERUnderlyingType {
tefBAD_AUTH_MASTER,
tefINVARIANT_FAILED,
tefTOO_BIG,
tefNO_TICKET,
};
//------------------------------------------------------------------------------
@@ -195,7 +197,8 @@ enum TERcodes : TERUnderlyingType {
// burden network.
terLAST, // DEPRECATED.
terNO_RIPPLE, // Rippling not allowed
terQUEUED // Transaction is being held in TxQ until fee drops
terQUEUED, // Transaction is being held in TxQ until fee drops
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
};
//------------------------------------------------------------------------------

View File

@@ -44,7 +44,7 @@ enum TxType {
ttOFFER_CANCEL = 8,
no_longer_used = 9,
ttTICKET_CREATE = 10,
ttTICKET_CANCEL = 11,
// = 11, // open
ttSIGNER_LIST_SET = 12,
ttPAYCHAN_CREATE = 13,
ttPAYCHAN_FUND = 14,

View File

@@ -92,7 +92,6 @@ detail::supportedAmendments()
// Removing them will cause servers to become amendment blocked.
static std::vector<std::string> const supported{
"MultiSign", // Unconditionally supported.
// "Tickets",
"TrustSetAuth", // Unconditionally supported.
"FeeEscalation", // Unconditionally supported.
// "OwnerPaysFee",
@@ -132,7 +131,8 @@ detail::supportedAmendments()
"fix1781",
"HardenedValidations",
"fixAmendmentMajorityCalc",
//"NegativeUNL" // Commented out to prevent automatic enablement
//"NegativeUNL", // Commented out to prevent automatic enablement
//"TicketBatch", // Commented out to prevent automatic enablement
};
return supported;
}
@@ -160,7 +160,6 @@ bitsetIndexToFeature(size_t i)
// clang-format off
uint256 const
featureTickets = *getRegisteredFeature("Tickets"),
featureOwnerPaysFee = *getRegisteredFeature("OwnerPaysFee"),
featureFlow = *getRegisteredFeature("Flow"),
featureCompareTakerFlowCross = *getRegisteredFeature("CompareTakerFlowCross"),
@@ -186,7 +185,8 @@ uint256 const
fix1781 = *getRegisteredFeature("fix1781"),
featureHardenedValidations = *getRegisteredFeature("HardenedValidations"),
fixAmendmentMajorityCalc = *getRegisteredFeature("fixAmendmentMajorityCalc"),
featureNegativeUNL = *getRegisteredFeature("NegativeUNL");
featureNegativeUNL = *getRegisteredFeature("NegativeUNL"),
featureTicketBatch = *getRegisteredFeature("TicketBatch");
// The following amendments have been active for at least two years. Their
// pre-amendment code has been removed and the identifiers are deprecated.

View File

@@ -18,6 +18,7 @@
//==============================================================================
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/SeqProxy.h>
#include <ripple/protocol/digest.h>
#include <boost/endian/conversion.hpp>
#include <algorithm>
@@ -107,10 +108,17 @@ getQuality(uint256 const& uBase)
}
uint256
getTicketIndex(AccountID const& account, std::uint32_t uSequence)
getTicketIndex(AccountID const& account, std::uint32_t ticketSeq)
{
return indexHash(
LedgerNameSpace::TICKET, account, std::uint32_t(uSequence));
LedgerNameSpace::TICKET, account, std::uint32_t(ticketSeq));
}
uint256
getTicketIndex(AccountID const& account, SeqProxy ticketSeq)
{
assert(ticketSeq.isTicket());
return getTicketIndex(account, ticketSeq.value());
}
//------------------------------------------------------------------------------
@@ -238,9 +246,15 @@ next_t::operator()(Keylet const& k) const
}
Keylet
ticket_t::operator()(AccountID const& id, std::uint32_t seq) const
ticket_t::operator()(AccountID const& id, std::uint32_t ticketSeq) const
{
return {ltTICKET, getTicketIndex(id, seq)};
return {ltTICKET, getTicketIndex(id, ticketSeq)};
}
Keylet
ticket_t::operator()(AccountID const& id, SeqProxy ticketSeq) const
{
return {ltTICKET, getTicketIndex(id, ticketSeq)};
}
// This function is presently static, since it's never accessed from anywhere

View File

@@ -53,6 +53,7 @@ LedgerFormats::LedgerFormats()
{sfTransferRate, soeOPTIONAL},
{sfDomain, soeOPTIONAL},
{sfTickSize, soeOPTIONAL},
{sfTicketCount, soeOPTIONAL},
},
commonFields);
@@ -155,10 +156,10 @@ LedgerFormats::LedgerFormats()
ltTICKET,
{
{sfAccount, soeREQUIRED},
{sfSequence, soeREQUIRED},
{sfOwnerNode, soeREQUIRED},
{sfTarget, soeOPTIONAL},
{sfExpiration, soeOPTIONAL},
{sfTicketSequence, soeREQUIRED},
{sfPreviousTxnID, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED},
},
commonFields);

View File

@@ -117,6 +117,8 @@ SF_U32 const sfCancelAfter(access, STI_UINT32, 36, "CancelAfter");
SF_U32 const sfFinishAfter(access, STI_UINT32, 37, "FinishAfter");
SF_U32 const sfSignerListID(access, STI_UINT32, 38, "SignerListID");
SF_U32 const sfSettleDelay(access, STI_UINT32, 39, "SettleDelay");
SF_U32 const sfTicketCount(access, STI_UINT32, 40, "TicketCount");
SF_U32 const sfTicketSequence(access, STI_UINT32, 41, "TicketSequence");
// 64-bit integers
SF_U64 const sfIndexNext(access, STI_UINT64, 1, "IndexNext");
@@ -162,7 +164,7 @@ SF_U256 const sfBookDirectory(access, STI_HASH256, 16, "BookDirectory");
SF_U256 const sfInvoiceID(access, STI_HASH256, 17, "InvoiceID");
SF_U256 const sfNickname(access, STI_HASH256, 18, "Nickname");
SF_U256 const sfAmendment(access, STI_HASH256, 19, "Amendment");
SF_U256 const sfTicketID(access, STI_HASH256, 20, "TicketID");
// 20 is currently unused
SF_U256 const sfDigest(access, STI_HASH256, 21, "Digest");
SF_U256 const sfPayChannel(access, STI_HASH256, 22, "Channel");
SF_U256 const sfConsensusHash(access, STI_HASH256, 23, "ConsensusHash");
@@ -234,7 +236,7 @@ SF_Account const sfDestination(access, STI_ACCOUNT, 3, "Destination");
SF_Account const sfIssuer(access, STI_ACCOUNT, 4, "Issuer");
SF_Account const sfAuthorize(access, STI_ACCOUNT, 5, "Authorize");
SF_Account const sfUnauthorize(access, STI_ACCOUNT, 6, "Unauthorize");
SF_Account const sfTarget(access, STI_ACCOUNT, 7, "Target");
// 7 is currently unused
SF_Account const sfRegularKey(access, STI_ACCOUNT, 8, "RegularKey");
// path set

View File

@@ -160,6 +160,22 @@ STTx::getSignature() const
}
}
SeqProxy
STTx::getSeqProxy() const
{
std::uint32_t const seq{getFieldU32(sfSequence)};
if (seq != 0)
return SeqProxy::sequence(seq);
boost::optional<std::uint32_t> const ticketSeq{operator[](
~sfTicketSequence)};
if (!ticketSeq)
// No TicketSequence specified. Return the Sequence, whatever it is.
return SeqProxy::sequence(seq);
return SeqProxy{SeqProxy::ticket, *ticketSeq};
}
void
STTx::sign(PublicKey const& publicKey, SecretKey const& secretKey)
{
@@ -250,8 +266,8 @@ STTx::getMetaSQL(
return str(
boost::format(bfTrans) % to_string(getTransactionID()) %
format->getName() % toBase58(getAccountID(sfAccount)) % getSequence() %
inLedger % status % rTxn % escapedMetaData);
format->getName() % toBase58(getAccountID(sfAccount)) %
getFieldU32(sfSequence) % inLedger % status % rTxn % escapedMetaData);
}
std::pair<bool, std::string>

View File

@@ -100,6 +100,7 @@ transResults()
MAKE_ERROR(tefBAD_AUTH_MASTER, "Auth for unclaimed account needs correct master key."),
MAKE_ERROR(tefINVARIANT_FAILED, "Fee claim violated invariants for the transaction."),
MAKE_ERROR(tefTOO_BIG, "Transaction affects too many items."),
MAKE_ERROR(tefNO_TICKET, "Ticket is not in ledger."),
MAKE_ERROR(telLOCAL_ERROR, "Local failure."),
MAKE_ERROR(telBAD_DOMAIN, "Domain too long."),
@@ -150,6 +151,7 @@ transResults()
MAKE_ERROR(temBAD_TICK_SIZE, "Malformed: Tick size out of range."),
MAKE_ERROR(temINVALID_ACCOUNT_ID, "Malformed: A field contains an invalid account ID."),
MAKE_ERROR(temCANNOT_PREAUTH_SELF, "Malformed: An account may not preauthorize itself."),
MAKE_ERROR(temINVALID_COUNT, "Malformed: Count field outside valid range."),
MAKE_ERROR(terRETRY, "Retry transaction."),
MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."),
@@ -162,6 +164,7 @@ transResults()
MAKE_ERROR(terPRE_SEQ, "Missing/inapplicable prior transaction."),
MAKE_ERROR(terOWNERS, "Non-zero owner count."),
MAKE_ERROR(terQUEUED, "Held until escalated fee drops."),
{terPRE_TICKET, {"terPRE_TICKET", "Ticket is not yet in ledger."}},
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
};

View File

@@ -54,6 +54,7 @@ TxFormats::TxFormats()
{sfSetFlag, soeOPTIONAL},
{sfClearFlag, soeOPTIONAL},
{sfTickSize, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -63,6 +64,7 @@ TxFormats::TxFormats()
{sfLimitAmount, soeOPTIONAL},
{sfQualityIn, soeOPTIONAL},
{sfQualityOut, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -73,6 +75,7 @@ TxFormats::TxFormats()
{sfTakerGets, soeREQUIRED},
{sfExpiration, soeOPTIONAL},
{sfOfferSequence, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -80,6 +83,7 @@ TxFormats::TxFormats()
ttOFFER_CANCEL,
{
{sfOfferSequence, soeREQUIRED},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -87,6 +91,7 @@ TxFormats::TxFormats()
ttREGULAR_KEY_SET,
{
{sfRegularKey, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -100,6 +105,7 @@ TxFormats::TxFormats()
{sfInvoiceID, soeOPTIONAL},
{sfDestinationTag, soeOPTIONAL},
{sfDeliverMin, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -112,6 +118,7 @@ TxFormats::TxFormats()
{sfCancelAfter, soeOPTIONAL},
{sfFinishAfter, soeOPTIONAL},
{sfDestinationTag, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -122,6 +129,7 @@ TxFormats::TxFormats()
{sfOfferSequence, soeREQUIRED},
{sfFulfillment, soeOPTIONAL},
{sfCondition, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -130,6 +138,7 @@ TxFormats::TxFormats()
{
{sfOwner, soeREQUIRED},
{sfOfferSequence, soeREQUIRED},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -164,15 +173,8 @@ TxFormats::TxFormats()
add(jss::TicketCreate,
ttTICKET_CREATE,
{
{sfTarget, soeOPTIONAL},
{sfExpiration, soeOPTIONAL},
},
commonFields);
add(jss::TicketCancel,
ttTICKET_CANCEL,
{
{sfTicketID, soeREQUIRED},
{sfTicketCount, soeREQUIRED},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -183,6 +185,7 @@ TxFormats::TxFormats()
{
{sfSignerQuorum, soeREQUIRED},
{sfSignerEntries, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -195,6 +198,7 @@ TxFormats::TxFormats()
{sfPublicKey, soeREQUIRED},
{sfCancelAfter, soeOPTIONAL},
{sfDestinationTag, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -204,6 +208,7 @@ TxFormats::TxFormats()
{sfPayChannel, soeREQUIRED},
{sfAmount, soeREQUIRED},
{sfExpiration, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -215,6 +220,7 @@ TxFormats::TxFormats()
{sfBalance, soeOPTIONAL},
{sfSignature, soeOPTIONAL},
{sfPublicKey, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -226,6 +232,7 @@ TxFormats::TxFormats()
{sfExpiration, soeOPTIONAL},
{sfDestinationTag, soeOPTIONAL},
{sfInvoiceID, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -235,6 +242,7 @@ TxFormats::TxFormats()
{sfCheckID, soeREQUIRED},
{sfAmount, soeOPTIONAL},
{sfDeliverMin, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -242,6 +250,7 @@ TxFormats::TxFormats()
ttCHECK_CANCEL,
{
{sfCheckID, soeREQUIRED},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -250,6 +259,7 @@ TxFormats::TxFormats()
{
{sfDestination, soeREQUIRED},
{sfDestinationTag, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
@@ -258,6 +268,7 @@ TxFormats::TxFormats()
{
{sfAuthorize, soeOPTIONAL},
{sfUnauthorize, soeOPTIONAL},
{sfTicketSequence, soeOPTIONAL},
},
commonFields);
}

View File

@@ -94,7 +94,6 @@ JSS(SigningPubKey); // field.
JSS(TakerGets); // field.
JSS(TakerPays); // field.
JSS(Ticket); // ledger type.
JSS(TicketCancel); // transaction type.
JSS(TicketCreate); // transaction type.
JSS(TxnSignature); // field.
JSS(TransactionType); // in: TransactionSign.
@@ -260,6 +259,7 @@ JSS(have_header); // out: InboundLedger
JSS(have_state); // out: InboundLedger
JSS(have_transactions); // out: InboundLedger
JSS(highest_sequence); // out: AccountInfo
JSS(highest_ticket); // out: AccountInfo
JSS(historical_perminute); // historical_perminute.
JSS(hostid); // out: NetworkOPs
JSS(hotwallet); // in: GatewayBalances
@@ -271,7 +271,6 @@ JSS(inbound); // out: PeerImp
JSS(index); // in: LedgerEntry, DownloadShard
// out: STLedgerEntry,
// LedgerEntry, TxHistory, LedgerData
// field
JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo
JSS(internal_command); // in: Internal
JSS(invalid_API_version); // out: Many, when a request has an invalid
@@ -337,6 +336,7 @@ JSS(local); // out: resource/Logic.h
JSS(local_txs); // out: GetCounts
JSS(local_static_keys); // out: ValidatorList
JSS(lowest_sequence); // out: AccountInfo
JSS(lowest_ticket); // out: AccountInfo
JSS(majority); // out: RPC feature
JSS(manifest); // out: ValidatorInfo, Manifest
JSS(marker); // in/out: AccountTx, AccountOffers,
@@ -472,6 +472,7 @@ JSS(seq); // in: LedgerEntry;
// out: NetworkOPs, RPCSub, AccountOffers,
// ValidatorList, ValidatorInfo, Manifest
JSS(seqNum); // out: LedgerToJson
JSS(sequence_count); // out: AccountInfo
JSS(server_state); // out: NetworkOPs
JSS(server_state_duration_us); // out: NetworkOPs
JSS(server_status); // out: NetworkOPs
@@ -513,6 +514,8 @@ JSS(taker_pays); // in: Subscribe, Unsubscribe, BookOffers
JSS(taker_pays_funded); // out: NetworkOPs
JSS(threshold); // in: Blacklist
JSS(ticket); // in: AccountObjects
JSS(ticket_count); // out: AccountInfo
JSS(ticket_seq); // in: LedgerEntry
JSS(time);
JSS(timeouts); // out: InboundLedger
JSS(traffic); // out: Overlay