Skip to content

Commit 525b24c

Browse files
committed
Expose fedpeg fetching to consensus and mempool internals
1 parent 4ac437b commit 525b24c

File tree

10 files changed

+76
-50
lines changed

10 files changed

+76
-50
lines changed

src/consensus/tx_verify.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
243243
}
244244

245245
namespace Consensus {
246-
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)
246+
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)
247247
{
248248
// are the actual inputs available?
249249
if (!inputs.HaveInputs(tx)) {
@@ -258,7 +258,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
258258
if (tx.vin[i].m_is_pegin) {
259259
// Check existence and validity of pegin witness
260260
std::string err;
261-
if (tx.witness.vtxinwit.size() <= i || !IsValidPeginWitness(tx.witness.vtxinwit[i].m_pegin_witness, prevout, err, true)) {
261+
if (tx.witness.vtxinwit.size() <= i || !IsValidPeginWitness(tx.witness.vtxinwit[i].m_pegin_witness, fedpegscripts, prevout, err, true)) {
262262
return state.DoS(0, false, REJECT_PEGIN, "bad-pegin-witness", false, err);
263263
}
264264
std::pair<uint256, COutPoint> pegin = std::make_pair(uint256(tx.witness.vtxinwit[i].m_pegin_witness.stack[2]), prevout);

src/consensus/tx_verify.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ namespace Consensus {
3131
* @param[out] fee_map Set to the transaction fee if successful.
3232
* Preconditions: tx.IsCoinBase() is false.
3333
*/
34-
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);
34+
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);
3535
} // namespace Consensus
3636

3737
/** Auxiliary functions for transaction validation (ideally should not be exposed) */

src/pegins.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ CScript calculate_contract(const CScript& federation_script, const CScript& scri
141141
}
142142

143143
template<typename T>
144-
static bool CheckPeginTx(const std::vector<unsigned char>& tx_data, T& pegtx, const COutPoint& prevout, const CAmount claim_amount, const CScript& claim_script)
144+
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)
145145
{
146146
try {
147147
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
172172
}
173173

174174
// Check that the witness program matches the p2ch on the p2sh-p2wsh transaction output
175-
CScript tweaked_fedpegscript = calculate_contract(Params().GetConsensus().fedpegScript, claim_script);
176-
CScript witness_output(GetScriptForWitness(tweaked_fedpegscript));
177-
CScript expected_script(CScript() << OP_HASH160 << ToByteVector(ScriptHash(CScriptID(witness_output))) << OP_EQUAL);
178-
if (pegtx->vout[prevout.n].scriptPubKey != expected_script) {
179-
return false;
175+
// We support multiple scripts as a grace period for peg-in users
176+
for (const auto& fedpegscript : fedpegscripts) {
177+
CScript tweaked_fedpegscript = calculate_contract(fedpegscript, claim_script);
178+
CScript witness_output(GetScriptForWitness(tweaked_fedpegscript));
179+
CScript expected_script(CScript() << OP_HASH160 << ToByteVector(ScriptHash(CScriptID(witness_output))) << OP_EQUAL);
180+
if (pegtx->vout[prevout.n].scriptPubKey == expected_script) {
181+
return true;
182+
}
180183
}
181-
182-
return true;
184+
return false;
183185
}
184186

185187
template<typename T>
@@ -226,7 +228,7 @@ bool CheckParentProofOfWork(uint256 hash, unsigned int nBits, const Consensus::P
226228
return true;
227229
}
228230

229-
bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& prevout, std::string& err_msg, bool check_depth) {
231+
bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const std::vector<CScript>& fedpegscripts, const COutPoint& prevout, std::string& err_msg, bool check_depth) {
230232
// 0) Return false if !consensus.has_parent_chain
231233
if (!Params().GetConsensus().has_parent_chain) {
232234
err_msg = "Parent chain is not enabled on this network.";
@@ -304,7 +306,7 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p
304306
}
305307

306308
Sidechain::Bitcoin::CTransactionRef pegtx;
307-
if (!CheckPeginTx(stack[4], pegtx, prevout, value, claim_script)) {
309+
if (!CheckPeginTx(stack[4], pegtx, prevout, value, claim_script, fedpegscripts)) {
308310
err_msg = "Peg-in tx is invalid.";
309311
return false;
310312
}
@@ -323,7 +325,7 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p
323325
}
324326

325327
CTransactionRef pegtx;
326-
if (!CheckPeginTx(stack[4], pegtx, prevout, value, claim_script)) {
328+
if (!CheckPeginTx(stack[4], pegtx, prevout, value, claim_script, fedpegscripts)) {
327329
err_msg = "Peg-in tx is invalid.";
328330
return false;
329331
}

src/pegins.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ bool GetAmountFromParentChainPegin(CAmount& amount, const CTransaction& txBTC, u
1919
/** Check whether a parent chain block hash satisfies the proof-of-work requirement specified by nBits */
2020
bool CheckParentProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);
2121
/** Checks pegin witness for validity */
22-
bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& prevout, std::string& err_msg, bool check_depth);
22+
bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const std::vector<CScript>& fedpegscripts, const COutPoint& prevout, std::string& err_msg, bool check_depth);
2323
// Constructs unblinded output to be used in amount and scriptpubkey checks during pegin
2424
CTxOut GetPeginOutputFromWitness(const CScriptWitness& pegin_witness);
2525

src/rpc/rawtransaction.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,9 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
988988
// Script verification errors
989989
UniValue vErrors(UniValue::VARR);
990990

991+
// TODO Have fedpegscript passed in optionally or perhaps always
992+
const std::vector<CScript> fedpegscripts = {Params().GetConsensus().fedpegScript};
993+
991994
// ELEMENTS:
992995
// Track an immature peg-in that's otherwise valid, give warning
993996
bool immature_pegin = false;
@@ -1006,12 +1009,12 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
10061009
if (!txin.m_is_pegin && coin.IsSpent()) {
10071010
TxInErrorToJSON(txin, inWitness, vErrors, "Input not found or already spent");
10081011
continue;
1009-
} else if (txin.m_is_pegin && (txConst.witness.vtxinwit.size() <= i || !IsValidPeginWitness(txConst.witness.vtxinwit[i].m_pegin_witness, txin.prevout, err, false))) {
1012+
} else if (txin.m_is_pegin && (txConst.witness.vtxinwit.size() <= i || !IsValidPeginWitness(txConst.witness.vtxinwit[i].m_pegin_witness, fedpegscripts, txin.prevout, err, false))) {
10101013
TxInErrorToJSON(txin, inWitness, vErrors, "Peg-in input has invalid proof.");
10111014
continue;
10121015
}
10131016
// Report warning about immature peg-in though
1014-
if(txin.m_is_pegin && !IsValidPeginWitness(txConst.witness.vtxinwit[i].m_pegin_witness, txin.prevout, err, true)) {
1017+
if(txin.m_is_pegin && !IsValidPeginWitness(txConst.witness.vtxinwit[i].m_pegin_witness, fedpegscripts, txin.prevout, err, true)) {
10151018
assert(err == "Needs more confirmations.");
10161019
immature_pegin = true;
10171020
}

src/test/coins_tests.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
#include <boost/test/unit_test.hpp>
1919

20-
int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out, const CTxIn& txin, const CScriptWitness& pegin_witness);
20+
int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out, const CTxIn& txin, const CScriptWitness& pegin_witness, const std::vector<CScript>& fedpegscripts);
2121
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight);
2222

