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"
20 FinalizeCCTx is a very useful function that will properly sign both CC and normal inputs, adds normal change and the opreturn.
22 This allows the contract transaction functions to create the appropriate vins and vouts and have FinalizeCCTx create a properly signed transaction.
24 By using -addressindex=1, it allows tracking of all the CC addresses
27 bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey)
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 )
34 UpdateTransaction(mtx,vini,sigdata);
36 } else fprintf(stderr,"signing error for SignTx vini.%d %.8f\n",vini,(double)utxovalue/COIN);
42 std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret)
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;
49 if ( mtx.vout[i].scriptPubKey.IsPayToCryptoCondition() == 0 )
50 normaloutputs += mtx.vout[i].nValue;
51 totaloutputs += mtx.vout[i].nValue;
53 if ( (n= mtx.vin.size()) > 64 )
55 fprintf(stderr,"FinalizeCCTx: %d is too many vins\n",n);
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));
68 if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 )
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 )
75 //fprintf(stderr,"vin.%d is normal %.8f\n",i,(double)utxovalues[i]/COIN);
76 normalinputs += utxovalues[i];
77 vinimask |= (1LL << i);
83 } else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
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 )
90 change = totalinputs - (totaloutputs+txfee);
91 mtx.vout.push_back(CTxOut(change,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
93 if ( opret.size() > 0 )
94 mtx.vout.push_back(CTxOut(0,opret));
95 PrecomputedTransactionData txdata(mtx);
99 if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 )
101 utxovout = mtx.vin[i].prevout.n;
102 if ( vintx.vout[utxovout].scriptPubKey.IsPayToCryptoCondition() == 0 )
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);
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 )
115 //fprintf(stderr,"my CC addr.(%s)\n",myaddr);
117 else if ( strcmp(destaddr,unspendable) == 0 )
119 privkey = unspendablepriv;
121 //fprintf(stderr,"unspendable CC addr.(%s)\n",unspendable);
123 else if ( strcmp(destaddr,cp->unspendableaddr2) == 0 )
125 //fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2);
126 privkey = cp->unspendablepriv2;
127 if ( othercond2 == 0 )
128 othercond2 = MakeCCcond1(cp->evalcode2,cp->unspendablepk2);
131 else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 )
133 //fprintf(stderr,"matched %s unspendable3!\n",cp->unspendableaddr3);
134 privkey = cp->unspendablepriv3;
135 if ( othercond3 == 0 )
136 othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3);
141 fprintf(stderr,"vini.%d has unknown CC address.(%s)\n",i,destaddr);
144 uint256 sighash = SignatureHash(CCPubKey(cond), mtx, i, SIGHASH_ALL, utxovalues[i],consensusBranchId, &txdata);
145 if ( cc_signTreeSecp256k1Msg32(cond,privkey,sighash.begin()) != 0 )
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);
158 fprintf(stderr,"vini.%d has CC signing error address.(%s)\n",i,destaddr);
161 } else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
165 if ( othercond != 0 )
167 if ( othercond2 != 0 )
169 if ( othercond3 != 0 )
171 std::string strHex = EncodeHexTx(mtx);
172 if ( strHex.size() > 0 )
177 void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr)
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);
182 ptr = (char *)addrstr.data();
184 ptr[i] = coinaddr[i];
185 CBitcoinAddress address(addrstr);
186 if ( address.GetIndexKey(hashBytes, type) == 0 )
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++)
191 if ( GetAddressUnspent((*it).first, (*it).second, unspentOutputs) == 0 )
196 void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr)
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);
201 ptr = (char *)addrstr.data();
203 ptr[i] = coinaddr[i];
204 CBitcoinAddress address(addrstr);
205 if ( address.GetIndexKey(hashBytes, type) == 0 )
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++)
210 if ( GetAddressIndex((*it).first, (*it).second, addressIndex) == 0 )
215 int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout)
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++)
221 txid = it->first.txhash;
222 if ( txid == utxotxid && utxovout == it->first.index )
223 return(it->second.satoshis);
228 int64_t CCaddress_balance(char *coinaddr)
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++)
234 sum += it->second.satoshis;
239 int64_t CCfullsupply(uint256 tokenid)
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 )
244 if ( DecodeAssetCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description) > 0 )
246 return(tx.vout[0].nValue);
252 int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
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++)
258 txid = it->first.txhash;
259 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
261 if ( DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,assetid2,price,origpubkey) != 0 && assetid == tokenid )
263 sum += it->second.satoshis;
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)
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++)
276 if ( (atx_value= utxos[i].nValue) <= 0 )
278 if ( atx_value == value )
280 *aboveip = *belowip = i;
281 *abovep = *belowp = 0;
284 else if ( atx_value > value )
286 gap = (atx_value - value);
287 if ( above == 0 || gap < above )
295 gap = (value - atx_value);
296 if ( below == 0 || gap < below )
302 //printf("value %.8f gap %.8f abovei.%d %.8f belowi.%d %.8f\n",dstr(value),dstr(gap),abovei,dstr(above),belowi,dstr(below));
308 //printf("above.%d below.%d\n",abovei,belowi);
309 if ( abovei >= 0 && belowi >= 0 )
311 if ( above < (below >> 1) )
315 else if ( abovei >= 0 )
320 int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs)
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;
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)
331 if ( out.fSpendable != 0 )
333 txid = out.tx->GetHash();
335 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && vout < tx.vout.size() && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() == 0 )
337 if ( mtx.vin.size() > 0 )
339 for (i=0; i<mtx.vin.size(); i++)
340 if ( txid == mtx.vin[i].prevout.hash && vout == mtx.vin[i].prevout.n )
342 if ( i != mtx.vin.size() )
348 if ( txid == utxos[i].txid && vout == utxos[i].vout )
353 if ( myIsutxo_spentinmempool(txid,vout) == 0 )
357 up->nValue = out.tx->vout[out.i].nValue;
359 //fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos);
367 for (i=0; i<maxinputs && n>0; i++)
370 abovei = belowi = -1;
371 if ( CC_vinselect(&abovei,&above,&belowi,&below,utxos,n,remains) < 0 )
373 printf("error finding unspent i.%d of %d, %.8f vs %.8f\n",i,n,(double)remains/COIN,(double)total/COIN);
377 if ( belowi < 0 || abovei >= 0 )
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);
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 )
397 if ( totalinputs >= total )
399 //fprintf(stderr,"return totalinputs %.8f\n",(double)totalinputs/COIN);