mirror of
https://github.com/Xahau/xahaud.git
synced 2026-04-29 15:37:46 +00:00
feat: add XPOP test helper and XPOP_test suite
- src/test/jtx/xpop.h: test utilities for building XPOPs from Env ledgers (TestValidator, TestVLPublisher, TestXPOPContext, buildTestXPOP) - src/test/app/XPOP_test.cpp: 4 tests (173 assertions) - LedgerProof construction from payment tx - XPOP v1 JSON structure verification - Merkle proof verification for multi-tx ledgers - Full Import round-trip: source Env payment → XPOP → dest Env Import → tesSUCCESS
This commit is contained in:
@@ -18,11 +18,13 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/import.h>
|
||||
#include <test/jtx/xpop.h>
|
||||
#include <xrpld/app/ledger/LedgerMaster.h>
|
||||
#include <xrpld/app/proof/LedgerProof.h>
|
||||
#include <xrpld/app/proof/ProofBuilder.h>
|
||||
#include <xrpld/app/proof/XPOPv1.h>
|
||||
#include <xrpl/protocol/Import.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
namespace ripple {
|
||||
@@ -220,12 +222,76 @@ struct XPOP_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(proofCount >= 3);
|
||||
}
|
||||
|
||||
void
|
||||
testImportWithGeneratedXPOP()
|
||||
{
|
||||
testcase("Import accepts dynamically generated XPOP");
|
||||
|
||||
using namespace jtx;
|
||||
|
||||
// Create XPOP context (VL publisher + validators).
|
||||
auto const xpopCtx = xpop::TestXPOPContext::create(3);
|
||||
|
||||
// --- Source "network": generate a payment and build XPOP ---
|
||||
Env srcEnv{*this};
|
||||
Account const alice{"alice"};
|
||||
Account const bob{"bob"};
|
||||
|
||||
srcEnv.fund(XRP(10000), alice, bob);
|
||||
srcEnv.close();
|
||||
|
||||
// Import requires: no sfNetworkID + sfOperationLimit = dest NETWORK_ID.
|
||||
Json::Value payTx;
|
||||
payTx[jss::TransactionType] = jss::Payment;
|
||||
payTx[jss::Account] = alice.human();
|
||||
payTx[jss::Destination] = bob.human();
|
||||
payTx[jss::Amount] = "100000000";
|
||||
payTx[sfOperationLimit.jsonName] = 21337;
|
||||
srcEnv(payTx, fee(XRP(1)));
|
||||
srcEnv.close();
|
||||
|
||||
// Find the tx hash and build the XPOP.
|
||||
auto const srcLcl = srcEnv.app().getLedgerMaster().getClosedLedger();
|
||||
BEAST_EXPECT(srcLcl);
|
||||
|
||||
uint256 paymentHash;
|
||||
srcLcl->txMap().visitLeaves(
|
||||
[&](boost::intrusive_ptr<SHAMapItem const> const& item) {
|
||||
paymentHash = item->key();
|
||||
});
|
||||
|
||||
auto const xpopJson = xpopCtx.buildXPOP(*srcLcl, paymentHash);
|
||||
BEAST_EXPECT(!xpopJson.isNull());
|
||||
|
||||
// --- Destination "network": import the XPOP ---
|
||||
Env dstEnv{*this, xpopCtx.makeEnvConfig(21337)};
|
||||
|
||||
// Burn some XRP so B2M can credit.
|
||||
auto const master = Account("masterpassphrase");
|
||||
dstEnv(noop(master), fee(10'000'000'000), ter(tesSUCCESS));
|
||||
dstEnv.close();
|
||||
|
||||
Account const importAlice{"alice"};
|
||||
dstEnv.fund(XRP(1000), importAlice);
|
||||
dstEnv.close();
|
||||
|
||||
auto const feeDrops = dstEnv.current()->fees().base;
|
||||
|
||||
// Submit the import — should succeed (B2M path).
|
||||
dstEnv(
|
||||
import::import(importAlice, xpopJson),
|
||||
fee(feeDrops * 10),
|
||||
ter(tesSUCCESS));
|
||||
dstEnv.close();
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testBuildLedgerProof();
|
||||
testBuildXPOPv1();
|
||||
testMerkleProofVerification();
|
||||
testImportWithGeneratedXPOP();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -100,7 +100,8 @@ struct TestVLPublisher
|
||||
buildVLData(
|
||||
std::vector<TestValidator> const& validators,
|
||||
std::uint32_t sequence = 1,
|
||||
std::uint32_t expiration = 0xFFFFFFFF) const
|
||||
std::uint32_t expiration =
|
||||
767784645) const // ~2024, matches Import_test
|
||||
{
|
||||
// Build the JSON blob
|
||||
std::string data = "{\"sequence\":" + std::to_string(sequence) +
|
||||
@@ -126,30 +127,72 @@ struct TestVLPublisher
|
||||
}
|
||||
};
|
||||
|
||||
/// Everything needed to build and import XPOPs in tests.
|
||||
struct TestXPOPContext
|
||||
{
|
||||
std::vector<TestValidator> validators;
|
||||
TestVLPublisher publisher;
|
||||
proof::VLData vlData;
|
||||
|
||||
static TestXPOPContext
|
||||
create(int validatorCount = 5)
|
||||
{
|
||||
auto pub = TestVLPublisher::create();
|
||||
std::vector<TestValidator> vals;
|
||||
for (int i = 0; i < validatorCount; ++i)
|
||||
vals.push_back(TestValidator::create());
|
||||
auto vl = pub.buildVLData(vals);
|
||||
return {std::move(vals), std::move(pub), std::move(vl)};
|
||||
}
|
||||
|
||||
/// Get the VL master public key hex for IMPORT_VL_KEYS config.
|
||||
std::string
|
||||
vlKeyHex() const
|
||||
{
|
||||
return strHex(publisher.masterPublic);
|
||||
}
|
||||
|
||||
/// Build an Env config with NETWORK_ID and IMPORT_VL_KEYS set.
|
||||
std::unique_ptr<Config>
|
||||
makeEnvConfig(std::uint32_t networkID = 21337) const
|
||||
{
|
||||
auto cfg = envconfig(jtx::validator, "");
|
||||
cfg->NETWORK_ID = networkID;
|
||||
auto const keyHex = vlKeyHex();
|
||||
auto const pkHex = strUnHex(keyHex);
|
||||
if (pkHex)
|
||||
cfg->IMPORT_VL_KEYS.emplace(keyHex, makeSlice(*pkHex));
|
||||
return cfg;
|
||||
}
|
||||
|
||||
/// Build XPOP from a closed ledger for a specific tx.
|
||||
Json::Value
|
||||
buildXPOP(Ledger const& ledger, uint256 const& txHash) const
|
||||
{
|
||||
std::vector<proof::ValidatorKeys> valKeys;
|
||||
for (auto const& v : validators)
|
||||
valKeys.push_back(v.toValidatorKeys());
|
||||
return proof::buildXPOPv1(ledger, txHash, valKeys, vlData);
|
||||
}
|
||||
|
||||
/// Build XPOP from an Env's last closed ledger.
|
||||
Json::Value
|
||||
buildXPOP(Env& env, uint256 const& txHash) const
|
||||
{
|
||||
auto const lcl = env.app().getLedgerMaster().getClosedLedger();
|
||||
if (!lcl)
|
||||
return {};
|
||||
return buildXPOP(*lcl, txHash);
|
||||
}
|
||||
};
|
||||
|
||||
/// Build a complete XPOP v1 JSON from an Env's last closed ledger.
|
||||
/// Creates fresh validator keys and VL publisher for each call.
|
||||
inline Json::Value
|
||||
buildTestXPOP(Env& env, uint256 const& txHash, int validatorCount = 5)
|
||||
{
|
||||
// Create validators
|
||||
std::vector<TestValidator> validators;
|
||||
std::vector<proof::ValidatorKeys> valKeys;
|
||||
for (int i = 0; i < validatorCount; ++i)
|
||||
{
|
||||
validators.push_back(TestValidator::create());
|
||||
valKeys.push_back(validators.back().toValidatorKeys());
|
||||
}
|
||||
|
||||
// Create VL publisher
|
||||
auto const publisher = TestVLPublisher::create();
|
||||
auto const vlData = publisher.buildVLData(validators);
|
||||
|
||||
// Build XPOP from the last closed ledger
|
||||
auto const lcl = env.app().getLedgerMaster().getClosedLedger();
|
||||
if (!lcl)
|
||||
return {};
|
||||
|
||||
return proof::buildXPOPv1(*lcl, txHash, valKeys, vlData);
|
||||
auto ctx = TestXPOPContext::create(validatorCount);
|
||||
return ctx.buildXPOP(env, txHash);
|
||||
}
|
||||
|
||||
/// Get the hex-encoded XPOP blob suitable for sfBlob in ttIMPORT.
|
||||
|
||||
Reference in New Issue
Block a user