Skip to content

Commit 4aad513

Browse files
committed
Add unit tests for peg-in authorization
1 parent be735cf commit 4aad513

File tree

5 files changed

+143
-4
lines changed

5 files changed

+143
-4
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ BITCOIN_TESTS =\
109109
test/multisig_tests.cpp \
110110
test/net_tests.cpp \
111111
test/netbase_tests.cpp \
112+
test/pegin_witness_tests.cpp \
112113
test/pmt_tests.cpp \
113114
test/policyestimator_tests.cpp \
114115
test/pow_tests.cpp \

src/test/pegin_witness_tests.cpp

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Copyright (c) 2017-2017 Blockstream
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include "clientversion.h"
6+
#include "chainparams.h"
7+
#include "checkqueue.h"
8+
#include "consensus/validation.h"
9+
#include "core_io.h"
10+
#include "validation.h" // For CheckTransaction
11+
#include "policy/policy.h"
12+
#include "script/script.h"
13+
#include "script/script_error.h"
14+
#include "utilstrencodings.h"
15+
#include "validation.h"
16+
#include "streams.h"
17+
#include "test/test_bitcoin.h"
18+
#include "util.h"
19+
20+
#include <boost/algorithm/string/classification.hpp>
21+
#include <boost/algorithm/string/split.hpp>
22+
#include <boost/assign/list_of.hpp>
23+
#include <boost/test/unit_test.hpp>
24+
#include <boost/assign/list_of.hpp>
25+
#include <boost/foreach.hpp>
26+
27+
std::vector<std::vector<unsigned char> > witness_stack = {
28+
ParseHex("00ca9a3b"),
29+
ParseHex("e48a1a02a8f799892fda58347c2d794144311d4307dbfd10f77ffe28088c60be"),
30+
ParseHex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f"),
31+
ParseHex("0014542a5a8eea9945cc3d7e24468f108b8e0c721a81"),
32+
ParseHex("020000000365d984d2d0323bbab4807c12c533c014491596929082b1e684205c3fa80397f4010000006b483045022100dfc4741b5dadb6c4c9bd8774d037450e1a281dc2fd73d84115d1d68863d7fc6f02201cfb193bb929ef0e84dfcea5b37bea6484b7a54e79d5a74968a7f3baa79d67880121035b218cb6172451fec3fc467a71938d7e78f425cd76a771da9f193f952ca8c812feffffff6f17f18a671f8e67bdb666e36d8941c1d8ee29b85d9bddbeedbc2973f44fd6bb0000000049483045022100a0848deef222213765ce67f41528e0df6b3877a5f2810d4800759ea8616479ac022058fa148daa1ed7daab46ec0cfe373c17d82d6281cb8e9c7a4a7334136c5e4f0501feffffff9e6a22f9045ec732bad1c0f98d81bd2c9a1b4d4adbfabefb09a9d49e354e80350000000049483045022100ff7c9f9e145c5572d4b21a65a1fbc3331ee3a6757f378554223d963f0f2821d2022048d4c12e7bc4333a2393778645f385f7266176f42e3e86d6af3f0508cc1eed5c01feffffff025892dc01000000001976a914d85a6ba69df7c74e53ec7b99e424c24e2db6d8c988ac00ca9a3b0000000017a914a8105ab6cc3d9aa6ecd9736989d3388c933250e28728030000"),
33+
ParseHex("0000002088912d3d4e77e8b023382aad412b06a56db195666744eb6d37f9a0c40539380b927fd4b53a3bf94e4df21ae6ea8e407a46df057c43477e2f7b27c67c3751d03e8b31c959ffff7f20010000000200000002b96824c26e89b2fa9989c682412fe3a16372fcdf6c0dce872a7e2d2728c6d69f6e441b8424dfddfcae9954c3a603210ef1336ba8a30e63b4fb0a25c6b8103dcd0105")
34+
};
35+
36+
std::vector<unsigned char> pegin_transaction = ParseHex("020000000001016e441b8424dfddfcae9954c3a603210ef1336ba8a30e63b4fb0a25c6b8103dcd0100004000ffffffff0201e48a1a02a8f799892fda58347c2d794144311d4307dbfd10f77ffe28088c60be01000000003b9aade0001976a914a4c05e4e702cec80df26074843a189cfb05bebdb88ac01e48a1a02a8f799892fda58347c2d794144311d4307dbfd10f77ffe28088c60be010000000000001c200000000002483045022100b2d5f19291a3297f28802a6a2bfef2bc0c440660c55a399bfa89533277bcfdcc022042a003eadd85bcc7fb568f9025d6d869ee5e52084613c859cfae6c929766f75e012103ced1fe72e7e33f37747782a505c94f26c1451e8ceceaef8c75f175f87fdb2e87060400ca9a3b20e48a1a02a8f799892fda58347c2d794144311d4307dbfd10f77ffe28088c60be2006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f160014542a5a8eea9945cc3d7e24468f108b8e0c721a81fdc401020000000365d984d2d0323bbab4807c12c533c014491596929082b1e684205c3fa80397f4010000006b483045022100dfc4741b5dadb6c4c9bd8774d037450e1a281dc2fd73d84115d1d68863d7fc6f02201cfb193bb929ef0e84dfcea5b37bea6484b7a54e79d5a74968a7f3baa79d67880121035b218cb6172451fec3fc467a71938d7e78f425cd76a771da9f193f952ca8c812feffffff6f17f18a671f8e67bdb666e36d8941c1d8ee29b85d9bddbeedbc2973f44fd6bb0000000049483045022100a0848deef222213765ce67f41528e0df6b3877a5f2810d4800759ea8616479ac022058fa148daa1ed7daab46ec0cfe373c17d82d6281cb8e9c7a4a7334136c5e4f0501feffffff9e6a22f9045ec732bad1c0f98d81bd2c9a1b4d4adbfabefb09a9d49e354e80350000000049483045022100ff7c9f9e145c5572d4b21a65a1fbc3331ee3a6757f378554223d963f0f2821d2022048d4c12e7bc4333a2393778645f385f7266176f42e3e86d6af3f0508cc1eed5c01feffffff025892dc01000000001976a914d85a6ba69df7c74e53ec7b99e424c24e2db6d8c988ac00ca9a3b0000000017a914a8105ab6cc3d9aa6ecd9736989d3388c933250e28728030000970000002088912d3d4e77e8b023382aad412b06a56db195666744eb6d37f9a0c40539380b927fd4b53a3bf94e4df21ae6ea8e407a46df057c43477e2f7b27c67c3751d03e8b31c959ffff7f20010000000200000002b96824c26e89b2fa9989c682412fe3a16372fcdf6c0dce872a7e2d2728c6d69f6e441b8424dfddfcae9954c3a603210ef1336ba8a30e63b4fb0a25c6b8103dcd01050000000000000000");
37+
38+
COutPoint prevout(uint256S("cd3d10b8c6250afbb4630ea3a86b33f10e2103a6c35499aefcdddf24841b446e"), 1);
39+
40+
// Needed for easier parent PoW check, and setting fedpegscript
41+
struct RegtestingSetup : public TestingSetup {
42+
RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST, "512103dff4923d778550cc13ce0d887d737553b4b58f4e8e886507fc39f5e447b2186451ae") {}
43+
};
44+
45+
BOOST_FIXTURE_TEST_SUITE(pegin_witness_tests, RegtestingSetup)
46+
47+
BOOST_AUTO_TEST_CASE(witness_valid)
48+
{
49+
50+
CScriptWitness witness;
51+
witness.stack = witness_stack;
52+
53+
BOOST_CHECK(IsValidPeginWitness(witness, prevout));
54+
55+
// Missing byte on each field to make claim ill-formatted
56+
// This will break deserialization and other data-matching checks
57+
for (unsigned int i = 0; i < witness.stack.size(); i++) {
58+
witness.stack[i].pop_back();
59+
BOOST_CHECK(!IsValidPeginWitness(witness, prevout));
60+
witness.stack = witness_stack;
61+
BOOST_CHECK(IsValidPeginWitness(witness, prevout));
62+
}
63+
64+
// Test mismatched but valid nOut to proof
65+
COutPoint fake_prevout = prevout;
66+
fake_prevout.n = 0;
67+
BOOST_CHECK(!IsValidPeginWitness(witness, fake_prevout));
68+
69+
// Test mistmatched but valid txid
70+
fake_prevout = prevout;
71+
fake_prevout.hash = uint256S("2f103ee04a5649eecb932b4da4ca9977f53a12bbe04d9d1eb5ccc0f4a06334");
72+
BOOST_CHECK(!IsValidPeginWitness(witness, fake_prevout));
73+
74+
// Ensure that all witness stack sizes are handled
75+
BOOST_CHECK(IsValidPeginWitness(witness, prevout));
76+
for (unsigned int i = 0; i < witness.stack.size(); i++) {
77+
witness.stack.pop_back();
78+
BOOST_CHECK(!IsValidPeginWitness(witness, prevout));
79+
}
80+
witness.stack = witness_stack;
81+
82+
// Extra element causes failure
83+
witness.stack.push_back(witness.stack.back());
84+
BOOST_CHECK(!IsValidPeginWitness(witness, prevout));
85+
witness.stack = witness_stack;
86+
87+
// Check validation of peg-in transaction's inputs and balance
88+
CDataStream ssTx(pegin_transaction, SER_NETWORK, PROTOCOL_VERSION);
89+
CTransactionRef txRef;
90+
ssTx >> txRef;
91+
CTransaction tx(*txRef);
92+
93+
// Only one(valid) input witness should exist, and should match
94+
BOOST_CHECK(tx.wit.vtxinwit.size() == 1);
95+
BOOST_CHECK(tx.wit.vtxinwit[0].m_pegin_witness.stack == witness_stack);
96+
BOOST_CHECK(tx.vin[0].m_is_pegin);
97+
// Check that serialization doesn't cause issuance to become non-null
98+
BOOST_CHECK(tx.vin[0].assetIssuance.IsNull());
99+
BOOST_CHECK(IsValidPeginWitness(tx.wit.vtxinwit[0].m_pegin_witness, prevout));
100+
101+
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
102+
CValidationState state;
103+
CCoinsView coinsDummy;
104+
CCoinsViewCache coins(&coinsDummy);
105+
BOOST_CHECK(Consensus::CheckTxInputs(tx, state, coins, 0, setPeginsSpent, nullptr, false));
106+
BOOST_CHECK(setPeginsSpent.size() == 1);
107+
setPeginsSpent.clear();
108+
109+
// Strip pegin_witness
110+
CMutableTransaction mtxn(tx);
111+
mtxn.wit.vtxinwit[0].m_pegin_witness.SetNull();
112+
CTransaction tx2(mtxn);
113+
BOOST_CHECK(!Consensus::CheckTxInputs(tx2, state, coins, 0, setPeginsSpent, nullptr, false));
114+
BOOST_CHECK(setPeginsSpent.empty());
115+
116+
// Invalidate peg-in (and spending) authorization by pegin marker.
117+
// This only checks for peg-in authorization, with the only input marked
118+
// as m_is_pegin
119+
CMutableTransaction mtxn2(tx);
120+
mtxn2.vin[0].m_is_pegin = false;
121+
CTransaction tx3(mtxn2);
122+
BOOST_CHECK(!Consensus::CheckTxInputs(tx3, state, coins, 0, setPeginsSpent, nullptr, false));
123+
BOOST_CHECK(setPeginsSpent.empty());
124+
125+
126+
// TODO Test mixed pegin/non-pegin input case
127+
// TODO Test spending authorization in conjunction with valid witness program in pegin auth
128+
129+
}
130+
131+
BOOST_AUTO_TEST_SUITE_END()

