Files
hush3/src/cc/CCtx.cpp
dimxy d1bd5b3b6c Squashed commit of the following:
commit 843168eddff34390f19fa661ac6315e1a51aafe2
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 14:34:03 2019 +0500

    logging improved for CCtokens.cpp

commit 43c5b3a5c4e36e76a235f987e07fe893d941d95e
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 14:23:41 2019 +0500

    more extra logging disabled for heir and token

commit a3f7ca963a0042237f4c97d6d89852646b541c6c
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 14:13:58 2019 +0500

    more extra logging disabled

commit f4dec8f8ad733c5a61dd0fc9f3decd103dd7a0c3
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 14:05:45 2019 +0500

    more extra logging disabled

commit eb9a41472004ccdacdacfc12b79880ac6da390ee
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 13:50:11 2019 +0500

    extra logging disabled in heir and tokens

commit 0fe01c8a7b52b03e0c0a3ba5d77f916862031d23
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 13:15:08 2019 +0500

    heir normal input validator changed to CNullValidator

commit 3b86e87c83b6993d5a3b4c056c10120223e8c9ed
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 12:58:03 2019 +0500

    enabled logiing in FinalizeCCtx

commit 2ea87c1b3c7967b316d22e2e65fc3c0203cc4b03
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 12:37:43 2019 +0500

    corrected parameters for tests

commit 216eb4ed84c6fd23e3fc22cd79509a09c8504c0c
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 12:22:30 2019 +0500

    changed to eval_assets for test

commit 2af850f06a4692200864a316208cdfc0709b1634
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 02:42:43 2019 +0500

    heiradd loggin vin

commit 28e033d2b2a1a01b2bc9c2d51a81b61ae53f3a29
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 02:04:33 2019 +0500

    logging added

commit ef1dbc504c5984a4997b5e06e736fa7b5b4e125d
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 01:29:46 2019 +0500

    logging added and corrected

commit 98c1e5a6896a97667c9d64f347c26b36c6a320a9
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 01:05:17 2019 +0500

    corrected isHeirSpendingBegan init in _UnmarshalOpret

commit 6006f073bfc136ed06c1636b3e6ffa7b403ce1d9
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 01:01:18 2019 +0500

    corrected dummyIsHeirSpendingBegan using

commit 9a95edf4e311a80538dd7b13aeeb201e97474ee8
Author: dimxy <dimxy@komodoplatform.com>
Date:   Wed Jan 9 00:53:50 2019 +0500

    isHeirSpendingBegan is put in opret

commit 4bd210709626e2f8b99889e50410eb0f75b3dbda
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 20:16:20 2019 +0500

    added logging to _FindLastextFundingTx for print C vouts

commit 3603b49c1143b1efe82dd545b9d7dca43f5bcec0
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 19:25:11 2019 +0500

    corrected isHeirSpendingBegun calc

commit e7d6923d4be080a5e98405634fafb175fa55f801
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 18:43:35 2019 +0500

    yet another cpToken correction in RunValidators

commit e425dcc4497652a062b45d4a5ce4c137bd2caa3d
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 18:22:08 2019 +0500

    changed cp param to cpTokens for heir tokens in validation

commit a4420f30d42d93dbc2729db4a5b2895d4b16d22b
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 17:11:10 2019 +0500

    corrected EVAL_HEIR in create opret

commit 788d75263fd5aaa7b66417441622c9bb6603ab81
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 16:41:07 2019 +0500

    corrected opret forming for 'F', tokens

commit 92bf6c53b36a5a4450b5c7079383792d634d61a7
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 16:12:09 2019 +0500

    _UnmarshalOpret corrected for non F

commit e4eb26e875d44f3e4c1d45aff6df8a7026b3329a
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 15:26:34 2019 +0500

    Revert "CCduration debug logging added"

    This reverts commit 5ffc2b0a8b49d387cd175754738d2c07701c7856.

commit ce97ac88af0b87b304ad1fc9cb29db0803d0bd42
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 15:17:10 2019 +0500

    changed pindex to pindexTip in CCduration for better reading

commit 5ffc2b0a8b49d387cd175754738d2c07701c7856
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 14:43:07 2019 +0500

    CCduration debug logging added

commit 34afdd16f0f6b5b97da864f082dcd019a7566da7
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 12:23:31 2019 +0500

    corrected again order to DecodeOpRet call in heir

commit bba6149969ea23aa4e3c6263a36bae0ba7fa6f5d
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 12:17:11 2019 +0500

    logging added in IsHeirFundingVout

