Skip to content

Commit

Permalink
Augment "submit" command response:
Browse files Browse the repository at this point in the history
If merged, this commit will report additional information in the
response to the submit command; this will make it easier for developers
to accurately track the status of transaction submission.

Fixes #2851
  • Loading branch information
p2peer authored and nbougalis committed Jan 2, 2020
1 parent 14f0234 commit 79e9085
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 2 deletions.
21 changes: 21 additions & 0 deletions src/ripple/app/misc/NetworkOPs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1070,9 +1070,15 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
if (changed)
reportFeeChange();

boost::optional<LedgerIndex> validatedLedgerIndex;
if (auto const l = m_ledgerMaster.getValidatedLedger())
validatedLedgerIndex = l->info().seq;

auto newOL = app_.openLedger().current();
for (TransactionStatus& e : transactions)
{
e.transaction->clearSubmitResult();

if (e.applied)
{
pubProposedTransaction (newOL,
Expand Down Expand Up @@ -1117,6 +1123,7 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
t, false, false, FailHard::no);
t->setApplying();
}
e.transaction->setApplied();
}
else if (e.result == tefPAST_SEQ)
{
Expand All @@ -1133,6 +1140,8 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
// kicked out of the queue, and this will try to
// put it back.
m_ledgerMaster.addHeldTransaction(e.transaction);
e.transaction->setQueued();
e.transaction->setKept();
}
else if (isTerRetry (e.result))
{
Expand All @@ -1147,6 +1156,7 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
<< "Transaction should be held: " << e.result;
e.transaction->setStatus (HELD);
m_ledgerMaster.addHeldTransaction (e.transaction);
e.transaction->setKept();
}
}
else
Expand All @@ -1161,6 +1171,7 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
m_localTX->push_back (
m_ledgerMaster.getCurrentLedgerIndex(),
e.transaction->getSTransaction());
e.transaction->setKept();
}

if (e.applied || ((mMode != OperatingMode::FULL) &&
Expand All @@ -1184,8 +1195,18 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
app_.overlay().foreach (send_if_not (
std::make_shared<Message> (tx, protocol::mtTRANSACTION),
peer_in_set(*toSkip)));
e.transaction->setBroadcast();
}
}

if (validatedLedgerIndex)
{
auto [fee, accountSeq, availableSeq] =
app_.getTxQ().getTxRequiredFeeAndSeq(
*newOL, e.transaction->getSTransaction());
e.transaction->setCurrentLedgerState(
*validatedLedgerIndex, fee, accountSeq, availableSeq);
}
}
}

Expand Down
132 changes: 132 additions & 0 deletions src/ripple/app/misc/Transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,133 @@ class Transaction
mApplying = false;
}

struct SubmitResult
{
/**
* @brief clear Clear all states
*/
void clear()
{
applied = false;
broadcast = false;
queued = false;
kept = false;
}

/**
* @brief any Get true of any state is true
* @return True if any state if true
*/
bool any() const
{
return applied || broadcast || queued || kept;
}

bool applied = false;
bool broadcast = false;
bool queued = false;
bool kept = false;
};

/**
* @brief getSubmitResult Return submit result
* @return SubmitResult struct
*/
SubmitResult getSubmitResult() const
{
return submitResult_;
}

/**
* @brief clearSubmitResult Clear all flags in SubmitResult
*/
void clearSubmitResult()
{
submitResult_.clear();
}

/**
* @brief setApplied Set this flag once was applied to open ledger
*/
void setApplied()
{
submitResult_.applied = true;
}

/**
* @brief setQueued Set this flag once was put into heldtxns queue
*/
void setQueued()
{
submitResult_.queued = true;
}

/**
* @brief setBroadcast Set this flag once was broadcasted via network
*/
void setBroadcast()
{
submitResult_.broadcast = true;
}

/**
* @brief setKept Set this flag once was put to localtxns queue
*/
void setKept()
{
submitResult_.kept = true;
}

struct CurrentLedgerState
{
CurrentLedgerState() = delete;

CurrentLedgerState(
LedgerIndex li,
XRPAmount fee,
std::uint32_t accSeqNext,
std::uint32_t accSeqAvail)
: validatedLedger{li}
, minFeeRequired{fee}
, accountSeqNext{accSeqNext}
, accountSeqAvail{accSeqAvail}
{
}

LedgerIndex validatedLedger;
XRPAmount minFeeRequired;
std::uint32_t accountSeqNext;
std::uint32_t accountSeqAvail;
};

