@@ -1185,6 +1185,17 @@ int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout)
|
||||
{
|
||||
bits256 addrhash;
|
||||
vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address));
|
||||
memcpy(&hashbuf[100],&addrhash,sizeof(addrhash));
|
||||
memcpy(&hashbuf[100+sizeof(addrhash)],&txid,sizeof(txid));
|
||||
memcpy(&hashbuf[100+sizeof(addrhash)+sizeof(txid)],&vout,sizeof(vout));
|
||||
vcalc_sha256(0,(uint8_t *)hashp,hashbuf,100 + (int32_t)sizeof(uint256)*2 + sizeof(vout));
|
||||
return(addrhash.uints[0]);
|
||||
}
|
||||
|
||||
uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr)
|
||||
{
|
||||
bool fNegative,fOverflow; uint8_t hashbuf[256]; char address[64]; bits256 addrhash; arith_uint256 hashval,mindiff,ratio,coinage256; uint256 hash,pasthash; int32_t diff=0,segid,minage,i,iter=0; uint32_t txtime,winner = 0 ; uint64_t value,coinage;
|
||||
@@ -1546,7 +1557,7 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
|
||||
int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
|
||||
{
|
||||
int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
|
||||
CTxDestination address; int32_t i,j,m,n,vout; uint8_t *script; uint256 txid,hashBlock; int64_t zfunds=0,vinsum=0,voutsum=0;
|
||||
n = pblock->vtx.size();
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
@@ -1571,10 +1582,17 @@ int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock)
|
||||
if ( (m= tx.vout.size()) > 0 )
|
||||
{
|
||||
for (j=0; j<m-1; j++)
|
||||
voutsum += tx.vout[j].nValue;
|
||||
{
|
||||
if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
|
||||
voutsum += tx.vout[j].nValue;
|
||||
else printf("skip %.8f -> %s\n",dstr(tx.vout[j].nValue),CBitcoinAddress(address).ToString().c_str());
|
||||
}
|
||||
script = (uint8_t *)tx.vout[j].scriptPubKey.data();
|
||||
if ( script == 0 || script[0] != 0x6a )
|
||||
voutsum += tx.vout[j].nValue;
|
||||
{
|
||||
if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 )
|
||||
voutsum += tx.vout[j].nValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
*zfundsp = zfunds;
|
||||
|
||||
@@ -4513,6 +4513,8 @@ UniValue z_listoperationids(const UniValue& params, bool fHelp)
|
||||
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
|
||||
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);
|
||||
int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n);
|
||||
|
||||
int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
|
||||
{
|
||||
@@ -4590,10 +4592,96 @@ 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));
|
||||
}
|
||||
kp = &array[(*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/COIN * diff);
|
||||
if ( nHeight >= 2500 && blocktime+iter+segid*2 > prevtime+180 )
|
||||
coinage *= ((blocktime+iter+segid*2) - (prevtime+60));
|
||||
coinage256 = arith_uint256(coinage+1);
|
||||
hashval = ratio * (kp->hashval / coinage256);
|
||||
if ( nHeight >= 900 && nHeight < 916 )
|
||||
hashval = (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 = 180; 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
set<CBitcoinAddress> setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector<COutput> vecOutputs; uint32_t eligible,earliest = 0; CScript best_scriptPubKey; arith_uint256 bnTarget; bool fNegative,fOverflow;
|
||||
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 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;
|
||||
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;
|
||||
@@ -4601,64 +4689,108 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
|
||||
memset(utxovoutp,0,sizeof(*utxovoutp));
|
||||
memset(utxosig,0,72);
|
||||
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs)
|
||||
if ( (tipindex= chainActive.Tip()) == 0 )
|
||||
return(0);
|
||||
nHeight = tipindex->nHeight + 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 )
|
||||
{
|
||||
if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
|
||||
if ( array != 0 )
|
||||
{
|
||||
//fprintf(stderr,"komodo_staked invalid depth %d\n",(int32_t)out.nDepth);
|
||||
continue;
|
||||
free(array);
|
||||
array = 0;
|
||||
maxkp = numkp = 0;
|
||||
lasttime = 0;
|
||||
}
|
||||
if ( setAddress.size() )
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs)
|
||||
{
|
||||
CTxDestination address;
|
||||
if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
|
||||
if ( (tipindex= chainActive.Tip()) == 0 || tipindex->nHeight+1 > nHeight )
|
||||
{
|
||||
fprintf(stderr,"komodo_staked ExtractDestination error\n");
|
||||
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;
|
||||
}
|
||||
if (!setAddress.count(address))
|
||||
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 )
|
||||
{
|
||||
fprintf(stderr,"komodo_staked setAddress.count error\n");
|
||||
if ( IsMine(*pwalletMain,address) == 0 )
|
||||
continue;
|
||||
if ( GetTransaction(out.tx->GetHash(),tx,hashBlock,true) != 0 && (pindex= mapBlockIndex[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
for (i=winners=0; i<numkp; i++)
|
||||
{
|
||||
if ( (tipindex= chainActive.Tip()) == 0 || tipindex->nHeight+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 < (uint32_t)tipindex->nTime-63 )
|
||||
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;
|
||||
}
|
||||
if ( IsMine(*pwalletMain, address) == 0 )
|
||||
continue;
|
||||
}
|
||||
CAmount nValue = out.tx->vout[out.i].nValue;
|
||||
if ( nValue < COIN || !out.fSpendable )
|
||||
continue;
|
||||
const CScript& pk = out.tx->vout[out.i].scriptPubKey;
|
||||
//entry.push_back(Pair("generated", out.tx->IsCoinBase()));
|
||||
CTxDestination address;
|
||||
if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
|
||||
{
|
||||
//entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
|
||||
//if (pwalletMain->mapAddressBook.count(address))
|
||||
// entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
|
||||
}
|
||||
//BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
|
||||
CBlockIndex *tipindex;
|
||||
if ( (tipindex= chainActive.Tip()) != 0 )
|
||||
{
|
||||
eligible = komodo_stake(0,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,0,(uint32_t)tipindex->nTime+27,(char *)CBitcoinAddress(address).ToString().c_str());
|
||||
if ( eligible > 0 )
|
||||
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)) )
|
||||
{
|
||||
if ( eligible != komodo_stake(1,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,eligible,(uint32_t)tipindex->nTime+27,(char *)CBitcoinAddress(address).ToString().c_str()) )
|
||||
{
|
||||
//fprintf(stderr,"tip.%d validation of winning blocktime failed %u -> eligible.%u\n",(uint32_t)tipindex->nHeight,*blocktimep,eligible);
|
||||
}
|
||||
else if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) )
|
||||
{
|
||||
earliest = eligible;
|
||||
best_scriptPubKey = out.tx->vout[out.i].scriptPubKey;
|
||||
*utxovaluep = (uint64_t)nValue;
|
||||
decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str());
|
||||
*utxovoutp = out.i;
|
||||
*txtimep = (uint32_t)out.tx->nLockTime;
|
||||
//fprintf(stderr,"ht.%d earliest.%u [%d] (%s) nValue %.8f locktime.%u\n",(uint32_t)tipindex->nHeight+1,earliest,(int32_t)(earliest- *blocktimep),CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,*txtimep);
|
||||
}
|
||||
} //else fprintf(stderr,"utxo not eligible\n");
|
||||
} //else fprintf(stderr,"no tipindex\n");
|
||||
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");
|
||||
} //else fprintf(stderr,"no tipindex\n");
|
||||
if ( numkp < 10000 && array != 0 )
|
||||
{
|
||||
free(array);
|
||||
array = 0;
|
||||
maxkp = numkp = 0;
|
||||
lasttime = 0;
|
||||
}
|
||||
if ( earliest != 0 )
|
||||
{
|
||||
@@ -4691,6 +4823,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
|
||||
*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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user