2 #include <cryptoconditions.h>
3 #include <gtest/gtest.h>
6 #include "importcoin.h"
11 #include "primitives/transaction.h"
12 #include "script/cc.h"
13 #include "script/interpreter.h"
14 #include "script/serverchecker.h"
15 #include "txmempool.h"
17 #include "testutils.h"
20 extern Eval* EVAL_TEST;
22 namespace TestCoinImport {
25 static uint8_t testNum = 0;
27 class TestCoinImport : public ::testing::Test, public Eval {
29 CMutableTransaction burnTx;
30 std::vector<CTxOut> payouts;
33 CMutableTransaction importTx;
38 burnTx.vout.resize(0);
39 burnTx.vout.push_back(MakeBurnOutput(amount, chainId, payouts));
40 MoMoM = burnTx.GetHash(); // TODO: an actual branch
41 importTx = CMutableTransaction(MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts));
44 uint32_t GetCurrentLedgerID() const { return chainId; }
46 bool GetNotarisationData(int notarisationHeight, NotarisationData &data, bool verifyCanonical) const
48 if (MoMoM.IsNull()) return false;
54 static void SetUpTestCase() { setupChain(); }
55 virtual void SetUp() {
59 std::vector<uint8_t> fakepk;
61 fakepk.begin()[0] = testNum++;
62 payouts.push_back(CTxOut(amount, CScript() << fakepk << OP_CHECKSIG));
67 void TestRunCCEval(CMutableTransaction mtx)
69 CTransaction importTx(mtx);
70 PrecomputedTransactionData txdata(importTx);
71 ServerTransactionSignatureChecker checker(&importTx, 0, 0, false, txdata);
72 CValidationState verifystate;
73 if (!VerifyCoinImport(importTx.vin[0].scriptSig, checker, verifystate))
74 printf("TestRunCCEval: %s\n", verifystate.GetRejectReason().data());
79 TEST_F(TestCoinImport, testProcessImportThroughPipeline)
81 CValidationState mainstate;
82 CTransaction tx(importTx);
87 // should fail in mempool
88 ASSERT_FALSE(acceptTx(tx, mainstate));
89 EXPECT_EQ("already in mempool", mainstate.GetRejectReason());
91 // should be in persisted UTXO set
93 ASSERT_FALSE(acceptTx(tx, mainstate));
94 EXPECT_EQ("already have coins", mainstate.GetRejectReason());
95 ASSERT_TRUE(pcoinsTip->HaveCoins(tx.GetHash()));
97 // Now disconnect the block
98 CValidationState invalstate;
99 if (!InvalidateBlock(invalstate, chainActive.Tip())) {
100 FAIL() << invalstate.GetRejectReason();
102 ASSERT_FALSE(pcoinsTip->HaveCoins(tx.GetHash()));
104 // should be back in mempool
105 ASSERT_FALSE(acceptTx(tx, mainstate));
106 EXPECT_EQ("already in mempool", mainstate.GetRejectReason());
110 TEST_F(TestCoinImport, testImportTombstone)
112 CValidationState mainstate;
113 // By setting an unspendable output, there will be no addition to UTXO
114 // Nonetheless, we dont want to be able to import twice
115 payouts[0].scriptPubKey = CScript() << OP_RETURN;
117 MoMoM = burnTx.GetHash(); // TODO: an actual branch
118 CTransaction tx(importTx);
123 // should be in persisted UTXO set
125 ASSERT_FALSE(acceptTx(tx, mainstate));
126 EXPECT_EQ("import tombstone exists", mainstate.GetRejectReason());
127 ASSERT_TRUE(pcoinsTip->HaveCoins(burnTx.GetHash()));
129 // Now disconnect the block
130 CValidationState invalstate;
131 if (!InvalidateBlock(invalstate, chainActive.Tip())) {
132 FAIL() << invalstate.GetRejectReason();
134 // Tombstone should be gone from utxo set
135 ASSERT_FALSE(pcoinsTip->HaveCoins(burnTx.GetHash()));
137 // should be back in mempool
138 ASSERT_FALSE(acceptTx(tx, mainstate));
139 EXPECT_EQ("already in mempool", mainstate.GetRejectReason());
143 TEST_F(TestCoinImport, testNoVouts)
145 importTx.vout.resize(0);
146 TestRunCCEval(importTx);
147 EXPECT_EQ("no-vouts", state.GetRejectReason());
151 TEST_F(TestCoinImport, testInvalidParams)
153 std::vector<uint8_t> payload = E_MARSHAL(ss << EVAL_IMPORTCOIN; ss << 'a');
154 importTx.vin[0].scriptSig = CScript() << payload;
155 TestRunCCEval(importTx);
156 EXPECT_EQ("invalid-params", state.GetRejectReason());
160 TEST_F(TestCoinImport, testNonCanonical)
162 importTx.nLockTime = 10;
163 TestRunCCEval(importTx);
164 EXPECT_EQ("non-canonical", state.GetRejectReason());
168 TEST_F(TestCoinImport, testInvalidBurnOutputs)
170 burnTx.vout.resize(0);
171 MoMoM = burnTx.GetHash(); // TODO: an actual branch
172 CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts);
174 EXPECT_EQ("invalid-burn-outputs", state.GetRejectReason());
178 TEST_F(TestCoinImport, testInvalidBurnParams)
180 burnTx.vout[0].scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << VARINT(chainId));
181 MoMoM = burnTx.GetHash(); // TODO: an actual branch
182 CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts);
184 EXPECT_EQ("invalid-burn-params", state.GetRejectReason());
188 TEST_F(TestCoinImport, testWrongChainId)
191 TestRunCCEval(importTx);
192 EXPECT_EQ("importcoin-wrong-chain", state.GetRejectReason());
196 TEST_F(TestCoinImport, testInvalidBurnAmount)
198 burnTx.vout[0].nValue = 0;
199 MoMoM = burnTx.GetHash(); // TODO: an actual branch
200 CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts);
202 EXPECT_EQ("invalid-burn-amount", state.GetRejectReason());
206 TEST_F(TestCoinImport, testPayoutTooHigh)
208 importTx.vout[0].nValue = 101;
209 TestRunCCEval(importTx);
210 EXPECT_EQ("payout-too-high", state.GetRejectReason());
214 TEST_F(TestCoinImport, testInvalidPayouts)
216 importTx.vout[0].nValue = 40;
217 importTx.vout.push_back(importTx.vout[0]);
218 TestRunCCEval(importTx);
219 EXPECT_EQ("wrong-payouts", state.GetRejectReason());
223 TEST_F(TestCoinImport, testCouldntLoadMomom)
226 TestRunCCEval(importTx);
227 EXPECT_EQ("coudnt-load-momom", state.GetRejectReason());
231 TEST_F(TestCoinImport, testMomomCheckFail)
234 MoMoM.begin()[0] = 1;
235 TestRunCCEval(importTx);
236 EXPECT_EQ("momom-check-fail", state.GetRejectReason());
239 } /* namespace TestCoinImport */