diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index 26c63c6092..ca8eba22a4 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -243,7 +243,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe } namespace Consensus { -bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set>& setPeginsSpent, std::vector *pvChecks, const bool cacheStore, bool fScriptChecks) +bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set>& setPeginsSpent, std::vector *pvChecks, const bool cacheStore, bool fScriptChecks, const std::vector& fedpegscripts) { // are the actual inputs available? if (!inputs.HaveInputs(tx)) { @@ -258,7 +258,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins if (tx.vin[i].m_is_pegin) { // Check existence and validity of pegin witness std::string err; - if (tx.witness.vtxinwit.size() <= i || !IsValidPeginWitness(tx.witness.vtxinwit[i].m_pegin_witness, prevout, err, true)) { + if (tx.witness.vtxinwit.size() <= i || !IsValidPeginWitness(tx.witness.vtxinwit[i].m_pegin_witness, fedpegscripts, prevout, err, true)) { return state.DoS(0, false, REJECT_PEGIN, "bad-pegin-witness", false, err); } std::pair pegin = std::make_pair(uint256(tx.witness.vtxinwit[i].m_pegin_witness.stack[2]), prevout); diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h index 767531e88e..9866f9521d 100644 --- a/src/consensus/tx_verify.h +++ b/src/consensus/tx_verify.h @@ -31,7 +31,7 @@ namespace Consensus { * @param[out] fee_map Set to the transaction fee if successful. * Preconditions: tx.IsCoinBase() is false. */ -bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set>& setPeginsSpent, std::vector *pvChecks, const bool cacheStore, bool fScriptChecks); +bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set>& setPeginsSpent, std::vector *pvChecks, const bool cacheStore, bool fScriptChecks, const std::vector& fedpegscripts); } // namespace Consensus /** Auxiliary functions for transaction validation (ideally should not be exposed) */ diff --git a/src/pegins.cpp b/src/pegins.cpp index 79fe24d5dc..9201913976 100644 --- a/src/pegins.cpp +++ b/src/pegins.cpp @@ -141,7 +141,7 @@ CScript calculate_contract(const CScript& federation_script, const CScript& scri } template -static bool CheckPeginTx(const std::vector& tx_data, T& pegtx, const COutPoint& prevout, const CAmount claim_amount, const CScript& claim_script) +static bool CheckPeginTx(const std::vector& tx_data, T& pegtx, const COutPoint& prevout, const CAmount claim_amount, const CScript& claim_script, const std::vector& fedpegscripts) { try { CDataStream pegtx_stream(tx_data, SER_NETWORK, PROTOCOL_VERSION); @@ -172,14 +172,16 @@ static bool CheckPeginTx(const std::vector& tx_data, T& pegtx, co } // Check that the witness program matches the p2ch on the p2sh-p2wsh transaction output - CScript tweaked_fedpegscript = calculate_contract(Params().GetConsensus().fedpegScript, claim_script); - CScript witness_output(GetScriptForWitness(tweaked_fedpegscript)); - CScript expected_script(CScript() << OP_HASH160 << ToByteVector(ScriptHash(CScriptID(witness_output))) << OP_EQUAL); - if (pegtx->vout[prevout.n].scriptPubKey != expected_script) { - return false; + // We support multiple scripts as a grace period for peg-in users + for (const auto& fedpegscript : fedpegscripts) { + CScript tweaked_fedpegscript = calculate_contract(fedpegscript, claim_script); + CScript witness_output(GetScriptForWitness(tweaked_fedpegscript)); + CScript expected_script(CScript() << OP_HASH160 << ToByteVector(ScriptHash(CScriptID(witness_output))) << OP_EQUAL); + if (pegtx->vout[prevout.n].scriptPubKey == expected_script) { + return true; + } } - - return true; + return false; } template @@ -226,7 +228,7 @@ bool CheckParentProofOfWork(uint256 hash, unsigned int nBits, const Consensus::P return true; } -bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& prevout, std::string& err_msg, bool check_depth) { +bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const std::vector& fedpegscripts, const COutPoint& prevout, std::string& err_msg, bool check_depth) { // 0) Return false if !consensus.has_parent_chain if (!Params().GetConsensus().has_parent_chain) { err_msg = "Parent chain is not enabled on this network."; @@ -304,7 +306,7 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p } Sidechain::Bitcoin::CTransactionRef pegtx; - if (!CheckPeginTx(stack[4], pegtx, prevout, value, claim_script)) { + if (!CheckPeginTx(stack[4], pegtx, prevout, value, claim_script, fedpegscripts)) { err_msg = "Peg-in tx is invalid."; return false; } @@ -323,7 +325,7 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p } CTransactionRef pegtx; - if (!CheckPeginTx(stack[4], pegtx, prevout, value, claim_script)) { + if (!CheckPeginTx(stack[4], pegtx, prevout, value, claim_script, fedpegscripts)) { err_msg = "Peg-in tx is invalid."; return false; } diff --git a/src/pegins.h b/src/pegins.h index 8860e31101..07d70e5529 100644 --- a/src/pegins.h +++ b/src/pegins.h @@ -19,7 +19,7 @@ bool GetAmountFromParentChainPegin(CAmount& amount, const CTransaction& txBTC, u /** Check whether a parent chain block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckParentProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); /** Checks pegin witness for validity */ -bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& prevout, std::string& err_msg, bool check_depth); +bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const std::vector& fedpegscripts, const COutPoint& prevout, std::string& err_msg, bool check_depth); // Constructs unblinded output to be used in amount and scriptpubkey checks during pegin CTxOut GetPeginOutputFromWitness(const CScriptWitness& pegin_witness); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 821b28601b..032ccb25b9 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1001,6 +1001,9 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con // Script verification errors UniValue vErrors(UniValue::VARR); + // TODO Have fedpegscript passed in optionally or perhaps always + const std::vector fedpegscripts = {Params().GetConsensus().fedpegScript}; + // ELEMENTS: // Track an immature peg-in that's otherwise valid, give warning bool immature_pegin = false; @@ -1019,12 +1022,12 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con if (!txin.m_is_pegin && coin.IsSpent()) { TxInErrorToJSON(txin, inWitness, vErrors, "Input not found or already spent"); continue; - } else if (txin.m_is_pegin && (txConst.witness.vtxinwit.size() <= i || !IsValidPeginWitness(txConst.witness.vtxinwit[i].m_pegin_witness, txin.prevout, err, false))) { + } else if (txin.m_is_pegin && (txConst.witness.vtxinwit.size() <= i || !IsValidPeginWitness(txConst.witness.vtxinwit[i].m_pegin_witness, fedpegscripts, txin.prevout, err, false))) { TxInErrorToJSON(txin, inWitness, vErrors, "Peg-in input has invalid proof."); continue; } // Report warning about immature peg-in though - if(txin.m_is_pegin && !IsValidPeginWitness(txConst.witness.vtxinwit[i].m_pegin_witness, txin.prevout, err, true)) { + if(txin.m_is_pegin && !IsValidPeginWitness(txConst.witness.vtxinwit[i].m_pegin_witness, fedpegscripts, txin.prevout, err, true)) { assert(err == "Needs more confirmations."); immature_pegin = true; } diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 5b2a5ec678..7633789351 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -17,7 +17,7 @@ #include -int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out, const CTxIn& txin, const CScriptWitness& pegin_witness); +int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out, const CTxIn& txin, const CScriptWitness& pegin_witness, const std::vector& fedpegscripts); void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight); namespace @@ -410,7 +410,8 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) if (!tx.IsCoinBase()) { const COutPoint &out = tx.vin[0].prevout; Coin coin = undo.vprevout[0]; - ApplyTxInUndo(std::move(coin), *(stack.back()), out, tx.vin[0], CScriptWitness()); + std::vector fedpegscripts; + ApplyTxInUndo(std::move(coin), *(stack.back()), out, tx.vin[0], CScriptWitness(), fedpegscripts); } // Store as a candidate for reconnection disconnected_coins.insert(utxod->first); diff --git a/src/test/pegin_witness_tests.cpp b/src/test/pegin_witness_tests.cpp index cd0dc77846..bc9de95088 100644 --- a/src/test/pegin_witness_tests.cpp +++ b/src/test/pegin_witness_tests.cpp @@ -36,9 +36,11 @@ std::vector pegin_transaction = ParseHex("020000000101f321df97906 COutPoint prevout(uint256S("ce9b0ee70f82e48f78e2a2e66e61ee4281df74419c23673cc33b639097df21f3"), 1); +const std::string fedpegscript_str = "512103dff4923d778550cc13ce0d887d737553b4b58f4e8e886507fc39f5e447b2186451ae"; + // Needed for easier parent PoW check, and setting fedpegscript struct FedpegSetup : public BasicTestingSetup { - FedpegSetup() : BasicTestingSetup("custom", "512103dff4923d778550cc13ce0d887d737553b4b58f4e8e886507fc39f5e447b2186451ae") {} + FedpegSetup() : BasicTestingSetup("custom", fedpegscript_str) {} }; BOOST_FIXTURE_TEST_SUITE(pegin_witness_tests, FedpegSetup) @@ -50,7 +52,13 @@ BOOST_AUTO_TEST_CASE(witness_valid) std::string err; - bool valid = IsValidPeginWitness(witness, prevout, err, false); + std::vector fedpegscript_bytes = ParseHex(fedpegscript_str); + CScript fedpegscript(fedpegscript_bytes.begin(), fedpegscript_bytes.end()); + std::vector fedpegscripts; + // TODO test with additional scripts + fedpegscripts.push_back(fedpegscript); + + bool valid = IsValidPeginWitness(witness, fedpegscripts, prevout, err, false); BOOST_CHECK(err == ""); BOOST_CHECK(valid); @@ -58,32 +66,32 @@ BOOST_AUTO_TEST_CASE(witness_valid) // This will break deserialization and other data-matching checks for (unsigned int i = 0; i < witness.stack.size(); i++) { witness.stack[i].pop_back(); - BOOST_CHECK(!IsValidPeginWitness(witness, prevout, err, false)); + BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, prevout, err, false)); witness.stack = witness_stack; - BOOST_CHECK(IsValidPeginWitness(witness, prevout, err, false)); + BOOST_CHECK(IsValidPeginWitness(witness, fedpegscripts, prevout, err, false)); } // Test mismatched but valid nOut to proof COutPoint fake_prevout = prevout; fake_prevout.n = 0; - BOOST_CHECK(!IsValidPeginWitness(witness, fake_prevout, err, false)); + BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, fake_prevout, err, false)); // Test mistmatched but valid txid fake_prevout = prevout; fake_prevout.hash = uint256S("2f103ee04a5649eecb932b4da4ca9977f53a12bbe04d9d1eb5ccc0f4a06334"); - BOOST_CHECK(!IsValidPeginWitness(witness, fake_prevout, err, false)); + BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, fake_prevout, err, false)); // Ensure that all witness stack sizes are handled - BOOST_CHECK(IsValidPeginWitness(witness, prevout, err, false)); + BOOST_CHECK(IsValidPeginWitness(witness, fedpegscripts, prevout, err, false)); for (unsigned int i = 0; i < witness.stack.size(); i++) { witness.stack.pop_back(); - BOOST_CHECK(!IsValidPeginWitness(witness, prevout, err, false)); + BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, prevout, err, false)); } witness.stack = witness_stack; // Extra element causes failure witness.stack.push_back(witness.stack.back()); - BOOST_CHECK(!IsValidPeginWitness(witness, prevout, err, false)); + BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, prevout, err, false)); witness.stack = witness_stack; // Check validation of peg-in transaction's inputs and balance @@ -103,7 +111,7 @@ BOOST_AUTO_TEST_CASE(witness_valid) BOOST_CHECK(tx.vin[0].m_is_pegin); // Check that serialization doesn't cause issuance to become non-null BOOST_CHECK(tx.vin[0].assetIssuance.IsNull()); - BOOST_CHECK(IsValidPeginWitness(tx.witness.vtxinwit[0].m_pegin_witness, prevout, err, false)); + BOOST_CHECK(IsValidPeginWitness(tx.witness.vtxinwit[0].m_pegin_witness, fedpegscripts, prevout, err, false)); CAmountMap fee_map; @@ -111,7 +119,9 @@ BOOST_AUTO_TEST_CASE(witness_valid) CValidationState state; CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); - BOOST_CHECK(Consensus::CheckTxInputs(tx, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true)); + // Get the latest block index to look up fedpegscripts + // For these tests, should be genesis-block-hardcoded consensus.fedpegscript + BOOST_CHECK(Consensus::CheckTxInputs(tx, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts)); BOOST_CHECK(setPeginsSpent.size() == 1); setPeginsSpent.clear(); @@ -119,7 +129,7 @@ BOOST_AUTO_TEST_CASE(witness_valid) CMutableTransaction mtxn(tx); mtxn.witness.vtxinwit[0].m_pegin_witness.SetNull(); CTransaction tx2(mtxn); - BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true)); + BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts)); BOOST_CHECK(setPeginsSpent.empty()); // Invalidate peg-in (and spending) authorization by pegin marker. @@ -128,7 +138,7 @@ BOOST_AUTO_TEST_CASE(witness_valid) CMutableTransaction mtxn2(tx); mtxn2.vin[0].m_is_pegin = false; CTransaction tx3(mtxn2); - BOOST_CHECK(!Consensus::CheckTxInputs(tx3, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true)); + BOOST_CHECK(!Consensus::CheckTxInputs(tx3, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts)); BOOST_CHECK(setPeginsSpent.empty()); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index c374274cb3..1395fa021f 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -603,7 +603,8 @@ static void CheckInputsAndUpdateCoins(const CTxMemPoolEntry& entry, CCoinsViewCa CValidationState state; CAmountMap fee_map; std::set > setPeginsSpent; - bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, fee_map, setPeginsSpent, NULL, false, true); + std::vector fedpegscripts = GetValidFedpegScripts(chainActive.Tip(), Params().GetConsensus(), true /* nextblock_validation */); + bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts); assert(fCheckResult); UpdateCoins(tx, mempoolDuplicate, 1000000); diff --git a/src/validation.cpp b/src/validation.cpp index 9ff4d68e90..050e791cc5 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -699,6 +699,9 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool } } + // Used when checking peg-ins + std::vector fedpegscripts = GetValidFedpegScripts(chainActive.Tip(), chainparams.GetConsensus(), true /* nextblock_validation */); + // do all inputs exist? for (unsigned int i = 0; i < tx.vin.size(); i++) { const CTxIn& txin = tx.vin[i]; @@ -711,7 +714,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // Peg-in witness is required, check here without validating existence in parent chain std::string err_msg = "no peg-in witness attached"; if (tx.witness.vtxinwit.size() != tx.vin.size() || - !IsValidPeginWitness(tx.witness.vtxinwit[i].m_pegin_witness, tx.vin[i].prevout, err_msg, false)) { + !IsValidPeginWitness(tx.witness.vtxinwit[i].m_pegin_witness, fedpegscripts, tx.vin[i].prevout, err_msg, false)) { return state.Invalid(false, REJECT_INVALID, "pegin-no-witness", err_msg); } @@ -757,7 +760,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final"); CAmountMap fee_map; - if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), fee_map, setPeginsSpent, NULL, true, true)) { + if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), fee_map, setPeginsSpent, NULL, true, true, fedpegscripts)) { return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); } @@ -1631,7 +1634,7 @@ static bool AbortNode(CValidationState& state, const std::string& strMessage, co * @param out The out point that corresponds to the tx input. * @return A DisconnectResult as an int */ -int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out, const CTxIn& txin, const CScriptWitness& pegin_witness) +int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out, const CTxIn& txin, const CScriptWitness& pegin_witness, const std::vector& fedpegscripts) { bool fClean = true; @@ -1663,7 +1666,7 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out, cons view.AddCoin(out, std::move(undo), !fClean); } else { std::string err; - if (!IsValidPeginWitness(pegin_witness, txin.prevout, err, false)) { + if (!IsValidPeginWitness(pegin_witness, fedpegscripts, txin.prevout, err, false)) { fClean = fClean && error("%s: peg-in occurred without proof", __func__); } else { std::pair outpoint = std::make_pair(uint256(pegin_witness.stack[2]), txin.prevout); @@ -1725,6 +1728,7 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI } // restore inputs + const std::vector fedpegscripts = GetValidFedpegScripts(pindex, Params().GetConsensus(), false /* nextblock_validation */); if (i > 0) { // not coinbases CTxUndo &txundo = blockUndo.vtxundo[i-1]; if (txundo.vprevout.size() != tx.vin.size()) { @@ -1734,7 +1738,7 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI for (unsigned int j = tx.vin.size(); j-- > 0;) { const COutPoint &out = tx.vin[j].prevout; const CScriptWitness& pegin_wit = tx.witness.vtxinwit.size() > j ? tx.witness.vtxinwit[j].m_pegin_witness : CScriptWitness(); - int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out, tx.vin[j], pegin_wit); + int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out, tx.vin[j], pegin_wit, fedpegscripts); if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED; fClean = fClean && res != DISCONNECT_UNCLEAN; } @@ -2140,6 +2144,9 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl // Used when ConnectBlock() results are unneeded for mempool ejection std::set> setPeginsSpentDummy; + // Used when checking peg-ins + std::vector fedpegscripts = GetValidFedpegScripts(pindex, chainparams.GetConsensus(), false /* nextblock_validation */); + for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = *(block.vtx[i]); @@ -2152,7 +2159,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, fee_map, setPeginsSpent == NULL ? setPeginsSpentDummy : *setPeginsSpent, - nScriptCheckThreads ? &vChecks : NULL, fCacheResults, fScriptChecks)) { + nScriptCheckThreads ? &vChecks : NULL, fCacheResults, fScriptChecks, fedpegscripts)) { return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); } control.Add(vChecks); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 4013b90027..58785b49d7 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5366,15 +5366,16 @@ extern UniValue signrawtransaction(const JSONRPCRequest& request); extern UniValue sendrawtransaction(const JSONRPCRequest& request); template -unsigned int GetPeginTxnOutputIndex(const T_tx& txn, const CScript& witnessProgram) +unsigned int GetPeginTxnOutputIndex(const T_tx& txn, const CScript& witnessProgram, const std::vector& fedpegscripts) { - unsigned int nOut = 0; - //Call contracthashtool - CScript mainchain_script = GetScriptForDestination(ScriptHash(GetScriptForWitness(calculate_contract(Params().GetConsensus().fedpegScript, witnessProgram)))); - for (; nOut < txn.vout.size(); nOut++) - if (txn.vout[nOut].scriptPubKey == mainchain_script) - break; - return nOut; + for (auto const& fedpegscript : fedpegscripts) { + CScript mainchain_script = GetScriptForDestination(ScriptHash(GetScriptForWitness(calculate_contract(fedpegscript, witnessProgram)))); + for (unsigned int nOut = 0; nOut < txn.vout.size(); nOut++) + if (txn.vout[nOut].scriptPubKey == mainchain_script) { + return nOut; + } + } + return txn.vout.size(); } template @@ -5446,6 +5447,7 @@ static UniValue createrawpegin(const JSONRPCRequest& request, T_tx_ref& txBTCRef CScript witness_script; unsigned int nOut = txBTC.vout.size(); + const std::vector fedpegscripts = GetValidFedpegScripts(chainActive.Tip(), Params().GetConsensus(), true /* nextblock_validation */); if (request.params.size() > 2) { const std::string claim_script = request.params[2].get_str(); if (!IsHex(claim_script)) { @@ -5454,7 +5456,7 @@ static UniValue createrawpegin(const JSONRPCRequest& request, T_tx_ref& txBTCRef // If given manually, no need for it to be a witness script std::vector witnessBytes(ParseHex(claim_script)); witness_script = CScript(witnessBytes.begin(), witnessBytes.end()); - nOut = GetPeginTxnOutputIndex(txBTC, witness_script); + nOut = GetPeginTxnOutputIndex(txBTC, witness_script, fedpegscripts); if (nOut == txBTC.vout.size()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Given claim_script does not match the given Bitcoin transaction."); } @@ -5463,7 +5465,7 @@ static UniValue createrawpegin(const JSONRPCRequest& request, T_tx_ref& txBTCRef // Look for known wpkh address in wallet for (std::map::const_iterator iter = pwallet->mapAddressBook.begin(); iter != pwallet->mapAddressBook.end(); ++iter) { CScript dest_script = GetScriptForDestination(iter->first); - nOut = GetPeginTxnOutputIndex(txBTC, dest_script); + nOut = GetPeginTxnOutputIndex(txBTC, dest_script, fedpegscripts); if (nOut != txBTC.vout.size()) { witness_script = dest_script; break; @@ -5540,7 +5542,7 @@ static UniValue createrawpegin(const JSONRPCRequest& request, T_tx_ref& txBTCRef // Peg-in witness isn't valid, even though the block header is(without depth check) // We re-check depth before returning with more descriptive result std::string err; - if (!IsValidPeginWitness(pegin_witness, mtx.vin[0].prevout, err, false)) { + if (!IsValidPeginWitness(pegin_witness, fedpegscripts, mtx.vin[0].prevout, err, false)) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Constructed peg-in witness is invalid: %s", err)); }