rippled
DepositPreauth.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2018 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/DepositPreauth.h>
21 #include <ripple/basics/Log.h>
22 #include <ripple/protocol/Feature.h>
23 #include <ripple/protocol/Indexes.h>
24 #include <ripple/protocol/st.h>
25 #include <ripple/protocol/TxFlags.h>
26 #include <ripple/ledger/View.h>
27 
28 namespace ripple {
29 
30 NotTEC
32 {
34  return temDISABLED;
35 
36  auto const ret = preflight1 (ctx);
37  if (!isTesSuccess (ret))
38  return ret;
39 
40  auto& tx = ctx.tx;
41  auto& j = ctx.j;
42 
43  if (tx.getFlags() & tfUniversalMask)
44  {
45  JLOG(j.trace()) <<
46  "Malformed transaction: Invalid flags set.";
47  return temINVALID_FLAG;
48  }
49 
50  auto const optAuth = ctx.tx[~sfAuthorize];
51  auto const optUnauth = ctx.tx[~sfUnauthorize];
52  if (static_cast<bool>(optAuth) == static_cast<bool>(optUnauth))
53  {
54  // Either both fields are present or neither field is present. In
55  // either case the transaction is malformed.
56  JLOG(j.trace()) <<
57  "Malformed transaction: "
58  "Invalid Authorize and Unauthorize field combination.";
59  return temMALFORMED;
60  }
61 
62  // Make sure that the passed account is valid.
63  AccountID const target {optAuth ? *optAuth : *optUnauth};
64  if (target == beast::zero)
65  {
66  JLOG(j.trace()) <<
67  "Malformed transaction: Authorized or Unauthorized field zeroed.";
68  return temINVALID_ACCOUNT_ID;
69  }
70 
71  // An account may not preauthorize itself.
72  if (optAuth && (target == ctx.tx[sfAccount]))
73  {
74  JLOG(j.trace()) <<
75  "Malformed transaction: Attempting to DepositPreauth self.";
77  }
78 
79  return preflight2 (ctx);
80 }
81 
82 TER
84 {
85  // Determine which operation we're performing: authorizing or unauthorizing.
86  if (ctx.tx.isFieldPresent (sfAuthorize))
87  {
88  // Verify that the Authorize account is present in the ledger.
89  AccountID const auth {ctx.tx[sfAuthorize]};
90  if (! ctx.view.exists (keylet::account (auth)))
91  return tecNO_TARGET;
92 
93  // Verify that the Preauth entry they asked to add is not already
94  // in the ledger.
95  if (ctx.view.exists (
96  keylet::depositPreauth (ctx.tx[sfAccount], auth)))
97  return tecDUPLICATE;
98  }
99  else
100  {
101  // Verify that the Preauth entry they asked to remove is in the ledger.
102  AccountID const unauth {ctx.tx[sfUnauthorize]};
103  if (! ctx.view.exists (
104  keylet::depositPreauth (ctx.tx[sfAccount], unauth)))
105  return tecNO_ENTRY;
106  }
107  return tesSUCCESS;
108 }
109 
110 TER
112 {
114  {
115  auto const sleOwner = view().peek (keylet::account (account_));
116  if (! sleOwner)
117  return {tefINTERNAL};
118 
119  // A preauth counts against the reserve of the issuing account, but we
120  // check the starting balance because we want to allow dipping into the
121  // reserve to pay fees.
122  {
123  STAmount const reserve {view().fees().accountReserve (
124  sleOwner->getFieldU32 (sfOwnerCount) + 1)};
125 
126  if (mPriorBalance < reserve)
128  }
129 
130  // Preclaim already verified that the Preauth entry does not yet exist.
131  // Create and populate the Preauth entry.
132  AccountID const auth {ctx_.tx[sfAuthorize]};
133  auto slePreauth =
134  std::make_shared<SLE>(keylet::depositPreauth (account_, auth));
135 
136  slePreauth->setAccountID (sfAccount, account_);
137  slePreauth->setAccountID (sfAuthorize, auth);
138  view().insert (slePreauth);
139 
140  auto viewJ = ctx_.app.journal ("View");
141  auto const page = view().dirInsert (keylet::ownerDir (account_),
142  slePreauth->key(), describeOwnerDir (account_));
143 
144  JLOG(j_.trace())
145  << "Adding DepositPreauth to owner directory "
146  << to_string (slePreauth->key())
147  << ": " << (page ? "success" : "failure");
148 
149  if (! page)
150  return tecDIR_FULL;
151 
152  slePreauth->setFieldU64 (sfOwnerNode, *page);
153 
154  // If we succeeded, the new entry counts against the creator's reserve.
155  adjustOwnerCount (view(), sleOwner, 1, viewJ);
156  }
157  else
158  {
159  AccountID const unauth {ctx_.tx[sfUnauthorize]};
160  uint256 const preauthIndex {getDepositPreauthIndex (account_, unauth)};
161 
163  ctx_.app, view(), preauthIndex, j_);
164  }
165  return tesSUCCESS;
166 }
167 
168 TER
170  ApplyView& view, uint256 const& preauthIndex, beast::Journal j)
171 {
172  // Verify that the Preauth entry they asked to remove is
173  // in the ledger.
174  std::shared_ptr<SLE> const slePreauth {
175  view.peek (keylet::depositPreauth (preauthIndex))};
176  if (! slePreauth)
177  {
178  JLOG(j.warn()) << "Selected DepositPreauth does not exist.";
179  return tecNO_ENTRY;
180  }
181 
182  AccountID const account {(*slePreauth)[sfAccount]};
183  std::uint64_t const page {(*slePreauth)[sfOwnerNode]};
184  if (! view.dirRemove (
185  keylet::ownerDir (account), page, preauthIndex, false))
186  {
187  JLOG(j.fatal()) << "Unable to delete DepositPreauth from owner.";
188  return tefBAD_LEDGER;
189  }
190 
191  // If we succeeded, update the DepositPreauth owner's reserve.
192  auto const sleOwner = view.peek (keylet::account (account));
193  if (! sleOwner)
194  return tefINTERNAL;
195 
196  adjustOwnerCount (view, sleOwner, -1, app.journal ("View"));
197 
198  // Remove DepositPreauth from ledger.
199  view.erase (slePreauth);
200 
201  return tesSUCCESS;
202 }
203 
204 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:312
ripple::DepositPreauth::doApply
TER doApply() override
Definition: DepositPreauth.cpp:111
ripple::Application
Definition: Application.h:85
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:90
ripple::tecNO_TARGET
@ tecNO_TARGET
Definition: TER.h:269
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:153
std::shared_ptr
STL class.
ripple::PreclaimContext::view
ReadView const & view
Definition: Transactor.h:53
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:287
ripple::ApplyView::peek
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:700
ripple::Transactor::j_
const beast::Journal j_
Definition: Transactor.h:82
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:501
ripple::featureDepositPreauth
const uint256 featureDepositPreauth
Definition: Feature.cpp:169
ripple::ApplyView::erase
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
ripple::ApplyView::dirInsert
boost::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:327
ripple::ReadView::fees
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
ripple::sfAccount
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
Definition: SField.h:460
ripple::temCANNOT_PREAUTH_SELF
@ temCANNOT_PREAUTH_SELF
Definition: TER.h:118
beast::Journal::warn
Stream warn() const
Definition: Journal.h:302
ripple::sfUnauthorize
const SF_Account sfUnauthorize(access, STI_ACCOUNT, 6, "Unauthorize")
Definition: SField.h:465
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::sfOwnerNode
const SF_U64 sfOwnerNode(access, STI_UINT64, 4, "OwnerNode")
Definition: SField.h:382
ripple::sfOwnerCount
const SF_U32 sfOwnerCount(access, STI_UINT32, 13, "OwnerCount")
Definition: SField.h:349
ripple::PreflightContext::j
const beast::Journal j
Definition: Transactor.h:39
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:150
ripple::ApplyContext::app
Application & app
Definition: ApplyContext.h:44
ripple::keylet::depositPreauth
static const depositPreauth_t depositPreauth
Definition: Indexes.h:269
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:41
ripple::base_uint< 160, detail::AccountIDTag >
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:109
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:150
ripple::DepositPreauth::removeFromLedger
static TER removeFromLedger(Application &app, ApplyView &view, uint256 const &delIndex, beast::Journal j)
Definition: DepositPreauth.cpp:169
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:629
ripple::DepositPreauth::preclaim
static TER preclaim(PreclaimContext const &ctx)
Definition: DepositPreauth.cpp:83
ripple::keylet::account
static const account_t account
Definition: Indexes.h:116
ripple::tecDUPLICATE
@ tecDUPLICATE
Definition: TER.h:280
ripple::TERSubset< CanCvtToTER >
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id)
The root page of an account's directory.
Definition: Indexes.cpp:318
ripple::STAmount
Definition: STAmount.h:42
ripple::ReadView::exists
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
std::uint64_t
ripple::Rules::enabled
bool enabled(uint256 const &id) const
Returns true if a feature is enabled.
Definition: ReadView.cpp:107
ripple::PreclaimContext::tx
STTx const & tx
Definition: Transactor.h:55
ripple::tecDIR_FULL
@ tecDIR_FULL
Definition: TER.h:252
ripple::PreclaimContext
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:49
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::getDepositPreauthIndex
uint256 getDepositPreauthIndex(AccountID const &owner, AccountID const &preauthorized)
Definition: Indexes.cpp:195
ripple::Application::journal
virtual beast::Journal journal(std::string const &name)=0
ripple::temINVALID_ACCOUNT_ID
@ temINVALID_ACCOUNT_ID
Definition: TER.h:117
ripple::Transactor::view
ApplyView & view()
Definition: Transactor.h:98
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:112
ripple::Fees::accountReserve
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
Definition: ReadView.h:64
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:392
ripple::Transactor::mPriorBalance
XRPAmount mPriorBalance
Definition: Transactor.h:85
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:272
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:81
ripple::Transactor::account_
AccountID account_
Definition: Transactor.h:84
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:271
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:85
ripple::tfUniversalMask
const std::uint32_t tfUniversalMask
Definition: TxFlags.h:50
ripple::PreflightContext::tx
STTx const & tx
Definition: Transactor.h:36
ripple::PreflightContext
State information when preflighting a tx.
Definition: Transactor.h:32
ripple::sfAuthorize
const SF_Account sfAuthorize(access, STI_ACCOUNT, 5, "Authorize")
Definition: SField.h:464
ripple::PreflightContext::rules
const Rules rules
Definition: Transactor.h:37
ripple::DepositPreauth::preflight
static NotTEC preflight(PreflightContext const &ctx)
Definition: DepositPreauth.cpp:31
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:219
ripple::ApplyContext::tx
STTx const & tx
Definition: ApplyContext.h:45
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:461