]> Git Repo - VerusCoin.git/blob - src/cc/CCtx.cpp
Update without PBaaS for interim release
[VerusCoin.git] / src / cc / CCtx.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 #include "key_io.h"
18
19 /*
20  FinalizeCCTx is a very useful function that will properly sign both CC and normal inputs, adds normal change and the opreturn.
21  
22  This allows the contract transaction functions to create the appropriate vins and vouts and have FinalizeCCTx create a properly signed transaction.
23  
24  By using -addressindex=1, it allows tracking of all the CC addresses
25  */
26  
27 bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey)
28 {
29 #ifdef ENABLE_WALLET
30     CTransaction txNewConst(mtx); SignatureData sigdata; const CKeyStore& keystore = *pwalletMain;
31     auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
32     if ( ProduceSignature(TransactionSignatureCreator(&keystore,&txNewConst,vini,utxovalue,SIGHASH_ALL),scriptPubKey,sigdata,consensusBranchId) != 0 )
33     {
34         UpdateTransaction(mtx,vini,sigdata);
35         return(true);
36     } else fprintf(stderr,"signing error for SignTx vini.%d %.8f\n",vini,(double)utxovalue/COIN);
37 #else
38     return(false);
39 #endif
40 }
41
42 std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret)
43 {
44     auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
45     CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0; int64_t utxovalues[64],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0; int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64]; uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; CC *mycond=0,*othercond=0,*othercond2=0,*othercond3=0,*cond; CPubKey unspendablepk;
46     n = mtx.vout.size();
47     for (i=0; i<n; i++)
48     {
49         if ( mtx.vout[i].scriptPubKey.IsPayToCryptoCondition() == 0 )
50             normaloutputs += mtx.vout[i].nValue;
51         totaloutputs += mtx.vout[i].nValue;
52     }
53     if ( (n= mtx.vin.size()) > 64 )
54     {
55         fprintf(stderr,"FinalizeCCTx: %d is too many vins\n",n);
56         return("0");
57     }
58     Myprivkey(myprivkey);
59     unspendablepk = GetUnspendable(cp,unspendablepriv);
60     GetCCaddress(cp,myaddr,mypk);
61     mycond = MakeCCcond1(cp->evalcode,mypk);
62     GetCCaddress(cp,unspendable,unspendablepk);
63     othercond = MakeCCcond1(cp->evalcode,unspendablepk);
64     //fprintf(stderr,"myCCaddr.(%s) %p vs unspendable.(%s) %p\n",myaddr,mycond,unspendable,othercond);
65     memset(utxovalues,0,sizeof(utxovalues));
66     for (i=0; i<n; i++)
67     {
68         if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 )
69         {
70             utxovout = mtx.vin[i].prevout.n;
71             utxovalues[i] = vintx.vout[utxovout].nValue;
72             totalinputs += utxovalues[i];
73             if ( vintx.vout[utxovout].scriptPubKey.IsPayToCryptoCondition() == 0 )
74             {
75                 //fprintf(stderr,"vin.%d is normal %.8f\n",i,(double)utxovalues[i]/COIN);
76                 normalinputs += utxovalues[i];
77                 vinimask |= (1LL << i);
78             }
79             else
80             {
81                 mask |= (1LL << i);
82             }
83         } else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
84     }
85     nmask = (1LL << n) - 1;
86     if ( 0 && (mask & nmask) != (CCmask & nmask) )
87         fprintf(stderr,"mask.%llx vs CCmask.%llx %llx %llx %llx\n",(long long)(mask & nmask),(long long)(CCmask & nmask),(long long)mask,(long long)CCmask,(long long)nmask);
88     if ( totalinputs >= totaloutputs+2*txfee )
89     {
90         change = totalinputs - (totaloutputs+txfee);
91         mtx.vout.push_back(CTxOut(change,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
92     }
93     if ( opret.size() > 0 )
94         mtx.vout.push_back(CTxOut(0,opret));
95     PrecomputedTransactionData txdata(mtx);
96     n = mtx.vin.size();
97     for (i=0; i<n; i++)
98     {
99         if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 )
100         {
101             utxovout = mtx.vin[i].prevout.n;
102             if ( vintx.vout[utxovout].scriptPubKey.IsPayToCryptoCondition() == 0 )
103             {
104                 if ( SignTx(mtx,i,vintx.vout[utxovout].nValue,vintx.vout[utxovout].scriptPubKey) == 0 )
105                     fprintf(stderr,"signing error for vini.%d of %llx\n",i,(long long)vinimask);
106             }
107             else
108             {
109                 Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey);
110                 //fprintf(stderr,"vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr);
111                 if ( strcmp(destaddr,myaddr) == 0 )
112                 {
113                     privkey = myprivkey;
114                     cond = mycond;
115                     //fprintf(stderr,"my CC addr.(%s)\n",myaddr);
116                 }
117                 else if ( strcmp(destaddr,unspendable) == 0 )
118                 {
119                     privkey = unspendablepriv;
120                     cond = othercond;
121                     //fprintf(stderr,"unspendable CC addr.(%s)\n",unspendable);
122                 }
123                 else if ( strcmp(destaddr,cp->unspendableaddr2) == 0 )
124                 {
125                     //fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2);
126                     privkey = cp->unspendablepriv2;
127                     if ( othercond2 == 0 )
128                         othercond2 = MakeCCcond1(cp->evalcode2,cp->unspendablepk2);
129                     cond = othercond2;
130                 }
131                 else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 )
132                 {
133                     //fprintf(stderr,"matched %s unspendable3!\n",cp->unspendableaddr3);
134                     privkey = cp->unspendablepriv3;
135                     if ( othercond3 == 0 )
136                         othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3);
137                     cond = othercond3;
138                 }
139                 else
140                 {
141                     fprintf(stderr,"vini.%d has unknown CC address.(%s)\n",i,destaddr);
142                     continue;
143                 }
144                 uint256 sighash = SignatureHash(CCPubKey(cond), mtx, i, SIGHASH_ALL, utxovalues[i],consensusBranchId, &txdata);
145                 if ( cc_signTreeSecp256k1Msg32(cond,privkey,sighash.begin()) != 0 )
146                 {
147                     //int32_t z;
148                     //for (z=0; z<32; z++)
149                     //    fprintf(stderr,"%02x",((uint8_t *)sighash.begin())[z]);
150                     //fprintf(stderr," sighash, ");
151                     //for (z=0; z<32; z++)
152                     //   fprintf(stderr,"%02x",privkey[z]);
153                     //fprintf(stderr," signed with privkey\n");
154                     mtx.vin[i].scriptSig = CCSig(cond);
155                 }
156                 else
157                 {
158                     fprintf(stderr,"vini.%d has CC signing error address.(%s)\n",i,destaddr);
159                 }
160             }
161         } else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
162     }
163     if ( mycond != 0 )
164         cc_free(mycond);
165     if ( othercond != 0 )
166         cc_free(othercond);
167     if ( othercond2 != 0 )
168         cc_free(othercond2);
169     if ( othercond3 != 0 )
170         cc_free(othercond3);
171     std::string strHex = EncodeHexTx(mtx);
172     if ( strHex.size() > 0 )
173         return(strHex);
174     else return("0");
175 }
176
177 void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr)
178 {
179     int32_t type=0,i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
180     n = (int32_t)strlen(coinaddr);
181     addrstr.resize(n+1);
182     ptr = (char *)addrstr.data();
183     for (i=0; i<=n; i++)
184         ptr[i] = coinaddr[i];
185     CBitcoinAddress address(addrstr);
186     if ( address.GetIndexKey(hashBytes, type) == 0 )
187         return;
188     addresses.push_back(std::make_pair(hashBytes,type));
189     for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++)
190     {
191         if ( GetAddressUnspent((*it).first, (*it).second, unspentOutputs) == 0 )
192             return;
193     }
194 }
195
196 void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr)
197 {
198     int32_t type=0,i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
199     n = (int32_t)strlen(coinaddr);
200     addrstr.resize(n+1);
201     ptr = (char *)addrstr.data();
202     for (i=0; i<=n; i++)
203         ptr[i] = coinaddr[i];
204     CBitcoinAddress address(addrstr);
205     if ( address.GetIndexKey(hashBytes, type) == 0 )
206         return;
207     addresses.push_back(std::make_pair(hashBytes,type));
208     for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++)
209     {
210         if ( GetAddressIndex((*it).first, (*it).second, addressIndex) == 0 )
211             return;
212     }
213 }
214
215 int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout)
216 {
217     uint256 txid; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
218     SetCCunspents(unspentOutputs,coinaddr);
219     for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
220     {
221         txid = it->first.txhash;
222         if ( txid == utxotxid && utxovout == it->first.index )
223             return(it->second.satoshis);
224     }
225     return(0);
226 }
227
228 int64_t CCaddress_balance(char *coinaddr)
229 {
230     int64_t sum = 0; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
231     SetCCunspents(unspentOutputs,coinaddr);
232     for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
233     {
234         sum += it->second.satoshis;
235     }
236     return(sum);
237 }
238
239 int64_t CCfullsupply(uint256 tokenid)
240 {
241     uint256 hashBlock; int32_t numvouts; CTransaction tx; std::vector<uint8_t> origpubkey; std::string name,description;
242     if ( GetTransaction(tokenid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
243     {
244         if ( DecodeAssetCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description) > 0 )
245         {
246             return(tx.vout[0].nValue);
247         }
248     }
249     return(0);
250 }
251
252 int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
253 {
254     int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock; std::vector<uint8_t> origpubkey; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
255     SetCCunspents(unspentOutputs,coinaddr);
256     for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
257     {
258         txid = it->first.txhash;
259         if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
260         {
261             if ( DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,assetid2,price,origpubkey) != 0 && assetid == tokenid )
262             {
263                 sum += it->second.satoshis;
264             }
265         }
266     }
267     return(sum);
268 }
269
270 int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *belowp,struct CC_utxo utxos[],int32_t numunspents,int64_t value)
271 {
272     int32_t i,abovei,belowi; int64_t above,below,gap,atx_value;
273     abovei = belowi = -1;
274     for (above=below=i=0; i<numunspents; i++)
275     {
276         if ( (atx_value= utxos[i].nValue) <= 0 )
277             continue;
278         if ( atx_value == value )
279         {
280             *aboveip = *belowip = i;
281             *abovep = *belowp = 0;
282             return(i);
283         }
284         else if ( atx_value > value )
285         {
286             gap = (atx_value - value);
287             if ( above == 0 || gap < above )
288             {
289                 above = gap;
290                 abovei = i;
291             }
292         }
293         else
294         {
295             gap = (value - atx_value);
296             if ( below == 0 || gap < below )
297             {
298                 below = gap;
299                 belowi = i;
300             }
301         }
302         //printf("value %.8f gap %.8f abovei.%d %.8f belowi.%d %.8f\n",dstr(value),dstr(gap),abovei,dstr(above),belowi,dstr(below));
303     }
304     *aboveip = abovei;
305     *abovep = above;
306     *belowip = belowi;
307     *belowp = below;
308     //printf("above.%d below.%d\n",abovei,belowi);
309     if ( abovei >= 0 && belowi >= 0 )
310     {
311         if ( above < (below >> 1) )
312             return(abovei);
313         else return(belowi);
314     }
315     else if ( abovei >= 0 )
316         return(abovei);
317     else return(belowi);
318 }
319
320 int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs)
321 {
322     int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=1024; int64_t above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector<COutput> vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up;
323 #ifdef ENABLE_WALLET
324     const CKeyStore& keystore = *pwalletMain;
325     assert(pwalletMain != NULL);
326     LOCK2(cs_main, pwalletMain->cs_wallet);
327     pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
328     utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos));
329     BOOST_FOREACH(const COutput& out, vecOutputs)
330     {
331         if ( out.fSpendable != 0 )
332         {
333             txid = out.tx->GetHash();
334             vout = out.i;
335             if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && vout < tx.vout.size() && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() == 0 )
336             {
337                 if ( mtx.vin.size() > 0 )
338                 {
339                     for (i=0; i<mtx.vin.size(); i++)
340                         if ( txid == mtx.vin[i].prevout.hash && vout == mtx.vin[i].prevout.n )
341                             break;
342                     if ( i != mtx.vin.size() )
343                         continue;
344                 }
345                 if ( n > 0 )
346                 {
347                     for (i=0; i<n; i++)
348                         if ( txid == utxos[i].txid && vout == utxos[i].vout )
349                             break;
350                     if ( i != n )
351                         continue;
352                 }
353                 if ( myIsutxo_spentinmempool(txid,vout) == 0 )
354                 {
355                     up = &utxos[n++];
356                     up->txid = txid;
357                     up->nValue = out.tx->vout[out.i].nValue;
358                     up->vout = vout;
359                     //fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos);
360                     if ( n >= maxutxos )
361                         break;
362                 }
363             }
364         }
365     }
366     remains = total;
367     for (i=0; i<maxinputs && n>0; i++)
368     {
369         below = above = 0;
370         abovei = belowi = -1;
371         if ( CC_vinselect(&abovei,&above,&belowi,&below,utxos,n,remains) < 0 )
372         {
373             printf("error finding unspent i.%d of %d, %.8f vs %.8f\n",i,n,(double)remains/COIN,(double)total/COIN);
374             free(utxos);
375             return(0);
376         }
377         if ( belowi < 0 || abovei >= 0 )
378             ind = abovei;
379         else ind = belowi;
380         if ( ind < 0 )
381         {
382             printf("error finding unspent i.%d of %d, %.8f vs %.8f, abovei.%d belowi.%d ind.%d\n",i,n,(double)remains/COIN,(double)total/COIN,abovei,belowi,ind);
383             free(utxos);
384             return(0);
385         }
386         up = &utxos[ind];
387         mtx.vin.push_back(CTxIn(up->txid,up->vout,CScript()));
388         totalinputs += up->nValue;
389         remains -= up->nValue;
390         utxos[ind] = utxos[--n];
391         memset(&utxos[n],0,sizeof(utxos[n]));
392         //fprintf(stderr,"totalinputs %.8f vs total %.8f i.%d vs max.%d\n",(double)totalinputs/COIN,(double)total/COIN,i,maxinputs);
393         if ( totalinputs >= total || (i+1) >= maxinputs )
394             break;
395     }
396     free(utxos);
397     if ( totalinputs >= total )
398     {
399         //fprintf(stderr,"return totalinputs %.8f\n",(double)totalinputs/COIN);
400         return(totalinputs);
401     }
402 #endif
403     return(0);
404 }
This page took 0.047663 seconds and 4 git commands to generate.