rippled
SetSignerList.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2014 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/tx/impl/SetSignerList.h>
21 
22 #include <ripple/app/ledger/Ledger.h>
23 #include <ripple/basics/Log.h>
24 #include <ripple/ledger/ApplyView.h>
25 #include <ripple/protocol/Feature.h>
26 #include <ripple/protocol/Indexes.h>
27 #include <ripple/protocol/STArray.h>
28 #include <ripple/protocol/STObject.h>
29 #include <ripple/protocol/STTx.h>
30 #include <algorithm>
31 #include <cstdint>
32 
33 namespace ripple {
34 
35 // We're prepared for there to be multiple signer lists in the future,
36 // but we don't need them yet. So for the time being we're manually
37 // setting the sfSignerListID to zero in all cases.
39 
41  NotTEC,
46  STTx const& tx,
47  ApplyFlags flags,
49 {
50  // Check the quorum. A non-zero quorum means we're creating or replacing
51  // the list. A zero quorum means we're destroying the list.
52  auto const quorum = tx[sfSignerQuorum];
54  Operation op = unknown;
55 
56  bool const hasSignerEntries(tx.isFieldPresent(sfSignerEntries));
57  if (quorum && hasSignerEntries)
58  {
59  auto signers = SignerEntries::deserialize(tx, j, "transaction");
60 
61  if (!signers)
62  return std::make_tuple(signers.error(), quorum, sign, op);
63 
64  std::sort(signers->begin(), signers->end());
65 
66  // Save deserialized list for later.
67  sign = std::move(*signers);
68  op = set;
69  }
70  else if ((quorum == 0) && !hasSignerEntries)
71  {
72  op = destroy;
73  }
74 
75  return std::make_tuple(tesSUCCESS, quorum, sign, op);
76 }
77 
78 NotTEC
80 {
81  if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
82  return ret;
83 
84  auto const result = determineOperation(ctx.tx, ctx.flags, ctx.j);
85  if (std::get<0>(result) != tesSUCCESS)
86  return std::get<0>(result);
87 
88  if (std::get<3>(result) == unknown)
89  {
90  // Neither a set nor a destroy. Malformed.
91  JLOG(ctx.j.trace())
92  << "Malformed transaction: Invalid signer set list format.";
93  return temMALFORMED;
94  }
95 
96  if (std::get<3>(result) == set)
97  {
98  // Validate our settings.
99  auto const account = ctx.tx.getAccountID(sfAccount);
101  std::get<1>(result), std::get<2>(result), account, ctx.j);
102  if (ter != tesSUCCESS)
103  {
104  return ter;
105  }
106  }
107 
108  return preflight2(ctx);
109 }
110 
111 TER
113 {
114  // Perform the operation preCompute() decided on.
115  switch (do_)
116  {
117  case set:
118  return replaceSignerList();
119 
120  case destroy:
121  return destroySignerList();
122 
123  default:
124  break;
125  }
126  assert(false); // Should not be possible to get here.
127  return temMALFORMED;
128 }
129 
130 void
132 {
133  // Get the quorum and operation info.
134  auto result = determineOperation(ctx_.tx, view().flags(), j_);
135  assert(std::get<0>(result) == tesSUCCESS);
136  assert(std::get<3>(result) != unknown);
137 
138  quorum_ = std::get<1>(result);
139  signers_ = std::get<2>(result);
140  do_ = std::get<3>(result);
141 
142  return Transactor::preCompute();
143 }
144 
145 // The return type is signed so it is compatible with the 3rd argument
146 // of adjustOwnerCount() (which must be signed).
147 //
148 // NOTE: This way of computing the OwnerCount associated with a SignerList
149 // is valid until the featureMultiSignReserve amendment passes. Once it
150 // passes then just 1 OwnerCount is associated with a SignerList.
151 static int
153 {
154  // We always compute the full change in OwnerCount, taking into account:
155  // o The fact that we're adding/removing a SignerList and
156  // o Accounting for the number of entries in the list.
157  // We can get away with that because lists are not adjusted incrementally;
158  // we add or remove an entire list.
159  //
160  // The rule is:
161  // o Simply having a SignerList costs 2 OwnerCount units.
162  // o And each signer in the list costs 1 more OwnerCount unit.
163  // So, at a minimum, adding a SignerList with 1 entry costs 3 OwnerCount
164  // units. A SignerList with 8 entries would cost 10 OwnerCount units.
165  //
166  // The static_cast should always be safe since entryCount should always
167  // be in the range from 1 to 8. We've got a lot of room to grow.
168  assert(entryCount >= STTx::minMultiSigners);
169  assert(entryCount <= STTx::maxMultiSigners);
170  return 2 + static_cast<int>(entryCount);
171 }
172 
173 static TER
175  Application& app,
176  ApplyView& view,
177  Keylet const& accountKeylet,
178  Keylet const& ownerDirKeylet,
179  Keylet const& signerListKeylet,
180  beast::Journal j)
181 {
182  // We have to examine the current SignerList so we know how much to
183  // reduce the OwnerCount.
184  SLE::pointer signers = view.peek(signerListKeylet);
185 
186  // If the signer list doesn't exist we've already succeeded in deleting it.
187  if (!signers)
188  return tesSUCCESS;
189 
190  // There are two different ways that the OwnerCount could be managed.
191  // If the lsfOneOwnerCount bit is set then remove just one owner count.
192  // Otherwise use the pre-MultiSignReserve amendment calculation.
193  int removeFromOwnerCount = -1;
194  if ((signers->getFlags() & lsfOneOwnerCount) == 0)
195  {
196  STArray const& actualList = signers->getFieldArray(sfSignerEntries);
197  removeFromOwnerCount =
198  signerCountBasedOwnerCountDelta(actualList.size()) * -1;
199  }
200 
201  // Remove the node from the account directory.
202  auto const hint = (*signers)[sfOwnerNode];
203 
204  if (!view.dirRemove(ownerDirKeylet, hint, signerListKeylet.key, false))
205  {
206  JLOG(j.fatal()) << "Unable to delete SignerList from owner.";
207  return tefBAD_LEDGER;
208  }
209 
211  view,
212  view.peek(accountKeylet),
213  removeFromOwnerCount,
214  app.journal("View"));
215 
216  view.erase(signers);
217 
218  return tesSUCCESS;
219 }
220 
221 TER
223  Application& app,
224  ApplyView& view,
225  AccountID const& account,
226  beast::Journal j)
227 {
228  auto const accountKeylet = keylet::account(account);
229  auto const ownerDirKeylet = keylet::ownerDir(account);
230  auto const signerListKeylet = keylet::signers(account);
231 
233  app, view, accountKeylet, ownerDirKeylet, signerListKeylet, j);
234 }
235 
236 NotTEC
238  std::uint32_t quorum,
240  AccountID const& account,
241  beast::Journal j)
242 {
243  // Reject if there are too many or too few entries in the list.
244  {
245  std::size_t const signerCount = signers.size();
246  if ((signerCount < STTx::minMultiSigners) ||
247  (signerCount > STTx::maxMultiSigners))
248  {
249  JLOG(j.trace()) << "Too many or too few signers in signer list.";
250  return temMALFORMED;
251  }
252  }
253 
254  // Make sure there are no duplicate signers.
255  assert(std::is_sorted(signers.begin(), signers.end()));
256  if (std::adjacent_find(signers.begin(), signers.end()) != signers.end())
257  {
258  JLOG(j.trace()) << "Duplicate signers in signer list";
259  return temBAD_SIGNER;
260  }
261 
262  // Make sure no signers reference this account. Also make sure the
263  // quorum can be reached.
264  std::uint64_t allSignersWeight(0);
265  for (auto const& signer : signers)
266  {
267  std::uint32_t const weight = signer.weight;
268  if (weight <= 0)
269  {
270  JLOG(j.trace()) << "Every signer must have a positive weight.";
271  return temBAD_WEIGHT;
272  }
273 
274  allSignersWeight += signer.weight;
275 
276  if (signer.account == account)
277  {
278  JLOG(j.trace()) << "A signer may not self reference account.";
279  return temBAD_SIGNER;
280  }
281 
282  // Don't verify that the signer accounts exist. Non-existent accounts
283  // may be phantom accounts (which are permitted).
284  }
285  if ((quorum <= 0) || (allSignersWeight < quorum))
286  {
287  JLOG(j.trace()) << "Quorum is unreachable";
288  return temBAD_QUORUM;
289  }
290  return tesSUCCESS;
291 }
292 
293 TER
295 {
296  auto const accountKeylet = keylet::account(account_);
297  auto const ownerDirKeylet = keylet::ownerDir(account_);
298  auto const signerListKeylet = keylet::signers(account_);
299 
300  // This may be either a create or a replace. Preemptively remove any
301  // old signer list. May reduce the reserve, so this is done before
302  // checking the reserve.
303  if (TER const ter = removeSignersFromLedger(
304  ctx_.app,
305  view(),
306  accountKeylet,
307  ownerDirKeylet,
308  signerListKeylet,
309  j_))
310  return ter;
311 
312  auto const sle = view().peek(accountKeylet);
313  if (!sle)
314  return tefINTERNAL;
315 
316  // Compute new reserve. Verify the account has funds to meet the reserve.
317  std::uint32_t const oldOwnerCount{(*sle)[sfOwnerCount]};
318 
319  // The required reserve changes based on featureMultiSignReserve...
320  int addedOwnerCount{1};
323  {
324  addedOwnerCount = signerCountBasedOwnerCountDelta(signers_.size());
325  flags = 0;
326  }
327 
328  XRPAmount const newReserve{
329  view().fees().accountReserve(oldOwnerCount + addedOwnerCount)};
330 
331  // We check the reserve against the starting balance because we want to
332  // allow dipping into the reserve to pay fees. This behavior is consistent
333  // with CreateTicket.
334  if (mPriorBalance < newReserve)
336 
337  // Everything's ducky. Add the ltSIGNER_LIST to the ledger.
338  auto signerList = std::make_shared<SLE>(signerListKeylet);
339  view().insert(signerList);
340  writeSignersToSLE(signerList, flags);
341 
342  auto viewJ = ctx_.app.journal("View");
343  // Add the signer list to the account's directory.
344  auto const page = ctx_.view().dirInsert(
345  ownerDirKeylet, signerListKeylet, describeOwnerDir(account_));
346 
347  JLOG(j_.trace()) << "Create signer list for account " << toBase58(account_)
348  << ": " << (page ? "success" : "failure");
349 
350  if (!page)
351  return tecDIR_FULL;
352 
353  signerList->setFieldU64(sfOwnerNode, *page);
354 
355  // If we succeeded, the new entry counts against the
356  // creator's reserve.
357  adjustOwnerCount(view(), sle, addedOwnerCount, viewJ);
358  return tesSUCCESS;
359 }
360 
361 TER
363 {
364  auto const accountKeylet = keylet::account(account_);
365  // Destroying the signer list is only allowed if either the master key
366  // is enabled or there is a regular key.
367  SLE::pointer ledgerEntry = view().peek(accountKeylet);
368  if (!ledgerEntry)
369  return tefINTERNAL;
370 
371  if ((ledgerEntry->isFlag(lsfDisableMaster)) &&
372  (!ledgerEntry->isFieldPresent(sfRegularKey)))
373  return tecNO_ALTERNATIVE_KEY;
374 
375  auto const ownerDirKeylet = keylet::ownerDir(account_);
376  auto const signerListKeylet = keylet::signers(account_);
378  ctx_.app, view(), accountKeylet, ownerDirKeylet, signerListKeylet, j_);
379 }
380 
381 void
383  SLE::pointer const& ledgerEntry,
384  std::uint32_t flags) const
385 {
386  // Assign the quorum, default SignerListID, and flags.
387  ledgerEntry->setFieldU32(sfSignerQuorum, quorum_);
388  ledgerEntry->setFieldU32(sfSignerListID, defaultSignerListID_);
389  if (flags) // Only set flags if they are non-default (default is zero).
390  ledgerEntry->setFieldU32(sfFlags, flags);
391 
392  // Create the SignerListArray one SignerEntry at a time.
393  STArray toLedger(signers_.size());
394  for (auto const& entry : signers_)
395  {
396  toLedger.emplace_back(sfSignerEntry);
397  STObject& obj = toLedger.back();
398  obj.reserve(2);
399  obj.setAccountID(sfAccount, entry.account);
400  obj.setFieldU16(sfSignerWeight, entry.weight);
401  }
402 
403  // Assign the SignerEntries.
404  ledgerEntry->setFieldArray(sfSignerEntries, toLedger);
405 }
406 
407 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::STArray::size
size_type size() const
Definition: STArray.h:248
ripple::sfSignerListID
const SF_UINT32 sfSignerListID
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:303
ripple::sfOwnerCount
const SF_UINT32 sfOwnerCount
ripple::Application
Definition: Application.h:115
ripple::STObject::setAccountID
void setAccountID(SField const &field, AccountID const &)
Definition: STObject.cpp:689
ripple::sfSignerWeight
const SF_UINT16 sfSignerWeight
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:109
std::make_tuple
T make_tuple(T... args)
ripple::Keylet
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:38
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:152
std::shared_ptr< STLedgerEntry >
ripple::sfOwnerNode
const SF_UINT64 sfOwnerNode
ripple::STObject::setFieldU16
void setFieldU16(SField const &field, std::uint16_t)
Definition: STObject.cpp:653
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::ApplyView::peek
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
ripple::lsfDisableMaster
@ lsfDisableMaster
Definition: LedgerFormats.h:229
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:731
ripple::SignerEntries::deserialize
static Expected< std::vector< SignerEntry >, NotTEC > deserialize(STObject const &obj, beast::Journal journal, std::string const &annotation)
Definition: SignerEntries.cpp:29
ripple::Transactor::j_
const beast::Journal j_
Definition: Transactor.h:89
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:594
ripple::sfRegularKey
const SF_ACCOUNT sfRegularKey
ripple::SetSignerList::destroySignerList
TER destroySignerList()
Definition: SetSignerList.cpp:362
ripple::ApplyView::erase
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
std::vector
STL class.
ripple::ReadView::fees
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
ripple::ApplyFlags
ApplyFlags
Definition: ApplyView.h:29
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
ripple::featureMultiSignReserve
const uint256 featureMultiSignReserve
std::tuple
ripple::SetSignerList::Operation
Operation
Definition: SetSignerList.h:45
ripple::PreflightContext::j
const beast::Journal j
Definition: Transactor.h:38
ripple::SetSignerList::set
@ set
Definition: SetSignerList.h:45
ripple::SetSignerList::validateQuorumAndSignerEntries
static NotTEC validateQuorumAndSignerEntries(std::uint32_t quorum, std::vector< SignerEntries::SignerEntry > const &signers, AccountID const &account, beast::Journal j)
Definition: SetSignerList.cpp:237
std::sort
T sort(T... args)
algorithm
ripple::defaultSignerListID_
static const std::uint32_t defaultSignerListID_
Definition: SetSignerList.cpp:38
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:57
ripple::ApplyView
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:134
std::is_sorted
T is_sorted(T... args)
ripple::ApplyContext::app
Application & app
Definition: ApplyContext.h:47
ripple::sfSignerQuorum
const SF_UINT32 sfSignerQuorum
ripple::ApplyView::dirRemove
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
Definition: ApplyView.cpp:189
ripple::Keylet::key
uint256 key
Definition: Keylet.h:40
ripple::base_uint< 160, detail::AccountIDTag >
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:149
ripple::temBAD_QUORUM
@ temBAD_QUORUM
Definition: TER.h:111
ripple::adjustOwnerCount
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
Definition: View.cpp:713
ripple::tecNO_ALTERNATIVE_KEY
@ tecNO_ALTERNATIVE_KEY
Definition: TER.h:260
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:133
ripple::STObject::getAccountID
AccountID getAccountID(SField const &field) const
Definition: STObject.cpp:589
ripple::temBAD_SIGNER
@ temBAD_SIGNER
Definition: TER.h:110
ripple::SetSignerList::do_
Operation do_
Definition: SetSignerList.h:46
ripple::TERSubset
Definition: TER.h:337
ripple::STArray
Definition: STArray.h:28
ripple::SetSignerList::unknown
@ unknown
Definition: SetSignerList.h:45
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:565
ripple::lsfOneOwnerCount
@ lsfOneOwnerCount
Definition: LedgerFormats.h:251
cstdint
ripple::STTx
Definition: STTx.h:43
ripple::SetSignerList::removeFromLedger
static TER removeFromLedger(Application &app, ApplyView &view, AccountID const &account, beast::Journal j)
Definition: SetSignerList.cpp:222
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint32_t
ripple::Rules::enabled
bool enabled(uint256 const &id) const
Returns true if a feature is enabled.
Definition: ReadView.cpp:102
ripple::STObject::reserve
void reserve(std::size_t n)
Definition: STObject.h:877
ripple::SetSignerList::determineOperation
static std::tuple< NotTEC, std::uint32_t, std::vector< SignerEntries::SignerEntry >, Operation > determineOperation(STTx const &tx, ApplyFlags flags, beast::Journal j)
Definition: SetSignerList.cpp:45
ripple::sfSignerEntry
const SField sfSignerEntry
ripple::ApplyContext::view
ApplyView & view()
Definition: ApplyContext.h:54
ripple::signerCountBasedOwnerCountDelta
static int signerCountBasedOwnerCountDelta(std::size_t entryCount)
Definition: SetSignerList.cpp:152
ripple::tecDIR_FULL
@ tecDIR_FULL
Definition: TER.h:251
ripple::SetSignerList::doApply
TER doApply() override
Definition: SetSignerList.cpp:112
ripple::sfSignerEntries
const SField sfSignerEntries
ripple::STObject
Definition: STObject.h:51
ripple::ApplyView::insert
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::PreflightContext::flags
ApplyFlags flags
Definition: Transactor.h:37
ripple::STTx::maxMultiSigners
static const std::size_t maxMultiSigners
Definition: STTx.h:50
ripple::Application::journal
virtual beast::Journal journal(std::string const &name)=0
ripple::SetSignerList::destroy
@ destroy
Definition: SetSignerList.h:45
ripple::SetSignerList::signers_
std::vector< SignerEntries::SignerEntry > signers_
Definition: SetSignerList.h:48
ripple::Transactor::view
ApplyView & view()
Definition: Transactor.h:107
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:238
ripple::STArray::emplace_back
void emplace_back(Args &&... args)
Definition: STArray.h:206
ripple::Fees::accountReserve
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
Definition: ReadView.h:66
ripple::ReadView::rules
virtual Rules const & rules() const =0
Returns the tx processing rules.
ripple::sfFlags
const SF_UINT32 sfFlags
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:428
ripple::SetSignerList::preCompute
void preCompute() override
Definition: SetSignerList.cpp:131
ripple::Transactor::mPriorBalance
XRPAmount mPriorBalance
Definition: Transactor.h:92
std::adjacent_find
T adjacent_find(T... args)
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:271
ripple::STTx::minMultiSigners
static const std::size_t minMultiSigners
Definition: STTx.h:49
ripple::removeSignersFromLedger
static TER removeSignersFromLedger(Application &app, ApplyView &view, Keylet const &accountKeylet, Keylet const &ownerDirKeylet, Keylet const &signerListKeylet, beast::Journal j)
Definition: SetSignerList.cpp:174
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:88
ripple::STArray::back
STObject & back()
Definition: STArray.h:193
ripple::SetSignerList::replaceSignerList
TER replaceSignerList()
Definition: SetSignerList.cpp:294
std::size_t
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:82
ripple::PreflightContext::tx
STTx const & tx
Definition: Transactor.h:35
ripple::PreflightContext
State information when preflighting a tx.
Definition: Transactor.h:31
ripple::keylet::signers
static Keylet signers(AccountID const &account, std::uint32_t page) noexcept
Definition: Indexes.cpp:268
ripple::ApplyView::dirInsert
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(std::shared_ptr< SLE > const &)> const &describe)
Insert an entry to a directory.
Definition: ApplyView.h:306
ripple::SetSignerList::writeSignersToSLE
void writeSignersToSLE(SLE::pointer const &ledgerEntry, std::uint32_t flags) const
Definition: SetSignerList.cpp:382
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:219
ripple::Transactor::account_
const AccountID account_
Definition: Transactor.h:91
ripple::Transactor::preCompute
virtual void preCompute()
Definition: Transactor.cpp:416
ripple::SetSignerList::quorum_
std::uint32_t quorum_
Definition: SetSignerList.h:47
ripple::ApplyContext::tx
STTx const & tx
Definition: ApplyContext.h:48
ripple::temBAD_WEIGHT
@ temBAD_WEIGHT
Definition: TER.h:112
ripple::SetSignerList::preflight
static NotTEC preflight(PreflightContext const &ctx)
Definition: SetSignerList.cpp:79
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:525