]> Git Repo - VerusCoin.git/blame - src/cc/betprotocol.cpp
Handle partial but not enough rewards funding
[VerusCoin.git] / src / cc / betprotocol.cpp
CommitLineData
f345b953 1/******************************************************************************
2 * Copyright © 2014-2018 The SuperNET Developers. *
3 * *
4 * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
5 * the top-level directory of this distribution for the individual copyright *
6 * holder information and the developer policies on copyright and licensing. *
7 * *
8 * Unless otherwise agreed in a custom licensing agreement, no part of the *
9 * SuperNET software, including this file may be copied, modified, propagated *
10 * or distributed except according to the terms contained in the LICENSE file *
11 * *
12 * Removal or modification of this copyright notice is prohibited. *
13 * *
14 ******************************************************************************/
15
37592740
SS
16#include <cryptoconditions.h>
17
0cb91a8d
SS
18#include "hash.h"
19#include "main.h"
20#include "chain.h"
561f3e18 21#include "streams.h"
8a8e10f0 22#include "script/cc.h"
561f3e18 23#include "cc/betprotocol.h"
20c3ac51
SS
24#include "cc/eval.h"
25#include "cc/utils.h"
37592740
SS
26#include "primitives/transaction.h"
27
28
561f3e18 29std::vector<CC*> BetProtocol::PlayerConditions()
37592740 30{
561f3e18
SS
31 std::vector<CC*> subs;
32 for (int i=0; i<players.size(); i++)
33 subs.push_back(CCNewSecp256k1(players[i]));
34 return subs;
37592740
SS
35}
36
37
561f3e18 38CC* BetProtocol::MakeDisputeCond()
37592740 39{
39c9911e
SS
40 CC *disputePoker = CCNewEval(E_MARSHAL(
41 ss << disputeCode << VARINT(waitBlocks) << vmParams;
42 ));
561f3e18
SS
43
44 CC *anySig = CCNewThreshold(1, PlayerConditions());
45
46 return CCNewThreshold(2, {disputePoker, anySig});
37592740
SS
47}
48
49
56cf273f
SS
50/*
51 * spendFee is the amount assigned to each output, for the purposes of posting
52 * dispute / evidence.
53 */
54CMutableTransaction BetProtocol::MakeSessionTx(CAmount spendFee)
37592740
SS
55{
56 CMutableTransaction mtx;
37592740 57
561f3e18 58 CC *disputeCond = MakeDisputeCond();
56cf273f 59 mtx.vout.push_back(CTxOut(spendFee, CCPubKey(disputeCond)));
37592740
SS
60 cc_free(disputeCond);
61
62 for (int i=0; i<players.size(); i++) {
561f3e18 63 CC *cond = CCNewSecp256k1(players[i]);
56cf273f 64 mtx.vout.push_back(CTxOut(spendFee, CCPubKey(cond)));
37592740
SS
65 cc_free(cond);
66 }
67 return mtx;
68}
69
70
561f3e18 71CMutableTransaction BetProtocol::MakeDisputeTx(uint256 signedSessionTxHash, uint256 vmResultHash)
37592740
SS
72{
73 CMutableTransaction mtx;
74
75 CC *disputeCond = MakeDisputeCond();
561f3e18 76 mtx.vin.push_back(CTxIn(signedSessionTxHash, 0, CScript()));
37592740
SS
77
78 std::vector<unsigned char> result(vmResultHash.begin(), vmResultHash.begin()+32);
79 mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << result));
80 return mtx;
81}
82
83
561f3e18 84CMutableTransaction BetProtocol::MakePostEvidenceTx(uint256 signedSessionTxHash,
37592740
SS
85 int playerIdx, std::vector<unsigned char> state)
86{
87 CMutableTransaction mtx;
88
561f3e18 89 mtx.vin.push_back(CTxIn(signedSessionTxHash, playerIdx+1, CScript()));
37592740
SS
90 mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << state));
91
92 return mtx;
93}
94
37592740 95
561f3e18 96CC* BetProtocol::MakePayoutCond(uint256 signedSessionTxHash)
37592740 97{
561f3e18
SS
98 // TODO: 2/3 majority
99 CC* agree = CCNewThreshold(players.size(), PlayerConditions());
37592740
SS
100
101 CC *import;
102 {
39c9911e
SS
103 CC *importEval = CCNewEval(E_MARSHAL(
104 ss << EVAL_IMPORTPAYOUT << signedSessionTxHash;
105 ));
37592740 106
561f3e18 107 CC *oneof = CCNewThreshold(1, PlayerConditions());
37592740
SS
108
109 import = CCNewThreshold(2, {oneof, importEval});
110 }
111
112 return CCNewThreshold(1, {agree, import});
113}
114
115
561f3e18 116CMutableTransaction BetProtocol::MakeStakeTx(CAmount totalPayout, uint256 signedSessionTxHash)
37592740
SS
117{
118 CMutableTransaction mtx;
37592740 119
561f3e18 120 CC *payoutCond = MakePayoutCond(signedSessionTxHash);
37592740
SS
121 mtx.vout.push_back(CTxOut(totalPayout, CCPubKey(payoutCond)));
122 cc_free(payoutCond);
123
124 return mtx;
125}
126
127
561f3e18
SS
128CMutableTransaction BetProtocol::MakeAgreePayoutTx(std::vector<CTxOut> payouts,
129 uint256 signedStakeTxHash)
37592740
SS
130{
131 CMutableTransaction mtx;
561f3e18
SS
132 mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript()));
133 mtx.vout = payouts;
37592740
SS
134 return mtx;
135}
136
137
561f3e18
SS
138CMutableTransaction BetProtocol::MakeImportPayoutTx(std::vector<CTxOut> payouts,
139 CTransaction signedDisputeTx, uint256 signedStakeTxHash, MoMProof momProof)
37592740 140{
37592740 141 CMutableTransaction mtx;
561f3e18 142 mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript()));
37592740 143 mtx.vout = payouts;
56cf273f 144 CScript proofData;
39c9911e 145 proofData << OP_RETURN << E_MARSHAL(ss << momProof << signedDisputeTx);
56cf273f 146 mtx.vout.insert(mtx.vout.begin(), CTxOut(0, proofData));
561f3e18 147 return mtx;
37592740 148}
56cf273f
SS
149
150
151bool GetOpReturnHash(CScript script, uint256 &hash)
152{
153 std::vector<unsigned char> vHash;
154 GetOpReturnData(script, vHash);
155 if (vHash.size() != 32) return false;
156 hash = uint256(vHash);
157 return true;
158}
0cb91a8d
SS
159
160
161/*
162 * Crypto-Condition EVAL method that verifies a payout against a transaction
163 * notarised on another chain.
164 *
165 * IN: params - condition params
166 * IN: importTx - Payout transaction on value chain (KMD)
167 * IN: nIn - index of input of stake
168 *
169 * importTx: Spends stakeTx with payouts from asset chain
170 *
171 * in 0: Spends Stake TX and contains ImportPayout CC
172 * out 0: OP_RETURN MomProof, disputeTx
173 * out 1-: arbitrary payouts
174 *
175 * disputeTx: Spends sessionTx.0 (opener on asset chain)
176 *
177 * in 0: spends sessionTx.0
178 * in 1-: anything
179 * out 0: OP_RETURN hash of payouts
180 * out 1-: anything
181 */
182bool Eval::ImportPayout(const std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn)
183{
184 if (importTx.vout.size() == 0) return Invalid("no-vouts");
185
186 // load data from vout[0]
187 MoMProof proof;
188 CTransaction disputeTx;
189 {
190 std::vector<unsigned char> vopret;
191 GetOpReturnData(importTx.vout[0].scriptPubKey, vopret);
192 if (!E_UNMARSHAL(vopret, ss >> proof; ss >> disputeTx))
193 return Invalid("invalid-payload");
194 }
195
196 // Check disputeTx.0 shows correct payouts
197 {
198 uint256 givenPayoutsHash;
199 GetOpReturnHash(disputeTx.vout[0].scriptPubKey, givenPayoutsHash);
200 std::vector<CTxOut> payouts(importTx.vout.begin() + 1, importTx.vout.end());
201 if (givenPayoutsHash != SerializeHash(payouts))
202 return Invalid("wrong-payouts");
203 }
204
205 // Check disputeTx spends sessionTx.0
206 // condition ImportPayout params is session ID from other chain
207 {
208 uint256 sessionHash;
209 if (!E_UNMARSHAL(params, ss >> sessionHash))
210 return Invalid("malformed-params");
211 if (disputeTx.vin[0].prevout != COutPoint(sessionHash, 0))
212 return Invalid("wrong-session");
213 }
214
215 // Check disputeTx solves momproof from vout[0]
216 {
06c960d2 217 NotarisationData data(0);
0cb91a8d
SS
218 if (!GetNotarisationData(proof.notarisationHash, data))
219 return Invalid("coudnt-load-mom");
220
221 if (data.MoM != proof.branch.Exec(disputeTx.GetHash()))
222 return Invalid("mom-check-fail");
223 }
224
225 return Valid();
226}
227
228
229/*
230 * Crypto-Condition EVAL method that resolves a dispute of a session
231 *
232 * IN: vm - AppVM virtual machine to verify states
233 * IN: params - condition params
234 * IN: disputeTx - transaction attempting to resolve dispute
235 * IN: nIn - index of input of dispute tx
236 *
237 * disputeTx: attempt to resolve a dispute
238 *
239 * in 0: Spends Session TX first output, reveals DisputeHeader
240 * out 0: OP_RETURN hash of payouts
241 */
242bool Eval::DisputePayout(AppVM &vm, std::vector<uint8_t> params, const CTransaction &disputeTx, unsigned int nIn)
243{
244 if (disputeTx.vout.size() == 0) return Invalid("no-vouts");
245
246 // get payouts hash
247 uint256 payoutHash;
248 if (!GetOpReturnHash(disputeTx.vout[0].scriptPubKey, payoutHash))
249 return Invalid("invalid-payout-hash");
250
251 // load params
252 uint16_t waitBlocks;
253 std::vector<uint8_t> vmParams;
254 if (!E_UNMARSHAL(params, ss >> VARINT(waitBlocks); ss >> vmParams))
255 return Invalid("malformed-params");
256
257 // ensure that enough time has passed
258 {
259 CTransaction sessionTx;
260 CBlockIndex sessionBlock;
261
262 // if unconformed its too soon
263 if (!GetTxConfirmed(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlock))
264 return Error("couldnt-get-parent");
265
266 if (GetCurrentHeight() < sessionBlock.nHeight + waitBlocks)
267 return Invalid("dispute-too-soon"); // Not yet
268 }
269
270 // get spends
271 std::vector<CTransaction> spends;
272 if (!GetSpendsConfirmed(disputeTx.vin[0].prevout.hash, spends))
273 return Error("couldnt-get-spends");
274
275 // verify result from VM
276 int maxLength = -1;
277 uint256 bestPayout;
278 for (int i=1; i<spends.size(); i++)
279 {
280 std::vector<unsigned char> vmState;
281 if (spends[i].vout.size() == 0) continue;
282 if (!GetOpReturnData(spends[i].vout[0].scriptPubKey, vmState)) continue;
283 auto out = vm.evaluate(vmParams, vmState);
284 uint256 resultHash = SerializeHash(out.second);
285 if (out.first > maxLength) {
286 maxLength = out.first;
287 bestPayout = resultHash;
288 }
289 // The below means that if for any reason there is a draw, the first dispute wins
290 else if (out.first == maxLength) {
291 if (bestPayout != payoutHash) {
292 fprintf(stderr, "WARNING: VM has multiple solutions of same length\n");
293 bestPayout = resultHash;
294 }
295 }
296 }
297
298 if (maxLength == -1) return Invalid("no-evidence");
299
300 return bestPayout == payoutHash ? Valid() : Invalid("wrong-payout");
301}
This page took 0.163111 seconds and 4 git commands to generate.