src/test/test_bitcoin.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ FastRandomContext insecure_rand_ctx(true);
3737
extern bool fPrintToConsole;
3838
extern void noui_connect();
3939

40-
BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
40+
BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::string& fedpegscript)
4141
{
4242
ECC_Start();
4343
SetupEnvironment();
@@ -47,6 +47,10 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
4747
InitSurjectionproofCache();
4848
fPrintToDebugLog = false; // don't want to write to debug.log file
4949
fCheckBlockIndex = true;
50+
// Hack to allow testing of fedpeg args
51+
if (!fedpegscript.empty()) {
52+
SoftSetArg("-fedpegscript", fedpegscript);
53+
}
5054
SelectParams(chainName);
5155
noui_connect();
5256
}
@@ -57,7 +61,7 @@ BasicTestingSetup::~BasicTestingSetup()
5761
g_connman.reset();
5862
}
5963

60-
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
64+
TestingSetup::TestingSetup(const std::string& chainName, const std::string& fedpegscript) : BasicTestingSetup(chainName, fedpegscript)
6165
{
6266
const CChainParams& chainparams = Params();
6367
// Ideally we'd move all the RPC tests to the functional testing framework

src/test/test_bitcoin.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
struct BasicTestingSetup {
2121
ECCVerifyHandle globalVerifyHandle;
2222

23-
BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
23+
BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::string& fedpegscript = "");
2424
~BasicTestingSetup();
2525
};
2626

@@ -35,7 +35,7 @@ struct TestingSetup: public BasicTestingSetup {
3535
CConnman* connman;
3636
CKey coinbaseKey; // private/public key needed to spend coinbase transactions
3737

38-
TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
38+
TestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::string& fedpegscript = "");
3939
~TestingSetup();
4040
};
4141

src/validation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,6 +2399,9 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p
23992399
CScript fedpegscript = Params().GetConsensus().fedpegScript;
24002400

24012401
// fedpegscript should be multisig or OP_TRUE
2402+
// When set to OP_TRUE, the witness program can be any valid witness program
2403+
// as there are no pubkeys to tweak. This means typically in regtest there
2404+
// is no spending authorization for peg-in inputs.
24022405
txnouttype type;
24032406
std::vector<std::vector<unsigned char> > solutions;
24042407
if (!Solver(fedpegscript, type, solutions) || (type != TX_MULTISIG && type != TX_TRUE)) {

0 commit comments

Comments
 (0)