@@ -2359,6 +2359,69 @@ CScript calculate_contract(const CScript& federationRedeemScript, const CScript&
23592359 return scriptDestination;
23602360}
23612361
2362+ template <typename T>
2363+ static bool GetBlockAndTxFromMerkleBlock (uint256& block_hash, uint256& tx_hash, T& merkle_block, const std::vector<unsigned char >& merkle_block_raw)
2364+ {
2365+ try {
2366+ std::vector<uint256> txHashes;
2367+ std::vector<unsigned int > txIndices;
2368+ CDataStream merkleBlockStream (merkle_block_raw, SER_NETWORK, PROTOCOL_VERSION);
2369+ merkleBlockStream >> merkle_block;
2370+ block_hash = merkle_block.header .GetHash ();
2371+
2372+ if (!merkleBlockStream.empty ()) {
2373+ return false ;
2374+ }
2375+ if (merkle_block.txn .ExtractMatches (txHashes, txIndices) != merkle_block.header .hashMerkleRoot || txHashes.size () != 1 ) {
2376+ return false ;
2377+ }
2378+ tx_hash = txHashes[0 ];
2379+ } catch (std::exception& e) {
2380+ // Invalid encoding of merkle block
2381+ return false ;
2382+ }
2383+ return true ;
2384+ }
2385+
2386+ template <typename T>
2387+ static bool CheckPeginTx (const std::vector<unsigned char >& tx_data, T& pegtx, const COutPoint& prevout, const CAmount claim_amount, const CScript& claim_script)
2388+ {
2389+ try {
2390+ CDataStream pegtx_stream (tx_data, SER_NETWORK, PROTOCOL_VERSION);
2391+ pegtx_stream >> pegtx;
2392+ if (!pegtx_stream.empty ()) {
2393+ return false ;
2394+ }
2395+ } catch (std::exception& e) {
2396+ // Invalid encoding of transaction
2397+ return false ;
2398+ }
2399+
2400+ // Check that transaction matches txid
2401+ if (pegtx->GetHash () != prevout.hash ) {
2402+ return false ;
2403+ }
2404+
2405+ if (prevout.n >= pegtx->vout .size ()) {
2406+ return false ;
2407+ }
2408+ CAmount amount = pegtx->vout [prevout.n ].nValue ;
2409+ // Check the transaction nout/value matches
2410+ if (claim_amount != amount) {
2411+ return false ;
2412+ }
2413+
2414+ // Check that the witness program matches the p2ch on the p2sh-p2wsh transaction output
2415+ CScript tweaked_fedpegscript = calculate_contract (Params ().GetConsensus ().fedpegScript , claim_script);
2416+ CScript witness_output (GetScriptForWitness (tweaked_fedpegscript));
2417+ CScript expected_script (CScript () << OP_HASH160 << ToByteVector (CScriptID (witness_output)) << OP_EQUAL);
2418+ if (pegtx->vout [prevout.n ].scriptPubKey != expected_script) {
2419+ return false ;
2420+ }
2421+
2422+ return true ;
2423+ }
2424+
23622425bool IsValidPeginWitness (const CScriptWitness& pegin_witness, const COutPoint& prevout, bool check_depth) {
23632426
23642427 // Format on stack is as follows:
@@ -2409,45 +2472,27 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p
24092472 return false ;
24102473 }
24112474
2412- // Get serialized transaction
2413- Sidechain::Bitcoin::CTransactionRef pegtx;
2414- try {
2415- CDataStream pegtx_stream (stack[4 ], SER_NETWORK, PROTOCOL_VERSION);
2416- pegtx_stream >> pegtx;
2417- if (!pegtx_stream.empty ()) {
2418- return false ;
2419- }
2420- } catch (std::exception& e) {
2421- // Invalid encoding of transaction
2422- return false ;
2423- }
2475+ uint256 block_hash;
2476+ uint256 tx_hash;
24242477
24252478 // Get txout proof
24262479 Sidechain::Bitcoin::CMerkleBlock merkle_block;
2427- std::vector<uint256> txHashes;
2428- std::vector<unsigned int > txIndices;
2429-
2430- try {
2431- CDataStream merkleBlockStream (stack[5 ], SER_NETWORK, PROTOCOL_VERSION);
2432- merkleBlockStream >> merkle_block;
2433- if (!merkleBlockStream.empty () || !CheckBitcoinProof (merkle_block.header .GetHash (), merkle_block.header .nBits )) {
2434- return false ;
2435- }
2436- if (merkle_block.txn .ExtractMatches (txHashes, txIndices) != merkle_block.header .hashMerkleRoot || txHashes.size () != 1 ) {
2437- return false ;
2438- }
2439- } catch (std::exception& e) {
2440- // Invalid encoding of merkle block
2480+ if (!GetBlockAndTxFromMerkleBlock (block_hash, tx_hash, merkle_block, stack[5 ])) {
2481+ return false ;
2482+ }
2483+ // TODO do this before to prevent DoS ?
2484+ if (!CheckBitcoinProof (block_hash, merkle_block.header .nBits )) {
24412485 return false ;
24422486 }
24432487
2444- // Check that transaction matches txid
2445- if (pegtx->GetHash () != prevout.hash ) {
2488+ // Get serialized transaction
2489+ Sidechain::Bitcoin::CTransactionRef pegtx;
2490+ if (!CheckPeginTx (stack[4 ], pegtx, prevout, value, claim_script)) {
24462491 return false ;
24472492 }
24482493
24492494 // Check that the merkle proof corresponds to the txid
2450- if (prevout.hash != txHashes[ 0 ] ) {
2495+ if (prevout.hash != tx_hash ) {
24512496 return false ;
24522497 }
24532498
@@ -2461,22 +2506,9 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p
24612506 return false ;
24622507 }
24632508
2464- // Check the transaction nout/value matches
2465- if (prevout.n >= pegtx->vout .size () || value != pegtx->vout [prevout.n ].nValue ) {
2466- return false ;
2467- }
2468-
2469- // Check that the witness program matches the p2ch on the p2sh-p2wsh transaction output
2470- CScript tweaked_fedpegscript = calculate_contract (Params ().GetConsensus ().fedpegScript , claim_script);
2471- CScript witness_output (GetScriptForWitness (tweaked_fedpegscript));
2472- CScript expected_script (CScript () << OP_HASH160 << ToByteVector (CScriptID (witness_output)) << OP_EQUAL);
2473- if (pegtx->vout [prevout.n ].scriptPubKey != expected_script) {
2474- return false ;
2475- }
2476-
24772509 // Finally, validate peg-in via rpc call
24782510 if (check_depth && GetBoolArg (" -validatepegin" , DEFAULT_VALIDATE_PEGIN)) {
2479- return IsConfirmedBitcoinBlock (merkle_block. header . GetHash () , Params ().GetConsensus ().pegin_min_depth );
2511+ return IsConfirmedBitcoinBlock (block_hash , Params ().GetConsensus ().pegin_min_depth );
24802512 }
24812513 return true ;
24822514}
0 commit comments