xrpld
Loading...
Searching...
No Matches
apply_test.cpp
1// Copyright (c) 2020 Dev Null Productions
2
3#include <test/jtx/Account.h>
4#include <test/jtx/Env.h>
5#include <test/jtx/JTx.h>
6#include <test/jtx/TestHelpers.h>
7#include <test/jtx/amount.h>
8#include <test/jtx/fee.h>
9#include <test/jtx/noop.h>
10#include <test/jtx/sig.h>
11#include <test/jtx/sponsor.h>
12
13#include <xrpl/basics/Slice.h>
14#include <xrpl/basics/StringUtilities.h>
15#include <xrpl/beast/unit_test/suite.h>
16#include <xrpl/protocol/Feature.h>
17#include <xrpl/protocol/SField.h>
18#include <xrpl/protocol/STTx.h>
19#include <xrpl/protocol/Serializer.h>
20#include <xrpl/protocol/TxFlags.h>
21#include <xrpl/tx/apply.h>
22
23#include <functional>
24#include <memory>
25
26namespace xrpl {
27
29{
30public:
31 void
32 run() override
33 {
34 testcase("Require Fully Canonical Signature");
38 }
39
40 // forceValidity means the caller verified nothing and wants the result
41 // trusted, so it has to hold in both prefix eras. If it marked only the
42 // ordinary slot, a role-signature transaction would still be verified
43 // under pre-fix rules, defeating the cluster path and the configurations
44 // that turn signature checks off.
45 void
47 {
48 testcase("Forced validity ignores the prefix era");
49
50 using namespace test::jtx;
51
52 Env preFix{*this, testableAmendments() - fixCleanup3_4_0};
53 Env postFix{*this, testableAmendments()};
54 auto const preFixRules = preFix.current()->rules();
55
56 Account const alice{"alice"};
57 Account const sponsor{"sponsor"};
58 postFix.fund(XRP(10'000), alice, sponsor);
59 postFix.close();
60
61 // Signed under the post-fix rules, so this signature does not verify
62 // under the pre-fix prefix. Only the forced verdict can make the check
63 // below pass.
64 auto const jt = postFix.jt(
65 noop(alice),
66 Fee(XRP(1)),
67 sponsor::As(sponsor, spfSponsorFee),
68 Sig(sfSponsorSignature, sponsor));
69 if (!BEAST_EXPECT(jt.stx))
70 return;
71
72 // A router that has never seen this transaction, so the only cached
73 // state is what forceValidity writes.
74 auto& router = preFix.app().getHashRouter();
75 forceValidity(router, jt.stx->getTransactionID(), Validity::SigGoodOnly);
76 BEAST_EXPECT(checkValidity(router, *jt.stx, preFixRules).first != Validity::SigBad);
77 }
78
79 // A signature verdict reached under one prefix era must not be honored in
80 // the other, because the two eras require the sponsor signature to cover
81 // different bytes. Each direction below uses one HashRouter and differs
82 // only in the rules, which is what the flag ledger looks like in practice:
83 // relay and submit verify against the validated rules, which lag the open
84 // ledger rules that preflight2 verifies against, so one transaction gets
85 // checked under both prefixes at the same time.
86 void
88 {
89 testcase("Role signature cache is era specific");
90
91 using namespace test::jtx;
92
93 Env preFix{*this, testableAmendments() - fixCleanup3_4_0};
94 Env postFix{*this, testableAmendments()};
95 auto const preFixRules = preFix.current()->rules();
96 auto const postFixRules = postFix.current()->rules();
97
98 Account const alice{"alice"};
99 Account const sponsor{"sponsor"};
100 Account const counterparty{"counterparty"};
101 for (auto* env : {&preFix, &postFix})
102 {
103 env->fund(XRP(10'000), alice, sponsor, counterparty);
104 env->close();
105 }
106
107 // Both directions for a transaction whose role signature sits in the
108 // field that makeTx signs. makeTx builds the transaction in the Env it
109 // is given, so the role signature carries that era's prefix.
110 auto checkBothDirections = [&](std::function<JTx(test::jtx::Env&)> const& makeTx) {
111 // Direction 1: a good verdict under the old prefix must not let a
112 // signature moved between roles survive the amendment.
113 {
114 auto const jt = makeTx(preFix);
115 if (!BEAST_EXPECT(jt.stx))
116 return;
117
118 auto& router = preFix.app().getHashRouter();
119 BEAST_EXPECT(checkValidity(router, *jt.stx, preFixRules).first == Validity::Valid);
120
121 // Same router, asked again under the post-fix rules. The Valid
122 // verdict above was reached under the old prefix and must not
123 // be reused, or a signature moved between roles would survive
124 // the amendment.
125 BEAST_EXPECT(
126 checkValidity(router, *jt.stx, postFixRules).first == Validity::SigBad);
127 }
128
129 // Direction 2: a bad verdict under the old prefix must not condemn
130 // a transaction that the new prefixes accept. A node whose
131 // validated rules still lag the open ledger will run this check
132 // pre-fix first and reject a correctly new-prefix-signed
133 // transaction; the post-fix check must then verify it afresh
134 // instead of reusing the pre-fix verdict.
135 {
136 auto const jt = makeTx(postFix);
137 if (!BEAST_EXPECT(jt.stx))
138 return;
139
140 auto& router = postFix.app().getHashRouter();
141 BEAST_EXPECT(checkValidity(router, *jt.stx, preFixRules).first == Validity::SigBad);
142 BEAST_EXPECT(checkValidity(router, *jt.stx, postFixRules).first == Validity::Valid);
143 }
144 };
145
146 // sfSponsorSignature, which uses the SPN and SPM prefixes.
147 checkBothDirections([&](Env& env) {
148 return env.jt(
149 noop(alice),
150 Fee(XRP(1)),
151 sponsor::As(sponsor, spfSponsorFee),
152 Sig(sfSponsorSignature, sponsor));
153 });
154
155 // sfCounterpartySignature, which uses its own prefixes, CPT and CPM,
156 // and only appears on a LoanSet. The transaction does not have to be
157 // applicable: checkValidity verifies signatures without consulting the
158 // ledger, so a placeholder LoanBrokerID is enough.
159 checkBothDirections([&](Env& env) {
160 return env.jt(
161 loan::set(alice, UInt256{1}, Number{1}),
162 loan::kCounterparty(counterparty),
163 Fee(XRP(1)),
164 Sig(sfCounterpartySignature, counterparty));
165 });
166 }
167
168 void
170 {
171 // Construct a payments w/out a fully-canonical tx
172 std::string const nonFullyCanonicalTx =
173 "12000022000000002400000001201B00497D9C6140000000000F6950684000000"
174 "00000000C732103767C7B2C13AD90050A4263745E4BAB2B975417FA22E87780E1"
175 "506DDAF21139BE74483046022100E95670988A34C4DB0FA73A8BFD6383872AF43"
176 "8C147A62BC8387406298C3EADC1022100A7DC80508ED5A4750705C702A81CBF9D"
177 "2C2DC3AFEDBED37BBCCD97BC8C40E08F8114E25A26437D923EEF4D6D815DF9336"
178 "8B62E6440848314BB85996936E4F595287774684DC2AC6266024BEF";
179
180 auto ret = strUnHex(nonFullyCanonicalTx);
181 SerialIter sitTrans(makeSlice(*ret)); // NOLINT(bugprone-unchecked-optional-access)
182 STTx const tx = *std::make_shared<STTx const>(std::ref(sitTrans));
183
184 {
185 test::jtx::Env fullyCanonical(*this, test::jtx::testableAmendments());
186
187 Validity const valid =
189 fullyCanonical.app().getHashRouter(), tx, fullyCanonical.current()->rules())
190 .first;
191 if (valid == Validity::Valid)
192 fail("Non-Fully canonical signature was permitted");
193 }
194
195 pass();
196 }
197};
198
200
201} // namespace xrpl
A testsuite class.
Definition suite.h:52
void pass()
Record a successful test condition.
Definition suite.h:532
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:554
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
void testFullyCanonicalSigs()
void testForcedValidityIgnoresPrefixEra()
void testRoleSignatureCacheIsEraSpecific()
void run() override
Runs the suite.
Number is a floating point type that can represent a wide range of values.
Definition Number.h:351
virtual HashRouter & getHashRouter()=0
A transaction testing environment.
Definition Env.h:161
Application & app()
Definition Env.h:300
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:377
T make_shared(T... args)
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
FeatureBitset testableAmendments()
Definition Env.h:92
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
constexpr FlagValue spfSponsorFee
Definition TxFlags.h:465
Validity
Describes the pre-processing validity of a transaction.
Definition apply.h:24
@ SigBad
Signature is bad.
Definition apply.h:28
@ Valid
Signature and local checks are good / passed.
Definition apply.h:36
@ SigGoodOnly
Signature is good, but local checks fail.
Definition apply.h:32
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules)
Checks transaction signature and local checks.
Definition apply.cpp:62
Slice makeSlice(std::array< T, N > const &a)
Definition Slice.h:228
void forceValidity(HashRouter &router, UInt256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
Definition apply.cpp:141
BaseUInt< 256 > UInt256
Definition base_uint.h:580
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, xrpl)
T ref(T... args)