1 /******************************************************************************
2 * Copyright © 2014-2018 The SuperNET Developers. *
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. *
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 *
12 * Removal or modification of this copyright notice is prohibited. *
14 ******************************************************************************/
16 #include "CCinclude.h"
19 CCutils has low level functions that are universally useful for all contracts.
22 void endiancpy(uint8_t *dest,uint8_t *src,int32_t len)
25 #if defined(WORDS_BIGENDIAN)
33 CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2)
36 pks.push_back(CCNewSecp256k1(pk1));
37 pks.push_back(CCNewSecp256k1(pk2));
38 CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
39 CC *Sig = CCNewThreshold(1, pks);
40 return CCNewThreshold(2, {condCC, Sig});
43 CC *MakeCCcond1(uint8_t evalcode, CPubKey pk)
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});
52 CC *MakeCCcond1(uint8_t evalcode, CTxDestination dest)
54 CPubKey pk = boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), dest);
58 pks.push_back(CCNewSecp256k1(pk));
62 pks.push_back(CCNewHashedSecp256k1(CKeyID(GetDestinationID(dest))));
64 CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
65 CC *Sig = CCNewThreshold(1, pks);
66 return CCNewThreshold(2, {condCC, Sig});
69 CC *MakeCCcondAny(uint8_t evalcode, std::vector<CTxDestination> dests)
72 for (auto dest : dests)
74 CPubKey pk = boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), dest);
77 pks.push_back(CCNewSecp256k1(pk));
81 pks.push_back(CCNewHashedSecp256k1(CKeyID(GetDestinationID(dest))));
85 CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
86 CC *Sig = CCNewThreshold(1, pks);
87 return CCNewThreshold(2, {condCC, Sig});
90 CTxOut MakeCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk)
93 CC *payoutCond = MakeCCcond1(evalcode,pk);
94 vout = CTxOut(nValue,CCPubKey(payoutCond));
99 CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2)
102 CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2);
103 vout = CTxOut(nValue,CCPubKey(payoutCond));
108 CC* GetCryptoCondition(CScript const& scriptSig)
110 auto pc = scriptSig.begin();
112 std::vector<unsigned char> ffbin;
113 if (scriptSig.GetOp(pc, opcode, ffbin))
114 return cc_readFulfillmentBinary((uint8_t*)ffbin.data(), ffbin.size()-1);
117 bool IsCCInput(CScript const& scriptSig)
120 if ( (cond= GetCryptoCondition(scriptSig)) == 0 )
126 int32_t unstringbits(char *buf,uint64_t bits)
129 for (i=0; i<8; i++,bits>>=8)
130 if ( (buf[i]= (char)(bits & 0xff)) == 0 )
136 uint64_t stringbits(char *str)
141 int32_t i,n = (int32_t)strlen(str);
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);
150 uint256 revuint256(uint256 txid)
152 uint256 revtxid; int32_t i;
153 for (i=31; i>=0; i--)
154 ((uint8_t *)&revtxid)[31-i] = ((uint8_t *)&txid)[i];
158 char *uint256_str(char *dest,uint256 txid)
161 for (i=31; i>=0; i--)
162 sprintf(&dest[j++ * 2],"%02x",((uint8_t *)&txid)[i]);
167 char *pubkey33_str(char *dest,uint8_t *pubkey33)
173 sprintf(&dest[i * 2],"%02x",pubkey33[i]);
178 uint256 Parseuint256(char *hexstr)
180 uint256 txid; int32_t i; std::vector<unsigned char> txidbytes(ParseHex(hexstr));
181 memset(&txid,0,sizeof(txid));
182 if ( strlen(hexstr) == 64 )
184 for (i=31; i>=0; i--)
185 ((uint8_t *)&txid)[31-i] = ((uint8_t *)txidbytes.data())[i];
190 CPubKey buf2pk(uint8_t *buf33)
192 CPubKey pk; int32_t i; uint8_t *dest;
193 dest = (uint8_t *)pk.begin();
199 CPubKey pubkey2pk(std::vector<uint8_t> pubkey)
201 CPubKey pk; int32_t i,n; uint8_t *dest,*pubkey33;
203 dest = (uint8_t *)pk.begin();
204 pubkey33 = (uint8_t *)pubkey.data();
206 dest[i] = pubkey33[i];
210 void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
212 cp->evalcode2 = evalcode;
213 cp->unspendablepk2 = pk;
214 memcpy(cp->unspendablepriv2,priv,32);
215 strcpy(cp->unspendableaddr2,coinaddr);
218 void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
220 cp->evalcode3 = evalcode;
221 cp->unspendablepk3 = pk;
222 memcpy(cp->unspendablepriv3,priv,32);
223 strcpy(cp->unspendableaddr3,coinaddr);
226 bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
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)
233 address = CKeyID(uint160(vvch[0]));
234 strcpy(destaddr,(char *)CBitcoinAddress(address).ToString().c_str());
237 fprintf(stderr,"Solver for scriptPubKey failed\n%s\n", scriptPubKey.ToString().c_str());
241 bool 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>> ¶ms)
246 if (myGetTransaction(tx.vin[nIn].prevout.hash, txOut, blockHash) && txOut.vout.size() > tx.vin[nIn].prevout.n)
248 // must ensure that the block is valid and that this is a valid
250 if (eval->GetBlock(blockHash, index))
252 // read preconditions
253 CScript subScript = CScript();
254 preConditions.clear();
255 if (txOut.vout[tx.vin[nIn].prevout.n].scriptPubKey.IsPayToCryptoCondition(&subScript, preConditions))
257 // read any available parameters in the output transaction
259 if (tx.vout.size() > 0 && tx.vout[tx.vout.size() - 1].scriptPubKey.IsOpReturn())
261 if (tx.vout[tx.vout.size() - 1].scriptPubKey.GetOpretData(params) && params.size() == 1)
263 CScript scr = CScript(params[0].begin(), params[0].end());
265 // printf("Script decoding inner:\n%s\nouter:\n%s\n", scr.ToString().c_str(), tx.vout[tx.vout.size() - 1].scriptPubKey.ToString().c_str());
267 if (!scr.GetPushedData(scr.begin(), params))
282 CPubKey CCtxidaddr(char *txidaddr,uint256 txid)
284 uint8_t buf33[33]; CPubKey pk;
286 endiancpy(&buf33[1],(uint8_t *)&txid,32);
288 Getscriptaddress(txidaddr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG);
292 bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk)
296 if ( (payoutCond= MakeCCcond1(evalcode,pk)) != 0 )
298 Getscriptaddress(destaddr,CCPubKey(payoutCond));
301 return(destaddr[0] != 0);
304 bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
307 if ( pk.size() == 0 )
308 pk = GetUnspendable(cp,0);
309 return(_GetCCaddress(destaddr,cp->evalcode,pk));
312 bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2)
316 if ( (payoutCond= MakeCCcond1of2(cp->evalcode,pk,pk2)) != 0 )
318 Getscriptaddress(destaddr,CCPubKey(payoutCond));
321 return(destaddr[0] != 0);
324 bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue)
327 if ( vout.scriptPubKey.IsPayToCryptoCondition() != CCflag )
329 fprintf(stderr,"constrain vout error isCC %d vs %d CCflag\n",vout.scriptPubKey.IsPayToCryptoCondition(),CCflag);
332 else if ( cmpaddr != 0 && (Getscriptaddress(destaddr,vout.scriptPubKey) == 0 || strcmp(destaddr,cmpaddr) != 0) )
334 fprintf(stderr,"constrain vout error addr %s vs %s\n",cmpaddr!=0?cmpaddr:"",destaddr!=0?destaddr:"");
337 else if ( nValue != 0 && nValue != vout.nValue ) //(nValue == 0 && vout.nValue < 10000) || (
339 fprintf(stderr,"constrain vout error nValue %.8f vs %.8f\n",(double)nValue/COIN,(double)vout.nValue/COIN);
345 bool PreventCC(Eval* eval,const CTransaction &tx,int32_t preventCCvins,int32_t numvins,int32_t preventCCvouts,int32_t numvouts)
348 if ( preventCCvins >= 0 )
350 for (i=preventCCvins; i<numvins; i++)
352 if ( IsCCInput(tx.vin[i].scriptSig) != 0 )
353 return eval->Invalid("invalid CC vin");
356 if ( preventCCvouts >= 0 )
358 for (i=preventCCvouts; i<numvouts; i++)
360 if ( tx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 )
362 fprintf(stderr,"vout.%d is CC\n",i);
363 return eval->Invalid("invalid CC vout");
370 std::vector<uint8_t> Mypubkey()
372 extern uint8_t NOTARY_PUBKEY33[33];
373 std::vector<uint8_t> pubkey; int32_t i; uint8_t *dest,*pubkey33;
374 pubkey33 = NOTARY_PUBKEY33;
376 dest = pubkey.data();
378 dest[i] = pubkey33[i];
382 bool Myprivkey(uint8_t myprivkey[])
384 char coinaddr[64]; std::string strAddress; char *dest; int32_t i,n; CBitcoinAddress address; CKeyID keyID; CKey vchSecret;
385 if ( Getscriptaddress(coinaddr,CScript() << Mypubkey() << OP_CHECKSIG) != 0 )
387 n = (int32_t)strlen(coinaddr);
388 strAddress.resize(n+1);
389 dest = (char *)strAddress.data();
391 dest[i] = coinaddr[i];
393 if ( address.SetString(strAddress) != 0 && address.GetKeyID(keyID) != 0 )
396 if ( pwalletMain->GetKey(keyID,vchSecret) != 0 )
398 memcpy(myprivkey,vchSecret.begin(),32);
402 fprintf(stderr,"0x%02x, ",myprivkey[i]);
403 fprintf(stderr," found privkey for %s!\n",dest);
410 fprintf(stderr,"privkey for the -pubkey= address is not in the wallet, importprivkey!\n");
414 CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv)
416 if ( unspendablepriv != 0 )
417 memcpy(unspendablepriv,cp->CCpriv,32);
418 return(pubkey2pk(ParseHex(cp->CChexstr)));
421 bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull,const CTransaction &ctx, unsigned int nIn, bool fulfilled)
423 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;
424 height = KOMODO_CONNECTING;
425 if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
427 if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE )
428 return eval->Invalid("CC are disabled or not active yet");
429 if ( (KOMODO_CONNECTING & (1<<30)) != 0 )
432 height &= ((1<<30) - 1);
434 //fprintf(stderr,"KOMODO_CONNECTING.%d mempool.%d vs CCactive.%d\n",height,from_mempool,KOMODO_CCACTIVATE);
435 // 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
436 //txid = ctx.GetHash();
437 //if ( txid == cp->prevtxid )
439 //fprintf(stderr,"process CC %02x\n",cp->evalcode);
440 cp->evalcode2 = cp->evalcode3 = 0;
441 cp->unspendableaddr2[0] = cp->unspendableaddr3[0] = 0;
442 if ( paramsNull.size() != 0 ) // Don't expect params
443 return eval->Invalid("Cannot have params");
444 //else if ( ctx.vout.size() == 0 ) // spend can go to z-addresses
445 // return eval->Invalid("no-vouts");
446 else if ( (*cp->validate)(cp, eval, ctx, nIn, fulfilled) != 0 )
448 //fprintf(stderr,"done CC %02x\n",cp->evalcode);
449 //cp->prevtxid = txid;
452 //fprintf(stderr,"invalid CC %02x\n",cp->evalcode);
456 int64_t CCduration(int32_t &numblocks,uint256 txid)
458 CTransaction tx; uint256 hashBlock; uint32_t txheight,txtime=0; char str[65]; CBlockIndex *pindex; int64_t duration = 0;
460 if ( myGetTransaction(txid,tx,hashBlock) == 0 )
462 fprintf(stderr,"CCduration cant find duration txid %s\n",uint256_str(str,txid));
465 else if ( hashBlock == zeroid )
467 fprintf(stderr,"CCduration no hashBlock for txid %s\n",uint256_str(str,txid));
470 else if ( (pindex= mapBlockIndex[hashBlock]) == 0 || (txtime= pindex->nTime) == 0 || (txheight= pindex->GetHeight()) <= 0 )
472 fprintf(stderr,"CCduration no txtime %u or txheight.%d %p for txid %s\n",txtime,txheight,pindex,uint256_str(str,txid));
475 else if ( (pindex= chainActive.LastTip()) == 0 || pindex->nTime < txtime || pindex->GetHeight() <= txheight )
477 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());
480 numblocks = (pindex->GetHeight() - txheight);
481 duration = (pindex->nTime - txtime);
482 fprintf(stderr,"duration %d (%u - %u) numblocks %d (%d - %d)\n",(int32_t)duration,(uint32_t)pindex->nTime,txtime,numblocks,pindex->GetHeight(),txheight);