rippled
Change.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 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/ledger/Ledger.h>
21 #include <ripple/app/main/Application.h>
22 #include <ripple/app/misc/AmendmentTable.h>
23 #include <ripple/app/misc/NetworkOPs.h>
24 #include <ripple/app/tx/impl/Change.h>
25 #include <ripple/basics/Log.h>
26 #include <ripple/protocol/Feature.h>
27 #include <ripple/protocol/Indexes.h>
28 #include <ripple/protocol/TxFlags.h>
29 
30 namespace ripple {
31 
32 NotTEC
34 {
35  auto const ret = preflight0(ctx);
36  if (!isTesSuccess(ret))
37  return ret;
38 
39  auto account = ctx.tx.getAccountID(sfAccount);
40  if (account != beast::zero)
41  {
42  JLOG(ctx.j.warn()) << "Change: Bad source id";
43  return temBAD_SRC_ACCOUNT;
44  }
45 
46  // No point in going any further if the transaction fee is malformed.
47  auto const fee = ctx.tx.getFieldAmount(sfFee);
48  if (!fee.native() || fee != beast::zero)
49  {
50  JLOG(ctx.j.warn()) << "Change: invalid fee";
51  return temBAD_FEE;
52  }
53 
54  if (!ctx.tx.getSigningPubKey().empty() || !ctx.tx.getSignature().empty() ||
56  {
57  JLOG(ctx.j.warn()) << "Change: Bad signature";
58  return temBAD_SIGNATURE;
59  }
60 
61  if (ctx.tx.getSequence() != 0 || ctx.tx.isFieldPresent(sfPreviousTxnID))
62  {
63  JLOG(ctx.j.warn()) << "Change: Bad sequence";
64  return temBAD_SEQUENCE;
65  }
66 
67  if (ctx.tx.getTxnType() == ttUNL_MODIFY &&
69  {
70  JLOG(ctx.j.warn()) << "Change: NegativeUNL not enabled";
71  return temDISABLED;
72  }
73 
74  return tesSUCCESS;
75 }
76 
77 TER
79 {
80  // If tapOPEN_LEDGER is resurrected into ApplyFlags,
81  // this block can be moved to preflight.
82  if (ctx.view.open())
83  {
84  JLOG(ctx.j.warn()) << "Change transaction against open ledger";
85  return temINVALID;
86  }
87 
88  switch (ctx.tx.getTxnType())
89  {
90  case ttAMENDMENT:
91  case ttFEE:
92  case ttUNL_MODIFY:
93  return tesSUCCESS;
94  default:
95  return temUNKNOWN;
96  }
97 }
98 
99 TER
101 {
102  switch (ctx_.tx.getTxnType())
103  {
104  case ttAMENDMENT:
105  return applyAmendment();
106  case ttFEE:
107  return applyFee();
108  case ttUNL_MODIFY:
109  return applyUNLModify();
110  default:
111  assert(0);
112  return tefFAILURE;
113  }
114 }
115 
116 void
118 {
120  assert(account_ == beast::zero);
121 }
122 
123 TER
125 {
126  uint256 amendment(ctx_.tx.getFieldH256(sfAmendment));
127 
128  auto const k = keylet::amendments();
129 
130  SLE::pointer amendmentObject = view().peek(k);
131 
132  if (!amendmentObject)
133  {
134  amendmentObject = std::make_shared<SLE>(k);
135  view().insert(amendmentObject);
136  }
137 
138  STVector256 amendments = amendmentObject->getFieldV256(sfAmendments);
139 
140  if (std::find(amendments.begin(), amendments.end(), amendment) !=
141  amendments.end())
142  return tefALREADY;
143 
144  auto flags = ctx_.tx.getFlags();
145 
146  const bool gotMajority = (flags & tfGotMajority) != 0;
147  const bool lostMajority = (flags & tfLostMajority) != 0;
148 
149  if (gotMajority && lostMajority)
150  return temINVALID_FLAG;
151 
152  STArray newMajorities(sfMajorities);
153 
154  bool found = false;
155  if (amendmentObject->isFieldPresent(sfMajorities))
156  {
157  const STArray& oldMajorities =
158  amendmentObject->getFieldArray(sfMajorities);
159  for (auto const& majority : oldMajorities)
160  {
161  if (majority.getFieldH256(sfAmendment) == amendment)
162  {
163  if (gotMajority)
164  return tefALREADY;
165  found = true;
166  }
167  else
168  {
169  // pass through
170  newMajorities.push_back(majority);
171  }
172  }
173  }
174 
175  if (!found && lostMajority)
176  return tefALREADY;
177 
178  if (gotMajority)
179  {
180  // This amendment now has a majority
181  newMajorities.push_back(STObject(sfMajority));
182  auto& entry = newMajorities.back();
183  entry.emplace_back(STHash256(sfAmendment, amendment));
184  entry.emplace_back(STUInt32(
185  sfCloseTime, view().parentCloseTime().time_since_epoch().count()));
186 
187  if (!ctx_.app.getAmendmentTable().isSupported(amendment))
188  {
189  JLOG(j_.warn()) << "Unsupported amendment " << amendment
190  << " received a majority.";
191  }
192  }
193  else if (!lostMajority)
194  {
195  // No flags, enable amendment
196  amendments.push_back(amendment);
197  amendmentObject->setFieldV256(sfAmendments, amendments);
198 
199  ctx_.app.getAmendmentTable().enable(amendment);
200 
201  if (!ctx_.app.getAmendmentTable().isSupported(amendment))
202  {
203  JLOG(j_.error()) << "Unsupported amendment " << amendment
204  << " activated: server blocked.";
206  }
207  }
208 
209  if (newMajorities.empty())
210  amendmentObject->makeFieldAbsent(sfMajorities);
211  else
212  amendmentObject->setFieldArray(sfMajorities, newMajorities);
213 
214  view().update(amendmentObject);
215 
216  return tesSUCCESS;
217 }
218 
219 TER
221 {
222  auto const k = keylet::fees();
223 
224  SLE::pointer feeObject = view().peek(k);
225 
226  if (!feeObject)
227  {
228  feeObject = std::make_shared<SLE>(k);
229  view().insert(feeObject);
230  }
231 
232  feeObject->setFieldU64(sfBaseFee, ctx_.tx.getFieldU64(sfBaseFee));
233  feeObject->setFieldU32(
235  feeObject->setFieldU32(sfReserveBase, ctx_.tx.getFieldU32(sfReserveBase));
236  feeObject->setFieldU32(
238 
239  view().update(feeObject);
240 
241  JLOG(j_.warn()) << "Fees have been changed";
242  return tesSUCCESS;
243 }
244 
245 TER
247 {
248  if (!isFlagLedger(view().seq()))
249  {
250  JLOG(j_.warn()) << "N-UNL: applyUNLModify, not a flag ledger, seq="
251  << view().seq();
252  return tefFAILURE;
253  }
254 
259  {
260  JLOG(j_.warn()) << "N-UNL: applyUNLModify, wrong Tx format.";
261  return tefFAILURE;
262  }
263 
264  bool const disabling = ctx_.tx.getFieldU8(sfUNLModifyDisabling);
265  auto const seq = ctx_.tx.getFieldU32(sfLedgerSequence);
266  if (seq != view().seq())
267  {
268  JLOG(j_.warn()) << "N-UNL: applyUNLModify, wrong ledger seq=" << seq;
269  return tefFAILURE;
270  }
271 
272  Blob const validator = ctx_.tx.getFieldVL(sfUNLModifyValidator);
273  if (!publicKeyType(makeSlice(validator)))
274  {
275  JLOG(j_.warn()) << "N-UNL: applyUNLModify, bad validator key";
276  return tefFAILURE;
277  }
278 
279  JLOG(j_.info()) << "N-UNL: applyUNLModify, "
280  << (disabling ? "ToDisable" : "ToReEnable")
281  << " seq=" << seq
282  << " validator data:" << strHex(validator);
283 
284  auto const k = keylet::negativeUNL();
285  SLE::pointer negUnlObject = view().peek(k);
286  if (!negUnlObject)
287  {
288  negUnlObject = std::make_shared<SLE>(k);
289  view().insert(negUnlObject);
290  }
291 
292  bool const found = [&] {
293  if (negUnlObject->isFieldPresent(sfDisabledValidators))
294  {
295  auto const& negUnl =
296  negUnlObject->getFieldArray(sfDisabledValidators);
297  for (auto const& v : negUnl)
298  {
299  if (v.isFieldPresent(sfPublicKey) &&
300  v.getFieldVL(sfPublicKey) == validator)
301  return true;
302  }
303  }
304  return false;
305  }();
306 
307  if (disabling)
308  {
309  // cannot have more than one toDisable
310  if (negUnlObject->isFieldPresent(sfValidatorToDisable))
311  {
312  JLOG(j_.warn()) << "N-UNL: applyUNLModify, already has ToDisable";
313  return tefFAILURE;
314  }
315 
316  // cannot be the same as toReEnable
317  if (negUnlObject->isFieldPresent(sfValidatorToReEnable))
318  {
319  if (negUnlObject->getFieldVL(sfValidatorToReEnable) == validator)
320  {
321  JLOG(j_.warn())
322  << "N-UNL: applyUNLModify, ToDisable is same as ToReEnable";
323  return tefFAILURE;
324  }
325  }
326 
327  // cannot be in negative UNL already
328  if (found)
329  {
330  JLOG(j_.warn())
331  << "N-UNL: applyUNLModify, ToDisable already in negative UNL";
332  return tefFAILURE;
333  }
334 
335  negUnlObject->setFieldVL(sfValidatorToDisable, validator);
336  }
337  else
338  {
339  // cannot have more than one toReEnable
340  if (negUnlObject->isFieldPresent(sfValidatorToReEnable))
341  {
342  JLOG(j_.warn()) << "N-UNL: applyUNLModify, already has ToReEnable";
343  return tefFAILURE;
344  }
345 
346  // cannot be the same as toDisable
347  if (negUnlObject->isFieldPresent(sfValidatorToDisable))
348  {
349  if (negUnlObject->getFieldVL(sfValidatorToDisable) == validator)
350  {
351  JLOG(j_.warn())
352  << "N-UNL: applyUNLModify, ToReEnable is same as ToDisable";
353  return tefFAILURE;
354  }
355  }
356 
357  // must be in negative UNL
358  if (!found)
359  {
360  JLOG(j_.warn())
361  << "N-UNL: applyUNLModify, ToReEnable is not in negative UNL";
362  return tefFAILURE;
363  }
364 
365  negUnlObject->setFieldVL(sfValidatorToReEnable, validator);
366  }
367 
368  view().update(negUnlObject);
369  return tesSUCCESS;
370 }
371 
372 } // namespace ripple
ripple::STArray::empty
bool empty() const
Definition: STArray.h:144
ripple::STTx::getTxnType
TxType getTxnType() const
Definition: STTx.h:105
ripple::isFlagLedger
bool isFlagLedger(LedgerIndex seq)
Returns true if the given ledgerIndex is a flag ledgerIndex.
Definition: Ledger.cpp:857
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:240
ripple::Change::applyUNLModify
TER applyUNLModify()
Definition: Change.cpp:246
std::shared_ptr< STLedgerEntry >
ripple::PreclaimContext::view
ReadView const & view
Definition: Transactor.h:57
ripple::keylet::amendments
Keylet const & amendments() noexcept
The index of the amendment table.
Definition: Indexes.cpp:151
ripple::PreclaimContext::j
const beast::Journal j
Definition: Transactor.h:61
ripple::publicKeyType
boost::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:203
ripple::ApplyView::peek
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
ripple::sfSigners
const SField sfSigners(access, STI_ARRAY, 3, "Signers", SField::sMD_Default, SField::notSigning)
Definition: SField.h:516
ripple::Transactor::j_
const beast::Journal j_
Definition: Transactor.h:90
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:576
ripple::STObject::getFieldU64
std::uint64_t getFieldU64(SField const &field) const
Definition: STObject.cpp:538
ripple::Application::getAmendmentTable
virtual AmendmentTable & getAmendmentTable()=0
std::vector< unsigned char >
std::find
T find(T... args)
ripple::STUInt32
STInteger< std::uint32_t > STUInt32
Definition: STInteger.h:114
ripple::STObject::getFieldU8
unsigned char getFieldU8(SField const &field) const
Definition: STObject.cpp:520
ripple::sfAccount
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
Definition: SField.h:480
ripple::sfMajorities
const SField sfMajorities(access, STI_ARRAY, 16, "Majorities")
Definition: SField.h:523
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::STArray::push_back
void push_back(STObject const &object)
Definition: STArray.h:102
ripple::Change::preCompute
void preCompute() override
Definition: Change.cpp:117
ripple::NetworkOPs::setAmendmentBlocked
virtual void setAmendmentBlocked()=0
ripple::ApplyView::update
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
ripple::sfUNLModifyValidator
const SF_Blob sfUNLModifyValidator(access, STI_VL, 19, "UNLModifyValidator")
Definition: SField.h:475
ripple::sfUNLModifyDisabling
const SF_U8 sfUNLModifyDisabling(access, STI_UINT8, 17, "UNLModifyDisabling")
Definition: SField.h:343
ripple::STObject::getFieldVL
Blob getFieldVL(SField const &field) const
Definition: STObject.cpp:568
ripple::sfDisabledValidators
const SField sfDisabledValidators(access, STI_ARRAY, 17, "DisabledValidators")
Definition: SField.h:524
ripple::tfLostMajority
const std::uint32_t tfLostMajority
Definition: TxFlags.h:102
ripple::PreflightContext::j
const beast::Journal j
Definition: Transactor.h:39
ripple::sfReserveBase
const SF_U32 sfReserveBase(access, STI_UINT32, 31, "ReserveBase")
Definition: SField.h:384
ripple::tfGotMajority
const std::uint32_t tfGotMajority
Definition: TxFlags.h:101
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::sfMajority
const SField sfMajority(access, STI_OBJECT, 18, "Majority")
Definition: SField.h:510
ripple::ApplyContext::app
Application & app
Definition: ApplyContext.h:47
ripple::ttFEE
@ ttFEE
Definition: TxFormats.h:60
ripple::base_uint< 256 >
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:106
ripple::preflight0
NotTEC preflight0(PreflightContext const &ctx)
Performs early sanity checks on the txid.
Definition: Transactor.cpp:40
ripple::STObject::getAccountID
AccountID getAccountID(SField const &field) const
Definition: STObject.cpp:562
ripple::sfAmendment
const SF_U256 sfAmendment(access, STI_HASH256, 19, "Amendment")
Definition: SField.h:431
ripple::TERSubset< CanCvtToTER >
ripple::STArray
Definition: STArray.h:28
ripple::temBAD_SEQUENCE
@ temBAD_SEQUENCE
Definition: TER.h:99
ripple::temBAD_SRC_ACCOUNT
@ temBAD_SRC_ACCOUNT
Definition: TER.h:101
ripple::Change::doApply
TER doApply() override
Definition: Change.cpp:100
ripple::sfLedgerSequence
const SF_U32 sfLedgerSequence(access, STI_UINT32, 6, "LedgerSequence")
Definition: SField.h:358
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::sfReferenceFeeUnits
const SF_U32 sfReferenceFeeUnits(access, STI_UINT32, 30, "ReferenceFeeUnits")
Definition: SField.h:383
ripple::STObject::getFlags
std::uint32_t getFlags() const
Definition: STObject.cpp:454
ripple::STTx::getSigningPubKey
Blob getSigningPubKey() const
Definition: STTx.h:111
ripple::temBAD_SIGNATURE
@ temBAD_SIGNATURE
Definition: TER.h:100
ripple::Rules::enabled
bool enabled(uint256 const &id) const
Returns true if a feature is enabled.
Definition: ReadView.cpp:103
ripple::temUNKNOWN
@ temUNKNOWN
Definition: TER.h:119
ripple::ttAMENDMENT
@ ttAMENDMENT
Definition: TxFormats.h:59
ripple::tefFAILURE
@ tefFAILURE
Definition: TER.h:142
ripple::AmendmentTable::enable
virtual bool enable(uint256 const &amendment)=0
ripple::temBAD_FEE
@ temBAD_FEE
Definition: TER.h:87
ripple::STHash256
STBitString< 256 > STHash256
Definition: STBitString.h:129
ripple::sfFee
const SF_Amount sfFee(access, STI_AMOUNT, 8, "Fee")
Definition: SField.h:447
ripple::PreclaimContext::tx
STTx const & tx
Definition: Transactor.h:59
ripple::STTx::getSequence
std::uint32_t getSequence() const
Definition: STTx.h:117
ripple::STArray::back
STObject & back()
Definition: STArray.h:83
ripple::Change::preclaim
static TER preclaim(PreclaimContext const &ctx)
Definition: Change.cpp:78
ripple::AmendmentTable::isSupported
virtual bool isSupported(uint256 const &amendment) const =0
ripple::PreclaimContext
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:53
ripple::sfValidatorToReEnable
const SF_Blob sfValidatorToReEnable(access, STI_VL, 21, "ValidatorToReEnable")
Definition: SField.h:477
ripple::Change::applyAmendment
TER applyAmendment()
Definition: Change.cpp:124
ripple::STObject::emplace_back
std::size_t emplace_back(Args &&... args)
Definition: STObject.h:384
ripple::Change::preflight
static NotTEC preflight(PreflightContext const &ctx)
Definition: Change.cpp:33
ripple::STObject
Definition: STObject.h:51
ripple::sfPublicKey
const SF_Blob sfPublicKey(access, STI_VL, 1, "PublicKey")
Definition: SField.h:457
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::Transactor::view
ApplyView & view()
Definition: Transactor.h:107
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:109
ripple::ReadView::seq
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition: ReadView.h:256
ripple::sfReserveIncrement
const SF_U32 sfReserveIncrement(access, STI_UINT32, 32, "ReserveIncrement")
Definition: SField.h:385
ripple::STTx::getSignature
Blob getSignature() const
Definition: STTx.cpp:151
ripple::tefALREADY
@ tefALREADY
Definition: TER.h:143
ripple::featureNegativeUNL
const uint256 featureNegativeUNL
Definition: Feature.cpp:189
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:401
ripple::sfCloseTime
const SF_U32 sfCloseTime(access, STI_UINT32, 7, "CloseTime")
Definition: SField.h:359
ripple::STVector256
Definition: STVector256.h:29
std::vector::empty
T empty(T... args)
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:89
ripple::Transactor::account_
AccountID account_
Definition: Transactor.h:92
ripple::ttUNL_MODIFY
@ ttUNL_MODIFY
Definition: TxFormats.h:61
ripple::keylet::fees
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition: Indexes.cpp:159
ripple::sfValidatorToDisable
const SF_Blob sfValidatorToDisable(access, STI_VL, 20, "ValidatorToDisable")
Definition: SField.h:476
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:67
ripple::sfAmendments
const SF_Vec256 sfAmendments(access, STI_VECTOR256, 3, "Amendments")
Definition: SField.h:495
ripple::PreflightContext::tx
STTx const & tx
Definition: Transactor.h:36
ripple::STObject::getFieldU32
std::uint32_t getFieldU32(SField const &field) const
Definition: STObject.cpp:532
ripple::PreflightContext
State information when preflighting a tx.
Definition: Transactor.h:32
ripple::sfBaseFee
const SF_U64 sfBaseFee(access, STI_UINT64, 5, "BaseFee")
Definition: SField.h:399
ripple::keylet::negativeUNL
Keylet const & negativeUNL() noexcept
The (fixed) index of the object containing the ledger negativeUNL.
Definition: Indexes.cpp:167
ripple::PreflightContext::rules
const Rules rules
Definition: Transactor.h:37
ripple::Change::applyFee
TER applyFee()
Definition: Change.cpp:220
ripple::ReadView::open
virtual bool open() const =0
Returns true if this reflects an open ledger.
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:213
ripple::STObject::getFieldAmount
STAmount const & getFieldAmount(SField const &field) const
Definition: STObject.cpp:576
ripple::sfPreviousTxnID
const SF_U256 sfPreviousTxnID(access, STI_HASH256, 5, "PreviousTxnID", SField::sMD_DeleteFinal)
Definition: SField.h:421
ripple::ApplyContext::tx
STTx const & tx
Definition: ApplyContext.h:48
ripple::temINVALID
@ temINVALID
Definition: TER.h:105
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:507
ripple::STObject::getFieldH256
uint256 getFieldH256(SField const &field) const
Definition: STObject.cpp:556