1111#include " base58.h"
1212#include " netbase.h"
1313#include " messagesigner.h"
14+ #include " policy/policy.h"
1415#include " keystore.h"
1516#include " spork.h"
1617
@@ -65,8 +66,6 @@ static std::vector<COutPoint> SelectUTXOs(SimpleUTXOMap& utoxs, CAmount amount,
6566
6667static void FundTransaction (CMutableTransaction& tx, SimpleUTXOMap& utoxs, const CScript& scriptPayout, CAmount amount, const CKey& coinbaseKey)
6768{
68- CScript scriptPubKey = CScript () << ToByteVector (coinbaseKey.GetPubKey ()) << OP_CHECKSIG;
69-
7069 CAmount change;
7170 auto inputs = SelectUTXOs (utoxs, amount, change);
7271 for (size_t i = 0 ; i < inputs.size (); i++) {
@@ -183,6 +182,22 @@ static CMutableTransaction CreateProUpRevTx(SimpleUTXOMap& utxos, const uint256&
183182 return tx;
184183}
185184
185+ template <typename ProTx>
186+ static CMutableTransaction MalleateProTxPayout (const CMutableTransaction& tx)
187+ {
188+ ProTx proTx;
189+ GetTxPayload (tx, proTx);
190+
191+ CKey key;
192+ key.MakeNewKey (false );
193+ proTx.scriptPayout = GetScriptForDestination (key.GetPubKey ().GetID ());
194+
195+ CMutableTransaction tx2 = tx;
196+ SetTxPayload (tx2, proTx);
197+
198+ return tx2;
199+ }
200+
186201static CScript GenerateRandomAddress ()
187202{
188203 CKey key;
@@ -208,6 +223,21 @@ static CDeterministicMNCPtr FindPayoutDmn(const CBlock& block)
208223 return nullptr ;
209224}
210225
226+ static bool CheckTransactionSignature (const CMutableTransaction& tx)
227+ {
228+ for (unsigned int i = 0 ; i < tx.vin .size (); i++) {
229+ const auto & txin = tx.vin [i];
230+ CTransactionRef txFrom;
231+ uint256 hashBlock;
232+ BOOST_ASSERT (GetTransaction (txin.prevout .hash , txFrom, Params ().GetConsensus (), hashBlock));
233+
234+ if (!VerifyScript (txin.scriptSig , txFrom->vout [txin.prevout .n ].scriptPubKey , STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker (&tx, i))) {
235+ return false ;
236+ }
237+ }
238+ return true ;
239+ }
240+
211241BOOST_AUTO_TEST_SUITE (evo_dip3_activation_tests)
212242
213243BOOST_FIXTURE_TEST_CASE(dip3_activation, TestChainDIP3BeforeActivationSetup)
@@ -268,6 +298,20 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChainDIP3Setup)
268298 dmnHashes.emplace_back (tx.GetHash ());
269299 ownerKeys.emplace (tx.GetHash (), ownerKey);
270300 operatorKeys.emplace (tx.GetHash (), operatorKey);
301+
302+ // also verify that payloads are not malleable after they have been signed
303+ // the form of ProRegTx we use here is one with a collateral included, so there is no signature inside the
304+ // payload itself. This means, we need to rely on script verification, which takes the hash of the extra payload
305+ // into account
306+ auto tx2 = MalleateProTxPayout<CProRegTx>(tx);
307+ CValidationState dummyState;
308+ // Technically, the payload is still valid...
309+ BOOST_ASSERT (CheckProRegTx (tx, chainActive.Tip (), dummyState));
310+ BOOST_ASSERT (CheckProRegTx (tx2, chainActive.Tip (), dummyState));
311+ // But the signature should not verify anymore
312+ BOOST_ASSERT (CheckTransactionSignature (tx));
313+ BOOST_ASSERT (!CheckTransactionSignature (tx2));
314+
271315 CreateAndProcessBlock ({tx}, coinbaseKey);
272316 deterministicMNManager->UpdatedBlockTip (chainActive.Tip ());
273317
@@ -362,6 +406,14 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChainDIP3Setup)
362406 newOperatorKey.MakeNewKey ();
363407 dmn = deterministicMNManager->GetListAtChainTip ().GetMN (dmnHashes[0 ]);
364408 tx = CreateProUpRegTx (utxos, dmnHashes[0 ], ownerKeys[dmnHashes[0 ]], newOperatorKey.GetPublicKey (), ownerKeys[dmnHashes[0 ]].GetPubKey ().GetID (), dmn->pdmnState ->scriptPayout , coinbaseKey);
409+ // check malleability protection again, but this time by also relying on the signature inside the ProUpRegTx
410+ auto tx2 = MalleateProTxPayout<CProUpRegTx>(tx);
411+ CValidationState dummyState;
412+ BOOST_ASSERT (CheckProUpRegTx (tx, chainActive.Tip (), dummyState));
413+ BOOST_ASSERT (!CheckProUpRegTx (tx2, chainActive.Tip (), dummyState));
414+ BOOST_ASSERT (CheckTransactionSignature (tx));
415+ BOOST_ASSERT (!CheckTransactionSignature (tx2));
416+ // now process the block
365417 CreateAndProcessBlock ({tx}, coinbaseKey);
366418 deterministicMNManager->UpdatedBlockTip (chainActive.Tip ());
367419 BOOST_ASSERT (chainActive.Height () == nHeight + 1 );
0 commit comments