From 77c76c044e526885a6fc30f36045df756924a2b8 Mon Sep 17 00:00:00 2001 From: Richard Holland Date: Wed, 28 Dec 2022 17:52:44 +0000 Subject: [PATCH] ledger_nonce test --- src/ripple/app/hook/impl/applyHook.cpp | 14 +++- src/test/app/SetHook_test.cpp | 101 +++++++++++++++++++++++++ src/test/jtx/Env.h | 4 + src/test/jtx/impl/Env.cpp | 6 ++ 4 files changed, 124 insertions(+), 1 deletion(-) diff --git a/src/ripple/app/hook/impl/applyHook.cpp b/src/ripple/app/hook/impl/applyHook.cpp index 4b997aaa2..17379ff63 100644 --- a/src/ripple/app/hook/impl/applyHook.cpp +++ b/src/ripple/app/hook/impl/applyHook.cpp @@ -3164,12 +3164,24 @@ DEFINE_HOOK_FUNCTION( auto hash = ripple::sha512Half( ripple::HashPrefix::hookNonce, view.info().seq, - view.info().parentCloseTime, + view.info().parentCloseTime.time_since_epoch().count(), applyCtx.app.getLedgerMaster().getValidatedLedger()->info().hash, applyCtx.tx.getTransactionID(), hookCtx.ledger_nonce_counter++, hookCtx.result.account ); + + /* + std::cout << + "seq: " << view.info().seq << + ", llc: " << view.info().parentCloseTime.time_since_epoch().count() << + ", llh: " << applyCtx.app.getLedgerMaster().getValidatedLedger()->info().hash << + ", txid: " << applyCtx.tx.getTransactionID() << + ", count: " << hookCtx.ledger_nonce_counter << + ", acc: " << hookCtx.result.account << + ", nonce: " << hash << "\n"; + */ + WRITE_WASM_MEMORY_AND_RETURN( write_ptr, 32, diff --git a/src/test/app/SetHook_test.cpp b/src/test/app/SetHook_test.cpp index 60218dbbb..5180460d7 100644 --- a/src/test/app/SetHook_test.cpp +++ b/src/test/app/SetHook_test.cpp @@ -4074,6 +4074,107 @@ public: void test_ledger_nonce() { + testcase("Test ledger_nonce"); + 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 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 ledger_nonce (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 nonce[64]; + + // Test out of bounds check + ASSERT(ledger_nonce(1000000, 32) == OUT_OF_BOUNDS); + ASSERT(ledger_nonce((uint32_t)nonce, 31) == TOO_SMALL); + ASSERT(ledger_nonce((uint32_t)nonce, 32) == 32); + ASSERT(ledger_nonce((uint32_t)(nonce + 32), 32) == 32); + + // return the two nonces as the return string + accept((uint32_t)nonce, 64, 0); + } + )[test.hook]"]; + + // install the hook on alice + env(ripple::test::jtx::hook(alice, {{hso(hook, overrideFlag)}}, 0), + M("set ledger_nonce"), + HSFEE); + env.close(); + + + + // invoke the hook + auto const seq = env.app().getLedgerMaster().getCurrentLedger()->info().seq; + auto const llc = env.app().getLedgerMaster().getCurrentLedger()->info().parentCloseTime.time_since_epoch().count(); + auto const llh = env.app().getLedgerMaster().getCurrentLedger()->info().hash; + + env(pay(bob, alice, XRP(1)), M("test ledger_nonce"), fee(XRP(1))); + auto const txid = env.txid(); + + 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 expected size (two nonces = 64 bytes) + BEAST_EXPECT(retStr.size() == 64); + + auto const computed_hash_1 = ripple::sha512Half( + ripple::HashPrefix::hookNonce, + seq, llc, llh, + txid, + (uint16_t)0UL, + alice.id() + ); + auto const computed_hash_2 = ripple::sha512Half( + ripple::HashPrefix::hookNonce, + seq, llc, llh, + txid, + (uint16_t)1UL, // second nonce + alice.id() + ); + + /* + std::cout << + "seq: " << seq << + ", llc: " << llc << + ", llh: " << llh << + ", txid: " << txid << + ", count: 0" << + ", acc: " << alice.human() << + ", nonce: " << computed_hash_1 << ", " << computed_hash_2 << "\n"; + */ + + BEAST_EXPECT(computed_hash_1 == uint256::fromVoid(retStr.data())); + BEAST_EXPECT(computed_hash_2 == uint256::fromVoid(retStr.data() + 32)); + } void diff --git a/src/test/jtx/Env.h b/src/test/jtx/Env.h index 8841d2d2f..4dbe96de9 100644 --- a/src/test/jtx/Env.h +++ b/src/test/jtx/Env.h @@ -596,6 +596,9 @@ public: if constexpr (sizeof...(args) > 0) fund(amount, args...); } + + // get the last txn id + uint256 txid() const; /** Establish trust lines. @@ -637,6 +640,7 @@ protected: uint256 txid_; TER ter_ = tesSUCCESS; + Json::Value do_rpc( std::vector const& args, diff --git a/src/test/jtx/impl/Env.cpp b/src/test/jtx/impl/Env.cpp index a87043bf9..6f9d4aa04 100644 --- a/src/test/jtx/impl/Env.cpp +++ b/src/test/jtx/impl/Env.cpp @@ -395,6 +395,12 @@ Env::tx() const return current()->txRead(txid_).first; } +uint256 +Env::txid() const +{ + return txid_; +} + void Env::autofill_sig(JTx& jt) {