mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
state change update to persist changes between hook executions in the same otxn, not compiling
This commit is contained in:
@@ -32,7 +32,6 @@ enum HookSetOperation : int8_t
|
||||
hsoUPDATE = 5
|
||||
};
|
||||
|
||||
|
||||
namespace hook
|
||||
{
|
||||
struct HookContext;
|
||||
@@ -40,6 +39,13 @@ namespace hook
|
||||
bool isEmittedTxn(ripple::STTx const& tx);
|
||||
|
||||
|
||||
// this map type acts as both a read and write cache for hook execution
|
||||
using HookStateMap = std::map<ripple::AccountID, // account that owns the state
|
||||
std::map<ripple::uint256, // namespace
|
||||
std::map<ripple::uint256, // key
|
||||
std::pair<
|
||||
bool, // is modified from ledger value
|
||||
ripple::Blob>>>>; // the value
|
||||
|
||||
namespace log
|
||||
{
|
||||
@@ -410,6 +416,7 @@ namespace hook
|
||||
std::vector<uint8_t>,
|
||||
std::vector<uint8_t>
|
||||
>> const& hookParamOverrides,
|
||||
std::shared_ptr<HookStateMap>& stateMap,
|
||||
ripple::ApplyContext& applyCtx,
|
||||
ripple::AccountID const& account, /* the account the hook is INSTALLED ON not always the otxn account */
|
||||
bool callback = false,
|
||||
@@ -441,14 +448,8 @@ namespace hook
|
||||
ripple::uint256 const& hookNamespace;
|
||||
|
||||
std::queue<std::shared_ptr<ripple::Transaction>> emittedTxn {}; // etx stored here until accept/rollback
|
||||
std::shared_ptr<
|
||||
std::map<ripple::AccountID, // account to whom the state belongs
|
||||
std::map<ripple::uint256, // namespace
|
||||
std::map<ripple::uint256, // state key
|
||||
std::pair<
|
||||
bool, // has been modified
|
||||
ripple::Blob>>>>> // actual state data
|
||||
changedState;
|
||||
std::shared_ptr<HookStateMap> stateMap;
|
||||
uint16_t changedStateCount = 0;
|
||||
std::map<
|
||||
ripple::uint256, // hook hash
|
||||
std::map<
|
||||
@@ -514,18 +515,26 @@ namespace hook
|
||||
ripple::uint256 const & key,
|
||||
ripple::Slice const& data);
|
||||
|
||||
// commit changes to ledger flags
|
||||
enum cclFlags : uint8_t {
|
||||
cclREMOVE = 0b10U,
|
||||
cclAPPLY = 0b01U
|
||||
};
|
||||
|
||||
// finalize the changes the hook made to the ledger
|
||||
void commitChangesToLedger( hook::HookResult& hookResult, ripple::ApplyContext&, uint8_t );
|
||||
// write hook execution metadata and remove emitted transaction ledger entries
|
||||
ripple::TER
|
||||
finalizeHookResult(
|
||||
hook::HookResult& hookResult,
|
||||
ripple::ApplyContext&,
|
||||
bool doEmit);
|
||||
|
||||
// write state map to ledger
|
||||
ripple::TER
|
||||
finalizeHookState(
|
||||
std::shared_ptr<HookStateMap>&,
|
||||
ripple::ApplyContext&);
|
||||
|
||||
// if the txn being executed was an emitted txn then this removes it from the emission directory
|
||||
ripple::TER
|
||||
removeEmissionEntry(
|
||||
ripple::ApplyContext& applyCtx);
|
||||
|
||||
// RH TODO: call destruct for these on rippled shutdown
|
||||
|
||||
#define ADD_HOOK_FUNCTION(F, ctx)\
|
||||
{\
|
||||
WasmEdge_FunctionInstanceContext* hf = WasmEdge_FunctionInstanceCreate(\
|
||||
|
||||
@@ -939,6 +939,7 @@ gatherHookParameters(
|
||||
bool /* error = true */
|
||||
executeHookChain(
|
||||
std::shared_ptr<ripple::STLedgerEntry const> const& hookSLE,
|
||||
std::shared_ptr<hook::HookStateMap>& stateMap,
|
||||
std::vector<hook::HookResult>& results,
|
||||
int& executedHookCount,
|
||||
ripple::AccountID const& account,
|
||||
@@ -956,6 +957,7 @@ executeHookChain(
|
||||
|
||||
auto const& hooks = hookSLE->getFieldArray(sfHooks);
|
||||
int hook_no = 0;
|
||||
|
||||
for (auto const& hook : hooks)
|
||||
{
|
||||
ripple::STObject const* hookObj = dynamic_cast<ripple::STObject const*>(&hook);
|
||||
@@ -999,7 +1001,11 @@ executeHookChain(
|
||||
// gather parameters
|
||||
std::map<std::vector<uint8_t>, std::vector<uint8_t>> parameters;
|
||||
if (gatherHookParameters(hookDef, hookObj, parameters, j_))
|
||||
{
|
||||
JLOG(j_.warn())
|
||||
<< "HookError[]: Failure: gatherHookParameters failed)";
|
||||
return true;
|
||||
}
|
||||
|
||||
results.push_back(
|
||||
hook::apply(
|
||||
@@ -1009,6 +1015,7 @@ executeHookChain(
|
||||
hookDef->getFieldVL(sfCreateCode),
|
||||
parameters,
|
||||
hookParamOverrides,
|
||||
stateMap,
|
||||
ctx,
|
||||
account,
|
||||
false,
|
||||
@@ -1087,6 +1094,10 @@ Transactor::operator()()
|
||||
(result == tesSUCCESS || result == tecHOOK_REJECTED))
|
||||
{
|
||||
|
||||
// this state map will be shared across all hooks in this execution chain
|
||||
// and any associated chains which are executed during this transaction also
|
||||
std::shared_ptr<hook::HookStateMap> stateMap = std::make_shared<hook::HookStateMap>();
|
||||
|
||||
auto const& ledger = ctx_.view();
|
||||
auto const& accountID = ctx_.tx.getAccountID(sfAccount);
|
||||
std::vector<hook::HookResult> sendResults;
|
||||
@@ -1096,7 +1107,8 @@ Transactor::operator()()
|
||||
|
||||
// First check if the Sending account has any hooks that can be fired
|
||||
if (hooksSending && hooksSending->isFieldPresent(sfHooks) && !ctx_.emitted())
|
||||
rollback = executeHookChain(hooksSending, sendResults, executedHookCount, accountID, ctx_, j_, result);
|
||||
rollback = executeHookChain(hooksSending, stateMap,
|
||||
sendResults, executedHookCount, accountID, ctx_, j_, result);
|
||||
|
||||
// Next check if the Receiving account has as a hook that can be fired...
|
||||
std::optional<AccountID>
|
||||
@@ -1107,12 +1119,23 @@ Transactor::operator()()
|
||||
auto const& hooksReceiving = ledger.read(keylet::hook(*destAccountID));
|
||||
if (hooksReceiving && hooksReceiving->isFieldPresent(sfHooks))
|
||||
rollback =
|
||||
executeHookChain(hooksReceiving, recvResults, executedHookCount, *destAccountID, ctx_, j_, result);
|
||||
executeHookChain(hooksReceiving, stateMap,
|
||||
recvResults, executedHookCount, *destAccountID, ctx_, j_, result);
|
||||
}
|
||||
|
||||
if (rollback && result != temMALFORMED)
|
||||
result = tecHOOK_REJECTED;
|
||||
|
||||
// write state if all chains executed successfully
|
||||
if (result == tesSUCCESS)
|
||||
hook::finalizeHookState(stateMap, ctx_);
|
||||
|
||||
// write hook results
|
||||
for (auto& sendResult: sendResults)
|
||||
hook::finalizeHookResult(sendResult, ctx_, result == tesSUCCESS);
|
||||
for (auto& recvResult: recvResults)
|
||||
hook::finalizeHookResult(recvResult, ctx_, result == tesSUCCESS);
|
||||
|
||||
// Finally check if there is a callback
|
||||
do
|
||||
{
|
||||
@@ -1138,7 +1161,6 @@ Transactor::operator()()
|
||||
{
|
||||
JLOG(j_.warn())
|
||||
<< "HookError[]: Hook def missing on callback";
|
||||
rollback = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1168,31 +1190,58 @@ Transactor::operator()()
|
||||
std::map<std::vector<uint8_t>, std::vector<uint8_t>> parameters;
|
||||
if (gatherHookParameters(hookDef, hookObj, parameters, j_))
|
||||
{
|
||||
rollback = true;
|
||||
JLOG(j_.warn())
|
||||
<< "HookError[]: Failure: gatherHookParameters failed)";
|
||||
break;
|
||||
}
|
||||
|
||||
found = true;
|
||||
|
||||
// this call will clean up ltEMITTED_NODE as well
|
||||
try {
|
||||
hook::apply(
|
||||
hookDef->getFieldH256(sfHookSetTxnID),
|
||||
callbackHookHash,
|
||||
ns,
|
||||
hookDef->getFieldVL(sfCreateCode),
|
||||
// params
|
||||
parameters,
|
||||
{},
|
||||
ctx_,
|
||||
callbackAccountID,
|
||||
true,
|
||||
safe_cast<TxType>(
|
||||
ctx_.tx.getFieldU16(sfTransactionType)) == ttEMIT_FAILURE ? 1UL : 0UL, hook_no - 1);
|
||||
try
|
||||
{
|
||||
// reset the stateMap
|
||||
stateMap = std::make_shared<hook::HookStateMap>();
|
||||
|
||||
hook::HookResult callbackResult =
|
||||
hook::apply(
|
||||
hookDef->getFieldH256(sfHookSetTxnID),
|
||||
callbackHookHash,
|
||||
ns,
|
||||
hookDef->getFieldVL(sfCreateCode),
|
||||
// params
|
||||
parameters,
|
||||
{},
|
||||
stateMap,
|
||||
ctx_,
|
||||
callbackAccountID,
|
||||
true,
|
||||
safe_cast<TxType>(ctx_.tx.getFieldU16(sfTransactionType)) == ttEMIT_FAILURE
|
||||
? 1UL : 0UL,
|
||||
hook_no - 1);
|
||||
|
||||
|
||||
bool success = callbackResult.exitType == hook_api::ExitType::ACCEPT;
|
||||
|
||||
// write any state changes if cbak resulted in accept()
|
||||
if (result == tesSUCCESS)
|
||||
hook::finalizeHookState(stateMap, ctx_);
|
||||
|
||||
// write the final result
|
||||
ripple::TER result =
|
||||
finalizeHookResult(callbackResult, ctx_, success);
|
||||
|
||||
JLOG(j_.trace())
|
||||
<< "HookInfo[" << HC_ACC() << "]: "
|
||||
<< "Callback finalizeHookResult = "
|
||||
<< result;
|
||||
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
JLOG(j_.fatal()) << "HookError[" << callbackAccountID << "]: Callback failure " << e.what();
|
||||
JLOG(j_.fatal())
|
||||
<< "HookError[" << callbackAccountID
|
||||
<< "]: Callback failure " << e.what();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1203,18 +1252,13 @@ Transactor::operator()()
|
||||
JLOG(j_.warn())
|
||||
<< "HookError[]: Hookhash not found on callback account";
|
||||
}
|
||||
|
||||
if (rollback)
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(0);
|
||||
|
||||
for (auto& sendResult: sendResults)
|
||||
hook::commitChangesToLedger(sendResult, ctx_, result == tesSUCCESS ? hook::cclAPPLY : hook::cclREMOVE);
|
||||
|
||||
for (auto& recvResult: recvResults)
|
||||
hook::commitChangesToLedger(recvResult, ctx_, result == tesSUCCESS ? hook::cclAPPLY : hook::cclREMOVE );
|
||||
// remove emission entry if this is an emitted transaction
|
||||
hook::removeEmissionEntry(ctx_);
|
||||
}
|
||||
|
||||
uint64_t posthook_cycles = rdtsc();
|
||||
|
||||
@@ -459,6 +459,7 @@ hook::apply(
|
||||
std::vector<uint8_t>,
|
||||
std::vector<uint8_t>
|
||||
>> const& hookParamOverrides,
|
||||
std::shared_ptr<HookStateMap> stateMap,
|
||||
ApplyContext& applyCtx,
|
||||
ripple::AccountID const& account, /* the account the hook is INSTALLED ON not always the otxn account */
|
||||
bool callback,
|
||||
@@ -479,14 +480,8 @@ hook::apply(
|
||||
.account = account,
|
||||
.otxnAccount = applyCtx.tx.getAccountID(sfAccount),
|
||||
.hookNamespace = hookNamespace,
|
||||
.changedState =
|
||||
std::make_shared<
|
||||
std::map<ripple::AccountID,
|
||||
std::map<ripple::uint256,
|
||||
std::map<ripple::uint256,
|
||||
std::pair<
|
||||
bool,
|
||||
ripple::Blob>>>>>(),
|
||||
.stateMap = stateMap,
|
||||
.changedStateCount = 0,
|
||||
.hookParamOverrides = hookParamOverrides,
|
||||
.hookParams = hookParams,
|
||||
.hookSkips = {},
|
||||
@@ -519,17 +514,6 @@ hook::apply(
|
||||
( hookCtx.result.exitType == hook_api::ExitType::ROLLBACK ? "ROLLBACK" : "ACCEPT" ) <<
|
||||
" RS: '" << hookCtx.result.exitReason.c_str() << "' RC: " << hookCtx.result.exitCode;
|
||||
|
||||
// callback auto-commits on non-rollback
|
||||
if (callback)
|
||||
{
|
||||
// importantly the callback always removes the entry from the ltEMITTED structure
|
||||
uint8_t cclMode = hook::cclREMOVE;
|
||||
// we will only apply changes from the callback if the callback accepted
|
||||
if (hookCtx.result.exitType == hook_api::ExitType::ACCEPT)
|
||||
cclMode |= hook::cclAPPLY;
|
||||
commitChangesToLedger(hookCtx.result, applyCtx, cclMode);
|
||||
}
|
||||
|
||||
return hookCtx.result;
|
||||
}
|
||||
|
||||
@@ -632,20 +616,27 @@ lookup_state_cache(
|
||||
ripple::uint256 const& ns,
|
||||
ripple::uint256 const& key)
|
||||
{
|
||||
auto& changedState = *(hookCtx.result.changedState);
|
||||
if (changedState.find(acc) == changedState.end())
|
||||
std::cout << "Lookup_state_cache: acc: " << acc << " ns: " << ns << " key: " << key << "\n";
|
||||
auto& stateMap = *(hookCtx.result.stateMap);
|
||||
if (stateMap.find(acc) == stateMap.end())
|
||||
return std::nullopt;
|
||||
|
||||
auto& changedStateAcc = changedState[acc];
|
||||
if (changedStateAcc.find(ns) == changedStateAcc.end())
|
||||
printf("here1\n");
|
||||
|
||||
auto& stateMapAcc = stateMap[acc];
|
||||
if (stateMapAcc.find(ns) == stateMapAcc.end())
|
||||
return std::nullopt;
|
||||
|
||||
printf("here2\n");
|
||||
|
||||
auto& changedStateNs = changedStateAcc[ns];
|
||||
auto& stateMapNs = stateMapAcc[ns];
|
||||
|
||||
auto const& ret = changedStateNs.find(key);
|
||||
auto const& ret = stateMapNs.find(key);
|
||||
|
||||
if (ret == changedStateNs.end())
|
||||
if (ret == stateMapNs.end())
|
||||
return std::nullopt;
|
||||
|
||||
printf("here3\n");
|
||||
|
||||
return std::cref(ret->second);
|
||||
}
|
||||
@@ -663,10 +654,10 @@ set_state_cache(
|
||||
bool modified)
|
||||
{
|
||||
|
||||
auto& changedState = *(hookCtx.result.changedState);
|
||||
if (changedState.find(acc) == changedState.end())
|
||||
auto& stateMap = *(hookCtx.result.stateMap);
|
||||
if (stateMap.find(acc) == stateMap.end())
|
||||
{
|
||||
changedState[acc] =
|
||||
stateMap[acc] =
|
||||
{
|
||||
{ ns,
|
||||
{
|
||||
@@ -679,10 +670,10 @@ set_state_cache(
|
||||
return;
|
||||
}
|
||||
|
||||
auto& changedStateAcc = changedState[acc];
|
||||
if (changedStateAcc.find(ns) == changedStateAcc.end())
|
||||
auto& stateMapAcc = stateMap[acc];
|
||||
if (stateMapAcc.find(ns) == stateMapAcc.end())
|
||||
{
|
||||
changedStateAcc[ns] =
|
||||
stateMapAcc[ns] =
|
||||
{
|
||||
{ key,
|
||||
{ modified, data }
|
||||
@@ -691,17 +682,23 @@ set_state_cache(
|
||||
return;
|
||||
}
|
||||
|
||||
auto& changedStateNs = changedStateAcc[ns];
|
||||
if (changedStateNs.find(key) == changedStateNs.end())
|
||||
auto& stateMapNs = stateMapAcc[ns];
|
||||
if (stateMapNs.find(key) == stateMapNs.end())
|
||||
{
|
||||
changedStateNs[key] = { modified, data };
|
||||
stateMapNs[key] = { modified, data };
|
||||
hookCtx.changedStateCount++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (modified)
|
||||
changedStateNs[key].first = true;
|
||||
{
|
||||
if (!stateMapNs[key].first)
|
||||
hookCtx.changedStateCount++;
|
||||
|
||||
changedStateNs[key].second = data;
|
||||
stateMapNs[key].first = true;
|
||||
}
|
||||
|
||||
stateMapNs[key].second = data;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -869,73 +866,103 @@ DEFINE_HOOK_FUNCTION(
|
||||
return read_len;
|
||||
}
|
||||
|
||||
|
||||
void hook::commitChangesToLedger(
|
||||
hook::HookResult& hookResult,
|
||||
ripple::ApplyContext& applyCtx,
|
||||
uint8_t cclMode = 0b11U)
|
||||
/* Mode: (Bits)
|
||||
* (MSB) (LSB)
|
||||
* ------------------------
|
||||
* | cclRemove | cclApply |
|
||||
* ------------------------
|
||||
* | 1 | 1 | Remove old ltEMITTED entry (where applicable) and apply state changes
|
||||
* | 0 | 1 | Apply but don't Remove ltEMITTED entry
|
||||
* | 1 | 0 | Remove but don't Apply (used when rollback on an emitted txn)
|
||||
* | 0 | 0 | Invalid option
|
||||
* ------------------------
|
||||
*/
|
||||
ripple::TER
|
||||
hook::
|
||||
finalizeHookState(
|
||||
std::shared_ptr<HookStateMap>& stateMap,
|
||||
ripple::ApplyContext& applyCtx)
|
||||
{
|
||||
|
||||
auto const& j = applyCtx.app.journal("View");
|
||||
if (cclMode == 0)
|
||||
{
|
||||
JLOG(j.warn()) <<
|
||||
"HookError[" << HR_ACC() << "]: commitChangesToLedger called with invalid mode (00)";
|
||||
return;
|
||||
}
|
||||
uint16_t changeCount = 0;
|
||||
|
||||
uint16_t change_count = 0;
|
||||
|
||||
// write hook state changes, if we are allowed to
|
||||
if (cclMode & cclAPPLY)
|
||||
{
|
||||
// write all changes to state, if in "apply" mode
|
||||
for (const auto& accEntry : *(hookResult.changedState)) {
|
||||
const auto& acc = accEntry.first;
|
||||
for (const auto& nsEntry : accEntry.second) {
|
||||
const auto& ns = nsEntry.first;
|
||||
for (const auto& cacheEntry : nsEntry.second) {
|
||||
bool is_modified = cacheEntry.second.first;
|
||||
const auto& key = cacheEntry.first;
|
||||
const auto& blob = cacheEntry.second.second;
|
||||
if (is_modified) {
|
||||
change_count++;
|
||||
// this entry isn't just cached, it was actually modified
|
||||
auto slice = Slice(blob.data(), blob.size());
|
||||
|
||||
TER result =
|
||||
setHookState(hookResult, applyCtx, acc, ns, key, slice);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "HookError[" << HR_ACC() << "]: SetHookState failed: " << result
|
||||
<< " Key: " << key
|
||||
<< " Value: " << slice;
|
||||
|
||||
}
|
||||
// ^ should not fail... checks were done before map insert
|
||||
// write all changes to state, if in "apply" mode
|
||||
for (const auto& accEntry : *(hookResult.stateMap)) {
|
||||
const auto& acc = accEntry.first;
|
||||
for (const auto& nsEntry : accEntry.second) {
|
||||
const auto& ns = nsEntry.first;
|
||||
for (const auto& cacheEntry : nsEntry.second) {
|
||||
bool is_modified = cacheEntry.second.first;
|
||||
const auto& key = cacheEntry.first;
|
||||
const auto& blob = cacheEntry.second.second;
|
||||
if (is_modified) {
|
||||
changeCount++;
|
||||
if (changeCount == 0) // RH TODO: limit the max number of state changes?
|
||||
{
|
||||
// overflow
|
||||
JLOG(j.warn())
|
||||
<< "HooKError[" << HR_ACC << "]: SetHooKState failed: Too many state changes";
|
||||
return tecHOOK_REJECTED;
|
||||
}
|
||||
|
||||
// this entry isn't just cached, it was actually modified
|
||||
auto slice = Slice(blob.data(), blob.size());
|
||||
|
||||
TER result =
|
||||
setHookState(hookResult, applyCtx, acc, ns, key, slice);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "HookError[" << HR_ACC() << "]: SetHookState failed: " << result
|
||||
<< " Key: " << key
|
||||
<< " Value: " << slice;
|
||||
|
||||
}
|
||||
// ^ should not fail... checks were done before map insert
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return changeCount;
|
||||
}
|
||||
|
||||
ripple::TER
|
||||
hook::
|
||||
removeEmissionEntry(ripple::ApplyContext& applyCtx)
|
||||
{
|
||||
auto const& j = applyCtx.app.journal("View");
|
||||
|
||||
auto const& tx = applyCtx.tx;
|
||||
if (!const_cast<ripple::STTx&>(tx).isFieldPresent(sfEmitDetails))
|
||||
return tesSUCCESS;
|
||||
|
||||
auto key = keylet::emitted(tx.getTransactionID());
|
||||
|
||||
auto const& sle = applyCtx.view().peek(key);
|
||||
|
||||
if (!sle)
|
||||
return tesSUCCESS;
|
||||
|
||||
if (!applyCtx.view().dirRemove(
|
||||
keylet::emittedDir(),
|
||||
sle->getFieldU64(sfOwnerNode),
|
||||
key,
|
||||
false))
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "HookError[" << HR_ACC() << "]: ccl tefBAD_LEDGER";
|
||||
return tefBAD_LEDGER;
|
||||
}
|
||||
|
||||
applyCtx.view().erase(sle);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
hook::
|
||||
finalizeHookResult(
|
||||
hook::HookResult& hookResult,
|
||||
ripple::ApplyContext& applyCtx,
|
||||
bool doEmit)
|
||||
{
|
||||
|
||||
auto const& j = applyCtx.app.journal("View");
|
||||
uint16_t change_count = 0;
|
||||
|
||||
// open views do not modify add/remove ledger entries
|
||||
if (applyCtx.view().open())
|
||||
return;
|
||||
return tesSUCCESS;
|
||||
|
||||
//RH TODO: this seems hacky... and also maybe there's a way this cast might fail?
|
||||
ApplyViewImpl& avi = dynamic_cast<ApplyViewImpl&>(applyCtx.view());
|
||||
@@ -943,7 +970,7 @@ void hook::commitChangesToLedger(
|
||||
uint16_t exec_index = avi.nextHookExecutionIndex();
|
||||
uint16_t emission_count = 0;
|
||||
// apply emitted transactions to the ledger (by adding them to the emitted directory) if we are allowed to
|
||||
if (cclMode & cclAPPLY)
|
||||
if (doEmit)
|
||||
{
|
||||
DBG_PRINTF("emitted txn count: %d\n", hookResult.emittedTxn.size());
|
||||
for (; hookResult.emittedTxn.size() > 0; hookResult.emittedTxn.pop())
|
||||
@@ -985,47 +1012,12 @@ void hook::commitChangesToLedger(
|
||||
{
|
||||
JLOG(j.warn()) << "HookError[" << HR_ACC() << "]: " <<
|
||||
"Emission Directory full when trying to insert " << id;
|
||||
break;
|
||||
return tecDIR_FULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove this (activating) transaction from the emitted directory if we were instructed to
|
||||
if (cclMode & cclREMOVE)
|
||||
{
|
||||
do
|
||||
{
|
||||
auto const& tx = applyCtx.tx;
|
||||
if (!const_cast<ripple::STTx&>(tx).isFieldPresent(sfEmitDetails))
|
||||
break;
|
||||
|
||||
auto key = keylet::emitted(tx.getTransactionID());
|
||||
|
||||
auto const& sle = applyCtx.view().peek(key);
|
||||
|
||||
if (!sle)
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "HookError[" << HR_ACC() << "]: ccl tried to remove already removed emittedtxn";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!applyCtx.view().dirRemove(
|
||||
keylet::emittedDir(),
|
||||
sle->getFieldU64(sfOwnerNode),
|
||||
key,
|
||||
false))
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "HookError[" << HR_ACC() << "]: ccl tefBAD_LEDGER";
|
||||
break;
|
||||
}
|
||||
|
||||
applyCtx.view().erase(sle);
|
||||
} while (0);
|
||||
}
|
||||
|
||||
// add a metadata entry for this hook execution result
|
||||
STObject meta { sfHookExecution };
|
||||
meta.setFieldU8(sfHookResult, hookResult.exitType );
|
||||
@@ -1042,11 +1034,14 @@ void hook::commitChangesToLedger(
|
||||
meta.setFieldU64(sfHookInstructionCount, hookResult.instructionCount);
|
||||
meta.setFieldU16(sfHookEmitCount, emission_count); // this will never wrap, hard limit
|
||||
meta.setFieldU16(sfHookExecutionIndex, exec_index );
|
||||
meta.setFieldU16(sfHookStateChangeCount, change_count );
|
||||
meta.setFieldU16(sfHookStateChangeCount, hookResult.changedStateCount );
|
||||
meta.setFieldH256(sfHookHash, hookResult.hookHash);
|
||||
avi.addHookMetaData(std::move(meta));
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Retrieve the state into write_ptr identified by the key in kread_ptr */
|
||||
DEFINE_HOOK_FUNCTION(
|
||||
int64_t,
|
||||
@@ -1058,8 +1053,8 @@ DEFINE_HOOK_FUNCTION(
|
||||
state_foreign(
|
||||
hookCtx, memoryCtx,
|
||||
write_ptr, write_len,
|
||||
0, 0,
|
||||
kread_ptr, kread_len,
|
||||
0, 0,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user