diff --git a/src/cc/betprotocol.cpp b/src/cc/betprotocol.cpp index 12637ebbd..b4e5a4e56 100644 --- a/src/cc/betprotocol.cpp +++ b/src/cc/betprotocol.cpp @@ -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; CC *disputeCond = MakeDisputeCond(); - mtx.vout.push_back(CTxOut(MINFEE, CCPubKey(disputeCond))); + mtx.vout.push_back(CTxOut(spendFee, CCPubKey(disputeCond))); cc_free(disputeCond); for (int i=0; i payouts, CMutableTransaction mtx; mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); mtx.vout = payouts; - mtx.vout.insert(mtx.vout.begin(), CTxOut(0, CScript() << OP_RETURN << CheckSerialize(momProof))); - mtx.vout.insert(mtx.vout.begin()+1, CTxOut(0, CScript() << OP_RETURN << CheckSerialize(signedDisputeTx))); + CScript proofData; + proofData << OP_RETURN << CheckSerialize(std::make_pair(momProof, signedDisputeTx)); + mtx.vout.insert(mtx.vout.begin(), CTxOut(0, proofData)); return mtx; } + + +bool GetOpReturnHash(CScript script, uint256 &hash) +{ + std::vector vHash; + GetOpReturnData(script, vHash); + if (vHash.size() != 32) return false; + hash = uint256(vHash); + return true; +} diff --git a/src/cc/betprotocol.h b/src/cc/betprotocol.h index 67a1979c3..ae4346c09 100644 --- a/src/cc/betprotocol.h +++ b/src/cc/betprotocol.h @@ -54,7 +54,6 @@ protected: char* disputeFunc = (char*) "DisputeBet"; std::vector playerConditions(); public: - CAmount MINFEE = 1; std::vector players; DisputeHeader disputeHeader; @@ -64,7 +63,7 @@ public: // on PANGEA CC* MakeDisputeCond(); - CMutableTransaction MakeSessionTx(); + CMutableTransaction MakeSessionTx(CAmount spendFee); CMutableTransaction MakeDisputeTx(uint256 signedSessionTxHash, uint256 vmResultHash); CMutableTransaction MakePostEvidenceTx(uint256 signedSessionTxHash, int playerIndex, std::vector state); @@ -78,4 +77,8 @@ public: }; + +bool GetOpReturnHash(CScript script, uint256 &hash); + + #endif /* BETPROTOCOL_H */ diff --git a/src/cc/disputepayout.cpp b/src/cc/disputepayout.cpp index ea34ed23c..9bd765c62 100644 --- a/src/cc/disputepayout.cpp +++ b/src/cc/disputepayout.cpp @@ -9,19 +9,6 @@ #include "primitives/transaction.h" -class DisputeHeader; - - -static bool GetOpReturnHash(CScript script, uint256 &hash) -{ - std::vector 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 * @@ -85,7 +72,7 @@ bool Eval::DisputePayout(AppVM &vm, const CC *cond, const CTransaction &disputeT maxLength = out.first; 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) { if (bestPayout != payoutHash) { fprintf(stderr, "WARNING: VM has multiple solutions of same length\n"); diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index 352a64c4b..eeb84311b 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -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) { *this = NotarisationData(); @@ -146,12 +149,14 @@ bool NotarisationData::Parse(const CScript scriptPK) try { ss >> blockHash; ss >> height; + if (ASSETCHAINS_SYMBOL[0]) + ss >> txHash; char *nullPos = (char*) memchr(&ss[0], 0, ss.size()); if (!nullPos) return false; ss.read(symbol, nullPos-&ss[0]+1); - if (ss.size() != 36) return false; + if (ss.size() < 36) return false; ss >> MoM; ss >> MoMDepth; } catch (...) { diff --git a/src/cc/eval.h b/src/cc/eval.h index 55d45153c..3eb4350b1 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -78,7 +78,7 @@ class NotarisationData { public: uint256 blockHash; uint32_t height; - uint256 txHash; + uint256 txHash; // Only get this guy in asset chains not in KMD char symbol[64]; uint256 MoM; uint32_t MoMDepth; @@ -91,7 +91,7 @@ public: * Serialisation boilerplate */ template -std::vector CheckSerialize(T &in) +std::vector CheckSerialize(const T in) { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << in; @@ -99,7 +99,7 @@ std::vector CheckSerialize(T &in) } template -bool CheckDeserialize(std::vector vIn, T &out) +bool CheckDeserialize(const std::vector vIn, T &out) { CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION); try { diff --git a/src/cc/importpayout.cpp b/src/cc/importpayout.cpp index 3be0cdaf7..858e71f31 100644 --- a/src/cc/importpayout.cpp +++ b/src/cc/importpayout.cpp @@ -13,15 +13,14 @@ * notarised on another chain. * * 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 * - * 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 - * out 0: OP_RETURN MomProof - * out 1: OP_RETURN serialized disputeTx from other chain - * out 2-: arbitrary payouts + * out 0: OP_RETURN MomProof, disputeTx + * out 1-: arbitrary payouts * * disputeTx: Spends sessionTx.0 (opener on asset chain) * @@ -30,25 +29,27 @@ * out 0: OP_RETURN hash of payouts * 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 (payoutTx.vout.size() < 2) return Invalid("need-2-vouts"); + if (importTx.vout.size() == 0) return Invalid("no-vouts"); - // load disputeTx from vout[1] + // load data from vout[0] + MoMProof proof; CTransaction disputeTx; - std::vector exportData; - GetOpReturnData(payoutTx.vout[1].scriptPubKey, exportData); - if (!CheckDeserialize(exportData, disputeTx)) - return Invalid("invalid-dispute-tx"); + { + std::pair pair(proof, disputeTx); + std::vector vopret; + GetOpReturnData(importTx.vout[0].scriptPubKey, vopret); + if (!CheckDeserialize(vopret, pair)) + return Invalid("invalid-payload"); + } // Check disputeTx.0 shows correct payouts { - std::vector payouts(payoutTx.vout.begin() + 2, payoutTx.vout.end()); - uint256 payoutsHash = SerializeHash(payouts); - std::vector vPayoutsHash(payoutsHash.begin(), payoutsHash.end()); - - if (disputeTx.vout[0].scriptPubKey != CScript() << OP_RETURN << vPayoutsHash) + uint256 givenPayoutsHash; + GetOpReturnHash(disputeTx.vout[0].scriptPubKey, givenPayoutsHash); + std::vector payouts(importTx.vout.begin() + 1, importTx.vout.end()); + if (givenPayoutsHash != SerializeHash(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] { - std::vector vProof; - GetOpReturnData(payoutTx.vout[0].scriptPubKey, vProof); - MoMProof proof; - if (!CheckDeserialize(vProof, proof)) - return Invalid("invalid-mom-proof-payload"); - NotarisationData data; if (!GetNotarisationData(proof.notarisationHash, data)) return Invalid("coudnt-load-mom"); diff --git a/src/test-komodo/test_eval_bet.cpp b/src/test-komodo/test_eval_bet.cpp index 25fea5d84..5da437646 100644 --- a/src/test-komodo/test_eval_bet.cpp +++ b/src/test-komodo/test_eval_bet.cpp @@ -152,7 +152,7 @@ public: CTransaction SessionTx() { - return CTransaction(bet.MakeSessionTx()); + return CTransaction(bet.MakeSessionTx(1)); } CC* DisputeCond() @@ -502,24 +502,24 @@ TEST_F(TestBet, testImportPayoutFewVouts) EvalMock eval = ebet.SetEvalMock(12); CMutableTransaction importTx = ebet.ImportPayoutTx(); - importTx.vout.resize(1); + importTx.vout.resize(0); CC *payoutCond = ebet.PayoutCond(); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); 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); CMutableTransaction importTx = ebet.ImportPayoutTx(); - importTx.vout[1].scriptPubKey.pop_back(); + 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-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); CMutableTransaction importTx = ebet.ImportPayoutTx(); - importTx.vout[2].nValue = 7; + importTx.vout[1].nValue = 7; CC *payoutCond = ebet.PayoutCond(); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); 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) { EvalMock eval = ebet.SetEvalMock(12); - CMutableTransaction importTx = ebet.ImportPayoutTx(); MoMProof proof = ebet.GetMoMProof(); 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(); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); @@ -587,10 +575,11 @@ TEST_F(TestBet, testImportPayoutMomFail) { EvalMock eval = ebet.SetEvalMock(12); - CMutableTransaction importTx = ebet.ImportPayoutTx(); MoMProof proof = ebet.GetMoMProof(); 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(); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); EXPECT_FALSE(TestCC(importTx, 0, payoutCond));