test git diff
This commit is contained in:
@@ -25,7 +25,8 @@
|
||||
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
|
||||
int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp);
|
||||
unsigned int lwmaGetNextPOSRequired(const CBlockIndex* pindexLast, const Consensus::Params& params);
|
||||
|
||||
bool EnsureWalletIsAvailable(bool avoidException);
|
||||
extern bool fRequestShutdown;
|
||||
//#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
|
||||
|
||||
struct MemoryStruct { char *memory; size_t size; };
|
||||
@@ -610,6 +611,28 @@ uint32_t komodo_txtime2(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
|
||||
return(txtime);
|
||||
}
|
||||
|
||||
int32_t komodo_WhoStaked(CBlock *pblock, CTxDestination &addressout)
|
||||
{
|
||||
int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid;
|
||||
if ( (n= pblock->vtx.size()) > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1 )
|
||||
{
|
||||
txid = pblock->vtx[n-1].vin[0].prevout.hash;
|
||||
vout = pblock->vtx[n-1].vin[0].prevout.n;
|
||||
txtime = komodo_txtime(&value,txid,vout,destaddr);
|
||||
if ( ExtractDestination(pblock->vtx[n-1].vout[0].scriptPubKey,voutaddress) )
|
||||
{
|
||||
strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
|
||||
if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[n-1].vout[0].nValue == value )
|
||||
{
|
||||
//fprintf(stderr,"is PoS block!\n");
|
||||
addressout = voutaddress;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t komodo_isPoS(CBlock *pblock)
|
||||
{
|
||||
int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid;
|
||||
@@ -1439,7 +1462,7 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_
|
||||
if ( slowflag != 0 && pindex != 0 )
|
||||
{
|
||||
pindex->segid = -1;
|
||||
fprintf(stderr,"PoW block detected set segid.%d <- %d\n",height,pindex->segid);
|
||||
//fprintf(stderr,"PoW block detected set segid.%d <- %d\n",height,pindex->segid);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1447,11 +1470,17 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_
|
||||
isPoS = 2; // 2 means staking utxo validated
|
||||
if ( slowflag != 0 && height > 100 )
|
||||
{
|
||||
segid = -3;
|
||||
if ( pindex != 0 && pindex->segid == -2 && (segid= komodo_segid(1,height)) >= 0 )
|
||||
CTxDestination voutaddress; char voutaddr[64];
|
||||
if ( ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
|
||||
{
|
||||
strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
|
||||
segid = komodo_segid32(voutaddr) & 0x3f;
|
||||
//fprintf(stderr,"komodo_segid.(%d) -> %d\n",height,segid);
|
||||
}
|
||||
if ( pindex != 0 && segid >= 0 )
|
||||
{
|
||||
pindex->segid = segid;
|
||||
fprintf(stderr,"B set segid.%d <- %d\n",height,pindex->segid);
|
||||
//fprintf(stderr,"B set segid.%d <- %d\n",height,pindex->segid);
|
||||
} //else fprintf(stderr,"unexpected null pindex for slowflag set ht.%d segid.%d:%d\n",height,pindex!=0?pindex->segid:-3,segid);
|
||||
}
|
||||
}
|
||||
@@ -1937,3 +1966,258 @@ int64_t komodo_coinsupply(int64_t *zfundsp,int64_t *sproutfundsp,int32_t height)
|
||||
*sproutfundsp = sproutfunds;
|
||||
return(supply);
|
||||
}
|
||||
struct komodo_staking
|
||||
{
|
||||
char address[64];
|
||||
uint256 txid;
|
||||
arith_uint256 hashval;
|
||||
uint64_t nValue;
|
||||
uint32_t segid32,txtime;
|
||||
int32_t vout;
|
||||
CScript scriptPubKey;
|
||||
};
|
||||
|
||||
struct komodo_staking *komodo_addutxo(struct komodo_staking *array,int32_t *numkp,int32_t *maxkp,uint32_t txtime,uint64_t nValue,uint256 txid,int32_t vout,char *address,uint8_t *hashbuf,CScript pk)
|
||||
{
|
||||
uint256 hash; uint32_t segid32; struct komodo_staking *kp;
|
||||
segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
|
||||
if ( *numkp >= *maxkp )
|
||||
{
|
||||
*maxkp += 1000;
|
||||
array = (struct komodo_staking *)realloc(array,sizeof(*array) * (*maxkp));
|
||||
//fprintf(stderr,"realloc max.%d array.%p\n",*maxkp,array);
|
||||
}
|
||||
kp = &array[(*numkp)++];
|
||||
//fprintf(stderr,"kp.%p num.%d\n",kp,*numkp);
|
||||
memset(kp,0,sizeof(*kp));
|
||||
strcpy(kp->address,address);
|
||||
kp->txid = txid;
|
||||
kp->vout = vout;
|
||||
kp->hashval = UintToArith256(hash);
|
||||
kp->txtime = txtime;
|
||||
kp->segid32 = segid32;
|
||||
kp->nValue = nValue;
|
||||
kp->scriptPubKey = pk;
|
||||
return(array);
|
||||
}
|
||||
|
||||
arith_uint256 _komodo_eligible(struct komodo_staking *kp,arith_uint256 ratio,uint32_t blocktime,int32_t iter,int32_t minage,int32_t segid,int32_t nHeight,uint32_t prevtime)
|
||||
{
|
||||
int32_t diff; uint64_t coinage; arith_uint256 coinage256,hashval;
|
||||
diff = (iter + blocktime - kp->txtime - minage);
|
||||
if ( diff < 0 )
|
||||
diff = 60;
|
||||
else if ( diff > 3600*24*30 )
|
||||
diff = 3600*24*30;
|
||||
if ( iter > 0 )
|
||||
diff += segid*2;
|
||||
coinage = ((uint64_t)kp->nValue * diff);
|
||||
if ( blocktime+iter+segid*2 > prevtime+480 )
|
||||
coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
|
||||
coinage256 = arith_uint256(coinage+1);
|
||||
hashval = ratio * (kp->hashval / coinage256);
|
||||
return(hashval);
|
||||
}
|
||||
|
||||
uint32_t komodo_eligible(arith_uint256 bnTarget,arith_uint256 ratio,struct komodo_staking *kp,int32_t nHeight,uint32_t blocktime,uint32_t prevtime,int32_t minage,uint8_t *hashbuf)
|
||||
{
|
||||
int32_t maxiters = 600; uint256 hash;
|
||||
int32_t segid,iter,diff; uint64_t coinage; arith_uint256 hashval,coinage256;
|
||||
komodo_stakehash(&hash,kp->address,hashbuf,kp->txid,kp->vout);
|
||||
kp->hashval = UintToArith256(hash);
|
||||
segid = ((nHeight + kp->segid32) & 0x3f);
|
||||
hashval = _komodo_eligible(kp,ratio,blocktime,maxiters,minage,segid,nHeight,prevtime);
|
||||
//for (int i=32; i>=0; i--)
|
||||
// fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
|
||||
//fprintf(stderr," b.%u minage.%d segid.%d ht.%d prev.%u\n",blocktime,minage,segid,nHeight,prevtime);
|
||||
if ( hashval <= bnTarget )
|
||||
{
|
||||
for (iter=0; iter<maxiters; iter++)
|
||||
{
|
||||
if ( blocktime+iter+segid*2 < kp->txtime+minage )
|
||||
continue;
|
||||
hashval = _komodo_eligible(kp,ratio,blocktime,iter,minage,segid,nHeight,prevtime);
|
||||
if ( hashval <= bnTarget )
|
||||
{
|
||||
//fprintf(stderr,"winner %.8f blocktime.%u iter.%d segid.%d\n",(double)kp->nValue/COIN,blocktime,iter,segid);
|
||||
blocktime += iter;
|
||||
blocktime += segid * 2;
|
||||
return(blocktime);
|
||||
}
|
||||
}
|
||||
} else fprintf(stderr,"maxiters is not good enough\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig)
|
||||
{
|
||||
static struct komodo_staking *array; static int32_t numkp,maxkp; static uint32_t lasttime;
|
||||
set<CBitcoinAddress> setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector<COutput> vecOutputs; uint32_t block_from_future_rejecttime,besttime,eligible,eligible2,earliest = 0; CScript best_scriptPubKey; arith_uint256 mindiff,ratio,bnTarget; CBlockIndex *tipindex,*pindex; CTxDestination address; bool fNegative,fOverflow; uint8_t hashbuf[256]; CTransaction tx; uint256 hashBlock;
|
||||
if (!EnsureWalletIsAvailable(0))
|
||||
return 0;
|
||||
|
||||
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
|
||||
mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
|
||||
ratio = (mindiff / bnTarget);
|
||||
assert(pwalletMain != NULL);
|
||||
*utxovaluep = 0;
|
||||
memset(utxotxidp,0,sizeof(*utxotxidp));
|
||||
memset(utxovoutp,0,sizeof(*utxovoutp));
|
||||
memset(utxosig,0,72);
|
||||
if ( (tipindex= chainActive.Tip()) == 0 )
|
||||
return(0);
|
||||
nHeight = tipindex->GetHeight() + 1;
|
||||
if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
|
||||
minage = 6000;
|
||||
komodo_segids(hashbuf,nHeight-101,100);
|
||||
if ( *blocktimep < tipindex->nTime+60 )
|
||||
*blocktimep = tipindex->nTime+60;
|
||||
//fprintf(stderr,"Start scan of utxo for staking %u ht.%d\n",(uint32_t)time(NULL),nHeight);
|
||||
|
||||
bool resetstaker = false;
|
||||
if ( array != 0 )
|
||||
{
|
||||
CBlockIndex* pblockindex = chainActive[tipindex->GetHeight()];
|
||||
CBlock block; CTxDestination addressout;
|
||||
if( ReadBlockFromDisk(block, pblockindex, 1) && komodo_WhoStaked(&block, addressout) != 0 && IsMine(*pwalletMain,addressout) != 0 )
|
||||
{
|
||||
resetstaker = true;
|
||||
fprintf(stderr, "Reset ram staker after mining a block!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if ( time(NULL) > lasttime+600 || array == 0 || resetstaker )
|
||||
{
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
|
||||
if ( array != 0 )
|
||||
{
|
||||
free(array);
|
||||
array = 0;
|
||||
maxkp = numkp = 0;
|
||||
lasttime = 0;
|
||||
}
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs)
|
||||
{
|
||||
if ( (tipindex= chainActive.Tip()) == 0 || tipindex->GetHeight()+1 > nHeight )
|
||||
{
|
||||
fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
|
||||
return(0);
|
||||
}
|
||||
counter++;
|
||||
if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
|
||||
{
|
||||
fprintf(stderr,"komodo_staked invalid depth %d\n",(int32_t)out.nDepth);
|
||||
continue;
|
||||
}
|
||||
CAmount nValue = out.tx->vout[out.i].nValue;
|
||||
if ( nValue < COIN || !out.fSpendable )
|
||||
continue;
|
||||
const CScript& pk = out.tx->vout[out.i].scriptPubKey;
|
||||
if ( ExtractDestination(pk,address) != 0 )
|
||||
{
|
||||
if ( IsMine(*pwalletMain,address) == 0 )
|
||||
continue;
|
||||
if ( GetTransaction(out.tx->GetHash(),tx,hashBlock,true) != 0 && (pindex= komodo_getblockindex(hashBlock)) != 0 )
|
||||
{
|
||||
array = komodo_addutxo(array,&numkp,&maxkp,(uint32_t)pindex->nTime,(uint64_t)nValue,out.tx->GetHash(),out.i,(char *)CBitcoinAddress(address).ToString().c_str(),hashbuf,(CScript)pk);
|
||||
//fprintf(stderr,"addutxo numkp.%d vs max.%d\n",numkp,maxkp);
|
||||
}
|
||||
}
|
||||
}
|
||||
lasttime = (uint32_t)time(NULL);
|
||||
//fprintf(stderr,"finished kp data of utxo for staking %u ht.%d numkp.%d maxkp.%d\n",(uint32_t)time(NULL),nHeight,numkp,maxkp);
|
||||
}
|
||||
//fprintf(stderr,"numkp.%d blocktime.%u\n",numkp,*blocktimep);
|
||||
block_from_future_rejecttime = (uint32_t)GetAdjustedTime() + 57;
|
||||
for (i=winners=0; i<numkp; i++)
|
||||
{
|
||||
if (fRequestShutdown)
|
||||
break;
|
||||
if ( (tipindex= chainActive.Tip()) == 0 || tipindex->GetHeight()+1 > nHeight )
|
||||
{
|
||||
fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
|
||||
return(0);
|
||||
}
|
||||
kp = &array[i];
|
||||
if ( (eligible2= komodo_eligible(bnTarget,ratio,kp,nHeight,*blocktimep,(uint32_t)tipindex->nTime+27,minage,hashbuf)) == 0 )
|
||||
continue;
|
||||
eligible = komodo_stake(0,bnTarget,nHeight,kp->txid,kp->vout,0,(uint32_t)tipindex->nTime+27,kp->address);
|
||||
//fprintf(stderr,"i.%d %u vs %u\n",i,eligible2,eligible);
|
||||
if ( eligible > 0 )
|
||||
{
|
||||
besttime = m = 0;
|
||||
if ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
|
||||
{
|
||||
while ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
|
||||
{
|
||||
besttime = eligible;
|
||||
eligible--;
|
||||
if ( eligible < block_from_future_rejecttime ) // nothing gained by going earlier
|
||||
break;
|
||||
m++;
|
||||
//fprintf(stderr,"m.%d ht.%d validated winning blocktime %u -> %.8f eligible.%u test prior\n",m,nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"ht.%d error validating winning blocktime %u -> %.8f eligible.%u test prior\n",nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
|
||||
continue;
|
||||
}
|
||||
eligible = besttime;
|
||||
winners++;
|
||||
//fprintf(stderr,"ht.%d validated winning [%d] -> %.8f eligible.%u test prior\n",nHeight,(int32_t)(eligible - tipindex->nTime),(double)kp->nValue/COIN,eligible);
|
||||
if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || kp->nValue < *utxovaluep)) )
|
||||
{
|
||||
earliest = eligible;
|
||||
best_scriptPubKey = kp->scriptPubKey; //out.tx->vout[out.i].scriptPubKey;
|
||||
*utxovaluep = (uint64_t)kp->nValue;
|
||||
//decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str());
|
||||
decode_hex((uint8_t *)utxotxidp,32,(char *)kp->txid.GetHex().c_str());
|
||||
*utxovoutp = kp->vout;
|
||||
*txtimep = kp->txtime;//(uint32_t)out.tx->nLockTime;
|
||||
fprintf(stderr,"ht.%d earliest.%u [%d].%d (%s) nValue %.8f locktime.%u counter.%d winners.%d\n",nHeight,earliest,(int32_t)(earliest - tipindex->nTime),m,kp->address,(double)kp->nValue/COIN,*txtimep,counter,winners);
|
||||
}
|
||||
} //else fprintf(stderr,"utxo not eligible\n");
|
||||
}
|
||||
if ( numkp < 1000 && array != 0 )
|
||||
{
|
||||
free(array);
|
||||
array = 0;
|
||||
maxkp = numkp = 0;
|
||||
lasttime = 0;
|
||||
}
|
||||
if ( earliest != 0 )
|
||||
{
|
||||
bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid;
|
||||
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
txNew.vin.resize(1);
|
||||
txNew.vout.resize(1);
|
||||
txfee = 0;
|
||||
for (i=0; i<32; i++)
|
||||
((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i];
|
||||
txNew.vin[0].prevout.hash = revtxid;
|
||||
txNew.vin[0].prevout.n = *utxovoutp;
|
||||
txNew.vout[0].scriptPubKey = best_scriptPubKey;// CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
|
||||
txNew.vout[0].nValue = *utxovaluep - txfee;
|
||||
txNew.nLockTime = earliest;
|
||||
CTransaction txNewConst(txNew);
|
||||
signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
|
||||
if (!signSuccess)
|
||||
fprintf(stderr,"failed to create signature\n");
|
||||
else
|
||||
{
|
||||
UpdateTransaction(txNew,0,sigdata);
|
||||
ptr = (uint8_t *)&sigdata.scriptSig[0];
|
||||
siglen = sigdata.scriptSig.size();
|
||||
for (i=0; i<siglen; i++)
|
||||
utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
|
||||
//fprintf(stderr," siglen.%d\n",siglen);
|
||||
//fprintf(stderr,"best %u from %u, gap %d lag.%d\n",earliest,*blocktimep,(int32_t)(earliest - *blocktimep),(int32_t)(time(NULL) - *blocktimep));
|
||||
*blocktimep = earliest;
|
||||
}
|
||||
} //else fprintf(stderr,"no earliest utxo for staking\n");
|
||||
//fprintf(stderr,"end scan of utxo for staking t.%u counter.%d numkp.%d winners.%d\n",(uint32_t)time(NULL),counter,numkp,winners);
|
||||
return(siglen);
|
||||
}
|
||||
|
||||
51
src/main.cpp
51
src/main.cpp
@@ -1610,6 +1610,15 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
if ( nextBlockHeight <= 1 || chainActive.LastTip() == 0 )
|
||||
tiptime = (uint32_t)time(NULL);
|
||||
else tiptime = (uint32_t)chainActive.LastTip()->nTime;
|
||||
|
||||
// is it already in the memory pool?
|
||||
uint256 hash = tx.GetHash();
|
||||
if (pool.exists(hash))
|
||||
{
|
||||
//fprintf(stderr,"already in mempool\n");
|
||||
return state.Invalid(false, REJECT_DUPLICATE, "already in mempool");
|
||||
}
|
||||
|
||||
// Node operator can choose to reject tx by number of transparent inputs
|
||||
static_assert(std::numeric_limits<size_t>::max() >= std::numeric_limits<int64_t>::max(), "size_t too small");
|
||||
size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0);
|
||||
@@ -1648,7 +1657,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
}
|
||||
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
|
||||
string reason;
|
||||
if (Params().RequireStandard() && !IsStandardTx(tx, reason, nextBlockHeight))
|
||||
if (!fSkipExpiry && Params().RequireStandard() && !IsStandardTx(tx, reason, nextBlockHeight))
|
||||
{
|
||||
//
|
||||
//fprintf(stderr,"AcceptToMemoryPool reject nonstandard transaction: %s\nscriptPubKey: %s\n",reason.c_str(),tx.vout[0].scriptPubKey.ToString().c_str());
|
||||
@@ -1657,21 +1666,14 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
// Only accept nLockTime-using transactions that can be mined in the next
|
||||
// block; we don't want our mempool filled up with transactions that can't
|
||||
// be mined yet.
|
||||
if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
|
||||
if (!fSkipExpiry && !CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
|
||||
{
|
||||
//fprintf(stderr,"AcceptToMemoryPool reject non-final\n");
|
||||
return state.DoS(0, false, REJECT_NONSTANDARD, "non-final");
|
||||
}
|
||||
|
||||
// is it already in the memory pool?
|
||||
uint256 hash = tx.GetHash();
|
||||
if (pool.exists(hash))
|
||||
{
|
||||
//fprintf(stderr,"already in mempool\n");
|
||||
return state.Invalid(false, REJECT_DUPLICATE, "already in mempool");
|
||||
}
|
||||
|
||||
// Check for conflicts with in-memory transactions
|
||||
if (!fSkipExpiry)
|
||||
{
|
||||
LOCK(pool.cs); // protect pool.mapNextTx
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
@@ -1721,7 +1723,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
if (ExistsImportTombstone(tx, view))
|
||||
return state.Invalid(false, REJECT_DUPLICATE, "import tombstone exists");
|
||||
}
|
||||
else
|
||||
else if (!fSkipExpiry)
|
||||
{
|
||||
// do all inputs exist?
|
||||
// Note that this does not check for the presence of actual outputs (see the next check for that),
|
||||
@@ -1733,10 +1735,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
if (pfMissingInputs)
|
||||
*pfMissingInputs = true;
|
||||
//fprintf(stderr,"missing inputs\n");
|
||||
if (!fSkipExpiry)
|
||||
return state.DoS(0, error("AcceptToMemoryPool: tx inputs not found"),REJECT_INVALID, "bad-txns-inputs-missing");
|
||||
else
|
||||
return(false);
|
||||
return state.DoS(0, error("AcceptToMemoryPool: tx inputs not found"),REJECT_INVALID, "bad-txns-inputs-missing");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1744,10 +1743,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
if (!view.HaveInputs(tx))
|
||||
{
|
||||
//fprintf(stderr,"accept failure.1\n");
|
||||
if (!fSkipExpiry)
|
||||
return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),REJECT_DUPLICATE, "bad-txns-inputs-spent");
|
||||
else
|
||||
return(false);
|
||||
return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),REJECT_DUPLICATE, "bad-txns-inputs-spent");
|
||||
}
|
||||
}
|
||||
// are the joinsplit's requirements met?
|
||||
@@ -1756,6 +1752,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
//fprintf(stderr,"accept failure.2\n");
|
||||
return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"),REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met");
|
||||
}
|
||||
|
||||
// Bring the best block into scope
|
||||
view.GetBestBlock();
|
||||
|
||||
@@ -1790,7 +1787,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
// Keep track of transactions that spend a coinbase, which we re-scan
|
||||
// during reorgs to ensure COINBASE_MATURITY is still met.
|
||||
bool fSpendsCoinbase = false;
|
||||
if (!tx.IsCoinImport()) {
|
||||
if (!fSkipExpiry && !tx.IsCoinImport()) {
|
||||
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
|
||||
const CCoins *coins = view.AccessCoins(txin.prevout.hash);
|
||||
if (coins->IsCoinBase()) {
|
||||
@@ -1865,7 +1862,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
// Check against previous transactions
|
||||
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
|
||||
if (!fSkipExpiry && !ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
|
||||
{
|
||||
//fprintf(stderr,"accept failure.9\n");
|
||||
return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString());
|
||||
@@ -1886,7 +1883,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
flag = 1;
|
||||
KOMODO_CONNECTING = (1<<30) + (int32_t)chainActive.LastTip()->GetHeight() + 1;
|
||||
}
|
||||
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
|
||||
if (!fSkipExpiry && !ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
|
||||
{
|
||||
if ( flag != 0 )
|
||||
KOMODO_CONNECTING = -1;
|
||||
@@ -1896,8 +1893,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
KOMODO_CONNECTING = -1;
|
||||
|
||||
// Store transaction in memory
|
||||
if ( komodo_is_notarytx(tx) == 0 )
|
||||
KOMODO_ON_DEMAND++;
|
||||
pool.addUnchecked(hash, entry, !IsInitialBlockDownload());
|
||||
|
||||
if (!tx.IsCoinImport())
|
||||
@@ -4680,12 +4675,15 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
|
||||
// Check transactions
|
||||
CTransaction sTx;
|
||||
CTransaction *ptx = NULL;
|
||||
if ( ASSETCHAINS_CC != 0 && !fCheckPOW )
|
||||
return true;
|
||||
|
||||
if ( ASSETCHAINS_CC != 0 ) // CC contracts might refer to transactions in the current block, from a CC spend within the same block and out of order
|
||||
{
|
||||
int32_t i,j,rejects=0,lastrejects=0;
|
||||
//fprintf(stderr,"put block's tx into mempool\n");
|
||||
// Copy all non Z-txs in mempool to temporary mempool because there can be tx in local mempool that make the block invalid.
|
||||
LOCK2(cs_main,mempool.cs);
|
||||
LOCK(mempool.cs);
|
||||
//fprintf(stderr, "starting... mempoolsize.%ld\n",mempool.size());
|
||||
list<CTransaction> transactionsToRemove;
|
||||
BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx) {
|
||||
@@ -6977,6 +6975,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
|
||||
else if (strCommand == "tx")
|
||||
{
|
||||
if (IsInitialBlockDownload())
|
||||
return true;
|
||||
|
||||
vector<uint256> vWorkQueue;
|
||||
vector<uint256> vEraseQueue;
|
||||
CTransaction tx;
|
||||
|
||||
488
src/miner.cpp
488
src/miner.cpp
@@ -199,261 +199,266 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
|
||||
boost::optional<CTransaction> cheatSpend;
|
||||
uint256 cbHash;
|
||||
|
||||
CBlockIndex* pindexPrev = 0;
|
||||
SaplingMerkleTree sapling_tree; uint64_t commission;
|
||||
int nHeight = 0;
|
||||
const Consensus::Params &consensusParams = chainparams.GetConsensus();
|
||||
|
||||
CBlockIndex* pindexPrev = chainActive.LastTip();;
|
||||
{
|
||||
LOCK2(cs_main, mempool.cs);
|
||||
pindexPrev = chainActive.LastTip();
|
||||
const int nHeight = pindexPrev->GetHeight() + 1;
|
||||
const Consensus::Params &consensusParams = chainparams.GetConsensus();
|
||||
uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, consensusParams);
|
||||
bool sapling = NetworkUpgradeActive(nHeight, consensusParams, Consensus::UPGRADE_SAPLING);
|
||||
{ // contain lock to block generation and not staking loops.
|
||||
LOCK2(cs_main, mempool.cs);
|
||||
nHeight = pindexPrev->GetHeight() + 1;
|
||||
uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, consensusParams);
|
||||
bool sapling = NetworkUpgradeActive(nHeight, consensusParams, Consensus::UPGRADE_SAPLING);
|
||||
|
||||
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
|
||||
uint32_t proposedTime = GetAdjustedTime();
|
||||
if (proposedTime == nMedianTimePast)
|
||||
{
|
||||
// too fast or stuck, this addresses the too fast issue, while moving
|
||||
// forward as quickly as possible
|
||||
for (int i; i < 100; i++)
|
||||
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
|
||||
uint32_t proposedTime = GetAdjustedTime();
|
||||
if (proposedTime == nMedianTimePast)
|
||||
{
|
||||
proposedTime = GetAdjustedTime();
|
||||
if (proposedTime == nMedianTimePast)
|
||||
MilliSleep(10);
|
||||
}
|
||||
}
|
||||
pblock->nTime = GetAdjustedTime();
|
||||
|
||||
CCoinsViewCache view(pcoinsTip);
|
||||
uint32_t expired; uint64_t commission;
|
||||
|
||||
SaplingMerkleTree sapling_tree;
|
||||
assert(view.GetSaplingAnchorAt(view.GetBestAnchor(SAPLING), sapling_tree));
|
||||
|
||||
// Priority order to process transactions
|
||||
list<COrphan> vOrphan; // list memory doesn't move
|
||||
map<uint256, vector<COrphan*> > mapDependers;
|
||||
bool fPrintPriority = GetBoolArg("-printpriority", false);
|
||||
|
||||
// This vector will be sorted into a priority queue:
|
||||
vector<TxPriority> vecPriority;
|
||||
vecPriority.reserve(mempool.mapTx.size() + 1);
|
||||
|
||||
// now add transactions from the mem pool
|
||||
for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
|
||||
mi != mempool.mapTx.end(); ++mi)
|
||||
{
|
||||
const CTransaction& tx = mi->GetTx();
|
||||
|
||||
int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
|
||||
? nMedianTimePast
|
||||
: pblock->GetBlockTime();
|
||||
|
||||
if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff) || IsExpiredTx(tx, nHeight))
|
||||
{
|
||||
//fprintf(stderr,"coinbase.%d finaltx.%d expired.%d\n",tx.IsCoinBase(),IsFinalTx(tx, nHeight, nLockTimeCutoff),IsExpiredTx(tx, nHeight));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && komodo_validate_interest(tx,nHeight,(uint32_t)pblock->nTime,0) < 0 )
|
||||
{
|
||||
//fprintf(stderr,"CreateNewBlock: komodo_validate_interest failure nHeight.%d nTime.%u vs locktime.%u\n",nHeight,(uint32_t)pblock->nTime,(uint32_t)tx.nLockTime);
|
||||
continue;
|
||||
}
|
||||
|
||||
COrphan* porphan = NULL;
|
||||
double dPriority = 0;
|
||||
CAmount nTotalIn = 0;
|
||||
bool fMissingInputs = false;
|
||||
if (tx.IsCoinImport())
|
||||
{
|
||||
CAmount nValueIn = GetCoinImportValue(tx);
|
||||
nTotalIn += nValueIn;
|
||||
dPriority += (double)nValueIn * 1000; // flat multiplier
|
||||
} else {
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
// too fast or stuck, this addresses the too fast issue, while moving
|
||||
// forward as quickly as possible
|
||||
for (int i; i < 100; i++)
|
||||
{
|
||||
// Read prev transaction
|
||||
if (!view.HaveCoins(txin.prevout.hash))
|
||||
{
|
||||
// This should never happen; all transactions in the memory
|
||||
// pool should connect to either transactions in the chain
|
||||
// or other transactions in the memory pool.
|
||||
if (!mempool.mapTx.count(txin.prevout.hash))
|
||||
{
|
||||
LogPrintf("ERROR: mempool transaction missing input\n");
|
||||
if (fDebug) assert("mempool transaction missing input" == 0);
|
||||
fMissingInputs = true;
|
||||
if (porphan)
|
||||
vOrphan.pop_back();
|
||||
break;
|
||||
}
|
||||
proposedTime = GetAdjustedTime();
|
||||
if (proposedTime == nMedianTimePast)
|
||||
MilliSleep(10);
|
||||
}
|
||||
}
|
||||
pblock->nTime = GetAdjustedTime();
|
||||
|
||||
// Has to wait for dependencies
|
||||
if (!porphan)
|
||||
{
|
||||
// Use list for automatic deletion
|
||||
vOrphan.push_back(COrphan(&tx));
|
||||
porphan = &vOrphan.back();
|
||||
}
|
||||
mapDependers[txin.prevout.hash].push_back(porphan);
|
||||
porphan->setDependsOn.insert(txin.prevout.hash);
|
||||
nTotalIn += mempool.mapTx.find(txin.prevout.hash)->GetTx().vout[txin.prevout.n].nValue;
|
||||
continue;
|
||||
}
|
||||
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
|
||||
assert(coins);
|
||||
CCoinsViewCache view(pcoinsTip);
|
||||
uint32_t expired;
|
||||
|
||||
CAmount nValueIn = coins->vout[txin.prevout.n].nValue;
|
||||
assert(view.GetSaplingAnchorAt(view.GetBestAnchor(SAPLING), sapling_tree));
|
||||
|
||||
// Priority order to process transactions
|
||||
list<COrphan> vOrphan; // list memory doesn't move
|
||||
map<uint256, vector<COrphan*> > mapDependers;
|
||||
bool fPrintPriority = GetBoolArg("-printpriority", false);
|
||||
|
||||
// This vector will be sorted into a priority queue:
|
||||
vector<TxPriority> vecPriority;
|
||||
vecPriority.reserve(mempool.mapTx.size() + 1);
|
||||
|
||||
// now add transactions from the mem pool
|
||||
for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
|
||||
mi != mempool.mapTx.end(); ++mi)
|
||||
{
|
||||
const CTransaction& tx = mi->GetTx();
|
||||
|
||||
int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
|
||||
? nMedianTimePast
|
||||
: pblock->GetBlockTime();
|
||||
|
||||
if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff) || IsExpiredTx(tx, nHeight))
|
||||
{
|
||||
//fprintf(stderr,"coinbase.%d finaltx.%d expired.%d\n",tx.IsCoinBase(),IsFinalTx(tx, nHeight, nLockTimeCutoff),IsExpiredTx(tx, nHeight));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && komodo_validate_interest(tx,nHeight,(uint32_t)pblock->nTime,0) < 0 )
|
||||
{
|
||||
//fprintf(stderr,"CreateNewBlock: komodo_validate_interest failure nHeight.%d nTime.%u vs locktime.%u\n",nHeight,(uint32_t)pblock->nTime,(uint32_t)tx.nLockTime);
|
||||
continue;
|
||||
}
|
||||
|
||||
COrphan* porphan = NULL;
|
||||
double dPriority = 0;
|
||||
CAmount nTotalIn = 0;
|
||||
bool fMissingInputs = false;
|
||||
bool fNotarisation = false;
|
||||
if (tx.IsCoinImport())
|
||||
{
|
||||
CAmount nValueIn = GetCoinImportValue(tx);
|
||||
nTotalIn += nValueIn;
|
||||
|
||||
int nConf = nHeight - coins->nHeight;
|
||||
|
||||
dPriority += (double)nValueIn * nConf;
|
||||
}
|
||||
nTotalIn += tx.GetShieldedValueIn();
|
||||
}
|
||||
|
||||
if (fMissingInputs) continue;
|
||||
|
||||
// Priority is sum(valuein * age) / modified_txsize
|
||||
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
dPriority = tx.ComputePriority(dPriority, nTxSize);
|
||||
|
||||
uint256 hash = tx.GetHash();
|
||||
mempool.ApplyDeltas(hash, dPriority, nTotalIn);
|
||||
|
||||
CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize);
|
||||
|
||||
if (porphan)
|
||||
{
|
||||
porphan->dPriority = dPriority;
|
||||
porphan->feeRate = feeRate;
|
||||
}
|
||||
else
|
||||
vecPriority.push_back(TxPriority(dPriority, feeRate, &(mi->GetTx())));
|
||||
}
|
||||
|
||||
// Collect transactions into block
|
||||
uint64_t nBlockSize = 1000;
|
||||
uint64_t nBlockTx = 0;
|
||||
int64_t interest;
|
||||
int nBlockSigOps = 100;
|
||||
bool fSortedByFee = (nBlockPrioritySize <= 0);
|
||||
|
||||
TxPriorityCompare comparer(fSortedByFee);
|
||||
std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
|
||||
|
||||
while (!vecPriority.empty())
|
||||
{
|
||||
// Take highest priority transaction off the priority queue:
|
||||
double dPriority = vecPriority.front().get<0>();
|
||||
CFeeRate feeRate = vecPriority.front().get<1>();
|
||||
const CTransaction& tx = *(vecPriority.front().get<2>());
|
||||
|
||||
std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
|
||||
vecPriority.pop_back();
|
||||
|
||||
// Size limits
|
||||
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
if (nBlockSize + nTxSize >= nBlockMaxSize-512) // room for extra autotx
|
||||
{
|
||||
//fprintf(stderr,"nBlockSize %d + %d nTxSize >= %d nBlockMaxSize\n",(int32_t)nBlockSize,(int32_t)nTxSize,(int32_t)nBlockMaxSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Legacy limits on sigOps:
|
||||
unsigned int nTxSigOps = GetLegacySigOpCount(tx);
|
||||
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1)
|
||||
{
|
||||
//fprintf(stderr,"A nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS);
|
||||
continue;
|
||||
}
|
||||
// Skip free transactions if we're past the minimum block size:
|
||||
const uint256& hash = tx.GetHash();
|
||||
double dPriorityDelta = 0;
|
||||
CAmount nFeeDelta = 0;
|
||||
mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
|
||||
if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
|
||||
{
|
||||
//fprintf(stderr,"fee rate skip\n");
|
||||
continue;
|
||||
}
|
||||
// Prioritise by fee once past the priority size or we run out of high-priority
|
||||
// transactions:
|
||||
if (!fSortedByFee &&
|
||||
((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority)))
|
||||
{
|
||||
fSortedByFee = true;
|
||||
comparer = TxPriorityCompare(fSortedByFee);
|
||||
std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
|
||||
}
|
||||
|
||||
if (!view.HaveInputs(tx))
|
||||
{
|
||||
//fprintf(stderr,"dont have inputs\n");
|
||||
continue;
|
||||
}
|
||||
CAmount nTxFees = view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime)-tx.GetValueOut();
|
||||
|
||||
nTxSigOps += GetP2SHSigOpCount(tx, view);
|
||||
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1)
|
||||
{
|
||||
//fprintf(stderr,"B nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS);
|
||||
continue;
|
||||
}
|
||||
// Note that flags: we don't want to set mempool/IsStandard()
|
||||
// policy here, but we still have to ensure that the block we
|
||||
// create only contains transactions that are valid in new blocks.
|
||||
CValidationState state;
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
|
||||
{
|
||||
//fprintf(stderr,"context failure\n");
|
||||
continue;
|
||||
}
|
||||
UpdateCoins(tx, view, nHeight);
|
||||
|
||||
BOOST_FOREACH(const OutputDescription &outDescription, tx.vShieldedOutput) {
|
||||
sapling_tree.append(outDescription.cm);
|
||||
}
|
||||
|
||||
// Added
|
||||
pblock->vtx.push_back(tx);
|
||||
pblocktemplate->vTxFees.push_back(nTxFees);
|
||||
pblocktemplate->vTxSigOps.push_back(nTxSigOps);
|
||||
nBlockSize += nTxSize;
|
||||
++nBlockTx;
|
||||
nBlockSigOps += nTxSigOps;
|
||||
nFees += nTxFees;
|
||||
|
||||
if (fPrintPriority)
|
||||
{
|
||||
LogPrintf("priority %.1f fee %s txid %s\n",dPriority, feeRate.ToString(), tx.GetHash().ToString());
|
||||
}
|
||||
|
||||
// Add transactions that depend on this one to the priority queue
|
||||
if (mapDependers.count(hash))
|
||||
{
|
||||
BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
|
||||
{
|
||||
if (!porphan->setDependsOn.empty())
|
||||
dPriority += (double)nValueIn * 1000; // flat multiplier
|
||||
} else {
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
{
|
||||
porphan->setDependsOn.erase(hash);
|
||||
if (porphan->setDependsOn.empty())
|
||||
// Read prev transaction
|
||||
if (!view.HaveCoins(txin.prevout.hash))
|
||||
{
|
||||
vecPriority.push_back(TxPriority(porphan->dPriority, porphan->feeRate, porphan->ptx));
|
||||
std::push_heap(vecPriority.begin(), vecPriority.end(), comparer);
|
||||
// This should never happen; all transactions in the memory
|
||||
// pool should connect to either transactions in the chain
|
||||
// or other transactions in the memory pool.
|
||||
if (!mempool.mapTx.count(txin.prevout.hash))
|
||||
{
|
||||
LogPrintf("ERROR: mempool transaction missing input\n");
|
||||
if (fDebug) assert("mempool transaction missing input" == 0);
|
||||
fMissingInputs = true;
|
||||
if (porphan)
|
||||
vOrphan.pop_back();
|
||||
break;
|
||||
}
|
||||
|
||||
// Has to wait for dependencies
|
||||
if (!porphan)
|
||||
{
|
||||
// Use list for automatic deletion
|
||||
vOrphan.push_back(COrphan(&tx));
|
||||
porphan = &vOrphan.back();
|
||||
}
|
||||
mapDependers[txin.prevout.hash].push_back(porphan);
|
||||
porphan->setDependsOn.insert(txin.prevout.hash);
|
||||
nTotalIn += mempool.mapTx.find(txin.prevout.hash)->GetTx().vout[txin.prevout.n].nValue;
|
||||
continue;
|
||||
}
|
||||
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
|
||||
assert(coins);
|
||||
|
||||
CAmount nValueIn = coins->vout[txin.prevout.n].nValue;
|
||||
nTotalIn += nValueIn;
|
||||
|
||||
int nConf = nHeight - coins->nHeight;
|
||||
|
||||
dPriority += (double)nValueIn * nConf;
|
||||
}
|
||||
nTotalIn += tx.GetShieldedValueIn();
|
||||
}
|
||||
|
||||
if (fMissingInputs) continue;
|
||||
|
||||
// Priority is sum(valuein * age) / modified_txsize
|
||||
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
dPriority = tx.ComputePriority(dPriority, nTxSize);
|
||||
|
||||
uint256 hash = tx.GetHash();
|
||||
mempool.ApplyDeltas(hash, dPriority, nTotalIn);
|
||||
|
||||
CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize);
|
||||
|
||||
if (porphan)
|
||||
{
|
||||
porphan->dPriority = dPriority;
|
||||
porphan->feeRate = feeRate;
|
||||
}
|
||||
else
|
||||
vecPriority.push_back(TxPriority(dPriority, feeRate, &(mi->GetTx())));
|
||||
}
|
||||
|
||||
// Collect transactions into block
|
||||
uint64_t nBlockSize = 1000;
|
||||
uint64_t nBlockTx = 0;
|
||||
int64_t interest;
|
||||
int nBlockSigOps = 100;
|
||||
bool fSortedByFee = (nBlockPrioritySize <= 0);
|
||||
|
||||
TxPriorityCompare comparer(fSortedByFee);
|
||||
std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
|
||||
|
||||
while (!vecPriority.empty())
|
||||
{
|
||||
// Take highest priority transaction off the priority queue:
|
||||
double dPriority = vecPriority.front().get<0>();
|
||||
CFeeRate feeRate = vecPriority.front().get<1>();
|
||||
const CTransaction& tx = *(vecPriority.front().get<2>());
|
||||
|
||||
std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
|
||||
vecPriority.pop_back();
|
||||
|
||||
// Size limits
|
||||
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
if (nBlockSize + nTxSize >= nBlockMaxSize-512) // room for extra autotx
|
||||
{
|
||||
//fprintf(stderr,"nBlockSize %d + %d nTxSize >= %d nBlockMaxSize\n",(int32_t)nBlockSize,(int32_t)nTxSize,(int32_t)nBlockMaxSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Legacy limits on sigOps:
|
||||
unsigned int nTxSigOps = GetLegacySigOpCount(tx);
|
||||
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1)
|
||||
{
|
||||
//fprintf(stderr,"A nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS);
|
||||
continue;
|
||||
}
|
||||
// Skip free transactions if we're past the minimum block size:
|
||||
const uint256& hash = tx.GetHash();
|
||||
double dPriorityDelta = 0;
|
||||
CAmount nFeeDelta = 0;
|
||||
mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
|
||||
if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
|
||||
{
|
||||
//fprintf(stderr,"fee rate skip\n");
|
||||
continue;
|
||||
}
|
||||
// Prioritise by fee once past the priority size or we run out of high-priority
|
||||
// transactions:
|
||||
if (!fSortedByFee &&
|
||||
((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority)))
|
||||
{
|
||||
fSortedByFee = true;
|
||||
comparer = TxPriorityCompare(fSortedByFee);
|
||||
std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
|
||||
}
|
||||
|
||||
if (!view.HaveInputs(tx))
|
||||
{
|
||||
//fprintf(stderr,"dont have inputs\n");
|
||||
continue;
|
||||
}
|
||||
CAmount nTxFees = view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime)-tx.GetValueOut();
|
||||
|
||||
nTxSigOps += GetP2SHSigOpCount(tx, view);
|
||||
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1)
|
||||
{
|
||||
//fprintf(stderr,"B nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS);
|
||||
continue;
|
||||
}
|
||||
// Note that flags: we don't want to set mempool/IsStandard()
|
||||
// policy here, but we still have to ensure that the block we
|
||||
// create only contains transactions that are valid in new blocks.
|
||||
CValidationState state;
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
|
||||
{
|
||||
//fprintf(stderr,"context failure\n");
|
||||
continue;
|
||||
}
|
||||
UpdateCoins(tx, view, nHeight);
|
||||
|
||||
BOOST_FOREACH(const OutputDescription &outDescription, tx.vShieldedOutput) {
|
||||
sapling_tree.append(outDescription.cm);
|
||||
}
|
||||
|
||||
// Added
|
||||
pblock->vtx.push_back(tx);
|
||||
pblocktemplate->vTxFees.push_back(nTxFees);
|
||||
pblocktemplate->vTxSigOps.push_back(nTxSigOps);
|
||||
nBlockSize += nTxSize;
|
||||
++nBlockTx;
|
||||
nBlockSigOps += nTxSigOps;
|
||||
nFees += nTxFees;
|
||||
|
||||
if (fPrintPriority)
|
||||
{
|
||||
LogPrintf("priority %.1f fee %s txid %s\n",dPriority, feeRate.ToString(), tx.GetHash().ToString());
|
||||
}
|
||||
|
||||
// Add transactions that depend on this one to the priority queue
|
||||
if (mapDependers.count(hash))
|
||||
{
|
||||
BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
|
||||
{
|
||||
if (!porphan->setDependsOn.empty())
|
||||
{
|
||||
porphan->setDependsOn.erase(hash);
|
||||
if (porphan->setDependsOn.empty())
|
||||
{
|
||||
vecPriority.push_back(TxPriority(porphan->dPriority, porphan->feeRate, porphan->ptx));
|
||||
std::push_heap(vecPriority.begin(), vecPriority.end(), comparer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nLastBlockTx = nBlockTx;
|
||||
nLastBlockSize = nBlockSize;
|
||||
blocktime = 1 + std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
||||
//pblock->nTime = blocktime + 1;
|
||||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
||||
nLastBlockTx = nBlockTx;
|
||||
nLastBlockSize = nBlockSize;
|
||||
blocktime = 1 + std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
||||
//pblock->nTime = blocktime + 1;
|
||||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
||||
|
||||
} // contain lock to block generation only!
|
||||
|
||||
int32_t stakeHeight = chainActive.Height() + 1;
|
||||
|
||||
@@ -497,7 +502,6 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
|
||||
//printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->GetHeight()+1,blocktime,(uint32_t)(GetAdjustedTime() - (blocktime-13)));
|
||||
} else return(0); //fprintf(stderr,"no utxos eligible for staking\n");
|
||||
}
|
||||
|
||||
// Create coinbase tx
|
||||
CMutableTransaction txNew = CreateNewContextualCMutableTransaction(consensusParams, nHeight);
|
||||
txNew.vin.resize(1);
|
||||
|
||||
@@ -606,6 +606,51 @@ UniValue getblockhash(const UniValue& params, bool fHelp)
|
||||
return pblockindex->GetBlockHash().GetHex();
|
||||
}
|
||||
|
||||
extern uint64_t ASSETCHAINS_STAKED;
|
||||
|
||||
UniValue getlastsegidstakes(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"getlastsegidstakes depth\n"
|
||||
"\nReturns object containing the counts of the last X blocks staked by each segid.\n"
|
||||
"\nArguments:\n"
|
||||
"1. depth (numeric, required) The amount of blocks to scan back."
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"0\" : n, (numeric) number of stakes from segid 0 in the last X blocks.\n"
|
||||
" .....\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getlastsegidstakes", "1000")
|
||||
+ HelpExampleRpc("getlastsegidstakes", "1000")
|
||||
);
|
||||
|
||||
if ( ASSETCHAINS_STAKED == 0 )
|
||||
throw runtime_error("Only applies to ac_staked chains\n");
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
int depth = params[0].get_int();
|
||||
int32_t segids[64] = {0};
|
||||
|
||||
for (int64_t i = chainActive.Height(); i > chainActive.Height()-depth; i--)
|
||||
{
|
||||
CBlockIndex* pblockindex = chainActive[i];
|
||||
if ( pblockindex->segid >= 0 )
|
||||
segids[pblockindex->segid] += 1;
|
||||
}
|
||||
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
for (int8_t i = 0; i < 64; i++)
|
||||
{
|
||||
char str[4];
|
||||
sprintf(str, "%d", i);
|
||||
ret.push_back(Pair(str,segids[i]));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*uint256 _komodo_getblockhash(int32_t nHeight)
|
||||
{
|
||||
uint256 hash;
|
||||
@@ -859,7 +904,7 @@ UniValue kvsearch(const UniValue& params, bool fHelp)
|
||||
" \"currentheight\": xxxxx, (numeric) current height of the chain\n"
|
||||
" \"key\": \"xxxxx\", (string) key\n"
|
||||
" \"keylen\": xxxxx, (string) length of the key \n"
|
||||
" \"owner\": \"xxxxx\" (string) hex string representing the owner of the key \n"
|
||||
" \"owner\": \"xxxxx\" (string) hex string representing the owner of the key \n"
|
||||
" \"height\": xxxxx, (numeric) height the key was stored at\n"
|
||||
" \"expiration\": xxxxx, (numeric) height the key will expire\n"
|
||||
" \"flags\": x (numeric) 1 if the key was created with a password; 0 otherwise.\n"
|
||||
|
||||
@@ -74,6 +74,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
{ "getblockheader", 1 },
|
||||
{ "gettransaction", 1 },
|
||||
{ "getrawtransaction", 1 },
|
||||
{ "getlastsegidstakes", 0 },
|
||||
{ "createrawtransaction", 0 },
|
||||
{ "createrawtransaction", 1 },
|
||||
{ "createrawtransaction", 2 },
|
||||
|
||||
@@ -302,6 +302,7 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "blockchain", "getblockhashes", &getblockhashes, true },
|
||||
{ "blockchain", "getblockhash", &getblockhash, true },
|
||||
{ "blockchain", "getblockheader", &getblockheader, true },
|
||||
{ "blockchain", "getlastsegidstakes", &getlastsegidstakes, true },
|
||||
{ "blockchain", "getchaintips", &getchaintips, true },
|
||||
{ "blockchain", "getdifficulty", &getdifficulty, true },
|
||||
{ "blockchain", "getmempoolinfo", &getmempoolinfo, true },
|
||||
@@ -364,16 +365,16 @@ static const CRPCCommand vRPCCommands[] =
|
||||
|
||||
// auction
|
||||
{ "auction", "auctionaddress", &auctionaddress, true },
|
||||
|
||||
|
||||
// lotto
|
||||
{ "lotto", "lottoaddress", &lottoaddress, true },
|
||||
|
||||
|
||||
// fsm
|
||||
{ "FSM", "FSMaddress", &FSMaddress, true },
|
||||
{ "FSM", "FSMcreate", &FSMcreate, true },
|
||||
{ "FSM", "FSMlist", &FSMlist, true },
|
||||
{ "FSM", "FSMinfo", &FSMinfo, true },
|
||||
|
||||
|
||||
// rewards
|
||||
{ "rewards", "rewardslist", &rewardslist, true },
|
||||
{ "rewards", "rewardsinfo", &rewardsinfo, true },
|
||||
@@ -382,7 +383,7 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "rewards", "rewardslock", &rewardslock, true },
|
||||
{ "rewards", "rewardsunlock", &rewardsunlock, true },
|
||||
{ "rewards", "rewardsaddress", &rewardsaddress, true },
|
||||
|
||||
|
||||
// faucet
|
||||
{ "faucet", "faucetinfo", &faucetinfo, true },
|
||||
{ "faucet", "faucetfund", &faucetfund, true },
|
||||
@@ -400,7 +401,7 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "channels", "channelspayment", &channelspayment, true },
|
||||
{ "channels", "channelsclose", &channelsclose, true },
|
||||
{ "channels", "channelsrefund", &channelsrefund, true },
|
||||
|
||||
|
||||
// Oracles
|
||||
{ "oracles", "oraclesaddress", &oraclesaddress, true },
|
||||
{ "oracles", "oracleslist", &oracleslist, true },
|
||||
|
||||
@@ -1674,7 +1674,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
|
||||
if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
|
||||
entry.push_back(Pair("involvesWatchonly", true));
|
||||
entry.push_back(Pair("account", account));
|
||||
|
||||
|
||||
CTxDestination dest;
|
||||
if (CScriptExt::ExtractVoutDestination(wtx, r.vout, dest))
|
||||
MaybePushAddress(entry, dest);
|
||||
@@ -2920,11 +2920,11 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||
// User did not provide zaddrs, so use default i.e. all addresses
|
||||
std::set<libzcash::SproutPaymentAddress> sproutzaddrs = {};
|
||||
pwalletMain->GetSproutPaymentAddresses(sproutzaddrs);
|
||||
|
||||
|
||||
// Sapling support
|
||||
std::set<libzcash::SaplingPaymentAddress> saplingzaddrs = {};
|
||||
pwalletMain->GetSaplingPaymentAddresses(saplingzaddrs);
|
||||
|
||||
|
||||
zaddrs.insert(sproutzaddrs.begin(), sproutzaddrs.end());
|
||||
zaddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end());
|
||||
}
|
||||
@@ -2936,7 +2936,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||
std::vector<SaplingNoteEntry> saplingEntries;
|
||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false);
|
||||
std::set<std::pair<PaymentAddress, uint256>> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs);
|
||||
|
||||
|
||||
for (auto & entry : sproutEntries) {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
|
||||
@@ -2954,7 +2954,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||
}
|
||||
results.push_back(obj);
|
||||
}
|
||||
|
||||
|
||||
for (auto & entry : saplingEntries) {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back(Pair("txid", entry.op.hash.ToString()));
|
||||
@@ -4115,7 +4115,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
|
||||
}
|
||||
if ( toSapling && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER,"Sprout usage will expire soon");
|
||||
|
||||
|
||||
// If we are sending from a shielded address, all recipient
|
||||
// shielded addresses must be of the same type.
|
||||
if ((fromSprout && toSapling) || (fromSapling && toSprout)) {
|
||||
@@ -4534,14 +4534,14 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
|
||||
string enableArg = "zmergetoaddress";
|
||||
auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-" + enableArg, true);
|
||||
std::string strDisabledMsg = "";
|
||||
if (!fEnableMergeToAddress) {
|
||||
strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg);
|
||||
}
|
||||
|
||||
|
||||
if (fHelp || params.size() < 2 || params.size() > 6)
|
||||
throw runtime_error(
|
||||
"z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n"
|
||||
@@ -4590,33 +4590,33 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
+ HelpExampleCli("z_mergetoaddress", "'[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf")
|
||||
+ HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\"")
|
||||
);
|
||||
|
||||
|
||||
if (!fEnableMergeToAddress) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled.");
|
||||
}
|
||||
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
|
||||
bool useAnyUTXO = false;
|
||||
bool useAnySprout = false;
|
||||
bool useAnySapling = false;
|
||||
std::set<CTxDestination> taddrs = {};
|
||||
std::set<libzcash::PaymentAddress> zaddrs = {};
|
||||
|
||||
|
||||
UniValue addresses = params[0].get_array();
|
||||
if (addresses.size()==0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
|
||||
|
||||
|
||||
// Keep track of addresses to spot duplicates
|
||||
std::set<std::string> setAddress;
|
||||
|
||||
|
||||
// Sources
|
||||
for (const UniValue& o : addresses.getValues()) {
|
||||
if (!o.isStr())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
|
||||
|
||||
|
||||
std::string address = o.get_str();
|
||||
|
||||
|
||||
if (address == "ANY_TADDR") {
|
||||
useAnyUTXO = true;
|
||||
} else if (address == "ANY_SPROUT") {
|
||||
@@ -4636,23 +4636,23 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (setAddress.count(address))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
|
||||
setAddress.insert(address);
|
||||
}
|
||||
|
||||
|
||||
if (useAnyUTXO && taddrs.size() > 0) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific t-addrs when using \"ANY_TADDR\"");
|
||||
}
|
||||
if ((useAnySprout || useAnySapling) && zaddrs.size() > 0) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific z-addrs when using \"ANY_SPROUT\" or \"ANY_SAPLING\"");
|
||||
}
|
||||
|
||||
|
||||
const int nextBlockHeight = chainActive.Height() + 1;
|
||||
const bool overwinterActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER);
|
||||
const bool saplingActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING);
|
||||
|
||||
|
||||
// Validate the destination address
|
||||
auto destaddress = params[1].get_str();
|
||||
bool isToSproutZaddr = false;
|
||||
@@ -4674,7 +4674,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Convert fee from currency format to zatoshis
|
||||
CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
|
||||
if (params.size() > 2) {
|
||||
@@ -4684,7 +4684,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
nFee = AmountFromValue( params[2] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT;
|
||||
if (params.size() > 3) {
|
||||
nUTXOLimit = params[3].get_int();
|
||||
@@ -4692,7 +4692,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int sproutNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT;
|
||||
int saplingNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT;
|
||||
if (params.size() > 4) {
|
||||
@@ -4703,7 +4703,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
sproutNoteLimit = nNoteLimit;
|
||||
saplingNoteLimit = nNoteLimit;
|
||||
}
|
||||
|
||||
|
||||
std::string memo;
|
||||
if (params.size() > 5) {
|
||||
memo = params[5].get_str();
|
||||
@@ -4716,9 +4716,9 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MergeToAddressRecipient recipient(destaddress, memo);
|
||||
|
||||
|
||||
// Prepare to get UTXOs and notes
|
||||
std::vector<MergeToAddressInputUTXO> utxoInputs;
|
||||
std::vector<MergeToAddressInputSproutNote> sproutNoteInputs;
|
||||
@@ -4732,7 +4732,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
bool maxedOutUTXOsFlag = false;
|
||||
bool maxedOutNotesFlag = false;
|
||||
size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (overwinterActive ? 0 : (size_t)GetArg("-mempooltxinputlimit", 0));
|
||||
|
||||
|
||||
unsigned int max_tx_size = saplingActive ? MAX_TX_SIZE_AFTER_SAPLING : MAX_TX_SIZE_BEFORE_SAPLING;
|
||||
size_t estimatedTxSize = 200; // tx overhead + wiggle room
|
||||
if (isToSproutZaddr) {
|
||||
@@ -4740,20 +4740,20 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
} else if (isToSaplingZaddr) {
|
||||
estimatedTxSize += OUTPUTDESCRIPTION_SIZE;
|
||||
}
|
||||
|
||||
|
||||
if (useAnyUTXO || taddrs.size() > 0) {
|
||||
// Get available utxos
|
||||
vector<COutput> vecOutputs;
|
||||
pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false);
|
||||
|
||||
|
||||
// Find unspent utxos and update estimated size
|
||||
for (const COutput& out : vecOutputs) {
|
||||
if (!out.fSpendable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
CScript scriptPubKey = out.tx->vout[out.i].scriptPubKey;
|
||||
|
||||
|
||||
CTxDestination address;
|
||||
if (!ExtractDestination(scriptPubKey, address)) {
|
||||
continue;
|
||||
@@ -4762,10 +4762,10 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
if (taddrs.size() > 0 && !taddrs.count(address)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
utxoCounter++;
|
||||
CAmount nValue = out.tx->vout[out.i].nValue;
|
||||
|
||||
|
||||
if (!maxedOutUTXOsFlag) {
|
||||
size_t increase = (boost::get<CScriptID>(&address) != nullptr) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
|
||||
if (estimatedTxSize + increase >= max_tx_size ||
|
||||
@@ -4779,19 +4779,19 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
mergedUTXOValue += nValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (maxedOutUTXOsFlag) {
|
||||
remainingUTXOValue += nValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (useAnySprout || useAnySapling || zaddrs.size() > 0) {
|
||||
// Get available notes
|
||||
std::vector<CSproutNotePlaintextEntry> sproutEntries,skipsprout;
|
||||
std::vector<SaplingNoteEntry> saplingEntries,skipsapling;
|
||||
pwalletMain->GetFilteredNotes(sproutEntries, useAnySprout == 0 ? saplingEntries : skipsapling, zaddrs);
|
||||
|
||||
|
||||
// If Sapling is not active, do not allow sending from a sapling addresses.
|
||||
if (!saplingActive && saplingEntries.size() > 0) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
|
||||
@@ -4808,12 +4808,12 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
RPC_INVALID_PARAMETER,
|
||||
"Cannot send between Sprout and Sapling addresses using z_mergetoaddress");
|
||||
}
|
||||
|
||||
|
||||
// Find unspent notes and update estimated size
|
||||
for (const CSproutNotePlaintextEntry& entry : sproutEntries) {
|
||||
noteCounter++;
|
||||
CAmount nValue = entry.plaintext.value();
|
||||
|
||||
|
||||
if (!maxedOutNotesFlag) {
|
||||
// If we haven't added any notes yet and the merge is to a
|
||||
// z-address, we have already accounted for the first JoinSplit.
|
||||
@@ -4831,12 +4831,12 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
mergedNoteValue += nValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (maxedOutNotesFlag) {
|
||||
remainingNoteValue += nValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (const SaplingNoteEntry& entry : saplingEntries) {
|
||||
noteCounter++;
|
||||
CAmount nValue = entry.note.value();
|
||||
@@ -4856,20 +4856,20 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
mergedNoteValue += nValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (maxedOutNotesFlag) {
|
||||
remainingNoteValue += nValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t numUtxos = utxoInputs.size();
|
||||
size_t numNotes = sproutNoteInputs.size() + saplingNoteInputs.size();
|
||||
|
||||
|
||||
if (numUtxos == 0 && numNotes == 0) {
|
||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
|
||||
}
|
||||
|
||||
|
||||
// Sanity check: Don't do anything if:
|
||||
// - We only have one from address
|
||||
// - It's equal to toaddress
|
||||
@@ -4877,26 +4877,26 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged.");
|
||||
}
|
||||
|
||||
|
||||
CAmount mergedValue = mergedUTXOValue + mergedNoteValue;
|
||||
if (mergedValue < nFee) {
|
||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
|
||||
strprintf("Insufficient funds, have %s, which is less than miners fee %s",
|
||||
FormatMoney(mergedValue), FormatMoney(nFee)));
|
||||
}
|
||||
|
||||
|
||||
// Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
|
||||
CAmount netAmount = mergedValue - nFee;
|
||||
if (nFee > netAmount) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
|
||||
}
|
||||
|
||||
|
||||
// Keep record of parameters in context object
|
||||
UniValue contextInfo(UniValue::VOBJ);
|
||||
contextInfo.push_back(Pair("fromaddresses", params[0]));
|
||||
contextInfo.push_back(Pair("toaddress", params[1]));
|
||||
contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
|
||||
|
||||
|
||||
// Contextual transaction we will build on
|
||||
CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
|
||||
Params().GetConsensus(),
|
||||
@@ -4905,7 +4905,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
if (contextualTx.nVersion == 1 && isSproutShielded) {
|
||||
contextualTx.nVersion = 2; // Tx format should support vjoinsplit
|
||||
}
|
||||
|
||||
|
||||
// Builder (used if Sapling addresses are involved)
|
||||
boost::optional<TransactionBuilder> builder;
|
||||
if (isToSaplingZaddr || saplingNoteInputs.size() > 0) {
|
||||
@@ -4917,7 +4917,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
|
||||
new AsyncRPCOperation_mergetoaddress(builder, contextualTx, utxoInputs, sproutNoteInputs, saplingNoteInputs, recipient, nFee, contextInfo) );
|
||||
q->addOperation(operation);
|
||||
AsyncRPCOperationId operationId = operation->getId();
|
||||
|
||||
|
||||
// Return continuation information
|
||||
UniValue o(UniValue::VOBJ);
|
||||
o.push_back(Pair("remainingUTXOs", static_cast<uint64_t>(utxoCounter - numUtxos)));
|
||||
@@ -5066,247 +5066,6 @@ int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
|
||||
return(siglen);
|
||||
}
|
||||
|
||||
struct komodo_staking
|
||||
{
|
||||
char address[64];
|
||||
uint256 txid;
|
||||
arith_uint256 hashval;
|
||||
uint64_t nValue;
|
||||
uint32_t segid32,txtime;
|
||||
int32_t vout;
|
||||
CScript scriptPubKey;
|
||||
};
|
||||
|
||||
struct komodo_staking *komodo_addutxo(struct komodo_staking *array,int32_t *numkp,int32_t *maxkp,uint32_t txtime,uint64_t nValue,uint256 txid,int32_t vout,char *address,uint8_t *hashbuf,CScript pk)
|
||||
{
|
||||
uint256 hash; uint32_t segid32; struct komodo_staking *kp;
|
||||
segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
|
||||
if ( *numkp >= *maxkp )
|
||||
{
|
||||
*maxkp += 1000;
|
||||
array = (struct komodo_staking *)realloc(array,sizeof(*array) * (*maxkp));
|
||||
//fprintf(stderr,"realloc max.%d array.%p\n",*maxkp,array);
|
||||
}
|
||||
kp = &array[(*numkp)++];
|
||||
//fprintf(stderr,"kp.%p num.%d\n",kp,*numkp);
|
||||
memset(kp,0,sizeof(*kp));
|
||||
strcpy(kp->address,address);
|
||||
kp->txid = txid;
|
||||
kp->vout = vout;
|
||||
kp->hashval = UintToArith256(hash);
|
||||
kp->txtime = txtime;
|
||||
kp->segid32 = segid32;
|
||||
kp->nValue = nValue;
|
||||
kp->scriptPubKey = pk;
|
||||
return(array);
|
||||
}
|
||||
|
||||
arith_uint256 _komodo_eligible(struct komodo_staking *kp,arith_uint256 ratio,uint32_t blocktime,int32_t iter,int32_t minage,int32_t segid,int32_t nHeight,uint32_t prevtime)
|
||||
{
|
||||
int32_t diff; uint64_t coinage; arith_uint256 coinage256,hashval;
|
||||
diff = (iter + blocktime - kp->txtime - minage);
|
||||
if ( diff < 0 )
|
||||
diff = 60;
|
||||
else if ( diff > 3600*24*30 )
|
||||
diff = 3600*24*30;
|
||||
if ( iter > 0 )
|
||||
diff += segid*2;
|
||||
coinage = ((uint64_t)kp->nValue * diff);
|
||||
if ( blocktime+iter+segid*2 > prevtime+480 )
|
||||
coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
|
||||
coinage256 = arith_uint256(coinage+1);
|
||||
hashval = ratio * (kp->hashval / coinage256);
|
||||
return(hashval);
|
||||
}
|
||||
|
||||
uint32_t komodo_eligible(arith_uint256 bnTarget,arith_uint256 ratio,struct komodo_staking *kp,int32_t nHeight,uint32_t blocktime,uint32_t prevtime,int32_t minage,uint8_t *hashbuf)
|
||||
{
|
||||
int32_t maxiters = 600; uint256 hash;
|
||||
int32_t segid,iter,diff; uint64_t coinage; arith_uint256 hashval,coinage256;
|
||||
komodo_stakehash(&hash,kp->address,hashbuf,kp->txid,kp->vout);
|
||||
kp->hashval = UintToArith256(hash);
|
||||
segid = ((nHeight + kp->segid32) & 0x3f);
|
||||
hashval = _komodo_eligible(kp,ratio,blocktime,maxiters,minage,segid,nHeight,prevtime);
|
||||
//for (int i=32; i>=0; i--)
|
||||
// fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
|
||||
//fprintf(stderr," b.%u minage.%d segid.%d ht.%d prev.%u\n",blocktime,minage,segid,nHeight,prevtime);
|
||||
if ( hashval <= bnTarget )
|
||||
{
|
||||
for (iter=0; iter<maxiters; iter++)
|
||||
{
|
||||
if ( blocktime+iter+segid*2 < kp->txtime+minage )
|
||||
continue;
|
||||
hashval = _komodo_eligible(kp,ratio,blocktime,iter,minage,segid,nHeight,prevtime);
|
||||
if ( hashval <= bnTarget )
|
||||
{
|
||||
//fprintf(stderr,"winner %.8f blocktime.%u iter.%d segid.%d\n",(double)kp->nValue/COIN,blocktime,iter,segid);
|
||||
blocktime += iter;
|
||||
blocktime += segid * 2;
|
||||
return(blocktime);
|
||||
}
|
||||
}
|
||||
} else fprintf(stderr,"maxiters is not good enough\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig)
|
||||
{
|
||||
static struct komodo_staking *array; static int32_t numkp,maxkp; static uint32_t lasttime;
|
||||
set<CBitcoinAddress> setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector<COutput> vecOutputs; uint32_t block_from_future_rejecttime,besttime,eligible,eligible2,earliest = 0; CScript best_scriptPubKey; arith_uint256 mindiff,ratio,bnTarget; CBlockIndex *tipindex,*pindex; CTxDestination address; bool fNegative,fOverflow; uint8_t hashbuf[256]; CTransaction tx; uint256 hashBlock;
|
||||
if (!EnsureWalletIsAvailable(0))
|
||||
return 0;
|
||||
|
||||
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
|
||||
mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
|
||||
ratio = (mindiff / bnTarget);
|
||||
assert(pwalletMain != NULL);
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
*utxovaluep = 0;
|
||||
memset(utxotxidp,0,sizeof(*utxotxidp));
|
||||
memset(utxovoutp,0,sizeof(*utxovoutp));
|
||||
memset(utxosig,0,72);
|
||||
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
|
||||
if ( (tipindex= chainActive.Tip()) == 0 )
|
||||
return(0);
|
||||
nHeight = tipindex->GetHeight() + 1;
|
||||
if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
|
||||
minage = 6000;
|
||||
komodo_segids(hashbuf,nHeight-101,100);
|
||||
if ( *blocktimep < tipindex->nTime+60 )
|
||||
*blocktimep = tipindex->nTime+60;
|
||||
//fprintf(stderr,"Start scan of utxo for staking %u ht.%d\n",(uint32_t)time(NULL),nHeight);
|
||||
if ( time(NULL) > lasttime+600 || array == 0 )
|
||||
{
|
||||
if ( array != 0 )
|
||||
{
|
||||
free(array);
|
||||
array = 0;
|
||||
maxkp = numkp = 0;
|
||||
lasttime = 0;
|
||||
}
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs)
|
||||
{
|
||||
if ( (tipindex= chainActive.Tip()) == 0 || tipindex->GetHeight()+1 > nHeight )
|
||||
{
|
||||
fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
|
||||
return(0);
|
||||
}
|
||||
counter++;
|
||||
if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
|
||||
{
|
||||
fprintf(stderr,"komodo_staked invalid depth %d\n",(int32_t)out.nDepth);
|
||||
continue;
|
||||
}
|
||||
CAmount nValue = out.tx->vout[out.i].nValue;
|
||||
if ( nValue < COIN || !out.fSpendable )
|
||||
continue;
|
||||
const CScript& pk = out.tx->vout[out.i].scriptPubKey;
|
||||
if ( ExtractDestination(pk,address) != 0 )
|
||||
{
|
||||
if ( IsMine(*pwalletMain,address) == 0 )
|
||||
continue;
|
||||
if ( GetTransaction(out.tx->GetHash(),tx,hashBlock,true) != 0 && (pindex= komodo_getblockindex(hashBlock)) != 0 )
|
||||
{
|
||||
array = komodo_addutxo(array,&numkp,&maxkp,(uint32_t)pindex->nTime,(uint64_t)nValue,out.tx->GetHash(),out.i,(char *)CBitcoinAddress(address).ToString().c_str(),hashbuf,(CScript)pk);
|
||||
//fprintf(stderr,"addutxo numkp.%d vs max.%d\n",numkp,maxkp);
|
||||
}
|
||||
}
|
||||
}
|
||||
lasttime = (uint32_t)time(NULL);
|
||||
//fprintf(stderr,"finished kp data of utxo for staking %u ht.%d numkp.%d maxkp.%d\n",(uint32_t)time(NULL),nHeight,numkp,maxkp);
|
||||
}
|
||||
//fprintf(stderr,"numkp.%d blocktime.%u\n",numkp,*blocktimep);
|
||||
block_from_future_rejecttime = (uint32_t)GetAdjustedTime() + 57;
|
||||
for (i=winners=0; i<numkp; i++)
|
||||
{
|
||||
if ( (tipindex= chainActive.Tip()) == 0 || tipindex->GetHeight()+1 > nHeight )
|
||||
{
|
||||
fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
|
||||
return(0);
|
||||
}
|
||||
kp = &array[i];
|
||||
if ( (eligible2= komodo_eligible(bnTarget,ratio,kp,nHeight,*blocktimep,(uint32_t)tipindex->nTime+27,minage,hashbuf)) == 0 )
|
||||
continue;
|
||||
eligible = komodo_stake(0,bnTarget,nHeight,kp->txid,kp->vout,0,(uint32_t)tipindex->nTime+27,kp->address);
|
||||
//fprintf(stderr,"i.%d %u vs %u\n",i,eligible2,eligible);
|
||||
if ( eligible > 0 )
|
||||
{
|
||||
besttime = m = 0;
|
||||
if ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
|
||||
{
|
||||
while ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) )
|
||||
{
|
||||
besttime = eligible;
|
||||
eligible--;
|
||||
if ( eligible < block_from_future_rejecttime ) // nothing gained by going earlier
|
||||
break;
|
||||
m++;
|
||||
//fprintf(stderr,"m.%d ht.%d validated winning blocktime %u -> %.8f eligible.%u test prior\n",m,nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"ht.%d error validating winning blocktime %u -> %.8f eligible.%u test prior\n",nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
|
||||
continue;
|
||||
}
|
||||
eligible = besttime;
|
||||
winners++;
|
||||
//fprintf(stderr,"ht.%d validated winning [%d] -> %.8f eligible.%u test prior\n",nHeight,(int32_t)(eligible - tipindex->nTime),(double)kp->nValue/COIN,eligible);
|
||||
if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || kp->nValue < *utxovaluep)) )
|
||||
{
|
||||
earliest = eligible;
|
||||
best_scriptPubKey = kp->scriptPubKey; //out.tx->vout[out.i].scriptPubKey;
|
||||
*utxovaluep = (uint64_t)kp->nValue;
|
||||
//decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str());
|
||||
decode_hex((uint8_t *)utxotxidp,32,(char *)kp->txid.GetHex().c_str());
|
||||
*utxovoutp = kp->vout;
|
||||
*txtimep = kp->txtime;//(uint32_t)out.tx->nLockTime;
|
||||
fprintf(stderr,"ht.%d earliest.%u [%d].%d (%s) nValue %.8f locktime.%u counter.%d winners.%d\n",nHeight,earliest,(int32_t)(earliest - tipindex->nTime),m,kp->address,(double)kp->nValue/COIN,*txtimep,counter,winners);
|
||||
}
|
||||
} //else fprintf(stderr,"utxo not eligible\n");
|
||||
}
|
||||
if ( numkp < 10000 && array != 0 )
|
||||
{
|
||||
free(array);
|
||||
array = 0;
|
||||
maxkp = numkp = 0;
|
||||
lasttime = 0;
|
||||
}
|
||||
if ( earliest != 0 )
|
||||
{
|
||||
bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid;
|
||||
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
txNew.vin.resize(1);
|
||||
txNew.vout.resize(1);
|
||||
txfee = 0;
|
||||
for (i=0; i<32; i++)
|
||||
((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i];
|
||||
txNew.vin[0].prevout.hash = revtxid;
|
||||
txNew.vin[0].prevout.n = *utxovoutp;
|
||||
txNew.vout[0].scriptPubKey = best_scriptPubKey;// CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
|
||||
txNew.vout[0].nValue = *utxovaluep - txfee;
|
||||
txNew.nLockTime = earliest;
|
||||
CTransaction txNewConst(txNew);
|
||||
signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
|
||||
if (!signSuccess)
|
||||
fprintf(stderr,"failed to create signature\n");
|
||||
else
|
||||
{
|
||||
UpdateTransaction(txNew,0,sigdata);
|
||||
ptr = (uint8_t *)&sigdata.scriptSig[0];
|
||||
siglen = sigdata.scriptSig.size();
|
||||
for (i=0; i<siglen; i++)
|
||||
utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
|
||||
//fprintf(stderr," siglen.%d\n",siglen);
|
||||
//fprintf(stderr,"best %u from %u, gap %d lag.%d\n",earliest,*blocktimep,(int32_t)(earliest - *blocktimep),(int32_t)(time(NULL) - *blocktimep));
|
||||
*blocktimep = earliest;
|
||||
}
|
||||
} //else fprintf(stderr,"no earliest utxo for staking\n");
|
||||
//fprintf(stderr,"end scan of utxo for staking t.%u counter.%d numkp.%d winners.%d\n",(uint32_t)time(NULL),counter,numkp,winners);
|
||||
return(siglen);
|
||||
}
|
||||
|
||||
int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig, CPubKey &pk)
|
||||
{
|
||||
return pwalletMain->VerusStakeTransaction(pBlock, txNew, nBits, hashResult, utxosig, pk);
|
||||
@@ -5677,7 +5436,7 @@ UniValue channelslist(const UniValue& params, bool fHelp)
|
||||
if ( fHelp || params.size() > 0 )
|
||||
throw runtime_error("channelsinfo\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
return(ChannelsList());
|
||||
}
|
||||
|
||||
@@ -6027,7 +5786,7 @@ UniValue gatewaysbind(const UniValue& params, bool fHelp)
|
||||
if ( params.size() < 6+i+1 )
|
||||
throw runtime_error("not enough parameters for N pubkeys\n");
|
||||
pubkey = ParseHex(params[6+i].get_str().c_str());
|
||||
if (pubkey.size()!= 33)
|
||||
if (pubkey.size()!= 33)
|
||||
throw runtime_error("invalid destination pubkey");
|
||||
pubkeys.push_back(pubkey2pk(pubkey));
|
||||
}
|
||||
@@ -6061,8 +5820,8 @@ UniValue gatewaysdeposit(const UniValue& params, bool fHelp)
|
||||
amount = atof((char *)params[8].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
if ( amount <= 0 || claimvout < 0 )
|
||||
throw runtime_error("invalid param: amount, numpks or claimvout\n");
|
||||
if (destpub.size()!= 33)
|
||||
throw runtime_error("invalid destination pubkey");
|
||||
if (destpub.size()!= 33)
|
||||
throw runtime_error("invalid destination pubkey");
|
||||
hex = GatewaysDeposit(0,bindtxid,height,coin,cointxid,claimvout,deposithex,proof,pubkey2pk(destpub),amount);
|
||||
|
||||
RETURN_IF_ERROR(CCerror);
|
||||
@@ -6087,9 +5846,9 @@ UniValue gatewaysclaim(const UniValue& params, bool fHelp)
|
||||
coin = params[1].get_str();
|
||||
deposittxid = Parseuint256((char *)params[2].get_str().c_str());
|
||||
destpub = ParseHex(params[3].get_str());
|
||||
amount = atof((char *)params[4].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
if (destpub.size()!= 33)
|
||||
throw runtime_error("invalid destination pubkey");
|
||||
amount = atof((char *)params[4].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
if (destpub.size()!= 33)
|
||||
throw runtime_error("invalid destination pubkey");
|
||||
hex = GatewaysClaim(0,bindtxid,coin,deposittxid,pubkey2pk(destpub),amount);
|
||||
RETURN_IF_ERROR(CCerror);
|
||||
if ( hex.size() > 0 )
|
||||
@@ -6112,9 +5871,9 @@ UniValue gatewayswithdraw(const UniValue& params, bool fHelp)
|
||||
bindtxid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
coin = params[1].get_str();
|
||||
withdrawpub = ParseHex(params[2].get_str());
|
||||
amount = atof((char *)params[3].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
if (withdrawpub.size()!= 33)
|
||||
throw runtime_error("invalid destination pubkey");
|
||||
amount = atof((char *)params[3].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
if (withdrawpub.size()!= 33)
|
||||
throw runtime_error("invalid destination pubkey");
|
||||
hex = GatewaysWithdraw(0,bindtxid,coin,pubkey2pk(withdrawpub),amount);
|
||||
RETURN_IF_ERROR(CCerror);
|
||||
if ( hex.size() > 0 )
|
||||
@@ -6133,7 +5892,7 @@ UniValue gatewayspartialsign(const UniValue& params, bool fHelp)
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
txid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
coin = params[1].get_str();
|
||||
parthex = params[2].get_str();
|
||||
@@ -6178,7 +5937,7 @@ UniValue gatewaysmarkdone(const UniValue& params, bool fHelp)
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
completetxid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
coin = params[1].get_str();
|
||||
coin = params[1].get_str();
|
||||
hex = GatewaysMarkDone(0,completetxid,coin);
|
||||
RETURN_IF_ERROR(CCerror);
|
||||
if ( hex.size() > 0 )
|
||||
@@ -7182,7 +6941,7 @@ UniValue tokenfillask(const UniValue& params, bool fHelp)
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
tokenid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
asktxid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
//fillunits = atol(params[2].get_str().c_str());
|
||||
//fillunits = atol(params[2].get_str().c_str());
|
||||
fillunits = atoll(params[2].get_str().c_str()); // dimxy changed to prevent loss of significance
|
||||
if ( fillunits <= 0 )
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user