mock txmeta and pass to weakly executed hooks, add meta_slot to access this data

This commit is contained in:
Richard Holland
2022-05-16 10:18:01 +00:00
parent 0bb38809be
commit b01bbcae5c
10 changed files with 421 additions and 213 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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()
{ {