/**
* @brief getCurrentLedgerState Get current ledger state of transaction
* @return Current ledger state
*/
boost::optional<CurrentLedgerState>
getCurrentLedgerState() const
{
return currentLedgerState_;
}

/**
* @brief setCurrentLedgerState Set current ledger state of transaction
* @param validatedLedger Number of last validated ledger
* @param fee minimum Fee required for the transaction
* @param accountSeq First valid account sequence in current ledger
* @param availableSeq First available sequence for the transaction
*/
void
setCurrentLedgerState(
LedgerIndex validatedLedger,
XRPAmount fee,
std::uint32_t accountSeq,
std::uint32_t availableSeq)
{
currentLedgerState_.emplace(
validatedLedger, fee, accountSeq, availableSeq);
}

Json::Value getJson (JsonOptions options, bool binary = false) const;

static pointer
Expand All @@ -169,6 +296,11 @@ class Transaction
TER mResult = temUNCERTAIN;
bool mApplying = false;

/** different ways for transaction to be accepted */
SubmitResult submitResult_;

boost::optional<CurrentLedgerState> currentLedgerState_;

std::shared_ptr<STTx const> mTransaction;
Application& mApp;
beast::Journal j_;
Expand Down
20 changes: 20 additions & 0 deletions src/ripple/app/misc/TxQ.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,26 @@ class TxQ
Metrics
getMetrics(OpenView const& view) const;

struct FeeAndSeq
{
XRPAmount fee;
std::uint32_t accountSeq;
std::uint32_t availableSeq;
};

/**
* @brief Returns minimum required fee for tx and two sequences:
* first vaild sequence for this account in current ledger
* and first available sequence for transaction
* @param view current open ledger
* @param tx the transaction
* @return minimum required fee, first sequence in the ledger
* and first available sequence
*/
FeeAndSeq
getTxRequiredFeeAndSeq(OpenView const& view,
std::shared_ptr<STTx const> const& tx) const;

