Support 'cron' with ledger_entry RPC (#608)

This commit is contained in:
tequ
2025-10-24 16:05:14 +09:00
committed by GitHub
parent 6f148a8ac7
commit 2a10013dfc
4 changed files with 115 additions and 1 deletions

View File

@@ -72,7 +72,7 @@ enum class LedgerNameSpace : std::uint16_t {
URI_TOKEN = 'U',
IMPORT_VLSEQ = 'I',
UNL_REPORT = 'R',
CRON = 'A',
CRON = 'L',
// No longer used or supported. Left here to reserve the space
// to avoid accidental reuse.

View File

@@ -256,6 +256,7 @@ JSS(coins);
JSS(children);
JSS(ctid); // in/out: Tx RPC
JSS(cres);
JSS(cron);
JSS(currency_a); // out: BookChanges
JSS(currency_b); // out: BookChanges
JSS(currentShard); // out: NodeToShardStatus

View File

@@ -506,6 +506,36 @@ doLedgerEntry(RPC::JsonContext& context)
jvResult[jss::error] = "malformedRequest";
}
}
else if (context.params.isMember(jss::cron))
{
expectedType = ltCRON;
if (!context.params[jss::cron].isObject())
{
if (!uNodeIndex.parseHex(context.params[jss::cron].asString()))
{
uNodeIndex = beast::zero;
jvResult[jss::error] = "malformedRequest";
}
}
else if (
!context.params[jss::cron].isMember(jss::owner) ||
!context.params[jss::cron].isMember(jss::time))
{
jvResult[jss::error] = "malformedRequest";
}
else
{
auto const id = parseBase58<AccountID>(
context.params[jss::cron][jss::owner].asString());
if (!id)
jvResult[jss::error] = "malformedAddress";
else
uNodeIndex =
keylet::cron(
context.params[jss::cron][jss::time].asUInt(), *id)
.key;
}
}
else
{
if (context.params.isMember("params") &&

View File

@@ -1839,6 +1839,88 @@ public:
}
}
void
testLedgerEntryCron()
{
testcase("ledger_entry Request Cron");
using namespace test::jtx;
Env env{*this};
Account const alice{"alice"};
env.fund(XRP(10000), alice);
env.close();
auto const startTime =
env.current()->parentCloseTime().time_since_epoch().count() + 100;
env(cron::set(alice),
cron::startTime(startTime),
cron::delay(100),
cron::repeat(200),
fee(XRP(1)),
ter(tesSUCCESS));
env.close();
std::string const ledgerHash{to_string(env.closed()->info().hash)};
uint256 const cronIndex{keylet::cron(startTime, alice).key};
{
// Request the cron using its index.
Json::Value jvParams;
jvParams[jss::cron] = to_string(cronIndex);
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::node][sfOwner.jsonName] == alice.human());
BEAST_EXPECT(jrr[jss::node][sfStartTime.jsonName] == startTime);
BEAST_EXPECT(jrr[jss::node][sfDelaySeconds.jsonName] == 100);
BEAST_EXPECT(jrr[jss::node][sfRepeatCount.jsonName] == 200);
}
{
// Request the cron using its owner and time.
Json::Value jvParams;
jvParams[jss::cron] = Json::objectValue;
jvParams[jss::cron][jss::owner] = alice.human();
jvParams[jss::cron][jss::time] = startTime;
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::node][sfOwner.jsonName] == alice.human());
BEAST_EXPECT(jrr[jss::node][sfStartTime.jsonName] == startTime);
BEAST_EXPECT(jrr[jss::node][sfDelaySeconds.jsonName] == 100);
BEAST_EXPECT(jrr[jss::node][sfRepeatCount.jsonName] == 200);
}
{
// Malformed uritoken object. Missing owner member.
Json::Value jvParams;
jvParams[jss::cron] = Json::objectValue;
jvParams[jss::cron][jss::time] = startTime;
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "malformedRequest", "");
}
{
// Malformed uritoken object. Missing time member.
Json::Value jvParams;
jvParams[jss::cron] = Json::objectValue;
jvParams[jss::cron][jss::owner] = alice.human();
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "malformedRequest", "");
}
{
// Request an index that is not a uritoken.
Json::Value jvParams;
jvParams[jss::cron] = ledgerHash;
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "");
}
}
void
testLedgerEntryUnknownOption()
{
@@ -2365,6 +2447,7 @@ public:
testLedgerEntryTicket();
testLedgerEntryURIToken();
testLedgerEntryImportVLSeq();
testLedgerEntryCron();
testLedgerEntryUnknownOption();
testLookupLedger();
testNoQueue();