various tweaks, combine payloads in ImportTx

This commit is contained in:
Scott Sadler
2018-04-06 13:37:56 -03:00
parent aa9eec4522
commit 56cf273faf
7 changed files with 67 additions and 73 deletions

View File

@@ -26,17 +26,21 @@ CC* BetProtocol::MakeDisputeCond()
} }
CMutableTransaction BetProtocol::MakeSessionTx() /*
* spendFee is the amount assigned to each output, for the purposes of posting
* dispute / evidence.
*/
CMutableTransaction BetProtocol::MakeSessionTx(CAmount spendFee)
{ {
CMutableTransaction mtx; CMutableTransaction mtx;
CC *disputeCond = MakeDisputeCond(); CC *disputeCond = MakeDisputeCond();
mtx.vout.push_back(CTxOut(MINFEE, CCPubKey(disputeCond))); mtx.vout.push_back(CTxOut(spendFee, CCPubKey(disputeCond)));
cc_free(disputeCond); cc_free(disputeCond);
for (int i=0; i<players.size(); i++) { for (int i=0; i<players.size(); i++) {
CC *cond = CCNewSecp256k1(players[i]); CC *cond = CCNewSecp256k1(players[i]);
mtx.vout.push_back(CTxOut(MINFEE, CCPubKey(cond))); mtx.vout.push_back(CTxOut(spendFee, CCPubKey(cond)));
cc_free(cond); cc_free(cond);
} }
return mtx; return mtx;
@@ -115,7 +119,18 @@ CMutableTransaction BetProtocol::MakeImportPayoutTx(std::vector<CTxOut> payouts,
CMutableTransaction mtx; CMutableTransaction mtx;
mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript()));
mtx.vout = payouts; mtx.vout = payouts;
mtx.vout.insert(mtx.vout.begin(), CTxOut(0, CScript() << OP_RETURN << CheckSerialize(momProof))); CScript proofData;
mtx.vout.insert(mtx.vout.begin()+1, CTxOut(0, CScript() << OP_RETURN << CheckSerialize(signedDisputeTx))); proofData << OP_RETURN << CheckSerialize(std::make_pair(momProof, signedDisputeTx));
mtx.vout.insert(mtx.vout.begin(), CTxOut(0, proofData));
return mtx; return mtx;
} }
bool GetOpReturnHash(CScript script, uint256 &hash)
{
std::vector<unsigned char> vHash;
GetOpReturnData(script, vHash);
if (vHash.size() != 32) return false;
hash = uint256(vHash);
return true;
}

View File

@@ -54,7 +54,6 @@ protected:
char* disputeFunc = (char*) "DisputeBet"; char* disputeFunc = (char*) "DisputeBet";
std::vector<CC*> playerConditions(); std::vector<CC*> playerConditions();
public: public:
CAmount MINFEE = 1;
std::vector<CPubKey> players; std::vector<CPubKey> players;
DisputeHeader disputeHeader; DisputeHeader disputeHeader;
@@ -64,7 +63,7 @@ public:
// on PANGEA // on PANGEA
CC* MakeDisputeCond(); CC* MakeDisputeCond();
CMutableTransaction MakeSessionTx(); CMutableTransaction MakeSessionTx(CAmount spendFee);
CMutableTransaction MakeDisputeTx(uint256 signedSessionTxHash, uint256 vmResultHash); CMutableTransaction MakeDisputeTx(uint256 signedSessionTxHash, uint256 vmResultHash);
CMutableTransaction MakePostEvidenceTx(uint256 signedSessionTxHash, CMutableTransaction MakePostEvidenceTx(uint256 signedSessionTxHash,
int playerIndex, std::vector<unsigned char> state); int playerIndex, std::vector<unsigned char> state);
@@ -78,4 +77,8 @@ public:
}; };
bool GetOpReturnHash(CScript script, uint256 &hash);
#endif /* BETPROTOCOL_H */ #endif /* BETPROTOCOL_H */

View File

