mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-20 10:35:50 +00:00
mock txmeta and pass to weakly executed hooks, add meta_slot to access this data
This commit is contained in:
@@ -284,7 +284,7 @@ namespace hook_api
|
|||||||
"hook_param_set",
|
"hook_param_set",
|
||||||
"hook_skip",
|
"hook_skip",
|
||||||
"hook_after",
|
"hook_after",
|
||||||
"hook_weak"
|
"meta_slot"
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -152,8 +152,7 @@ namespace hook_api
|
|||||||
DECLARE_HOOK_FUNCTION(int64_t, hook_param, uint32_t write_ptr, uint32_t write_len,
|
DECLARE_HOOK_FUNCTION(int64_t, hook_param, uint32_t write_ptr, uint32_t write_len,
|
||||||
uint32_t read_ptr, uint32_t read_len);
|
uint32_t read_ptr, uint32_t read_len);
|
||||||
|
|
||||||
DECLARE_HOOK_FUNCNARG(int64_t, hook_after);
|
DECLARE_HOOK_FUNCNARG(int64_t, hook_again);
|
||||||
DECLARE_HOOK_FUNCNARG(int64_t, hook_weak);
|
|
||||||
|
|
||||||
DECLARE_HOOK_FUNCTION(int64_t, hook_skip, uint32_t read_ptr, uint32_t read_len, uint32_t flags);
|
DECLARE_HOOK_FUNCTION(int64_t, hook_skip, uint32_t read_ptr, uint32_t read_len, uint32_t flags);
|
||||||
DECLARE_HOOK_FUNCNARG(int64_t, hook_pos);
|
DECLARE_HOOK_FUNCNARG(int64_t, hook_pos);
|
||||||
@@ -195,6 +194,7 @@ namespace hook_api
|
|||||||
DECLARE_HOOK_FUNCNARG(int64_t, otxn_type );
|
DECLARE_HOOK_FUNCNARG(int64_t, otxn_type );
|
||||||
DECLARE_HOOK_FUNCTION(int64_t, otxn_slot, uint32_t slot_no );
|
DECLARE_HOOK_FUNCTION(int64_t, otxn_slot, uint32_t slot_no );
|
||||||
|
|
||||||
|
DECLARE_HOOK_FUNCTION(int64_t, meta_slot, uint32_t slot_no );
|
||||||
|
|
||||||
} /* end namespace hook_api */
|
} /* end namespace hook_api */
|
||||||
|
|
||||||
@@ -225,10 +225,12 @@ namespace hook
|
|||||||
ripple::ApplyContext& applyCtx,
|
ripple::ApplyContext& applyCtx,
|
||||||
ripple::AccountID const& account, /* the account the hook is INSTALLED ON not always the otxn account */
|
ripple::AccountID const& account, /* the account the hook is INSTALLED ON not always the otxn account */
|
||||||
bool hasCallback,
|
bool hasCallback,
|
||||||
bool isCallback = false,
|
bool isCallback,
|
||||||
bool isStrongTSH = false,
|
bool isStrongTSH,
|
||||||
uint32_t wasmParam = 0,
|
uint32_t wasmParam,
|
||||||
int32_t hookChainPosition = -1
|
int32_t hookChainPosition,
|
||||||
|
// result of apply() if this is weak exec
|
||||||
|
std::shared_ptr<STObject const> const& provisionalMeta
|
||||||
);
|
);
|
||||||
|
|
||||||
struct HookContext;
|
struct HookContext;
|
||||||
@@ -280,8 +282,9 @@ namespace hook
|
|||||||
uint32_t overrideCount = 0;
|
uint32_t overrideCount = 0;
|
||||||
int32_t hookChainPosition = -1;
|
int32_t hookChainPosition = -1;
|
||||||
bool foreignStateSetDisabled = false;
|
bool foreignStateSetDisabled = false;
|
||||||
bool executeAgainAsWeak = false; // hook_after allows strong pre-apply to nominate
|
bool executeAgainAsWeak = false; // hook_again allows strong pre-apply to nominate
|
||||||
// additional weak post-apply execution
|
// additional weak post-apply execution
|
||||||
|
std::shared_ptr<STObject const> provisionalMeta;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HookExecutor;
|
class HookExecutor;
|
||||||
@@ -554,8 +557,7 @@ namespace hook
|
|||||||
ADD_HOOK_FUNCTION(otxn_slot, ctx);
|
ADD_HOOK_FUNCTION(otxn_slot, ctx);
|
||||||
ADD_HOOK_FUNCTION(hook_account, ctx);
|
ADD_HOOK_FUNCTION(hook_account, ctx);
|
||||||
ADD_HOOK_FUNCTION(hook_hash, ctx);
|
ADD_HOOK_FUNCTION(hook_hash, ctx);
|
||||||
ADD_HOOK_FUNCTION(hook_after, ctx);
|
ADD_HOOK_FUNCTION(hook_again, ctx);
|
||||||
ADD_HOOK_FUNCTION(hook_weak, ctx);
|
|
||||||
ADD_HOOK_FUNCTION(fee_base, ctx);
|
ADD_HOOK_FUNCTION(fee_base, ctx);
|
||||||
ADD_HOOK_FUNCTION(ledger_seq, ctx);
|
ADD_HOOK_FUNCTION(ledger_seq, ctx);
|
||||||
ADD_HOOK_FUNCTION(ledger_last_hash, ctx);
|
ADD_HOOK_FUNCTION(ledger_last_hash, ctx);
|
||||||
@@ -588,6 +590,8 @@ namespace hook
|
|||||||
ADD_HOOK_FUNCTION(trace_num, ctx);
|
ADD_HOOK_FUNCTION(trace_num, ctx);
|
||||||
ADD_HOOK_FUNCTION(trace_float, ctx);
|
ADD_HOOK_FUNCTION(trace_float, ctx);
|
||||||
|
|
||||||
|
ADD_HOOK_FUNCTION(meta_slot, ctx);
|
||||||
|
|
||||||
WasmEdge_TableInstanceContext* hostTable = WasmEdge_TableInstanceCreate(tableType);
|
WasmEdge_TableInstanceContext* hostTable = WasmEdge_TableInstanceCreate(tableType);
|
||||||
WasmEdge_ImportObjectAddTable(importObj, tableName, hostTable);
|
WasmEdge_ImportObjectAddTable(importObj, tableName, hostTable);
|
||||||
WasmEdge_MemoryInstanceContext* hostMem = WasmEdge_MemoryInstanceCreate(memType);
|
WasmEdge_MemoryInstanceContext* hostMem = WasmEdge_MemoryInstanceCreate(memType);
|
||||||
|
|||||||
@@ -683,7 +683,8 @@ hook::apply(
|
|||||||
bool isCallback,
|
bool isCallback,
|
||||||
bool isStrong,
|
bool isStrong,
|
||||||
uint32_t wasmParam,
|
uint32_t wasmParam,
|
||||||
int32_t hookChainPosition)
|
int32_t hookChainPosition,
|
||||||
|
std::shared_ptr<STObject const> const& provisionalMeta)
|
||||||
{
|
{
|
||||||
|
|
||||||
HookContext hookCtx =
|
HookContext hookCtx =
|
||||||
@@ -712,7 +713,8 @@ hook::apply(
|
|||||||
.isStrong = isStrong,
|
.isStrong = isStrong,
|
||||||
.wasmParam = wasmParam,
|
.wasmParam = wasmParam,
|
||||||
.hookChainPosition = hookChainPosition,
|
.hookChainPosition = hookChainPosition,
|
||||||
.foreignStateSetDisabled = false
|
.foreignStateSetDisabled = false,
|
||||||
|
.provisionalMeta = provisionalMeta
|
||||||
},
|
},
|
||||||
.emitFailure =
|
.emitFailure =
|
||||||
isCallback && wasmParam & 1
|
isCallback && wasmParam & 1
|
||||||
@@ -4493,15 +4495,7 @@ DEFINE_HOOK_FUNCNARG(
|
|||||||
|
|
||||||
DEFINE_HOOK_FUNCNARG(
|
DEFINE_HOOK_FUNCNARG(
|
||||||
int64_t,
|
int64_t,
|
||||||
hook_weak)
|
hook_again)
|
||||||
{
|
|
||||||
HOOK_SETUP();
|
|
||||||
return (hookCtx.result.isStrong ? 0 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_HOOK_FUNCNARG(
|
|
||||||
int64_t,
|
|
||||||
hook_after)
|
|
||||||
{
|
{
|
||||||
HOOK_SETUP();
|
HOOK_SETUP();
|
||||||
|
|
||||||
@@ -4516,3 +4510,38 @@ DEFINE_HOOK_FUNCNARG(
|
|||||||
|
|
||||||
return PREREQUISITE_NOT_MET;
|
return PREREQUISITE_NOT_MET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_HOOK_FUNCTION(
|
||||||
|
int64_t,
|
||||||
|
meta_slot,
|
||||||
|
uint32_t slot_into )
|
||||||
|
{
|
||||||
|
HOOK_SETUP();
|
||||||
|
if (!hookCtx.result.provisionalMeta)
|
||||||
|
return PREREQUISITE_NOT_MET;
|
||||||
|
|
||||||
|
if (slot_into > hook_api::max_slots)
|
||||||
|
return INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
// check if we can emplace the object to a slot
|
||||||
|
if (slot_into == 0 && no_free_slots(hookCtx))
|
||||||
|
return NO_FREE_SLOTS;
|
||||||
|
|
||||||
|
if (slot_into == 0)
|
||||||
|
slot_into = get_free_slot(hookCtx);
|
||||||
|
|
||||||
|
hookCtx.slot.emplace( std::pair<int, hook::SlotEntry> { slot_into, hook::SlotEntry {
|
||||||
|
.id = {
|
||||||
|
0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU,
|
||||||
|
0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU,
|
||||||
|
0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU,
|
||||||
|
0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU,
|
||||||
|
},
|
||||||
|
.storage = hookCtx.result.provisionalMeta,
|
||||||
|
.entry = 0
|
||||||
|
}});
|
||||||
|
hookCtx.slot[slot_into].entry = &(*hookCtx.slot[slot_into].storage);
|
||||||
|
|
||||||
|
return slot_into;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,6 +101,13 @@ public:
|
|||||||
view_->rawDestroyXRP(fee);
|
view_->rawDestroyXRP(fee);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TxMeta
|
||||||
|
generateProvisionalMeta()
|
||||||
|
{
|
||||||
|
return view_->generateProvisionalMeta(base_, tx, journal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Applies all invariant checkers one by one.
|
/** Applies all invariant checkers one by one.
|
||||||
|
|
||||||
@param result the result generated by processing this transaction.
|
@param result the result generated by processing this transaction.
|
||||||
|
|||||||
@@ -901,7 +901,8 @@ executeHookChain(
|
|||||||
hook::HookStateMap& stateMap,
|
hook::HookStateMap& stateMap,
|
||||||
std::vector<hook::HookResult>& results,
|
std::vector<hook::HookResult>& results,
|
||||||
ripple::AccountID const& account,
|
ripple::AccountID const& account,
|
||||||
bool strong)
|
bool strong,
|
||||||
|
std::shared_ptr<STObject const> const& provisionalMeta)
|
||||||
{
|
{
|
||||||
std::set<uint256> hookSkips;
|
std::set<uint256> hookSkips;
|
||||||
std::map<
|
std::map<
|
||||||
@@ -978,8 +979,9 @@ executeHookChain(
|
|||||||
hasCallback,
|
hasCallback,
|
||||||
false,
|
false,
|
||||||
strong,
|
strong,
|
||||||
0,
|
(strong ? 0 : 1UL), // 0 = strong, 1 = weak
|
||||||
hook_no));
|
hook_no,
|
||||||
|
provisionalMeta));
|
||||||
|
|
||||||
executedHookCount_++;
|
executedHookCount_++;
|
||||||
|
|
||||||
@@ -1015,7 +1017,7 @@ executeHookChain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Transactor::doHookCallback()
|
Transactor::doHookCallback(std::shared_ptr<STObject const> const& provisionalMeta)
|
||||||
{
|
{
|
||||||
// Finally check if there is a callback
|
// Finally check if there is a callback
|
||||||
if (!ctx_.tx.isFieldPresent(sfEmitDetails))
|
if (!ctx_.tx.isFieldPresent(sfEmitDetails))
|
||||||
@@ -1117,7 +1119,8 @@ Transactor::doHookCallback()
|
|||||||
false,
|
false,
|
||||||
safe_cast<TxType>(ctx_.tx.getFieldU16(sfTransactionType)) == ttEMIT_FAILURE
|
safe_cast<TxType>(ctx_.tx.getFieldU16(sfTransactionType)) == ttEMIT_FAILURE
|
||||||
? 1UL : 0UL,
|
? 1UL : 0UL,
|
||||||
hook_no - 1);
|
hook_no - 1,
|
||||||
|
provisionalMeta);
|
||||||
|
|
||||||
|
|
||||||
bool success = callbackResult.exitType == hook_api::ExitType::ACCEPT;
|
bool success = callbackResult.exitType == hook_api::ExitType::ACCEPT;
|
||||||
@@ -1185,7 +1188,8 @@ Transactor::
|
|||||||
doTSH(
|
doTSH(
|
||||||
bool strong, // only strong iff true, only weak iff false
|
bool strong, // only strong iff true, only weak iff false
|
||||||
hook::HookStateMap& stateMap,
|
hook::HookStateMap& stateMap,
|
||||||
std::vector<hook::HookResult>& results)
|
std::vector<hook::HookResult>& results,
|
||||||
|
std::shared_ptr<STObject const> const& provisionalMeta)
|
||||||
{
|
{
|
||||||
auto& view = ctx_.view();
|
auto& view = ctx_.view();
|
||||||
|
|
||||||
@@ -1298,7 +1302,8 @@ doTSH(
|
|||||||
stateMap,
|
stateMap,
|
||||||
results,
|
results,
|
||||||
tshAccountID,
|
tshAccountID,
|
||||||
strong);
|
strong,
|
||||||
|
provisionalMeta);
|
||||||
|
|
||||||
if (canRollback && (tshResult != tesSUCCESS))
|
if (canRollback && (tshResult != tesSUCCESS))
|
||||||
return tshResult;
|
return tshResult;
|
||||||
@@ -1307,6 +1312,111 @@ doTSH(
|
|||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Transactor::doAaw(
|
||||||
|
AccountID const& hookAccountID,
|
||||||
|
std::set<uint256> const& hookHashes,
|
||||||
|
hook::HookStateMap& stateMap,
|
||||||
|
std::vector<hook::HookResult>& results,
|
||||||
|
std::shared_ptr<STObject const> const& provisionalMeta)
|
||||||
|
{
|
||||||
|
|
||||||
|
auto const& hooksArray = view().peek(keylet::hook(hookAccountID));
|
||||||
|
if (!hooksArray)
|
||||||
|
{
|
||||||
|
JLOG(j_.warn())
|
||||||
|
<< "HookError[]: Hook missing on aaw";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hooksArray->isFieldPresent(sfHooks))
|
||||||
|
{
|
||||||
|
JLOG(j_.warn())
|
||||||
|
<< "HookError[]: Hooks Array missing on aaw";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& hooks = hooksArray->getFieldArray(sfHooks);
|
||||||
|
int hook_no = 0;
|
||||||
|
for (auto const& hook : hooks)
|
||||||
|
{
|
||||||
|
hook_no++;
|
||||||
|
|
||||||
|
STObject const* hookObj = dynamic_cast<STObject const*>(&hook);
|
||||||
|
|
||||||
|
if (!hookObj->isFieldPresent(sfHookHash)) // skip blanks
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint256 const& hookHash = hookObj->getFieldH256(sfHookHash);
|
||||||
|
|
||||||
|
if (hookHashes.find(hookObj->getFieldH256(sfHookHash)) == hookHashes.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto const& hookDef = view().peek(keylet::hookDefinition(hookHash));
|
||||||
|
if (!hookDef)
|
||||||
|
{
|
||||||
|
JLOG(j_.warn())
|
||||||
|
<< "HookError[]: Hook def missing on aaw, hash: "
|
||||||
|
<< hookHash;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch the namespace either from the hook object of, if absent, the hook def
|
||||||
|
uint256 const& ns =
|
||||||
|
(hookObj->isFieldPresent(sfHookNamespace)
|
||||||
|
? hookObj->getFieldH256(sfHookNamespace)
|
||||||
|
: hookDef->getFieldH256(sfHookNamespace));
|
||||||
|
|
||||||
|
executedHookCount_++;
|
||||||
|
|
||||||
|
std::map<std::vector<uint8_t>, std::vector<uint8_t>> parameters;
|
||||||
|
if (hook::gatherHookParameters(hookDef, hookObj, parameters, j_))
|
||||||
|
{
|
||||||
|
JLOG(j_.warn())
|
||||||
|
<< "HookError[]: Failure: gatherHookParameters failed)";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
hook::HookResult aawResult =
|
||||||
|
hook::apply(
|
||||||
|
hookDef->getFieldH256(sfHookSetTxnID),
|
||||||
|
hookHash,
|
||||||
|
ns,
|
||||||
|
hookDef->getFieldVL(sfCreateCode),
|
||||||
|
parameters,
|
||||||
|
{},
|
||||||
|
stateMap,
|
||||||
|
ctx_,
|
||||||
|
hookAccountID,
|
||||||
|
hookDef->isFieldPresent(sfHookCallbackFee),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
2UL, // param 2 = aaw
|
||||||
|
hook_no - 1,
|
||||||
|
provisionalMeta);
|
||||||
|
|
||||||
|
|
||||||
|
results.push_back(aawResult);
|
||||||
|
|
||||||
|
JLOG(j_.trace())
|
||||||
|
<< "HookInfo[" << hookAccountID << "-" <<ctx_.tx.getAccountID(sfAccount) << "]: "
|
||||||
|
<< " aaw Hook ExitCode = "
|
||||||
|
<< aawResult.exitCode;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
JLOG(j_.fatal())
|
||||||
|
<< "HookError[" << hookAccountID << "-" <<ctx_.tx.getAccountID(sfAccount) << "]: "
|
||||||
|
<< "]: aaw failure " << e.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
std::pair<TER, bool>
|
std::pair<TER, bool>
|
||||||
Transactor::operator()()
|
Transactor::operator()()
|
||||||
@@ -1337,12 +1447,9 @@ Transactor::operator()()
|
|||||||
|
|
||||||
bool const hooksEnabled = view().rules().enabled(featureHooks);
|
bool const hooksEnabled = view().rules().enabled(featureHooks);
|
||||||
|
|
||||||
// This vector stores any "strong" hooks that requested a weak "after application" re-execution.
|
// AgainAsWeak map stores information about accounts whose strongly executed hooks
|
||||||
std::vector<
|
// request an additional weak execution after the otxn has finished application to the ledger
|
||||||
std::pair<
|
std::map<AccountID, std::set<uint256>> aawMap;
|
||||||
AccountID, // account of hook
|
|
||||||
uint256 // hash of hook
|
|
||||||
>> executeAgainAsWeak;
|
|
||||||
|
|
||||||
// Pre-application (Strong TSH) Hooks are executed here
|
// Pre-application (Strong TSH) Hooks are executed here
|
||||||
// These TSH have the right to rollback.
|
// These TSH have the right to rollback.
|
||||||
@@ -1355,8 +1462,7 @@ Transactor::operator()()
|
|||||||
hook::HookStateMap stateMap;
|
hook::HookStateMap stateMap;
|
||||||
|
|
||||||
auto const& accountID = ctx_.tx.getAccountID(sfAccount);
|
auto const& accountID = ctx_.tx.getAccountID(sfAccount);
|
||||||
std::vector<hook::HookResult> orgResults;
|
std::vector<hook::HookResult> hookResults;
|
||||||
std::vector<hook::HookResult> tshResults;
|
|
||||||
|
|
||||||
auto const& hooksOriginator = view().read(keylet::hook(accountID));
|
auto const& hooksOriginator = view().read(keylet::hook(accountID));
|
||||||
|
|
||||||
@@ -1366,9 +1472,10 @@ Transactor::operator()()
|
|||||||
executeHookChain(
|
executeHookChain(
|
||||||
hooksOriginator,
|
hooksOriginator,
|
||||||
stateMap,
|
stateMap,
|
||||||
orgResults,
|
hookResults,
|
||||||
accountID,
|
accountID,
|
||||||
true);
|
true,
|
||||||
|
{});
|
||||||
|
|
||||||
if (isTesSuccess(result))
|
if (isTesSuccess(result))
|
||||||
{
|
{
|
||||||
@@ -1376,7 +1483,7 @@ Transactor::operator()()
|
|||||||
// here. Note these are only strong TSH (who have the right to rollback the txn),
|
// here. Note these are only strong TSH (who have the right to rollback the txn),
|
||||||
// any weak TSH will be executed after doApply has been successful (callback as well)
|
// any weak TSH will be executed after doApply has been successful (callback as well)
|
||||||
|
|
||||||
result = doTSH(true, stateMap, tshResults);
|
result = doTSH(true, stateMap, hookResults, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// write state if all chains executed successfully
|
// write state if all chains executed successfully
|
||||||
@@ -1387,20 +1494,18 @@ Transactor::operator()()
|
|||||||
// this happens irrespective of whether final result was a tesSUCCESS
|
// this happens irrespective of whether final result was a tesSUCCESS
|
||||||
// because it contains error codes that any failed hooks would have
|
// because it contains error codes that any failed hooks would have
|
||||||
// returned for meta
|
// returned for meta
|
||||||
for (auto& orgResult: orgResults)
|
|
||||||
{
|
|
||||||
hook::finalizeHookResult(orgResult, ctx_, isTesSuccess(result));
|
|
||||||
if (isTesSuccess(result) && orgResult.executeAgainAsWeak)
|
|
||||||
executeAgainAsWeak.emplace_back(orgResult.account, orgResult.hookHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& tshResult: tshResults)
|
for (auto& hookResult: hookResults)
|
||||||
{
|
{
|
||||||
hook::finalizeHookResult(tshResult, ctx_, isTesSuccess(result));
|
hook::finalizeHookResult(hookResult, ctx_, isTesSuccess(result));
|
||||||
if (isTesSuccess(result) && tshResult.executeAgainAsWeak)
|
if (isTesSuccess(result) && hookResult.executeAgainAsWeak)
|
||||||
executeAgainAsWeak.emplace_back(tshResult.account, tshResult.hookHash);
|
{
|
||||||
|
if (aawMap.find(hookResult.account) == aawMap.end())
|
||||||
|
aawMap[hookResult.account] = {hookResult.hookHash};
|
||||||
|
else
|
||||||
|
aawMap[hookResult.account].emplace(hookResult.hookHash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fall through allows normal apply
|
// fall through allows normal apply
|
||||||
@@ -1416,38 +1521,6 @@ Transactor::operator()()
|
|||||||
|
|
||||||
bool applied = isTesSuccess(result);
|
bool applied = isTesSuccess(result);
|
||||||
|
|
||||||
// Post-application (Weak TSH) Hooks are executed here.
|
|
||||||
// These TSH do not have the ability to rollback.
|
|
||||||
// The callback, if any, is also executed here.
|
|
||||||
if (hooksEnabled && applied)
|
|
||||||
{
|
|
||||||
// perform callback logic if applicable
|
|
||||||
if (ctx_.tx.isFieldPresent(sfEmitDetails))
|
|
||||||
doHookCallback();
|
|
||||||
|
|
||||||
// remove emission entry if this is an emitted transaction
|
|
||||||
hook::removeEmissionEntry(ctx_);
|
|
||||||
|
|
||||||
// process weak TSH
|
|
||||||
hook::HookStateMap stateMap;
|
|
||||||
std::vector<hook::HookResult> tshResults;
|
|
||||||
|
|
||||||
doTSH(false, stateMap, tshResults);
|
|
||||||
|
|
||||||
// execute any hooks that nominated for 'again as weak'
|
|
||||||
for (auto const& [accID, hash] : executeAgainAsWeak)
|
|
||||||
{
|
|
||||||
|
|
||||||
// RH UPTO: execute individual hooks again here
|
|
||||||
}
|
|
||||||
|
|
||||||
// write hook results
|
|
||||||
hook::finalizeHookState(stateMap, ctx_, ctx_.tx.getTransactionID());
|
|
||||||
for (auto& tshResult: tshResults)
|
|
||||||
hook::finalizeHookResult(tshResult, ctx_, isTesSuccess(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
auto fee = ctx_.tx.getFieldAmount(sfFee).xrp();
|
auto fee = ctx_.tx.getFieldAmount(sfFee).xrp();
|
||||||
|
|
||||||
if (ctx_.size() > oversizeMetaDataCap)
|
if (ctx_.size() > oversizeMetaDataCap)
|
||||||
@@ -1534,6 +1607,44 @@ Transactor::operator()()
|
|||||||
applied = false;
|
applied = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Post-application (Weak TSH/AAW) Hooks are executed here.
|
||||||
|
// These TSH do not have the ability to rollback.
|
||||||
|
// The callback, if any, is also executed here.
|
||||||
|
if (applied && hooksEnabled)
|
||||||
|
{
|
||||||
|
// weakly executed hooks have access to a provisional TxMeta
|
||||||
|
// for this tx application.
|
||||||
|
std::shared_ptr<STObject const>
|
||||||
|
proMeta = std::make_shared<STObject const>(std::move(ctx_.generateProvisionalMeta().getAsObject()));
|
||||||
|
|
||||||
|
// perform callback logic if applicable
|
||||||
|
if (ctx_.tx.isFieldPresent(sfEmitDetails))
|
||||||
|
doHookCallback(proMeta);
|
||||||
|
|
||||||
|
// remove emission entry if this is an emitted transaction
|
||||||
|
hook::removeEmissionEntry(ctx_);
|
||||||
|
|
||||||
|
// process weak TSH
|
||||||
|
hook::HookStateMap stateMap;
|
||||||
|
std::vector<hook::HookResult> weakResults;
|
||||||
|
|
||||||
|
doTSH(false, stateMap, weakResults, proMeta);
|
||||||
|
|
||||||
|
// execute any hooks that nominated for 'again as weak'
|
||||||
|
for (auto const& [accID, hookHashes] : aawMap)
|
||||||
|
doAaw(accID, hookHashes, stateMap, weakResults, proMeta);
|
||||||
|
|
||||||
|
// write hook results
|
||||||
|
hook::finalizeHookState(stateMap, ctx_, ctx_.tx.getTransactionID());
|
||||||
|
for (auto& weakResult: weakResults)
|
||||||
|
hook::finalizeHookResult(weakResult, ctx_, isTesSuccess(result));
|
||||||
|
|
||||||
|
if (ctx_.size() > oversizeMetaDataCap)
|
||||||
|
result = tecOVERSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (applied)
|
if (applied)
|
||||||
{
|
{
|
||||||
// Transaction succeeded fully or (retries are not allowed and the
|
// Transaction succeeded fully or (retries are not allowed and the
|
||||||
|
|||||||
@@ -191,13 +191,27 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
|
|
||||||
void
|
void
|
||||||
doHookCallback();
|
doHookCallback(
|
||||||
|
std::shared_ptr<STObject const> const& provisionalMeta);
|
||||||
|
|
||||||
TER
|
TER
|
||||||
doTSH(
|
doTSH(
|
||||||
bool strong, // only do strong TSH iff true, otheriwse only weak
|
bool strong, // only do strong TSH iff true, otheriwse only weak
|
||||||
hook::HookStateMap& stateMap,
|
hook::HookStateMap& stateMap,
|
||||||
std::vector<hook::HookResult>& results);
|
std::vector<hook::HookResult>& result,
|
||||||
|
std::shared_ptr<STObject const> const& provisionalMeta);
|
||||||
|
|
||||||
|
|
||||||
|
// Execute a hook "Again As Weak" is a feature that allows
|
||||||
|
// a hook that which is being executed pre-application of the otxn
|
||||||
|
// to request an additional post-application execution.
|
||||||
|
void
|
||||||
|
doAaw(
|
||||||
|
AccountID const& hookAccountID,
|
||||||
|
std::set<uint256> const& hookHashes,
|
||||||
|
hook::HookStateMap& stateMap,
|
||||||
|
std::vector<hook::HookResult>& results,
|
||||||
|
std::shared_ptr<STObject const> const& provisionalMeta);
|
||||||
|
|
||||||
TER
|
TER
|
||||||
executeHookChain(
|
executeHookChain(
|
||||||
@@ -205,7 +219,9 @@ protected:
|
|||||||
hook::HookStateMap& stateMap,
|
hook::HookStateMap& stateMap,
|
||||||
std::vector<hook::HookResult>& results,
|
std::vector<hook::HookResult>& results,
|
||||||
ripple::AccountID const& account,
|
ripple::AccountID const& account,
|
||||||
bool strong);
|
bool strong,
|
||||||
|
std::shared_ptr<STObject const> const& provisionalMeta);
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
addWeakTSHFromSandbox(detail::ApplyViewBase const& pv);
|
addWeakTSHFromSandbox(detail::ApplyViewBase const& pv);
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ public:
|
|||||||
deliver_ = amount;
|
deliver_ = amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TxMeta
|
||||||
|
generateProvisionalMeta(OpenView const& to, STTx const& tx, beast::Journal j);
|
||||||
|
|
||||||
/* Set hook metadata for a hook execution
|
/* Set hook metadata for a hook execution
|
||||||
* Takes ownership / use std::move
|
* Takes ownership / use std::move
|
||||||
|
|||||||
@@ -27,8 +27,10 @@
|
|||||||
#include <ripple/ledger/ReadView.h>
|
#include <ripple/ledger/ReadView.h>
|
||||||
#include <ripple/protocol/TER.h>
|
#include <ripple/protocol/TER.h>
|
||||||
#include <ripple/protocol/TxMeta.h>
|
#include <ripple/protocol/TxMeta.h>
|
||||||
|
#include <utility>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
@@ -37,6 +39,7 @@ class ApplyStateTable
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using key_type = ReadView::key_type;
|
using key_type = ReadView::key_type;
|
||||||
|
using Mods = hash_map<key_type, std::shared_ptr<SLE>>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class Action {
|
enum class Action {
|
||||||
@@ -64,6 +67,15 @@ public:
|
|||||||
void
|
void
|
||||||
apply(RawView& to) const;
|
apply(RawView& to) const;
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<TxMeta, Mods>
|
||||||
|
generateTxMeta(
|
||||||
|
OpenView const& to,
|
||||||
|
STTx const& tx,
|
||||||
|
std::optional<STAmount> const& deliver,
|
||||||
|
std::vector<STObject> const& hookExecution,
|
||||||
|
beast::Journal j);
|
||||||
|
|
||||||
void
|
void
|
||||||
apply(
|
apply(
|
||||||
OpenView& to,
|
OpenView& to,
|
||||||
@@ -126,7 +138,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using Mods = hash_map<key_type, std::shared_ptr<SLE>>;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
threadItem(TxMeta& meta, std::shared_ptr<SLE> const& to);
|
threadItem(TxMeta& meta, std::shared_ptr<SLE> const& to);
|
||||||
|
|||||||
@@ -109,20 +109,15 @@ ApplyStateTable::visit(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
// return a txmeta and a set of created nodes
|
||||||
ApplyStateTable::apply(
|
// does not modify ledger
|
||||||
OpenView& to,
|
std::pair<TxMeta, ApplyStateTable::Mods>
|
||||||
|
ApplyStateTable::generateTxMeta(
|
||||||
|
OpenView const& to,
|
||||||
STTx const& tx,
|
STTx const& tx,
|
||||||
TER ter,
|
|
||||||
std::optional<STAmount> const& deliver,
|
std::optional<STAmount> const& deliver,
|
||||||
std::vector<STObject> const& hookExecution,
|
std::vector<STObject> const& hookExecution,
|
||||||
beast::Journal j)
|
beast::Journal j)
|
||||||
{
|
|
||||||
// Build metadata and insert
|
|
||||||
auto const sTx = std::make_shared<Serializer>();
|
|
||||||
tx.add(*sTx);
|
|
||||||
std::shared_ptr<Serializer> sMeta;
|
|
||||||
if (!to.open())
|
|
||||||
{
|
{
|
||||||
TxMeta meta(tx.getTransactionID(), to.seq());
|
TxMeta meta(tx.getTransactionID(), to.seq());
|
||||||
if (deliver)
|
if (deliver)
|
||||||
@@ -252,6 +247,29 @@ ApplyStateTable::apply(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {meta, newMod};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ApplyStateTable::apply(
|
||||||
|
OpenView& to,
|
||||||
|
STTx const& tx,
|
||||||
|
TER ter,
|
||||||
|
std::optional<STAmount> const& deliver,
|
||||||
|
std::vector<STObject> const& hookExecution,
|
||||||
|
beast::Journal j)
|
||||||
|
{
|
||||||
|
// Build metadata and insert
|
||||||
|
auto const sTx = std::make_shared<Serializer>();
|
||||||
|
tx.add(*sTx);
|
||||||
|
std::shared_ptr<Serializer> sMeta;
|
||||||
|
if (!to.open())
|
||||||
|
{
|
||||||
|
|
||||||
|
// generate meta
|
||||||
|
auto [meta, newMod] =
|
||||||
|
generateTxMeta(to, tx, deliver, hookExecution, j);
|
||||||
|
|
||||||
// add any new modified nodes to the modification set
|
// add any new modified nodes to the modification set
|
||||||
for (auto& mod : newMod)
|
for (auto& mod : newMod)
|
||||||
to.rawReplace(mod.second);
|
to.rawReplace(mod.second);
|
||||||
|
|||||||
@@ -34,6 +34,16 @@ ApplyViewImpl::apply(OpenView& to, STTx const& tx, TER ter, beast::Journal j)
|
|||||||
items_.apply(to, tx, ter, deliver_, hookExecution_, j);
|
items_.apply(to, tx, ter, deliver_, hookExecution_, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TxMeta
|
||||||
|
ApplyViewImpl::
|
||||||
|
generateProvisionalMeta(OpenView const& to, STTx const& tx, beast::Journal j)
|
||||||
|
{
|
||||||
|
auto [meta, _] =
|
||||||
|
items_.generateTxMeta(to, tx, deliver_, hookExecution_, j);
|
||||||
|
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t
|
std::size_t
|
||||||
ApplyViewImpl::size()
|
ApplyViewImpl::size()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user