Browse Source

Delete more CCs #381

duke
Duke 3 months ago
parent
commit
7bd7a716df
  1. 492
      src/cc/CCtx.cpp

492
src/cc/CCtx.cpp

@ -46,350 +46,14 @@ By using -addressindex=1, it allows tracking of all the CC addresses
*/
std::string FinalizeCCTx(uint64_t CCmask, struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey mypk, uint64_t txfee, CScript opret, std::vector<CPubKey> pubkeys)
{
UniValue sigData = FinalizeCCTxExt(false, CCmask, cp, mtx, mypk, txfee, opret, pubkeys);
return sigData[JSON_HEXTX].getValStr();
return std::string("");
}
// extended version that supports signInfo object with conds to vins map for remote cc calls
UniValue FinalizeCCTxExt(bool remote, uint64_t CCmask, struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey mypk, uint64_t txfee, CScript opret, std::vector<CPubKey> pubkeys)
{
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
CTransaction vintx; std::string hex; CPubKey globalpk; 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,flag,mgret,utxovout,n,err = 0;
char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64], unspendabletokensaddr[64],CC1of2CCaddr[64];
uint8_t *privkey = NULL, myprivkey[32] = { '\0' }, unspendablepriv[32] = { '\0' }, /*tokensunspendablepriv[32],*/ *msg32 = 0;
CC *mycond=0, *othercond=0, *othercond2=0,*othercond4=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond=0, *condCC2=0,*mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL;
CPubKey unspendablepk /*, tokensunspendablepk*/;
struct CCcontract_info *cpTokens, tokensC;
UniValue sigData(UniValue::VARR),result(UniValue::VOBJ);
const UniValue sigDataNull = NullUniValue;
globalpk = GetUnspendable(cp,0);
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);
result.push_back(Pair(JSON_HEXTX, "0"));
return result;
}
//Myprivkey(myprivkey); // for NSPV mode we need to add myprivkey for the explicitly defined mypk param
#ifdef ENABLE_WALLET
// get privkey for mypk
CKeyID keyID = mypk.GetID();
CKey vchSecret;
if (pwalletMain->GetKey(keyID, vchSecret))
memcpy(myprivkey, vchSecret.begin(), sizeof(myprivkey));
#endif
GetCCaddress(cp,myaddr,mypk);
mycond = MakeCCcond1(cp->evalcode,mypk);
// to spend from single-eval evalcode 'unspendable' cc addr
unspendablepk = GetUnspendable(cp, unspendablepriv);
GetCCaddress(cp, unspendable, unspendablepk);
othercond = MakeCCcond1(cp->evalcode, unspendablepk);
GetCCaddress1of2(cp,CC1of2CCaddr,unspendablepk,unspendablepk);
//fprintf(stderr,"evalcode.%d (%s)\n",cp->evalcode,unspendable);
// tokens support:
// to spend from dual/three-eval mypk vout
GetTokensCCaddress(cp, mytokensaddr, mypk);
// NOTE: if additionalEvalcode2 is not set it is a dual-eval (not three-eval) cc cond:
mytokenscond = MakeTokensCCcond1(cp->evalcode, cp->additionalTokensEvalcode2, mypk);
// to spend from single-eval EVAL_TOKENS mypk
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
GetCCaddress(cpTokens, mysingletokensaddr, mypk);
mysingletokenscond = MakeCCcond1(EVAL_TOKENS, mypk);
// to spend from dual/three-eval EVAL_TOKEN+evalcode 'unspendable' pk:
GetTokensCCaddress(cp, unspendabletokensaddr, unspendablepk); // it may be a three-eval cc, if cp->additionalEvalcode2 is set
othertokenscond = MakeTokensCCcond1(cp->evalcode, cp->additionalTokensEvalcode2, 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 (i==0 && mtx.vin[i].prevout.n==10e8)
continue;
if ( myGetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock) != 0 && mtx.vin[i].prevout.n < vintx.vout.size() )
{
if ( vintx.vout[mtx.vin[i].prevout.n].scriptPubKey.IsPayToCryptoCondition() == 0 && ccvins==0)
normalvins++;
else ccvins++;
}
else
{
fprintf(stderr,"vin.%d vout.%d is bigger than vintx.%d\n",i,mtx.vin[i].prevout.n,(int32_t)vintx.vout.size());
memset(myprivkey,0,32);
return UniValue(UniValue::VOBJ);
}
}
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 (i==0 && mtx.vin[i].prevout.n==10e8) continue;
if ( (mgret= myGetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock)) != 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 mgret.%d\n",mtx.vin[i].prevout.hash.ToString().c_str(),mgret);
}
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 (i==0 && mtx.vin[i].prevout.n==10e8)
continue;
if ( (mgret= myGetTransaction(mtx.vin[i].prevout.hash,vintx,hashBlock)) != 0 )
{
utxovout = mtx.vin[i].prevout.n;
if ( vintx.vout[utxovout].scriptPubKey.IsPayToCryptoCondition() == 0 )
{
if ( HUSH_NSPV_FULLNODE )
{
if (!remote)
{
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
{
// if no myprivkey for mypk it means remote call from nspv superlite client
// add sigData for superlite client
UniValue cc(UniValue::VNULL);
AddSigData2UniValue(sigData, i, cc, HexStr(vintx.vout[utxovout].scriptPubKey), vintx.vout[utxovout].nValue ); // store vin i with scriptPubKey
}
}
else
{
{
char addr[64];
Getscriptaddress(addr,vintx.vout[utxovout].scriptPubKey);
fprintf(stderr,"vout[%d] %.8f -> %s\n",utxovout,dstr(vintx.vout[utxovout].nValue),addr);
}
if ( NSPV_SignTx(mtx,i,vintx.vout[utxovout].nValue,vintx.vout[utxovout].scriptPubKey,0) == 0 )
fprintf(stderr,"NSPV signing error for vini.%d of %llx\n",i,(long long)vinimask);
}
}
else
{
Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey);
//fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s) vs %s\n",i,(double)utxovalues[i]/COIN,destaddr,mysingletokensaddr);
//std::cerr << "FinalizeCCtx() searching destaddr=" << destaddr << " for vin[" << i << "] satoshis=" << utxovalues[i] << std::endl;
if( strcmp(destaddr, myaddr) == 0 )
{
//fprintf(stderr, "FinalizeCCTx() matched cc myaddr (%s)\n", myaddr);
privkey = myprivkey;
cond = mycond;
}
else if (strcmp(destaddr, mytokensaddr) == 0) // if this is TokensCC1vout
{
privkey = myprivkey;
cond = mytokenscond;
//fprintf(stderr,"FinalizeCCTx() matched dual-eval TokensCC1vout my token addr.(%s)\n",mytokensaddr);
}
else if (strcmp(destaddr, mysingletokensaddr) == 0) // if this is TokensCC1vout
{
privkey = myprivkey;
cond = mysingletokenscond;
//fprintf(stderr, "FinalizeCCTx() matched single-eval token CC1vout my token addr.(%s)\n", mytokensaddr);
}
else if ( strcmp(destaddr,unspendable) == 0 )
{
privkey = unspendablepriv;
cond = othercond;
//fprintf(stderr,"FinalizeCCTx evalcode(%d) matched unspendable CC addr.(%s)\n",cp->evalcode,unspendable);
}
else if (strcmp(destaddr, unspendabletokensaddr) == 0)
{
privkey = unspendablepriv;
cond = othertokenscond;
//fprintf(stderr,"FinalizeCCTx() matched unspendabletokensaddr dual/three-eval CC addr.(%s)\n",unspendabletokensaddr);
}
// check if this is the 2nd additional evalcode + 'unspendable' cc addr:
else if ( strcmp(destaddr, cp->unspendableaddr2) == 0)
{
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable2!\n",cp->unspendableaddr2);
privkey = cp->unspendablepriv2;
if( othercond2 == 0 )
othercond2 = MakeCCcond1(cp->unspendableEvalcode2, cp->unspendablepk2);
cond = othercond2;
}
// check if this is 3rd additional evalcode + 'unspendable' cc addr:
else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 )
{
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable3!\n",cp->unspendableaddr3);
privkey = cp->unspendablepriv3;
if( othercond3 == 0 )
othercond3 = MakeCCcond1(cp->unspendableEvalcode3, cp->unspendablepk3);
cond = othercond3;
}
// check if this is spending from 1of2 cc coins addr:
else if (strcmp(cp->coins1of2addr, destaddr) == 0)
{
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable1of2!\n",cp->coins1of2addr);
privkey = cp->coins1of2priv;//myprivkey;
if (othercond1of2 == 0)
othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->coins1of2pk[0], cp->coins1of2pk[1]);
cond = othercond1of2;
}
else if ( strcmp(CC1of2CCaddr,destaddr) == 0 )
{
//fprintf(stderr,"FinalizeCCTx() matched %s CC1of2CCaddr!\n",CC1of2CCaddr);
privkey = unspendablepriv;
if (condCC2 == 0)
condCC2 = MakeCCcond1of2(cp->evalcode,unspendablepk,unspendablepk);
cond = condCC2;
}
// check if this is spending from 1of2 cc tokens addr:
else if (strcmp(cp->tokens1of2addr, destaddr) == 0)
{
//fprintf(stderr,"FinalizeCCTx() matched %s cp->tokens1of2addr!\n", cp->tokens1of2addr);
privkey = cp->tokens1of2priv;//myprivkey;
if (othercond1of2tokens == 0)
// NOTE: if additionalEvalcode2 is not set then it is dual-eval cc else three-eval cc
// TODO: verify evalcodes order if additionalEvalcode2 is not 0
othercond1of2tokens = MakeTokensCCcond1of2(cp->evalcode, cp->additionalTokensEvalcode2, cp->tokens1of2pk[0], cp->tokens1of2pk[1]);
cond = othercond1of2tokens;
}
else
{
flag = 0;
if ( pubkeys != NULL_pubkeys )
{
char coinaddr[64];
GetCCaddress1of2(cp,coinaddr,globalpk,pubkeys[i]);
//fprintf(stderr,"%s + %s -> %s vs %s\n",HexStr(globalpk).c_str(),HexStr(pubkeys[i]).c_str(),coinaddr,destaddr);
if ( strcmp(destaddr,coinaddr) == 0 )
{
privkey = cp->CCpriv;
if ( othercond4 != 0 )
cc_free(othercond4);
othercond4 = MakeCCcond1of2(cp->evalcode,globalpk,pubkeys[i]);
cond = othercond4;
flag = 1;
}
} //else privkey = myprivkey;
if ( flag == 0 )
{
fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr);
memset(myprivkey,0,32);
return sigDataNull;
}
}
uint256 sighash = SignatureHash(CCPubKey(cond), mtx, i, SIGHASH_ALL,utxovalues[i],consensusBranchId, &txdata);
if ( 0 )
{
int32_t z;
for (z=0; z<32; z++)
fprintf(stderr,"%02x",privkey[z]);
fprintf(stderr," privkey, ");
for (z=0; z<32; z++)
fprintf(stderr,"%02x",((uint8_t *)sighash.begin())[z]);
fprintf(stderr," sighash [%d] %.8f %x\n",i,(double)utxovalues[i]/COIN,consensusBranchId);
}
if (!remote) // we have privkey in the wallet
{
if (cc_signTreeSecp256k1Msg32(cond, privkey, sighash.begin()) != 0)
{
mtx.vin[i].scriptSig = CCSig(cond);
}
else
{
fprintf(stderr, "vini.%d has CC signing error address.(%s) %s\n", i, destaddr, EncodeHexTx(mtx).c_str());
memset(myprivkey, 0, sizeof(myprivkey));
return sigDataNull;
}
}
else // no privkey locally - remote call
{
// serialize cc:
UniValue ccjson;
ccjson.read(cc_conditionToJSONString(cond));
if (ccjson.empty())
{
fprintf(stderr, "vini.%d can't serialize CC.(%s) %s\n", i, destaddr, EncodeHexTx(mtx).c_str());
memset(myprivkey, 0, sizeof(myprivkey));
return sigDataNull;
}
AddSigData2UniValue(sigData, i, ccjson, std::string(), vintx.vout[utxovout].nValue); // store vin i with scriptPubKey
}
}
} else fprintf(stderr,"FinalizeCCTx2 couldnt find %s mgret.%d\n",mtx.vin[i].prevout.hash.ToString().c_str(),mgret);
}
if ( mycond != 0 )
cc_free(mycond);
if ( condCC2 != 0 )
cc_free(condCC2);
if ( othercond != 0 )
cc_free(othercond);
if ( othercond2 != 0 )
cc_free(othercond2);
if ( othercond3 != 0 )
cc_free(othercond3);
if ( othercond4 != 0 )
cc_free(othercond4);
if ( othercond1of2 != 0 )
cc_free(othercond1of2);
if ( othercond1of2tokens != 0 )
cc_free(othercond1of2tokens);
if ( mytokenscond != 0 )
cc_free(mytokenscond);
if ( mysingletokenscond != 0 )
cc_free(mysingletokenscond);
if ( othertokenscond != 0 )
cc_free(othertokenscond);
memset(myprivkey,0,sizeof(myprivkey));
std::string strHex = EncodeHexTx(mtx);
if ( strHex.size() > 0 )
result.push_back(Pair(JSON_HEXTX, strHex));
else {
result.push_back(Pair(JSON_HEXTX, "0"));
}
if (sigData.size() > 0) result.push_back(Pair(JSON_SIGDATA,sigData));
UniValue result(UniValue::VOBJ);
return result;
}
@ -399,187 +63,47 @@ void NSPV_CCtxids(std::vector<uint256> &txids,char *coinaddr,bool ccflag, uint8_
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr,bool ccflag)
{
int32_t type=0,i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
if ( HUSH_NSPV_SUPERLITE )
{
NSPV_CCunspents(unspentOutputs,coinaddr,ccflag);
return;
}
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, ccflag) == 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;
}
return;
}
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr,bool ccflag)
{
int32_t type=0,i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
if ( HUSH_NSPV_SUPERLITE )
{
NSPV_CCtxids(addressIndex,coinaddr,ccflag);
return;
}
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, ccflag) == 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;
}
return;
}
void SetCCtxids(std::vector<uint256> &txids,char *coinaddr,bool ccflag, uint8_t evalcode, uint256 filtertxid, uint8_t func)
{
int32_t type=0,i,n; char *ptr; std::string addrstr; uint160 hashBytes; std::vector<std::pair<uint160, int> > addresses;
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
if ( HUSH_NSPV_SUPERLITE )
{
NSPV_CCtxids(txids,coinaddr,ccflag,evalcode,filtertxid,func);
return;
}
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, ccflag) == 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;
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it1=addressIndex.begin(); it1!=addressIndex.end(); it1++)
{
if (it1->second>=0) txids.push_back(it1->first.txhash);
}
}
return;
}
int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout,int32_t CCflag)
{
uint256 txid; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr,CCflag!=0?true:false);
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);
}
int64_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag,int32_t lockflag)
{
CCoins coins;
//fprintf(stderr,"CCgettxoud %s/v%d\n",txid.GetHex().c_str(),vout);
if ( mempoolflag != 0 )
{
if ( lockflag != 0 )
{
LOCK(mempool.cs);
CCoinsViewMemPool view(pcoinsTip, mempool);
if (!view.GetCoins(txid, coins))
return(-1);
else if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) != 0 )
return(-1);
}
else
{
CCoinsViewMemPool view(pcoinsTip, mempool);
if (!view.GetCoins(txid, coins))
return(-1);
else if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,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);
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,int32_t CCflag)
{
int64_t sum = 0; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr,CCflag!=0?true:false);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
sum += it->second.satoshis;
}
return(sum);
return 0;
}
int64_t CCfullsupply(uint256 tokenid)
{
uint256 hashBlock; int32_t numvouts; CTransaction tx; std::vector<uint8_t> origpubkey; std::string name,description;
if ( myGetTransaction(tokenid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if (DecodeTokenCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description))
{
return(tx.vout[1].nValue);
}
}
return(0);
}
int64_t CCtoken_balance(char *coinaddr,uint256 reftokenid)
{
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 tokenid,txid,hashBlock;
std::vector<uint8_t> vopretExtra;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
uint8_t evalCode;
SetCCunspents(unspentOutputs,coinaddr,true);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts=tx.vout.size()) > 0 )
{
char str[65];
std::vector<CPubKey> voutTokenPubkeys;
std::vector<std::pair<uint8_t, vscript_t>> oprets;
if ( reftokenid==txid || (DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, tokenid, voutTokenPubkeys, oprets) != 0 && reftokenid == tokenid))
{
sum += it->second.satoshis;
}
}
}
return(sum);
return 0;
}
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)

Loading…
Cancel
Save