Duke
3 months ago
5 changed files with 7 additions and 1060 deletions
@ -1,203 +0,0 @@ |
|||
// Copyright (c) 2016-2023 The Hush developers
|
|||
// Distributed under the GPLv3 software license, see the accompanying
|
|||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|||
#include <cryptoconditions.h> |
|||
#include <gtest/gtest.h> |
|||
|
|||
#include "base58.h" |
|||
#include "key.h" |
|||
#include "script/cc.h" |
|||
#include "cc/eval.h" |
|||
#include "primitives/transaction.h" |
|||
#include "script/interpreter.h" |
|||
#include "script/serverchecker.h" |
|||
|
|||
#include "testutils.h" |
|||
|
|||
|
|||
|
|||
class CCTest : public ::testing::Test { |
|||
public: |
|||
void CCSign(CMutableTransaction &tx, CC *cond) { |
|||
tx.vin.resize(1); |
|||
PrecomputedTransactionData txdata(tx); |
|||
uint256 sighash = SignatureHash(CCPubKey(cond), tx, 0, SIGHASH_ALL, 0, 0, &txdata); |
|||
|
|||
int out = cc_signTreeSecp256k1Msg32(cond, notaryKey.begin(), sighash.begin()); |
|||
tx.vin[0].scriptSig = CCSig(cond); |
|||
} |
|||
protected: |
|||
virtual void SetUp() { |
|||
// enable CC
|
|||
ASSETCHAINS_CC = 1; |
|||
} |
|||
}; |
|||
|
|||
|
|||
TEST_F(CCTest, testIsPayToCryptoCondition) |
|||
{ |
|||
CScript s = CScript() << VCH("a", 1); |
|||
ASSERT_FALSE(s.IsPayToCryptoCondition()); |
|||
|
|||
s = CScript() << VCH("a", 1) << OP_CHECKCRYPTOCONDITION; |
|||
ASSERT_TRUE(s.IsPayToCryptoCondition()); |
|||
|
|||
s = CScript() << OP_CHECKCRYPTOCONDITION; |
|||
ASSERT_FALSE(s.IsPayToCryptoCondition()); |
|||
} |
|||
|
|||
|
|||
TEST_F(CCTest, testMayAcceptCryptoCondition) |
|||
{ |
|||
CC *cond; |
|||
|
|||
// ok
|
|||
CCFromJson(cond, R"!!( |
|||
{ "type": "threshold-sha-256", |
|||
"threshold": 2, |
|||
"subfulfillments": [ |
|||
{ "type": "secp256k1-sha-256", "publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" } |
|||
] |
|||
})!!"); |
|||
ASSERT_TRUE(CCPubKey(cond).MayAcceptCryptoCondition()); |
|||
|
|||
|
|||
// prefix not allowed
|
|||
CCFromJson(cond, R"!!( |
|||
{ "type": "prefix-sha-256", |
|||
"prefix": "abc", |
|||
"maxMessageLength": 10, |
|||
"subfulfillment": |
|||
{ "type": "secp256k1-sha-256", "publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" } |
|||
})!!"); |
|||
ASSERT_FALSE(CCPubKey(cond).MayAcceptCryptoCondition()); |
|||
|
|||
|
|||
// has no signature nodes
|
|||
CCFromJson(cond, R"!!( |
|||
{ "type": "threshold-sha-256", |
|||
"threshold": 1, |
|||
"subfulfillments": [ |
|||
{ "type": "eval-sha-256", "code": "" }, |
|||
{ "type": "eval-sha-256", "code": "" } |
|||
] |
|||
})!!"); |
|||
ASSERT_FALSE(CCPubKey(cond).MayAcceptCryptoCondition()); |
|||
} |
|||
|
|||
|
|||
static bool CCVerify(const CMutableTransaction &mtxTo, const CC *cond) { |
|||
CAmount amount; |
|||
ScriptError error; |
|||
CTransaction txTo(mtxTo); |
|||
PrecomputedTransactionData txdata(txTo); |
|||
auto checker = ServerTransactionSignatureChecker(&txTo, 0, amount, false, txdata); |
|||
return VerifyScript(CCSig(cond), CCPubKey(cond), 0, checker, 0, &error); |
|||
}; |
|||
|
|||
|
|||
TEST_F(CCTest, testVerifyCryptoCondition) |
|||
{ |
|||
CC *cond; |
|||
CMutableTransaction mtxTo; |
|||
|
|||
// ok
|
|||
cond = CCNewSecp256k1(notaryKey.GetPubKey()); |
|||
CCFromJson(cond, R"!!({ |
|||
"type": "secp256k1-sha-256", |
|||
"publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" |
|||
})!!"); |
|||
CCSign(mtxTo, cond); |
|||
ASSERT_TRUE(CCVerify(mtxTo, cond)); |
|||
|
|||
|
|||
// has signature nodes
|
|||
CCFromJson(cond, R"!!({ |
|||
"type": "threshold-sha-256", |
|||
"threshold": 1, |
|||
"subfulfillments": [ |
|||
{ "type": "preimage-sha-256", "preimage": "" }, |
|||
{ "type": "secp256k1-sha-256", "publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" } |
|||
] |
|||
})!!"); |
|||
cond->threshold = 2; |
|||
CCSign(mtxTo, cond); |
|||
ASSERT_TRUE(CCVerify(mtxTo, cond)); |
|||
|
|||
// no signatures; the preimage will get encoded as a fulfillment because it's cheaper
|
|||
// and the secp256k1 node will get encoded as a condition
|
|||
cond->threshold = 1; |
|||
ASSERT_FALSE(CCVerify(mtxTo, cond)); |
|||
|
|||
// here the signature is set wrong
|
|||
cond->threshold = 2; |
|||
ASSERT_TRUE(CCVerify(mtxTo, cond)); |
|||
memset(cond->subconditions[1]->signature, 0, 32); |
|||
ASSERT_FALSE(CCVerify(mtxTo, cond)); |
|||
} |
|||
|
|||
extern Eval* EVAL_TEST; |
|||
|
|||
TEST_F(CCTest, testVerifyEvalCondition) |
|||
{ |
|||
|
|||
class EvalMock : public Eval |
|||
{ |
|||
public: |
|||
bool Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) |
|||
{ return cond->code[0] ? Valid() : Invalid(""); } |
|||
}; |
|||
|
|||
EvalMock eval; |
|||
EVAL_TEST = &eval; |
|||
|
|||
|
|||
CC *cond; |
|||
CMutableTransaction mtxTo; |
|||
|
|||
// ok
|
|||
cond = CCNewThreshold(2, { CCNewSecp256k1(notaryKey.GetPubKey()), CCNewEval({1}) }); |
|||
CCSign(mtxTo, cond); |
|||
ASSERT_TRUE(CCVerify(mtxTo, cond)); |
|||
|
|||
cond->subconditions[1]->code[0] = 0; |
|||
ASSERT_FALSE(CCVerify(mtxTo, cond)); |
|||
} |
|||
|
|||
|
|||
TEST_F(CCTest, testCryptoConditionsDisabled) |
|||
{ |
|||
CC *cond; |
|||
ScriptError error; |
|||
CMutableTransaction mtxTo; |
|||
|
|||
// ok
|
|||
CCFromJson(cond, R"!!({ |
|||
"type": "secp256k1-sha-256", |
|||
"publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" |
|||
})!!"); |
|||
CCSign(mtxTo, cond); |
|||
ASSERT_TRUE(CCVerify(mtxTo, cond)); |
|||
|
|||
ASSETCHAINS_CC = 0; |
|||
ASSERT_FALSE(CCVerify(mtxTo, cond)); |
|||
} |
|||
|
|||
|
|||
TEST_F(CCTest, testLargeCondition) |
|||
{ |
|||
CC *cond; |
|||
ScriptError error; |
|||
CMutableTransaction mtxTo; |
|||
|
|||
std::vector<CC*> ccs; |
|||
for (int i=0; i<18; i++) { |
|||
ccs.push_back(CCNewSecp256k1(notaryKey.GetPubKey())); |
|||
} |
|||
cond = CCNewThreshold(16, ccs); |
|||
CCSign(mtxTo, cond); |
|||
EXPECT_EQ("(16 of 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,A5,A5)", |
|||
CCShowStructure(CCPrune(cond))); |
|||
EXPECT_EQ(1744, CCSig(cond).size()); |
|||
ASSERT_TRUE(CCVerify(mtxTo, cond)); |
|||
} |
@ -1,597 +0,0 @@ |
|||
// Copyright (c) 2016-2023 The Hush developers
|
|||
// Distributed under the GPLv3 software license, see the accompanying
|
|||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|||
#include <cryptoconditions.h> |
|||
#include <gtest/gtest.h> |
|||
#include "cc/betprotocol.h" |
|||
#include "cc/eval.h" |
|||
#include "base58.h" |
|||
#include "key.h" |
|||
#include "main.h" |
|||
#include "script/cc.h" |
|||
#include "primitives/transaction.h" |
|||
#include "script/interpreter.h" |
|||
#include "script/serverchecker.h" |
|||
#include "testutils.h" |
|||
|
|||
extern Eval* EVAL_TEST; |
|||
|
|||
namespace TestBet { |
|||
|
|||
static std::vector<CKey> playerSecrets; |
|||
static std::vector<CPubKey> players; |
|||
|
|||
static int Dealer = 0, Player1 = 1, Player2 = 2; |
|||
|
|||
|
|||
int CCSign(CMutableTransaction &tx, unsigned int nIn, CC *cond, std::vector<int> keyIds) { |
|||
PrecomputedTransactionData txdata(tx); |
|||
uint256 sighash = SignatureHash(CCPubKey(cond), tx, nIn, SIGHASH_ALL, 0, 0, &txdata); |
|||
int nSigned = 0; |
|||
for (int i=0; i<keyIds.size(); i++) |
|||
nSigned += cc_signTreeSecp256k1Msg32(cond, playerSecrets[keyIds[i]].begin(), sighash.begin()); |
|||
tx.vin[nIn].scriptSig = CCSig(cond); |
|||
return nSigned; |
|||
} |
|||
|
|||
|
|||
int TestCC(CMutableTransaction &mtxTo, unsigned int nIn, CC *cond) |
|||
{ |
|||
CAmount amount; |
|||
ScriptError error; |
|||
CTransaction txTo(mtxTo); |
|||
PrecomputedTransactionData txdata(txTo); |
|||
auto checker = ServerTransactionSignatureChecker(&txTo, nIn, amount, false, txdata); |
|||
return VerifyScript(txTo.vin[nIn].scriptSig, CCPubKey(cond), 0, checker, 0, &error); |
|||
} |
|||
|
|||
|
|||
#define ASSERT_CC(tx, nIn, cond) if (!TestCC(tx, nIn, cond)) FAIL(); |
|||
|
|||
|
|||
class MockVM : public AppVM |
|||
{ |
|||
public: |
|||
std::pair<int,std::vector<CTxOut>> evaluate( |
|||
std::vector<unsigned char> header, std::vector<unsigned char> body) |
|||
{ |
|||
std::vector<CTxOut> outs; |
|||
if (memcmp(header.data(), "BetHeader", 9)) { |
|||
printf("Wrong VM header\n"); |
|||
return std::make_pair(0, outs); |
|||
} |
|||
outs.push_back(CTxOut(2, CScript() << OP_RETURN << body.size())); |
|||
return std::make_pair(body.size(), outs); |
|||
} |
|||
}; |
|||
|
|||
const EvalCode EVAL_DISPUTEBET = 0xf2; |
|||
|
|||
class EvalMock : public Eval |
|||
{ |
|||
public: |
|||
uint256 MoM; |
|||
int currentHeight; |
|||
std::map<uint256, CTransaction> txs; |
|||
std::map<uint256, CBlockIndex> blocks; |
|||
std::map<uint256, std::vector<CTransaction>> spends; |
|||
|
|||
bool Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) |
|||
{ |
|||
EvalCode ecode = cond->code[0]; |
|||
std::vector<uint8_t> vparams(cond->code+1, cond->code+cond->codeLength); |
|||
|
|||
if (ecode == EVAL_DISPUTEBET) { |
|||
MockVM vm; |
|||
return DisputePayout(vm, vparams, txTo, nIn); |
|||
} |
|||
if (ecode == EVAL_IMPORTPAYOUT) { |
|||
return ImportPayout(vparams, txTo, nIn); |
|||
} |
|||
return Invalid("invalid-code"); |
|||
} |
|||
|
|||
bool GetSpendsConfirmed(uint256 hash, std::vector<CTransaction> &spendsOut) const |
|||
{ |
|||
auto r = spends.find(hash); |
|||
if (r != spends.end()) { |
|||
spendsOut = r->second; |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
bool GetTxUnconfirmed(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) const |
|||
{ |
|||
auto r = txs.find(hash); |
|||
if (r != txs.end()) { |
|||
txOut = r->second; |
|||
if (blocks.count(hash) > 0) |
|||
hashBlock = hash; |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
unsigned int GetCurrentHeight() const { return currentHeight; } |
|||
|
|||
bool GetBlock(uint256 hash, CBlockIndex& blockIdx) const |
|||
{ |
|||
auto r = blocks.find(hash); |
|||
if (r == blocks.end()) return false; |
|||
blockIdx = r->second; |
|||
return true; |
|||
} |
|||
|
|||
bool GetNotarizationData(uint256 notarizationHash, NotarizationData &data) const |
|||
{ |
|||
if (notarizationHash == NotarizationHash()) { |
|||
data.MoM = MoM; |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
static uint256 NotarizationHash() |
|||
{ |
|||
uint256 h; |
|||
h.begin()[0] = 123; |
|||
return h; |
|||
} |
|||
}; |
|||
|
|||
|
|||
/*
|
|||
* Generates example data that we will test with and shows how to call BetProtocol. |
|||
*/ |
|||
class ExampleBet |
|||
{ |
|||
public: |
|||
BetProtocol bet; |
|||
CAmount totalPayout; |
|||
|
|||
ExampleBet() : bet(BetProtocol(EVAL_DISPUTEBET, players, 2, VCH("BetHeader", 9))), totalPayout(100) {} |
|||
~ExampleBet() {}; |
|||
|
|||
CTransaction SessionTx() |
|||
{ |
|||
return CTransaction(bet.MakeSessionTx(1)); |
|||
} |
|||
|
|||
CC* DisputeCond() |
|||
{ |
|||
return bet.MakeDisputeCond(); |
|||
} |
|||
|
|||
CC* PayoutCond() |
|||
{ |
|||
return bet.MakePayoutCond(SessionTx().GetHash()); |
|||
} |
|||
|
|||
CTransaction StakeTx() |
|||
{ |
|||
return CTransaction(bet.MakeStakeTx(totalPayout, SessionTx().GetHash())); |
|||
} |
|||
|
|||
std::vector<unsigned char> PlayerState(int playerIdx) |
|||
{ |
|||
std::vector<unsigned char> state; |
|||
for (int i=0; i<playerIdx+1; i++) state.push_back(1); |
|||
return state; |
|||
} |
|||
|
|||
std::vector<CTxOut> Payouts(int playerIdx) |
|||
{ |
|||
return MockVM().evaluate(bet.vmParams, PlayerState(playerIdx)).second; |
|||
} |
|||
|
|||
CMutableTransaction DisputeTx(int playerIdx) |
|||
{ |
|||
return bet.MakeDisputeTx(SessionTx().GetHash(), SerializeHash(Payouts(playerIdx))); |
|||
} |
|||
|
|||
CMutableTransaction PostEvidenceTx(int playerIdx) |
|||
{ |
|||
return bet.MakePostEvidenceTx(SessionTx().GetHash(), playerIdx, PlayerState(playerIdx)); |
|||
} |
|||
|
|||
CMutableTransaction AgreePayoutTx() |
|||
{ |
|||
std::vector<CTxOut> v; |
|||
return bet.MakeAgreePayoutTx(v, uint256()); |
|||
} |
|||
|
|||
MoMProof GetMoMProof() |
|||
{ |
|||
int nIndex = 5; |
|||
std::vector<uint256> vBranch; |
|||
vBranch.resize(3); |
|||
return {MerkleBranch(nIndex, vBranch), EvalMock::NotarizationHash()}; |
|||
} |
|||
|
|||
CMutableTransaction ImportPayoutTx() |
|||
{ |
|||
CMutableTransaction disputeTx = DisputeTx(Player2); |
|||
return bet.MakeImportPayoutTx(Payouts(Player2), disputeTx, uint256(), GetMoMProof()); |
|||
} |
|||
|
|||
EvalMock SetEvalMock(int currentHeight) |
|||
{ |
|||
EvalMock eval; |
|||
CTransaction sessionTx = SessionTx(); |
|||
|
|||
eval.txs[sessionTx.GetHash()] = sessionTx; |
|||
|
|||
CBlockIndex sessionBlock; |
|||
sessionBlock.SetHeight(10); |
|||
eval.blocks[sessionTx.GetHash()] = sessionBlock; |
|||
|
|||
std::vector<CTransaction> sessionSpends; |
|||
sessionSpends.push_back(CTransaction(PostEvidenceTx(Dealer))); |
|||
sessionSpends.push_back(CTransaction()); // Invalid, should be ignored
|
|||
sessionSpends.push_back(CTransaction(PostEvidenceTx(Player2))); |
|||
eval.spends[sessionTx.GetHash()] = sessionSpends; |
|||
|
|||
eval.currentHeight = currentHeight; |
|||
|
|||
MoMProof proof = GetMoMProof(); |
|||
eval.MoM = proof.branch.Exec(DisputeTx(Player2).GetHash()); |
|||
|
|||
EVAL_TEST = &eval; |
|||
return eval; |
|||
} |
|||
}; |
|||
|
|||
|
|||
ExampleBet ebet; |
|||
|
|||
|
|||
class TestBet : public ::testing::Test { |
|||
protected: |
|||
static void SetUpTestCase() { |
|||
// Make playerSecrets
|
|||
CBitcoinSecret vchSecret; |
|||
auto addKey = [&] (std::string k) { vchSecret.SetString(k); playerSecrets.push_back(vchSecret.GetKey()); }; |
|||
addKey("UwFBKf4d6wC3yqdnk3LoGrFjy7gwxrWerBT8jTFamrBbem8wSw9L"); |
|||
addKey("Up6GpWwrmx2VpqF8rD3snJXToKT56Dzc8YSoL24osXnfNdCucaMR"); |
|||
addKey("UxEHwki3A95PSHHVRzE2N67eHTeoUcqLkovxp6yDPVViv54skF8c"); |
|||
// Make playerpubkeys
|
|||
for (int i=0; i<playerSecrets.size(); i++) players.push_back(playerSecrets[i].GetPubKey()); |
|||
// enable CC
|
|||
ASSETCHAINS_CC = 1; |
|||
} |
|||
virtual void SetUp() { |
|||
EVAL_TEST = 0; |
|||
ebet = ExampleBet(); |
|||
} |
|||
}; |
|||
|
|||
|
|||
TEST_F(TestBet, testMakeSessionTx) |
|||
{ |
|||
CTransaction sessionTx = ebet.SessionTx(); |
|||
EXPECT_EQ(0, sessionTx.vin.size()); |
|||
EXPECT_EQ(4, sessionTx.vout.size()); |
|||
EXPECT_EQ(CCPubKey(ebet.DisputeCond()), sessionTx.vout[0].scriptPubKey); |
|||
for (int i=0; i<players.size(); i++) |
|||
EXPECT_EQ(CCPubKey(CCNewSecp256k1(players[i])), sessionTx.vout[i+1].scriptPubKey); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testMakeDisputeCond) |
|||
{ |
|||
CC *disputeCond = ebet.DisputeCond(); |
|||
EXPECT_EQ("(2 of 15,(1 of 5,5,5))", CCShowStructure(disputeCond)); |
|||
|
|||
CC *evalCond = disputeCond->subconditions[0]; |
|||
uint8_t target[100]; |
|||
sprintf((char*)target, "%c\x02\tBetHeader", EVAL_DISPUTEBET); |
|||
EXPECT_EQ(0, memcmp(target, evalCond->code, 12)); |
|||
|
|||
for (int i=0; i<players.size(); i++) |
|||
EXPECT_EQ(CCPubKey(CCNewSecp256k1(players[i])), |
|||
CCPubKey(disputeCond->subconditions[1]->subconditions[i])); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testSignDisputeCond) |
|||
{ |
|||
// Only one key needed to dispute
|
|||
CMutableTransaction disputeTx = ebet.DisputeTx(Player1); |
|||
CC *disputeCond = ebet.DisputeCond(); |
|||
EXPECT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player1})); |
|||
|
|||
EXPECT_EQ(1, cc_isFulfilled(disputeCond->subconditions[0])); |
|||
EXPECT_EQ(1, cc_isFulfilled(disputeCond->subconditions[1])); |
|||
EXPECT_EQ(0, cc_isFulfilled(disputeCond->subconditions[1]->subconditions[0])); |
|||
EXPECT_EQ(1, cc_isFulfilled(disputeCond->subconditions[1]->subconditions[1])); |
|||
EXPECT_EQ(0, cc_isFulfilled(disputeCond->subconditions[1]->subconditions[2])); |
|||
EXPECT_EQ(1, cc_isFulfilled(disputeCond)); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testDispute) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(12); |
|||
|
|||
// Only one key needed to dispute
|
|||
CMutableTransaction disputeTx = ebet.DisputeTx(Player2); |
|||
CC *disputeCond = ebet.DisputeCond(); |
|||
EXPECT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); |
|||
|
|||
// Success
|
|||
EXPECT_TRUE(TestCC(disputeTx, 0, disputeCond)); |
|||
|
|||
// Set result hash to 0 and check false
|
|||
uint256 nonsense; |
|||
disputeTx.vout[0].scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << nonsense); |
|||
EXPECT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); |
|||
EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); |
|||
EXPECT_EQ("wrong-payout", eval.state.GetRejectReason()); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testDisputeInvalidOutput) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(11); |
|||
|
|||
// Only one key needed to dispute
|
|||
CMutableTransaction disputeTx = ebet.DisputeTx(Dealer); |
|||
CC *disputeCond = ebet.DisputeCond(); |
|||
|
|||
// invalid payout hash
|
|||
std::vector<unsigned char> invalidHash = {0,1,2}; |
|||
disputeTx.vout[0].scriptPubKey = CScript() << OP_RETURN << invalidHash; |
|||
ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player1})); |
|||
EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); |
|||
EXPECT_EQ("invalid-payout-hash", eval.state.GetRejectReason()); |
|||
|
|||
// no vout at all
|
|||
disputeTx.vout.resize(0); |
|||
ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player1})); |
|||
EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); |
|||
EXPECT_EQ("no-vouts", eval.state.GetRejectReason()); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testDisputeEarly) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(11); |
|||
|
|||
// Only one key needed to dispute
|
|||
CMutableTransaction disputeTx = ebet.DisputeTx(Dealer); |
|||
CC *disputeCond = ebet.DisputeCond(); |
|||
EXPECT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player1})); |
|||
|
|||
EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); |
|||
EXPECT_EQ("dispute-too-soon", eval.state.GetRejectReason()); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testDisputeInvalidParams) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(12); |
|||
|
|||
CMutableTransaction disputeTx = ebet.DisputeTx(Player2); |
|||
CC *disputeCond = ebet.DisputeCond(); |
|||
CC *evalCond = disputeCond->subconditions[0]; |
|||
|
|||
// too long
|
|||
evalCond->code = (unsigned char*) realloc(evalCond->code, ++evalCond->codeLength); |
|||
ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); |
|||
EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); |
|||
EXPECT_EQ("malformed-params", eval.state.GetRejectReason()); |
|||
|
|||
// too short
|
|||
eval.state = CValidationState(); |
|||
evalCond->codeLength = 1; |
|||
ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); |
|||
EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); |
|||
EXPECT_EQ("malformed-params", eval.state.GetRejectReason()); |
|||
|
|||
// is fine
|
|||
eval.state = CValidationState(); |
|||
evalCond->codeLength = 12; |
|||
ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); |
|||
EXPECT_TRUE(TestCC(disputeTx, 0, disputeCond)); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testDisputeInvalidEvidence) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(12); |
|||
|
|||
CMutableTransaction disputeTx = ebet.DisputeTx(Player2); |
|||
CC *disputeCond = ebet.DisputeCond(); |
|||
CCSign(disputeTx, 0, disputeCond, {Player2}); |
|||
|
|||
CMutableTransaction mtx; |
|||
|
|||
mtx.vout.resize(1); |
|||
mtx.vout[0].scriptPubKey = CScript(); |
|||
eval.spends[ebet.SessionTx().GetHash()][1] = CTransaction(mtx); |
|||
ASSERT_TRUE(TestCC(disputeTx, 0, disputeCond)); |
|||
|
|||
mtx.vout[0].scriptPubKey << OP_RETURN; |
|||
eval.spends[ebet.SessionTx().GetHash()][1] = CTransaction(mtx); |
|||
ASSERT_TRUE(TestCC(disputeTx, 0, disputeCond)); |
|||
|
|||
mtx.vout[0].scriptPubKey = CScript() << 0; |
|||
eval.spends[ebet.SessionTx().GetHash()][1] = CTransaction(mtx); |
|||
ASSERT_TRUE(TestCC(disputeTx, 0, disputeCond)); |
|||
|
|||
eval.spends[ebet.SessionTx().GetHash()].resize(1); |
|||
eval.spends[ebet.SessionTx().GetHash()][0] = CTransaction(); |
|||
ASSERT_FALSE(TestCC(disputeTx, 0, disputeCond)); |
|||
EXPECT_EQ("no-evidence", eval.state.GetRejectReason()); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testMakeStakeTx) |
|||
{ |
|||
CTransaction stakeTx = ebet.StakeTx(); |
|||
EXPECT_EQ(0, stakeTx.vin.size()); |
|||
EXPECT_EQ(1, stakeTx.vout.size()); |
|||
EXPECT_EQ(ebet.totalPayout, stakeTx.vout[0].nValue); |
|||
EXPECT_EQ(CCPubKey(ebet.PayoutCond()), stakeTx.vout[0].scriptPubKey); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testMakePayoutCond) |
|||
{ |
|||
CC *payoutCond = ebet.PayoutCond(); |
|||
EXPECT_EQ("(1 of (3 of 5,5,5),(2 of (1 of 5,5,5),15))", CCShowStructure(payoutCond)); |
|||
EXPECT_EQ(0, memcmp(payoutCond->subconditions[1]->subconditions[1]->code+1, |
|||
ebet.SessionTx().GetHash().begin(), 32)); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testSignPayout) |
|||
{ |
|||
|
|||
CMutableTransaction payoutTx = ebet.AgreePayoutTx(); |
|||
CC *payoutCond = ebet.PayoutCond(); |
|||
|
|||
EXPECT_EQ(0, cc_isFulfilled(payoutCond->subconditions[0])); |
|||
EXPECT_EQ(0, cc_isFulfilled(payoutCond->subconditions[1])); |
|||
EXPECT_EQ(0, cc_isFulfilled(payoutCond)); |
|||
|
|||
EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Player1})); |
|||
EXPECT_EQ(0, cc_isFulfilled(payoutCond->subconditions[0])); |
|||
EXPECT_EQ(1, cc_isFulfilled(payoutCond->subconditions[1])); |
|||
EXPECT_EQ(1, cc_isFulfilled(payoutCond)); |
|||
|
|||
EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Player2})); |
|||
EXPECT_EQ(0, cc_isFulfilled(payoutCond->subconditions[0])); |
|||
|
|||
EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Dealer})); |
|||
EXPECT_EQ(1, cc_isFulfilled(payoutCond->subconditions[0])); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testAgreePayout) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(12); |
|||
|
|||
CMutableTransaction payoutTx = ebet.AgreePayoutTx(); |
|||
CC *payoutCond = ebet.PayoutCond(); |
|||
|
|||
EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Dealer})); |
|||
EXPECT_FALSE(TestCC(payoutTx, 0, payoutCond)); |
|||
EXPECT_EQ("(1 of (2 of (1 of 5,A5,A5),15),A2)", |
|||
CCShowStructure(CCPrune(payoutCond))); |
|||
|
|||
EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Player1})); |
|||
EXPECT_FALSE(TestCC(payoutTx, 0, payoutCond)); |
|||
EXPECT_EQ("(1 of (2 of (1 of 5,A5,A5),15),A2)", |
|||
CCShowStructure(CCPrune(payoutCond))); |
|||
|
|||
EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Player2})); |
|||
EXPECT_TRUE( TestCC(payoutTx, 0, payoutCond)); |
|||
EXPECT_EQ("(1 of (3 of 5,5,5),A2)", |
|||
CCShowStructure(CCPrune(payoutCond))); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testImportPayout) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(12); |
|||
|
|||
CMutableTransaction importTx = ebet.ImportPayoutTx(); |
|||
CC *payoutCond = ebet.PayoutCond(); |
|||
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); |
|||
EXPECT_TRUE(TestCC(importTx, 0, payoutCond)); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testImportPayoutFewVouts) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(12); |
|||
|
|||
CMutableTransaction importTx = ebet.ImportPayoutTx(); |
|||
importTx.vout.resize(0); |
|||
CC *payoutCond = ebet.PayoutCond(); |
|||
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); |
|||
EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); |
|||
EXPECT_EQ("no-vouts", eval.state.GetRejectReason()); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testImportPayoutInvalidPayload) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(12); |
|||
|
|||
CMutableTransaction importTx = ebet.ImportPayoutTx(); |
|||
importTx.vout[0].scriptPubKey.pop_back(); |
|||
CC *payoutCond = ebet.PayoutCond(); |
|||
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); |
|||
EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); |
|||
EXPECT_EQ("invalid-payload", eval.state.GetRejectReason()); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testImportPayoutWrongPayouts) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(12); |
|||
|
|||
CMutableTransaction importTx = ebet.ImportPayoutTx(); |
|||
importTx.vout[1].nValue = 7; |
|||
CC *payoutCond = ebet.PayoutCond(); |
|||
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); |
|||
ASSERT_FALSE(TestCC(importTx, 0, payoutCond)); |
|||
EXPECT_EQ("wrong-payouts", eval.state.GetRejectReason()); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testImportPayoutMangleSessionId) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(12); |
|||
|
|||
CMutableTransaction importTx = ebet.ImportPayoutTx(); |
|||
CC *payoutCond = ebet.PayoutCond(); |
|||
payoutCond->subconditions[1]->subconditions[1]->codeLength = 31; |
|||
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); |
|||
ASSERT_FALSE(TestCC(importTx, 0, payoutCond)); |
|||
EXPECT_EQ("malformed-params", eval.state.GetRejectReason()); |
|||
|
|||
payoutCond = ebet.PayoutCond(); |
|||
memset(payoutCond->subconditions[1]->subconditions[1]->code+1, 1, 32); |
|||
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); |
|||
ASSERT_FALSE(TestCC(importTx, 0, payoutCond)); |
|||
EXPECT_EQ("wrong-session", eval.state.GetRejectReason()); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testImportPayoutInvalidNotarizationHash) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(12); |
|||
|
|||
MoMProof proof = ebet.GetMoMProof(); |
|||
proof.notarizationHash = uint256(); |
|||
CMutableTransaction importTx = ebet.bet.MakeImportPayoutTx( |
|||
ebet.Payouts(Player2), ebet.DisputeTx(Player2), uint256(), proof); |
|||
|
|||
CC *payoutCond = ebet.PayoutCond(); |
|||
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); |
|||
EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); |
|||
EXPECT_EQ("coudnt-load-mom", eval.state.GetRejectReason()); |
|||
} |
|||
|
|||
|
|||
TEST_F(TestBet, testImportPayoutMomFail) |
|||
{ |
|||
EvalMock eval = ebet.SetEvalMock(12); |
|||
|
|||
MoMProof proof = ebet.GetMoMProof(); |
|||
proof.branch.nIndex ^= 1; |
|||
CMutableTransaction importTx = ebet.bet.MakeImportPayoutTx( |
|||
ebet.Payouts(Player2), ebet.DisputeTx(Player2), uint256(), proof); |
|||
|
|||
CC *payoutCond = ebet.PayoutCond(); |
|||
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); |
|||
EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); |
|||
EXPECT_EQ("mom-check-fail", eval.state.GetRejectReason()); |
|||
} |
|||
|
|||
|
|||
} /* namespace TestBet */ |
Loading…
Reference in new issue