Ram staker is fixed!
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
|
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);
|
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);
|
unsigned int lwmaGetNextPOSRequired(const CBlockIndex* pindexLast, const Consensus::Params& params);
|
||||||
|
bool EnsureWalletIsAvailable(bool avoidException);
|
||||||
|
|
||||||
//#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
|
//#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"curl",(char *)"http://127.0.0.1:7776",0,0,(char *)(cmdstr))
|
||||||
|
|
||||||
@@ -610,6 +611,28 @@ uint32_t komodo_txtime2(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
|
|||||||
return(txtime);
|
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 komodo_isPoS(CBlock *pblock)
|
||||||
{
|
{
|
||||||
int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid;
|
int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid;
|
||||||
@@ -1935,3 +1958,257 @@ int64_t komodo_coinsupply(int64_t *zfundsp,int64_t *sproutfundsp,int32_t height)
|
|||||||
*sproutfundsp = sproutfunds;
|
*sproutfundsp = sproutfunds;
|
||||||
return(supply);
|
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 ( (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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1589,7 +1589,6 @@ void static BitcoinMiner()
|
|||||||
KOMODO_INSYNC = Mining_height;
|
KOMODO_INSYNC = Mining_height;
|
||||||
sleep(3);
|
sleep(3);
|
||||||
}*/
|
}*/
|
||||||
bool breakLoop = false;
|
|
||||||
komodo_longestchain();
|
komodo_longestchain();
|
||||||
// Hash state
|
// Hash state
|
||||||
KOMODO_CHOSEN_ONE = 0;
|
KOMODO_CHOSEN_ONE = 0;
|
||||||
@@ -1614,7 +1613,7 @@ void static BitcoinMiner()
|
|||||||
else hashTarget = HASHTarget;
|
else hashTarget = HASHTarget;
|
||||||
std::function<bool(std::vector<unsigned char>)> validBlock =
|
std::function<bool(std::vector<unsigned char>)> validBlock =
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
[&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams, &breakLoop]
|
[&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams]
|
||||||
#else
|
#else
|
||||||
[&pblock, &hashTarget, &m_cs, &cancelSolver, &chainparams]
|
[&pblock, &hashTarget, &m_cs, &cancelSolver, &chainparams]
|
||||||
#endif
|
#endif
|
||||||
@@ -1683,8 +1682,6 @@ void static BitcoinMiner()
|
|||||||
for (z=31; z>=0; z--)
|
for (z=31; z>=0; z--)
|
||||||
fprintf(stderr,"%02x",((uint8_t *)&h)[z]);
|
fprintf(stderr,"%02x",((uint8_t *)&h)[z]);
|
||||||
fprintf(stderr," Invalid block mined, try again\n");
|
fprintf(stderr," Invalid block mined, try again\n");
|
||||||
if ( ASSETCHAINS_STAKED != 0 )
|
|
||||||
breakLoop = true;
|
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
KOMODO_CHOSEN_ONE = 1;
|
KOMODO_CHOSEN_ONE = 1;
|
||||||
@@ -1715,8 +1712,6 @@ void static BitcoinMiner()
|
|||||||
std::lock_guard<std::mutex> lock{m_cs};
|
std::lock_guard<std::mutex> lock{m_cs};
|
||||||
return cancelSolver;
|
return cancelSolver;
|
||||||
};
|
};
|
||||||
if (breakLoop)
|
|
||||||
break;
|
|
||||||
// TODO: factor this out into a function with the same API for each solver.
|
// TODO: factor this out into a function with the same API for each solver.
|
||||||
if (solver == "tromp" ) { //&& notaryid >= 0 ) {
|
if (solver == "tromp" ) { //&& notaryid >= 0 ) {
|
||||||
// Create solver and initialize it.
|
// Create solver and initialize it.
|
||||||
|
|||||||
@@ -4218,7 +4218,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
|
|||||||
}
|
}
|
||||||
if ( toSapling && ASSETCHAINS_SYMBOL[0] == 0 )
|
if ( toSapling && ASSETCHAINS_SYMBOL[0] == 0 )
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER,"Sprout usage will expire soon");
|
throw JSONRPCError(RPC_INVALID_PARAMETER,"Sprout usage will expire soon");
|
||||||
|
|
||||||
// If we are sending from a shielded address, all recipient
|
// If we are sending from a shielded address, all recipient
|
||||||
// shielded addresses must be of the same type.
|
// shielded addresses must be of the same type.
|
||||||
if ((fromSprout && toSapling) || (fromSapling && toSprout)) {
|
if ((fromSprout && toSapling) || (fromSapling && toSprout)) {
|
||||||
@@ -5109,9 +5109,6 @@ UniValue z_listoperationids(const UniValue& params, bool fHelp)
|
|||||||
#include "script/sign.h"
|
#include "script/sign.h"
|
||||||
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
|
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
|
||||||
extern std::string NOTARY_PUBKEY;
|
extern std::string NOTARY_PUBKEY;
|
||||||
uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime,char *destaddr);
|
|
||||||
int8_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout);
|
|
||||||
void komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n);
|
|
||||||
|
|
||||||
int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
|
int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
|
||||||
{
|
{
|
||||||
@@ -5192,247 +5189,6 @@ int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
|
|||||||
return(siglen);
|
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 < 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig, CPubKey &pk)
|
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);
|
return pwalletMain->VerusStakeTransaction(pBlock, txNew, nBits, hashResult, utxosig, pk);
|
||||||
|
|||||||
Reference in New Issue
Block a user