From c9077e8c84772ca717023a12a66d9a9126df51f4 Mon Sep 17 00:00:00 2001 From: Richard Holland Date: Fri, 6 Jan 2023 17:31:49 +0000 Subject: [PATCH] preliminary version of emit test cases --- src/ripple/app/hook/impl/applyHook.cpp | 5 +- src/test/app/SetHook_test.cpp | 337 +++++++++++++++++++++++++ 2 files changed, 341 insertions(+), 1 deletion(-) diff --git a/src/ripple/app/hook/impl/applyHook.cpp b/src/ripple/app/hook/impl/applyHook.cpp index 2ae5979be..bc29c0b47 100644 --- a/src/ripple/app/hook/impl/applyHook.cpp +++ b/src/ripple/app/hook/impl/applyHook.cpp @@ -2795,9 +2795,12 @@ DEFINE_HOOK_FUNCTION( if (NOT_IN_BOUNDS(read_ptr, read_len, memory_length)) return OUT_OF_BOUNDS; - if (NOT_IN_BOUNDS(write_ptr, 32, memory_length)) + if (NOT_IN_BOUNDS(write_ptr, write_len, memory_length)) return OUT_OF_BOUNDS; + if (write_len < 32) + return TOO_SMALL; + auto& app = hookCtx.applyCtx.app; if (hookCtx.expected_etxn_count < 0) diff --git a/src/test/app/SetHook_test.cpp b/src/test/app/SetHook_test.cpp index 351b79948..79a1168dd 100644 --- a/src/test/app/SetHook_test.cpp +++ b/src/test/app/SetHook_test.cpp @@ -1873,6 +1873,343 @@ public: void test_emit() { + testcase("Test float_compare"); + using namespace jtx; + Env env{*this, supported_amendments()}; + + auto const alice = Account{"alice"}; + auto const bob = Account{"bob"}; + env.fund(XRP(10000), alice); + env.fund(XRP(10000), bob); + + TestHook hook = wasm[R"[test.hook]( + #include + extern int32_t _g(uint32_t, uint32_t); + 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 emit (uint32_t, uint32_t, uint32_t, uint32_t); + extern int64_t etxn_reserve(uint32_t); + extern int64_t otxn_param(uint32_t, uint32_t, uint32_t, uint32_t); + extern int64_t hook_account(uint32_t, uint32_t); + #define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1) + #define OUT_OF_BOUNDS (-1) + #define ttPAYMENT 0 + #define tfCANONICAL 0x80000000UL + #define amAMOUNT 1U + #define amFEE 8U + #define atACCOUNT 1U + #define DOESNT_EXIST (-5) + #define atDESTINATION 3U + #define SBUF(x) (uint32_t)x,sizeof(x) + + #define ENCODE_DROPS_SIZE 9 + #define ENCODE_DROPS(buf_out, drops, amount_type ) \ + {\ + uint8_t uat = amount_type; \ + uint64_t udrops = drops; \ + buf_out[0] = 0x60U +(uat & 0x0FU ); \ + buf_out[1] = 0b01000000 + (( udrops >> 56 ) & 0b00111111 ); \ + buf_out[2] = (udrops >> 48) & 0xFFU; \ + buf_out[3] = (udrops >> 40) & 0xFFU; \ + buf_out[4] = (udrops >> 32) & 0xFFU; \ + buf_out[5] = (udrops >> 24) & 0xFFU; \ + buf_out[6] = (udrops >> 16) & 0xFFU; \ + buf_out[7] = (udrops >> 8) & 0xFFU; \ + buf_out[8] = (udrops >> 0) & 0xFFU; \ + buf_out += ENCODE_DROPS_SIZE; \ + } + + #define _06_XX_ENCODE_DROPS(buf_out, drops, amount_type )\ + ENCODE_DROPS(buf_out, drops, amount_type ); + + #define ENCODE_DROPS_AMOUNT(buf_out, drops )\ + ENCODE_DROPS(buf_out, drops, amAMOUNT ); + #define _06_01_ENCODE_DROPS_AMOUNT(buf_out, drops )\ + ENCODE_DROPS_AMOUNT(buf_out, drops ); + + #define ENCODE_DROPS_FEE(buf_out, drops )\ + ENCODE_DROPS(buf_out, drops, amFEE ); + #define _06_08_ENCODE_DROPS_FEE(buf_out, drops )\ + ENCODE_DROPS_FEE(buf_out, drops ); + + #define ENCODE_TT_SIZE 3 + #define ENCODE_TT(buf_out, tt )\ + {\ + uint8_t utt = tt;\ + buf_out[0] = 0x12U;\ + buf_out[1] =(utt >> 8 ) & 0xFFU;\ + buf_out[2] =(utt >> 0 ) & 0xFFU;\ + buf_out += ENCODE_TT_SIZE; \ + } + #define _01_02_ENCODE_TT(buf_out, tt)\ + ENCODE_TT(buf_out, tt); + + + #define ENCODE_ACCOUNT_SIZE 22 + #define ENCODE_ACCOUNT(buf_out, account_id, account_type)\ + {\ + uint8_t uat = account_type;\ + buf_out[0] = 0x80U + uat;\ + buf_out[1] = 0x14U;\ + *(uint64_t*)(buf_out + 2) = *(uint64_t*)(account_id + 0);\ + *(uint64_t*)(buf_out + 10) = *(uint64_t*)(account_id + 8);\ + *(uint32_t*)(buf_out + 18) = *(uint32_t*)(account_id + 16);\ + buf_out += ENCODE_ACCOUNT_SIZE;\ + } + #define _08_XX_ENCODE_ACCOUNT(buf_out, account_id, account_type)\ + ENCODE_ACCOUNT(buf_out, account_id, account_type); + + #define ENCODE_ACCOUNT_SRC_SIZE 22 + #define ENCODE_ACCOUNT_SRC(buf_out, account_id)\ + ENCODE_ACCOUNT(buf_out, account_id, atACCOUNT); + #define _08_01_ENCODE_ACCOUNT_SRC(buf_out, account_id)\ + ENCODE_ACCOUNT_SRC(buf_out, account_id); + + #define ENCODE_ACCOUNT_DST_SIZE 22 + #define ENCODE_ACCOUNT_DST(buf_out, account_id)\ + ENCODE_ACCOUNT(buf_out, account_id, atDESTINATION); + #define _08_03_ENCODE_ACCOUNT_DST(buf_out, account_id)\ + ENCODE_ACCOUNT_DST(buf_out, account_id); + + #define ENCODE_ACCOUNT_OWNER_SIZE 22 + #define ENCODE_ACCOUNT_OWNER(buf_out, account_id) \ + ENCODE_ACCOUNT(buf_out, account_id, atOWNER); + #define _08_02_ENCODE_ACCOUNT_OWNER(buf_out, account_id) \ + ENCODE_ACCOUNT_OWNER(buf_out, account_id); + + #define ENCODE_UINT32_COMMON_SIZE 5U + #define ENCODE_UINT32_COMMON(buf_out, i, field)\ + {\ + uint32_t ui = i; \ + uint8_t uf = field; \ + buf_out[0] = 0x20U +(uf & 0x0FU); \ + buf_out[1] =(ui >> 24 ) & 0xFFU; \ + buf_out[2] =(ui >> 16 ) & 0xFFU; \ + buf_out[3] =(ui >> 8 ) & 0xFFU; \ + buf_out[4] =(ui >> 0 ) & 0xFFU; \ + buf_out += ENCODE_UINT32_COMMON_SIZE; \ + } + #define _02_XX_ENCODE_UINT32_COMMON(buf_out, i, field)\ + ENCODE_UINT32_COMMON(buf_out, i, field)\ + + #define ENCODE_UINT32_UNCOMMON_SIZE 6U + #define ENCODE_UINT32_UNCOMMON(buf_out, i, field)\ + {\ + uint32_t ui = i; \ + uint8_t uf = field; \ + buf_out[0] = 0x20U; \ + buf_out[1] = uf; \ + buf_out[2] =(ui >> 24 ) & 0xFFU; \ + buf_out[3] =(ui >> 16 ) & 0xFFU; \ + buf_out[4] =(ui >> 8 ) & 0xFFU; \ + buf_out[5] =(ui >> 0 ) & 0xFFU; \ + buf_out += ENCODE_UINT32_UNCOMMON_SIZE; \ + } + #define _02_XX_ENCODE_UINT32_UNCOMMON(buf_out, i, field)\ + ENCODE_UINT32_UNCOMMON(buf_out, i, field)\ + + #define ENCODE_LLS_SIZE 6U + #define ENCODE_LLS(buf_out, lls )\ + ENCODE_UINT32_UNCOMMON(buf_out, lls, 0x1B ); + #define _02_27_ENCODE_LLS(buf_out, lls )\ + ENCODE_LLS(buf_out, lls ); + + #define ENCODE_FLS_SIZE 6U + #define ENCODE_FLS(buf_out, fls )\ + ENCODE_UINT32_UNCOMMON(buf_out, fls, 0x1A ); + #define _02_26_ENCODE_FLS(buf_out, fls )\ + ENCODE_FLS(buf_out, fls ); + + #define ENCODE_TAG_SRC_SIZE 5 + #define ENCODE_TAG_SRC(buf_out, tag )\ + ENCODE_UINT32_COMMON(buf_out, tag, 0x3U ); + #define _02_03_ENCODE_TAG_SRC(buf_out, tag )\ + ENCODE_TAG_SRC(buf_out, tag ); + + #define ENCODE_TAG_DST_SIZE 5 + #define ENCODE_TAG_DST(buf_out, tag )\ + ENCODE_UINT32_COMMON(buf_out, tag, 0xEU ); + #define _02_14_ENCODE_TAG_DST(buf_out, tag )\ + ENCODE_TAG_DST(buf_out, tag ); + + #define ENCODE_SEQUENCE_SIZE 5 + #define ENCODE_SEQUENCE(buf_out, sequence )\ + ENCODE_UINT32_COMMON(buf_out, sequence, 0x4U ); + #define _02_04_ENCODE_SEQUENCE(buf_out, sequence )\ + ENCODE_SEQUENCE(buf_out, sequence ); + + #define ENCODE_FLAGS_SIZE 5 + #define ENCODE_FLAGS(buf_out, tag )\ + ENCODE_UINT32_COMMON(buf_out, tag, 0x2U ); + #define _02_02_ENCODE_FLAGS(buf_out, tag )\ + ENCODE_FLAGS(buf_out, tag ); + + #define ENCODE_SIGNING_PUBKEY_SIZE 35 + #define ENCODE_SIGNING_PUBKEY(buf_out, pkey )\ + {\ + buf_out[0] = 0x73U;\ + buf_out[1] = 0x21U;\ + *(uint64_t*)(buf_out + 2) = *(uint64_t*)(pkey + 0);\ + *(uint64_t*)(buf_out + 10) = *(uint64_t*)(pkey + 8);\ + *(uint64_t*)(buf_out + 18) = *(uint64_t*)(pkey + 16);\ + *(uint64_t*)(buf_out + 26) = *(uint64_t*)(pkey + 24);\ + buf[34] = pkey[32];\ + buf_out += ENCODE_SIGNING_PUBKEY_SIZE;\ + } + + #define _07_03_ENCODE_SIGNING_PUBKEY(buf_out, pkey )\ + ENCODE_SIGNING_PUBKEY(buf_out, pkey ); + + #define ENCODE_SIGNING_PUBKEY_NULL_SIZE 35 + #define ENCODE_SIGNING_PUBKEY_NULL(buf_out )\ + {\ + buf_out[0] = 0x73U;\ + buf_out[1] = 0x21U;\ + *(uint64_t*)(buf_out+2) = 0;\ + *(uint64_t*)(buf_out+10) = 0;\ + *(uint64_t*)(buf_out+18) = 0;\ + *(uint64_t*)(buf_out+25) = 0;\ + buf_out += ENCODE_SIGNING_PUBKEY_NULL_SIZE;\ + } + + #define _07_03_ENCODE_SIGNING_PUBKEY_NULL(buf_out )\ + ENCODE_SIGNING_PUBKEY_NULL(buf_out ); + + extern int64_t etxn_fee_base ( + uint32_t read_ptr, + uint32_t read_len + ); + extern int64_t etxn_details ( + uint32_t write_ptr, + uint32_t write_len + ); + extern int64_t ledger_seq (void); + + #define PREPARE_PAYMENT_SIMPLE_SIZE 270U + #define PREPARE_PAYMENT_SIMPLE(buf_out_master, drops_amount_raw, to_address, dest_tag_raw, src_tag_raw)\ + {\ + uint8_t* buf_out = buf_out_master;\ + uint8_t acc[20];\ + uint64_t drops_amount = (drops_amount_raw);\ + uint32_t dest_tag = (dest_tag_raw);\ + uint32_t src_tag = (src_tag_raw);\ + uint32_t cls = (uint32_t)ledger_seq();\ + hook_account(SBUF(acc));\ + _01_02_ENCODE_TT (buf_out, ttPAYMENT ); /* uint16 | size 3 */ \ + _02_02_ENCODE_FLAGS (buf_out, tfCANONICAL ); /* uint32 | size 5 */ \ + _02_03_ENCODE_TAG_SRC (buf_out, src_tag ); /* uint32 | size 5 */ \ + _02_04_ENCODE_SEQUENCE (buf_out, 0 ); /* uint32 | size 5 */ \ + _02_14_ENCODE_TAG_DST (buf_out, dest_tag ); /* uint32 | size 5 */ \ + _02_26_ENCODE_FLS (buf_out, cls + 1 ); /* uint32 | size 6 */ \ + _02_27_ENCODE_LLS (buf_out, cls + 5 ); /* uint32 | size 6 */ \ + _06_01_ENCODE_DROPS_AMOUNT (buf_out, drops_amount ); /* amount | size 9 */ \ + uint8_t* fee_ptr = buf_out;\ + _06_08_ENCODE_DROPS_FEE (buf_out, 0 ); /* amount | size 9 */ \ + _07_03_ENCODE_SIGNING_PUBKEY_NULL (buf_out ); /* pk | size 35 */ \ + _08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); /* account | size 22 */ \ + _08_03_ENCODE_ACCOUNT_DST (buf_out, to_address ); /* account | size 22 */ \ + int64_t edlen = etxn_details((uint32_t)buf_out, PREPARE_PAYMENT_SIMPLE_SIZE); /* emitdet | size 1?? */ \ + int64_t fee = etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_SIZE); \ + _06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \ + } + + #define UINT16_FROM_BUF(buf)\ + (((uint64_t)((buf)[0]) << 8U) +\ + ((uint64_t)((buf)[1]) << 0U)) + + #define BUFFER_EQUAL_32(buf1, buf2)\ + (\ + *(((uint64_t*)(buf1)) + 0) == *(((uint64_t*)(buf2)) + 0) &&\ + *(((uint64_t*)(buf1)) + 1) == *(((uint64_t*)(buf2)) + 1) &&\ + *(((uint64_t*)(buf1)) + 2) == *(((uint64_t*)(buf2)) + 2) &&\ + *(((uint64_t*)(buf1)) + 3) == *(((uint64_t*)(buf2)) + 3) &&\ + *(((uint64_t*)(buf1)) + 4) == *(((uint64_t*)(buf2)) + 4) &&\ + *(((uint64_t*)(buf1)) + 5) == *(((uint64_t*)(buf2)) + 5) &&\ + *(((uint64_t*)(buf1)) + 6) == *(((uint64_t*)(buf2)) + 6) &&\ + *(((uint64_t*)(buf1)) + 7) == *(((uint64_t*)(buf2)) + 7)) + + #define ASSERT(x)\ + if (!(x))\ + rollback((uint32_t)#x,sizeof(#x),__LINE__) + + int64_t cbak(uint32_t r) + { + } + + int64_t hook(uint32_t r) + { + _g(1,1); + + + // emit txns based on otxn_params + uint8_t emitcount[2]; + ASSERT(otxn_param(SBUF(emitcount), "count", 5) == 2); + + uint16_t ec = UINT16_FROM_BUF(emitcount); + ASSERT(ec > 0); + etxn_reserve(ec); + + // bounds checks + ASSERT(emit(1000000, 32, 0, 32) == OUT_OF_BOUNDS); + ASSERT(emit(0,1000000, 0, 32) == OUT_OF_BOUNDS); + ASSERT(emit(0,32, 1000000, 32) == OUT_OF_BOUNDS); + ASSERT(emit(0,32, 0, 1000000) == OUT_OF_BOUNDS); + + + uint8_t bob[20]; + ASSERT(otxn_param(SBUF(bob), "bob", 3) == 20); + + uint8_t tx[PREPARE_PAYMENT_SIMPLE_SIZE]; + PREPARE_PAYMENT_SIMPLE(tx, 1000, bob, 0, 0); + + uint8_t tmp[32]; + uint8_t incr = otxn_param(SBUF(tmp), "inc", 3) != DOESNT_EXIST; + + uint8_t hashes[64]; + + for (int i = 0; GUARD(64), i < ec; ++i) + { + if (incr) + { + tx[6] = (uint8_t)(i >> 8U); + tx[7] = (uint8_t)(i & 0xFFU); + } + ASSERT(emit(hashes + (i % 2) * 32, 32, SBUF(tx)) == 32); + + // assert the hash isn't the same as the previous txn + ASSERT(!BUFFER_EQUAL_32(hashes, hashes + 32)); + } + + return accept(0,0,0); + } + )[test.hook]"]; + + env(ripple::test::jtx::hook(alice, {{hso(hook, overrideFlag)}}, 0), + M("set emit"), + HSFEE); + env.close(); + + Json::Value invoke; + invoke[jss::TransactionType] = "Invoke"; + invoke[jss::Account] = alice.human(); + + Json::Value params{Json::arrayValue}; + params[0U][jss::HookParameter][jss::HookParameterName ] = strHex(std::string("bob")); + params[0U][jss::HookParameter][jss::HookParameterValue] = strHex(bob.id()); + + params[1U][jss::HookParameter][jss::HookParameterName ] = strHex(std::string("count")); + params[1U][jss::HookParameter][jss::HookParameterValue] = "0001"; + + invoke[jss::HookParameters] = params; + + env(invoke, M("test otxn_param"), fee(XRP(1))); + + // RH UPTO: check emit count = 1, check that the emitted txn is correct + // cbak + // add to another account and make a fork bomb + // test burden and generation logic + // test emit failure + env.close(); } void