]> Git Repo - VerusCoin.git/blame - src/cc/CCutils.cpp
Improve support for ID address differentiation and begin referral validation
[VerusCoin.git] / src / cc / CCutils.cpp
CommitLineData
44a9fd7c 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
16#include "CCinclude.h"
17
18/*
19 CCutils has low level functions that are universally useful for all contracts.
20 */
21
810f6366 22void endiancpy(uint8_t *dest,uint8_t *src,int32_t len)
23{
24 int32_t i,j=0;
25#if defined(WORDS_BIGENDIAN)
26 for (i=31; i>=0; i--)
27 dest[j++] = src[i];
28#else
29 memcpy(dest,src,len);
30#endif
31}
db3b8abe 32
d7a84c74 33CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2)
34{
35 std::vector<CC*> pks;
36 pks.push_back(CCNewSecp256k1(pk1));
d5d98d1f 37 pks.push_back(CCNewSecp256k1(pk2));
d7a84c74 38 CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
39 CC *Sig = CCNewThreshold(1, pks);
40 return CCNewThreshold(2, {condCC, Sig});
41}
42
3a27113e 43CC *MakeCCcond1(uint8_t evalcode, CPubKey pk)
26e796c0 44{
45 std::vector<CC*> pks;
46 pks.push_back(CCNewSecp256k1(pk));
47 CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
48 CC *Sig = CCNewThreshold(1, pks);
49 return CCNewThreshold(2, {condCC, Sig});
50}
51
770924f5 52CC *MakeCCcond1(uint8_t evalcode, CTxDestination dest)
41f170fd 53{
770924f5 54 CPubKey pk = boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), dest);
41f170fd 55 std::vector<CC*> pks;
770924f5 56 if (pk.IsValid())
57 {
58 pks.push_back(CCNewSecp256k1(pk));
59 }
60 else
61 {
62 pks.push_back(CCNewHashedSecp256k1(CKeyID(GetDestinationID(dest))));
63 }
41f170fd 64 CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
3a27113e 65 CC *Sig = CCNewThreshold(1, pks);
353949fe 66 return CCNewThreshold(2, {condCC, Sig});
41f170fd
MT
67}
68
b35cb19a 69CC *MakeCCcondAny(uint8_t evalcode, std::vector<CTxDestination> dests)
70{
71 std::vector<CC*> pks;
72 for (auto dest : dests)
73 {
74 CPubKey pk = boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), dest);
75 if (pk.IsValid())
76 {
77 pks.push_back(CCNewSecp256k1(pk));
78 }
79 else
80 {
81 pks.push_back(CCNewHashedSecp256k1(CKeyID(GetDestinationID(dest))));
82 }
83 }
84
85 CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
86 CC *Sig = CCNewThreshold(1, pks);
87 return CCNewThreshold(2, {condCC, Sig});
88}
89
b7c685b8 90CTxOut MakeCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk)
2492726d 91{
92 CTxOut vout;
93 CC *payoutCond = MakeCCcond1(evalcode,pk);
94 vout = CTxOut(nValue,CCPubKey(payoutCond));
95 cc_free(payoutCond);
96 return(vout);
97}
98
7fe1ffc7 99CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2)
810f6366 100{
101 CTxOut vout;
7fe1ffc7 102 CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2);
810f6366 103 vout = CTxOut(nValue,CCPubKey(payoutCond));
104 cc_free(payoutCond);
105 return(vout);
106}
107
44a9fd7c 108CC* GetCryptoCondition(CScript const& scriptSig)
109{
110 auto pc = scriptSig.begin();
111 opcodetype opcode;
112 std::vector<unsigned char> ffbin;
113 if (scriptSig.GetOp(pc, opcode, ffbin))
114 return cc_readFulfillmentBinary((uint8_t*)ffbin.data(), ffbin.size()-1);
115}
116
117bool IsCCInput(CScript const& scriptSig)
118{
119 CC *cond;
120 if ( (cond= GetCryptoCondition(scriptSig)) == 0 )
121 return false;
122 cc_free(cond);
123 return true;
124}
125
cfea7a46 126int32_t unstringbits(char *buf,uint64_t bits)
127{
128 int32_t i;
129 for (i=0; i<8; i++,bits>>=8)
130 if ( (buf[i]= (char)(bits & 0xff)) == 0 )
131 break;
132 buf[i] = 0;
133 return(i);
134}
135
136uint64_t stringbits(char *str)
137{
138 uint64_t bits = 0;
139 if ( str == 0 )
140 return(0);
141 int32_t i,n = (int32_t)strlen(str);
142 if ( n > 8 )
143 n = 8;
144 for (i=n-1; i>=0; i--)
145 bits = (bits << 8) | (str[i] & 0xff);
146 //printf("(%s) -> %llx %llu\n",str,(long long)bits,(long long)bits);
147 return(bits);
148}
149
44a9fd7c 150uint256 revuint256(uint256 txid)
151{
152 uint256 revtxid; int32_t i;
153 for (i=31; i>=0; i--)
154 ((uint8_t *)&revtxid)[31-i] = ((uint8_t *)&txid)[i];
155 return(revtxid);
156}
157
158char *uint256_str(char *dest,uint256 txid)
159{
160 int32_t i,j=0;
161 for (i=31; i>=0; i--)
162 sprintf(&dest[j++ * 2],"%02x",((uint8_t *)&txid)[i]);
1cdfa0b5 163 dest[64] = 0;
164 return(dest);
165}
166
167char *pubkey33_str(char *dest,uint8_t *pubkey33)
168{
169 int32_t i;
170 if ( pubkey33 != 0 )
171 {
172 for (i=0; i<33; i++)
173 sprintf(&dest[i * 2],"%02x",pubkey33[i]);
174 } else dest[0] = 0;
175 return(dest);
44a9fd7c 176}
177
178uint256 Parseuint256(char *hexstr)
179{
180 uint256 txid; int32_t i; std::vector<unsigned char> txidbytes(ParseHex(hexstr));
02c68a7b 181 memset(&txid,0,sizeof(txid));
182 if ( strlen(hexstr) == 64 )
183 {
184 for (i=31; i>=0; i--)
185 ((uint8_t *)&txid)[31-i] = ((uint8_t *)txidbytes.data())[i];
186 }
44a9fd7c 187 return(txid);
188}
189
366625ca 190CPubKey buf2pk(uint8_t *buf33)
191{
192 CPubKey pk; int32_t i; uint8_t *dest;
193 dest = (uint8_t *)pk.begin();
194 for (i=0; i<33; i++)
195 dest[i] = buf33[i];
196 return(pk);
197}
198
5cf0c1db 199CPubKey pubkey2pk(std::vector<uint8_t> pubkey)
200{
201 CPubKey pk; int32_t i,n; uint8_t *dest,*pubkey33;
202 n = pubkey.size();
203 dest = (uint8_t *)pk.begin();
204 pubkey33 = (uint8_t *)pubkey.data();
205 for (i=0; i<n; i++)
206 dest[i] = pubkey33[i];
207 return(pk);
208}
209
23e0b80b 210void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
211{
212 cp->evalcode2 = evalcode;
213 cp->unspendablepk2 = pk;
214 memcpy(cp->unspendablepriv2,priv,32);
215 strcpy(cp->unspendableaddr2,coinaddr);
216}
217
218void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
219{
220 cp->evalcode3 = evalcode;
221 cp->unspendablepk3 = pk;
222 memcpy(cp->unspendablepriv3,priv,32);
223 strcpy(cp->unspendableaddr3,coinaddr);
224}
225
44a9fd7c 226bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
227{
68b9a352 228 CTxDestination address;
229 txnouttype whichType;
230 std::vector<std::vector<unsigned char>> vvch = std::vector<std::vector<unsigned char>>();
231 if (Solver(scriptPubKey, whichType, vvch) && vvch[0].size() == 20)
44a9fd7c 232 {
68b9a352 233 address = CKeyID(uint160(vvch[0]));
44a9fd7c 234 strcpy(destaddr,(char *)CBitcoinAddress(address).ToString().c_str());
235 return(true);
236 }
191f3bbd 237 fprintf(stderr,"Solver for scriptPubKey failed\n%s\n", scriptPubKey.ToString().c_str());
44a9fd7c 238 return(false);
239}
240
905fe35e 241bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn,
242 CTransaction &txOut, std::vector<std::vector<unsigned char>> &preConditions, std::vector<std::vector<unsigned char>> &params)
8a727a26 243{
8a727a26 244 uint256 blockHash;
8a727a26 245
281a5e2e 246 if (myGetTransaction(tx.vin[nIn].prevout.hash, txOut, blockHash) && txOut.vout.size() > tx.vin[nIn].prevout.n)
8a727a26 247 {
248 CBlockIndex index;
249 if (eval->GetBlock(blockHash, index))
250 {
251 // read preconditions
252 CScript subScript = CScript();
253 preConditions.clear();
254 if (txOut.vout[tx.vin[nIn].prevout.n].scriptPubKey.IsPayToCryptoCondition(&subScript, preConditions))
255 {
256 // read any available parameters in the output transaction
257 params.clear();
191f3bbd 258 if (tx.vout.size() > 0 && tx.vout[tx.vout.size() - 1].scriptPubKey.IsOpReturn())
259 {
60b798c4 260 if (tx.vout[tx.vout.size() - 1].scriptPubKey.GetOpretData(params) && params.size() == 1)
281a5e2e 261 {
26bf01e9 262 CScript scr = CScript(params[0].begin(), params[0].end());
263
51848bbc 264 // printf("Script decoding inner:\n%s\nouter:\n%s\n", scr.ToString().c_str(), tx.vout[tx.vout.size() - 1].scriptPubKey.ToString().c_str());
26bf01e9 265
60b798c4 266 if (!scr.GetPushedData(scr.begin(), params))
281a5e2e 267 {
60b798c4 268 return false;
281a5e2e 269 }
60b798c4 270 else return true;
281a5e2e 271 }
60b798c4 272 else return false;
191f3bbd 273 }
60b798c4 274 else return true;
8a727a26 275 }
276 }
277 }
60b798c4 278 return false;
8a727a26 279}
280
612f676a 281CPubKey CCtxidaddr(char *txidaddr,uint256 txid)
282{
283 uint8_t buf33[33]; CPubKey pk;
284 buf33[0] = 0x02;
285 endiancpy(&buf33[1],(uint8_t *)&txid,32);
286 pk = buf2pk(buf33);
384c05de 287 Getscriptaddress(txidaddr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG);
612f676a 288 return(pk);
289}
290
3515c101 291bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk)
ec6fec40 292{
293 CC *payoutCond;
294 destaddr[0] = 0;
3515c101 295 if ( (payoutCond= MakeCCcond1(evalcode,pk)) != 0 )
ec6fec40 296 {
297 Getscriptaddress(destaddr,CCPubKey(payoutCond));
298 cc_free(payoutCond);
810f6366 299 }
300 return(destaddr[0] != 0);
301}
302
3515c101 303bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
304{
305 destaddr[0] = 0;
306 if ( pk.size() == 0 )
307 pk = GetUnspendable(cp,0);
308 return(_GetCCaddress(destaddr,cp->evalcode,pk));
309}
310
810f6366 311bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2)
312{
313 CC *payoutCond;
314 destaddr[0] = 0;
315 if ( (payoutCond= MakeCCcond1of2(cp->evalcode,pk,pk2)) != 0 )
316 {
317 Getscriptaddress(destaddr,CCPubKey(payoutCond));
318 cc_free(payoutCond);
ec6fec40 319 }
320 return(destaddr[0] != 0);
321}
322
59da6d30 323bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue)
d082e563 324{
325 char destaddr[64];
326 if ( vout.scriptPubKey.IsPayToCryptoCondition() != CCflag )
36e071fc 327 {
328 fprintf(stderr,"constrain vout error isCC %d vs %d CCflag\n",vout.scriptPubKey.IsPayToCryptoCondition(),CCflag);
d082e563 329 return(false);
36e071fc 330 }
d082e563 331 else if ( cmpaddr != 0 && (Getscriptaddress(destaddr,vout.scriptPubKey) == 0 || strcmp(destaddr,cmpaddr) != 0) )
37e67a2a 332 {
20eb6d30 333 fprintf(stderr,"constrain vout error addr %s vs %s\n",cmpaddr!=0?cmpaddr:"",destaddr!=0?destaddr:"");
d082e563 334 return(false);
37e67a2a 335 }
698d25f7 336 else if ( nValue != 0 && nValue != vout.nValue ) //(nValue == 0 && vout.nValue < 10000) || (
37e67a2a 337 {
338 fprintf(stderr,"constrain vout error nValue %.8f vs %.8f\n",(double)nValue/COIN,(double)vout.nValue/COIN);
d082e563 339 return(false);
37e67a2a 340 }
d082e563 341 else return(true);
342}
343
e49eb6ed 344bool PreventCC(Eval* eval,const CTransaction &tx,int32_t preventCCvins,int32_t numvins,int32_t preventCCvouts,int32_t numvouts)
02c68a7b 345{
346 int32_t i;
347 if ( preventCCvins >= 0 )
348 {
349 for (i=preventCCvins; i<numvins; i++)
350 {
351 if ( IsCCInput(tx.vin[i].scriptSig) != 0 )
352 return eval->Invalid("invalid CC vin");
353 }
354 }
355 if ( preventCCvouts >= 0 )
356 {
357 for (i=preventCCvouts; i<numvouts; i++)
358 {
359 if ( tx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 )
ee360983 360 {
361 fprintf(stderr,"vout.%d is CC\n",i);
02c68a7b 362 return eval->Invalid("invalid CC vout");
ee360983 363 }
02c68a7b 364 }
365 }
366 return(true);
367}
368
44a9fd7c 369std::vector<uint8_t> Mypubkey()
370{
371 extern uint8_t NOTARY_PUBKEY33[33];
372 std::vector<uint8_t> pubkey; int32_t i; uint8_t *dest,*pubkey33;
373 pubkey33 = NOTARY_PUBKEY33;
374 pubkey.resize(33);
375 dest = pubkey.data();
376 for (i=0; i<33; i++)
377 dest[i] = pubkey33[i];
378 return(pubkey);
379}
380
381bool Myprivkey(uint8_t myprivkey[])
382{
383 char coinaddr[64]; std::string strAddress; char *dest; int32_t i,n; CBitcoinAddress address; CKeyID keyID; CKey vchSecret;
384 if ( Getscriptaddress(coinaddr,CScript() << Mypubkey() << OP_CHECKSIG) != 0 )
385 {
386 n = (int32_t)strlen(coinaddr);
387 strAddress.resize(n+1);
388 dest = (char *)strAddress.data();
389 for (i=0; i<n; i++)
390 dest[i] = coinaddr[i];
391 dest[i] = 0;
392 if ( address.SetString(strAddress) != 0 && address.GetKeyID(keyID) != 0 )
393 {
394#ifdef ENABLE_WALLET
395 if ( pwalletMain->GetKey(keyID,vchSecret) != 0 )
396 {
397 memcpy(myprivkey,vchSecret.begin(),32);
558b29ac 398 if ( 0 )
ff780022 399 {
400 for (i=0; i<32; i++)
401 fprintf(stderr,"0x%02x, ",myprivkey[i]);
aed3f987 402 fprintf(stderr," found privkey for %s!\n",dest);
ff780022 403 }
44a9fd7c 404 return(true);
405 }
406#endif
407 }
408 }
409 fprintf(stderr,"privkey for the -pubkey= address is not in the wallet, importprivkey!\n");
410 return(false);
411}
412
287efad4 413CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv)
414{
415 if ( unspendablepriv != 0 )
416 memcpy(unspendablepriv,cp->CCpriv,32);
417 return(pubkey2pk(ParseHex(cp->CChexstr)));
418}
419
420bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull,const CTransaction &ctx, unsigned int nIn)
421{
e4e12ec0 422 CTransaction createTx; uint256 assetid,assetid2,hashBlock; uint8_t funcid; int32_t height,i,n,from_mempool = 0; int64_t amount; std::vector<uint8_t> origpubkey;
90c81155 423 height = KOMODO_CONNECTING;
ad274d5b 424 if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
425 return(true);
57c2bccd 426 if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE )
90c81155 427 return eval->Invalid("CC are disabled or not active yet");
e4e12ec0 428 if ( (KOMODO_CONNECTING & (1<<30)) != 0 )
429 {
430 from_mempool = 1;
431 height &= ((1<<30) - 1);
432 }
756e9cf7 433 //fprintf(stderr,"KOMODO_CONNECTING.%d mempool.%d vs CCactive.%d\n",height,from_mempool,KOMODO_CCACTIVATE);
4d2b7323 434 // there is a chance CC tx is valid in mempool, but invalid when in block, so we cant filter duplicate requests. if any of the vins are spent, for example
7347a801 435 //txid = ctx.GetHash();
436 //if ( txid == cp->prevtxid )
437 // return(true);
b4795ed6 438 //fprintf(stderr,"process CC %02x\n",cp->evalcode);
23e0b80b 439 cp->evalcode2 = cp->evalcode3 = 0;
440 cp->unspendableaddr2[0] = cp->unspendableaddr3[0] = 0;
287efad4 441 if ( paramsNull.size() != 0 ) // Don't expect params
442 return eval->Invalid("Cannot have params");
191f3bbd 443 //else if ( ctx.vout.size() == 0 ) // spend can go to z-addresses
444 // return eval->Invalid("no-vouts");
8a727a26 445 else if ( (*cp->validate)(cp,eval,ctx,nIn) != 0 )
287efad4 446 {
7adbb3e3 447 //fprintf(stderr,"done CC %02x\n",cp->evalcode);
7347a801 448 //cp->prevtxid = txid;
287efad4 449 return(true);
450 }
7adbb3e3 451 //fprintf(stderr,"invalid CC %02x\n",cp->evalcode);
287efad4 452 return(false);
453}
454
da07d84b 455int64_t CCduration(int32_t &numblocks,uint256 txid)
2b011ff7 456{
da07d84b 457 CTransaction tx; uint256 hashBlock; uint32_t txheight,txtime=0; char str[65]; CBlockIndex *pindex; int64_t duration = 0;
458 numblocks = 0;
fb89b441 459 if ( myGetTransaction(txid,tx,hashBlock) == 0 )
2b011ff7 460 {
f1c75a66 461 fprintf(stderr,"CCduration cant find duration txid %s\n",uint256_str(str,txid));
2b011ff7 462 return(0);
463 }
f1c75a66 464 else if ( hashBlock == zeroid )
465 {
466 fprintf(stderr,"CCduration no hashBlock for txid %s\n",uint256_str(str,txid));
467 return(0);
468 }
4b729ec5 469 else if ( (pindex= mapBlockIndex[hashBlock]) == 0 || (txtime= pindex->nTime) == 0 || (txheight= pindex->GetHeight()) <= 0 )
f1c75a66 470 {
da07d84b 471 fprintf(stderr,"CCduration no txtime %u or txheight.%d %p for txid %s\n",txtime,txheight,pindex,uint256_str(str,txid));
f1c75a66 472 return(0);
473 }
4b729ec5 474 else if ( (pindex= chainActive.LastTip()) == 0 || pindex->nTime < txtime || pindex->GetHeight() <= txheight )
f1c75a66 475 {
4b729ec5 476 fprintf(stderr,"CCduration backwards timestamps %u %u for txid %s hts.(%d %d)\n",(uint32_t)pindex->nTime,txtime,uint256_str(str,txid),txheight,(int32_t)pindex->GetHeight());
f1c75a66 477 return(0);
478 }
4b729ec5 479 numblocks = (pindex->GetHeight() - txheight);
f1c75a66 480 duration = (pindex->nTime - txtime);
4b729ec5 481 fprintf(stderr,"duration %d (%u - %u) numblocks %d (%d - %d)\n",(int32_t)duration,(uint32_t)pindex->nTime,txtime,numblocks,pindex->GetHeight(),txheight);
2b011ff7 482 return(duration);
483}
484
This page took 0.227543 seconds and 4 git commands to generate.