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  auto const ret = preflight1(ctx);
82  if (!isTesSuccess(ret))
83  return ret;
84 
85  auto const result = determineOperation(ctx.tx, ctx.flags, ctx.j);
86  if (std::get<0>(result) != tesSUCCESS)
87  return std::get<0>(result);
88 
89  if (std::get<3>(result) == unknown)
90  {
91  // Neither a set nor a destroy. Malformed.
92  JLOG(ctx.j.trace())
93  << "Malformed transaction: Invalid signer set list format.";
94  return temMALFORMED;
95  }
96 
97  if (std::get<3>(result) == set)
98  {
99  // Validate our settings.
100  auto const account = ctx.tx.getAccountID(sfAccount);
102  std::get<1>(result), std::get<2>(result), account, ctx.j);
103  if (ter != tesSUCCESS)
104  {
105  return ter;
106  }
107  }
108 
109  return preflight2(ctx);
110 }
111 
112 TER
114 {
115  // Perform the operation preCompute() decided on.
116  switch (do_)
117  {
118  case set:
119  return replaceSignerList();
120 
121  case destroy:
122  return destroySignerList();
123 
124  default:
125  break;
126  }
127  assert(false); // Should not be possible to get here.
128  return temMALFORMED;
129 }
130 
131 void
133 {
134  // Get the quorum and operation info.
135  auto result = determineOperation(ctx_.tx, view().flags(), j_);
136  assert(std::get<0>(result) == tesSUCCESS);
137  assert(std::get<3>(result) != unknown);
138 
139  quorum_ = std::get<1>(result);
140  signers_ = std::get<2>(result);
141  do_ = std::get<3>(result);
142 
143  return Transactor::preCompute();
144 }
145 
146 // The return type is signed so it is compatible with the 3rd argument
147 // of adjustOwnerCount() (which must be signed).
148 //
149 // NOTE: This way of computing the OwnerCount associated with a SignerList
150 // is valid until the featureMultiSignReserve amendment passes. Once it
151 // passes then just 1 OwnerCount is associated with a SignerList.
152 static int
154 {
155  // We always compute the full change in OwnerCount, taking into account:
156  // o The fact that we're adding/removing a SignerList and
157  // o Accounting for the number of entries in the list.
158  // We can get away with that because lists are not adjusted incrementally;
159  // we add or remove an entire list.
160  //
161  // The rule is:
162  // o Simply having a SignerList costs 2 OwnerCount units.
163  // o And each signer in the list costs 1 more OwnerCount unit.
164  // So, at a minimum, adding a SignerList with 1 entry costs 3 OwnerCount
165  // units. A SignerList with 8 entries would cost 10 OwnerCount units.
166  //
167  // The static_cast should always be safe since entryCount should always
168  // be in the range from 1 to 8. We've got a lot of room to grow.
169  assert(entryCount >= STTx::minMultiSigners);
170  assert(entryCount <= STTx::maxMultiSigners);
171  return 2 + static_cast<int>(entryCount);
172 }
173 
174 static TER
176  Application& app,
177  ApplyView& view,
178  Keylet const& accountKeylet,
179  Keylet const& ownerDirKeylet,
180  Keylet const& signerListKeylet,
181  beast::Journal j)
182 {
183  // We have to examine the current SignerList so we know how much to
184  // reduce the OwnerCount.
185  SLE::pointer signers = view.peek(signerListKeylet);
186 
187  // If the signer list doesn't exist we've already succeeded in deleting it.
188  if (!signers)
189  return tesSUCCESS;
190 
191  // There are two different ways that the OwnerCount could be managed.
192  // If the lsfOneOwnerCount bit is set then remove just one owner count.
193  // Otherwise use the pre-MultiSignReserve amendment calculation.
194  int removeFromOwnerCount = -1;
195  if ((signers->getFlags() & lsfOneOwnerCount) == 0)
196  {
197  STArray const& actualList = signers->getFieldArray(sfSignerEntries);
198  removeFromOwnerCount =
199  signerCountBasedOwnerCountDelta(actualList.size()) * -1;
200  }
201 
202  // Remove the node from the account directory.
203  auto const hint = (*signers)[sfOwnerNode];
204 
205  if (!view.dirRemove(ownerDirKeylet, hint, signerListKeylet.key, false))
206  {
207  JLOG(j.fatal()) << "Unable to delete SignerList from owner.";
208  return tefBAD_LEDGER;
209  }
210 
212  view,
213  view.peek(accountKeylet),
214  removeFromOwnerCount,
215  app.journal("View"));
216 
217  view.erase(signers);
218 
219  return tesSUCCESS;
220 }
221 
222 TER
224  Application& app,
225  ApplyView& view,
226  AccountID const& account,
227  beast::Journal j)
228 {
229  auto const accountKeylet = keylet::account(account);
230  auto const ownerDirKeylet = keylet::ownerDir(account);
231  auto const signerListKeylet = keylet::signers(account);
232 
234  app, view, accountKeylet, ownerDirKeylet, signerListKeylet, j);
235 }
236 
237 NotTEC
239  std::uint32_t quorum,
241  AccountID const& account,
242  beast::Journal j)
243 {
244  // Reject if there are too many or too few entries in the list.
245  {
246  std::size_t const signerCount = signers.size();
247  if ((signerCount < STTx::minMultiSigners) ||
248  (signerCount > STTx::maxMultiSigners))
249  {
250  JLOG(j.trace()) << "Too many or too few signers in signer list.";
251  return temMALFORMED;
252  }
253  }
254 
255  // Make sure there are no duplicate signers.
256  assert(std::is_sorted(signers.begin(), signers.end()));
257  if (std::adjacent_find(signers.begin(), signers.end()) != signers.end())
258  {
259  JLOG(j.trace()) << "Duplicate signers in signer list";
260  return temBAD_SIGNER;
261  }
262 
263  // Make sure no signers reference this account. Also make sure the
264  // quorum can be reached.
265  std::uint64_t allSignersWeight(0);
266  for (auto const& signer : signers)
267  {
268  std::uint32_t const weight = signer.weight;
269  if (weight <= 0)
270  {
271  JLOG(j.trace()) << "Every signer must have a positive weight.";
272  return temBAD_WEIGHT;
273  }
274 
275  allSignersWeight += signer.weight;
276 
277  if (signer.account == account)
278  {
279  JLOG(j.trace()) << "A signer may not self reference account.";
280  return temBAD_SIGNER;
281  }
282 
283  // Don't verify that the signer accounts exist. Non-existent accounts
284  // may be phantom accounts (which are permitted).
285  }
286  if ((quorum <= 0) || (allSignersWeight < quorum))
287  {
288  JLOG(j.trace()) << "Quorum is unreachable";
289  return temBAD_QUORUM;
290  }
291  return tesSUCCESS;
292 }
293 
294 TER
296 {
297  auto const accountKeylet = keylet::account(account_);
298  auto const ownerDirKeylet = keylet::ownerDir(account_);
299  auto const signerListKeylet = keylet::signers(account_);
300 
301  // This may be either a create or a replace. Preemptively remove any
302  // old signer list. May reduce the reserve, so this is done before
303  // checking the reserve.
304  if (TER const ter = removeSignersFromLedger(
305  ctx_.app,
306  view(),
307  accountKeylet,
308  ownerDirKeylet,
309  signerListKeylet,
310  j_))
311  return ter;
312 
313  auto const sle = view().peek(accountKeylet);
314  if (!sle)
315  return tefINTERNAL;
316 
317  // Compute new reserve. Verify the account has funds to meet the reserve.
318  std::uint32_t const oldOwnerCount{(*sle)[sfOwnerCount]};
319 
320  // The required reserve changes based on featureMultiSignReserve...
321  int addedOwnerCount{1};
324  {
325  addedOwnerCount = signerCountBasedOwnerCountDelta(signers_.size());
326  flags = 0;
327  }
328 
329  XRPAmount const newReserve{
330  view().fees().accountReserve(oldOwnerCount + addedOwnerCount)};
331 
332  // We check the reserve against the starting balance because we want to
333  // allow dipping into the reserve to pay fees. This behavior is consistent
334  // with CreateTicket.
335  if (mPriorBalance < newReserve)
337 
338  // Everything's ducky. Add the ltSIGNER_LIST to the ledger.
339  auto signerList = std::make_shared<SLE>(signerListKeylet);
340  view().insert(signerList);
341  writeSignersToSLE(signerList, flags);
342 
343  auto viewJ = ctx_.app.journal("View");
344  // Add the signer list to the account's directory.
345  auto const page = ctx_.view().dirInsert(
346  ownerDirKeylet, signerListKeylet, describeOwnerDir(account_));
347 
348  JLOG(j_.trace()) << "Create signer list for account " << toBase58(account_)
349  << ": " << (page ? "success" : "failure");
350 
351  if (!page)
352  return tecDIR_FULL;
353 
354  signerList->setFieldU64(sfOwnerNode, *page);
355 
356  // If we succeeded, the new entry counts against the
357  // creator's reserve.
358  adjustOwnerCount(view(), sle, addedOwnerCount, viewJ);
359  return tesSUCCESS;
360 }
361 
362 TER
364 {
365  auto const accountKeylet = keylet::account(account_);
366  // Destroying the signer list is only allowed if either the master key
367  // is enabled or there is a regular key.
368  SLE::pointer ledgerEntry = view().peek(accountKeylet);
369  if (!ledgerEntry)
370  return tefINTERNAL;
371 
372  if ((ledgerEntry->isFlag(lsfDisableMaster)) &&
373  (!ledgerEntry->isFieldPresent(sfRegularKey)))
374  return tecNO_ALTERNATIVE_KEY;
375 
376  auto const ownerDirKeylet = keylet::ownerDir(account_);
377  auto const signerListKeylet = keylet::signers(account_);
379  ctx_.app, view(), accountKeylet, ownerDirKeylet, signerListKeylet, j_);
380 }
381 
382 void
384  SLE::pointer const& ledgerEntry,
385  std::uint32_t flags) const
386 {
387  // Assign the quorum, default SignerListID, and flags.
388  ledgerEntry->setFieldU32(sfSignerQuorum, quorum_);
389  ledgerEntry->setFieldU32(sfSignerListID, defaultSignerListID_);
390  if (flags) // Only set flags if they are non-default (default is zero).
391  ledgerEntry->setFieldU32(sfFlags, flags);
392 
393  // Create the SignerListArray one SignerEntry at a time.
394  STArray toLedger(signers_.size());
395  for (auto const& entry : signers_)
396  {
397  toLedger.emplace_back(sfSignerEntry);
398  STObject& obj = toLedger.back();
399  obj.reserve(2);
400  obj.setAccountID(sfAccount, entry.account);
401  obj.setFieldU16(sfSignerWeight, entry.weight);
402  }
403 
404  // Assign the SignerEntries.
405  ledgerEntry->setFieldArray(sfSignerEntries, toLedger);
406 }
407 
408 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::STArray::size
size_type size() const
Definition: STArray.h:209
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:300
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:108
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:151
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:217
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:584
ripple::sfRegularKey
const SF_ACCOUNT sfRegularKey
ripple::SetSignerList::destroySignerList
TER destroySignerList()
Definition: SetSignerList.cpp:363
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:238
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:56
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:148
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:258
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:130
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:327
ripple::STArray
Definition: STArray.h:28
ripple::SetSignerList::unknown
@ unknown
Definition: SetSignerList.h:45
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:555
ripple::lsfOneOwnerCount
@ lsfOneOwnerCount
Definition: LedgerFormats.h:239
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:223
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:863
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:153
ripple::tecDIR_FULL
@ tecDIR_FULL
Definition: TER.h:249
ripple::SetSignerList::doApply
TER doApply() override
Definition: SetSignerList.cpp:113
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:167
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:132
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:269
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:175
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:88
ripple::STArray::back
STObject & back()
Definition: STArray.h:154
ripple::SetSignerList::replaceSignerList
TER replaceSignerList()
Definition: SetSignerList.cpp:295
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:265
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:383
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:217
ripple::Transactor::account_
const AccountID account_
Definition: Transactor.h:91
ripple::Transactor::preCompute
virtual void preCompute()
Definition: Transactor.cpp:415
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:515