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  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()) << "Malformed transaction: Invalid flags set.";
46  return temINVALID_FLAG;
47  }
48 
49  auto const optAuth = ctx.tx[~sfAuthorize];
50  auto const optUnauth = ctx.tx[~sfUnauthorize];
51  if (static_cast<bool>(optAuth) == static_cast<bool>(optUnauth))
52  {
53  // Either both fields are present or neither field is present. In
54  // either case the transaction is malformed.
55  JLOG(j.trace())
56  << "Malformed transaction: "
57  "Invalid Authorize and Unauthorize field combination.";
58  return temMALFORMED;
59  }
60 
61  // Make sure that the passed account is valid.
62  AccountID const target{optAuth ? *optAuth : *optUnauth};
63  if (target == beast::zero)
64  {
65  JLOG(j.trace()) << "Malformed transaction: Authorized or Unauthorized "
66  "field zeroed.";
67  return temINVALID_ACCOUNT_ID;
68  }
69 
70  // An account may not preauthorize itself.
71  if (optAuth && (target == ctx.tx[sfAccount]))
72  {
73  JLOG(j.trace())
74  << "Malformed transaction: Attempting to DepositPreauth self.";
76  }
77 
78  return preflight2(ctx);
79 }
80 
81 TER
83 {
84  // Determine which operation we're performing: authorizing or unauthorizing.
85  if (ctx.tx.isFieldPresent(sfAuthorize))
86  {
87  // Verify that the Authorize account is present in the ledger.
88  AccountID const auth{ctx.tx[sfAuthorize]};
89  if (!ctx.view.exists(keylet::account(auth)))
90  return tecNO_TARGET;
91 
92  // Verify that the Preauth entry they asked to add is not already
93  // in the ledger.
94  if (ctx.view.exists(keylet::depositPreauth(ctx.tx[sfAccount], auth)))
95  return tecDUPLICATE;
96  }
97  else
98  {
99  // Verify that the Preauth entry they asked to remove is in the ledger.
100  AccountID const unauth{ctx.tx[sfUnauthorize]};
101  if (!ctx.view.exists(keylet::depositPreauth(ctx.tx[sfAccount], unauth)))
102  return tecNO_ENTRY;
103  }
104  return tesSUCCESS;
105 }
106 
107 TER
109 {
111  {
112  auto const sleOwner = view().peek(keylet::account(account_));
113  if (!sleOwner)
114  return {tefINTERNAL};
115 
116  // A preauth counts against the reserve of the issuing account, but we
117  // check the starting balance because we want to allow dipping into the
118  // reserve to pay fees.
119  {
120  STAmount const reserve{view().fees().accountReserve(
121  sleOwner->getFieldU32(sfOwnerCount) + 1)};
122 
123  if (mPriorBalance < reserve)
125  }
126 
127  // Preclaim already verified that the Preauth entry does not yet exist.
128  // Create and populate the Preauth entry.
129  AccountID const auth{ctx_.tx[sfAuthorize]};
130  auto slePreauth =
131  std::make_shared<SLE>(keylet::depositPreauth(account_, auth));
132 
133  slePreauth->setAccountID(sfAccount, account_);
134  slePreauth->setAccountID(sfAuthorize, auth);
135  view().insert(slePreauth);
136 
137  auto viewJ = ctx_.app.journal("View");
138  auto const page = view().dirInsert(
140  slePreauth->key(),
142 
143  JLOG(j_.trace()) << "Adding DepositPreauth to owner directory "
144  << to_string(slePreauth->key()) << ": "
145  << (page ? "success" : "failure");
146 
147  if (!page)
148  return tecDIR_FULL;
149 
150  slePreauth->setFieldU64(sfOwnerNode, *page);
151 
152  // If we succeeded, the new entry counts against the creator's reserve.
153  adjustOwnerCount(view(), sleOwner, 1, viewJ);
154  }
155  else
156  {
157  auto const preauth =
159 
161  ctx_.app, view(), preauth.key, j_);
162  }
163  return tesSUCCESS;
164 }
165 
166 TER
168  Application& app,
169  ApplyView& view,
170  uint256 const& preauthIndex,
171  beast::Journal j)
172 {
173  // Verify that the Preauth entry they asked to remove is
174  // in the ledger.
175  std::shared_ptr<SLE> const slePreauth{
176  view.peek(keylet::depositPreauth(preauthIndex))};
177  if (!slePreauth)
178  {
179  JLOG(j.warn()) << "Selected DepositPreauth does not exist.";
180  return tecNO_ENTRY;
181  }
182 
183  AccountID const account{(*slePreauth)[sfAccount]};
184  std::uint64_t const page{(*slePreauth)[sfOwnerNode]};
185  if (!view.dirRemove(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:339
ripple::DepositPreauth::doApply
TER doApply() override
Definition: DepositPreauth.cpp:108
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:285
ripple::Application
Definition: Application.h:97
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:262
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:149
std::shared_ptr
STL class.
ripple::PreclaimContext::view
ReadView const & view
Definition: Transactor.h:57
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:713
ripple::Transactor::j_
const beast::Journal j_
Definition: Transactor.h:90
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:576
ripple::featureDepositPreauth
const uint256 featureDepositPreauth
Definition: Feature.cpp:175
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:315
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:480
ripple::temCANNOT_PREAUTH_SELF
@ temCANNOT_PREAUTH_SELF
Definition: TER.h:115
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::sfUnauthorize
const SF_Account sfUnauthorize(access, STI_ACCOUNT, 6, "Unauthorize")
Definition: SField.h:485
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::sfOwnerNode
const SF_U64 sfOwnerNode(access, STI_UINT64, 4, "OwnerNode")
Definition: SField.h:398
ripple::sfOwnerCount
const SF_U32 sfOwnerCount(access, STI_UINT32, 13, "OwnerCount")
Definition: SField.h:365
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:140
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:41
ripple::base_uint< 160, detail::AccountIDTag >
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:106
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:146
ripple::DepositPreauth::removeFromLedger
static TER removeFromLedger(Application &app, ApplyView &view, uint256 const &delIndex, beast::Journal j)
Definition: DepositPreauth.cpp:167
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:642
ripple::DepositPreauth::preclaim
static TER preclaim(PreclaimContext const &ctx)
Definition: DepositPreauth.cpp:82
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:121
ripple::tecDUPLICATE
@ tecDUPLICATE
Definition: TER.h:273
ripple::TERSubset< CanCvtToTER >
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:58
std::uint64_t
ripple::Rules::enabled
bool enabled(uint256 const &id) const
Returns true if a feature is enabled.
Definition: ReadView.cpp:103
ripple::PreclaimContext::tx
STTx const & tx
Definition: Transactor.h:59
ripple::tecDIR_FULL
@ tecDIR_FULL
Definition: TER.h:245
ripple::PreclaimContext
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:53
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:114
ripple::Transactor::view
ApplyView & view()
Definition: Transactor.h:107
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:109
ripple::Fees::accountReserve
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
Definition: ReadView.h:65
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:401
ripple::Transactor::mPriorBalance
XRPAmount mPriorBalance
Definition: Transactor.h:93
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:265
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:89
ripple::Transactor::account_
AccountID account_
Definition: Transactor.h:92
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:264
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:82
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:484
ripple::PreflightContext::rules
const Rules rules
Definition: Transactor.h:37
ripple::DepositPreauth::preflight
static NotTEC preflight(PreflightContext const &ctx)
Definition: DepositPreauth.cpp:31
ripple::keylet::depositPreauth
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Definition: Indexes.cpp:269
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:213
ripple::ApplyContext::tx
STTx const & tx
Definition: ApplyContext.h:48
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:507