/** Returns information about the transactions currently
in the queue for the account.
Expand Down
35 changes: 35 additions & 0 deletions src/ripple/app/misc/impl/TxQ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,41 @@ TxQ::getMetrics(OpenView const& view) const
return result;
}

TxQ::FeeAndSeq
TxQ::getTxRequiredFeeAndSeq(OpenView const& view,
std::shared_ptr<STTx const> const& tx) const
{
auto const account = (*tx)[sfAccount];

std::lock_guard lock(mutex_);

auto const snapshot = feeMetrics_.getSnapshot();
auto const baseFee = calculateBaseFee(view, *tx);
auto const fee = FeeMetrics::scaleFeeLevel(snapshot, view);

auto const accountSeq = [&view, &account]() -> std::uint32_t {
auto const sle = view.read(keylet::account(account));
if (sle)
return (*sle)[sfSequence];
return 0;
}();

auto availableSeq = accountSeq;

if (auto iter {byAccount_.find(account)}; iter != byAccount_.end())
{
auto& txQAcct = iter->second;
for (auto const& [seq, _] : txQAcct.transactions)
{
(void)_;
if (seq >= availableSeq)
availableSeq = seq + 1;
}
}

return {fee * baseFee / baseLevel, accountSeq, availableSeq};
}

auto
TxQ::getAccountTxs(AccountID const& account, ReadView const& view) const
-> std::map<TxSeq, AccountTxDetails const>
Expand Down
11 changes: 9 additions & 2 deletions src/ripple/protocol/jss.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ JSS ( TransactionType ); // in: TransactionSign.
JSS ( TransferRate ); // in: TransferRate.
JSS ( TrustSet ); // transaction type.
JSS ( aborted ); // out: InboundLedger
JSS ( accepted ); // out: LedgerToJson, OwnerInfo
JSS ( accepted ); // out: LedgerToJson, OwnerInfo, SubmitTransaction
JSS ( account ); // in/out: many
JSS ( accountState ); // out: LedgerToJson
JSS ( accountTreeHash ); // out: ledger/Ledger.cpp
Expand All @@ -109,6 +109,8 @@ JSS ( account_hash ); // out: LedgerToJson
JSS ( account_id ); // out: WalletPropose
JSS ( account_objects ); // out: AccountObjects
JSS ( account_root ); // in: LedgerEntry
JSS ( account_sequence_next ); // out: SubmitTransaction
JSS ( account_sequence_available ); // out: SubmitTransaction
JSS ( accounts ); // in: LedgerEntry, Subscribe,
// handlers/Ledger, Unsubscribe
JSS ( accounts_proposed ); // in: Subscribe, Unsubscribe
Expand All @@ -121,6 +123,7 @@ JSS ( alternatives ); // out: PathRequest, RipplePathFind
JSS ( amendment_blocked ); // out: NetworkOPs
JSS ( amendments ); // in: AccountObjects, out: NetworkOPs
JSS ( amount ); // out: AccountChannels
JSS ( applied ); // out: SubmitTransaction
JSS ( asks ); // out: Subscribe
JSS ( assets ); // out: GatewayBalances
JSS ( authorized ); // out: AccountLines
Expand All @@ -140,6 +143,7 @@ JSS ( binary ); // in: AccountTX, LedgerEntry,
JSS ( books ); // in: Subscribe, Unsubscribe
JSS ( both ); // in: Subscribe, Unsubscribe
JSS ( both_sides ); // in: Subscribe, Unsubscribe
JSS ( broadcast ); // out: SubmitTransaction
JSS ( build_path ); // in: TransactionSign
JSS ( build_version ); // out: NetworkOPs
JSS ( cancel_after ); // out: AccountChannels
Expand Down Expand Up @@ -271,6 +275,7 @@ JSS ( job_queue );
JSS ( jobs );
JSS ( jsonrpc ); // json version
JSS ( jq_trans_overflow ); // JobQueue transaction limit overflow.
JSS ( kept ); // out: SubmitTransaction
JSS ( key ); // out
JSS ( key_type ); // in/out: WalletPropose, TransactionSign
JSS ( latency ); // out: PeerImp
Expand Down Expand Up @@ -371,6 +376,7 @@ JSS ( offers ); // out: NetworkOPs, AccountOffers, Subscribe
JSS ( offline ); // in: TransactionSign
JSS ( offset ); // in/out: AccountTxOld
JSS ( open ); // out: handlers/Ledger
JSS ( open_ledger_cost ); // out: SubmitTransaction
JSS ( open_ledger_fee ); // out: TxQ
JSS ( open_ledger_level ); // out: TxQ
JSS ( owner ); // in: LedgerEntry, out: NetworkOPs
Expand Down Expand Up @@ -412,7 +418,7 @@ JSS ( quality_in ); // out: AccountLines
JSS ( quality_out ); // out: AccountLines
JSS ( queue ); // in: AccountInfo
JSS ( queue_data ); // out: AccountInfo
JSS ( queued );
JSS ( queued ); // out: SubmitTransaction
JSS ( queued_duration_us );
JSS ( random ); // out: Random
JSS ( raw_meta ); // out: AcceptedLedgerTx
Expand Down Expand Up @@ -540,6 +546,7 @@ JSS ( validator_list_expires ); // out: NetworkOps, ValidatorList
JSS ( validator_list ); // out: NetworkOps, ValidatorList
JSS ( validators );
JSS ( validated_ledger ); // out: NetworkOPs
JSS ( validated_ledger_index ); // out: SubmitTransaction
JSS ( validated_ledgers ); // out: NetworkOPs
JSS ( validation_key ); // out: ValidationCreate, ValidationSeed
JSS ( validation_private_key ); // out: ValidationCreate
Expand Down
20 changes: 20 additions & 0 deletions src/ripple/rpc/handlers/Submit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,26 @@ Json::Value doSubmit (RPC::Context& context)
jvResult[jss::engine_result] = sToken;
jvResult[jss::engine_result_code] = tpTrans->getResult ();
jvResult[jss::engine_result_message] = sHuman;

auto const submitResult = tpTrans->getSubmitResult();

jvResult[jss::accepted] = submitResult.any();
jvResult[jss::applied] = submitResult.applied;
jvResult[jss::broadcast] = submitResult.broadcast;
jvResult[jss::queued] = submitResult.queued;
jvResult[jss::kept] = submitResult.kept;

if (auto currentLedgerState = tpTrans->getCurrentLedgerState())
{
jvResult[jss::account_sequence_next]
= safe_cast<Json::Value::UInt>(currentLedgerState->accountSeqNext);
jvResult[jss::account_sequence_available]
= safe_cast<Json::Value::UInt>(currentLedgerState->accountSeqAvail);
jvResult[jss::open_ledger_cost]
= to_string(currentLedgerState->minFeeRequired);
jvResult[jss::validated_ledger_index]
= safe_cast<Json::Value::UInt>(currentLedgerState->validatedLedger);
}
}

return jvResult;
Expand Down

0 comments on commit 79e9085

Please sign in to comment.