From a5bab40247dad9aa19026d562d42aa03e901cade Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Tue, 14 Jul 2026 19:04:59 +0700 Subject: [PATCH] test(export): cover wrong relay signer charging --- .../consensus/ConsensusExtensions_test.cpp | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/test/consensus/ConsensusExtensions_test.cpp b/src/test/consensus/ConsensusExtensions_test.cpp index 1b7adf50b..4daeac864 100644 --- a/src/test/consensus/ConsensusExtensions_test.cpp +++ b/src/test/consensus/ConsensusExtensions_test.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,34 @@ namespace test { namespace { +Manifest +makeValidatorManifest( + SecretKey const& masterSecret, + SecretKey const& signingSecret) +{ + auto const master = derivePublicKey(KeyType::secp256k1, masterSecret); + auto const signing = derivePublicKey(KeyType::secp256k1, signingSecret); + STObject object{sfGeneric}; + object.setFieldU32(sfSequence, 0); + object.setFieldVL(sfPublicKey, master.slice()); + object.setFieldVL(sfSigningPubKey, signing.slice()); + sign(object, HashPrefix::manifest, KeyType::secp256k1, signingSecret); + sign( + object, + HashPrefix::manifest, + KeyType::secp256k1, + masterSecret, + sfMasterSignature); + + Serializer serialized; + object.add(serialized); + auto manifest = deserializeManifest(std::string{ + static_cast(serialized.data()), serialized.size()}); + if (!manifest) + Throw("failed to build validator manifest"); + return std::move(*manifest); +} + class ActiveNoopSink : public beast::Journal::Sink { public: @@ -3733,6 +3762,21 @@ class ConsensusExtensions_test : public beast::unit_test::suite valKeys.keys->publicKey, signature}; + auto const foreignMasterSecret = + generateSecretKey(KeyType::secp256k1, randomSeed()); + auto const foreignSigningSecret = + generateSecretKey(KeyType::secp256k1, randomSeed()); + auto const foreignSigningKey = + derivePublicKey(KeyType::secp256k1, foreignSigningSecret); + BEAST_EXPECT( + env.app().validatorManifests().applyManifest(makeValidatorManifest( + foreignMasterSecret, foreignSigningSecret)) == + ManifestDisposition::accepted); + auto wrongSigner = share; + wrongSigner.signingKey = foreignSigningKey; + wrongSigner.signature = ExportResultBuilder::signExportedTxn( + release.value(), foreignSigningKey, foreignSigningSecret); + auto wsc = makeWSClient(env.app().config()); Json::Value stream; stream[jss::streams] = Json::arrayValue; @@ -3808,12 +3852,16 @@ class ConsensusExtensions_test : public beast::unit_test::suite BEAST_EXPECT(admission.disposition == ExportShareDisposition::deferred); BEAST_EXPECT(deferredCount() == 2); + admission = ce.onExportShare(wrongSigner, deferredCharge); + BEAST_EXPECT(admission.disposition == ExportShareDisposition::deferred); + BEAST_EXPECT(deferredCount() == 3); + auto beyondHorizon = share; beyondHorizon.originLedgerSeq = universe->info().seq + ConsensusExtensions::maxDeferredExportShareFutureLedgers_ + 1; admission = ce.onExportShare(beyondHorizon, deferredCharge); BEAST_EXPECT(admission.disposition == ExportShareDisposition::deferred); - BEAST_EXPECT(deferredCount() == 2); + BEAST_EXPECT(deferredCount() == 3); installValidated(originLedger); @@ -3883,6 +3931,10 @@ class ConsensusExtensions_test : public beast::unit_test::suite BEAST_EXPECT(admission.disposition == ExportShareDisposition::invalid); BEAST_EXPECT(admission.charge == ExportShareCharge::invalidData); + admission = ce.onExportShare(wrongSigner, {}); + BEAST_EXPECT(admission.disposition == ExportShareDisposition::invalid); + BEAST_EXPECT(admission.charge == ExportShareCharge::invalidData); + auto invalidSignature = share; invalidSignature.signature = sign( valKeys.keys->publicKey, @@ -3893,7 +3945,7 @@ class ConsensusExtensions_test : public beast::unit_test::suite BEAST_EXPECT(admission.charge == ExportShareCharge::invalidSignature); BEAST_EXPECT(deferredCount() == 0); - BEAST_EXPECT(deferredCharges.load(std::memory_order_relaxed) == 1); + BEAST_EXPECT(deferredCharges.load(std::memory_order_relaxed) == 2); BEAST_EXPECT( lastDeferredCharge.load(std::memory_order_relaxed) == ExportShareCharge::invalidData);