mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-16 13:01:19 +02:00
Expose fedpeg fetching to consensus and mempool internals
This commit is contained in:
parent
b00515e223
commit
0cfe03bec4
10 changed files with 76 additions and 50 deletions
|
|
@ -243,7 +243,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Consensus {
|
namespace Consensus {
|
||||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set<std::pair<uint256, COutPoint>>& setPeginsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore, bool fScriptChecks)
|
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set<std::pair<uint256, COutPoint>>& setPeginsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore, bool fScriptChecks, const std::vector<CScript>& fedpegscripts)
|
||||||
{
|
{
|
||||||
// are the actual inputs available?
|
// are the actual inputs available?
|
||||||
if (!inputs.HaveInputs(tx)) {
|
if (!inputs.HaveInputs(tx)) {
|
||||||
|
|
@ -258,7 +258,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
|
||||||
if (tx.vin[i].m_is_pegin) {
|
if (tx.vin[i].m_is_pegin) {
|
||||||
// Check existence and validity of pegin witness
|
// Check existence and validity of pegin witness
|
||||||
std::string err;
|
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);
|
return state.DoS(0, false, REJECT_PEGIN, "bad-pegin-witness", false, err);
|
||||||
}
|
}
|
||||||
std::pair<uint256, COutPoint> pegin = std::make_pair(uint256(tx.witness.vtxinwit[i].m_pegin_witness.stack[2]), prevout);
|
std::pair<uint256, COutPoint> pegin = std::make_pair(uint256(tx.witness.vtxinwit[i].m_pegin_witness.stack[2]), prevout);
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Consensus {
|
||||||
* @param[out] fee_map Set to the transaction fee if successful.
|
* @param[out] fee_map Set to the transaction fee if successful.
|
||||||
* Preconditions: tx.IsCoinBase() is false.
|
* Preconditions: tx.IsCoinBase() is false.
|
||||||
*/
|
*/
|
||||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set<std::pair<uint256, COutPoint>>& setPeginsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore, bool fScriptChecks);
|
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmountMap& fee_map, std::set<std::pair<uint256, COutPoint>>& setPeginsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore, bool fScriptChecks, const std::vector<CScript>& fedpegscripts);
|
||||||
} // namespace Consensus
|
} // namespace Consensus
|
||||||
|
|
||||||
/** Auxiliary functions for transaction validation (ideally should not be exposed) */
|
/** Auxiliary functions for transaction validation (ideally should not be exposed) */
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ CScript calculate_contract(const CScript& federation_script, const CScript& scri
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static bool CheckPeginTx(const std::vector<unsigned char>& tx_data, T& pegtx, const COutPoint& prevout, const CAmount claim_amount, const CScript& claim_script)
|
static bool CheckPeginTx(const std::vector<unsigned char>& tx_data, T& pegtx, const COutPoint& prevout, const CAmount claim_amount, const CScript& claim_script, const std::vector<CScript>& fedpegscripts)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
CDataStream pegtx_stream(tx_data, SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream pegtx_stream(tx_data, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
|
@ -172,14 +172,16 @@ static bool CheckPeginTx(const std::vector<unsigned char>& tx_data, T& pegtx, co
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the witness program matches the p2ch on the p2sh-p2wsh transaction output
|
// Check that the witness program matches the p2ch on the p2sh-p2wsh transaction output
|
||||||
CScript tweaked_fedpegscript = calculate_contract(Params().GetConsensus().fedpegScript, claim_script);
|
// We support multiple scripts as a grace period for peg-in users
|
||||||
CScript witness_output(GetScriptForWitness(tweaked_fedpegscript));
|
for (const auto& fedpegscript : fedpegscripts) {
|
||||||
CScript expected_script(CScript() << OP_HASH160 << ToByteVector(ScriptHash(CScriptID(witness_output))) << OP_EQUAL);
|
CScript tweaked_fedpegscript = calculate_contract(fedpegscript, claim_script);
|
||||||
if (pegtx->vout[prevout.n].scriptPubKey != expected_script) {
|
CScript witness_output(GetScriptForWitness(tweaked_fedpegscript));
|
||||||
return false;
|
CScript expected_script(CScript() << OP_HASH160 << ToByteVector(ScriptHash(CScriptID(witness_output))) << OP_EQUAL);
|
||||||
|
if (pegtx->vout[prevout.n].scriptPubKey == expected_script) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
@ -226,7 +228,7 @@ bool CheckParentProofOfWork(uint256 hash, unsigned int nBits, const Consensus::P
|
||||||
return true;
|
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<CScript>& fedpegscripts, const COutPoint& prevout, std::string& err_msg, bool check_depth) {
|
||||||
// 0) Return false if !consensus.has_parent_chain
|
// 0) Return false if !consensus.has_parent_chain
|
||||||
if (!Params().GetConsensus().has_parent_chain) {
|
if (!Params().GetConsensus().has_parent_chain) {
|
||||||
err_msg = "Parent chain is not enabled on this network.";
|
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;
|
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.";
|
err_msg = "Peg-in tx is invalid.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -323,7 +325,7 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p
|
||||||
}
|
}
|
||||||
|
|
||||||
CTransactionRef pegtx;
|
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.";
|
err_msg = "Peg-in tx is invalid.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
/** 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&);
|
bool CheckParentProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);
|
||||||
/** Checks pegin witness for validity */
|
/** 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<CScript>& fedpegscripts, const COutPoint& prevout, std::string& err_msg, bool check_depth);
|
||||||
// Constructs unblinded output to be used in amount and scriptpubkey checks during pegin
|
// Constructs unblinded output to be used in amount and scriptpubkey checks during pegin
|
||||||
CTxOut GetPeginOutputFromWitness(const CScriptWitness& pegin_witness);
|
CTxOut GetPeginOutputFromWitness(const CScriptWitness& pegin_witness);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1001,6 +1001,9 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
|
||||||
// Script verification errors
|
// Script verification errors
|
||||||
UniValue vErrors(UniValue::VARR);
|
UniValue vErrors(UniValue::VARR);
|
||||||
|
|
||||||
|
// TODO Have fedpegscript passed in optionally or perhaps always
|
||||||
|
const std::vector<CScript> fedpegscripts = {Params().GetConsensus().fedpegScript};
|
||||||
|
|
||||||
// ELEMENTS:
|
// ELEMENTS:
|
||||||
// Track an immature peg-in that's otherwise valid, give warning
|
// Track an immature peg-in that's otherwise valid, give warning
|
||||||
bool immature_pegin = false;
|
bool immature_pegin = false;
|
||||||
|
|
@ -1019,12 +1022,12 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
|
||||||
if (!txin.m_is_pegin && coin.IsSpent()) {
|
if (!txin.m_is_pegin && coin.IsSpent()) {
|
||||||
TxInErrorToJSON(txin, inWitness, vErrors, "Input not found or already spent");
|
TxInErrorToJSON(txin, inWitness, vErrors, "Input not found or already spent");
|
||||||
continue;
|
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.");
|
TxInErrorToJSON(txin, inWitness, vErrors, "Peg-in input has invalid proof.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Report warning about immature peg-in though
|
// 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.");
|
assert(err == "Needs more confirmations.");
|
||||||
immature_pegin = true;
|
immature_pegin = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
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<CScript>& fedpegscripts);
|
||||||
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight);
|
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight);
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
|
@ -410,7 +410,8 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
|
||||||
if (!tx.IsCoinBase()) {
|
if (!tx.IsCoinBase()) {
|
||||||
const COutPoint &out = tx.vin[0].prevout;
|
const COutPoint &out = tx.vin[0].prevout;
|
||||||
Coin coin = undo.vprevout[0];
|
Coin coin = undo.vprevout[0];
|
||||||
ApplyTxInUndo(std::move(coin), *(stack.back()), out, tx.vin[0], CScriptWitness());
|
std::vector<CScript> fedpegscripts;
|
||||||
|
ApplyTxInUndo(std::move(coin), *(stack.back()), out, tx.vin[0], CScriptWitness(), fedpegscripts);
|
||||||
}
|
}
|
||||||
// Store as a candidate for reconnection
|
// Store as a candidate for reconnection
|
||||||
disconnected_coins.insert(utxod->first);
|
disconnected_coins.insert(utxod->first);
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,11 @@ std::vector<unsigned char> pegin_transaction = ParseHex("020000000101f321df97906
|
||||||
|
|
||||||
COutPoint prevout(uint256S("ce9b0ee70f82e48f78e2a2e66e61ee4281df74419c23673cc33b639097df21f3"), 1);
|
COutPoint prevout(uint256S("ce9b0ee70f82e48f78e2a2e66e61ee4281df74419c23673cc33b639097df21f3"), 1);
|
||||||
|
|
||||||
|
const std::string fedpegscript_str = "512103dff4923d778550cc13ce0d887d737553b4b58f4e8e886507fc39f5e447b2186451ae";
|
||||||
|
|
||||||
// Needed for easier parent PoW check, and setting fedpegscript
|
// Needed for easier parent PoW check, and setting fedpegscript
|
||||||
struct FedpegSetup : public BasicTestingSetup {
|
struct FedpegSetup : public BasicTestingSetup {
|
||||||
FedpegSetup() : BasicTestingSetup("custom", "512103dff4923d778550cc13ce0d887d737553b4b58f4e8e886507fc39f5e447b2186451ae") {}
|
FedpegSetup() : BasicTestingSetup("custom", fedpegscript_str) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(pegin_witness_tests, FedpegSetup)
|
BOOST_FIXTURE_TEST_SUITE(pegin_witness_tests, FedpegSetup)
|
||||||
|
|
@ -50,7 +52,13 @@ BOOST_AUTO_TEST_CASE(witness_valid)
|
||||||
|
|
||||||
std::string err;
|
std::string err;
|
||||||
|
|
||||||
bool valid = IsValidPeginWitness(witness, prevout, err, false);
|
std::vector<unsigned char> fedpegscript_bytes = ParseHex(fedpegscript_str);
|
||||||
|
CScript fedpegscript(fedpegscript_bytes.begin(), fedpegscript_bytes.end());
|
||||||
|
std::vector<CScript> fedpegscripts;
|
||||||
|
// TODO test with additional scripts
|
||||||
|
fedpegscripts.push_back(fedpegscript);
|
||||||
|
|
||||||
|
bool valid = IsValidPeginWitness(witness, fedpegscripts, prevout, err, false);
|
||||||
BOOST_CHECK(err == "");
|
BOOST_CHECK(err == "");
|
||||||
BOOST_CHECK(valid);
|
BOOST_CHECK(valid);
|
||||||
|
|
||||||
|
|
@ -58,32 +66,32 @@ BOOST_AUTO_TEST_CASE(witness_valid)
|
||||||
// This will break deserialization and other data-matching checks
|
// This will break deserialization and other data-matching checks
|
||||||
for (unsigned int i = 0; i < witness.stack.size(); i++) {
|
for (unsigned int i = 0; i < witness.stack.size(); i++) {
|
||||||
witness.stack[i].pop_back();
|
witness.stack[i].pop_back();
|
||||||
BOOST_CHECK(!IsValidPeginWitness(witness, prevout, err, false));
|
BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, prevout, err, false));
|
||||||
witness.stack = witness_stack;
|
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
|
// Test mismatched but valid nOut to proof
|
||||||
COutPoint fake_prevout = prevout;
|
COutPoint fake_prevout = prevout;
|
||||||
fake_prevout.n = 0;
|
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
|
// Test mistmatched but valid txid
|
||||||
fake_prevout = prevout;
|
fake_prevout = prevout;
|
||||||
fake_prevout.hash = uint256S("2f103ee04a5649eecb932b4da4ca9977f53a12bbe04d9d1eb5ccc0f4a06334");
|
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
|
// 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++) {
|
for (unsigned int i = 0; i < witness.stack.size(); i++) {
|
||||||
witness.stack.pop_back();
|
witness.stack.pop_back();
|
||||||
BOOST_CHECK(!IsValidPeginWitness(witness, prevout, err, false));
|
BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, prevout, err, false));
|
||||||
}
|
}
|
||||||
witness.stack = witness_stack;
|
witness.stack = witness_stack;
|
||||||
|
|
||||||
// Extra element causes failure
|
// Extra element causes failure
|
||||||
witness.stack.push_back(witness.stack.back());
|
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;
|
witness.stack = witness_stack;
|
||||||
|
|
||||||
// Check validation of peg-in transaction's inputs and balance
|
// 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);
|
BOOST_CHECK(tx.vin[0].m_is_pegin);
|
||||||
// Check that serialization doesn't cause issuance to become non-null
|
// Check that serialization doesn't cause issuance to become non-null
|
||||||
BOOST_CHECK(tx.vin[0].assetIssuance.IsNull());
|
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;
|
CAmountMap fee_map;
|
||||||
|
|
||||||
|
|
@ -111,7 +119,9 @@ BOOST_AUTO_TEST_CASE(witness_valid)
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
CCoinsView coinsDummy;
|
CCoinsView coinsDummy;
|
||||||
CCoinsViewCache coins(&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);
|
BOOST_CHECK(setPeginsSpent.size() == 1);
|
||||||
setPeginsSpent.clear();
|
setPeginsSpent.clear();
|
||||||
|
|
||||||
|
|
@ -119,7 +129,7 @@ BOOST_AUTO_TEST_CASE(witness_valid)
|
||||||
CMutableTransaction mtxn(tx);
|
CMutableTransaction mtxn(tx);
|
||||||
mtxn.witness.vtxinwit[0].m_pegin_witness.SetNull();
|
mtxn.witness.vtxinwit[0].m_pegin_witness.SetNull();
|
||||||
CTransaction tx2(mtxn);
|
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());
|
BOOST_CHECK(setPeginsSpent.empty());
|
||||||
|
|
||||||
// Invalidate peg-in (and spending) authorization by pegin marker.
|
// Invalidate peg-in (and spending) authorization by pegin marker.
|
||||||
|
|
@ -128,7 +138,7 @@ BOOST_AUTO_TEST_CASE(witness_valid)
|
||||||
CMutableTransaction mtxn2(tx);
|
CMutableTransaction mtxn2(tx);
|
||||||
mtxn2.vin[0].m_is_pegin = false;
|
mtxn2.vin[0].m_is_pegin = false;
|
||||||
CTransaction tx3(mtxn2);
|
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());
|
BOOST_CHECK(setPeginsSpent.empty());
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -603,7 +603,8 @@ static void CheckInputsAndUpdateCoins(const CTxMemPoolEntry& entry, CCoinsViewCa
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
CAmountMap fee_map;
|
CAmountMap fee_map;
|
||||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||||
bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, fee_map, setPeginsSpent, NULL, false, true);
|
std::vector<CScript> 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);
|
assert(fCheckResult);
|
||||||
UpdateCoins(tx, mempoolDuplicate, 1000000);
|
UpdateCoins(tx, mempoolDuplicate, 1000000);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -699,6 +699,9 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used when checking peg-ins
|
||||||
|
std::vector<CScript> fedpegscripts = GetValidFedpegScripts(chainActive.Tip(), chainparams.GetConsensus(), true /* nextblock_validation */);
|
||||||
|
|
||||||
// do all inputs exist?
|
// do all inputs exist?
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||||
const CTxIn& txin = tx.vin[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
|
// Peg-in witness is required, check here without validating existence in parent chain
|
||||||
std::string err_msg = "no peg-in witness attached";
|
std::string err_msg = "no peg-in witness attached";
|
||||||
if (tx.witness.vtxinwit.size() != tx.vin.size() ||
|
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);
|
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");
|
return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final");
|
||||||
|
|
||||||
CAmountMap fee_map;
|
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));
|
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.
|
* @param out The out point that corresponds to the tx input.
|
||||||
* @return A DisconnectResult as an int
|
* @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<CScript>& fedpegscripts)
|
||||||
{
|
{
|
||||||
bool fClean = true;
|
bool fClean = true;
|
||||||
|
|
||||||
|
|
@ -1663,7 +1666,7 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out, cons
|
||||||
view.AddCoin(out, std::move(undo), !fClean);
|
view.AddCoin(out, std::move(undo), !fClean);
|
||||||
} else {
|
} else {
|
||||||
std::string err;
|
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__);
|
fClean = fClean && error("%s: peg-in occurred without proof", __func__);
|
||||||
} else {
|
} else {
|
||||||
std::pair<uint256, COutPoint> outpoint = std::make_pair(uint256(pegin_witness.stack[2]), txin.prevout);
|
std::pair<uint256, COutPoint> 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
|
// restore inputs
|
||||||
|
const std::vector<CScript> fedpegscripts = GetValidFedpegScripts(pindex, Params().GetConsensus(), false /* nextblock_validation */);
|
||||||
if (i > 0) { // not coinbases
|
if (i > 0) { // not coinbases
|
||||||
CTxUndo &txundo = blockUndo.vtxundo[i-1];
|
CTxUndo &txundo = blockUndo.vtxundo[i-1];
|
||||||
if (txundo.vprevout.size() != tx.vin.size()) {
|
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;) {
|
for (unsigned int j = tx.vin.size(); j-- > 0;) {
|
||||||
const COutPoint &out = tx.vin[j].prevout;
|
const COutPoint &out = tx.vin[j].prevout;
|
||||||
const CScriptWitness& pegin_wit = tx.witness.vtxinwit.size() > j ? tx.witness.vtxinwit[j].m_pegin_witness : CScriptWitness();
|
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;
|
if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED;
|
||||||
fClean = fClean && res != DISCONNECT_UNCLEAN;
|
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
|
// Used when ConnectBlock() results are unneeded for mempool ejection
|
||||||
std::set<std::pair<uint256, COutPoint>> setPeginsSpentDummy;
|
std::set<std::pair<uint256, COutPoint>> setPeginsSpentDummy;
|
||||||
|
|
||||||
|
// Used when checking peg-ins
|
||||||
|
std::vector<CScript> fedpegscripts = GetValidFedpegScripts(pindex, chainparams.GetConsensus(), false /* nextblock_validation */);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
||||||
{
|
{
|
||||||
const CTransaction &tx = *(block.vtx[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) */
|
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,
|
if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, fee_map,
|
||||||
setPeginsSpent == NULL ? setPeginsSpentDummy : *setPeginsSpent,
|
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));
|
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
control.Add(vChecks);
|
control.Add(vChecks);
|
||||||
|
|
|
||||||
|
|
@ -5366,15 +5366,16 @@ extern UniValue signrawtransaction(const JSONRPCRequest& request);
|
||||||
extern UniValue sendrawtransaction(const JSONRPCRequest& request);
|
extern UniValue sendrawtransaction(const JSONRPCRequest& request);
|
||||||
|
|
||||||
template<typename T_tx>
|
template<typename T_tx>
|
||||||
unsigned int GetPeginTxnOutputIndex(const T_tx& txn, const CScript& witnessProgram)
|
unsigned int GetPeginTxnOutputIndex(const T_tx& txn, const CScript& witnessProgram, const std::vector<CScript>& fedpegscripts)
|
||||||
{
|
{
|
||||||
unsigned int nOut = 0;
|
for (auto const& fedpegscript : fedpegscripts) {
|
||||||
//Call contracthashtool
|
CScript mainchain_script = GetScriptForDestination(ScriptHash(GetScriptForWitness(calculate_contract(fedpegscript, witnessProgram))));
|
||||||
CScript mainchain_script = GetScriptForDestination(ScriptHash(GetScriptForWitness(calculate_contract(Params().GetConsensus().fedpegScript, witnessProgram))));
|
for (unsigned int nOut = 0; nOut < txn.vout.size(); nOut++)
|
||||||
for (; nOut < txn.vout.size(); nOut++)
|
if (txn.vout[nOut].scriptPubKey == mainchain_script) {
|
||||||
if (txn.vout[nOut].scriptPubKey == mainchain_script)
|
return nOut;
|
||||||
break;
|
}
|
||||||
return nOut;
|
}
|
||||||
|
return txn.vout.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T_tx_ref, typename T_tx, typename T_merkle_block>
|
template<typename T_tx_ref, typename T_tx, typename T_merkle_block>
|
||||||
|
|
@ -5446,6 +5447,7 @@ static UniValue createrawpegin(const JSONRPCRequest& request, T_tx_ref& txBTCRef
|
||||||
|
|
||||||
CScript witness_script;
|
CScript witness_script;
|
||||||
unsigned int nOut = txBTC.vout.size();
|
unsigned int nOut = txBTC.vout.size();
|
||||||
|
const std::vector<CScript> fedpegscripts = GetValidFedpegScripts(chainActive.Tip(), Params().GetConsensus(), true /* nextblock_validation */);
|
||||||
if (request.params.size() > 2) {
|
if (request.params.size() > 2) {
|
||||||
const std::string claim_script = request.params[2].get_str();
|
const std::string claim_script = request.params[2].get_str();
|
||||||
if (!IsHex(claim_script)) {
|
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
|
// If given manually, no need for it to be a witness script
|
||||||
std::vector<unsigned char> witnessBytes(ParseHex(claim_script));
|
std::vector<unsigned char> witnessBytes(ParseHex(claim_script));
|
||||||
witness_script = CScript(witnessBytes.begin(), witnessBytes.end());
|
witness_script = CScript(witnessBytes.begin(), witnessBytes.end());
|
||||||
nOut = GetPeginTxnOutputIndex(txBTC, witness_script);
|
nOut = GetPeginTxnOutputIndex(txBTC, witness_script, fedpegscripts);
|
||||||
if (nOut == txBTC.vout.size()) {
|
if (nOut == txBTC.vout.size()) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Given claim_script does not match the given Bitcoin transaction.");
|
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
|
// Look for known wpkh address in wallet
|
||||||
for (std::map<CTxDestination, CAddressBookData>::const_iterator iter = pwallet->mapAddressBook.begin(); iter != pwallet->mapAddressBook.end(); ++iter) {
|
for (std::map<CTxDestination, CAddressBookData>::const_iterator iter = pwallet->mapAddressBook.begin(); iter != pwallet->mapAddressBook.end(); ++iter) {
|
||||||
CScript dest_script = GetScriptForDestination(iter->first);
|
CScript dest_script = GetScriptForDestination(iter->first);
|
||||||
nOut = GetPeginTxnOutputIndex(txBTC, dest_script);
|
nOut = GetPeginTxnOutputIndex(txBTC, dest_script, fedpegscripts);
|
||||||
if (nOut != txBTC.vout.size()) {
|
if (nOut != txBTC.vout.size()) {
|
||||||
witness_script = dest_script;
|
witness_script = dest_script;
|
||||||
break;
|
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)
|
// 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
|
// We re-check depth before returning with more descriptive result
|
||||||
std::string err;
|
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));
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Constructed peg-in witness is invalid: %s", err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue