]> Git Repo - VerusCoin.git/blob - src/cc/CCutils.cpp
Remove spurious error messages & improve identity sync
[VerusCoin.git] / src / cc / CCutils.cpp
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
22 void 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 }
32
33 CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2)
34 {
35     std::vector<CC*> pks;
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});
41 }
42
43 CC *MakeCCcond1(uint8_t evalcode, CPubKey pk)
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
52 CC *MakeCCcond1(uint8_t evalcode, CTxDestination dest)
53 {
54     CPubKey pk = boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), dest);
55     std::vector<CC*> pks;
56     if (pk.IsValid())
57     {
58         pks.push_back(CCNewSecp256k1(pk));
59     }
60     else
61     {
62         pks.push_back(CCNewHashedSecp256k1(CKeyID(GetDestinationID(dest))));
63     }
64     CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
65     CC *Sig = CCNewThreshold(1, pks);
66     return CCNewThreshold(2, {condCC, Sig});
67 }
68
69 CC *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
90 CTxOut MakeCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk)
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
99 CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2)
100 {
101     CTxOut vout;
102     CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2);
103     vout = CTxOut(nValue,CCPubKey(payoutCond));
104     cc_free(payoutCond);
105     return(vout);
106 }
107
108 CC* 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
117 bool 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
126 int32_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
136 uint64_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
150 uint256 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
158 char *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]);
163     dest[64] = 0;
164     return(dest);
165 }
166
167 char *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);
176 }
177
178 uint256 Parseuint256(char *hexstr)
179 {
180     uint256 txid; int32_t i; std::vector<unsigned char> txidbytes(ParseHex(hexstr));
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     }
187     return(txid);
188 }
189
190 CPubKey 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
199 CPubKey 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
210 void 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
218 void 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
226 bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
227 {
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)
232     {
233         address = CKeyID(uint160(vvch[0]));
234         strcpy(destaddr,(char *)CBitcoinAddress(address).ToString().c_str());
235         return(true);
236     }
237     fprintf(stderr,"Solver for scriptPubKey failed\n%s\n", scriptPubKey.ToString().c_str());
238     return(false);
239 }
240
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>> &params)
243 {
244     uint256 blockHash;
245
246     if (myGetTransaction(tx.vin[nIn].prevout.hash, txOut, blockHash) && txOut.vout.size() > tx.vin[nIn].prevout.n)
247     {
248         // must ensure that the block is valid and that this is a valid
249         CBlockIndex index;
250         if (eval->GetBlock(blockHash, index))
251         {
252             // read preconditions
253             CScript subScript = CScript();
254             preConditions.clear();
255             if (txOut.vout[tx.vin[nIn].prevout.n].scriptPubKey.IsPayToCryptoCondition(&subScript, preConditions))
256             {
257                 // read any available parameters in the output transaction
258                 params.clear();
259                 if (tx.vout.size() > 0 && tx.vout[tx.vout.size() - 1].scriptPubKey.IsOpReturn())
260                 {
261                     if (tx.vout[tx.vout.size() - 1].scriptPubKey.GetOpretData(params) && params.size() == 1)
262                     {
263                         CScript scr = CScript(params[0].begin(), params[0].end());
264
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());
266
267                         if (!scr.GetPushedData(scr.begin(), params))
268                         {
269                             return false;
270                         }
271                         else return true;
272                     }
273                     else return false;
274                 }
275                 else return true;
276             }
277         }
278     }
279     return false;
280 }
281
282 CPubKey CCtxidaddr(char *txidaddr,uint256 txid)
283 {
284     uint8_t buf33[33]; CPubKey pk;
285     buf33[0] = 0x02;
286     endiancpy(&buf33[1],(uint8_t *)&txid,32);
287     pk = buf2pk(buf33);
288     Getscriptaddress(txidaddr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG);
289     return(pk);
290 }
291
292 bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk)
293 {
294     CC *payoutCond;
295     destaddr[0] = 0;
296     if ( (payoutCond= MakeCCcond1(evalcode,pk)) != 0 )
297     {
298         Getscriptaddress(destaddr,CCPubKey(payoutCond));
299         cc_free(payoutCond);
300     }
301     return(destaddr[0] != 0);
302 }
303
304 bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
305 {
306     destaddr[0] = 0;
307     if ( pk.size() == 0 )
308         pk = GetUnspendable(cp,0);
309     return(_GetCCaddress(destaddr,cp->evalcode,pk));
310 }
311
312 bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2)
313 {
314     CC *payoutCond;
315     destaddr[0] = 0;
316     if ( (payoutCond= MakeCCcond1of2(cp->evalcode,pk,pk2)) != 0 )
317     {
318         Getscriptaddress(destaddr,CCPubKey(payoutCond));
319         cc_free(payoutCond);
320     }
321     return(destaddr[0] != 0);
322 }
323
324 bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue)
325 {
326     char destaddr[64];
327     if ( vout.scriptPubKey.IsPayToCryptoCondition() != CCflag )
328     {
329         fprintf(stderr,"constrain vout error isCC %d vs %d CCflag\n",vout.scriptPubKey.IsPayToCryptoCondition(),CCflag);
330         return(false);
331     }
332     else if ( cmpaddr != 0 && (Getscriptaddress(destaddr,vout.scriptPubKey) == 0 || strcmp(destaddr,cmpaddr) != 0) )
333     {
334         fprintf(stderr,"constrain vout error addr %s vs %s\n",cmpaddr!=0?cmpaddr:"",destaddr!=0?destaddr:"");
335         return(false);
336     }
337     else if ( nValue != 0 && nValue != vout.nValue ) //(nValue == 0 && vout.nValue < 10000) || (
338     {
339         fprintf(stderr,"constrain vout error nValue %.8f vs %.8f\n",(double)nValue/COIN,(double)vout.nValue/COIN);
340         return(false);
341     }
342     else return(true);
343 }
344
345 bool PreventCC(Eval* eval,const CTransaction &tx,int32_t preventCCvins,int32_t numvins,int32_t preventCCvouts,int32_t numvouts)
346 {
347     int32_t i;
348     if ( preventCCvins >= 0 )
349     {
350         for (i=preventCCvins; i<numvins; i++)
351         {
352             if ( IsCCInput(tx.vin[i].scriptSig) != 0 )
353                 return eval->Invalid("invalid CC vin");
354         }
355     }
356     if ( preventCCvouts >= 0 )
357     {
358         for (i=preventCCvouts; i<numvouts; i++)
359         {
360             if ( tx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 )
361             {
362                 fprintf(stderr,"vout.%d is CC\n",i);
363                 return eval->Invalid("invalid CC vout");
364             }
365         }
366     }
367     return(true);
368 }
369
370 std::vector<uint8_t> Mypubkey()
371 {
372     extern uint8_t NOTARY_PUBKEY33[33];
373     std::vector<uint8_t> pubkey; int32_t i; uint8_t *dest,*pubkey33;
374     pubkey33 = NOTARY_PUBKEY33;
375     pubkey.resize(33);
376     dest = pubkey.data();
377     for (i=0; i<33; i++)
378         dest[i] = pubkey33[i];
379     return(pubkey);
380 }
381
382 bool Myprivkey(uint8_t myprivkey[])
383 {
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 )
386     {
387         n = (int32_t)strlen(coinaddr);
388         strAddress.resize(n+1);
389         dest = (char *)strAddress.data();
390         for (i=0; i<n; i++)
391             dest[i] = coinaddr[i];
392         dest[i] = 0;
393         if ( address.SetString(strAddress) != 0 && address.GetKeyID(keyID) != 0 )
394         {
395 #ifdef ENABLE_WALLET
396             if ( pwalletMain->GetKey(keyID,vchSecret) != 0 )
397             {
398                 memcpy(myprivkey,vchSecret.begin(),32);
399                 if ( 0 )
400                 {
401                     for (i=0; i<32; i++)
402                         fprintf(stderr,"0x%02x, ",myprivkey[i]);
403                     fprintf(stderr," found privkey for %s!\n",dest);
404                 }
405                 return(true);
406             }
407 #endif
408         }
409     }
410     fprintf(stderr,"privkey for the -pubkey= address is not in the wallet, importprivkey!\n");
411     return(false);
412 }
413
414 CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv)
415 {
416     if ( unspendablepriv != 0 )
417         memcpy(unspendablepriv,cp->CCpriv,32);
418     return(pubkey2pk(ParseHex(cp->CChexstr)));
419 }
420
421 bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull,const CTransaction &ctx, unsigned int nIn, bool fulfilled)
422 {
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
426         return(true);
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 )
430     {
431         from_mempool = 1;
432         height &= ((1<<30) - 1);
433     }
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 )
438     //    return(true);
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 )
447     {
448         //fprintf(stderr,"done CC %02x\n",cp->evalcode);
449         //cp->prevtxid = txid;
450         return(true);
451     }
452     //fprintf(stderr,"invalid CC %02x\n",cp->evalcode);
453     return(false);
454 }
455
456 int64_t CCduration(int32_t &numblocks,uint256 txid)
457 {
458     CTransaction tx; uint256 hashBlock; uint32_t txheight,txtime=0; char str[65]; CBlockIndex *pindex; int64_t duration = 0;
459     numblocks = 0;
460     if ( myGetTransaction(txid,tx,hashBlock) == 0 )
461     {
462         fprintf(stderr,"CCduration cant find duration txid %s\n",uint256_str(str,txid));
463         return(0);
464     }
465     else if ( hashBlock == zeroid )
466     {
467         fprintf(stderr,"CCduration no hashBlock for txid %s\n",uint256_str(str,txid));
468         return(0);
469     }
470     else if ( (pindex= mapBlockIndex[hashBlock]) == 0 || (txtime= pindex->nTime) == 0 || (txheight= pindex->GetHeight()) <= 0 )
471     {
472         fprintf(stderr,"CCduration no txtime %u or txheight.%d %p for txid %s\n",txtime,txheight,pindex,uint256_str(str,txid));
473         return(0);
474     }
475     else if ( (pindex= chainActive.LastTip()) == 0 || pindex->nTime < txtime || pindex->GetHeight() <= txheight )
476     {
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());
478         return(0);
479     }
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);
483     return(duration);
484 }
485
This page took 0.050887 seconds and 4 git commands to generate.