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;
34 uint32_t testCcid = 2;
35 std::string testSymbol = "PIZZA";
39 burnTx.vout.resize(0);
40 burnTx.vout.push_back(MakeBurnOutput(amount, testCcid, testSymbol, payouts));
41 importTx = CMutableTransaction(MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts));
42 MoMoM = burnTx.GetHash(); // TODO: an actual branch
45 uint32_t GetAssetchainsCC() const { return testCcid; }
46 std::string GetAssetchainsSymbol() const { return testSymbol; }
48 bool GetProofRoot(uint256 hash, uint256 &momom) const
50 if (MoMoM.IsNull()) return false;
57 static void SetUpTestCase() { setupChain(); }
58 virtual void SetUp() {
62 std::vector<uint8_t> fakepk;
64 fakepk.begin()[0] = testNum++;
65 payouts.push_back(CTxOut(amount, CScript() << fakepk << OP_CHECKSIG));
70 void TestRunCCEval(CMutableTransaction mtx)
72 CTransaction importTx(mtx);
73 PrecomputedTransactionData txdata(importTx);
74 ServerTransactionSignatureChecker checker(&importTx, 0, 0, false, txdata);
75 CValidationState verifystate;
76 if (!VerifyCoinImport(importTx.vin[0].scriptSig, checker, verifystate))
77 printf("TestRunCCEval: %s\n", verifystate.GetRejectReason().data());
82 TEST_F(TestCoinImport, testProcessImportThroughPipeline)
84 CValidationState mainstate;
85 CTransaction tx(importTx);
90 // should fail in mempool
91 ASSERT_FALSE(acceptTx(tx, mainstate));
92 EXPECT_EQ("already in mempool", mainstate.GetRejectReason());
94 // should be in persisted UTXO set
96 ASSERT_FALSE(acceptTx(tx, mainstate));
97 EXPECT_EQ("already have coins", mainstate.GetRejectReason());
98 ASSERT_TRUE(pcoinsTip->HaveCoins(tx.GetHash()));
100 // Now disconnect the block
101 CValidationState invalstate;
102 if (!InvalidateBlock(invalstate, Params(), chainActive.Tip())) {
103 FAIL() << invalstate.GetRejectReason();
105 ASSERT_FALSE(pcoinsTip->HaveCoins(tx.GetHash()));
107 // should be back in mempool
108 ASSERT_FALSE(acceptTx(tx, mainstate));
109 EXPECT_EQ("already in mempool", mainstate.GetRejectReason());
113 TEST_F(TestCoinImport, testImportTombstone)
115 CValidationState mainstate;
116 // By setting an unspendable output, there will be no addition to UTXO
117 // Nonetheless, we dont want to be able to import twice
118 payouts[0].scriptPubKey = CScript() << OP_RETURN;
120 MoMoM = burnTx.GetHash(); // TODO: an actual branch
121 CTransaction tx(importTx);
126 // should be in persisted UTXO set
128 ASSERT_FALSE(acceptTx(tx, mainstate));
129 EXPECT_EQ("import tombstone exists", mainstate.GetRejectReason());
130 ASSERT_TRUE(pcoinsTip->HaveCoins(burnTx.GetHash()));
132 // Now disconnect the block
133 CValidationState invalstate;
134 if (!InvalidateBlock(invalstate, Params(), chainActive.Tip())) {
135 FAIL() << invalstate.GetRejectReason();
137 // Tombstone should be gone from utxo set
138 ASSERT_FALSE(pcoinsTip->HaveCoins(burnTx.GetHash()));
140 // should be back in mempool
141 ASSERT_FALSE(acceptTx(tx, mainstate));
142 EXPECT_EQ("already in mempool", mainstate.GetRejectReason());
146 TEST_F(TestCoinImport, testNoVouts)
148 importTx.vout.resize(0);
149 TestRunCCEval(importTx);
150 EXPECT_EQ("too-few-vouts", state.GetRejectReason());
154 TEST_F(TestCoinImport, testInvalidParams)
156 std::vector<uint8_t> payload = E_MARSHAL(ss << EVAL_IMPORTCOIN; ss << 'a');
157 importTx.vin[0].scriptSig = CScript() << payload;
158 TestRunCCEval(importTx);
159 EXPECT_EQ("invalid-params", state.GetRejectReason());
163 TEST_F(TestCoinImport, testNonCanonical)
165 importTx.nLockTime = 10;
166 TestRunCCEval(importTx);
167 EXPECT_EQ("non-canonical", state.GetRejectReason());
171 TEST_F(TestCoinImport, testInvalidBurnOutputs)
173 burnTx.vout.resize(0);
174 MoMoM = burnTx.GetHash(); // TODO: an actual branch
175 CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts);
177 EXPECT_EQ("invalid-burn-tx", state.GetRejectReason());
181 TEST_F(TestCoinImport, testInvalidBurnParams)
183 burnTx.vout.back().scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << VARINT(testCcid));
184 MoMoM = burnTx.GetHash(); // TODO: an actual branch
185 CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts);
187 EXPECT_EQ("invalid-burn-tx", state.GetRejectReason());
191 TEST_F(TestCoinImport, testWrongChainId)
194 TestRunCCEval(importTx);
195 EXPECT_EQ("importcoin-wrong-chain", state.GetRejectReason());
199 TEST_F(TestCoinImport, testInvalidBurnAmount)
201 burnTx.vout.back().nValue = 0;
202 MoMoM = burnTx.GetHash(); // TODO: an actual branch
203 CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts);
205 EXPECT_EQ("invalid-burn-amount", state.GetRejectReason());
209 TEST_F(TestCoinImport, testPayoutTooHigh)
211 importTx.vout[1].nValue = 101;
212 TestRunCCEval(importTx);
213 EXPECT_EQ("payout-too-high", state.GetRejectReason());
217 TEST_F(TestCoinImport, testAmountInOpret)
219 importTx.vout[0].nValue = 1;
220 TestRunCCEval(importTx);
221 EXPECT_EQ("non-canonical", state.GetRejectReason());
226 TEST_F(TestCoinImport, testInvalidPayouts)
228 importTx.vout[1].nValue = 40;
229 importTx.vout.push_back(importTx.vout[0]);
230 TestRunCCEval(importTx);
231 EXPECT_EQ("wrong-payouts", state.GetRejectReason());
235 TEST_F(TestCoinImport, testCouldntLoadMomom)
238 TestRunCCEval(importTx);
239 EXPECT_EQ("coudnt-load-momom", state.GetRejectReason());
243 TEST_F(TestCoinImport, testMomomCheckFail)
246 MoMoM.begin()[0] = 1;
247 TestRunCCEval(importTx);
248 EXPECT_EQ("momom-check-fail", state.GetRejectReason());
252 TEST_F(TestCoinImport, testGetCoinImportValue)
254 ASSERT_EQ(100, GetCoinImportValue(importTx));
257 } /* namespace TestCoinImport */