ledger and account rpc tests (#62)

This commit is contained in:
Denis Angell
2023-04-03 05:05:04 +00:00
parent dfc95ec291
commit f9af9ac6c8
10 changed files with 681 additions and 34 deletions

View File

@@ -32,6 +32,7 @@
#include <boost/logic/tribool.hpp>
#include <optional>
#include <sstream>
#include <deque>
namespace ripple {

View File

@@ -121,8 +121,10 @@ JSS(SetFlag); // field.
JSS(SetRegularKey); // transaction type.
JSS(SetHook); // transaction type.
JSS(Hook); // ledger type.
JSS(HookDefinition); // ledger type.
JSS(HookState); // ledger type.
JSS(HookDefinition);
JSS(HookStateData); // field.
JSS(HookStateKey); // field.
JSS(EmittedTxn); // ledger type.
JSS(SignerList); // ledger type.
JSS(SignerListSet); // transaction type.
@@ -283,6 +285,7 @@ JSS(error_code); // out: error
JSS(error_exception); // out: Submit
JSS(error_message); // out: error
JSS(escrow); // in: LedgerEntry
JSS(emitted_txn); // in: LedgerEntry
JSS(expand); // in: handler/Ledger
JSS(expected_date); // out: any (warnings)
JSS(expected_date_UTC); // out: any (warnings)
@@ -326,7 +329,9 @@ JSS(high); // out: BookChanges
JSS(highest_sequence); // out: AccountInfo
JSS(highest_ticket); // out: AccountInfo
JSS(historical_perminute); // historical_perminute.
JSS(hook_hash); // in: LedgerEntry
JSS(hook); // in: LedgerEntry
JSS(hook_definition); // in: LedgerEntry
JSS(hook_state); // in: LedgerEntry
JSS(hostid); // out: NetworkOPs
JSS(hotwallet); // in: GatewayBalances
JSS(id); // websocket.

View File

@@ -217,6 +217,19 @@ doLedgerEntry(RPC::JsonContext& context)
.key;
}
}
else if (context.params.isMember(jss::emitted_txn))
{
expectedType = ltEMITTED_TXN;
if (!context.params[jss::emitted_txn].isObject())
{
if (!uNodeIndex.parseHex(context.params[jss::emitted_txn].asString()))
{
uNodeIndex = beast::zero;
jvResult[jss::error] = "malformedRequest";
}
uNodeIndex = keylet::emittedTxn(uNodeIndex).key;
}
}
else if (context.params.isMember(jss::offer))
{
expectedType = ltOFFER;
@@ -337,11 +350,37 @@ doLedgerEntry(RPC::JsonContext& context)
*id, context.params[jss::ticket][jss::ticket_seq].asUInt());
}
}
else if (context.params.isMember(jss::hook_hash))
else if (context.params.isMember(jss::hook))
{
expectedType = ltHOOK;
if (!context.params[jss::hook].isObject())
{
if (!uNodeIndex.parseHex(context.params[jss::hook].asString()))
{
uNodeIndex = beast::zero;
jvResult[jss::error] = "malformedRequest";
}
}
else if (
!context.params[jss::hook].isMember(jss::account))
{
jvResult[jss::error] = "malformedRequest";
}
else
{
auto const id = parseBase58<AccountID>(
context.params[jss::hook][jss::account].asString());
if (!id)
jvResult[jss::error] = "malformedAddress";
else
uNodeIndex = keylet::hook(*id).key;
}
}
else if (context.params.isMember(jss::hook_definition))
{
expectedType = ltHOOK_DEFINITION;
if (context.params[jss::hook_hash].isObject() ||
(!uNodeIndex.parseHex(context.params[jss::hook_hash].asString())))
if (context.params[jss::hook_definition].isObject() ||
(!uNodeIndex.parseHex(context.params[jss::hook_definition].asString())))
{
uNodeIndex = beast::zero;
jvResult[jss::error] = "malformedRequest";
@@ -351,6 +390,45 @@ doLedgerEntry(RPC::JsonContext& context)
uNodeIndex = keylet::hookDefinition(uNodeIndex).key;
}
}
else if (context.params.isMember(jss::hook_state))
{
expectedType = ltHOOK_STATE;
uint256 uNodeKey;
uint256 uNameSpace;
Json::Value jvHookState = context.params[jss::hook_state];
if (!jvHookState.isObject() ||
!jvHookState.isMember(jss::account) ||
!jvHookState.isMember(jss::key) ||
!jvHookState.isMember(jss::namespace_id) ||
!jvHookState[jss::account].isString() ||
!jvHookState[jss::key].isString() ||
!jvHookState[jss::namespace_id].isString())
{
uNodeIndex = beast::zero;
jvResult[jss::error] = "malformedRequest";
}
else
{
auto const account = parseBase58<AccountID>(jvHookState[jss::account].asString());
if (!account)
{
jvResult[jss::error] = "malformedAddress";
}
else if (!uNodeKey.parseHex(jvHookState[jss::key].asString()))
{
jvResult[jss::error] = "malformedRequest";
}
else if (!uNameSpace.parseHex(jvHookState[jss::namespace_id].asString()))
{
jvResult[jss::error] = "malformedRequest";
}
else
{
uNodeIndex = keylet::hookState(*account, uNodeKey, uNameSpace).key;
}
}
}
else if (context.params.isMember(jss::nft_page))
{
expectedType = ltNFTOKEN_PAGE;

View File

@@ -1067,7 +1067,7 @@ chooseLedgerEntryType(Json::Value const& params)
std::pair<RPC::Status, LedgerEntryType> result{RPC::Status::OK, ltANY};
if (params.isMember(jss::type))
{
static constexpr std::array<std::pair<char const*, LedgerEntryType>, 15>
static constexpr std::array<std::pair<char const*, LedgerEntryType>, 17>
types{
{{jss::account, ltACCOUNT_ROOT},
{jss::amendments, ltAMENDMENTS},
@@ -1075,6 +1075,9 @@ chooseLedgerEntryType(Json::Value const& params)
{jss::deposit_preauth, ltDEPOSIT_PREAUTH},
{jss::directory, ltDIR_NODE},
{jss::escrow, ltESCROW},
{jss::hook, ltHOOK},
{jss::hook_definition, ltHOOK_DEFINITION},
{jss::hook_state, ltHOOK_STATE},
{jss::fee, ltFEE_SETTINGS},
{jss::hashes, ltLEDGER_HASHES},
{jss::offer, ltOFFER},

View File

@@ -34,6 +34,9 @@ hook(Account const& account, std::optional<std::vector<Json::Value>> hooks, std:
Json::Value
hso(std::vector<uint8_t> const& wasmBytes, void (*f)(Json::Value& jv) = 0);
Json::Value
hso(std::string const& wasmHex, void (*f)(Json::Value& jv) = 0);
Json::Value
hso_delete(void (*f)(Json::Value& jv) = 0);

View File

@@ -80,6 +80,28 @@ hso(std::vector<uint8_t> const& wasmBytes, void (*f)(Json::Value& jv))
}
Json::Value
hso(std::string const& wasmHex, void (*f)(Json::Value& jv))
{
if (wasmHex.size() == 0)
throw std::runtime_error("empty hook wasm passed to hso()");
Json::Value jv;
jv[jss::CreateCode] = wasmHex;
{
jv[jss::HookOn] = "0000000000000000000000000000000000000000000000000000000000000000";
jv[jss::HookNamespace] = to_string(uint256{beast::zero});
jv[jss::HookApiVersion] = Json::Value{0};
}
if (f)
f(jv);
return jv;
}
} // namespace jtx
} // namespace test
} // namespace ripple

View File

@@ -17,6 +17,7 @@
*/
//==============================================================================
#include <ripple/app/hook/Enum.h>
#include <ripple/json/json_reader.h>
#include <ripple/json/json_value.h>
#include <ripple/json/to_string.h>
@@ -111,6 +112,7 @@ static char const* bobs_account_objects[] = {
class AccountObjects_test : public beast::unit_test::suite
{
public:
#define HSFEE fee(100'000'000)
void
testErrors()
{
@@ -586,6 +588,7 @@ public:
BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::state), 0));
BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::ticket), 0));
BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::uri_token), 0));
BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hook), 0));
// gw mints an NFT so we can find it.
uint256 const nftID{token::getNextID(env, gw, 0u, tfTransferable)};
@@ -755,6 +758,23 @@ public:
BEAST_EXPECT(uritoken[sfIssuer.jsonName] == gw.human());
BEAST_EXPECT(uritoken[sfURI.jsonName] == strHex(uri));
}
{
// Create hook
auto setHook = [](test::jtx::Account const& account) {
std::string const createCodeHex = "0061736D0100000001130360037F7F7E017E60027F7F017F60017F017E02170203656E7606616363657074000003656E76025F670001030201020503010002062B077F01418088040B7F004180080B7F004180080B7F004180080B7F00418088040B7F0041000B7F0041010B07080104686F6F6B00020AB5800001B1800001017F230041106B220124002001200036020C410022002000420010001A41012200200010011A200141106A240042000B";
Json::Value jv = ripple::test::jtx::hook(account, {{hso(createCodeHex)}}, 0);
return jv;
};
env(setHook(gw), HSFEE);
env.close();
}
{
// Find the hook.
Json::Value const resp = acct_objs(gw, jss::hook);
BEAST_EXPECT(acct_objs_is_size(resp, 1));
auto const& hook = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(hook[sfAccount.jsonName] == gw.human());
}
{
// See how "deletion_blockers_only" handles gw's directory.
Json::Value params;
@@ -765,6 +785,7 @@ public:
std::vector<std::string> const expectedLedgerTypes = [] {
std::vector<std::string> v{
jss::Escrow.c_str(),
jss::Hook.c_str(),
jss::Check.c_str(),
jss::NFTokenPage.c_str(),
jss::RippleState.c_str(),
@@ -811,7 +832,7 @@ public:
// directory nodes.
for (int d = 1'000'032; d >= 1'000'000; --d)
{
env(offer(gw, USD(1), drops(d)));
env(offer(gw, USD(1), drops(d)), HSFEE);
env.close();
}

View File

@@ -18,9 +18,11 @@
//==============================================================================
#include <ripple/beast/unit_test.h>
#include <ripple/app/misc/TxQ.h>
#include <ripple/protocol/ErrorCodes.h>
#include <ripple/protocol/jss.h>
#include <ripple/rpc/impl/RPCHelpers.h>
#include <ripple/app/hook/Enum.h>
#include <ripple/protocol/jss.h>
#include <test/jtx.h>
#include <boost/container/flat_set.hpp>
@@ -31,6 +33,8 @@ namespace test {
class AccountTx_test : public beast::unit_test::suite
{
#define HSFEE fee(100'000'000)
// A data structure used to describe the basic structure of a
// transactions array node as returned by the account_tx RPC command.
struct NodeSanity
@@ -101,7 +105,6 @@ class AccountTx_test : public beast::unit_test::suite
__FILE__,
__LINE__);
}
BEAST_EXPECT(createdNodes == sane.created);
BEAST_EXPECT(deletedNodes == sane.deleted);
BEAST_EXPECT(modifiedNodes == sane.modified);
@@ -393,6 +396,8 @@ class AccountTx_test : public beast::unit_test::suite
env(check::cancel(alice, aliceCheckId), sig(alie));
env.close();
}
// Ticket
{
// Deposit preauthorization with a Ticket.
std::uint32_t const tktSeq{env.seq(alice) + 1};
@@ -403,7 +408,138 @@ class AccountTx_test : public beast::unit_test::suite
env.close();
}
// Setup is done. Look at the transactions returned by account_tx.
// URIToken
{
using namespace std::chrono_literals;
std::string const uri(maxTokenURILength, '?');
// Mint URIToken
auto mintURI = [](test::jtx::Account const& account, std::string const& uri) {
Json::Value jv;
jv[jss::TransactionType] = jss::URITokenMint;
jv[jss::Flags] = tfBurnable;
jv[jss::Account] = account.human();
jv[sfURI.jsonName] = strHex(uri);
return jv;
};
env(mintURI(alice, uri), sig(alie));
env.close();
auto tokenid = [](jtx::Account const& account, std::string const& uri) {
auto const k = keylet::uritoken(account, Blob(uri.begin(), uri.end()));
return k.key;
};
auto const tid = tokenid(alice, uri);
std::string const hexid{strHex(tid)};
// Sell URIToken
auto sellURI = [](test::jtx::Account const& account, std::string const& id, STAmount const& amount) {
Json::Value jv;
jv[jss::TransactionType] = jss::URITokenCreateSellOffer;
jv[jss::Account] = account.human();
jv[jss::Amount] = amount.getJson(JsonOptions::none);
jv[sfURITokenID.jsonName] = id;
return jv;
};
env(sellURI(alice, hexid, XRP(10)), sig(alie));
env.close();
// Buy URIToken
auto buyURI = [](test::jtx::Account const& account, std::string const& id, STAmount const& amount) {
Json::Value jv;
jv[jss::TransactionType] = jss::URITokenBuy;
jv[jss::Account] = account.human();
jv[jss::Amount] = amount.getJson(JsonOptions::none);
jv[sfURITokenID.jsonName] = id;
return jv;
};
env(buyURI(gw, hexid, XRP(10)));
env.close();
// Sell URIToken
env(sellURI(gw, hexid, XRP(10)));
env.close();
// Clear URIToken
auto cancelURI = [](test::jtx::Account const& account, std::string const& id) {
Json::Value jv;
jv[jss::TransactionType] = jss::URITokenCancelSellOffer;
jv[jss::Account] = account.human();
jv[sfURITokenID.jsonName] = id;
return jv;
};
env(cancelURI(gw, hexid));
env.close();
// Burn URIToken
auto burnURI = [](test::jtx::Account const& account, std::string const& id) {
Json::Value jv;
jv[jss::TransactionType] = jss::URITokenBurn;
jv[jss::Account] = account.human();
jv[sfURITokenID.jsonName] = id;
return jv;
};
env(burnURI(gw, hexid));
env.close();
}
// Hook
{
// Create Hook
auto createHook = [](test::jtx::Account const& account) {
std::string const createHookHex = "0061736D0100000001130360037F7F7E017E60027F7F017F60017F017E02170203656E7606616363657074000003656E76025F670001030201020503010002062B077F01418088040B7F004180080B7F004180080B7F004180080B7F00418088040B7F0041000B7F0041010B07080104686F6F6B00020AB5800001B1800001017F230041106B220124002001200036020C410022002000420010001A41012200200010011A200141106A240042000B";
Json::Value jv = ripple::test::jtx::hook(account, {{hso(createHookHex)}}, 0);
return jv;
};
env(createHook(alice), HSFEE, sig(alie));
env.close();
// Update Hook - Binary
auto updateHook = [](test::jtx::Account const& account) {
std::string const updateHookHex = "0061736D0100000001130360037F7F7E017E60027F7F017F60017F017E02170203656E7606616363657074000003656E76025F670001030201020503010002062B077F01418088040B7F004180080B7F004180080B7F004180080B7F00418088040B7F0041000B7F0041010B07080104686F6F6B00020AB5800001B1800001017F230041106B220124002001200036020C410022002000420010001A41012200200010011A200141106A240042000B";
Json::Value jhv = hso(updateHookHex);
jhv[jss::Flags] = hsfOVERRIDE;
Json::Value jv = ripple::test::jtx::hook(account, {{jhv}}, hsfOVERRIDE);
return jv;
};
env(updateHook(alice), HSFEE, sig(alie));
env.close();
// Install Hook - Hash
auto hh = [&](jtx::Env const& env, jtx::Account const& account) -> uint256 {
auto const hook = env.le(keylet::hook(account.id()));
if (hook) {
auto const& hooks = hook->getFieldArray(sfHooks);
if (hooks.size() > 0) {
return hooks[0].getFieldH256(sfHookHash);
}
}
return uint256{beast::zero};
};
auto installHook = [](test::jtx::Account const& account, uint256 const& hookHash) {
Json::Value jhv;
jhv[jss::Flags] = hsfOVERRIDE;
jhv[jss::HookOn] = "0000000000000000000000000000000000000000000000000000000000000000";
jhv[jss::HookNamespace] = to_string(uint256{beast::zero});
jhv[jss::HookHash] = to_string(hookHash);
Json::Value jv = ripple::test::jtx::hook(account, {{jhv}}, hsfOVERRIDE);
return jv;
};
uint256 const hid = hh(env, alice);
env(installHook(alice, hid), HSFEE, sig(alie));
env.close();
// Delete Hook
auto deleteHook = [](test::jtx::Account const& account) {
Json::Value jv = ripple::test::jtx::hook(account, {{hso_delete()}}, hsfOVERRIDE);
return jv;
};
env(deleteHook(alice), HSFEE, sig(alie));
env.close();
}
// Setup is done. Look at the transactions returned by account_tx.
Json::Value params;
params[jss::account] = alice.human();
params[jss::ledger_index_min] = -1;
@@ -421,29 +557,39 @@ class AccountTx_test : public beast::unit_test::suite
// Do a sanity check on each returned transaction. They should
// be returned in the reverse order of application to the ledger.
static const NodeSanity sanity[]{
// txType, created, deleted, modified
{0, jss::DepositPreauth, {jss::DepositPreauth}, {jss::Ticket}, {jss::AccountRoot, jss::DirectoryNode}},
{1, jss::TicketCreate, {jss::Ticket}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{2, jss::CheckCancel, {}, {jss::Check}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{3, jss::CheckCash, {}, {jss::Check}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{4, jss::CheckCreate, {jss::Check}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{5, jss::CheckCreate, {jss::Check}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{6, jss::PaymentChannelClaim, {}, {jss::PayChannel}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{7, jss::PaymentChannelFund, {}, {}, {jss::AccountRoot, jss::PayChannel}},
{8, jss::PaymentChannelCreate, {jss::PayChannel}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{9, jss::EscrowCancel, {}, {jss::Escrow}, {jss::AccountRoot, jss::DirectoryNode}},
{10, jss::EscrowFinish, {}, {jss::Escrow}, {jss::AccountRoot, jss::DirectoryNode}},
{11, jss::EscrowCreate, {jss::Escrow}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{12, jss::EscrowCreate, {jss::Escrow}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{13, jss::SignerListSet, {jss::SignerList}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{14, jss::OfferCancel, {}, {jss::Offer, jss::DirectoryNode}, {jss::AccountRoot, jss::DirectoryNode}},
{15, jss::OfferCreate, {jss::Offer, jss::DirectoryNode}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{16, jss::TrustSet, {jss::RippleState, jss::DirectoryNode, jss::DirectoryNode}, {}, {jss::AccountRoot, jss::AccountRoot}},
{17, jss::SetRegularKey, {}, {}, {jss::AccountRoot}},
{18, jss::Payment, {}, {}, {jss::AccountRoot, jss::AccountRoot}},
{19, jss::AccountSet, {}, {}, {jss::AccountRoot}},
{20, jss::AccountSet, {}, {}, {jss::AccountRoot}},
{21, jss::Payment, {jss::AccountRoot}, {}, {jss::AccountRoot}},
// txType, created, deleted, modified
{0, jss::SetHook, {}, {jss::Hook, jss::HookDefinition}, {jss::AccountRoot, jss::DirectoryNode}},
{1, jss::SetHook, {}, {}, {jss::AccountRoot, jss::Hook}},
{2, jss::SetHook, {}, {}, {jss::AccountRoot, jss::Hook}},
{3, jss::SetHook, {jss::Hook, jss::HookDefinition}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{4, jss::URITokenBurn, {}, {jss::URIToken}, {jss::AccountRoot, jss::DirectoryNode}},
{5, jss::URITokenCancelSellOffer, {}, {}, {jss::AccountRoot, jss::URIToken}},
{6, jss::URITokenCreateSellOffer, {}, {}, {jss::AccountRoot, jss::URIToken}},
{7, jss::URITokenBuy, {}, {}, {jss::AccountRoot, jss::DirectoryNode, jss::URIToken}},
{8, jss::URITokenCreateSellOffer, {}, {}, {jss::AccountRoot, jss::URIToken}},
{9, jss::URITokenMint, {jss::URIToken}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{10, jss::DepositPreauth, {jss::DepositPreauth}, {jss::Ticket}, {jss::AccountRoot, jss::DirectoryNode}},
{11, jss::TicketCreate, {jss::Ticket}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{12, jss::CheckCancel, {}, {jss::Check}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{13, jss::CheckCash, {}, {jss::Check}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{14, jss::CheckCreate, {jss::Check}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{15, jss::CheckCreate, {jss::Check}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{16, jss::PaymentChannelClaim, {}, {jss::PayChannel}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{17, jss::PaymentChannelFund, {}, {}, {jss::AccountRoot, jss::PayChannel}},
{18, jss::PaymentChannelCreate, {jss::PayChannel}, {}, {jss::AccountRoot, jss::AccountRoot, jss::DirectoryNode, jss::DirectoryNode}},
{19, jss::EscrowCancel, {}, {jss::Escrow}, {jss::AccountRoot, jss::DirectoryNode}},
{20, jss::EscrowFinish, {}, {jss::Escrow}, {jss::AccountRoot, jss::DirectoryNode}},
{21, jss::EscrowCreate, {jss::Escrow}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{22, jss::EscrowCreate, {jss::Escrow}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{23, jss::SignerListSet, {jss::SignerList}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{24, jss::OfferCancel, {}, {jss::Offer, jss::DirectoryNode}, {jss::AccountRoot, jss::DirectoryNode}},
{25, jss::OfferCreate, {jss::Offer, jss::DirectoryNode}, {}, {jss::AccountRoot, jss::DirectoryNode}},
{26, jss::TrustSet, {jss::RippleState, jss::DirectoryNode, jss::DirectoryNode}, {}, {jss::AccountRoot, jss::AccountRoot}},
{27, jss::SetRegularKey, {}, {}, {jss::AccountRoot}},
{28, jss::Payment, {}, {}, {jss::AccountRoot, jss::AccountRoot}},
{29, jss::AccountSet, {}, {}, {jss::AccountRoot}},
{30, jss::AccountSet, {}, {}, {jss::AccountRoot}},
{31, jss::Payment, {jss::AccountRoot}, {}, {jss::AccountRoot}},
};
// clang-format on

View File

@@ -376,6 +376,17 @@ public:
env(jv);
}
{
std::string const createCodeHex = "0061736D01000000011B0460027F7F017F60047F7F7F7F017E60037F7F7E017E60017F017E02270303656E76025F67000003656E760973746174655F736574000103656E76066163636570740002030201030503010002062B077F01419088040B7F004180080B7F00418A080B7F004180080B7F00419088040B7F0041000B7F0041010B07080104686F6F6B00030AE7800001E3800002017F017E230041106B220124002001200036020C41012200200010001A2001418008280000360208200141046A410022002F0088083B010020012000280084083602004100200020014106200141086A4104100110022102200141106A240020020B0B1001004180080B096B65790076616C7565";
std::string ns_str = "CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFE";
Json::Value jv = ripple::test::jtx::hook(Account{"bob3"}, {{hso(createCodeHex)}}, 0);
jv[jss::Hooks][0U][jss::Hook][jss::HookNamespace] = ns_str;
env(jv, fee(100'000'000));
env.close();
env(pay(Account{"bob2"}, Account{"bob3"}, XRP(1)), fee(XRP(1)));
env.close();
}
{
Json::Value jv;
jv[jss::TransactionType] = jss::PaymentChannelCreate;
@@ -423,7 +434,7 @@ public:
{ // jvParams[jss::type] = "directory";
auto const jrr = makeRequest(jss::directory);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 9));
BEAST_EXPECT(checkArraySize(jrr[jss::state], 10));
for (auto const& j : jrr[jss::state])
BEAST_EXPECT(j["LedgerEntryType"] == jss::DirectoryNode);
}
@@ -477,6 +488,27 @@ public:
BEAST_EXPECT(j["LedgerEntryType"] == jss::Escrow);
}
{ // jvParams[jss::type] = "hook";
auto const jrr = makeRequest(jss::hook);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
for (auto const& j : jrr[jss::state])
BEAST_EXPECT(j["LedgerEntryType"] == jss::Hook);
}
{ // jvParams[jss::type] = "hook_definition";
auto const jrr = makeRequest(jss::hook_definition);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
for (auto const& j : jrr[jss::state])
BEAST_EXPECT(j["LedgerEntryType"] == jss::HookDefinition);
}
{ // jvParams[jss::type] = "hook_state";
auto const jrr = makeRequest(jss::hook_state);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
for (auto const& j : jrr[jss::state])
BEAST_EXPECT(j["LedgerEntryType"] == jss::HookState);
}
{ // jvParams[jss::type] = "payment_channel";
auto const jrr = makeRequest(jss::payment_channel);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));

File diff suppressed because one or more lines are too long