#include #include "primitives/transaction.h" class DisputeHeader { public: int waitBlocks; std::vector vmParams; ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(VARINT(waitBlocks)); READWRITE(vmParams); } }; static CScript CCPubKey(const CC *cond) { unsigned char buf[1000]; size_t len = cc_conditionBinary(cond, buf); return CScript() << std::vector(buf, buf+len) << OP_CHECKCRYPTOCONDITION; } static CScript CCSig(const CC *cond) { unsigned char buf[1000]; size_t len = cc_fulfillmentBinary(cond, buf, 1000); auto ffill = std::vector(buf, buf+len); ffill.push_back(SIGHASH_ALL); return CScript() << ffill; } static unsigned char* CopyPubKey(CPubKey pkIn) { auto *pk = malloc(33); memcpy(pk, pkIn.begin(), 33); // TODO: compressed? return pk; } class PokerProtocol { public: CAmount MINFEE = 1; std::vector players; DisputeHeader disputeHeader; // on PANGEA CC* MakeDisputeCond(); CMutableTransaction MakeSessionTx(CTxIn dealerInput); CMutableTransaction MakeDisputeTx(uint256 signedSessionTxHash); CMutableTransaction MakePostEvidenceTx(uint256 signedSessionTxHash, CPubKey playerKey, std::vector state); // on KMD CC* MakePayoutCond(); CMutableTransaction MakeStakeTx(CAmount totalPayout, std::vector playerInputs, uint256 signedSessionTx); CMutableTransaction MakeAgreePayoutTx(std::vector payouts, CC *signedPayoutCond, uint256 signedStakeTxHash); CMutableTransaction MakeImportPayoutTx(std::vector payouts, CC *signedPayoutCond, CTransaction signedDisputeTx); } CC* PokerProtocol::MakeDisputeCond() { CC *disputePoker = cond->subconditions[0] = cc_new(CC_Eval); char err[1000]; std::vector headerData; disputeHeader >> CDataStream(headerData, SER_DISK, PROTOCOL_VERSION); disputePoker->paramsBin = malloc(headerData.size()); memcpy(disputePoker->paramsBin, headerData.data()); disputePoker.paramsBinLength = headerData.size(); CC *spendSig = cond->subconditions[1] = cc_new(CC_Threshold); spendSig->threshold = 1; spendSig->size = players.size() + 1; spendSig->subconditions = malloc(spendSig->size, sizeof(CC*)); for (int i=0; isubconditions[i] = cc_new(CC_Secp256k1); sub->publicKey = CopyPubKey(players[i]); } CC *cond = cc_new(CC_Threshold); cond->threshold = 2; cond->size = 2; cond->subconditions = calloc(2, sizeof(CC*)); cond->subconditions[0] = disputePoker; cond->subconditions[1] = spendSig; return cond; } CMutableTransaction PokerProtocol::MakeSessionTx(CTxIn dealerInput) { CMutableTransaction mtx; mtx.vin.push_back(dealerInput); CC *disputeCond = MakeDisputeCond(players, disputeHeader); mtx.vout.push_back(CTxOut(MINFEE, CCPubKey(disputeCond))); cc_free(disputeCond); for (int i=0; ipublicKey = CopyPubKey(players[i]); mtx.vout.push_back(CTxOut(MINFEE, CCPubKey(cond))); cc_free(cond); } return mtx; } CMutableTransaction PokerProtocol::MakeDisputeTx(uint256 signedSessionTxHash, CC *signedDisputeCond, uint256 vmResultHash) { CMutableTransaction mtx; CC *disputeCond = MakeDisputeCond(); mtx.vin.push_back(CTxIn(signedSessionTxHash, 0, CCSig(signedDisputeCond))); std::vector result(vmResultHash.begin(), vmResultHash.begin()+32); mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << result)); return mtx; } CMutableTransaction PokerProtocol::MakePostEvidenceTx(uint256 signedSessionTxHash, int playerIdx, std::vector state) { CMutableTransaction mtx; CC *cond = cc_new(CC_Secp256k1); cond->publicKey = CopyPubKey(players[i]); mtx.vin.push_back(CTxIn(signedSessionTxHash, playerIdx+1, CCSig(cond))); mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << state)); return mtx; } CC* CCNewThreshold(int t, std::vector v) { CC *cond = cc_new(CC_Threshold); cond->threshold = t; cond->size = v.size(); cond->subconditions = calloc(1, sizeof(CC*)); memcpy(cond->subconditions, v.data(), v.size() * sizeof(CC*)); return cond; } CCNewSecp256k1(CPubKey &k) { cond = cc_new(CC_Secp256k1); cond->publicKey = CopyPubKey(players[i]); return cond; } CCNewEval(char *method, unsigned char* paramsBin, size_t len) { CC *cond = cc_new(CC_Eval); strcpy(cond->method, method); cond->paramsBin = malloc(32); memcpy(cond->paramsBin, bin, len); cond->paramsBinLength = len; return cond; } CC* MakePayoutCond(uint256 signedSessionTx) { CC* agree; { // TODO: 2/3 majority std::vector subs; for (int i=0; i subs; for (int i=0; i playerInputs, uint256 signedSessionTx) { CMutableTransaction mtx; mtx.vin = playerInputs; CC *payoutCond = MakePayoutCond(signedSessionTx);push mtx.vout.push_back(CTxOut(totalPayout, CCPubKey(payoutCond))); cc_free(payoutCond); return mtx; } CMutableTransaction PokerProtocol::MakeAgreePayoutTx(std::vector payouts, CC *signedPayoutCond, uint256 signedStakeTxHash) { CMutableTransaction mtx; mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CCSig(signedPayoutCond))); mtx.vouts = payouts; return mtx; } CMutableTransaction PokerProtocol::MakeImportPayoutTx(std::vector payouts, CC *signedPayoutCond, CTransaction signedDisputeTx, uint256 signedStakeTxHash) { std::vector vDisputeTx; signedDisputeTx >> CDataStream(vDisputeTx, SER_DISK, PROTOCOL_VERSION); CMutableTransaction mtx; mtx.vin.push_back(CTxInput(signedStakeTxHash, 0, CCSig(signedPayoutCond))); mtx.vout = payouts; CMutableTransaction.vout.insert(0, CTxOutput(0, CScript() << OP_RETURN << "PROOF HERE")); CMutableTransaction.vout.insert(1, CTxOutput(0, CScript() << OP_RETURN << vDisputeTx)); }