mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-28 14:35:48 +00:00
unit tests for hook_account, hook_hash
This commit is contained in:
@@ -3206,6 +3206,10 @@ DEFINE_HOOK_FUNCTION(
|
||||
uint32_t write_ptr, uint32_t ptr_len )
|
||||
{
|
||||
HOOK_SETUP(); // populates memory_ctx, memory, memory_length, applyCtx, hookCtx on current stack
|
||||
|
||||
if (ptr_len < 20)
|
||||
return TOO_SMALL;
|
||||
|
||||
if (NOT_IN_BOUNDS(write_ptr, 20, memory_length))
|
||||
return OUT_OF_BOUNDS;
|
||||
|
||||
|
||||
@@ -3731,6 +3731,127 @@ public:
|
||||
void
|
||||
test_hook_account()
|
||||
{
|
||||
testcase("Test hook_account");
|
||||
using namespace jtx;
|
||||
|
||||
|
||||
auto const test = [&](Account alice)->void
|
||||
{
|
||||
Env env{*this, supported_amendments()};
|
||||
|
||||
auto const bob = Account{"bob"};
|
||||
env.fund(XRP(10000), alice);
|
||||
env.fund(XRP(10000), bob);
|
||||
|
||||
TestHook
|
||||
hook =
|
||||
wasm[R"[test.hook](
|
||||
#include <stdint.h>
|
||||
extern int32_t _g (uint32_t id, uint32_t maxiter);
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t rollback (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t hook_account (uint32_t, uint32_t);
|
||||
#define TOO_SMALL -4
|
||||
#define OUT_OF_BOUNDS -1
|
||||
#define ASSERT(x)\
|
||||
if (!(x))\
|
||||
rollback((uint32_t)#x, sizeof(#x), __LINE__);
|
||||
int64_t hook(uint32_t reserved )
|
||||
{
|
||||
_g(1,1);
|
||||
uint8_t acc[20];
|
||||
|
||||
// Test out of bounds check
|
||||
ASSERT(hook_account(1000000, 20) == OUT_OF_BOUNDS);
|
||||
ASSERT(hook_account((uint32_t)acc, 19) == TOO_SMALL);
|
||||
ASSERT(hook_account((uint32_t)acc, 20) == 20);
|
||||
|
||||
// return the accid as the return string
|
||||
accept((uint32_t)acc, 20, 0);
|
||||
}
|
||||
)[test.hook]"];
|
||||
|
||||
// install the hook on alice
|
||||
env(ripple::test::jtx::hook(alice, {{hso(hook, overrideFlag)}}, 0),
|
||||
M("set hook_account"),
|
||||
HSFEE);
|
||||
env.close();
|
||||
|
||||
// invoke the hook
|
||||
env(pay(bob, alice, XRP(1)),
|
||||
M("test hook_account"),
|
||||
fee(XRP(1)));
|
||||
|
||||
{
|
||||
auto meta = env.meta();
|
||||
|
||||
// ensure hook execution occured
|
||||
BEAST_REQUIRE(meta);
|
||||
BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions));
|
||||
|
||||
// ensure there was only one hook execution
|
||||
auto const hookExecutions = meta->getFieldArray(sfHookExecutions);
|
||||
BEAST_REQUIRE(hookExecutions.size() == 1);
|
||||
|
||||
// get the data in the return string of the extention
|
||||
auto const retStr = hookExecutions[0].getFieldVL(sfHookReturnString);
|
||||
|
||||
// check that it matches the account id
|
||||
BEAST_EXPECT(retStr.size() == 20);
|
||||
auto const a = alice.id();
|
||||
BEAST_EXPECT(memcmp(retStr.data(), a.data(), 20) == 0);
|
||||
}
|
||||
|
||||
// install the same hook bob
|
||||
env(ripple::test::jtx::hook(bob, {{hso(hook, overrideFlag)}}, 0),
|
||||
M("set hook_account 2"),
|
||||
HSFEE);
|
||||
env.close();
|
||||
|
||||
// invoke the hook
|
||||
env(pay(bob, alice, XRP(1)),
|
||||
M("test hook_account 2"),
|
||||
fee(XRP(1)));
|
||||
|
||||
// there should be two hook executions, the first should be bob's address
|
||||
// the second should be alice's
|
||||
{
|
||||
auto meta = env.meta();
|
||||
|
||||
// ensure hook execution occured
|
||||
BEAST_REQUIRE(meta);
|
||||
BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions));
|
||||
|
||||
// ensure there were two hook executions
|
||||
auto const hookExecutions = meta->getFieldArray(sfHookExecutions);
|
||||
BEAST_REQUIRE(hookExecutions.size() == 2);
|
||||
|
||||
{
|
||||
// get the data in the return string of the extention
|
||||
auto const retStr = hookExecutions[0].getFieldVL(sfHookReturnString);
|
||||
|
||||
// check that it matches the account id
|
||||
BEAST_EXPECT(retStr.size() == 20);
|
||||
auto const b = bob.id();
|
||||
BEAST_EXPECT(memcmp(retStr.data(), b.data(), 20) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
// get the data in the return string of the extention
|
||||
auto const retStr = hookExecutions[1].getFieldVL(sfHookReturnString);
|
||||
|
||||
// check that it matches the account id
|
||||
BEAST_EXPECT(retStr.size() == 20);
|
||||
auto const a = alice.id();
|
||||
BEAST_EXPECT(memcmp(retStr.data(), a.data(), 20) == 0);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
test(Account{"alice"});
|
||||
test(Account{"cho"});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -3741,6 +3862,172 @@ public:
|
||||
void
|
||||
test_hook_hash()
|
||||
{
|
||||
testcase("Test hook_hash");
|
||||
using namespace jtx;
|
||||
|
||||
|
||||
auto const test = [&](Account alice)->void
|
||||
{
|
||||
Env env{*this, supported_amendments()};
|
||||
|
||||
auto const bob = Account{"bob"};
|
||||
env.fund(XRP(10000), alice);
|
||||
env.fund(XRP(10000), bob);
|
||||
|
||||
TestHook
|
||||
hook =
|
||||
wasm[R"[test.hook](
|
||||
#include <stdint.h>
|
||||
extern int32_t _g (uint32_t id, uint32_t maxiter);
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t rollback (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t hook_hash (uint32_t, uint32_t, int32_t);
|
||||
#define TOO_SMALL -4
|
||||
#define OUT_OF_BOUNDS -1
|
||||
#define ASSERT(x)\
|
||||
if (!(x))\
|
||||
rollback((uint32_t)#x, sizeof(#x), __LINE__);
|
||||
int64_t hook(uint32_t reserved )
|
||||
{
|
||||
_g(1,1);
|
||||
uint8_t hash[32];
|
||||
|
||||
// Test out of bounds check
|
||||
ASSERT(hook_hash(1000000, 32, -1) == OUT_OF_BOUNDS);
|
||||
ASSERT(hook_hash((uint32_t)hash, 31, -1) == TOO_SMALL);
|
||||
ASSERT(hook_hash((uint32_t)hash, 32, -1) == 32);
|
||||
|
||||
// return the hash as the return string
|
||||
accept((uint32_t)hash, 32, 0);
|
||||
}
|
||||
)[test.hook]"];
|
||||
|
||||
// install the hook on alice
|
||||
env(ripple::test::jtx::hook(alice, {{hso(hook, overrideFlag)}}, 0),
|
||||
M("set hook_hash"),
|
||||
HSFEE);
|
||||
env.close();
|
||||
|
||||
// invoke the hook
|
||||
env(pay(bob, alice, XRP(1)),
|
||||
M("test hook_hash"),
|
||||
fee(XRP(1)));
|
||||
|
||||
{
|
||||
auto meta = env.meta();
|
||||
|
||||
// ensure hook execution occured
|
||||
BEAST_REQUIRE(meta);
|
||||
BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions));
|
||||
|
||||
// ensure there was only one hook execution
|
||||
auto const hookExecutions = meta->getFieldArray(sfHookExecutions);
|
||||
BEAST_REQUIRE(hookExecutions.size() == 1);
|
||||
|
||||
// get the data in the return string of the extention
|
||||
auto const retStr = hookExecutions[0].getFieldVL(sfHookReturnString);
|
||||
|
||||
// check that it matches the hook hash
|
||||
BEAST_EXPECT(retStr.size() == 32);
|
||||
|
||||
auto const hash = hookExecutions[0].getFieldH256(sfHookHash);
|
||||
BEAST_EXPECT(memcmp(hash.data(), retStr.data(), 32) == 0);
|
||||
}
|
||||
|
||||
TestHook
|
||||
hook2 =
|
||||
wasm[R"[test.hook](
|
||||
#include <stdint.h>
|
||||
extern int32_t _g (uint32_t id, uint32_t maxiter);
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t rollback (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t hook_hash (uint32_t, uint32_t, int32_t);
|
||||
#define TOO_SMALL -4
|
||||
#define OUT_OF_BOUNDS -1
|
||||
#define ASSERT(x)\
|
||||
if (!(x))\
|
||||
rollback((uint32_t)#x, sizeof(#x), __LINE__);
|
||||
int64_t hook(uint32_t reserved )
|
||||
{
|
||||
_g(1,2);
|
||||
uint8_t hash[32];
|
||||
|
||||
// Test out of bounds check
|
||||
ASSERT(hook_hash(1000000, 32, -1) == OUT_OF_BOUNDS);
|
||||
ASSERT(hook_hash((uint32_t)hash, 31, -1) == TOO_SMALL);
|
||||
ASSERT(hook_hash((uint32_t)hash, 32, -1) == 32);
|
||||
|
||||
// return the hash as the return string
|
||||
accept((uint32_t)hash, 32, 0);
|
||||
}
|
||||
)[test.hook]"];
|
||||
|
||||
// install a slightly different hook on bob
|
||||
env(ripple::test::jtx::hook(bob, {{hso(hook2, overrideFlag)}}, 0),
|
||||
M("set hook_hash 2"),
|
||||
HSFEE);
|
||||
env.close();
|
||||
|
||||
// invoke the hook
|
||||
env(pay(bob, alice, XRP(1)),
|
||||
M("test hook_hash 2"),
|
||||
fee(XRP(1)));
|
||||
|
||||
|
||||
// there should be two hook executions, the first should have bob's hook hash
|
||||
// the second should have alice's hook hash
|
||||
{
|
||||
auto meta = env.meta();
|
||||
|
||||
// ensure hook execution occured
|
||||
BEAST_REQUIRE(meta);
|
||||
BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions));
|
||||
|
||||
// ensure there was only one hook execution
|
||||
auto const hookExecutions = meta->getFieldArray(sfHookExecutions);
|
||||
BEAST_REQUIRE(hookExecutions.size() == 2);
|
||||
|
||||
// get the data in the return string of the extention
|
||||
auto const retStr1 = hookExecutions[0].getFieldVL(sfHookReturnString);
|
||||
|
||||
// check that it matches the hook hash
|
||||
BEAST_EXPECT(retStr1.size() == 32);
|
||||
|
||||
auto const hash1 = hookExecutions[0].getFieldH256(sfHookHash);
|
||||
BEAST_EXPECT(memcmp(hash1.data(), retStr1.data(), 32) == 0);
|
||||
|
||||
// get the data in the return string of the extention
|
||||
auto const retStr2 = hookExecutions[1].getFieldVL(sfHookReturnString);
|
||||
|
||||
// check that it matches the hook hash
|
||||
BEAST_EXPECT(retStr2.size() == 32);
|
||||
|
||||
auto const hash2 = hookExecutions[1].getFieldH256(sfHookHash);
|
||||
BEAST_EXPECT(memcmp(hash2.data(), retStr2.data(), 32) == 0);
|
||||
|
||||
// make sure they're not the same
|
||||
BEAST_EXPECT(memcmp(hash1.data(), hash2.data(), 32) != 0);
|
||||
|
||||
// compute the hashes
|
||||
auto computedHash2 =
|
||||
ripple::sha512Half_s(
|
||||
ripple::Slice(hook.data(), hook.size())
|
||||
);
|
||||
|
||||
auto computedHash1 =
|
||||
ripple::sha512Half_s(
|
||||
ripple::Slice(hook2.data(), hook2.size())
|
||||
);
|
||||
|
||||
// ensure the computed hashes match
|
||||
BEAST_EXPECT(computedHash1 == hash1);
|
||||
BEAST_EXPECT(computedHash2 == hash2);
|
||||
}
|
||||
};
|
||||
|
||||
test(Account{"alice"});
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -25,6 +25,8 @@ cat SetHook_test.cpp | tr '\n' '\f' |
|
||||
WAT=`grep -Eo '\(module' <<< $line | wc -l`
|
||||
if [ "$WAT" -eq "0" ]
|
||||
then
|
||||
echo '#include "api.h"' > /root/xrpld-hooks/hook/tests/hookapi/wasm/test-$COUNTER.c
|
||||
tr '\f' '\n' <<< $line >> /root/xrpld-hooks/hook/tests/hookapi/wasm/test-$COUNTER.c
|
||||
wasmcc -x c /dev/stdin -o /dev/stdout -O2 -Wl,--allow-undefined <<< `tr '\f' '\n' <<< $line` |
|
||||
hook-cleaner - - 2>/dev/null |
|
||||
xxd -p -u -c 19 |
|
||||
|
||||
@@ -376,9 +376,14 @@ Env::postconditions(JTx const& jt, TER ter, bool didApply)
|
||||
std::shared_ptr<STObject const>
|
||||
Env::meta()
|
||||
{
|
||||
close();
|
||||
auto const item = closed()->txRead(txid_);
|
||||
return item.second;
|
||||
auto cur = current()->txRead(txid_);
|
||||
if (cur.second)
|
||||
return cur.second;
|
||||
else
|
||||
if (cur.first)
|
||||
close();
|
||||
|
||||
return closed()->txRead(txid_).second;
|
||||
}
|
||||
|
||||
std::shared_ptr<STTx const>
|
||||
|
||||
Reference in New Issue
Block a user