mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
Add Batch feature (XLS-56) (#5060)
- Specification: [XRPLF/XRPL-Standards 56](https://github.com/XRPLF/XRPL-Standards/blob/master/XLS-0056d-batch/README.md) - Amendment: `Batch` - Implements execution of multiple transactions within a single batch transaction with four execution modes: `tfAllOrNothing`, `tfOnlyOne`, `tfUntilFailure`, and `tfIndependent`. - Enables atomic multi-party transactions where multiple accounts can participate in a single batch, with up to 8 inner transactions and 8 batch signers per batch transaction. - Inner transactions use `tfInnerBatchTxn` flag with zero fees, no signature, and empty signing public key. - Inner transactions are applied after the outer batch succeeds via the `applyBatchTransactions` function in apply.cpp. - Network layer prevents relay of transactions with `tfInnerBatchTxn` flag - each peer applies inner transactions locally from the batch. - Batch transactions are excluded from AccountDelegate permissions but inner transactions retain full delegation support. - Metadata includes `ParentBatchID` linking inner transactions to their containing batch for traceability and auditing. - Extended STTx with batch-specific signature verification methods and added protocol structures (`sfRawTransactions`, `sfBatchSigners`).
This commit is contained in:
@@ -2132,6 +2132,127 @@ public:
|
||||
result[jss::result][jss::request][jss::command] == "bad_command");
|
||||
}
|
||||
|
||||
void
|
||||
testAutoFillFails()
|
||||
{
|
||||
testcase("autofill fails");
|
||||
using namespace test::jtx;
|
||||
|
||||
// test batch raw transactions max size
|
||||
{
|
||||
Env env(*this);
|
||||
auto ledger = env.current();
|
||||
auto const& feeTrack = env.app().getFeeTrack();
|
||||
Json::Value req;
|
||||
Account const alice("alice");
|
||||
Account const bob("bob");
|
||||
env.fund(XRP(100000), alice);
|
||||
env.close();
|
||||
|
||||
auto const batchFee = batch::calcBatchFee(env, 0, 2);
|
||||
auto const seq = env.seq(alice);
|
||||
auto jt = env.jtnofill(
|
||||
batch::outer(alice, env.seq(alice), batchFee, tfAllOrNothing),
|
||||
batch::inner(pay(alice, bob, XRP(1)), seq + 1),
|
||||
batch::inner(pay(alice, bob, XRP(2)), seq + 2),
|
||||
batch::inner(pay(alice, bob, XRP(3)), seq + 3),
|
||||
batch::inner(pay(alice, bob, XRP(4)), seq + 4),
|
||||
batch::inner(pay(alice, bob, XRP(5)), seq + 5),
|
||||
batch::inner(pay(alice, bob, XRP(6)), seq + 6),
|
||||
batch::inner(pay(alice, bob, XRP(7)), seq + 7),
|
||||
batch::inner(pay(alice, bob, XRP(8)), seq + 8),
|
||||
batch::inner(pay(alice, bob, XRP(9)), seq + 9));
|
||||
|
||||
jt.jv.removeMember(jss::Fee);
|
||||
jt.jv.removeMember(jss::TxnSignature);
|
||||
req[jss::tx_json] = jt.jv;
|
||||
Json::Value result = checkFee(
|
||||
req,
|
||||
Role::ADMIN,
|
||||
true,
|
||||
env.app().config(),
|
||||
feeTrack,
|
||||
env.app().getTxQ(),
|
||||
env.app());
|
||||
BEAST_EXPECT(result.size() == 0);
|
||||
BEAST_EXPECT(
|
||||
req[jss::tx_json].isMember(jss::Fee) &&
|
||||
req[jss::tx_json][jss::Fee] ==
|
||||
env.current()->fees().base.jsonClipped());
|
||||
}
|
||||
|
||||
// test signers max size
|
||||
{
|
||||
Env env(*this);
|
||||
auto ledger = env.current();
|
||||
auto const& feeTrack = env.app().getFeeTrack();
|
||||
Json::Value req;
|
||||
Account const alice("alice");
|
||||
Account const bob("bob");
|
||||
env.fund(XRP(100000), alice, bob);
|
||||
env.close();
|
||||
|
||||
auto jt = env.jtnofill(
|
||||
noop(alice),
|
||||
msig(
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice,
|
||||
alice));
|
||||
|
||||
req[jss::tx_json] = jt.jv;
|
||||
Json::Value result = checkFee(
|
||||
req,
|
||||
Role::ADMIN,
|
||||
true,
|
||||
env.app().config(),
|
||||
feeTrack,
|
||||
env.app().getTxQ(),
|
||||
env.app());
|
||||
BEAST_EXPECT(result.size() == 0);
|
||||
BEAST_EXPECT(
|
||||
req[jss::tx_json].isMember(jss::Fee) &&
|
||||
req[jss::tx_json][jss::Fee] ==
|
||||
env.current()->fees().base.jsonClipped());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testAutoFillFees()
|
||||
{
|
||||
@@ -2785,6 +2906,7 @@ public:
|
||||
run() override
|
||||
{
|
||||
testBadRpcCommand();
|
||||
testAutoFillFails();
|
||||
testAutoFillFees();
|
||||
testAutoFillEscalatedFees();
|
||||
testAutoFillNetworkID();
|
||||
|
||||
Reference in New Issue
Block a user