2323
namespace
@@ -410,7 +410,8 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
410410
if (!tx.IsCoinBase()) {
411411
const COutPoint &out = tx.vin[0].prevout;
412412
Coin coin = undo.vprevout[0];
413-
ApplyTxInUndo(std::move(coin), *(stack.back()), out, tx.vin[0], CScriptWitness());
413+
std::vector<CScript> fedpegscripts;
414+
ApplyTxInUndo(std::move(coin), *(stack.back()), out, tx.vin[0], CScriptWitness(), fedpegscripts);
414415
}
415416
// Store as a candidate for reconnection
416417
disconnected_coins.insert(utxod->first);

src/test/pegin_witness_tests.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@ std::vector<unsigned char> pegin_transaction = ParseHex("020000000101f321df97906
3636

3737
COutPoint prevout(uint256S("ce9b0ee70f82e48f78e2a2e66e61ee4281df74419c23673cc33b639097df21f3"), 1);
3838

39+
const std::string fedpegscript_str = "512103dff4923d778550cc13ce0d887d737553b4b58f4e8e886507fc39f5e447b2186451ae";
40+
3941
// Needed for easier parent PoW check, and setting fedpegscript
4042
struct FedpegSetup : public BasicTestingSetup {
41-
FedpegSetup() : BasicTestingSetup("custom", "512103dff4923d778550cc13ce0d887d737553b4b58f4e8e886507fc39f5e447b2186451ae") {}
43+
FedpegSetup() : BasicTestingSetup("custom", fedpegscript_str) {}
4244
};
4345

4446
BOOST_FIXTURE_TEST_SUITE(pegin_witness_tests, FedpegSetup)
@@ -50,40 +52,46 @@ BOOST_AUTO_TEST_CASE(witness_valid)
5052

5153
std::string err;
5254

53-
bool valid = IsValidPeginWitness(witness, prevout, err, false);
55+
std::vector<unsigned char> fedpegscript_bytes = ParseHex(fedpegscript_str);
56+
CScript fedpegscript(fedpegscript_bytes.begin(), fedpegscript_bytes.end());
57+
std::vector<CScript> fedpegscripts;
58+
// TODO test with additional scripts
59+
fedpegscripts.push_back(fedpegscript);
60+
61+
bool valid = IsValidPeginWitness(witness, fedpegscripts, prevout, err, false);
5462
BOOST_CHECK(err == "");
5563
BOOST_CHECK(valid);
5664

5765
// Missing byte on each field to make claim ill-formatted
5866
// This will break deserialization and other data-matching checks
5967
for (unsigned int i = 0; i < witness.stack.size(); i++) {
6068
witness.stack[i].pop_back();
61-
BOOST_CHECK(!IsValidPeginWitness(witness, prevout, err, false));
69+
BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, prevout, err, false));
6270
witness.stack = witness_stack;
63-
BOOST_CHECK(IsValidPeginWitness(witness, prevout, err, false));
71+
BOOST_CHECK(IsValidPeginWitness(witness, fedpegscripts, prevout, err, false));
6472
}
6573

