Delete more CCs #381
This commit is contained in:
@@ -44,70 +44,11 @@ static unsigned char* CopyPubKey(CPubKey pkIn)
|
||||
}
|
||||
|
||||
|
||||
CC* CCNewThreshold(int t, std::vector<CC*> v)
|
||||
{
|
||||
CC *cond = cc_new(CC_Threshold);
|
||||
cond->threshold = t;
|
||||
cond->size = v.size();
|
||||
cond->subconditions = (CC**) calloc(v.size(), sizeof(CC*));
|
||||
memcpy(cond->subconditions, v.data(), v.size() * sizeof(CC*));
|
||||
return cond;
|
||||
}
|
||||
|
||||
|
||||
CC* CCNewSecp256k1(CPubKey k)
|
||||
{
|
||||
CC *cond = cc_new(CC_Secp256k1);
|
||||
cond->publicKey = CopyPubKey(k);
|
||||
return cond;
|
||||
}
|
||||
|
||||
|
||||
CC* CCNewEval(std::vector<unsigned char> code)
|
||||
{
|
||||
CC *cond = cc_new(CC_Eval);
|
||||
cond->code = (unsigned char*) malloc(code.size());
|
||||
memcpy(cond->code, code.data(), code.size());
|
||||
cond->codeLength = code.size();
|
||||
return cond;
|
||||
}
|
||||
|
||||
|
||||
CScript CCPubKey(const CC *cond)
|
||||
{
|
||||
return CScript();
|
||||
}
|
||||
|
||||
|
||||
CScript CCSig(const CC *cond)
|
||||
{
|
||||
return CScript();
|
||||
}
|
||||
|
||||
std::vector<unsigned char> CCSigVec(const CC *cond)
|
||||
{
|
||||
unsigned char buf[10000];
|
||||
size_t len = cc_fulfillmentBinary(cond, buf, 10000);
|
||||
auto ffill = std::vector<unsigned char>(buf, buf+len);
|
||||
ffill.push_back(1); // SIGHASH_ALL
|
||||
return ffill;
|
||||
}
|
||||
|
||||
std::string CCShowStructure(CC *cond)
|
||||
{
|
||||
std::string out;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
CC* CCPrune(CC *cond)
|
||||
{
|
||||
std::vector<unsigned char> ffillBin;
|
||||
GetPushData(CCSig(cond), ffillBin);
|
||||
return cc_readFulfillmentBinary(ffillBin.data(), ffillBin.size()-1);
|
||||
}
|
||||
|
||||
|
||||
bool GetPushData(const CScript &sig, std::vector<unsigned char> &data)
|
||||
{
|
||||
opcodetype opcode;
|
||||
|
||||
@@ -958,6 +958,7 @@ bool EvalScript(
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
case OP_CHECKCRYPTOCONDITION:
|
||||
case OP_CHECKCRYPTOCONDITIONVERIFY:
|
||||
{
|
||||
@@ -987,6 +988,7 @@ bool EvalScript(
|
||||
}
|
||||
}
|
||||
break;
|
||||
*/
|
||||
|
||||
INTERPRETER_DEFAULT:
|
||||
default:
|
||||
@@ -1361,43 +1363,7 @@ int TransactionSignatureChecker::CheckCryptoCondition(
|
||||
const CScript& scriptCode,
|
||||
uint32_t consensusBranchId) const
|
||||
{
|
||||
// Hash type is one byte tacked on to the end of the fulfillment
|
||||
if (ffillBin.empty())
|
||||
return false;
|
||||
|
||||
CC *cond;
|
||||
int error = cc_readFulfillmentBinaryExt((unsigned char*)ffillBin.data(), ffillBin.size()-1, &cond);
|
||||
if (error || !cond) return -1;
|
||||
|
||||
if (!IsSupportedCryptoCondition(cond)) return 0;
|
||||
if (!IsSignedCryptoCondition(cond)) return 0;
|
||||
|
||||
uint256 sighash;
|
||||
int nHashType = ffillBin.back();
|
||||
try {
|
||||
sighash = SignatureHash(CCPubKey(cond), *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata);
|
||||
} catch (logic_error ex) {
|
||||
return 0;
|
||||
}
|
||||
/*int32_t z; uint8_t *ptr;
|
||||
ptr = (uint8_t *)scriptCode.data();
|
||||
for (z=0; z<scriptCode.size(); z++)
|
||||
fprintf(stderr,"%02x",ptr[z]);
|
||||
fprintf(stderr," <- CScript\n");
|
||||
for (z=0; z<32; z++)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&sighash)[z]);
|
||||
fprintf(stderr," sighash nIn.%d nHashType.%d %.8f id.%d\n",(int32_t)nIn,(int32_t)nHashType,(double)amount/COIN,(int32_t)consensusBranchId);
|
||||
*/
|
||||
VerifyEval eval = [] (CC *cond, void *checker) {
|
||||
//fprintf(stderr,"checker.%p\n",(TransactionSignatureChecker*)checker);
|
||||
return ((TransactionSignatureChecker*)checker)->CheckEvalCondition(cond);
|
||||
};
|
||||
//fprintf(stderr,"non-checker path\n");
|
||||
int out = cc_verify(cond, (const unsigned char*)&sighash, 32, 0,
|
||||
condBin.data(), condBin.size(), eval, (void*)this);
|
||||
//fprintf(stderr,"out.%d from cc_verify\n",(int32_t)out);
|
||||
cc_free(cond);
|
||||
return out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -72,19 +72,8 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
|
||||
}
|
||||
//fprintf(stderr,"privkey (%s) for %s\n",NSPV_wifstr,EncodeDestination(key.GetPubKey().GetID()).c_str());
|
||||
|
||||
if (scriptCode.IsPayToCryptoCondition())
|
||||
if (0) // scriptCode.IsPayToCryptoCondition())
|
||||
{
|
||||
CC *cc = (CC *)extraData;
|
||||
// assume either 1of1 or 1of2. if the condition created by the
|
||||
if (!cc || cc_signTreeSecp256k1Msg32(cc, key.begin(), hash.begin()) == 0)
|
||||
{
|
||||
fprintf(stderr,"CC tree error\n");
|
||||
return false;
|
||||
}
|
||||
vchSig = CCSigVec(cc);
|
||||
if ( HUSH_NSPV_SUPERLITE )
|
||||
memset((uint8_t *)key.begin(),0,32);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -139,25 +128,6 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
|
||||
return nSigned==nRequired;
|
||||
}
|
||||
|
||||
CC *CCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2)
|
||||
{
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk1));
|
||||
pks.push_back(CCNewSecp256k1(pk2));
|
||||
CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
|
||||
CC *Sig = CCNewThreshold(1, pks);
|
||||
return CCNewThreshold(2, {condCC, Sig});
|
||||
}
|
||||
|
||||
CC *CCcond1(uint8_t evalcode,CPubKey pk)
|
||||
{
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk));
|
||||
CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
|
||||
CC *Sig = CCNewThreshold(1, pks);
|
||||
return CCNewThreshold(2, {condCC, Sig});
|
||||
}
|
||||
|
||||
std::vector<CCcontract_info> &GetCryptoConditions()
|
||||
{
|
||||
static bool initialized = false;
|
||||
@@ -173,36 +143,12 @@ std::vector<CCcontract_info> &GetCryptoConditions()
|
||||
|
||||
bool GetCCByUnspendableAddress(struct CCcontract_info *cp, char *addrstr)
|
||||
{
|
||||
std::vector<CCcontract_info> &vCC = GetCryptoConditions();
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < vCC.size(); i++)
|
||||
{
|
||||
if (strcmp(addrstr, vCC[i].unspendableCCaddr) == 0)
|
||||
{
|
||||
found = true;
|
||||
*cp = vCC[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCinitLite(struct CCcontract_info *cp, uint8_t evalcode)
|
||||
{
|
||||
std::vector<CCcontract_info> &vCC = GetCryptoConditions();
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < vCC.size(); i++)
|
||||
{
|
||||
if (vCC[i].evalcode == evalcode)
|
||||
{
|
||||
found = true;
|
||||
*cp = vCC[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _Getscriptaddress(char *destaddr, const CScript &scriptPubKey)
|
||||
@@ -222,118 +168,12 @@ bool _Getscriptaddress(char *destaddr, const CScript &scriptPubKey)
|
||||
|
||||
CScript _CCPubKey(const CC *cond)
|
||||
{
|
||||
unsigned char buf[1000];
|
||||
size_t len = cc_conditionBinary(cond, buf);
|
||||
return CScript() << std::vector<unsigned char>(buf, buf+len) << OP_CHECKCRYPTOCONDITION;
|
||||
return CScript();
|
||||
}
|
||||
|
||||
static bool SignStepCC(const BaseSignatureCreator& creator, const CScript& scriptPubKey, vector<valtype> &vSolutions,
|
||||
vector<valtype>& ret, uint32_t consensusBranchId)
|
||||
{
|
||||
CScript subScript;
|
||||
vector<CPubKey> vPK;
|
||||
vector<valtype> vParams = vector<valtype>();
|
||||
COptCCParams p;
|
||||
|
||||
// get information to sign with
|
||||
CCcontract_info C;
|
||||
|
||||
scriptPubKey.IsPayToCryptoCondition(&subScript, vParams);
|
||||
if (vParams.empty())
|
||||
{
|
||||
// get the keyID address of the cc and if it is an unspendable cc address, use its pubkey
|
||||
// we have nothing else
|
||||
char addr[64];
|
||||
if (_Getscriptaddress(addr, subScript) && GetCCByUnspendableAddress(&C, addr))
|
||||
{
|
||||
vPK.push_back(CPubKey(ParseHex(C.CChexstr)));
|
||||
p = COptCCParams(p.VERSION, C.evalcode, 1, 1, vPK, vParams);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p = COptCCParams(vParams[0]);
|
||||
}
|
||||
|
||||
if (p.IsValid() && p.vKeys.size() >= p.n)
|
||||
{
|
||||
bool is1of2 = (p.m == 1 && p.n == 2);
|
||||
CKey privKey;
|
||||
|
||||
// must be a valid cc eval code
|
||||
if (CCinitLite(&C, p.evalCode))
|
||||
{
|
||||
// pay to cc address is a valid tx
|
||||
if (!is1of2)
|
||||
{
|
||||
bool havePriv = creator.KeyStore().GetKey(p.vKeys[0].GetID(), privKey);
|
||||
|
||||
// if we don't have the private key, it must be the unspendable address
|
||||
if (!havePriv && (p.vKeys[0] == CPubKey(ParseHex(C.CChexstr))))
|
||||
{
|
||||
privKey = CKey();
|
||||
std::vector<unsigned char> vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv));
|
||||
privKey.Set(vch.begin(), vch.end(), false);
|
||||
}
|
||||
|
||||
CC *cc = CCcond1(p.evalCode, p.vKeys[0]);
|
||||
|
||||
if (cc)
|
||||
{
|
||||
vector<unsigned char> vch;
|
||||
if (creator.CreateSig(vch, p.vKeys[0].GetID(), _CCPubKey(cc), consensusBranchId, &privKey, (void *)cc))
|
||||
{
|
||||
ret.push_back(vch);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"vin has 1of1 CC signing error with address.(%s)\n", p.vKeys[0].GetID().ToString().c_str());
|
||||
}
|
||||
|
||||
cc_free(cc);
|
||||
return ret.size() != 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// first of priv key in our key store or contract address is what we sign with
|
||||
for (auto pk : p.vKeys)
|
||||
{
|
||||
if (creator.IsKeystoreValid() && creator.KeyStore().GetKey(pk.GetID(), privKey) && privKey.IsValid())
|
||||
break;
|
||||
|
||||
if (pk == CPubKey(ParseHex(C.CChexstr)))
|
||||
{
|
||||
privKey = CKey();
|
||||
std::vector<unsigned char> vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv));
|
||||
privKey.Set(vch.begin(), vch.end(), false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!privKey.IsValid())
|
||||
return false;
|
||||
|
||||
CC *cc = CCcond1of2(p.evalCode, p.vKeys[0], p.vKeys[1]);
|
||||
|
||||
if (cc)
|
||||
{
|
||||
vector<unsigned char> vch;
|
||||
if (creator.CreateSig(vch, p.vKeys[0].GetID(), _CCPubKey(cc), consensusBranchId, &privKey, (void *)cc))
|
||||
{
|
||||
ret.push_back(vch);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"vin has 1of2 CC signing error with addresses.(%s)\n(%s)\n", p.vKeys[0].GetID().ToString().c_str(), p.vKeys[1].GetID().ToString().c_str());
|
||||
}
|
||||
|
||||
cc_free(cc);
|
||||
return ret.size() != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user