commit 6c5d4b313ef3e54cb5eb2bf67b2fa78d9ffd0b04
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 12:02:15 2019 +0500

    logging added to Add1of2AddrInputs

commit 40d6d84971a8ed764523567f08df4c74fda4f12d
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 11:36:23 2019 +0500

    corrected vopretExtra getting for heir for coins

commit 36061d25fb8992551915afc3dd0600878a64c540
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 11:13:30 2019 +0500

    corrected CCinit C-param separate

commit 0a6710433868c315afe3f656c1bc5f5138fe5288
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 10:58:19 2019 +0500

    logging added in decodeheiropret

commit 2503d8cb59b94b024a9ded43a0602f89800a9549
Author: dimxy <dimxy@komodoplatform.com>
Date:   Tue Jan 8 10:39:21 2019 +0500

    corrected decode opret for heir for coins
2019-01-18 01:04:36 +05:00

581 lines
24 KiB
C++

/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#include "CCinclude.h"
#include "key_io.h"
/*
FinalizeCCTx is a very useful function that will properly sign both CC and normal inputs, adds normal change and the opreturn.
This allows the contract transaction functions to create the appropriate vins and vouts and have FinalizeCCTx create a properly signed transaction.
By using -addressindex=1, it allows tracking of all the CC addresses
*/
bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey)
{
#ifdef ENABLE_WALLET
CTransaction txNewConst(mtx); SignatureData sigdata; const CKeyStore& keystore = *pwalletMain;
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
if ( ProduceSignature(TransactionSignatureCreator(&keystore,&txNewConst,vini,utxovalue,SIGHASH_ALL),scriptPubKey,sigdata,consensusBranchId) != 0 )
{
UpdateTransaction(mtx,vini,sigdata);
return(true);
} else fprintf(stderr,"signing error for SignTx vini.%d %.8f\n",vini,(double)utxovalue/COIN);
#endif
return(false);
}
std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret)
{
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0;
int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=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, *othercond1of2=NULL, *cond;
CPubKey unspendablepk;
n = mtx.vout.size();
for (i=0; i<n; i++)
{
if ( mtx.vout[i].scriptPubKey.IsPayToCryptoCondition() == 0 )
normaloutputs += mtx.vout[i].nValue;
totaloutputs += mtx.vout[i].nValue;
}
if ( (n= mtx.vin.size()) > CC_MAXVINS )
{
fprintf(stderr,"FinalizeCCTx: %d is too many vins\n",n);
return("0");
}
Myprivkey(myprivkey);
unspendablepk = GetUnspendable(cp,unspendablepriv);
GetCCaddress(cp,myaddr,mypk);
mycond = MakeCCcond1(cp->evalcode,mypk);
GetCCaddress(cp,unspendable,unspendablepk);
othercond = MakeCCcond1(cp->evalcode,unspendablepk);
//Reorder vins so that for multiple normal vins all other except vin0 goes to the end
//This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation.
for (i=0; i<n; i++)
{
if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 )
{
if ( vintx.vout[mtx.vin[i].prevout.n].scriptPubKey.IsPayToCryptoCondition() == 0 && ccvins==0)
normalvins++;
else ccvins++;
}
}
if (normalvins>1 && ccvins)
{
for(i=1;i<normalvins;i++)
{
mtx.vin.push_back(mtx.vin[1]);
mtx.vin.erase(mtx.vin.begin() + 1);
}
}
memset(utxovalues,0,sizeof(utxovalues));
for (i=0; i<n; i++)
{
if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 )
{
utxovout = mtx.vin[i].prevout.n;
utxovalues[i] = vintx.vout[utxovout].nValue;
totalinputs += utxovalues[i];
if ( vintx.vout[utxovout].scriptPubKey.IsPayToCryptoCondition() == 0 )
{
//fprintf(stderr,"vin.%d is normal %.8f\n",i,(double)utxovalues[i]/COIN);
normalinputs += utxovalues[i];
vinimask |= (1LL << i);
}
else
{
mask |= (1LL << i);
}
} else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
}
nmask = (1LL << n) - 1;
if ( 0 && (mask & nmask) != (CCmask & nmask) )
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);
if ( totalinputs >= totaloutputs+2*txfee )
{
change = totalinputs - (totaloutputs+txfee);
mtx.vout.push_back(CTxOut(change,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
}
if ( opret.size() > 0 )
mtx.vout.push_back(CTxOut(0,opret));
PrecomputedTransactionData txdata(mtx);
n = mtx.vin.size();
for (i=0; i<n; i++)
{
if ( GetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock,false) != 0 )
{
utxovout = mtx.vin[i].prevout.n;
if ( vintx.vout[utxovout].scriptPubKey.IsPayToCryptoCondition() == 0 )
{
if ( SignTx(mtx,i,vintx.vout[utxovout].nValue,vintx.vout[utxovout].scriptPubKey) == 0 )
fprintf(stderr,"signing error for vini.%d of %llx\n",i,(long long)vinimask);
}
else
{
Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey);
//fprintf(stderr,"vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr);
if ( strcmp(destaddr,myaddr) == 0 )
{
privkey = myprivkey;
cond = mycond;
}
else if ( strcmp(destaddr,unspendable) == 0 )
{
privkey = unspendablepriv;
cond = othercond;
//fprintf(stderr,"unspendable CC addr.(%s)\n",unspendable);
}
// check if this is the 2nd additional evalcode + 'unspendable' cc addr:
else if ( strcmp(destaddr,cp->unspendableaddr2) == 0)
{
//fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2);
privkey = cp->unspendablepriv2;
if ( othercond2 == 0 ) //&& cp->evalcode != EVAL_CHANNELS && cp->evalcode != EVAL_HEIR && cp->evalcode != EVAL_ASSETS && cp->evalcode != EVAL_TOKENS)
othercond2 = MakeCCcond1(cp->evalcode2, cp->unspendablepk2);
//else if ( othercond2 == 0 && (cp->evalcode == EVAL_CHANNELS || cp->evalcode == EVAL_HEIR || cp->evalcode == EVAL_ASSETS || cp->evalcode == EVAL_TOKENS) )
// othercond2 = MakeCCcond1of2(cp->evalcode2,cp->unspendablepk2,cp->unspendablepk3);
cond = othercond2;
}
// check if this is 3rd additional evalcode + 'unspendable' cc addr:
else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 )
{
//fprintf(stderr,"matched %s unspendable3!\n",cp->unspendableaddr3);
privkey = cp->unspendablepriv3;
if ( othercond3 == 0 )
othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3);
cond = othercond3;
}
// check if this is spending from 1of2 cc addr:
else if (strcmp(cp->unspendable1of2addr, destaddr) == 0)
{
//fprintf(stderr,"matched %s unspendable1of2!\n",cp->unspendable1of2addr);
privkey = myprivkey;
if (othercond1of2 == 0)
othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->unspendable1of2pk[0], cp->unspendable1of2pk[1]);
cond = othercond1of2;
}
else
{
fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr);
return("");
}
uint256 sighash = SignatureHash(CCPubKey(cond), mtx, i, SIGHASH_ALL, utxovalues[i],consensusBranchId, &txdata);
if ( cc_signTreeSecp256k1Msg32(cond,privkey,sighash.begin()) != 0 )
{
//int32_t z;
//for (z=0; z<32; z++)
// fprintf(stderr,"%02x",((uint8_t *)sighash.begin())[z]);
//fprintf(stderr," sighash, ");
//for (z=0; z<32; z++)
// fprintf(stderr,"%02x",privkey[z]);
//fprintf(stderr," signed with privkey\n");
mtx.vin[i].scriptSig = CCSig(cond);
}
else
{
fprintf(stderr,"vini.%d has CC signing error address.(%s)\n",i,destaddr);
return("");
}
}
} else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
}
if ( mycond != 0 )
cc_free(mycond);
if ( othercond != 0 )
cc_free(othercond);
if ( othercond2 != 0 )
cc_free(othercond2);
if ( othercond3 != 0 )
cc_free(othercond3);
std::string strHex = EncodeHexTx(mtx);
if ( strHex.size() > 0 )
return(strHex);
else return("0");
}
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr)
{
int32_t type=0,i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
n = (int32_t)strlen(coinaddr);
addrstr.resize(n+1);
ptr = (char *)addrstr.data();
for (i=0; i<=n; i++)
ptr[i] = coinaddr[i];
CBitcoinAddress address(addrstr);
if ( address.GetIndexKey(hashBytes, type) == 0 )
return;
addresses.push_back(std::make_pair(hashBytes,type));
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++)
{
if ( GetAddressUnspent((*it).first, (*it).second, unspentOutputs) == 0 )
return;
}
}
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr)
{
int32_t type=0,i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
n = (int32_t)strlen(coinaddr);
addrstr.resize(n+1);
ptr = (char *)addrstr.data();
for (i=0; i<=n; i++)
ptr[i] = coinaddr[i];
CBitcoinAddress address(addrstr);
if ( address.GetIndexKey(hashBytes, type) == 0 )
return;
addresses.push_back(std::make_pair(hashBytes,type));
for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++)
{
if ( GetAddressIndex((*it).first, (*it).second, addressIndex) == 0 )
return;
}
}
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout)
{
uint256 txid; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if ( txid == utxotxid && utxovout == it->first.index )
return(it->second.satoshis);
}
return(0);
}
int32_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag)
{
CCoins coins;
if ( mempoolflag != 0 )
{
LOCK(mempool.cs);
CCoinsViewMemPool view(pcoinsTip, mempool);
if (!view.GetCoins(txid, coins))
return(-1);
if ( myIsutxo_spentinmempool(txid,vout) != 0 )
return(-1);
}
else
{
if (!pcoinsTip->GetCoins(txid, coins))
return(-1);
}
if ( vout < coins.vout.size() )
return(coins.vout[vout].nValue);
else return(-1);
}
int32_t CCgetspenttxid(uint256 &spenttxid,int32_t &vini,int32_t &height,uint256 txid,int32_t vout)
{
CSpentIndexKey key(txid, vout);
CSpentIndexValue value;
if ( !GetSpentIndex(key, value) )
return(-1);
spenttxid = value.txid;
vini = (int32_t)value.inputIndex;
height = value.blockHeight;
return(0);
}
int64_t CCaddress_balance(char *coinaddr)
{
int64_t sum = 0; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
sum += it->second.satoshis;
}
return(sum);
}
int64_t CCfullsupply(uint256 tokenid)
{
uint256 hashBlock; int32_t numvouts; CTransaction tx; std::vector<uint8_t> origpubkey; std::string name,description;
if ( GetTransaction(tokenid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if (DecodeTokenCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description))
{
return(tx.vout[0].nValue);
}
}
return(0);
}
int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
{
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock;
std::vector<uint8_t> vopretExtra;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
uint8_t evalCode;
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
char str[65]; fprintf(stderr,"check %s %.8f\n",uint256_str(str,txid),(double)it->second.satoshis/COIN);
std::vector<CPubKey> voutTokenPubkeys;
if ( DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, assetid, voutTokenPubkeys, vopretExtra) != 0 && assetid == tokenid )
{
sum += it->second.satoshis;
}
}
}
return(sum);
}
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)
{
int32_t i,abovei,belowi; int64_t above,below,gap,atx_value;
abovei = belowi = -1;
for (above=below=i=0; i<numunspents; i++)
{
// Filter to randomly pick utxo to avoid conflicts, and having multiple CC choose the same ones.
//if ( numunspents > 200 ) {
// if ( (rand() % 100) < 90 )
// continue;
//}
if ( (atx_value= utxos[i].nValue) <= 0 )
continue;
if ( atx_value == value )
{
*aboveip = *belowip = i;
*abovep = *belowp = 0;
return(i);
}
else if ( atx_value > value )
{
gap = (atx_value - value);
if ( above == 0 || gap < above )
{
above = gap;
abovei = i;
}
}
else
{
gap = (value - atx_value);
if ( below == 0 || gap < below )
{
below = gap;
belowi = i;
}
}
//printf("value %.8f gap %.8f abovei.%d %.8f belowi.%d %.8f\n",dstr(value),dstr(gap),abovei,dstr(above),belowi,dstr(below));
}
*aboveip = abovei;
*abovep = above;
*belowip = belowi;
*belowp = below;
//printf("above.%d below.%d\n",abovei,belowi);
if ( abovei >= 0 && belowi >= 0 )
{
if ( above < (below >> 1) )
return(abovei);
else return(belowi);
}
else if ( abovei >= 0 )
return(abovei);
else return(belowi);
}
int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs)
{
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=64; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector<COutput> vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up;
#ifdef ENABLE_WALLET
const CKeyStore& keystore = *pwalletMain;
assert(pwalletMain != NULL);
LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos));
threshold = total/(maxinputs+1);
if ( maxinputs > maxutxos )
maxutxos = maxinputs;
sum = 0;
BOOST_FOREACH(const COutput& out, vecOutputs)
{
if ( out.fSpendable != 0 && out.tx->vout[out.i].nValue >= threshold )
{
txid = out.tx->GetHash();
vout = out.i;
if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && vout < tx.vout.size() && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() == 0 )
{
//fprintf(stderr,"check %.8f to vins array.%d of %d %s/v%d\n",(double)out.tx->vout[out.i].nValue/COIN,n,maxutxos,txid.GetHex().c_str(),(int32_t)vout);
if ( mtx.vin.size() > 0 )
{
for (i=0; i<mtx.vin.size(); i++)
if ( txid == mtx.vin[i].prevout.hash && vout == mtx.vin[i].prevout.n )
break;
if ( i != mtx.vin.size() )
continue;
}
if ( n > 0 )
{
for (i=0; i<n; i++)
if ( txid == utxos[i].txid && vout == utxos[i].vout )
break;
if ( i != n )
continue;
}
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
{
up = &utxos[n++];
up->txid = txid;
up->nValue = out.tx->vout[out.i].nValue;
up->vout = vout;
sum += up->nValue;
//fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos);
if ( n >= maxutxos || sum >= total )
break;
}
}
}
}
remains = total;
for (i=0; i<maxinputs && n>0; i++)
{
below = above = 0;
abovei = belowi = -1;
if ( CC_vinselect(&abovei,&above,&belowi,&below,utxos,n,remains) < 0 )
{
printf("error finding unspent i.%d of %d, %.8f vs %.8f\n",i,n,(double)remains/COIN,(double)total/COIN);
free(utxos);
return(0);
}
if ( belowi < 0 || abovei >= 0 )
ind = abovei;
else ind = belowi;
if ( ind < 0 )
{
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);
free(utxos);
return(0);
}
up = &utxos[ind];
mtx.vin.push_back(CTxIn(up->txid,up->vout,CScript()));
totalinputs += up->nValue;
remains -= up->nValue;
utxos[ind] = utxos[--n];
memset(&utxos[n],0,sizeof(utxos[n]));
//fprintf(stderr,"totalinputs %.8f vs total %.8f i.%d vs max.%d\n",(double)totalinputs/COIN,(double)total/COIN,i,maxinputs);
if ( totalinputs >= total || (i+1) >= maxinputs )
break;
}
free(utxos);
if ( totalinputs >= total )
{
//fprintf(stderr,"return totalinputs %.8f\n",(double)totalinputs/COIN);
return(totalinputs);
}
#endif
return(0);
}
int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinputs)
{
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=64; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; char coinaddr[64]; uint256 txid,hashBlock; CTransaction tx; struct CC_utxo *utxos,*up;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos));
threshold = total/(maxinputs+1);
if ( maxinputs > maxutxos )
maxutxos = maxinputs;
sum = 0;
Getscriptaddress(coinaddr,CScript() << Mypubkey() << OP_CHECKSIG);
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( it->second.satoshis < threshold )
continue;
if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && vout < tx.vout.size() && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() == 0 )
{
//fprintf(stderr,"check %.8f to vins array.%d of %d %s/v%d\n",(double)out.tx->vout[out.i].nValue/COIN,n,maxutxos,txid.GetHex().c_str(),(int32_t)vout);
if ( mtx.vin.size() > 0 )
{
for (i=0; i<mtx.vin.size(); i++)
if ( txid == mtx.vin[i].prevout.hash && vout == mtx.vin[i].prevout.n )
break;
if ( i != mtx.vin.size() )
continue;
}
if ( n > 0 )
{
for (i=0; i<n; i++)
if ( txid == utxos[i].txid && vout == utxos[i].vout )
break;
if ( i != n )
continue;
}
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
{
up = &utxos[n++];
up->txid = txid;
up->nValue = it->second.satoshis;
up->vout = vout;
sum += up->nValue;
//fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos);
if ( n >= maxutxos || sum >= total )
break;
}
}
}
remains = total;
for (i=0; i<maxinputs && n>0; i++)
{
below = above = 0;
abovei = belowi = -1;
if ( CC_vinselect(&abovei,&above,&belowi,&below,utxos,n,remains) < 0 )
{
printf("error finding unspent i.%d of %d, %.8f vs %.8f\n",i,n,(double)remains/COIN,(double)total/COIN);
free(utxos);
return(0);
}
if ( belowi < 0 || abovei >= 0 )
ind = abovei;
else ind = belowi;
if ( ind < 0 )
{
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);
free(utxos);
return(0);
}
up = &utxos[ind];
mtx.vin.push_back(CTxIn(up->txid,up->vout,CScript()));
totalinputs += up->nValue;
remains -= up->nValue;
utxos[ind] = utxos[--n];
memset(&utxos[n],0,sizeof(utxos[n]));
//fprintf(stderr,"totalinputs %.8f vs total %.8f i.%d vs max.%d\n",(double)totalinputs/COIN,(double)total/COIN,i,maxinputs);
if ( totalinputs >= total || (i+1) >= maxinputs )
break;
}
free(utxos);
if ( totalinputs >= total )
{
//fprintf(stderr,"return totalinputs %.8f\n",(double)totalinputs/COIN);
return(totalinputs);
}
return(0);
}