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

@@ -109,6 +109,147 @@ ApplyStateTable::visit(
}
}
// return a txmeta and a set of created nodes
// does not modify ledger
std::pair<TxMeta, ApplyStateTable::Mods>
ApplyStateTable::generateTxMeta(
OpenView const& to,
STTx const& tx,
std::optional<STAmount> const& deliver,
std::vector<STObject> const& hookExecution,
beast::Journal j)
{
TxMeta meta(tx.getTransactionID(), to.seq());
if (deliver)
meta.setDeliveredAmount(*deliver);
if (!hookExecution.empty())
meta.setHookExecutions(STArray{hookExecution, sfHookExecutions});
Mods newMod;
for (auto& item : items_)
{
SField const* type;
switch (item.second.first)
{
default:
case Action::cache:
continue;
case Action::erase:
type = &sfDeletedNode;
break;
case Action::insert:
type = &sfCreatedNode;
break;
case Action::modify:
type = &sfModifiedNode;
break;
}
auto const origNode = to.read(keylet::unchecked(item.first));
auto curNode = item.second.second;
if ((type == &sfModifiedNode) && (*curNode == *origNode))
continue;
std::uint16_t nodeType = curNode
? curNode->getFieldU16(sfLedgerEntryType)
: origNode->getFieldU16(sfLedgerEntryType);
meta.setAffectedNode(item.first, *type, nodeType);
if (type == &sfDeletedNode)
{
assert(origNode && curNode);
threadOwners(to, meta, origNode, newMod, j);
STObject prevs(sfPreviousFields);
for (auto const& obj : *origNode)
{
// go through the original node for
// modified fields saved on modification
if (obj.getFName().shouldMeta(SField::sMD_ChangeOrig) &&
!curNode->hasMatchingEntry(obj))
prevs.emplace_back(obj);
}
if (!prevs.empty())
meta.getAffectedNode(item.first)
.emplace_back(std::move(prevs));
STObject finals(sfFinalFields);
for (auto const& obj : *curNode)
{
// go through the final node for final fields
if (obj.getFName().shouldMeta(
SField::sMD_Always | SField::sMD_DeleteFinal))
finals.emplace_back(obj);
}
if (!finals.empty())
meta.getAffectedNode(item.first)
.emplace_back(std::move(finals));
}
else if (type == &sfModifiedNode)
{
assert(curNode && origNode);
if (curNode->isThreadedType()) // thread transaction to node
// item modified
threadItem(meta, curNode);
STObject prevs(sfPreviousFields);
for (auto const& obj : *origNode)
{
// search the original node for values saved on modify
if (obj.getFName().shouldMeta(SField::sMD_ChangeOrig) &&
!curNode->hasMatchingEntry(obj))
prevs.emplace_back(obj);
}
if (!prevs.empty())
meta.getAffectedNode(item.first)
.emplace_back(std::move(prevs));
STObject finals(sfFinalFields);
for (auto const& obj : *curNode)
{
// search the final node for values saved always
if (obj.getFName().shouldMeta(
SField::sMD_Always | SField::sMD_ChangeNew))
finals.emplace_back(obj);
}
if (!finals.empty())
meta.getAffectedNode(item.first)
.emplace_back(std::move(finals));
}
else if (type == &sfCreatedNode) // if created, thread to owner(s)
{
assert(curNode && !origNode);
threadOwners(to, meta, curNode, newMod, j);
if (curNode->isThreadedType()) // always thread to self
threadItem(meta, curNode);
STObject news(sfNewFields);
for (auto const& obj : *curNode)
{
// save non-default values
if (!obj.isDefault() &&
obj.getFName().shouldMeta(
SField::sMD_Create | SField::sMD_Always))
news.emplace_back(obj);
}
if (!news.empty())
meta.getAffectedNode(item.first)
.emplace_back(std::move(news));
}
else
{
assert(false);
}
}
return {meta, newMod};
}
void
ApplyStateTable::apply(
OpenView& to,
@@ -124,133 +265,10 @@ ApplyStateTable::apply(
std::shared_ptr<Serializer> sMeta;
if (!to.open())
{
TxMeta meta(tx.getTransactionID(), to.seq());
if (deliver)
meta.setDeliveredAmount(*deliver);
if (!hookExecution.empty())
meta.setHookExecutions(STArray{hookExecution, sfHookExecutions});
Mods newMod;
for (auto& item : items_)
{
SField const* type;
switch (item.second.first)
{
default:
case Action::cache:
continue;
case Action::erase:
type = &sfDeletedNode;
break;
case Action::insert:
type = &sfCreatedNode;
break;
case Action::modify:
type = &sfModifiedNode;
break;
}
auto const origNode = to.read(keylet::unchecked(item.first));
auto curNode = item.second.second;
if ((type == &sfModifiedNode) && (*curNode == *origNode))
continue;
std::uint16_t nodeType = curNode
? curNode->getFieldU16(sfLedgerEntryType)
: origNode->getFieldU16(sfLedgerEntryType);
meta.setAffectedNode(item.first, *type, nodeType);
if (type == &sfDeletedNode)
{
assert(origNode && curNode);
threadOwners(to, meta, origNode, newMod, j);
STObject prevs(sfPreviousFields);
for (auto const& obj : *origNode)
{
// go through the original node for
// modified fields saved on modification
if (obj.getFName().shouldMeta(SField::sMD_ChangeOrig) &&
!curNode->hasMatchingEntry(obj))
prevs.emplace_back(obj);
}
if (!prevs.empty())
meta.getAffectedNode(item.first)
.emplace_back(std::move(prevs));
STObject finals(sfFinalFields);
for (auto const& obj : *curNode)
{
// go through the final node for final fields
if (obj.getFName().shouldMeta(
SField::sMD_Always | SField::sMD_DeleteFinal))
finals.emplace_back(obj);
}
if (!finals.empty())
meta.getAffectedNode(item.first)
.emplace_back(std::move(finals));
}
else if (type == &sfModifiedNode)
{
assert(curNode && origNode);
if (curNode->isThreadedType()) // thread transaction to node
// item modified
threadItem(meta, curNode);
STObject prevs(sfPreviousFields);
for (auto const& obj : *origNode)
{
// search the original node for values saved on modify
if (obj.getFName().shouldMeta(SField::sMD_ChangeOrig) &&
!curNode->hasMatchingEntry(obj))
prevs.emplace_back(obj);
}
if (!prevs.empty())
meta.getAffectedNode(item.first)
.emplace_back(std::move(prevs));
STObject finals(sfFinalFields);
for (auto const& obj : *curNode)
{
// search the final node for values saved always
if (obj.getFName().shouldMeta(
SField::sMD_Always | SField::sMD_ChangeNew))
finals.emplace_back(obj);
}
if (!finals.empty())
meta.getAffectedNode(item.first)
.emplace_back(std::move(finals));
}
else if (type == &sfCreatedNode) // if created, thread to owner(s)
{
assert(curNode && !origNode);
threadOwners(to, meta, curNode, newMod, j);
if (curNode->isThreadedType()) // always thread to self
threadItem(meta, curNode);
STObject news(sfNewFields);
for (auto const& obj : *curNode)
{
// save non-default values
if (!obj.isDefault() &&
obj.getFName().shouldMeta(
SField::sMD_Create | SField::sMD_Always))
news.emplace_back(obj);
}
if (!news.empty())
meta.getAffectedNode(item.first)
.emplace_back(std::move(news));
}
else
{
assert(false);
}
}
// generate meta
auto [meta, newMod] =
generateTxMeta(to, tx, deliver, hookExecution, j);
// add any new modified nodes to the modification set
for (auto& mod : newMod)