]> Git Repo - VerusCoin.git/blame - src/cc/StakeGuard.cpp
Merge branch 'dev' of github.com:miketout/VerusCoin into dev
[VerusCoin.git] / src / cc / StakeGuard.cpp
CommitLineData
8a727a26 1/********************************************************************
2 * (C) 2018 Michael Toutonghi
3 *
4 * Distributed under the MIT software license, see the accompanying
5 * file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 *
7 * This crypto-condition eval solves the problem of nothing-at-stake
8 * in a proof of stake consensus system.
9 *
10 */
11
ca4a5f26 12#include "StakeGuard.h"
06f41160 13#include "script/script.h"
8a727a26 14#include "main.h"
905fe35e 15#include "hash.h"
b2a98c42 16#include "key_io.h"
905fe35e 17
a4f9bc97 18#include <vector>
19#include <map>
20
905fe35e 21#include "streams.h"
8a727a26 22
23extern int32_t VERUS_MIN_STAKEAGE;
24
3bfa5e22 25bool IsData(opcodetype opcode)
26{
27 return (opcode >= 0 && opcode <= OP_PUSHDATA4) || (opcode >= OP_1 && opcode <= OP_16);
28}
29
06f41160 30bool UnpackStakeOpRet(const CTransaction &stakeTx, std::vector<std::vector<unsigned char>> &vData)
8a727a26 31{
32 bool isValid = stakeTx.vout[stakeTx.vout.size() - 1].scriptPubKey.GetOpretData(vData);
33
3bfa5e22 34 if (isValid && vData.size() == 1)
8a727a26 35 {
06f41160 36 CScript data = CScript(vData[0].begin(), vData[0].end());
37 vData.clear();
38
39 uint32_t bytesTotal;
40 CScript::const_iterator pc = data.begin();
41 std::vector<unsigned char> vch = std::vector<unsigned char>();
42 opcodetype op;
43 bool moreData = true;
44
45 for (bytesTotal = vch.size();
3bfa5e22 46 bytesTotal <= nMaxDatacarrierBytes && !(isValid = (pc == data.end())) && (moreData = data.GetOp(pc, op, vch)) && IsData(op);
06f41160 47 bytesTotal += vch.size())
48 {
3bfa5e22 49 if (op >= OP_1 && op <= OP_16)
50 {
51 vch.resize(1);
52 vch[0] = (op - OP_1) + 1;
53 }
06f41160 54 vData.push_back(vch);
55 }
56
57 // if we ran out of data, we're ok
06f41160 58 if (isValid && (vData.size() >= CStakeParams::STAKE_MINPARAMS) && (vData.size() <= CStakeParams::STAKE_MAXPARAMS))
59 {
60 return true;
61 }
8a727a26 62 }
63 return false;
64}
65
3bfa5e22 66CStakeParams::CStakeParams(const std::vector<std::vector<unsigned char>> &vData)
8a727a26 67{
56fe75cb 68 // An original format stake OP_RETURN contains:
8a727a26 69 // 1. source block height in little endian 32 bit
70 // 2. target block height in little endian 32 bit
71 // 3. 32 byte prev block hash
3bfa5e22 72 // 4. 33 byte pubkey, or not present to use same as stake destination
56fe75cb 73 // New format serialization and deserialization is handled by normal stream serialization.
74 version = VERSION_INVALID;
8a727a26 75 srcHeight = 0;
76 blkHeight = 0;
77 if (vData[0].size() == 1 &&
56fe75cb 78 vData[0][0] == OPRETTYPE_STAKEPARAMS2 &&
79 vData.size() == 2)
80 {
81 ::FromVector(vData[1], *this);
82 }
83 else if (vData[0].size() == 1 &&
8a727a26 84 vData[0][0] == OPRETTYPE_STAKEPARAMS && vData[1].size() <= 4 &&
85 vData[2].size() <= 4 &&
86 vData[3].size() == sizeof(prevHash) &&
06f41160 87 (vData.size() == STAKE_MINPARAMS || (vData.size() == STAKE_MAXPARAMS && vData[4].size() == 33)))
8a727a26 88 {
56fe75cb 89 version = VERSION_ORIGINAL;
3bfa5e22 90 for (int i = 0, size = vData[1].size(); i < size; i++)
8a727a26 91 {
3bfa5e22 92 srcHeight = srcHeight | vData[1][i] << (8 * i);
8a727a26 93 }
3bfa5e22 94 for (int i = 0, size = vData[2].size(); i < size; i++)
8a727a26 95 {
3bfa5e22 96 blkHeight = blkHeight | vData[2][i] << (8 * i);
8a727a26 97 }
98
99 prevHash = uint256(vData[3]);
100
101 if (vData.size() == 4)
102 {
06f41160 103 pk = CPubKey();
8a727a26 104 }
105 else if (vData[4].size() == 33)
106 {
06f41160 107 pk = CPubKey(vData[4]);
108 if (!pk.IsValid())
8a727a26 109 {
110 // invalidate
111 srcHeight = 0;
56fe75cb 112 version = VERSION_INVALID;
8a727a26 113 }
114 }
115 else
116 {
117 // invalidate
118 srcHeight = 0;
56fe75cb 119 version = VERSION_INVALID;
8a727a26 120 }
121 }
122}
123
905fe35e 124bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams)
125{
126 std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
127
3bfa5e22 128 //printf("opret stake script: %s\nvalue at scriptPubKey[0]: %x\n", stakeTx.vout[1].scriptPubKey.ToString().c_str(), stakeTx.vout[1].scriptPubKey[0]);
129
905fe35e 130 if (stakeTx.vin.size() == 1 &&
131 stakeTx.vout.size() == 2 &&
132 stakeTx.vout[0].nValue > 0 &&
133 stakeTx.vout[1].scriptPubKey.IsOpReturn() &&
134 UnpackStakeOpRet(stakeTx, vData))
135 {
136 stakeParams = CStakeParams(vData);
3bfa5e22 137 return stakeParams.IsValid();
905fe35e 138 }
139 return false;
140}
141
f3b0d2ab 142// this validates the format of the stake transaction and, optionally, whether or not it is
143// properly signed to spend the source stake.
144// it does not validate the relationship to a coinbase guard, PoS eligibility or the actual stake spend.
56fe75cb 145// the only time it matters is to validate a properly formed stake transaction for either pre-check before PoS validity check,
146// or to validate the stake transaction on a fork that will be used to spend a winning stake that cheated by being posted
8a727a26 147// on two fork chains
f3b0d2ab 148bool ValidateStakeTransaction(const CTransaction &stakeTx, CStakeParams &stakeParams, bool validateSig)
8a727a26 149{
150 std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
151
152 // a valid stake transaction has one input and two outputs, one output is the monetary value and one is an op_ret with CStakeParams
153 // stake output #1 must be P2PK or P2PKH, unless a delegate for the coinbase is specified
f3ec769e 154 if (GetStakeParams(stakeTx, stakeParams))
8a727a26 155 {
f3ec769e 156 // if we have gotten this far and are still valid, we need to validate everything else
157 // even if the utxo is spent, this can succeed, as it only checks that is was ever valid
158 CTransaction srcTx = CTransaction();
159 uint256 blkHash = uint256();
160 txnouttype txType;
161 CBlockIndex *pindex;
162 if (myGetTransaction(stakeTx.vin[0].prevout.hash, srcTx, blkHash))
8a727a26 163 {
d565e7b7 164 BlockMap::const_iterator it = mapBlockIndex.find(blkHash);
56fe75cb 165 if (it != mapBlockIndex.end() && (pindex = it->second) != NULL && chainActive.Contains(pindex))
8a727a26 166 {
f3ec769e 167 std::vector<std::vector<unsigned char>> vAddr = std::vector<std::vector<unsigned char>>();
5c7c7edc 168 bool extendedStake = CConstVerusSolutionVector::GetVersionByHeight(stakeParams.blkHeight) >= CActivationHeight::ACTIVATE_EXTENDEDSTAKE;
169 COptCCParams p;
8a727a26 170
f3ec769e 171 if (stakeParams.srcHeight == pindex->GetHeight() &&
172 (stakeParams.blkHeight - stakeParams.srcHeight >= VERUS_MIN_STAKEAGE) &&
5c7c7edc 173 ((srcTx.vout[stakeTx.vin[0].prevout.n].scriptPubKey.IsPayToCryptoCondition(p) &&
174 extendedStake &&
175 p.IsValid() &&
176 srcTx.vout[stakeTx.vin[0].prevout.n].scriptPubKey.IsSpendableOutputType(p)) ||
177 (!p.IsValid() && Solver(srcTx.vout[stakeTx.vin[0].prevout.n].scriptPubKey, txType, vAddr))))
f3ec769e 178 {
5c7c7edc 179 if (!p.IsValid() && txType == TX_PUBKEY && !stakeParams.pk.IsValid())
8a727a26 180 {
f3ec769e 181 stakeParams.pk = CPubKey(vAddr[0]);
182 }
56fe75cb 183 // once extended stake hits, we only accept extended form of staking
184 if (!(extendedStake && stakeParams.Version() < stakeParams.VERSION_EXTENDED_STAKE) &&
185 !(!extendedStake && stakeParams.Version() >= stakeParams.VERSION_EXTENDED_STAKE) &&
5c7c7edc 186 ((extendedStake && p.IsValid()) || (txType == TX_PUBKEY) || (txType == TX_PUBKEYHASH && (extendedStake || stakeParams.pk.IsFullyValid()))))
f3ec769e 187 {
188 auto consensusBranchId = CurrentEpochBranchId(stakeParams.blkHeight, Params().GetConsensus());
f3b0d2ab 189
a4f9bc97 190 std::map<uint160, pair<int, std::vector<std::vector<unsigned char>>>> idAddressMap;
191 if (validateSig)
192 {
193 idAddressMap = ServerTransactionSignatureChecker::ExtractIDMap(srcTx.vout[stakeTx.vin[0].prevout.n].scriptPubKey, stakeParams.blkHeight);
194 }
195
f3b0d2ab 196 if (!validateSig || VerifyScript(stakeTx.vin[0].scriptSig,
197 srcTx.vout[stakeTx.vin[0].prevout.n].scriptPubKey,
477fd227 198 MANDATORY_SCRIPT_VERIFY_FLAGS,
a4f9bc97 199 TransactionSignatureChecker(&stakeTx, (uint32_t)0, srcTx.vout[stakeTx.vin[0].prevout.n].nValue, &idAddressMap),
f3b0d2ab 200 consensusBranchId))
8a727a26 201 {
f3ec769e 202 return true;
8a727a26 203 }
204 }
205 }
206 }
8a727a26 207 }
208 }
f3ec769e 209 return false;
8a727a26 210}
211
c52bd43c 212bool MakeGuardedOutput(CAmount value, CTxDestination &dest, CTransaction &stakeTx, CTxOut &vout)
8a727a26 213{
56fe75cb 214 CStakeParams p;
215 if (GetStakeParams(stakeTx, p) && p.IsValid())
216 {
217 CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
8a727a26 218
56fe75cb 219 hw << stakeTx.vin[0].prevout.hash;
220 hw << stakeTx.vin[0].prevout.n;
8a727a26 221
56fe75cb 222 uint256 utxo = hw.GetHash();
8a727a26 223
56fe75cb 224 if (p.Version() >= p.VERSION_EXTENDED_STAKE)
225 {
226 CCcontract_info *cp, C;
227 cp = CCinit(&C,EVAL_STAKEGUARD);
228
229 CStakeInfo stakeInfo(p.blkHeight, p.srcHeight, utxo, p.prevHash);
fc1ca997 230
231 std::vector<CTxDestination> dests1({dest});
232 CConditionObj<CStakeInfo> primary(EVAL_STAKEGUARD, dests1, 1, &stakeInfo);
233 std::vector<CTxDestination> dests2({CTxDestination(CPubKey(ParseHex(cp->CChexstr)))});
234 CConditionObj<CStakeInfo> cheatCatcher(EVAL_STAKEGUARD, dests2, 1);
235
236 std::vector<CTxDestination> indexDests;
237
238 vout = CTxOut(value, MakeMofNCCScript(1, primary, cheatCatcher));
56fe75cb 239 }
c52bd43c 240 else if (dest.which() == COptCCParams::ADDRTYPE_PK)
56fe75cb 241 {
242 CCcontract_info *cp, C;
243 cp = CCinit(&C,EVAL_STAKEGUARD);
905fe35e 244
56fe75cb 245 CPubKey ccAddress = CPubKey(ParseHex(cp->CChexstr));
905fe35e 246
56fe75cb 247 // return an output that is bound to the stake transaction and can be spent by presenting either a signed condition by the original
248 // destination address or a properly signed stake transaction of the same utxo on a fork
c52bd43c 249 vout = MakeCC1of2vout(EVAL_STAKEGUARD, value, boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), dest), ccAddress);
905fe35e 250
56fe75cb 251 std::vector<CTxDestination> vKeys;
252 vKeys.push_back(dest);
253 vKeys.push_back(ccAddress);
254
255 std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
905fe35e 256
56fe75cb 257 vData.push_back(std::vector<unsigned char>(utxo.begin(), utxo.end()));
258
259 // prev block hash and height is here to make validation easy
260 vData.push_back(std::vector<unsigned char>(p.prevHash.begin(), p.prevHash.end()));
261 std::vector<unsigned char> height = std::vector<unsigned char>(4);
262 for (int i = 0; i < 4; i++)
263 {
264 height[i] = (p.blkHeight >> (8 * i)) & 0xff;
265 }
266 vData.push_back(height);
905fe35e 267
56fe75cb 268 COptCCParams ccp = COptCCParams(COptCCParams::VERSION_V1, EVAL_STAKEGUARD, 1, 2, vKeys, vData);
905fe35e 269
56fe75cb 270 vout.scriptPubKey << ccp.AsVector() << OP_DROP;
271 }
272
905fe35e 273 return true;
274 }
275 return false;
276}
277
278// validates if a stake transaction is both valid and cheating, defined by:
23f0b6ec 279// the same exact utxo source, a target block height of later than that of the provided coinbase tx that is also targeting a fork
280// of the chain. the source transaction must be a coinbase
f3b0d2ab 281bool ValidateMatchingStake(const CTransaction &ccTx, uint32_t voutNum, const CTransaction &stakeTx, bool &cheating)
905fe35e 282{
f3b0d2ab 283 // an invalid or non-matching stake transaction cannot cheat
284 cheating = false;
285
79b0432d 286 //printf("ValidateMatchingStake: ccTx.vin[0].prevout.hash: %s, ccTx.vin[0].prevout.n: %d\n", ccTx.vin[0].prevout.hash.GetHex().c_str(), ccTx.vin[0].prevout.n);
287
905fe35e 288 if (ccTx.IsCoinBase())
289 {
290 CStakeParams p;
f3b0d2ab 291 if (ValidateStakeTransaction(stakeTx, p))
905fe35e 292 {
293 std::vector<std::vector<unsigned char>> vParams = std::vector<std::vector<unsigned char>>();
294 CScript dummy;
295
296 if (ccTx.vout[voutNum].scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) && vParams.size() > 0)
297 {
298 COptCCParams ccp = COptCCParams(vParams[0]);
56fe75cb 299 CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
300
301 if (p.version >= p.VERSION_EXTENDED_STAKE && ccp.version >= ccp.VERSION_V3 && ccp.vData.size())
905fe35e 302 {
56fe75cb 303 CStakeInfo stakeInfo(ccp.vData[0]);
304 hw << stakeTx.vin[0].prevout.hash;
305 hw << stakeTx.vin[0].prevout.n;
306 uint256 utxo = hw.GetHash();
905fe35e 307
56fe75cb 308 if (utxo == stakeInfo.utxo)
309 {
310 if (p.prevHash != stakeInfo.prevHash && p.blkHeight >= stakeInfo.height)
311 {
312 cheating = true;
313 return true;
314 }
315 // if block height is equal and we are at the else, prevHash must have been equal
316 else if (p.blkHeight >= stakeInfo.height)
317 {
318 return true;
319 }
320 }
321 }
6a23bf78 322 else if (p.version < p.VERSION_EXTENDED_STAKE &&
323 ccp.version < ccp.VERSION_V3 &&
324 ccp.IsValid() &&
325 ccp.vData.size() >= 3 &&
56fe75cb 326 ccp.vData[2].size() <= 4)
327 {
f3b0d2ab 328 hw << stakeTx.vin[0].prevout.hash;
329 hw << stakeTx.vin[0].prevout.n;
905fe35e 330 uint256 utxo = hw.GetHash();
905fe35e 331
332 uint32_t height = 0;
185b2d4f 333 int i, dataLen = ccp.vData[2].size();
334 for (i = dataLen - 1; i >= 0; i--)
905fe35e 335 {
185b2d4f 336 height = (height << 8) + ccp.vData[2][i];
905fe35e 337 }
95c5c69b 338 // for debugging strange issue
339 // printf("iterator: %d, height: %d, datalen: %d\n", i, height, dataLen);
8a727a26 340
f3b0d2ab 341 if (utxo == uint256(ccp.vData[0]))
905fe35e 342 {
f3b0d2ab 343 if (p.prevHash != uint256(ccp.vData[1]) && p.blkHeight >= height)
344 {
345 cheating = true;
346 return true;
347 }
348 // if block height is equal and we are at the else, prevHash must have been equal
349 else if (p.blkHeight == height)
350 {
351 return true;
352 }
905fe35e 353 }
354 }
355 }
356 }
357 }
8a727a26 358 return false;
359}
360
905fe35e 361// this attaches an opret to a mutable transaction that provides the necessary evidence of a signed, cheating stake transaction
362bool MakeCheatEvidence(CMutableTransaction &mtx, const CTransaction &ccTx, uint32_t voutNum, const CTransaction &cheatTx)
8a727a26 363{
905fe35e 364 std::vector<unsigned char> vch;
b2a98c42 365 CDataStream s = CDataStream(SER_DISK, PROTOCOL_VERSION);
df756d24 366 bool isCheater = false;
8a727a26 367
f3b0d2ab 368 if (ValidateMatchingStake(ccTx, voutNum, cheatTx, isCheater) && isCheater)
905fe35e 369 {
370 CTxOut vOut = CTxOut();
26bf01e9 371 int64_t opretype_stakecheat = OPRETTYPE_STAKECHEAT;
905fe35e 372
373 CScript vData = CScript();
374 cheatTx.Serialize(s);
375 vch = std::vector<unsigned char>(s.begin(), s.end());
26bf01e9 376 vData << opretype_stakecheat << vch;
377 vch = std::vector<unsigned char>(vData.begin(), vData.end());
378 vOut.scriptPubKey << OP_RETURN << vch;
379
51848bbc 380 // printf("Script encoding inner:\n%s\nouter:\n%s\n", vData.ToString().c_str(), vOut.scriptPubKey.ToString().c_str());
26bf01e9 381
905fe35e 382 vOut.nValue = 0;
383 mtx.vout.push_back(vOut);
384 }
df756d24 385 return isCheater;
8a727a26 386}
387
fc1ca997 388// a version 3 guard output should be a 1 of 2 meta condition, with both of the
389// conditions being stakeguard only and one of the conditions being sent to the public
390// stakeguard destination. Only for smart transaction V3 and beyond.
391bool PrecheckStakeGuardOutput(const CTransaction &tx, int32_t outNum, CValidationState &state, uint32_t height)
392{
393 if (CConstVerusSolutionVector::GetVersionByHeight(height) < CActivationHeight::ACTIVATE_EXTENDEDSTAKE)
394 {
395 return true;
396 }
397
398 // ensure that we have all required spend conditions for primary, revocation, and recovery
399 // if there are additional spend conditions, their addition or removal is checked for validity
400 // depending on which of the mandatory spend conditions is authorized.
401 COptCCParams p, master, secondary;
402
403 CCcontract_info *cp, C;
404 cp = CCinit(&C,EVAL_STAKEGUARD);
405 CPubKey defaultPubKey(ParseHex(cp->CChexstr));
406
407 if (tx.vout[outNum].scriptPubKey.IsPayToCryptoCondition(p) &&
408 p.IsValid() &&
409 p.version >= p.VERSION_V3 &&
410 p.evalCode == EVAL_STAKEGUARD &&
411 p.vData.size() == 3 &&
412 (master = COptCCParams(p.vData.back())).IsValid() &&
413 master.evalCode == 0 &&
414 master.m == 1 &&
0bd17d21 415 (secondary = COptCCParams(p.vData[1])).IsValid() &&
fc1ca997 416 secondary.evalCode == EVAL_STAKEGUARD &&
417 secondary.m == 1 &&
418 secondary.n == 1 &&
419 secondary.vKeys.size() == 1 &&
420 secondary.vKeys[0].which() == COptCCParams::ADDRTYPE_PK &&
421 GetDestinationBytes(secondary.vKeys[0]) == GetDestinationBytes(defaultPubKey))
422 {
423 return true;
424 }
425 return false;
426}
427
191f3bbd 428typedef struct ccFulfillmentCheck {
281a5e2e 429 std::vector<CPubKey> &vPK;
430 std::vector<uint32_t> &vCount;
191f3bbd 431} ccFulfillmentCheck;
432
191f3bbd 433// to figure out which node is signed
434int CCFulfillmentVisitor(CC *cc, struct CCVisitor visitor)
435{
281a5e2e 436 //printf("cc_typeName: %s, cc_isFulfilled: %x, cc_isAnon: %x, cc_typeMask: %x, cc_condToJSONString:\n%s\n",
437 // cc_typeName(cc), cc_isFulfilled(cc), cc_isAnon(cc), cc_typeMask(cc), cc_conditionToJSONString(cc));
438
439 if (strcmp(cc_typeName(cc), "secp256k1-sha-256") == 0)
440 {
441 cJSON *json = cc_conditionToJSON(cc);
442 if (json)
443 {
444 cJSON *pubKeyNode = json->child->next;
445 if (strcmp(pubKeyNode->string, "publicKey") == 0)
446 {
447 ccFulfillmentCheck *pfc = (ccFulfillmentCheck *)(visitor.context);
448
f2450b36 449 //printf("public key: %s\n", pubKeyNode->valuestring);
281a5e2e 450 CPubKey pubKey = CPubKey(ParseHex(pubKeyNode->valuestring));
451
452 for (int i = 0; i < pfc->vPK.size(); i++)
453 {
454 if (i < pfc->vCount.size() && (pfc->vPK[i] == pubKey))
455 {
456 pfc->vCount[i]++;
457 }
458 }
459 }
460 cJSON_free(json);
461 }
462 }
281a5e2e 463 return 1;
191f3bbd 464}
465
466int IsCCFulfilled(CC *cc, ccFulfillmentCheck *ctx)
467{
191f3bbd 468 struct CCVisitor visitor = {&CCFulfillmentVisitor, NULL, 0, (void *)ctx};
469 cc_visit(cc, visitor);
281a5e2e 470
f2450b36 471 //printf("count key 1: %d, count key 2: %d\n", ctx->vCount[0], ctx->vCount[1]);
281a5e2e 472 return ctx->vCount[0];
191f3bbd 473}
474
4ecaf167 475bool StakeGuardValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn, bool fulfilled)
8a727a26 476{
ca4a5f26 477 // WARNING: this has not been tested combined with time locks
8a727a26 478 // validate this spend of a transaction with it being past any applicable time lock and one of the following statements being true:
479 // 1. the spend is signed by the original output destination's private key and normal payment requirements, spends as normal
ca4a5f26 480 // 2. the spend is signed by the private key of the StakeGuard contract and pushes a signed stake transaction
f3b0d2ab 481 // with the same exact utxo source, a target block height of later than or equal to this tx, and a different prevBlock hash
8a727a26 482
483 // first, check to see if the spending contract is signed by the default destination address
484 // if so, success and we are done
485
486 // get preConditions and parameters
487 std::vector<std::vector<unsigned char>> preConditions = std::vector<std::vector<unsigned char>>();
488 std::vector<std::vector<unsigned char>> params = std::vector<std::vector<unsigned char>>();
905fe35e 489 CTransaction txOut;
8a727a26 490
191f3bbd 491 bool signedByFirstKey = false;
f3b0d2ab 492 bool validCheat = false;
f3ec769e 493
191f3bbd 494 CC *cc = GetCryptoCondition(tx.vin[nIn].scriptSig);
495
23f0b6ec 496 // tx is the spending tx, the cc transaction comes back in txOut
497 bool validCCParams = GetCCParams(eval, tx, nIn, txOut, preConditions, params);
498 COptCCParams ccp;
499 if (preConditions.size() > 0)
500 {
501 ccp = COptCCParams(preConditions[0]);
502 }
503
504 if (validCCParams && ccp.IsValid() && ((cc && ccp.version < COptCCParams::VERSION_V3) || (!cc && ccp.version >= COptCCParams::VERSION_V3)))
8a727a26 505 {
281a5e2e 506 signedByFirstKey = false;
191f3bbd 507 validCheat = false;
f3b0d2ab 508
fc1ca997 509 if (ccp.version >= COptCCParams::VERSION_V3)
510 {
48afe4a2 511 CPubKey defaultPubKey(ParseHex(cp->CChexstr));
512
513 CSmartTransactionSignatures smartSigs;
514 bool signedByDefaultKey = false;
515 std::vector<unsigned char> ffVec = GetFulfillmentVector(tx.vin[nIn].scriptSig);
516 smartSigs = CSmartTransactionSignatures(std::vector<unsigned char>(ffVec.begin(), ffVec.end()));
517 CKeyID checkKeyID = defaultPubKey.GetID();
518 for (auto &keySig : smartSigs.signatures)
519 {
520 CPubKey thisKey;
521 thisKey.Set(keySig.second.pubKeyData.begin(), keySig.second.pubKeyData.end());
522 if (thisKey.GetID() == checkKeyID)
523 {
524 signedByDefaultKey = true;
525 break;
526 }
527 }
528
529 // if we don't have enough signatures to satisfy conditions,
530 // it will fail before we check this. that means if it is not signed
531 // by the default key, it must be signed / fulfilled by the alternate, which is
532 // the first condition/key/identity
533 signedByFirstKey = fulfilled || !signedByDefaultKey;
534
fc1ca997 535 if (!signedByFirstKey &&
536 params.size() == 2 &&
537 params[0].size() > 0 &&
538 params[0][0] == OPRETTYPE_STAKECHEAT)
539 {
540 CDataStream s = CDataStream(std::vector<unsigned char>(params[1].begin(), params[1].end()), SER_DISK, PROTOCOL_VERSION);
541 bool checkOK = false;
542 CTransaction cheatTx;
543 try
544 {
545 cheatTx.Unserialize(s);
546 checkOK = true;
547 }
548 catch (...)
549 {
550 }
551 if (checkOK && !ValidateMatchingStake(txOut, tx.vin[0].prevout.n, cheatTx, validCheat))
552 {
553 validCheat = false;
554 }
555 }
556 }
557 else if (ccp.m == 1 && ccp.n == 2 && ccp.vKeys.size() == 2)
905fe35e 558 {
23f0b6ec 559 std::vector<uint32_t> vc = {0, 0};
560 std::vector<CPubKey> keys;
f3b0d2ab 561
23f0b6ec 562 for (auto pk : ccp.vKeys)
f3b0d2ab 563 {
23f0b6ec 564 uint160 keyID = GetDestinationID(pk);
565 std::vector<unsigned char> vkch = GetDestinationBytes(pk);
566 if (vkch.size() == 33)
f3b0d2ab 567 {
23f0b6ec 568 keys.push_back(CPubKey(vkch));
b2a98c42 569 }
23f0b6ec 570 }
b2a98c42 571
23f0b6ec 572 if (keys.size() == 2)
573 {
48afe4a2 574 ccFulfillmentCheck fc = {keys, vc};
575 signedByFirstKey = (IsCCFulfilled(cc, &fc) != 0);
23f0b6ec 576
6a23bf78 577 if (!signedByFirstKey &&
578 ccp.evalCode == EVAL_STAKEGUARD &&
579 ccp.vKeys.size() == 2 &&
580 params.size() == 2 &&
581 params[0].size() > 0 &&
582 params[0][0] == OPRETTYPE_STAKECHEAT)
23f0b6ec 583 {
584 CDataStream s = CDataStream(std::vector<unsigned char>(params[1].begin(), params[1].end()), SER_DISK, PROTOCOL_VERSION);
585 bool checkOK = false;
586 CTransaction cheatTx;
587 try
588 {
589 cheatTx.Unserialize(s);
590 checkOK = true;
591 }
592 catch (...)
593 {
594 }
595 if (checkOK && !ValidateMatchingStake(txOut, tx.vin[0].prevout.n, cheatTx, validCheat))
596 {
597 validCheat = false;
598 }
599 }
f3b0d2ab 600 }
905fe35e 601 }
23f0b6ec 602 }
603 if (cc)
604 {
8a727a26 605 cc_free(cc);
606 }
281a5e2e 607 if (!(signedByFirstKey || validCheat))
608 {
696d2d67 609 return eval->Error("error reading coinbase or spending proof invalid\n");
281a5e2e 610 }
611 else return true;
8a727a26 612}
613
ec8a120b 614bool IsStakeGuardInput(const CScript &scriptSig)
615{
68b309c0
MT
616 uint32_t ecode;
617 return scriptSig.IsPayToCryptoCondition(&ecode) && ecode == EVAL_STAKEGUARD;
ec8a120b 618}
619
ca4a5f26 620UniValue StakeGuardInfo()
8a727a26 621{
622 UniValue result(UniValue::VOBJ); char numstr[64];
623 CMutableTransaction mtx;
624 CPubKey pk;
625
626 CCcontract_info *cp,C;
627
ca4a5f26 628 cp = CCinit(&C,EVAL_STAKEGUARD);
8a727a26 629
630 result.push_back(Pair("result","success"));
ca4a5f26 631 result.push_back(Pair("name","StakeGuard"));
8a727a26 632
633 // all UTXOs to the contract address that are to any of the wallet addresses are to us
634 // each is spendable as a normal transaction, but the spend may fail if it gets spent out
635 // from under us
636 pk = GetUnspendable(cp,0);
637 return(result);
638}
639
This page took 0.202347 seconds and 4 git commands to generate.