mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
add tests for CronSet
This commit is contained in:
@@ -736,6 +736,7 @@ if (tests)
|
||||
src/test/app/BaseFee_test.cpp
|
||||
src/test/app/Check_test.cpp
|
||||
src/test/app/ClaimReward_test.cpp
|
||||
src/test/app/Cron_test.cpp
|
||||
src/test/app/Clawback_test.cpp
|
||||
src/test/app/CrossingLimits_test.cpp
|
||||
src/test/app/DeliverMin_test.cpp
|
||||
@@ -900,6 +901,7 @@ if (tests)
|
||||
src/test/jtx/impl/amount.cpp
|
||||
src/test/jtx/impl/balance.cpp
|
||||
src/test/jtx/impl/check.cpp
|
||||
src/test/jtx/impl/cron.cpp
|
||||
src/test/jtx/impl/delivermin.cpp
|
||||
src/test/jtx/impl/deposit.cpp
|
||||
src/test/jtx/impl/envconfig.cpp
|
||||
|
||||
@@ -491,6 +491,7 @@ LedgerEntryTypesMatch::visitEntry(
|
||||
case ltNFTOKEN_PAGE:
|
||||
case ltNFTOKEN_OFFER:
|
||||
case ltURI_TOKEN:
|
||||
case ltCRON:
|
||||
case ltIMPORT_VLSEQ:
|
||||
case ltUNL_REPORT:
|
||||
break;
|
||||
|
||||
@@ -19,12 +19,9 @@
|
||||
|
||||
#include <ripple/app/tx/impl/SetCron.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/PublicKey.h>
|
||||
#include <ripple/protocol/Quality.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/protocol/st.h>
|
||||
|
||||
@@ -75,7 +72,7 @@ SetCron::preflight(PreflightContext const& ctx)
|
||||
auto delay = tx.getFieldU32(sfDelaySeconds);
|
||||
if (delay > 31536000UL /* 365 days in seconds */)
|
||||
{
|
||||
JLOG(j.debug()) << "SetCron: DelaySeconds was too high. (max 14 "
|
||||
JLOG(j.debug()) << "SetCron: DelaySeconds was too high. (max 365 "
|
||||
"days in seconds).";
|
||||
return temMALFORMED;
|
||||
}
|
||||
@@ -99,18 +96,6 @@ SetCron::preflight(PreflightContext const& ctx)
|
||||
TER
|
||||
SetCron::preclaim(PreclaimContext const& ctx)
|
||||
{
|
||||
if (!ctx.view.rules().enabled(featureCron))
|
||||
return temDISABLED;
|
||||
|
||||
auto& j = ctx.j;
|
||||
|
||||
auto const id = ctx.tx[sfAccount];
|
||||
|
||||
auto const sle = ctx.view.read(keylet::account(id));
|
||||
|
||||
if (!sle)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -244,22 +229,27 @@ SetCron::doApply()
|
||||
XRPAmount
|
||||
SetCron::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
auto fee = Transactor::calculateBaseFee(view, tx);
|
||||
auto const baseFee = Transactor::calculateBaseFee(view, tx);
|
||||
|
||||
auto const hasRepeat = tx.isFieldPresent(sfRepeatCount);
|
||||
auto const hasDelay = tx.isFieldPresent(sfDelaySeconds);
|
||||
|
||||
if (!hasRepeat && !hasDelay)
|
||||
// delete cron
|
||||
return baseFee;
|
||||
|
||||
// factor a cost based on the total number of txns expected
|
||||
// for RepeatCount of 0 we have this txn (SetCron) and the
|
||||
// single Cron txn (2). For a RepeatCount of 1 we have this txn,
|
||||
// the first time the cron executes, and the second time (3).
|
||||
uint32_t recur = tx.isFieldPresent(sfRepeatCount)
|
||||
? tx.getFieldU32(sfRepeatCount) + 2
|
||||
: 2;
|
||||
uint32_t const additionalExpectedExecutions =
|
||||
tx.getFieldU32(sfRepeatCount) + 1;
|
||||
auto const additionalFee = baseFee * additionalExpectedExecutions;
|
||||
|
||||
auto finalFee = fee * recur;
|
||||
if (baseFee + additionalFee < baseFee)
|
||||
return baseFee;
|
||||
|
||||
if (finalFee < fee)
|
||||
return fee;
|
||||
|
||||
return finalFee;
|
||||
return baseFee + additionalFee;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include <ripple/app/tx/impl/Transactor.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
278
src/test/app/Cron_test.cpp
Normal file
278
src/test/app/Cron_test.cpp
Normal file
@@ -0,0 +1,278 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2025 XRPL Labs
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/ledger/LedgerMaster.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include "ripple/protocol/Indexes.h"
|
||||
#include "ripple/protocol/TER.h"
|
||||
#include "ripple/protocol/TxFlags.h"
|
||||
#include "test/jtx/TestHelpers.h"
|
||||
#include "test/jtx/cron.h"
|
||||
#include <test/jtx.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
struct Cron_test : public beast::unit_test::suite
|
||||
{
|
||||
void
|
||||
testEnabled(FeatureBitset features)
|
||||
{
|
||||
testcase("enabled");
|
||||
using namespace jtx;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
// setup env
|
||||
auto const alice = Account("alice");
|
||||
auto const issuer = Account("issuer");
|
||||
|
||||
for (bool const withCron : {false, true})
|
||||
{
|
||||
// If the BalanceRewards amendment is not enabled, you should not be
|
||||
// able to claim rewards.
|
||||
auto const amend = withCron ? features : features - featureCron;
|
||||
Env env{*this, amend};
|
||||
|
||||
env.fund(XRP(1000), alice, issuer);
|
||||
env.close();
|
||||
|
||||
auto const expectResult =
|
||||
withCron ? ter(tesSUCCESS) : ter(temDISABLED);
|
||||
|
||||
auto tx = cron::set(alice);
|
||||
// CLAIM
|
||||
env(cron::set(alice), fee(XRP(1)), expectResult);
|
||||
env.close();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testFee(FeatureBitset features)
|
||||
{
|
||||
testcase("fee");
|
||||
using namespace jtx;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
auto const alice = Account("alice");
|
||||
Env env{*this, features | featureCron};
|
||||
|
||||
auto const baseFee = env.current()->fees().base;
|
||||
|
||||
env.fund(XRP(1000), alice);
|
||||
env.close();
|
||||
|
||||
// create with RepeatCount
|
||||
auto expected = baseFee * 2 + baseFee * 256;
|
||||
env(cron::set(alice),
|
||||
cron::delay(356 * 24 * 60 * 60),
|
||||
cron::repeat(256),
|
||||
fee(expected - 1),
|
||||
ter(telINSUF_FEE_P));
|
||||
env.close();
|
||||
|
||||
env(cron::set(alice),
|
||||
cron::delay(356 * 24 * 60 * 60),
|
||||
cron::repeat(256),
|
||||
fee(expected),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// create with no RepeatCount
|
||||
expected = baseFee * 2;
|
||||
env(cron::set(alice),
|
||||
cron::delay(356 * 24 * 60 * 60),
|
||||
fee(expected - 1),
|
||||
ter(telINSUF_FEE_P));
|
||||
env.close();
|
||||
|
||||
env(cron::set(alice),
|
||||
cron::delay(356 * 24 * 60 * 60),
|
||||
fee(expected),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// delete
|
||||
expected = baseFee;
|
||||
env(cron::set(alice), fee(expected - 1), ter(telINSUF_FEE_P));
|
||||
env.close();
|
||||
|
||||
env(cron::set(alice), fee(expected), ter(tesSUCCESS));
|
||||
env.close();
|
||||
}
|
||||
|
||||
void
|
||||
testInvalidPreflight(FeatureBitset features)
|
||||
{
|
||||
testcase("invalid preflight");
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
|
||||
auto const alice = Account("alice");
|
||||
|
||||
test::jtx::Env env{
|
||||
*this, network::makeNetworkConfig(21337), features | featureCron};
|
||||
|
||||
env.fund(XRP(1000), alice);
|
||||
env.close();
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// preflight
|
||||
|
||||
// temINVALID_FLAG
|
||||
// can have flag 1 set to opt-out of rewards
|
||||
{
|
||||
env(cron::set(alice), txflags(tfClose), ter(temINVALID_FLAG));
|
||||
env(cron::set(alice),
|
||||
txflags(tfUniversalMask),
|
||||
ter(temINVALID_FLAG));
|
||||
}
|
||||
|
||||
// temMALFORMED
|
||||
{
|
||||
// Invalid DelaySeconds and RepeatCount combination
|
||||
// (only RepeatCount specified)
|
||||
env(cron::set(alice), cron::repeat(256), ter(temMALFORMED));
|
||||
env.close();
|
||||
|
||||
// Invalid DelaySeconds
|
||||
env(cron::set(alice),
|
||||
cron::delay(365 * 24 * 60 * 60 + 1),
|
||||
cron::repeat(256),
|
||||
ter(temMALFORMED));
|
||||
env.close();
|
||||
|
||||
// Invalid RepeatCount
|
||||
env(cron::set(alice),
|
||||
cron::delay(365 * 24 * 60 * 60),
|
||||
cron::repeat(257),
|
||||
ter(temMALFORMED));
|
||||
env.close();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testInvalidPreclaim(FeatureBitset features)
|
||||
{
|
||||
testcase("invalid preclaim");
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
|
||||
// no preclaim checks exists
|
||||
BEAST_EXPECT(true);
|
||||
}
|
||||
|
||||
void
|
||||
testDoApply(FeatureBitset features)
|
||||
{
|
||||
testcase("doApply");
|
||||
using namespace jtx;
|
||||
using namespace std::literals::chrono_literals;
|
||||
auto const alice = Account("alice");
|
||||
Env env{*this, features | featureCron};
|
||||
|
||||
env.fund(XRP(1000), alice);
|
||||
env.close();
|
||||
|
||||
auto const aliceOwnerCount = ownerCount(env, alice);
|
||||
|
||||
// create cron
|
||||
env(cron::set(alice),
|
||||
cron::delay(356 * 24 * 60 * 60),
|
||||
cron::repeat(256),
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// increment owner count
|
||||
BEAST_EXPECT(ownerCount(env, alice) == aliceOwnerCount + 1);
|
||||
|
||||
auto const accSle = env.le(keylet::account(alice.id()));
|
||||
BEAST_EXPECT(accSle);
|
||||
BEAST_EXPECT(accSle->isFieldPresent(sfCron));
|
||||
|
||||
auto const cronKey = keylet::child(accSle->getFieldH256(sfCron));
|
||||
auto const cronSle = env.le(cronKey);
|
||||
BEAST_EXPECT(cronSle);
|
||||
BEAST_EXPECT(
|
||||
cronSle->getFieldU32(sfDelaySeconds) == 356 * 24 * 60 * 60);
|
||||
BEAST_EXPECT(cronSle->getFieldU32(sfRepeatCount) == 256);
|
||||
|
||||
// update cron
|
||||
env(cron::set(alice),
|
||||
cron::delay(100),
|
||||
cron::repeat(10),
|
||||
fee(XRP(1)),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// owner count does not change
|
||||
BEAST_EXPECT(ownerCount(env, alice) == aliceOwnerCount + 1);
|
||||
|
||||
auto const accSle2 = env.le(keylet::account(alice.id()));
|
||||
BEAST_EXPECT(accSle2);
|
||||
BEAST_EXPECT(accSle2->isFieldPresent(sfCron));
|
||||
|
||||
// old cron sle is deleted
|
||||
BEAST_EXPECT(!env.le(cronKey));
|
||||
|
||||
auto const cronKey2 = keylet::child(accSle2->getFieldH256(sfCron));
|
||||
auto const cronSle2 = env.le(cronKey2);
|
||||
BEAST_EXPECT(cronSle2);
|
||||
BEAST_EXPECT(cronSle2->getFieldU32(sfDelaySeconds) == 100);
|
||||
BEAST_EXPECT(cronSle2->getFieldU32(sfRepeatCount) == 10);
|
||||
|
||||
// delete cron
|
||||
env(cron::set(alice), fee(XRP(1)), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// owner count decremented
|
||||
BEAST_EXPECT(ownerCount(env, alice) == aliceOwnerCount);
|
||||
|
||||
auto const accSle3 = env.le(keylet::account(alice.id()));
|
||||
BEAST_EXPECT(accSle3);
|
||||
BEAST_EXPECT(!accSle3->isFieldPresent(sfCron));
|
||||
|
||||
// old cron sle is deleted
|
||||
BEAST_EXPECT(!env.le(cronKey2));
|
||||
}
|
||||
|
||||
void
|
||||
testWithFeats(FeatureBitset features)
|
||||
{
|
||||
testEnabled(features);
|
||||
testFee(features);
|
||||
testInvalidPreflight(features);
|
||||
testInvalidPreclaim(features);
|
||||
testDoApply(features);
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
using namespace test::jtx;
|
||||
auto const sa = supported_amendments();
|
||||
testWithFeats(sa);
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(Cron, app, ripple);
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/balance.h>
|
||||
#include <test/jtx/check.h>
|
||||
#include <test/jtx/cron.h>
|
||||
#include <test/jtx/delivermin.h>
|
||||
#include <test/jtx/deposit.h>
|
||||
#include <test/jtx/escrow.h>
|
||||
|
||||
74
src/test/jtx/cron.h
Normal file
74
src/test/jtx/cron.h
Normal file
@@ -0,0 +1,74 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2025 XRPL Labs
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TEST_JTX_CRON_H_INCLUDED
|
||||
#define RIPPLE_TEST_JTX_CRON_H_INCLUDED
|
||||
|
||||
#include <test/jtx/Account.h>
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
|
||||
/** Cron operations. */
|
||||
namespace cron {
|
||||
|
||||
/** Set a cron. */
|
||||
Json::Value
|
||||
set(jtx::Account const& account);
|
||||
|
||||
/** Sets the optional DelaySeconds on a JTx. */
|
||||
class delay
|
||||
{
|
||||
private:
|
||||
uint32_t delay_;
|
||||
|
||||
public:
|
||||
explicit delay(uint32_t delay) : delay_(delay)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
/** Sets the optional RepeatCount on a JTx. */
|
||||
class repeat
|
||||
{
|
||||
private:
|
||||
uint32_t repeat_;
|
||||
|
||||
public:
|
||||
explicit repeat(uint32_t repeat) : repeat_(repeat)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
} // namespace cron
|
||||
|
||||
} // namespace jtx
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_TEST_JTX_CRON_H_INCLUDED
|
||||
56
src/test/jtx/impl/cron.cpp
Normal file
56
src/test/jtx/impl/cron.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2025 XRPL Labs
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <test/jtx/cron.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
|
||||
namespace cron {
|
||||
|
||||
// Set a cron.
|
||||
Json::Value
|
||||
set(jtx::Account const& account)
|
||||
{
|
||||
using namespace jtx;
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::SetCron;
|
||||
jv[jss::Account] = account.human();
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
delay::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
jt.jv[sfDelaySeconds.jsonName] = delay_;
|
||||
}
|
||||
|
||||
void
|
||||
repeat::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
jt.jv[sfRepeatCount.jsonName] = repeat_;
|
||||
}
|
||||
|
||||
} // namespace cron
|
||||
|
||||
} // namespace jtx
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
Reference in New Issue
Block a user