more unit tests for hooks, still wip

This commit is contained in:
Richard Holland
2022-10-13 12:37:47 +00:00
parent 09a4087256
commit 223606aacb
8 changed files with 458 additions and 167 deletions

View File

@@ -92,7 +92,7 @@ namespace hook_api
(((TERtoInt(x)) << 16)*-1)
// for debugging if you want a lot of output change these to if (1)
#define HOOK_DBG 1
#define HOOK_DBG 0
#define DBG_PRINTF if (HOOK_DBG) printf
#define DBG_FPRINTF if (HOOK_DBG) fprintf

View File

@@ -388,7 +388,7 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj)
return false;
}
// validate api version, if provided
// ensure api version is provided
if (!hookSetObj.isFieldPresent(sfHookApiVersion))
{
JLOG(ctx.j.trace())
@@ -1093,7 +1093,6 @@ SetHook::setHook()
if (hookSetObj)
op = inferOperation(hookSetObj->get());
// these flags are not able to be passed onto the ledger object
int newFlags = 0;
if (flags)
@@ -1106,15 +1105,6 @@ SetHook::setHook()
newFlags -= hsfNSDELETE;
}
printf("HookSet operation %d: %s\n", hookSetNumber,
(op == hsoNSDELETE ? "hsoNSDELETE" :
(op == hsoDELETE ? "hsoDELETE" :
(op == hsoCREATE ? "hsoCREATE" :
(op == hsoINSTALL ? "hsoINSTALL" :
(op == hsoUPDATE ? "hsoUPDATE" :
(op == hsoNOOP ? "hsoNOOP" : "hsoINALID")))))));
// if an existing hook exists at this position in the chain then extract the relevant fields
if (oldHook && oldHook->get().isFieldPresent(sfHookHash))
{

View File

@@ -341,9 +341,9 @@ TERtoInt(TECcodes v)
template <template <typename> class Trait>
class TERSubset
{
public:
TERUnderlyingType code_;
public:
// Constructors
constexpr TERSubset() : code_(tesSUCCESS)
{

View File

@@ -177,6 +177,7 @@ transResults()
MAKE_ERROR(terOWNERS, "Non-zero owner count."),
MAKE_ERROR(terQUEUED, "Held until escalated fee drops."),
MAKE_ERROR(terPRE_TICKET, "Ticket is not yet in ledger."),
MAKE_ERROR(terNO_HOOK, "No hook with that hash exists on the ledger."),
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
};

View File

@@ -56,8 +56,6 @@ class SetHook_test : public beast::unit_test::suite
{
public:
// This is a large fee, large enough that we can set most small test hooks without running into fee issues
// we only want to test fee code specifically in fee unit tests, the rest of the time we want to ignore it.
#define HSFEE fee(1'000'000)
@@ -78,7 +76,7 @@ public:
}
void
testMalformedTxStructure()
testTxStructure()
{
testcase("Checks malformed transactions");
using namespace jtx;
@@ -90,12 +88,12 @@ public:
// Test outer structure
env(ripple::test::jtx::hook(alice, {}, 0),
env(ripple::test::jtx::hook(alice, {}, 0),
M("Must have a hooks field"),
HSFEE, ter(temMALFORMED));
env(ripple::test::jtx::hook(alice, {{}}, 0),
env(ripple::test::jtx::hook(alice, {{}}, 0),
M("Must have a non-empty hooks field"),
HSFEE, ter(temMALFORMED));
@@ -104,7 +102,7 @@ public:
hso(accept_wasm),
hso(accept_wasm),
hso(accept_wasm),
hso(accept_wasm)}}, 0),
hso(accept_wasm)}}, 0),
M("Must have fewer than 5 entries"),
HSFEE, ter(temMALFORMED));
@@ -121,119 +119,16 @@ public:
iv[jss::MemoType] = "";
jv[jss::Hooks][0U][jss::Memo] = iv;
env(jv,
M("Hooks Array must contain Hook objects"),
HSFEE, ter(temMALFORMED));
env.close();
}
{
Json::Value jv =
ripple::test::jtx::hook(alice, {{hso(accept_wasm)}}, 0);
Json::Value iv = jv[jss::Hooks][0U];
iv[jss::Hook][jss::HookHash] = to_string(uint256{beast::zero});
jv[jss::Hooks][0U] = iv;
env(jv,
M("Cannot have both CreateCode and HookHash"),
M("Hooks Array must contain Hook objects"),
HSFEE, ter(temMALFORMED));
env.close();
}
env(ripple::test::jtx::hook(alice, {{hso(long_wasm)}}, 0),
M("If CreateCode is present, then it must be less than 64kib"),
HSFEE, ter(temMALFORMED));
env.close();
}
void testMalformedDelete()
{
testcase("Checks malformed delete operation");
using namespace jtx;
Env env{*this, supported_amendments()};
auto const alice = Account{"alice"};
env.fund(XRP(10000), alice);
Json::Value jv;
jv[jss::Account] = alice.human();
jv[jss::TransactionType] = jss::SetHook;
jv[jss::Flags] = 0;
jv[jss::Hooks] = Json::Value{Json::arrayValue};
// flag required
{
Json::Value iv;
iv[jss::CreateCode] = "";
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook DELETE operation must include hsfOVERRIDE flag"),
HSFEE, ter(temMALFORMED));
env.close();
}
// invalid flags
{
Json::Value iv;
iv[jss::CreateCode] = "";
iv[jss::Flags] = "2147483648";
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook DELETE operation must include hsfOVERRIDE flag"),
HSFEE, ter(temMALFORMED));
env.close();
}
// grants, parameters, hookon, hookapiversion, hooknamespace keys must be absent
for (auto const& [key, value]:
JSSMap {
{jss::HookGrants, Json::arrayValue},
{jss::HookParameters, Json::arrayValue},
{jss::HookOn, "0"},
{jss::HookApiVersion, "0"},
{jss::HookNamespace, to_string(uint256{beast::zero})}
})
{
Json::Value iv;
iv[jss::CreateCode] = "";
iv[key] = value;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook DELETE operation cannot include: grants, params, hookon, apiversion, namespace"),
HSFEE, ter(temMALFORMED));
env.close();
}
}
void testMalformedInstall()
{
testcase("Checks malformed install operation");
using namespace jtx;
Env env{*this, supported_amendments()};
auto const alice = Account{"alice"};
env.fund(XRP(10000), alice);
Json::Value jv;
jv[jss::Account] = alice.human();
jv[jss::TransactionType] = jss::SetHook;
jv[jss::Flags] = 0;
jv[jss::Hooks] = Json::Value{Json::arrayValue};
// trying to set api version
{
Json::Value iv;
iv[jss::HookHash] = to_string(uint256{beast::zero});
iv[jss::HookApiVersion] = 1U;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook Install operation cannot set apiversion"),
HSFEE, ter(temMALFORMED));
env.close();
}
}
void testMalformedGrants()
void testGrants()
{
testcase("Checks malformed grants on install operation");
using namespace jtx;
@@ -256,10 +151,10 @@ public:
iv[jss::HookGrants] = Json::Value{Json::arrayValue};
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO must include at least one entry in HookGrants when field is present"),
M("HSO must include at least one entry in HookGrants when field is present"),
HSFEE, ter(temMALFORMED));
env.close();
}
}
// check too many grants
{
@@ -277,10 +172,10 @@ public:
iv[jss::HookGrants] = grants;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO must not include more than 8 grants"),
M("HSO must not include more than 8 grants"),
HSFEE, ter(temMALFORMED));
env.close();
}
}
// check wrong inner type
{
@@ -294,14 +189,13 @@ public:
iv[jss::HookGrants] = grants;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO grant array can only contain HookGrant objects"),
M("HSO grant array can only contain HookGrant objects"),
HSFEE, ter(temMALFORMED));
env.close();
}
}
void testMalformedParams()
void testParams()
{
testcase("Checks malformed params on install operation");
using namespace jtx;
@@ -326,17 +220,17 @@ public:
Json::Value pv;
Json::Value piv;
piv[jss::HookParameterName] = strHex("param" + std::to_string(i));
piv[jss::HookParameterValue] = strHex("value" + std::to_string(i));
piv[jss::HookParameterValue] = strHex("value" + std::to_string(i));
pv[jss::HookParameter] = piv;
params[i] = pv;
}
iv[jss::HookParameters] = params;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO must not include more than 16 parameters"),
M("HSO must not include more than 16 parameters"),
HSFEE, ter(temMALFORMED));
env.close();
}
}
// check repeat parameters
{
@@ -352,10 +246,10 @@ public:
iv[jss::HookParameters] = params;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO must not repeat parameter names"),
M("HSO must not repeat parameter names"),
HSFEE, ter(temMALFORMED));
env.close();
}
}
// check too long parameter name
{
@@ -368,12 +262,12 @@ public:
iv[jss::HookParameters] = params;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO must must not contain parameter names longer than 32 bytes"),
M("HSO must must not contain parameter names longer than 32 bytes"),
HSFEE, ter(temMALFORMED));
env.close();
}
// check too long parameter value
// check too long parameter value
{
Json::Value iv;
iv[jss::HookHash] = to_string(uint256{beast::zero});
@@ -385,7 +279,7 @@ public:
iv[jss::HookParameters] = params;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO must must not contain parameter values longer than 128 bytes"),
M("HSO must must not contain parameter values longer than 128 bytes"),
HSFEE, ter(temMALFORMED));
env.close();
}
@@ -402,16 +296,110 @@ public:
iv[jss::HookParameters] = params;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO parameter array can only contain HookParameter objects"),
M("HSO parameter array can only contain HookParameter objects"),
HSFEE, ter(temMALFORMED));
env.close();
}
}
void testMalformedCreate()
void testInstall()
{
testcase("Checks malformed create operation");
testcase("Checks malformed install operation");
using namespace jtx;
Env env{*this, supported_amendments()};
auto const alice = Account{"alice"};
env.fund(XRP(10000), alice);
auto const bob = Account{"bob"};
env.fund(XRP(10000), bob);
// create a hook that we can then install
{
env(ripple::test::jtx::hook(bob, {{
hso(accept_wasm),
hso(rollback_wasm)
}}, 0),
M("First set = tesSUCCESS"),
HSFEE, ter(tesSUCCESS));
}
std::string accept_hash = to_string(ripple::sha512Half_s(
ripple::Slice(accept_wasm.data(), accept_wasm.size())
));
std::string rollback_hash = to_string(ripple::sha512Half_s(
ripple::Slice(accept_wasm.data(), accept_wasm.size())
));
Json::Value jv;
jv[jss::Account] = alice.human();
jv[jss::TransactionType] = jss::SetHook;
jv[jss::Flags] = 0;
jv[jss::Hooks] = Json::Value{Json::arrayValue};
// can't set api version
{
Json::Value iv;
iv[jss::HookHash] = accept_hash;
iv[jss::HookApiVersion] = 1U;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook Install operation cannot set apiversion"),
HSFEE, ter(temMALFORMED));
env.close();
}
// can't set non-existent hook
{
Json::Value iv;
iv[jss::HookHash] = "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF";
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook Install operation cannot set non existent hook hash"),
HSFEE, ter(terNO_HOOK));
env.close();
}
// can set extant hook
{
Json::Value iv;
iv[jss::HookHash] = accept_hash;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook Install operation can set extant hook hash"),
HSFEE, ter(tesSUCCESS));
env.close();
}
// can't set extant hook over other hook without override flag
{
Json::Value iv;
iv[jss::HookHash] = rollback_hash;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook Install operation can set extant hook hash"),
HSFEE, ter(tecREQUIRES_FLAG));
env.close();
}
// can set extant hook over other hook with override flag
{
Json::Value iv;
iv[jss::HookHash] = rollback_hash;
iv[jss::Flags] = hsfOVERRIDE;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook Install operation can set extant hook hash"),
HSFEE, ter(tesSUCCESS));
env.close();
}
}
void testDelete()
{
testcase("Checks malformed delete operation");
using namespace jtx;
Env env{*this, supported_amendments()};
@@ -423,18 +411,304 @@ public:
jv[jss::TransactionType] = jss::SetHook;
jv[jss::Flags] = 0;
jv[jss::Hooks] = Json::Value{Json::arrayValue};
// RH UPTO
// flag required
{
Json::Value iv;
iv[jss::CreateCode] = "";
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook DELETE operation must include hsfOVERRIDE flag"),
HSFEE, ter(temMALFORMED));
env.close();
}
// invalid flags
{
Json::Value iv;
iv[jss::CreateCode] = "";
iv[jss::Flags] = "2147483648";
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook DELETE operation must include hsfOVERRIDE flag"),
HSFEE, ter(temMALFORMED));
env.close();
}
// grants, parameters, hookon, hookapiversion, hooknamespace keys must be absent
for (auto const& [key, value]:
JSSMap {
{jss::HookGrants, Json::arrayValue},
{jss::HookParameters, Json::arrayValue},
{jss::HookOn, "0"},
{jss::HookApiVersion, "0"},
{jss::HookNamespace, to_string(uint256{beast::zero})}
})
{
Json::Value iv;
iv[jss::CreateCode] = "";
iv[key] = value;
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook DELETE operation cannot include: grants, params, hookon, apiversion, namespace"),
HSFEE, ter(temMALFORMED));
env.close();
}
}
void testMalformedUpdate()
void testNSDelete()
{
testcase("Checks malformed nsdelete operation");
using namespace jtx;
Env env{*this, supported_amendments()};
auto const alice = Account{"alice"};
env.fund(XRP(10000), alice);
auto const bob = Account{"bob"};
env.fund(XRP(10000), bob);
Json::Value jv;
jv[jss::Account] = alice.human();
jv[jss::TransactionType] = jss::SetHook;
jv[jss::Flags] = 0;
jv[jss::Hooks] = Json::Value{Json::arrayValue};
for (auto const& [key, value]:
JSSMap {
{jss::HookGrants, Json::arrayValue},
{jss::HookParameters, Json::arrayValue},
{jss::HookOn, "0"},
{jss::HookApiVersion, "0"},
})
{
Json::Value iv;
iv[key] = value;
iv[jss::Flags] = hsfNSDELETE;
iv[jss::HookNamespace] = to_string(uint256{beast::zero});
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Hook NSDELETE operation cannot include: grants, params, hookon, apiversion"),
HSFEE, ter(temMALFORMED));
env.close();
}
// create a namespace
std::string ns = "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFE";
{
// create hook
Json::Value jv =
ripple::test::jtx::hook(alice, {{hso(makestate_wasm)}}, 0);
jv[jss::Hooks][0U][jss::Hook][jss::HookNamespace] = ns;
env(jv, M("Create makestate hook"), HSFEE, ter(tesSUCCESS));
// run hook
env(pay(bob, alice, XRP(1)),
M("Run create state hook"),
fee(XRP(1)));
env.close();
}
// RH UPTO
// delete the namespace
}
void testCreate()
{
testcase("Checks malformed create operation");
using namespace jtx;
Env env{*this, supported_amendments()};
auto const bob = Account{"bob"};
env.fund(XRP(10000), bob);
auto const alice = Account{"alice"};
env.fund(XRP(10000), alice);
// test normal create and missing override flag
{
env(ripple::test::jtx::hook(bob, {{hso(accept_wasm)}}, 0),
M("First set = tesSUCCESS"),
HSFEE, ter(tesSUCCESS));
env(ripple::test::jtx::hook(bob, {{hso(accept_wasm)}}, 0),
M("Second set = tecREQUIRES_FLAG"),
HSFEE, ter(tecREQUIRES_FLAG));
env.close();
}
Json::Value jv;
jv[jss::Account] = alice.human();
jv[jss::TransactionType] = jss::SetHook;
jv[jss::Flags] = 0;
jv[jss::Hooks] = Json::Value{Json::arrayValue};
// payload too large
{
env(ripple::test::jtx::hook(alice, {{hso(long_wasm)}}, 0),
M("If CreateCode is present, then it must be less than 64kib"),
HSFEE, ter(temMALFORMED));
env.close();
}
// namespace missing
{
Json::Value iv;
iv[jss::CreateCode] = strHex(accept_wasm);
iv[jss::HookApiVersion] = 0U;
iv[jss::HookOn] = uint64_hex(0);
jv[jss::Hooks][0U] = Json::Value{};
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO Create operation must contain namespace"),
HSFEE, ter(temMALFORMED));
env.close();
}
// api version missing
{
Json::Value iv;
iv[jss::CreateCode] = strHex(accept_wasm);
iv[jss::HookNamespace] = to_string(uint256{beast::zero});
iv[jss::HookOn] = uint64_hex(0);
jv[jss::Hooks][0U] = Json::Value{};
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO Create operation must contain api version"),
HSFEE, ter(temMALFORMED));
env.close();
}
// api version wrong
{
Json::Value iv;
iv[jss::CreateCode] = strHex(accept_wasm);
iv[jss::HookNamespace] = to_string(uint256{beast::zero});
iv[jss::HookApiVersion] = 1U;
iv[jss::HookOn] = uint64_hex(0);
jv[jss::Hooks][0U] = Json::Value{};
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO Create operation must contain valid api version"),
HSFEE, ter(temMALFORMED));
env.close();
}
// hookon missing
{
Json::Value iv;
iv[jss::CreateCode] = strHex(accept_wasm);
iv[jss::HookNamespace] = to_string(uint256{beast::zero});
iv[jss::HookApiVersion] = 0U;
jv[jss::Hooks][0U] = Json::Value{};
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("HSO Create operation must contain hookon"),
HSFEE, ter(temMALFORMED));
env.close();
}
// hook hash present
{
Json::Value jv =
ripple::test::jtx::hook(alice, {{hso(accept_wasm)}}, 0);
Json::Value iv = jv[jss::Hooks][0U];
iv[jss::Hook][jss::HookHash] = to_string(uint256{beast::zero});
jv[jss::Hooks][0U] = iv;
env(jv,
M("Cannot have both CreateCode and HookHash"),
HSFEE, ter(temMALFORMED));
env.close();
}
}
void testUpdate()
{
testcase("Checks malformed update operation");
using namespace jtx;
Env env{*this, supported_amendments()};
auto const alice = Account{"alice"};
env.fund(XRP(10000), alice);
Json::Value jv;
jv[jss::Account] = alice.human();
jv[jss::TransactionType] = jss::SetHook;
jv[jss::Flags] = 0;
jv[jss::Hooks] = Json::Value{Json::arrayValue};
// first create the hook
{
Json::Value iv;
iv[jss::CreateCode] = strHex(accept_wasm);
iv[jss::HookNamespace] = to_string(uint256{beast::zero});
iv[jss::HookApiVersion] = 0U;
iv[jss::HookOn] = uint64_hex(0);
jv[jss::Hooks][0U] = Json::Value{};
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Create accept"),
HSFEE, ter(tesSUCCESS));
env.close();
}
// all alice operations below are then updates
// must not specify override flag
{
Json::Value iv;
iv[jss::Flags] = hsfOVERRIDE;
jv[jss::Hooks][0U] = Json::Value{};
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("Override flag not allowed on update"),
HSFEE, ter(temMALFORMED));
env.close();
}
// must not specify NSDELETE unless also Namespace
{
Json::Value iv;
iv[jss::Flags] = hsfNSDELETE;
jv[jss::Hooks][0U] = Json::Value{};
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("NSDELETE flag not allowed on update unless HookNamespace also present"),
HSFEE, ter(temMALFORMED));
env.close();
}
// api version not allowed in update
{
Json::Value iv;
iv[jss::HookApiVersion] = 0U;
jv[jss::Hooks][0U] = Json::Value{};
jv[jss::Hooks][0U][jss::Hook] = iv;
env(jv,
M("ApiVersion not allowed in update"),
HSFEE, ter(temMALFORMED));
env.close();
}
}
void testInferHookSetOperation()
{
testcase("Test operation inference");
// hsoNOOP
{
STObject hso{sfHook};
@@ -474,10 +748,10 @@ public:
// hsoUPDATE
{
STObject hso{sfHook};
hso.setFieldU64(sfHookOn, 1LLU);
hso.setFieldU64(sfHookOn, 1LLU);
BEAST_EXPECT(SetHook::inferOperation(hso) == hsoUPDATE);
}
//hsoINVALID
{
STObject hso{sfHook};
@@ -488,7 +762,7 @@ public:
}
void
testMalformedWasm()
testWasm()
{
testcase("Checks malformed hook binaries");
using namespace jtx;
@@ -496,7 +770,7 @@ public:
auto const alice = Account{"alice"};
env.fund(XRP(10000), alice);
env(ripple::test::jtx::hook(alice, {{hso(noguard_wasm)}}, 0),
M("Must import guard"),
HSFEE, ter(temMALFORMED));
@@ -518,7 +792,7 @@ public:
env.fund(XRP(10000), alice);
env.fund(XRP(10000), bob);
env(ripple::test::jtx::hook(alice, {{hso(accept_wasm)}}, 0),
env(ripple::test::jtx::hook(alice, {{hso(accept_wasm)}}, 0),
M("Install Accept Hook"),
HSFEE);
env.close();
@@ -529,7 +803,7 @@ public:
env.close();
}
void
testRollback()
{
@@ -558,14 +832,20 @@ public:
{
//testTicketSetHook(); // RH TODO
testHooksDisabled();
testMalformedTxStructure();
testTxStructure();
testInferHookSetOperation();
testMalformedDelete();
testMalformedInstall();
testMalformedParams();
testMalformedGrants();
testParams();
testGrants();
testMalformedWasm();
testDelete();
testInstall();
testCreate();
testUpdate();
testNSDelete();
testWasm();
testAccept();
testRollback();
}
@@ -586,7 +866,7 @@ private:
}
)[test.hook]"
];
TestHook
rollback_wasm = // WASM: 1
wasm[
@@ -602,7 +882,7 @@ private:
}
)[test.hook]"
];
TestHook
noguard_wasm = // WASM: 2
wasm[
@@ -668,8 +948,8 @@ private:
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
#define SBUF(x) (uint32_t)(x), sizeof(x)
#define M_REPEAT_10(X) X X X X X X X X X X
#define M_REPEAT_100(X) M_REPEAT_10(M_REPEAT_10(X))
#define M_REPEAT_1000(X) M_REPEAT_100(M_REPEAT_10(X))
#define M_REPEAT_100(X) M_REPEAT_10(M_REPEAT_10(X))
#define M_REPEAT_1000(X) M_REPEAT_100(M_REPEAT_10(X))
int64_t hook(uint32_t reserved )
{
_g(1,1);
@@ -679,6 +959,24 @@ private:
)[test.hook]"
];
TestHook
makestate_wasm = // WASM: 5
wasm[
R"[test.hook](
#include <stdint.h>
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t state_set (uint32_t read_ptr, uint32_t read_len, uint32_t kread_ptr, uint32_t kread_len);
#define SBUF(x) x, sizeof(x)
int64_t hook(uint32_t reserved )
{
_g(1,1);
uint8_t test_key[] = "key";
uint8_t test_value[] = "value";
return accept(0,0, state_set(SBUF(test_value), SBUF(test_key)));
}
)[test.hook]"
];
};
BEAST_DEFINE_TESTSUITE(SetHook, tx, ripple);
@@ -687,7 +985,7 @@ BEAST_DEFINE_TESTSUITE(SetHook, tx, ripple);
/*
Json::Value jv;
jv[jss::Account] = alice.human();
jv[jss::TransactionType] = jss::SetHook;
jv[jss::Flags] = 0;
@@ -695,12 +993,12 @@ BEAST_DEFINE_TESTSUITE(SetHook, tx, ripple);
Json::Value{Json::arrayValue};
Json::Value iv;
iv[jss::CreateCode] = std::string(65536, 'F');
iv[jss::HookOn] = "0000000000000000";
iv[jss::HookNamespace] = to_string(uint256{beast::zero});
iv[jss::HookApiVersion] = Json::Value{0};
jv[jss::Hooks][i][jss::Hook] = iv;
env(jv, ter(temMALFORMED));
*/

View File

@@ -34,6 +34,8 @@ hook(Account const& account, std::optional<std::vector<Json::Value>> hooks, std:
Json::Value
hso(std::vector<uint8_t> const& wasmBytes, uint64_t hookOn = 0, uint256 ns = beast::zero, uint8_t apiversion = 0);
std::string uint64_hex(uint64_t x);
} // namespace jtx
} // namespace test
} // namespace ripple

View File

@@ -349,7 +349,7 @@ Env::postconditions(JTx const& jt, TER ter, bool didApply)
!test.expect(
ter == *jt.ter,
"apply: Got " + transToken(ter) + " (" + transHuman(ter) +
"); Expected " + transToken(*jt.ter) + " (" +
") [=" + std::to_string(ter.code_) + "]; Expected " + transToken(*jt.ter) + " (" +
transHuman(*jt.ter) + ")"))
{
test.log << pretty(jt.jv) << std::endl;

View File

@@ -45,7 +45,7 @@ hook(Account const& account, std::optional<std::vector<Json::Value>> hooks, std:
}
inline std::string uint64_hex(uint64_t x)
std::string uint64_hex(uint64_t x)
{
auto const nibble = [](uint64_t n) -> char
{