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/ledger/View.h>
23 #include <ripple/protocol/Feature.h>
24 #include <ripple/protocol/Indexes.h>
25 #include <ripple/protocol/TxFlags.h>
26 #include <ripple/protocol/st.h>
27 
28 namespace ripple {
29 
30 NotTEC
32 {
34  return temDISABLED;
35 
36  if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
37  return ret;
38 
39  auto& tx = ctx.tx;
40  auto& j = ctx.j;
41 
42  if (tx.getFlags() & tfUniversalMask)
43  {
44  JLOG(j.trace()) << "Malformed transaction: Invalid flags set.";
45  return temINVALID_FLAG;
46  }
47 
48  auto const optAuth = ctx.tx[~sfAuthorize];
49  auto const optUnauth = ctx.tx[~sfUnauthorize];
50  if (static_cast<bool>(optAuth) == static_cast<bool>(optUnauth))
51  {
52  // Either both fields are present or neither field is present. In
53  // either case the transaction is malformed.
54  JLOG(j.trace())
55  << "Malformed transaction: "
56  "Invalid Authorize and Unauthorize field combination.";
57  return temMALFORMED;
58  }
59 
60  // Make sure that the passed account is valid.
61  AccountID const target{optAuth ? *optAuth : *optUnauth};
62  if (target == beast::zero)
63  {
64  JLOG(j.trace()) << "Malformed transaction: Authorized or Unauthorized "
65  "field zeroed.";
66  return temINVALID_ACCOUNT_ID;
67  }
68 
69  // An account may not preauthorize itself.
70  if (optAuth && (target == ctx.tx[sfAccount]))
71  {
72  JLOG(j.trace())
73  << "Malformed transaction: Attempting to DepositPreauth self.";
75  }
76 
77  return preflight2(ctx);
78 }
79 
80 TER
82 {
83  // Determine which operation we're performing: authorizing or unauthorizing.
84  if (ctx.tx.isFieldPresent(sfAuthorize))
85  {
86  // Verify that the Authorize account is present in the ledger.
87  AccountID const auth{ctx.tx[sfAuthorize]};
88  if (!ctx.view.exists(keylet::account(auth)))
89  return tecNO_TARGET;
90 
91  // Verify that the Preauth entry they asked to add is not already
92  // in the ledger.
93  if (ctx.view.exists(keylet::depositPreauth(ctx.tx[sfAccount], auth)))
94  return tecDUPLICATE;
95  }
96  else
97  {
98  // Verify that the Preauth entry they asked to remove is in the ledger.
99  AccountID const unauth{ctx.tx[sfUnauthorize]};
100  if (!ctx.view.exists(keylet::depositPreauth(ctx.tx[sfAccount], unauth)))
101  return tecNO_ENTRY;
102  }
103  return tesSUCCESS;
104 }
105 
106 TER
108 {
110  {
111  auto const sleOwner = view().peek(keylet::account(account_));
112  if (!sleOwner)
113  return {tefINTERNAL};
114 
115  // A preauth counts against the reserve of the issuing account, but we
116  // check the starting balance because we want to allow dipping into the
117  // reserve to pay fees.
118  {
119  STAmount const reserve{view().fees().accountReserve(
120  sleOwner->getFieldU32(sfOwnerCount) + 1)};
121 
122  if (mPriorBalance < reserve)
124  }
125 
126  // Preclaim already verified that the Preauth entry does not yet exist.
127  // Create and populate the Preauth entry.
128  AccountID const auth{ctx_.tx[sfAuthorize]};
129  Keylet const preauthKeylet = keylet::depositPreauth(account_, auth);
130  auto slePreauth = std::make_shared<SLE>(preauthKeylet);
131 
132  slePreauth->setAccountID(sfAccount, account_);
133  slePreauth->setAccountID(sfAuthorize, auth);
134  view().insert(slePreauth);
135 
136  auto viewJ = ctx_.app.journal("View");
137  auto const page = view().dirInsert(
139  preauthKeylet,
141 
142  JLOG(j_.trace()) << "Adding DepositPreauth to owner directory "
143  << to_string(preauthKeylet.key) << ": "
144  << (page ? "success" : "failure");
145 
146  if (!page)
147  return tecDIR_FULL;
148 
149  slePreauth->setFieldU64(sfOwnerNode, *page);
150 
151  // If we succeeded, the new entry counts against the creator's reserve.
152  adjustOwnerCount(view(), sleOwner, 1, viewJ);
153  }
154  else
155  {
156  auto const preauth =
158 
160  ctx_.app, view(), preauth.key, j_);
161  }
162  return tesSUCCESS;
163 }
164 
165 TER
167  Application& app,
168  ApplyView& view,
169  uint256 const& preauthIndex,
170  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(keylet::ownerDir(account), page, preauthIndex, false))
185  {
186  JLOG(j.fatal()) << "Unable to delete DepositPreauth from owner.";
187  return tefBAD_LEDGER;
188  }
189 
190  // If we succeeded, update the DepositPreauth owner's reserve.
191  auto const sleOwner = view.peek(keylet::account(account));
192  if (!sleOwner)
193  return tefINTERNAL;
194 
195  adjustOwnerCount(view, sleOwner, -1, app.journal("View"));
196 
197  // Remove DepositPreauth from ledger.
198  view.erase(slePreauth);
199 
200  return tesSUCCESS;
201 }
202 
203 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::DepositPreauth::doApply
TER doApply() override
Definition: DepositPreauth.cpp:107
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::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:130
ripple::Keylet
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:38
ripple::tecNO_TARGET
@ tecNO_TARGET
Definition: TER.h:271
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:155
ripple::Rules::enabled
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:94
std::shared_ptr
STL class.
ripple::PreclaimContext::view
ReadView const & view
Definition: Transactor.h:56
ripple::sfOwnerNode
const SF_UINT64 sfOwnerNode
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::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:731
ripple::Transactor::j_
const beast::Journal j_
Definition: Transactor.h:89
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:597
ripple::featureDepositPreauth
const uint256 featureDepositPreauth
ripple::ApplyView::erase
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
ripple::ReadView::fees
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
ripple::temCANNOT_PREAUTH_SELF
@ temCANNOT_PREAUTH_SELF
Definition: TER.h:118
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::PreflightContext::j
const beast::Journal j
Definition: Transactor.h:38
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:78
ripple::ApplyView
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:134
ripple::ApplyContext::app
Application & app
Definition: ApplyContext.h:47
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::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:109
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:152
ripple::DepositPreauth::removeFromLedger
static TER removeFromLedger(Application &app, ApplyView &view, uint256 const &delIndex, beast::Journal j)
Definition: DepositPreauth.cpp:166
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::DepositPreauth::preclaim
static TER preclaim(PreclaimContext const &ctx)
Definition: DepositPreauth.cpp:81
ripple::sfUnauthorize
const SF_ACCOUNT sfUnauthorize
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:133
ripple::tecDUPLICATE
@ tecDUPLICATE
Definition: TER.h:282
ripple::TERSubset< CanCvtToTER >
ripple::STAmount
Definition: STAmount.h:45
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:58
ripple::sfAuthorize
const SF_ACCOUNT sfAuthorize
std::uint64_t
ripple::PreclaimContext::tx
STTx const & tx
Definition: Transactor.h:58
ripple::tecDIR_FULL
@ tecDIR_FULL
Definition: TER.h:254
ripple::PreclaimContext
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:52
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::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:107
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:66
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:428
ripple::Transactor::mPriorBalance
XRPAmount mPriorBalance
Definition: Transactor.h:92
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:274
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:88
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:273
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:85
ripple::PreflightContext::tx
STTx const & tx
Definition: Transactor.h:35
ripple::PreflightContext
State information when preflighting a tx.
Definition: Transactor.h:31
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::PreflightContext::rules
const Rules rules
Definition: Transactor.h:36
ripple::DepositPreauth::preflight
static NotTEC preflight(PreflightContext const &ctx)
Definition: DepositPreauth.cpp:31
ripple::tfUniversalMask
constexpr std::uint32_t tfUniversalMask
Definition: TxFlags.h:60
ripple::keylet::depositPreauth
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Definition: Indexes.cpp:287
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:222
ripple::Transactor::account_
const AccountID account_
Definition: Transactor.h:91
ripple::ApplyContext::tx
STTx const & tx
Definition: ApplyContext.h:48
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:528