@@ -9,19 +9,6 @@
#include "primitives/transaction.h" #include "primitives/transaction.h"
class DisputeHeader;
static bool GetOpReturnHash(CScript script, uint256 &hash)
{
std::vector<unsigned char> vHash;
GetOpReturnData(script, vHash);
if (vHash.size() != 32) return false;
memcpy(hash.begin(), vHash.data(), 32);
return true;
}
/* /*
* Crypto-Condition EVAL method that resolves a dispute of a session * Crypto-Condition EVAL method that resolves a dispute of a session
* *
@@ -85,7 +72,7 @@ bool Eval::DisputePayout(AppVM &vm, const CC *cond, const CTransaction &disputeT
maxLength = out.first; maxLength = out.first;
bestPayout = resultHash; bestPayout = resultHash;
} }
// The below means that if for any reason there is a draw, // The below means that if for any reason there is a draw, the first dispute wins
else if (out.first == maxLength) { else if (out.first == maxLength) {
if (bestPayout != payoutHash) { if (bestPayout != payoutHash) {
fprintf(stderr, "WARNING: VM has multiple solutions of same length\n"); fprintf(stderr, "WARNING: VM has multiple solutions of same length\n");

View File

@@ -134,6 +134,9 @@ bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t t
} }
extern char ASSETCHAINS_SYMBOL[16];
bool NotarisationData::Parse(const CScript scriptPK) bool NotarisationData::Parse(const CScript scriptPK)
{ {
*this = NotarisationData(); *this = NotarisationData();
@@ -146,12 +149,14 @@ bool NotarisationData::Parse(const CScript scriptPK)
try { try {
ss >> blockHash; ss >> blockHash;
ss >> height; ss >> height;
if (ASSETCHAINS_SYMBOL[0])
ss >> txHash;
char *nullPos = (char*) memchr(&ss[0], 0, ss.size()); char *nullPos = (char*) memchr(&ss[0], 0, ss.size());
if (!nullPos) return false; if (!nullPos) return false;
ss.read(symbol, nullPos-&ss[0]+1); ss.read(symbol, nullPos-&ss[0]+1);
if (ss.size() != 36) return false; if (ss.size() < 36) return false;
ss >> MoM; ss >> MoM;
ss >> MoMDepth; ss >> MoMDepth;
} catch (...) { } catch (...) {

View File

@@ -78,7 +78,7 @@ class NotarisationData {
public: public:
uint256 blockHash; uint256 blockHash;
uint32_t height; uint32_t height;
uint256 txHash; uint256 txHash; // Only get this guy in asset chains not in KMD
char symbol[64]; char symbol[64];
uint256 MoM; uint256 MoM;
uint32_t MoMDepth; uint32_t MoMDepth;
@@ -91,7 +91,7 @@ public:
* Serialisation boilerplate * Serialisation boilerplate
*/ */
template <class T> template <class T>
std::vector<unsigned char> CheckSerialize(T &in) std::vector<unsigned char> CheckSerialize(const T in)
{ {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << in; ss << in;
@@ -99,7 +99,7 @@ std::vector<unsigned char> CheckSerialize(T &in)
} }
template <class T> template <class T>
bool CheckDeserialize(std::vector<unsigned char> vIn, T &out) bool CheckDeserialize(const std::vector<unsigned char> vIn, T &out)
{ {
CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION); CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION);
try { try {

View File

@@ -13,15 +13,14 @@
* notarised on another chain. * notarised on another chain.
* *
* IN: cond - CC EVAL node * IN: cond - CC EVAL node
* IN: payoutTx - Payout transaction on value chain (KMD) * IN: importTx - Payout transaction on value chain (KMD)
* IN: nIn - index of input of stake * IN: nIn - index of input of stake
* *
* payoutTx: Spends stakeTx with payouts from asset chain * importTx: Spends stakeTx with payouts from asset chain
* *
* in 0: Spends Stake TX and contains ImportPayout CC * in 0: Spends Stake TX and contains ImportPayout CC
* out 0: OP_RETURN MomProof * out 0: OP_RETURN MomProof, disputeTx
* out 1: OP_RETURN serialized disputeTx from other chain * out 1-: arbitrary payouts
* out 2-: arbitrary payouts
* *
* disputeTx: Spends sessionTx.0 (opener on asset chain) * disputeTx: Spends sessionTx.0 (opener on asset chain)
* *
@@ -30,25 +29,27 @@
* out 0: OP_RETURN hash of payouts * out 0: OP_RETURN hash of payouts
* out 1-: anything * out 1-: anything
*/ */
bool Eval::ImportPayout(const CC *cond, const CTransaction &payoutTx, unsigned int nIn) bool Eval::ImportPayout(const CC *cond, const CTransaction &importTx, unsigned int nIn)
{ {
// TODO: Error messages! if (importTx.vout.size() == 0) return Invalid("no-vouts");
if (payoutTx.vout.size() < 2) return Invalid("need-2-vouts");
// load disputeTx from vout[1] // load data from vout[0]
MoMProof proof;
CTransaction disputeTx; CTransaction disputeTx;
std::vector<unsigned char> exportData; {
GetOpReturnData(payoutTx.vout[1].scriptPubKey, exportData); std::pair<MoMProof&, CTransaction&> pair(proof, disputeTx);
if (!CheckDeserialize(exportData, disputeTx)) std::vector<unsigned char> vopret;
return Invalid("invalid-dispute-tx"); GetOpReturnData(importTx.vout[0].scriptPubKey, vopret);
if (!CheckDeserialize(vopret, pair))
return Invalid("invalid-payload");
}
// Check disputeTx.0 shows correct payouts // Check disputeTx.0 shows correct payouts
{ {
std::vector<CTxOut> payouts(payoutTx.vout.begin() + 2, payoutTx.vout.end()); uint256 givenPayoutsHash;
uint256 payoutsHash = SerializeHash(payouts); GetOpReturnHash(disputeTx.vout[0].scriptPubKey, givenPayoutsHash);
std::vector<unsigned char> vPayoutsHash(payoutsHash.begin(), payoutsHash.end()); std::vector<CTxOut> payouts(importTx.vout.begin() + 1, importTx.vout.end());
if (givenPayoutsHash != SerializeHash(payouts))
if (disputeTx.vout[0].scriptPubKey != CScript() << OP_RETURN << vPayoutsHash)
return Invalid("wrong-payouts"); return Invalid("wrong-payouts");
} }
@@ -63,12 +64,6 @@ bool Eval::ImportPayout(const CC *cond, const CTransaction &payoutTx, unsigned i
// Check disputeTx solves momproof from vout[0] // Check disputeTx solves momproof from vout[0]
{ {
std::vector<unsigned char> vProof;
GetOpReturnData(payoutTx.vout[0].scriptPubKey, vProof);
MoMProof proof;
if (!CheckDeserialize(vProof, proof))
return Invalid("invalid-mom-proof-payload");
NotarisationData data; NotarisationData data;
if (!GetNotarisationData(proof.notarisationHash, data)) return Invalid("coudnt-load-mom"); if (!GetNotarisationData(proof.notarisationHash, data)) return Invalid("coudnt-load-mom");

View File

@@ -152,7 +152,7 @@ public:
CTransaction SessionTx() CTransaction SessionTx()
{ {
return CTransaction(bet.MakeSessionTx()); return CTransaction(bet.MakeSessionTx(1));
} }
CC* DisputeCond() CC* DisputeCond()
@@ -502,24 +502,24 @@ TEST_F(TestBet, testImportPayoutFewVouts)
EvalMock eval = ebet.SetEvalMock(12); EvalMock eval = ebet.SetEvalMock(12);
CMutableTransaction importTx = ebet.ImportPayoutTx(); CMutableTransaction importTx = ebet.ImportPayoutTx();
importTx.vout.resize(1); importTx.vout.resize(0);
CC *payoutCond = ebet.PayoutCond(); CC *payoutCond = ebet.PayoutCond();
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2}));
EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); EXPECT_FALSE(TestCC(importTx, 0, payoutCond));
EXPECT_EQ("need-2-vouts", eval.state.GetRejectReason()); EXPECT_EQ("no-vouts", eval.state.GetRejectReason());
} }
TEST_F(TestBet, testImportPayoutInvalidDisputeTx) TEST_F(TestBet, testImportPayoutInvalidPayload)
{ {
EvalMock eval = ebet.SetEvalMock(12); EvalMock eval = ebet.SetEvalMock(12);
CMutableTransaction importTx = ebet.ImportPayoutTx(); CMutableTransaction importTx = ebet.ImportPayoutTx();
importTx.vout[1].scriptPubKey.pop_back(); importTx.vout[0].scriptPubKey.pop_back();
CC *payoutCond = ebet.PayoutCond(); CC *payoutCond = ebet.PayoutCond();
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2}));
EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); EXPECT_FALSE(TestCC(importTx, 0, payoutCond));
EXPECT_EQ("invalid-dispute-tx", eval.state.GetRejectReason()); EXPECT_EQ("invalid-payload", eval.state.GetRejectReason());
} }
@@ -528,7 +528,7 @@ TEST_F(TestBet, testImportPayoutWrongPayouts)
EvalMock eval = ebet.SetEvalMock(12); EvalMock eval = ebet.SetEvalMock(12);
CMutableTransaction importTx = ebet.ImportPayoutTx(); CMutableTransaction importTx = ebet.ImportPayoutTx();
importTx.vout[2].nValue = 7; importTx.vout[1].nValue = 7;
CC *payoutCond = ebet.PayoutCond(); CC *payoutCond = ebet.PayoutCond();
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2}));
ASSERT_FALSE(TestCC(importTx, 0, payoutCond)); ASSERT_FALSE(TestCC(importTx, 0, payoutCond));
@@ -555,27 +555,15 @@ TEST_F(TestBet, testImportPayoutMangleSessionId)
} }
TEST_F(TestBet, testImportPayoutInvalidProofPayload)
{
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-mom-proof-payload", eval.state.GetRejectReason());
}
TEST_F(TestBet, testImportPayoutInvalidNotarisationHash) TEST_F(TestBet, testImportPayoutInvalidNotarisationHash)
{ {
EvalMock eval = ebet.SetEvalMock(12); EvalMock eval = ebet.SetEvalMock(12);
CMutableTransaction importTx = ebet.ImportPayoutTx();
MoMProof proof = ebet.GetMoMProof(); MoMProof proof = ebet.GetMoMProof();
proof.notarisationHash = uint256(); proof.notarisationHash = uint256();
importTx.vout[0].scriptPubKey = CScript() << OP_RETURN << CheckSerialize(proof); CMutableTransaction importTx = ebet.bet.MakeImportPayoutTx(
ebet.Payouts(Player2), ebet.DisputeTx(Player2), uint256(), proof);
CC *payoutCond = ebet.PayoutCond(); CC *payoutCond = ebet.PayoutCond();
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2}));
EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); EXPECT_FALSE(TestCC(importTx, 0, payoutCond));
@@ -587,10 +575,11 @@ TEST_F(TestBet, testImportPayoutMomFail)
{ {
EvalMock eval = ebet.SetEvalMock(12); EvalMock eval = ebet.SetEvalMock(12);
CMutableTransaction importTx = ebet.ImportPayoutTx();
MoMProof proof = ebet.GetMoMProof(); MoMProof proof = ebet.GetMoMProof();
proof.nIndex ^= 1; proof.nIndex ^= 1;
importTx.vout[0].scriptPubKey = CScript() << OP_RETURN << CheckSerialize(proof); CMutableTransaction importTx = ebet.bet.MakeImportPayoutTx(
ebet.Payouts(Player2), ebet.DisputeTx(Player2), uint256(), proof);
CC *payoutCond = ebet.PayoutCond(); CC *payoutCond = ebet.PayoutCond();
EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2}));
EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); EXPECT_FALSE(TestCC(importTx, 0, payoutCond));