mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
hook Hook APIs
This commit is contained in:
@@ -46,7 +46,7 @@ public:
|
|||||||
|
|
||||||
/// etxn APIs
|
/// etxn APIs
|
||||||
Expected<std::shared_ptr<Transaction>, HookReturnCode>
|
Expected<std::shared_ptr<Transaction>, HookReturnCode>
|
||||||
emit(Slice txBlob);
|
emit(Slice txBlob) const;
|
||||||
|
|
||||||
Expected<uint64_t, HookReturnCode>
|
Expected<uint64_t, HookReturnCode>
|
||||||
etxn_burden() const;
|
etxn_burden() const;
|
||||||
@@ -139,13 +139,29 @@ public:
|
|||||||
otxn_param(Bytes param_name) const;
|
otxn_param(Bytes param_name) const;
|
||||||
|
|
||||||
/// hook APIs
|
/// hook APIs
|
||||||
// hook_account
|
AccountID
|
||||||
// hook_hash
|
hook_account() const;
|
||||||
// hook_again
|
|
||||||
// hook_param
|
Expected<ripple::uint256, HookReturnCode>
|
||||||
// hook_param_set
|
hook_hash(int32_t hook_no) const;
|
||||||
// hook_skip
|
|
||||||
// hook_pos
|
Expected<int64_t, HookReturnCode>
|
||||||
|
hook_again() const;
|
||||||
|
|
||||||
|
Expected<Blob, HookReturnCode>
|
||||||
|
hook_param(Bytes const& paramName) const;
|
||||||
|
|
||||||
|
Expected<uint64_t, HookReturnCode>
|
||||||
|
hook_param_set(
|
||||||
|
uint256 const& hash,
|
||||||
|
Bytes const& paramName,
|
||||||
|
Bytes const& paramValue) const;
|
||||||
|
|
||||||
|
Expected<uint64_t, HookReturnCode>
|
||||||
|
hook_skip(uint256 const& hash, uint32_t flags) const;
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
hook_pos() const;
|
||||||
|
|
||||||
/// ledger APIs
|
/// ledger APIs
|
||||||
// fee_base
|
// fee_base
|
||||||
|
|||||||
@@ -396,8 +396,178 @@ HookAPI::otxn_param(Bytes param_name) const
|
|||||||
return Unexpected(DOESNT_EXIST);
|
return Unexpected(DOESNT_EXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AccountID
|
||||||
|
HookAPI::hook_account() const
|
||||||
|
{
|
||||||
|
return hookCtx.result.account;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ripple::uint256, HookReturnCode>
|
||||||
|
HookAPI::hook_hash(int32_t hook_no) const
|
||||||
|
{
|
||||||
|
if (hook_no == -1)
|
||||||
|
return hookCtx.result.hookHash;
|
||||||
|
|
||||||
|
std::shared_ptr<SLE> hookSLE =
|
||||||
|
hookCtx.applyCtx.view().peek(hookCtx.result.hookKeylet);
|
||||||
|
if (!hookSLE || !hookSLE->isFieldPresent(sfHooks))
|
||||||
|
return Unexpected(INTERNAL_ERROR);
|
||||||
|
|
||||||
|
ripple::STArray const& hooks = hookSLE->getFieldArray(sfHooks);
|
||||||
|
if (hook_no >= hooks.size())
|
||||||
|
return Unexpected(DOESNT_EXIST);
|
||||||
|
|
||||||
|
auto const& hook = hooks[hook_no];
|
||||||
|
if (!hook.isFieldPresent(sfHookHash))
|
||||||
|
return Unexpected(DOESNT_EXIST);
|
||||||
|
|
||||||
|
return hook.getFieldH256(sfHookHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<int64_t, HookReturnCode>
|
||||||
|
HookAPI::hook_again() const
|
||||||
|
{
|
||||||
|
if (hookCtx.result.executeAgainAsWeak)
|
||||||
|
return ALREADY_SET;
|
||||||
|
|
||||||
|
if (hookCtx.result.isStrong)
|
||||||
|
{
|
||||||
|
hookCtx.result.executeAgainAsWeak = true;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PREREQUISITE_NOT_MET;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<Blob, HookReturnCode>
|
||||||
|
HookAPI::hook_param(Bytes const& paramName) const
|
||||||
|
{
|
||||||
|
if (paramName.size() < 1)
|
||||||
|
return Unexpected(TOO_SMALL);
|
||||||
|
|
||||||
|
if (paramName.size() > 32)
|
||||||
|
return Unexpected(TOO_BIG);
|
||||||
|
|
||||||
|
// first check for overrides set by prior hooks in the chain
|
||||||
|
auto const& overrides = hookCtx.result.hookParamOverrides;
|
||||||
|
if (overrides.find(hookCtx.result.hookHash) != overrides.end())
|
||||||
|
{
|
||||||
|
auto const& params = overrides.at(hookCtx.result.hookHash);
|
||||||
|
if (params.find(paramName) != params.end())
|
||||||
|
{
|
||||||
|
auto const& param = params.at(paramName);
|
||||||
|
if (param.size() == 0)
|
||||||
|
// allow overrides to "delete" parameters
|
||||||
|
return Unexpected(DOESNT_EXIST);
|
||||||
|
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// next check if there's a param set on this hook
|
||||||
|
auto const& params = hookCtx.result.hookParams;
|
||||||
|
if (params.find(paramName) != params.end())
|
||||||
|
{
|
||||||
|
auto const& param = params.at(paramName);
|
||||||
|
if (param.size() == 0)
|
||||||
|
return Unexpected(DOESNT_EXIST);
|
||||||
|
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Unexpected(DOESNT_EXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<uint64_t, HookReturnCode>
|
||||||
|
HookAPI::hook_param_set(
|
||||||
|
uint256 const& hash,
|
||||||
|
Bytes const& paramName,
|
||||||
|
Bytes const& paramValue) const
|
||||||
|
{
|
||||||
|
if (paramName.size() < 1)
|
||||||
|
return Unexpected(TOO_SMALL);
|
||||||
|
|
||||||
|
if (paramName.size() > hook::maxHookParameterKeySize())
|
||||||
|
return Unexpected(TOO_BIG);
|
||||||
|
|
||||||
|
if (paramValue.size() > hook::maxHookParameterValueSize())
|
||||||
|
return Unexpected(TOO_BIG);
|
||||||
|
|
||||||
|
if (hookCtx.result.overrideCount >= hook_api::max_params)
|
||||||
|
return Unexpected(TOO_MANY_PARAMS);
|
||||||
|
|
||||||
|
hookCtx.result.overrideCount++;
|
||||||
|
|
||||||
|
auto& overrides = hookCtx.result.hookParamOverrides;
|
||||||
|
if (overrides.find(hash) == overrides.end())
|
||||||
|
{
|
||||||
|
overrides[hash] = std::map<Bytes, Bytes>{
|
||||||
|
{std::move(paramName), std::move(paramValue)}};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
overrides[hash][std::move(paramName)] = std::move(paramValue);
|
||||||
|
|
||||||
|
return paramValue.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<uint64_t, HookReturnCode>
|
||||||
|
HookAPI::hook_skip(uint256 const& hash, uint32_t flags) const
|
||||||
|
{
|
||||||
|
if (flags != 0 && flags != 1)
|
||||||
|
return INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
auto& skips = hookCtx.result.hookSkips;
|
||||||
|
|
||||||
|
if (flags == 1)
|
||||||
|
{
|
||||||
|
// delete flag
|
||||||
|
if (skips.find(hash) == skips.end())
|
||||||
|
return Unexpected(DOESNT_EXIST);
|
||||||
|
skips.erase(hash);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// first check if it's already in the skips set
|
||||||
|
if (skips.find(hash) != skips.end())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// next check if it's even in this chain
|
||||||
|
std::shared_ptr<SLE> hookSLE =
|
||||||
|
hookCtx.applyCtx.view().peek(hookCtx.result.hookKeylet);
|
||||||
|
|
||||||
|
if (!hookSLE || !hookSLE->isFieldPresent(sfHooks))
|
||||||
|
return Unexpected(INTERNAL_ERROR);
|
||||||
|
|
||||||
|
ripple::STArray const& hooks = hookSLE->getFieldArray(sfHooks);
|
||||||
|
bool found = false;
|
||||||
|
for (auto const& hookObj : hooks)
|
||||||
|
{
|
||||||
|
if (hookObj.isFieldPresent(sfHookHash))
|
||||||
|
{
|
||||||
|
if (hookObj.getFieldH256(sfHookHash) == hash)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
return Unexpected(DOESNT_EXIST);
|
||||||
|
|
||||||
|
// finally add it to the skips list
|
||||||
|
hookCtx.result.hookSkips.emplace(hash);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
HookAPI::hook_pos() const
|
||||||
|
{
|
||||||
|
return hookCtx.result.hookChainPosition;
|
||||||
|
}
|
||||||
|
|
||||||
Expected<std::shared_ptr<Transaction>, HookReturnCode>
|
Expected<std::shared_ptr<Transaction>, HookReturnCode>
|
||||||
HookAPI::emit(Slice txBlob)
|
HookAPI::emit(Slice txBlob) const
|
||||||
{
|
{
|
||||||
auto& applyCtx = hookCtx.applyCtx;
|
auto& applyCtx = hookCtx.applyCtx;
|
||||||
auto j = applyCtx.app.journal("View");
|
auto j = applyCtx.app.journal("View");
|
||||||
|
|||||||
@@ -3256,31 +3256,11 @@ DEFINE_HOOK_FUNCTION(
|
|||||||
if (NOT_IN_BOUNDS(write_ptr, write_len, memory_length))
|
if (NOT_IN_BOUNDS(write_ptr, write_len, memory_length))
|
||||||
return OUT_OF_BOUNDS;
|
return OUT_OF_BOUNDS;
|
||||||
|
|
||||||
if (hook_no == -1)
|
hook::HookAPI api(hookCtx);
|
||||||
{
|
auto const result = api.hook_hash(hook_no);
|
||||||
WRITE_WASM_MEMORY_AND_RETURN(
|
if (!result)
|
||||||
write_ptr,
|
return result.error();
|
||||||
write_len,
|
auto const& hash = result.value();
|
||||||
hookCtx.result.hookHash.data(),
|
|
||||||
32,
|
|
||||||
memory,
|
|
||||||
memory_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SLE> hookSLE =
|
|
||||||
applyCtx.view().peek(hookCtx.result.hookKeylet);
|
|
||||||
if (!hookSLE || !hookSLE->isFieldPresent(sfHooks))
|
|
||||||
return INTERNAL_ERROR;
|
|
||||||
|
|
||||||
ripple::STArray const& hooks = hookSLE->getFieldArray(sfHooks);
|
|
||||||
if (hook_no >= hooks.size())
|
|
||||||
return DOESNT_EXIST;
|
|
||||||
|
|
||||||
auto const& hook = hooks[hook_no];
|
|
||||||
if (!hook.isFieldPresent(sfHookHash))
|
|
||||||
return DOESNT_EXIST;
|
|
||||||
|
|
||||||
ripple::uint256 const& hash = hook.getFieldH256(sfHookHash);
|
|
||||||
|
|
||||||
WRITE_WASM_MEMORY_AND_RETURN(
|
WRITE_WASM_MEMORY_AND_RETURN(
|
||||||
write_ptr, write_len, hash.data(), hash.size(), memory, memory_length);
|
write_ptr, write_len, hash.data(), hash.size(), memory, memory_length);
|
||||||
@@ -3304,13 +3284,11 @@ DEFINE_HOOK_FUNCTION(
|
|||||||
if (ptr_len < 20)
|
if (ptr_len < 20)
|
||||||
return TOO_SMALL;
|
return TOO_SMALL;
|
||||||
|
|
||||||
|
hook::HookAPI api(hookCtx);
|
||||||
|
auto const result = api.hook_account();
|
||||||
|
|
||||||
WRITE_WASM_MEMORY_AND_RETURN(
|
WRITE_WASM_MEMORY_AND_RETURN(
|
||||||
write_ptr,
|
write_ptr, 20, result.data(), 20, memory, memory_length);
|
||||||
20,
|
|
||||||
hookCtx.result.account.data(),
|
|
||||||
20,
|
|
||||||
memory,
|
|
||||||
memory_length);
|
|
||||||
|
|
||||||
HOOK_TEARDOWN();
|
HOOK_TEARDOWN();
|
||||||
}
|
}
|
||||||
@@ -4970,54 +4948,18 @@ DEFINE_HOOK_FUNCTION(
|
|||||||
if (NOT_IN_BOUNDS(write_ptr, write_len, memory_length))
|
if (NOT_IN_BOUNDS(write_ptr, write_len, memory_length))
|
||||||
return OUT_OF_BOUNDS;
|
return OUT_OF_BOUNDS;
|
||||||
|
|
||||||
if (read_len < 1)
|
Bytes paramName{read_ptr + memory, read_ptr + read_len + memory};
|
||||||
return TOO_SMALL;
|
|
||||||
|
|
||||||
if (read_len > 32)
|
hook::HookAPI api(hookCtx);
|
||||||
return TOO_BIG;
|
auto const result = api.hook_param(paramName);
|
||||||
|
|
||||||
std::vector<uint8_t> paramName{
|
if (!result)
|
||||||
read_ptr + memory, read_ptr + read_len + memory};
|
return result.error();
|
||||||
|
|
||||||
// first check for overrides set by prior hooks in the chain
|
auto const& val = result.value();
|
||||||
auto const& overrides = hookCtx.result.hookParamOverrides;
|
|
||||||
if (overrides.find(hookCtx.result.hookHash) != overrides.end())
|
|
||||||
{
|
|
||||||
auto const& params = overrides.at(hookCtx.result.hookHash);
|
|
||||||
if (params.find(paramName) != params.end())
|
|
||||||
{
|
|
||||||
auto const& param = params.at(paramName);
|
|
||||||
if (param.size() == 0)
|
|
||||||
return DOESNT_EXIST; // allow overrides to "delete" parameters
|
|
||||||
|
|
||||||
WRITE_WASM_MEMORY_AND_RETURN(
|
WRITE_WASM_MEMORY_AND_RETURN(
|
||||||
write_ptr,
|
write_ptr, write_len, val.data(), val.size(), memory, memory_length);
|
||||||
write_len,
|
|
||||||
param.data(),
|
|
||||||
param.size(),
|
|
||||||
memory,
|
|
||||||
memory_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// next check if there's a param set on this hook
|
|
||||||
auto const& params = hookCtx.result.hookParams;
|
|
||||||
if (params.find(paramName) != params.end())
|
|
||||||
{
|
|
||||||
auto const& param = params.at(paramName);
|
|
||||||
if (param.size() == 0)
|
|
||||||
return DOESNT_EXIST;
|
|
||||||
|
|
||||||
WRITE_WASM_MEMORY_AND_RETURN(
|
|
||||||
write_ptr,
|
|
||||||
write_len,
|
|
||||||
param.data(),
|
|
||||||
param.size(),
|
|
||||||
memory,
|
|
||||||
memory_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return DOESNT_EXIST;
|
|
||||||
|
|
||||||
HOOK_TEARDOWN();
|
HOOK_TEARDOWN();
|
||||||
}
|
}
|
||||||
@@ -5040,6 +4982,9 @@ DEFINE_HOOK_FUNCTION(
|
|||||||
NOT_IN_BOUNDS(hread_ptr, hread_len, memory_length))
|
NOT_IN_BOUNDS(hread_ptr, hread_len, memory_length))
|
||||||
return OUT_OF_BOUNDS;
|
return OUT_OF_BOUNDS;
|
||||||
|
|
||||||
|
{
|
||||||
|
// those checks are also done in the HookAPI
|
||||||
|
// but we need to check them here too for backwards compatibility
|
||||||
if (kread_len < 1)
|
if (kread_len < 1)
|
||||||
return TOO_SMALL;
|
return TOO_SMALL;
|
||||||
|
|
||||||
@@ -5051,29 +4996,17 @@ DEFINE_HOOK_FUNCTION(
|
|||||||
|
|
||||||
if (read_len > hook::maxHookParameterValueSize())
|
if (read_len > hook::maxHookParameterValueSize())
|
||||||
return TOO_BIG;
|
return TOO_BIG;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> paramName{
|
Bytes paramName{kread_ptr + memory, kread_ptr + kread_len + memory};
|
||||||
kread_ptr + memory, kread_ptr + kread_len + memory};
|
Bytes paramValue{read_ptr + memory, read_ptr + read_len + memory};
|
||||||
std::vector<uint8_t> paramValue{
|
|
||||||
read_ptr + memory, read_ptr + read_len + memory};
|
|
||||||
|
|
||||||
ripple::uint256 hash = ripple::uint256::fromVoid(memory + hread_ptr);
|
ripple::uint256 hash = ripple::uint256::fromVoid(memory + hread_ptr);
|
||||||
|
|
||||||
if (hookCtx.result.overrideCount >= hook_api::max_params)
|
hook::HookAPI api(hookCtx);
|
||||||
return TOO_MANY_PARAMS;
|
auto const result = api.hook_param_set(hash, paramName, paramValue);
|
||||||
|
if (!result)
|
||||||
hookCtx.result.overrideCount++;
|
return result.error();
|
||||||
|
return result.value();
|
||||||
auto& overrides = hookCtx.result.hookParamOverrides;
|
|
||||||
if (overrides.find(hash) == overrides.end())
|
|
||||||
{
|
|
||||||
overrides[hash] = std::map<std::vector<uint8_t>, std::vector<uint8_t>>{
|
|
||||||
{std::move(paramName), std::move(paramValue)}};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
overrides[hash][std::move(paramName)] = std::move(paramValue);
|
|
||||||
|
|
||||||
return read_len;
|
|
||||||
|
|
||||||
HOOK_TEARDOWN();
|
HOOK_TEARDOWN();
|
||||||
}
|
}
|
||||||
@@ -5094,75 +5027,34 @@ DEFINE_HOOK_FUNCTION(
|
|||||||
if (read_len != 32)
|
if (read_len != 32)
|
||||||
return INVALID_ARGUMENT;
|
return INVALID_ARGUMENT;
|
||||||
|
|
||||||
if (flags != 0 && flags != 1)
|
|
||||||
return INVALID_ARGUMENT;
|
|
||||||
|
|
||||||
auto& skips = hookCtx.result.hookSkips;
|
|
||||||
ripple::uint256 hash = ripple::uint256::fromVoid(memory + read_ptr);
|
ripple::uint256 hash = ripple::uint256::fromVoid(memory + read_ptr);
|
||||||
|
|
||||||
if (flags == 1)
|
hook::HookAPI api(hookCtx);
|
||||||
{
|
auto const result = api.hook_skip(hash, flags);
|
||||||
// delete flag
|
if (!result)
|
||||||
if (skips.find(hash) == skips.end())
|
return result.error();
|
||||||
return DOESNT_EXIST;
|
return result.value();
|
||||||
skips.erase(hash);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// first check if it's already in the skips set
|
|
||||||
if (skips.find(hash) != skips.end())
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
// next check if it's even in this chain
|
|
||||||
std::shared_ptr<SLE> hookSLE =
|
|
||||||
applyCtx.view().peek(hookCtx.result.hookKeylet);
|
|
||||||
|
|
||||||
if (!hookSLE || !hookSLE->isFieldPresent(sfHooks))
|
|
||||||
return INTERNAL_ERROR;
|
|
||||||
|
|
||||||
ripple::STArray const& hooks = hookSLE->getFieldArray(sfHooks);
|
|
||||||
bool found = false;
|
|
||||||
for (auto const& hookObj : hooks)
|
|
||||||
{
|
|
||||||
if (hookObj.isFieldPresent(sfHookHash))
|
|
||||||
{
|
|
||||||
if (hookObj.getFieldH256(sfHookHash) == hash)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
return DOESNT_EXIST;
|
|
||||||
|
|
||||||
// finally add it to the skips list
|
|
||||||
hookCtx.result.hookSkips.emplace(hash);
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
HOOK_TEARDOWN();
|
HOOK_TEARDOWN();
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_HOOK_FUNCNARG(int64_t, hook_pos)
|
DEFINE_HOOK_FUNCNARG(int64_t, hook_pos)
|
||||||
{
|
{
|
||||||
return hookCtx.result.hookChainPosition;
|
hook::HookAPI api(hookCtx);
|
||||||
|
return api.hook_pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_HOOK_FUNCNARG(int64_t, hook_again)
|
DEFINE_HOOK_FUNCNARG(int64_t, hook_again)
|
||||||
{
|
{
|
||||||
HOOK_SETUP();
|
HOOK_SETUP();
|
||||||
|
|
||||||
if (hookCtx.result.executeAgainAsWeak)
|
hook::HookAPI api(hookCtx);
|
||||||
return ALREADY_SET;
|
auto const result = api.hook_again();
|
||||||
|
|
||||||
if (hookCtx.result.isStrong)
|
if (!result)
|
||||||
{
|
return result.error();
|
||||||
hookCtx.result.executeAgainAsWeak = true;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return PREREQUISITE_NOT_MET;
|
return result.value();
|
||||||
|
|
||||||
HOOK_TEARDOWN();
|
HOOK_TEARDOWN();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user