6674
// Test mismatched but valid nOut to proof
6775
COutPoint fake_prevout = prevout;
6876
fake_prevout.n = 0;
69-
BOOST_CHECK(!IsValidPeginWitness(witness, fake_prevout, err, false));
77+
BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, fake_prevout, err, false));
7078

7179
// Test mistmatched but valid txid
7280
fake_prevout = prevout;
7381
fake_prevout.hash = uint256S("2f103ee04a5649eecb932b4da4ca9977f53a12bbe04d9d1eb5ccc0f4a06334");
74-
BOOST_CHECK(!IsValidPeginWitness(witness, fake_prevout, err, false));
82+
BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, fake_prevout, err, false));
7583

7684
// Ensure that all witness stack sizes are handled
77-
BOOST_CHECK(IsValidPeginWitness(witness, prevout, err, false));
85+
BOOST_CHECK(IsValidPeginWitness(witness, fedpegscripts, prevout, err, false));
7886
for (unsigned int i = 0; i < witness.stack.size(); i++) {
7987
witness.stack.pop_back();
80-
BOOST_CHECK(!IsValidPeginWitness(witness, prevout, err, false));
88+
BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, prevout, err, false));
8189
}
8290
witness.stack = witness_stack;
8391

8492
// Extra element causes failure
8593
witness.stack.push_back(witness.stack.back());
86-
BOOST_CHECK(!IsValidPeginWitness(witness, prevout, err, false));
94+
BOOST_CHECK(!IsValidPeginWitness(witness, fedpegscripts, prevout, err, false));
8795
witness.stack = witness_stack;
8896

8997
// Check validation of peg-in transaction's inputs and balance
@@ -103,23 +111,25 @@ BOOST_AUTO_TEST_CASE(witness_valid)
103111
BOOST_CHECK(tx.vin[0].m_is_pegin);
104112
// Check that serialization doesn't cause issuance to become non-null
105113
BOOST_CHECK(tx.vin[0].assetIssuance.IsNull());
106-
BOOST_CHECK(IsValidPeginWitness(tx.witness.vtxinwit[0].m_pegin_witness, prevout, err, false));
114+
BOOST_CHECK(IsValidPeginWitness(tx.witness.vtxinwit[0].m_pegin_witness, fedpegscripts, prevout, err, false));
107115

108116
CAmountMap fee_map;
109117

110118
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
111119
CValidationState state;
112120
CCoinsView coinsDummy;
113121
CCoinsViewCache coins(&coinsDummy);
114-
BOOST_CHECK(Consensus::CheckTxInputs(tx, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true));
122+
// Get the latest block index to look up fedpegscripts
123+
// For these tests, should be genesis-block-hardcoded consensus.fedpegscript
124+
BOOST_CHECK(Consensus::CheckTxInputs(tx, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts));
115125
BOOST_CHECK(setPeginsSpent.size() == 1);
116126
setPeginsSpent.clear();
117127

118128
// Strip pegin_witness
119129
CMutableTransaction mtxn(tx);
120130
mtxn.witness.vtxinwit[0].m_pegin_witness.SetNull();
121131
CTransaction tx2(mtxn);
122-
BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true));
132+
BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts));
123133
BOOST_CHECK(setPeginsSpent.empty());
124134

125135
// Invalidate peg-in (and spending) authorization by pegin marker.
@@ -128,7 +138,7 @@ BOOST_AUTO_TEST_CASE(witness_valid)
128138
CMutableTransaction mtxn2(tx);
129139
mtxn2.vin[0].m_is_pegin = false;
130140
CTransaction tx3(mtxn2);
131-
BOOST_CHECK(!Consensus::CheckTxInputs(tx3, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true));
141+
BOOST_CHECK(!Consensus::CheckTxInputs(tx3, state, coins, 0, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts));
132142
BOOST_CHECK(setPeginsSpent.empty());
133143

134144

src/txmempool.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,8 @@ static void CheckInputsAndUpdateCoins(const CTxMemPoolEntry& entry, CCoinsViewCa
603603
CValidationState state;
604604
CAmountMap fee_map;
605605
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
606-
bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, fee_map, setPeginsSpent, NULL, false, true);
606+
std::vector<CScript> fedpegscripts = GetValidFedpegScripts(chainActive.Tip(), Params().GetConsensus(), true /* nextblock_validation */);
607+
bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, fee_map, setPeginsSpent, NULL, false, true, fedpegscripts);
607608
assert(fCheckResult);
608609
UpdateCoins(tx, mempoolDuplicate, 1000000);
609610

0 commit comments

Comments
 (0)