1#include <xrpl/tx/transactors/proposal/TransactionProposalCreate.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/core/ServiceRegistry.h>
5#include <xrpl/ledger/ApplyView.h>
6#include <xrpl/ledger/View.h>
7#include <xrpl/ledger/helpers/AccountRootHelpers.h>
8#include <xrpl/ledger/helpers/DirectoryHelpers.h>
9#include <xrpl/ledger/helpers/ProposalHelpers.h>
10#include <xrpl/ledger/helpers/SponsorHelpers.h>
11#include <xrpl/protocol/AccountID.h>
12#include <xrpl/protocol/Indexes.h>
13#include <xrpl/protocol/Keylet.h>
14#include <xrpl/protocol/SField.h>
15#include <xrpl/protocol/STLedgerEntry.h>
16#include <xrpl/protocol/STObject.h>
17#include <xrpl/protocol/STTx.h>
18#include <xrpl/protocol/SeqProxy.h>
19#include <xrpl/protocol/TER.h>
20#include <xrpl/protocol/XRPAmount.h>
21#include <xrpl/tx/SignerEntries.h>
22#include <xrpl/tx/Transactor.h>
23#include <xrpl/tx/applySteps.h>
37 if (ctx.
tx[sfExpiration] == 0)
39 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: zero expiration.";
61 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: proposed txn "
68 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: proposed txn "
69 "fails local checks: "
76 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: proposed txn is "
89 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: proposed txn is not "
90 "independently submittable.";
98 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: proposed txn "
99 "carries signature fields.";
105 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: proposed txn "
106 "SigningPubKey must be present and empty.";
129 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: proposed txn "
130 "reuses the Ticket this transaction itself consumes.";
142 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: already expired.";
153 if (proposedTx.isFieldPresent(sfLastLedgerSequence) &&
154 proposedTx.getFieldU32(sfLastLedgerSequence) <= ctx.
view.
seq())
156 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: proposed txn "
157 "LastLedgerSequence has passed.";
161 AccountID const target = proposedTx.getAccountID(sfAccount);
165 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: target account "
184 auto isAuthorizedFor = [&](
AccountID const& account) -> std::expected<bool, TER> {
185 if (proposer == account)
206 auto const accountSigners =
214 JLOG(ctx.
j.
fatal()) <<
"TransactionProposalCreate: unparseable SignerList: "
220 *accountSigners, [&](
auto const& entry) {
return entry.account == proposer; });
228 <<
"TransactionProposalCreate: unparseable SignerList: " << e.
what();
233 auto isSigner = isAuthorizedFor(target);
235 return isSigner.error();
248 if (!*isSigner && proposedTx.isFieldPresent(sfDelegate))
250 AccountID const delegateAccount = proposedTx.getAccountID(sfDelegate);
261 isSigner = isAuthorizedFor(delegateAccount);
263 return isSigner.error();
269 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: proposer is "
270 "not the target account, one of its "
271 "signers, or an authorized delegate.";
276 std::uint32_t const ticketSequence = proposedTx.getFieldU32(sfTicketSequence);
283 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: target ticket "
290 JLOG(ctx.
j.
debug()) <<
"TransactionProposalCreate: duplicate proposal.";
304 auto const proposedTx =
ctx_.tx.getFieldObject(sfProposedTransaction);
311 ctx_.getApplyViewContext(),
314 {.ownerCountDelta = static_cast<int>(ownerCount)},
319 AccountID const target = proposedTx.getAccountID(sfAccount);
320 std::uint32_t const ticketSequence = proposedTx.getFieldU32(sfTicketSequence);
324 sleProposal->setAccountID(sfOwner,
accountID_);
325 sleProposal->setFieldObject(sfProposedTransaction, proposedTx);
326 sleProposal->setFieldU32(sfExpiration,
ctx_.tx[sfExpiration]);
330 auto viewJ =
ctx_.registry.get().getJournal(
"View");
336 sleProposal->setFieldU64(sfOwnerNode, *page);
A generic endpoint for log messages.
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void insert(SLE::Ref sle)=0
Insert a new state SLE.
std::optional< std::uint64_t > dirInsert(Keylet const &directory, UInt256 const &key, std::function< void(SLE::Ref)> const &describe)
Insert an entry to a directory.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
LedgerIndex seq() const
Returns the sequence number of the base ledger.
std::shared_ptr< STLedgerEntry const > const & ConstRef
std::uint32_t getFieldU32(SField const &field) const
bool isFieldPresent(SField const &field) const
STObject getFieldObject(SField const &field) const
AccountID getAccountID(SField const &field) const
SeqProxy getSeqProxy() const
constexpr bool isTicket() const
static constexpr SeqProxy rawTicket(std::uint32_t v)
Factory function to return a ticket-based SeqProxy.
constexpr std::uint32_t value() const
static std::expected< std::vector< SignerEntry >, NotTEC > deserialize(STObject const &obj, beast::Journal journal, std::string_view annotation)
void visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override
Inspect a single ledger entry modified by this transaction.
bool finalizeInvariants(STTx const &tx, TER result, XRPAmount fee, ReadView const &view, beast::Journal const &j) override
Check transaction-specific post-conditions after all entries have been visited.
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
AccountID const accountID_
Keylet signerList(AccountID const &account) noexcept
A SignerList.
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet txProposal(AccountID const &target, std::uint32_t ticketSequence) noexcept
A TransactionProposal.
Keylet ticket(AccountID const &id, SeqProxy const &ticketSeq)
A ticket belonging to an account.
Keylet account(AccountID const &id) noexcept
AccountID root.
std::uint32_t proposalOwnerCount(STObject const &proposedTx)
Owner-reserve increments held by a proposal of the given transaction.
bool hasSignatureField(STObject const &proposedTx)
Whether the proposed transaction carries any signature field.
bool isValidProposal(STObject const &proposedTx)
Whether the proposed transaction is independently submittable through the ordinary multi-sign path: n...
bool hasEmptySigningPubKey(STObject const &proposedTx)
Whether the proposed transaction's SigningPubKey is present and empty, as unsigned canonical form req...
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp, ExpiryComparison comparison=ExpiryComparison::Inclusive)
Determines whether the given expiration time has passed.
PreflightResult preflight(ServiceRegistry ®istry, Rules const &rules, STTx const &tx, ApplyFlags flags, beast::Journal j)
Gate a transaction based on static information.
std::uint32_t ownerCount(SLE::ConstRef sle, beast::Journal j, std::int32_t ownerCountAdj=0)
Return number of the objects which reserve is covered by the account(sle) (so called "ownercount").
std::string transHuman(TER code)
TER checkReserve(ApplyViewContext ctx, SLE::ConstRef accSle, XRPAmount accBalance, SLE::ConstRef sponsorSle, Adjustment adj, beast::Journal j, TER insufReserveCode=tecINSUFFICIENT_RESERVE)
Check if an account has sufficient reserve.
void increaseOwnerCount(ApplyView &view, SLE::Ref accountSle, SLE::Ref sponsorSle, std::uint32_t count, beast::Journal j)
Increase owner-count fields when the caller supplies the sponsor.
std::string transToken(TER code)
void addSponsorToLedgerEntry(SLE::Ref sle, SLE::ConstRef sponsorSle, SF_ACCOUNT const &field=sfSponsor)
Stamp a reserve sponsor onto a ledger entry using an explicit sponsor SLE.
bool passesLocalChecks(STTx const &tx, std::string &)
TERSubset< CanCvtToNotTEC > NotTEC
NotTEC invokeCheckPermission(ReadView const &view, STTx const &tx)
Type-erased overload of Transactor::invokeCheckPermission.
bool isPseudoAccount(SLE::const_pointer sleAcct)
Returns true if and only if sleAcct is a pseudo-account of any kind (i.e.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
bool isTesSuccess(TER x) noexcept
TERSubset< CanCvtToTER > TER
std::function< void(SLE::Ref)> describeOwnerDir(AccountID const &account)
Returns a function that sets the owner on a directory SLE.
A pair of SHAMap key and LedgerEntryType.
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.
std::reference_wrapper< ServiceRegistry > registry