diff --git a/COPYING b/COPYING index c84bfb7aa..eecf5ccc8 100644 --- a/COPYING +++ b/COPYING @@ -1,3 +1,4 @@ +Copyright (c) 2016-2018 The Komodo developers Copyright (c) 2016-2017 The Zcash developers Copyright (c) 2009-2017 The Bitcoin Core developers diff --git a/README.md b/README.md index 5d85d013d..788635536 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It downloads and stores the entire history of Komodo transactions; depending on - Support: [https://support.komodoplatform.com/support/home](https://support.komodoplatform.com/support/home) - Knowledgebase & How-to: [https://komodoplatform.atlassian.net/wiki/spaces/KPSD/pages](https://komodoplatform.atlassian.net/wiki/spaces/KPSD/pages) - API references: [http://docs.supernet.org/](http://docs.supernet.org/) #Not up to date. -- Whitepaper: [Komodo Whitepaper](https://komodoplatform.com/wp-content/uploads/2018/03/2018-03-12-Komodo-White-Paper-Full.pdf) +- Whitepaper: [Komodo Whitepaper](https://komodoplatform.com/wp-content/uploads/2018/06/Komodo-Whitepaper-June-3.pdf) - Komodo Platform public material: [Komodo Platform public material](https://docs.google.com/document/d/1AbhWrtagu4vYdkl-vsWz-HSNyNvK-W-ZasHCqe7CZy0) ## List of Komodo Platform Technologies diff --git a/src/Makefile.test.include b/src/Makefile.test.include index ff270bd6a..a52b66335 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -45,7 +45,6 @@ BITCOIN_TESTS =\ test/arith_uint256_tests.cpp \ test/bignum.h \ test/addrman_tests.cpp \ - test/alert_tests.cpp \ test/allocator_tests.cpp \ test/base32_tests.cpp \ test/base58_tests.cpp \ diff --git a/src/chain.cpp b/src/chain.cpp index 7bb72d5d3..d79a66f9a 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -11,6 +11,7 @@ using namespace std; * CChain implementation */ void CChain::SetTip(CBlockIndex *pindex) { + lastTip = pindex; if (pindex == NULL) { vChain.clear(); return; diff --git a/src/chain.h b/src/chain.h index a28e4e44a..d882083e6 100644 --- a/src/chain.h +++ b/src/chain.h @@ -121,7 +121,7 @@ public: //! height of the entry in the chain. The genesis block has height 0 int nHeight; - + int64_t newcoins,zfunds; //! Which # file this block is stored in (blk?????.dat) int nFile; @@ -181,6 +181,7 @@ public: void SetNull() { phashBlock = NULL; + newcoins = zfunds = 0; pprev = NULL; pskip = NULL; nHeight = 0; @@ -321,6 +322,7 @@ public: //! Efficiently find an ancestor of this block. CBlockIndex* GetAncestor(int height); const CBlockIndex* GetAncestor(int height) const; + }; /** Used to marshal pointers into hashes for db storage. */ @@ -414,6 +416,7 @@ public: class CChain { private: std::vector vChain; + CBlockIndex *lastTip; public: /** Returns the index entry for the genesis block of this chain, or NULL if none. */ @@ -425,6 +428,11 @@ public: CBlockIndex *Tip() const { return vChain.size() > 0 ? vChain[vChain.size() - 1] : NULL; } + + /** Returns the last tip of the chain, or NULL if none. */ + CBlockIndex *LastTip() const { + return vChain.size() > 0 ? lastTip : NULL; + } /** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */ CBlockIndex *operator[](int nHeight) const { diff --git a/src/coins.cpp b/src/coins.cpp index b2d838506..38b105e9d 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -466,7 +466,7 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const const COutPoint &prevout = tx.vin[i].prevout; const CCoins* coins = AccessCoins(prevout.hash); if (!coins || !coins->IsAvailable(prevout.n)) { - fprintf(stderr,"HaveInputs missing input %s/v%d\n",prevout.hash.ToString().c_str(),prevout.n); + //fprintf(stderr,"HaveInputs missing input %s/v%d\n",prevout.hash.ToString().c_str(),prevout.n); return false; } } diff --git a/src/deprecation.h b/src/deprecation.h index 78ed8ebda..11eb69ef4 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -6,11 +6,11 @@ #define ZCASH_DEPRECATION_H // Deprecation policy: -// * Shut down 16 weeks' worth of blocks after the estimated release block height. -// * A warning is shown during the 2 weeks' worth of blocks prior to shut down. -static const int APPROX_RELEASE_HEIGHT = 800000; +// * Shut down WEEKS_UNTIL_DEPRECATION weeks' worth of blocks after the estimated release block height. +// * A warning is shown during the DEPRECATION_WARN_LIMIT worth of blocks prior to shut down. static const int WEEKS_UNTIL_DEPRECATION = 52; -static const int DEPRECATION_HEIGHT = APPROX_RELEASE_HEIGHT + (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 24); +static const int DEPRECATION_HEIGHT = 1400000; +static const int APPROX_RELEASE_HEIGHT = DEPRECATION_HEIGHT - (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 60); // Number of blocks before deprecation to warn users static const int DEPRECATION_WARN_LIMIT = 60 * 24 * 60; // 2 months diff --git a/src/init.cpp b/src/init.cpp index 1b8018b56..a9bdc6151 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1756,11 +1756,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) StartNode(threadGroup, scheduler); - // Monitor the chain, and alert if we get blocks much quicker or slower than expected - int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing; - CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload, - boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing); - scheduler.scheduleEvery(f, nPowTargetSpacing); #ifdef ENABLE_MINING // Generate coins in the background diff --git a/src/komodo.h b/src/komodo.h index ae0898ed3..e89dea2e4 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -823,7 +823,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) komodo_event_rewind(sp,symbol,pindex->nHeight); komodo_stateupdate(pindex->nHeight,0,0,0,zero,0,0,0,0,-pindex->nHeight,pindex->nTime,0,0,0,0,zero,0); } - komodo_currentheight_set(chainActive.Tip()->nHeight); + komodo_currentheight_set(chainActive.LastTip()->nHeight); if ( pindex != 0 ) { height = pindex->nHeight; @@ -907,7 +907,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) #else memcpy(scriptbuf,(uint8_t *)&block.vtx[i].vout[j].scriptPubKey[0],len); #endif - notaryid = komodo_voutupdate(&isratification,notaryid,scriptbuf,len,height,txhash,i,j,&voutmask,&specialtx,¬arizedheight,(uint64_t)block.vtx[i].vout[j].nValue,notarized,signedmask,(uint32_t)chainActive.Tip()->GetBlockTime()); + notaryid = komodo_voutupdate(&isratification,notaryid,scriptbuf,len,height,txhash,i,j,&voutmask,&specialtx,¬arizedheight,(uint64_t)block.vtx[i].vout[j].nValue,notarized,signedmask,(uint32_t)chainActive.LastTip()->GetBlockTime()); if ( 0 && i > 0 ) { for (k=0; knTime; + else txtime = tx.nLockTime; + //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); + if ( n < tx.vout.size() ) + { + *valuep = tx.vout[n].nValue; + if (ExtractDestination(tx.vout[n].scriptPubKey, address)) + strcpy(destaddr,CBitcoinAddress(address).ToString().c_str()); + } + return(txtime); +} + +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; + if ( ASSETCHAINS_STAKED != 0 ) + { + 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"); + return(1); + } + } + } + } + return(0); +} + void komodo_disconnect(CBlockIndex *pindex,CBlock& block) { char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; @@ -701,8 +751,8 @@ int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex) uint32_t komodo_chainactive_timestamp() { - if ( chainActive.Tip() != 0 ) - return((uint32_t)chainActive.Tip()->GetBlockTime()); + if ( chainActive.LastTip() != 0 ) + return((uint32_t)chainActive.LastTip()->GetBlockTime()); else return(0); } @@ -710,11 +760,11 @@ CBlockIndex *komodo_chainactive(int32_t height) { if ( chainActive.Tip() != 0 ) { - if ( height <= chainActive.Tip()->nHeight ) + if ( height <= chainActive.LastTip()->nHeight ) return(chainActive[height]); - // else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.Tip()->nHeight); + // else fprintf(stderr,"komodo_chainactive height %d > active.%d\n",height,chainActive.LastTip()->nHeight); } - //fprintf(stderr,"komodo_chainactive null chainActive.Tip() height %d\n",height); + //fprintf(stderr,"komodo_chainactive null chainActive.LastTip() height %d\n",height); return(0); } @@ -944,7 +994,7 @@ int32_t komodo_MoM(int32_t *notarized_heightp,uint256 *MoMp,uint256 *kmdtxidp,in int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash) { int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex; - if ( (pindex= chainActive.Tip()) == 0 ) + if ( (pindex= chainActive.LastTip()) == 0 ) return(-1); notarized_height = komodo_notarizeddata(pindex->nHeight,¬arized_hash,¬arized_desttxid); *notarized_heightp = notarized_height; @@ -986,7 +1036,7 @@ uint32_t komodo_interest_args(uint32_t *txheighttimep,int32_t *txheightp,uint32_ *valuep = tx.vout[n].nValue; *txheightp = pindex->nHeight; *txheighttimep = pindex->nTime; - if ( *tiptimep == 0 && (tipindex= chainActive.Tip()) != 0 ) + if ( *tiptimep == 0 && (tipindex= chainActive.LastTip()) != 0 ) *tiptimep = (uint32_t)tipindex->nTime; locktime = tx.nLockTime; //fprintf(stderr,"tx locktime.%u %.8f height.%d | tiptime.%u\n",locktime,(double)*valuep/COIN,*txheightp,*tiptimep); @@ -1019,18 +1069,18 @@ int32_t komodo_isrealtime(int32_t *kmdheightp) if ( (sp= komodo_stateptrget((char *)"KMD")) != 0 ) *kmdheightp = sp->CURRENT_HEIGHT; else *kmdheightp = 0; - if ( (pindex= chainActive.Tip()) != 0 && pindex->nHeight >= (int32_t)komodo_longestchain() ) + if ( (pindex= chainActive.LastTip()) != 0 && pindex->nHeight >= (int32_t)komodo_longestchain() ) return(1); else return(0); } int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t cmptime,int32_t dispflag) { - if ( KOMODO_REWIND == 0 && ASSETCHAINS_SYMBOL[0] == 0 && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 ) + if ( KOMODO_REWIND == 0 && (ASSETCHAINS_SYMBOL[0] == 0 || ASSETCHAINS_STAKED != 0) && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 ) { - if ( txheight > 246748 ) + if ( txheight > 246748 || ASSETCHAINS_STAKED != 0 ) { - if ( txheight < 247205 ) + if ( txheight < 247205 && ASSETCHAINS_STAKED == 0 ) cmptime -= 16000; if ( (int64_t)tx.nLockTime < cmptime-KOMODO_MAXMEMPOOLTIME ) { @@ -1054,9 +1104,8 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ commission must be in coinbase.vout[1] and must be >= 10000 sats PoS stake must be without txfee and in the last tx in the block at vout[0] - PoW mining on PoS chain must solve a harder diff that adjusts, but never less than KOMODO_POWMINMULT */ -#define KOMODO_POWMINMULT 16 +//#define KOMODO_POWMINMULT 16 uint64_t komodo_commission(const CBlock *pblock) { @@ -1086,76 +1135,152 @@ uint32_t komodo_segid32(char *coinaddr) 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) +int8_t komodo_segid(int32_t height) { - CBlockIndex *pindex; bool fNegative,fOverflow; uint8_t hashbuf[128]; char address[64]; bits256 addrhash; arith_uint256 hashval; uint256 hash,pasthash; int64_t diff=0; int32_t segid,minage,i,iter=0; uint32_t txtime,winner = 0; arith_uint256 bnMaxPoSdiff; uint64_t value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; - txtime = komodo_txtime(&value,txid,vout,address); - if ( blocktime < prevtime+57 ) - blocktime = prevtime+57; - if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 ) + CTxDestination voutaddress; CBlock block; CBlockIndex *pindex; uint64_t value; uint32_t txtime; char voutaddr[64],destaddr[64]; int32_t txn_count,vout; uint256 txid; int8_t segid = -1; + if ( height > 0 && (pindex= komodo_chainactive(height)) != 0 ) { - fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime); - return(0); - } - bnMaxPoSdiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); - bnMaxPoSdiff = (bnMaxPoSdiff / arith_uint256(4)); - if ( bnTarget < bnMaxPoSdiff ) - bnTarget = bnMaxPoSdiff; - if ( (minage= nHeight*3) > 6000 ) // about 100 blocks - minage = 6000; - pindex = 0; - if ( (pindex= komodo_chainactive(nHeight>50?nHeight-50:1)) != 0 ) - { - vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address)); - segid = ((nHeight + addrhash.uints[0]) & 0x3f); - pasthash = pindex->GetBlockHash(); - memcpy(hashbuf,&pasthash,sizeof(pasthash)); - memcpy(&hashbuf[sizeof(pasthash)],&addrhash,sizeof(addrhash)); - vcalc_sha256(0,(uint8_t *)&hash,hashbuf,(int32_t)sizeof(uint256)*2); - //fprintf(stderr,"(%s) vs. (%s) %s %.8f txtime.%u\n",address,destaddr,hash.ToString().c_str(),dstr(value),txtime); - for (iter=0; iter<3600; iter++) + if ( komodo_blockload(block,pindex) == 0 ) { - diff = (iter + blocktime - txtime - minage); - if ( iter > 0 ) - diff += iter + segid*2; - //if ( diff > 3600*24 ) - // break; - if ( blocktime+iter+segid*2 < txtime+minage ) - continue; - coinage = (value * diff) * ((diff >> 16) + 1); - hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); - if ( hashval <= bnTarget ) + txn_count = block.vtx.size(); + if ( txn_count > 1 && block.vtx[txn_count-1].vin.size() == 1 && block.vtx[txn_count-1].vout.size() == 1 ) { - winner = 1; - if ( validateflag == 0 ) + txid = block.vtx[txn_count-1].vin[0].prevout.hash; + vout = block.vtx[txn_count-1].vin[0].prevout.n; + txtime = komodo_txtime(&value,txid,vout,destaddr); + if ( ExtractDestination(block.vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) ) { - blocktime += iter; - blocktime += segid * 2; - } - break; - } - if ( validateflag != 0 ) - { - /*for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); - fprintf(stderr," vs target "); - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(int32_t)diff);*/ - break; + strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str()); + if ( strcmp(destaddr,voutaddr) == 0 && block.vtx[txn_count-1].vout[0].nValue == value ) + { + segid = komodo_segid32(voutaddr) & 0x3f; + } + } else fprintf(stderr,"komodo_segid ht.%d couldnt extract voutaddress\n",height); } } - //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); - if ( 0 ) + } + return(segid); +} + +int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n) +{ + static uint8_t prevhashbuf[100]; static int32_t prevheight; + int32_t i; + if ( height == prevheight && n == 100 ) + memcpy(hashbuf,prevhashbuf,100); + else + { + memset(hashbuf,0xff,n); + for (i=0; i=24; i--) + hashbuf[i] = (uint8_t)komodo_segid(height+i); + //fprintf(stderr,"%02x ",hashbuf[i]); + } + if ( n == 100 ) + { + memcpy(prevhashbuf,hashbuf,100); + prevheight = height; + //fprintf(stderr,"prevsegids.%d\n",height+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; + txtime = komodo_txtime2(&value,txid,vout,address); + if ( validateflag == 0 ) + { + //fprintf(stderr,"blocktime.%u -> ",blocktime); + if ( blocktime < prevtime+3 ) + blocktime = prevtime+3; + if ( blocktime < GetAdjustedTime()-60 ) + blocktime = GetAdjustedTime()+30; + //fprintf(stderr,"blocktime.%u txtime.%u\n",blocktime,txtime); + } + if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 ) + { + //fprintf(stderr,"komodo_stake null %.8f %u %u %u\n",dstr(value),txtime,blocktime,prevtime); + return(0); + } + if ( value < SATOSHIDEN ) + return(0); + value /= SATOSHIDEN; + mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + ratio = (mindiff / bnTarget); + if ( (minage= nHeight*3) > 6000 ) // about 100 blocks + minage = 6000; + vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address)); + segid = ((nHeight + addrhash.uints[0]) & 0x3f); + komodo_segids(hashbuf,nHeight-101,100); + 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 *)&hash,hashbuf,100 + (int32_t)sizeof(uint256)*2 + sizeof(vout)); + for (iter=0; iter<180; iter++) + { + if ( blocktime+iter+segid*2 < txtime+minage ) + continue; + diff = (iter + blocktime - txtime - minage); + if ( diff < 0 ) + diff = 60; + else if ( diff > 3600*24*30 ) + { + //printf("diff.%d (iter.%d blocktime.%u txtime.%u minage.%d)\n",(int32_t)diff,iter,blocktime,txtime,(int32_t)minage); + diff = 3600*24*30; + } + if ( iter > 0 ) + diff += segid*2; + coinage = (value * diff); + if ( nHeight >= 2500 && blocktime+iter+segid*2 > prevtime+180 ) + coinage *= ((blocktime+iter+segid*2) - (prevtime+60)); + coinage256 = arith_uint256(coinage+1); + hashval = ratio * (UintToArith256(hash) / coinage256); + if ( nHeight >= 900 && nHeight < 916 ) + hashval = (hashval / coinage256); + if ( hashval <= bnTarget ) + { + winner = 1; + if ( validateflag == 0 ) + { + //fprintf(stderr,"winner blocktime.%u iter.%d segid.%d\n",blocktime,iter,segid); + blocktime += iter; + blocktime += segid * 2; + } + break; + } + if ( validateflag != 0 ) + { + /*for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); fprintf(stderr," vs "); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u %.8f diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,dstr(value),(int32_t)diff); + fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff);*/ + break; } - } //else fprintf(stderr,"skip PoS scan: diff %d blocktime %u > %u txtime+minage %u pindex.%p\n",(int32_t)(blocktime - (txtime+minage)),blocktime,txtime,minage,pindex); + } + //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); + if ( 0 && validateflag != 0 ) + { + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); + fprintf(stderr," vs "); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u v%d diff.%d ht.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,(int32_t)value,(int32_t)diff,nHeight); + } if ( nHeight < 10 ) return(blocktime); return(blocktime * winner); @@ -1163,18 +1288,36 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc) { - CBlockIndex *pindex; arith_uint256 bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,ht,percPoS,diff,val; + CBlockIndex *pindex; arith_uint256 easydiff,bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,m,ht,percPoS,diff,val; *percPoSp = percPoS = 0; if ( height <= 10 || (ASSETCHAINS_STAKED == 100 && height <= 100) ) return(target); sum = arith_uint256(0); ave = sum; - for (i=n=0; i<100; i++) + easydiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + for (i=n=m=0; i<100; i++) { ht = height - 100 + i; if ( ht <= 1 ) continue; if ( (pindex= komodo_chainactive(ht)) != 0 ) + { + if ( komodo_segid(ht) >= 0 ) + { + n++; + percPoS++; + if ( ASSETCHAINS_STAKED < 100 ) + fprintf(stderr,"0"); + } + else + { + if ( ASSETCHAINS_STAKED < 100 ) + fprintf(stderr,"1"); + sum += UintToArith256(pindex->GetBlockHash()); + m++; + } + } + /*if ( (pindex= komodo_chainactive(ht)) != 0 ) { bnTarget.SetCompact(pindex->nBits,&fNegative,&fOverflow); bnTarget = (bnTarget / arith_uint256(KOMODO_POWMINMULT)); @@ -1188,26 +1331,27 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he } else { + n++; percPoS++; if ( ASSETCHAINS_STAKED < 100 ) fprintf(stderr,"0"); } - if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 ) - fprintf(stderr," %d, ",percPoS); - } + }*/ + if ( ASSETCHAINS_STAKED < 100 && (i % 10) == 9 ) + fprintf(stderr," %d, ",percPoS); } - if ( n < 100 ) + if ( m+n < 100 ) percPoS = ((percPoS * n) + (goalperc * (100-n))) / 100; if ( ASSETCHAINS_STAKED < 100 ) fprintf(stderr," -> %d%% percPoS vs goalperc.%d ht.%d\n",percPoS,goalperc,height); *percPoSp = percPoS; - target = (target / arith_uint256(KOMODO_POWMINMULT)); - if ( n > 0 ) + //target = (target / arith_uint256(KOMODO_POWMINMULT)); + if ( m > 0 ) { - ave = (sum / arith_uint256(n)); + ave = (sum / arith_uint256(m)); if ( ave > target ) ave = target; - } else return(target); + } else ave = easydiff; //else return(target); if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget { bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc); @@ -1226,7 +1370,15 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he } else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget { - bnTarget = ((ave * arith_uint256(goalperc)) + (target * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc); + bnTarget = (ave * arith_uint256(percPoS * percPoS * percPoS)) / arith_uint256(goalperc * goalperc); + if ( bnTarget > easydiff ) + bnTarget = easydiff; + else if ( bnTarget < ave ) // overflow + { + bnTarget = ((ave * arith_uint256(goalperc)) + (easydiff * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc); + if ( bnTarget < ave ) + bnTarget = ave; + } if ( 1 ) { for (i=31; i>=24; i--) @@ -1246,9 +1398,11 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_uint256 bnTarget) { - CBlockIndex *previndex; char voutaddr[64],destaddr[64]; uint256 txid; uint32_t txtime,prevtime=0; int32_t vout,txn_count,eligible,isPoS = 0; uint64_t value; CTxDestination voutaddress; + CBlockIndex *previndex; char voutaddr[64],destaddr[64]; uint256 txid; uint32_t txtime,prevtime=0; int32_t vout,txn_count,eligible=0,isPoS = 0; uint64_t value; CTxDestination voutaddress; + if ( ASSETCHAINS_STAKED == 100 && height <= 10 ) + return(1); txn_count = pblock->vtx.size(); - if ( txn_count > 1 ) + if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 ) { if ( prevtime == 0 ) { @@ -1259,24 +1413,29 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_ vout = pblock->vtx[txn_count-1].vin[0].prevout.n; if ( prevtime != 0 ) { - eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime,(char *)""); + if ( komodo_isPoS(pblock) != 0 ) + eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)""); if ( eligible == 0 || eligible > pblock->nTime ) { - fprintf(stderr,"komodo_is_PoSblock PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d -> check to see if it is PoW block\n",height,eligible,(uint32_t)pblock->nTime,(int32_t)(eligible - pblock->nTime)); + if ( ASSETCHAINS_STAKED < 100 ) + fprintf(stderr,"komodo_is_PoSblock PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d -> check to see if it is PoW block\n",height,eligible,(uint32_t)pblock->nTime,(int32_t)(eligible - pblock->nTime)); } else isPoS = 1; } - else if ( slowflag == 0 ) // maybe previous block is not seen yet, do the best approx + if ( slowflag == 0 ) // maybe previous block is not seen yet, do the best approx { - txtime = komodo_txtime(&value,txid,vout,destaddr); + if ( komodo_isPoS(pblock) != 0 ) + isPoS = 1; + /*txtime = komodo_txtime(&value,txid,vout,destaddr); if ( ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) ) { strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str()); if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[txn_count-1].vout[0].nValue == value ) isPoS = 1; // close enough for a pre-filter - else fprintf(stderr,"komodo_is_PoSblock ht.%d (%s) != (%s) or %.8f != %.8f\n",height,destaddr,voutaddr,dstr(value),dstr(pblock->vtx[txn_count-1].vout[0].nValue)); - } else fprintf(stderr,"komodo_is_PoSblock ht.%d couldnt extract voutaddress\n",height); - } else return(-1); + //else fprintf(stderr,"komodo_is_PoSblock ht.%d (%s) != (%s) or %.8f != %.8f\n",height,destaddr,voutaddr,dstr(value),dstr(pblock->vtx[txn_count-1].vout[0].nValue)); + } else fprintf(stderr,"komodo_is_PoSblock ht.%d couldnt extract voutaddress\n",height);*/ + } //else return(-1); } + //fprintf(stderr,"slow.%d ht.%d isPoS.%d\n",slowflag,height,isPoS); return(isPoS); } @@ -1344,23 +1503,24 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height) } else if ( possible == 0 || ASSETCHAINS_SYMBOL[0] != 0 ) { - if (KOMODO_TEST_ASSETCHAIN_SKIP_POW) return(0); - fprintf(stderr,"pow violation and no chance it is notary ht.%d %s\n",height,hash.ToString().c_str()); - return(-1); + if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW ) + return(0); + if ( ASSETCHAINS_STAKED == 0 ) // komodo_is_PoSblock will check bnTarget + return(-1); } } - else if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW + if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW { if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget)) == 0 ) { - if ( ASSETCHAINS_STAKED == 100 && height > 100 ) // only PoS allowed! + if ( ASSETCHAINS_STAKED == 100 && height > 100 ) // only PoS allowed! POSTEST64 return(-1); else { + if ( slowflag == 0 ) // need all past 100 blocks to calculate PoW target + return(0); if ( slowflag != 0 ) bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED); - else if ( height > 100 ) - bnTarget = (bnTarget / arith_uint256(KOMODO_POWMINMULT)); // lower bound if ( bhash > bnTarget ) { for (i=31; i>=16; i--) @@ -1395,3 +1555,79 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height) else return(0); } +int64_t komodo_newcoins(int64_t *zfundsp,int32_t nHeight,CBlock *pblock) +{ + 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; ivtx[i]; + zfunds += (tx.GetJoinSplitValueOut() - tx.GetJoinSplitValueIn()); + if ( (m= tx.vin.size()) > 0 ) + { + for (j=0; j= vintx.vout.size() ) + { + fprintf(stderr,"ERROR: %s/v%d cant find\n",txid.ToString().c_str(),vout); + return(0); + } + vinsum += vintx.vout[vout].nValue; + } + } + if ( (m= tx.vout.size()) > 0 ) + { + for (j=0; j %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 ) + { + if ( ExtractDestination(tx.vout[j].scriptPubKey,address) != 0 && strcmp("RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY",CBitcoinAddress(address).ToString().c_str()) != 0 ) + voutsum += tx.vout[j].nValue; + } + } + } + *zfundsp = zfunds; + if ( ASSETCHAINS_SYMBOL[0] == 0 && (voutsum-vinsum) == 100003*SATOSHIDEN ) // 15 times + return(3 * SATOSHIDEN); + //if ( voutsum-vinsum+zfunds > 100000*SATOSHIDEN || voutsum-vinsum+zfunds < 0 ) + //. fprintf(stderr,"ht.%d vins %.8f, vouts %.8f -> %.8f zfunds %.8f\n",nHeight,dstr(vinsum),dstr(voutsum),dstr(voutsum)-dstr(vinsum),dstr(zfunds)); + return(voutsum - vinsum); +} + +int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height) +{ + CBlockIndex *pindex; CBlock block; int64_t zfunds=0,supply = 0; + //fprintf(stderr,"coinsupply %d\n",height); + *zfundsp = 0; + if ( (pindex= komodo_chainactive(height)) != 0 ) + { + while ( pindex != 0 && pindex->nHeight > 0 ) + { + if ( pindex->newcoins == 0 && pindex->zfunds == 0 ) + { + if ( komodo_blockload(block,pindex) == 0 ) + pindex->newcoins = komodo_newcoins(&pindex->zfunds,pindex->nHeight,&block); + else + { + fprintf(stderr,"error loading block.%d\n",pindex->nHeight); + return(0); + } + } + supply += pindex->newcoins; + zfunds += pindex->zfunds; + //printf("start ht.%d new %.8f -> supply %.8f zfunds %.8f -> %.8f\n",pindex->nHeight,dstr(pindex->newcoins),dstr(supply),dstr(pindex->zfunds),dstr(zfunds)); + pindex = pindex->pprev; + } + } + *zfundsp = zfunds; + return(supply); +} diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 9de6b4fc9..6a8ef310b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1490,7 +1490,7 @@ void komodo_passport_iteration() komodo_statefname(fname,baseid<32?base:(char *)"",(char *)"realtime"); if ( (fp= fopen(fname,"wb")) != 0 ) { - buf[0] = (uint32_t)chainActive.Tip()->nHeight; + buf[0] = (uint32_t)chainActive.LastTip()->nHeight; buf[1] = (uint32_t)komodo_longestchain(); if ( buf[0] != 0 && buf[0] == buf[1] ) { diff --git a/src/komodo_globals.h b/src/komodo_globals.h index c46486430..8dfc7108c 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -52,7 +52,7 @@ uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_PUBLIC char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096]; uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; -uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC; +uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC,KOMODO_STOPAT; uint32_t ASSETCHAINS_MAGIC = 2387029918; uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE; uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_DECAY,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10; diff --git a/src/komodo_jumblr.h b/src/komodo_jumblr.h index f36bb441a..fa44425fd 100755 --- a/src/komodo_jumblr.h +++ b/src/komodo_jumblr.h @@ -648,7 +648,7 @@ void jumblr_iteration() free(retstr); } } - height = (int32_t)chainActive.Tip()->nHeight; + height = (int32_t)chainActive.LastTip()->nHeight; if ( time(NULL) < lasttime+40 ) return; lasttime = (uint32_t)time(NULL); diff --git a/src/komodo_pax.h b/src/komodo_pax.h index d0bad0e14..35d226fc3 100644 --- a/src/komodo_pax.h +++ b/src/komodo_pax.h @@ -637,13 +637,13 @@ uint64_t komodo_paxpriceB(uint64_t seed,int32_t height,char *base,char *rel,uint uint64_t komodo_paxprice(uint64_t *seedp,int32_t height,char *base,char *rel,uint64_t basevolume) { int32_t i,nonz=0; int64_t diff; uint64_t price,seed,sum = 0; - if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.Tip() != 0 && height > chainActive.Tip()->nHeight ) + if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.LastTip() != 0 && height > chainActive.LastTip()->nHeight ) { if ( height < 100000000 ) { static uint32_t counter; if ( counter++ < 3 ) - printf("komodo_paxprice height.%d vs tip.%d\n",height,chainActive.Tip()->nHeight); + printf("komodo_paxprice height.%d vs tip.%d\n",height,chainActive.LastTip()->nHeight); } return(0); } diff --git a/src/komodo_utils.h b/src/komodo_utils.h index f61fd05ea..8188a6154 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1539,6 +1539,7 @@ void komodo_args(char *argv0) } } } + KOMODO_STOPAT = GetArg("-stopat",0); ASSETCHAINS_CC = GetArg("-ac_cc",0); ASSETCHAINS_PUBLIC = GetArg("-ac_public",0); ASSETCHAINS_PRIVATE = GetArg("-ac_private",0); diff --git a/src/main.cpp b/src/main.cpp index 8d1649d3b..330bf6ad1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1104,7 +1104,7 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio if ( ASSETCHAINS_PRIVATE != 0 ) { fprintf(stderr,"private chain nValue %.8f iscoinbase.%d\n",(double)txout.nValue/COIN,iscoinbase); - if ( txout.nValue > 0 && iscoinbase == 0 ) + if ( (txout.nValue > 0 && iscoinbase == 0) || tx.GetJoinSplitValueOut() > 0 ) return state.DoS(100, error("CheckTransaction(): this is a private chain, no public allowed"),REJECT_INVALID, "bad-txns-acprivacy-chain"); } nValueOut += txout.nValue; @@ -1269,7 +1269,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } auto verifier = libzcash::ProofVerifier::Strict(); - if ( komodo_validate_interest(tx,chainActive.Tip()->nHeight+1,chainActive.Tip()->GetMedianTimePast() + 777,0) < 0 ) + if ( komodo_validate_interest(tx,chainActive.LastTip()->nHeight+1,chainActive.LastTip()->GetMedianTimePast() + 777,0) < 0 ) { //fprintf(stderr,"AcceptToMemoryPool komodo_validate_interest failure\n"); return error("AcceptToMemoryPool: komodo_validate_interest failed"); @@ -1311,7 +1311,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa uint256 hash = tx.GetHash(); if (pool.exists(hash)) { - fprintf(stderr,"already in mempool\n"); + //fprintf(stderr,"already in mempool\n"); return state.Invalid(false, REJECT_DUPLICATE, "already in mempool"); } @@ -1399,7 +1399,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Bring the best block into scope view.GetBestBlock(); - nValueIn = view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime); + nValueIn = view.GetValueIn(chainActive.LastTip()->nHeight,&interest,tx,chainActive.LastTip()->nTime); if ( 0 && interest != 0 ) fprintf(stderr,"add interest %.8f\n",(double)interest/COIN); // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool @@ -1891,7 +1891,7 @@ void CheckForkWarningConditions() if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 288) pindexBestForkTip = NULL; - if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6))) + if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.LastTip()->nChainWork + (GetBlockProof(*chainActive.LastTip()) * 6))) { if (!fLargeWorkForkFound && pindexBestForkBase) { @@ -1926,7 +1926,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) AssertLockHeld(cs_main); // If we are on a fork that is sufficiently large, set a warning flag CBlockIndex* pfork = pindexNewForkTip; - CBlockIndex* plonger = chainActive.Tip(); + CBlockIndex* plonger = chainActive.LastTip(); while (pfork && pfork != plonger) { while (plonger && plonger->nHeight > pfork->nHeight) @@ -1983,7 +1983,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew) pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexNew->GetBlockTime())); - CBlockIndex *tip = chainActive.Tip(); + CBlockIndex *tip = chainActive.LastTip(); assert (tip); LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__, tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0), @@ -2111,14 +2111,14 @@ namespace Consensus { // Check for negative or overflow input values nValueIn += coins->vout[prevout.n].nValue; #ifdef KOMODO_ENABLE_INTEREST - if ( ASSETCHAINS_SYMBOL[0] == 0 && nSpendHeight > 60000 )//chainActive.Tip() != 0 && chainActive.Tip()->nHeight >= 60000 ) + if ( ASSETCHAINS_SYMBOL[0] == 0 && nSpendHeight > 60000 )//chainActive.LastTip() != 0 && chainActive.LastTip()->nHeight >= 60000 ) { if ( coins->vout[prevout.n].nValue >= 10*COIN ) { int64_t interest; int32_t txheight; uint32_t locktime; if ( (interest= komodo_accrued_interest(&txheight,&locktime,prevout.hash,prevout.n,0,coins->vout[prevout.n].nValue,(int32_t)nSpendHeight-1)) != 0 ) { - //fprintf(stderr,"checkResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueIn/COIN,(double)coins->vout[prevout.n].nValue/COIN,(double)interest/COIN,txheight,locktime,chainActive.Tip()->nTime); + //fprintf(stderr,"checkResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueIn/COIN,(double)coins->vout[prevout.n].nValue/COIN,(double)interest/COIN,txheight,locktime,chainActive.LastTip()->nTime); nValueIn += interest; } } @@ -2691,7 +2691,8 @@ static int64_t nTimeTotal = 0; bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck,bool fCheckPOW) { const CChainParams& chainparams = Params(); - + if ( KOMODO_STOPAT != 0 && pindex->nHeight > KOMODO_STOPAT ) + return(false); //fprintf(stderr,"connectblock ht.%d\n",(int32_t)pindex->nHeight); AssertLockHeld(cs_main); bool fExpensiveChecks = true; @@ -2867,7 +2868,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (!tx.IsCoinBase()) { - nFees += view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime) - tx.GetValueOut(); + nFees += view.GetValueIn(chainActive.LastTip()->nHeight,&interest,tx,chainActive.LastTip()->nTime) - tx.GetValueOut(); sum += interest; std::vector vChecks; @@ -3194,10 +3195,19 @@ void static UpdateTip(CBlockIndex *pindexNew) { nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); KOMODO_NEWBLOCKS++; + double progress; + if ( ASSETCHAINS_SYMBOL[0] == 0 ) { + progress = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.LastTip()); + } else { + int32_t longestchain = komodo_longestchain(); + progress = (longestchain > 0 ) ? (double) chainActive.Height() / longestchain : 1.0; + } + LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); + chainActive.LastTip()->GetBlockHash().ToString(), chainActive.Height(), + log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.LastTip()->nChainTx, + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.LastTip()->GetBlockTime()), progress, + pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); cvBlockChange.notify_all(); @@ -3252,13 +3262,17 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) return false; - if (!fBare) { + if (!fBare) + { // Resurrect mempool transactions from the disconnected block. - BOOST_FOREACH(const CTransaction &tx, block.vtx) { + //BOOST_FOREACH(const CTransaction &tx, block.vtx) { + for (int i = 0; i < block.vtx.size(); i++) + { + CTransaction &tx = block.vtx[i]; // ignore validation errors in resurrected transactions list removed; CValidationState stateDummy; - if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) + if (tx.IsCoinBase() || ((i == (block.vtx.size() - 1)) && komodo_isPoS((CBlock *)&block) != 0) || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) mempool.remove(tx, removed, true); } if (anchorBeforeDisconnect != anchorAfterDisconnect) { @@ -3275,11 +3289,23 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { assert(pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), newTree)); // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - SyncWithWallets(tx, NULL); - } + //BOOST_FOREACH(const CTransaction &tx, block.vtx) { + // SyncWithWallets(tx, NULL); + //} // Update cached incremental witnesses //fprintf(stderr,"chaintip false\n"); + for (int i = 0; i < block.vtx.size(); i++) + { + CTransaction &tx = block.vtx[i]; + if ( (i == (block.vtx.size() - 1)) && komodo_isPoS((CBlock *)&block) != 0 ) + { + EraseFromWallets(tx.GetHash()); + } + else + { + SyncWithWallets(tx, NULL); + } + } GetMainSignals().ChainTip(pindexDelete, &block, newTree, false); return true; } @@ -3429,7 +3455,7 @@ static void PruneBlockIndexCandidates() { // Note that we can't delete the current block itself, as we may need to return to it later in case a // reorganization to a better block fails. std::set::iterator it = setBlockIndexCandidates.begin(); - while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) { + while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, chainActive.LastTip())) { setBlockIndexCandidates.erase(it++); } // Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates. @@ -3481,8 +3507,8 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo if ( KOMODO_REWIND != 0 ) { CBlockIndex *tipindex; - fprintf(stderr,">>>>>>>>>>> rewind start ht.%d -> KOMODO_REWIND.%d\n",chainActive.Tip()->nHeight,KOMODO_REWIND); - while ( KOMODO_REWIND > 0 && (tipindex= chainActive.Tip()) != 0 && tipindex->nHeight > KOMODO_REWIND ) + fprintf(stderr,">>>>>>>>>>> rewind start ht.%d -> KOMODO_REWIND.%d\n",chainActive.LastTip()->nHeight,KOMODO_REWIND); + while ( KOMODO_REWIND > 0 && (tipindex= chainActive.LastTip()) != 0 && tipindex->nHeight > KOMODO_REWIND ) { fBlocksDisconnected = true; fprintf(stderr,"%d ",(int32_t)tipindex->nHeight); @@ -3896,9 +3922,9 @@ bool CheckBlockHeader(int32_t *futureblockp,int32_t height,CBlockIndex *pindex, for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&hash)[i]); fprintf(stderr," <- CheckBlockHeader\n"); - if ( chainActive.Tip() != 0 ) + if ( chainActive.LastTip() != 0 ) { - hash = chainActive.Tip()->GetBlockHash(); + hash = chainActive.LastTip()->GetBlockHash(); for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&hash)[i]); fprintf(stderr," <- chainTip\n"); @@ -4077,8 +4103,13 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta // Don't accept any forks from the main chain prior to last checkpoint CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints()); int32_t notarized_height; - if ( nHeight == 1 && chainActive.Tip() != 0 && chainActive.Tip()->nHeight > 1 ) - return(false); + if ( nHeight == 1 && chainActive.LastTip() != 0 && chainActive.LastTip()->nHeight > 1 ) + { + CBlockIndex *heightblock = chainActive[nHeight]; + if ( heightblock != 0 && heightblock->GetBlockHash() == hash ) + return true; + return state.DoS(1, error("%s: trying to change height 1 forbidden", __func__)); + } if ( nHeight != 0 ) { if ( pcheckpoint != 0 && nHeight < pcheckpoint->nHeight ) @@ -4409,8 +4440,8 @@ bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNo auto verifier = libzcash::ProofVerifier::Disabled(); hash = pblock->GetHash(); - if ( chainActive.Tip() != 0 ) - komodo_currentheight_set(chainActive.Tip()->nHeight); + if ( chainActive.LastTip() != 0 ) + komodo_currentheight_set(chainActive.LastTip()->nHeight); checked = CheckBlock(&futureblock,height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier,0); { LOCK(cs_main); @@ -4828,11 +4859,21 @@ bool static LoadBlockIndexDB() it->second->hashAnchorEnd = pcoinsTip->GetBestAnchor(); PruneBlockIndexCandidates(); + + double progress; + if ( ASSETCHAINS_SYMBOL[0] == 0 ) { + progress = Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.Tip()); + } else { + int32_t longestchain = komodo_longestchain(); + // TODO: komodo_longestchain does not have the data it needs at the time LoadBlockIndexDB + // runs, which makes it return 0, so we guess 50% for now + progress = (longestchain > 0 ) ? (double) chainActive.Height() / longestchain : 0.5; + } LogPrintf("%s: hashBestChain=%s height=%d date=%s progress=%f\n", __func__, - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.Tip())); + chainActive.LastTip()->GetBlockHash().ToString(), chainActive.Height(), + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.LastTip()->GetBlockTime()), + progress); EnforceNodeDeprecation(chainActive.Height(), true); diff --git a/src/metrics.cpp b/src/metrics.cpp index 6c8f80fe5..cb9fe245c 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -211,7 +211,7 @@ int printStats(bool mining) { LOCK2(cs_main, cs_vNodes); height = chainActive.Height(); - tipmediantime = chainActive.Tip()->GetMedianTimePast(); + tipmediantime = chainActive.LastTip()->GetMedianTimePast(); connections = vNodes.size(); netsolps = GetNetworkHashPS(120, -1); } diff --git a/src/miner.cpp b/src/miner.cpp index 755b7439e..0c458a985 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -117,11 +117,7 @@ uint32_t Mining_start,Mining_height; int32_t My_notaryid = -1; int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp); int32_t komodo_pax_opreturn(int32_t height,uint8_t *opret,int32_t maxsize); -//uint64_t komodo_paxtotal(); int32_t komodo_baseid(char *origbase); -//int32_t komodo_is_issuer(); -//int32_t komodo_gateway_deposits(CMutableTransaction *txNew,char *symbol,int32_t tokomodo); -//int32_t komodo_isrealtime(int32_t *kmdheightp); int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag); uint64_t komodo_commission(const CBlock *block); 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); @@ -140,29 +136,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,int32_t gpucount) return NULL; } CBlock *pblock = &pblocktemplate->block; // pointer for convenience - /*if ( ASSETCHAINS_SYMBOL[0] != 0 && komodo_baseid(ASSETCHAINS_SYMBOL) >= 0 && chainActive.Tip()->nHeight >= ASSETCHAINS_MINHEIGHT ) - { - isrealtime = komodo_isrealtime(&kmdheight); - deposits = komodo_paxtotal(); - while ( KOMODO_ON_DEMAND == 0 && deposits == 0 && (int32_t)mempool.GetTotalTxSize() == 0 ) - { - deposits = komodo_paxtotal(); - if ( KOMODO_PASSPORT_INITDONE == 0 || KOMODO_INITDONE == 0 || (komodo_baseid(ASSETCHAINS_SYMBOL) >= 0 && (isrealtime= komodo_isrealtime(&kmdheight)) == 0) ) - { - //fprintf(stderr,"INITDONE.%d RT.%d deposits %.8f ht.%d\n",KOMODO_INITDONE,isrealtime,(double)deposits/COIN,kmdheight); - } - else if ( komodo_isrealtime(&kmdheight) != 0 && (deposits != 0 || (int32_t)mempool.GetTotalTxSize() > 0) ) - { - fprintf(stderr,"start CreateNewBlock %s initdone.%d deposit %.8f mempool.%d RT.%u KOMODO_ON_DEMAND.%d\n",ASSETCHAINS_SYMBOL,KOMODO_INITDONE,(double)komodo_paxtotal()/COIN,(int32_t)mempool.GetTotalTxSize(),isrealtime,KOMODO_ON_DEMAND); - break; - } - sleep(10); - } - KOMODO_ON_DEMAND = 0; - if ( 0 && deposits != 0 ) - printf("miner KOMODO_DEPOSIT %llu pblock->nHeight %d mempool.GetTotalTxSize(%d)\n",(long long)komodo_paxtotal(),(int32_t)chainActive.Tip()->nHeight,(int32_t)mempool.GetTotalTxSize()); - }*/ - // -regtest only: allow overriding block.nVersion with + // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios if (Params().MineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); @@ -192,7 +166,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,int32_t gpucount) { LOCK2(cs_main, mempool.cs); - CBlockIndex* pindexPrev = chainActive.Tip(); + CBlockIndex* pindexPrev = chainActive.LastTip(); const int nHeight = pindexPrev->nHeight + 1; uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus()); pblock->nTime = GetAdjustedTime(); @@ -360,7 +334,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,int32_t gpucount) //fprintf(stderr,"dont have inputs\n"); continue; } - CAmount nTxFees = view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime)-tx.GetValueOut(); + CAmount nTxFees = view.GetValueIn(chainActive.LastTip()->nHeight,&interest,tx,chainActive.LastTip()->nTime)-tx.GetValueOut(); nTxSigOps += GetP2SHSigOpCount(tx, view); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1) @@ -422,17 +396,18 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,int32_t gpucount) { uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid,revtxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); + sleep(1); if ( (siglen= komodo_staked(txStaked,pblock->nBits,&blocktime,&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) { CAmount txfees = 0; - if ( (int32_t)chainActive.Tip()->nHeight+1 > 100 && GetAdjustedTime() < blocktime-13 ) - return(0); + //if ( (int32_t)chainActive.LastTip()->nHeight+1 > 100 && GetAdjustedTime() < blocktime-157 ) + // return(0); pblock->vtx.push_back(txStaked); pblocktemplate->vTxFees.push_back(txfees); pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txStaked)); nFees += txfees; pblock->nTime = blocktime; - printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.Tip()->nHeight+1,blocktime,(uint32_t)(GetAdjustedTime() - (blocktime-13))); + //printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->nHeight+1,blocktime,(uint32_t)(GetAdjustedTime() - (blocktime-13))); } else return(0); //fprintf(stderr,"no utxos eligible for staking\n"); } @@ -517,7 +492,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,int32_t gpucount) return(0); } } - else + else if ( ASSETCHAINS_STAKED == 0 ) { CValidationState state; if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) @@ -665,19 +640,19 @@ static bool ProcessBlockFound(CBlock* pblock) #endif // ENABLE_WALLET { LogPrintf("%s\n", pblock->ToString()); - LogPrintf("generated %s height.%d\n", FormatMoney(pblock->vtx[0].vout[0].nValue),chainActive.Tip()->nHeight+1); + LogPrintf("generated %s height.%d\n", FormatMoney(pblock->vtx[0].vout[0].nValue),chainActive.LastTip()->nHeight+1); // Found a solution { LOCK(cs_main); - if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) + if (pblock->hashPrevBlock != chainActive.LastTip()->GetBlockHash()) { uint256 hash; int32_t i; hash = pblock->hashPrevBlock; for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&hash)[i]); fprintf(stderr," <- prev (stale)\n"); - hash = chainActive.Tip()->GetBlockHash(); + hash = chainActive.LastTip()->GetBlockHash(); for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&hash)[i]); fprintf(stderr," <- chainTip (stale)\n"); @@ -705,7 +680,7 @@ static bool ProcessBlockFound(CBlock* pblock) // Process this block the same as if we had received it from another node CValidationState state; - if (!ProcessNewBlock(1,chainActive.Tip()->nHeight+1,state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(1,chainActive.LastTip()->nHeight+1,state, NULL, pblock, true, NULL)) return error("KomodoMiner: ProcessNewBlock, block not accepted"); TrackMinedBlock(pblock->GetHash()); @@ -743,13 +718,13 @@ void static BitcoinMiner() unsigned int n = chainparams.EquihashN(); unsigned int k = chainparams.EquihashK(); uint8_t *script; uint64_t total,checktoshis; int32_t i,j,gpucount=KOMODO_MAXGPUCOUNT,notaryid = -1; - while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) ) //chainActive.Tip()->nHeight != 235300 && + while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) ) //chainActive.LastTip()->nHeight != 235300 && { sleep(1); if ( komodo_baseid(ASSETCHAINS_SYMBOL) < 0 ) break; } - komodo_chosennotary(¬aryid,chainActive.Tip()->nHeight,NOTARY_PUBKEY33,(uint32_t)chainActive.Tip()->GetBlockTime()); + komodo_chosennotary(¬aryid,chainActive.LastTip()->nHeight,NOTARY_PUBKEY33,(uint32_t)chainActive.LastTip()->GetBlockTime()); if ( notaryid != My_notaryid ) My_notaryid = notaryid; std::string solver; @@ -775,9 +750,9 @@ void static BitcoinMiner() fprintf(stderr,"try %s Mining with %s\n",ASSETCHAINS_SYMBOL,solver.c_str()); while (true) { - if (chainparams.MiningRequiresPeers()) //chainActive.Tip()->nHeight != 235300 && + if (chainparams.MiningRequiresPeers()) //chainActive.LastTip()->nHeight != 235300 && { - //if ( ASSETCHAINS_SEED != 0 && chainActive.Tip()->nHeight < 100 ) + //if ( ASSETCHAINS_SEED != 0 && chainActive.LastTip()->nHeight < 100 ) // break; // Busy-wait for the network to come online so we don't waste time mining // on an obsolete chain. In regtest mode we expect to fly solo. @@ -801,7 +776,7 @@ void static BitcoinMiner() // Create new block // unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrev = chainActive.Tip(); + CBlockIndex* pindexPrev = chainActive.LastTip(); if ( Mining_height != pindexPrev->nHeight+1 ) { Mining_height = pindexPrev->nHeight+1; @@ -810,7 +785,7 @@ void static BitcoinMiner() if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED == 0 ) { //fprintf(stderr,"%s create new block ht.%d\n",ASSETCHAINS_SYMBOL,Mining_height); - sleep(3); + //sleep(3); } #ifdef ENABLE_WALLET CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey,pindexPrev->nHeight+1,gpucount); @@ -856,9 +831,10 @@ void static BitcoinMiner() // // Search // - uint8_t pubkeys[66][33]; uint32_t blocktimes[66]; int mids[256],nonzpkeys,i,j,externalflag; uint32_t savebits; int64_t nStart = GetTime(); + uint8_t pubkeys[66][33]; arith_uint256 bnMaxPoSdiff; uint32_t blocktimes[66]; int mids[256],nonzpkeys,i,j,externalflag; uint32_t savebits; int64_t nStart = GetTime(); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); savebits = pblock->nBits; - HASHTarget = arith_uint256().SetCompact(pblock->nBits); + HASHTarget = arith_uint256().SetCompact(savebits); roundrobin_delay = ROUNDROBIN_DELAY; if ( ASSETCHAINS_SYMBOL[0] == 0 && notaryid >= 0 ) { @@ -911,15 +887,11 @@ void static BitcoinMiner() } //else fprintf(stderr,"duplicate at j.%d\n",j); } else Mining_start = 0; } else Mining_start = 0; - if ( ASSETCHAINS_STAKED != 0 && GetArg("-genproclimit", 0) == 0 ) + if ( ASSETCHAINS_STAKED != 0 ) { - int32_t percPoS,z; - /*if ( Mining_height <= 100 ) - { - sleep(60); - continue; - }*/ + int32_t percPoS,z; bool fNegative,fOverflow; HASHTarget_POW = komodo_PoWtarget(&percPoS,HASHTarget,Mining_height,ASSETCHAINS_STAKED); + HASHTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); if ( ASSETCHAINS_STAKED < 100 ) { for (z=31; z>=0; z--) @@ -979,14 +951,18 @@ void static BitcoinMiner() fprintf(stderr,"%02x",((uint8_t *)&HASHTarget_POW)[z]); fprintf(stderr," POW\n");*/ if ( h > hashTarget ) - return false; - if ( B.nTime > GetAdjustedTime() ) { - fprintf(stderr,"need to wait %d seconds to submit block\n",(int32_t)(B.nTime - GetAdjustedTime())); + //if ( ASSETCHAINS_STAKED != 0 && GetArg("-genproclimit", 0) == 0 ) + // sleep(1); + return false; + } + if ( IS_KOMODO_NOTARY != 0 && B.nTime > GetAdjustedTime() ) + { + //fprintf(stderr,"need to wait %d seconds to submit block\n",(int32_t)(B.nTime - GetAdjustedTime())); while ( GetAdjustedTime() < B.nTime-2 ) { sleep(1); - if ( chainActive.Tip()->nHeight >= Mining_height ) + if ( chainActive.LastTip()->nHeight >= Mining_height ) { fprintf(stderr,"new block arrived\n"); return(false); @@ -1004,15 +980,19 @@ void static BitcoinMiner() } else { - while ( GetAdjustedTime() < B.nTime ) + while ( B.nTime-57 > GetAdjustedTime() ) + { sleep(1); + if ( chainActive.LastTip()->nHeight >= Mining_height ) + return(false); + } uint256 tmp = B.GetHash(); int32_t z; for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&tmp)[z]); - fprintf(stderr," mined block %d!\n",Mining_height); + fprintf(stderr," mined %s block %d!\n",ASSETCHAINS_SYMBOL,Mining_height); } CValidationState state; - if ( !TestBlockValidity(state,B, chainActive.Tip(), true, false)) + if ( !TestBlockValidity(state,B, chainActive.LastTip(), true, false)) { h = UintToArith256(B.GetHash()); for (z=31; z>=0; z--) @@ -1132,7 +1112,7 @@ void static BitcoinMiner() fprintf(stderr,"timeout, break\n"); break; } - if ( pindexPrev != chainActive.Tip() ) + if ( pindexPrev != chainActive.LastTip() ) { if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) fprintf(stderr,"Tip advanced, break\n"); diff --git a/src/pow.cpp b/src/pow.cpp index 2e525e8cb..6d218ef13 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -190,6 +190,11 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash,unsigned int } if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) return error("CheckProofOfWork(): nBits below minimum work"); + if ( ASSETCHAINS_STAKED != 0 ) + { + arith_uint256 bnMaxPoSdiff; + bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + } // Check proof of work matches claimed amount if ( UintToArith256(hash) > bnTarget ) { diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index d6ad31c3a..04222e854 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -232,11 +232,26 @@ CAmount CTransaction::GetJoinSplitValueIn() const { // NB: vpub_new "gives" money to the value pool just as inputs do nValue += it->vpub_new; - + if (!MoneyRange(it->vpub_new) || !MoneyRange(nValue)) throw std::runtime_error("CTransaction::GetJoinSplitValueIn(): value out of range"); } + + return nValue; +} +CAmount CTransaction::GetJoinSplitValueOut() const +{ + CAmount nValue = 0; + for (std::vector::const_iterator it(vjoinsplit.begin()); it != vjoinsplit.end(); ++it) + { + // NB: vpub_new "gives" money to the value pool just as inputs do + nValue += it->vpub_old; + + if (!MoneyRange(it->vpub_old) || !MoneyRange(nValue)) + throw std::runtime_error("CTransaction::GetJoinSplitValueOut(): value out of range"); + } + return nValue; } diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 88ee9a312..e3615c120 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -445,6 +445,8 @@ public: // Return sum of JoinSplit vpub_new CAmount GetJoinSplitValueIn() const; + // Return sum of JoinSplit vpub_old + CAmount GetJoinSplitValueOut() const; // Compute priority, given priority of inputs and (optionally) tx size double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const; diff --git a/src/rest.cpp b/src/rest.cpp index 8e2e4d1e6..38cc38466 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -530,7 +530,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) // serialize data // use exact same output as mentioned in Bip64 CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); - ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; + ssGetUTXOResponse << chainActive.Height() << chainActive.LastTip()->GetBlockHash() << bitmap << outs; string ssGetUTXOResponseString = ssGetUTXOResponse.str(); req->WriteHeader("Content-Type", "application/octet-stream"); @@ -540,7 +540,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) case RF_HEX: { CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); - ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; + ssGetUTXOResponse << chainActive.Height() << chainActive.LastTip()->GetBlockHash() << bitmap << outs; string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); @@ -554,7 +554,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) // pack in some essentials // use more or less the same output as mentioned in Bip64 objGetUTXOResponse.push_back(Pair("chainHeight", chainActive.Height())); - objGetUTXOResponse.push_back(Pair("chaintipHash", chainActive.Tip()->GetBlockHash().GetHex())); + objGetUTXOResponse.push_back(Pair("chaintipHash", chainActive.LastTip()->GetBlockHash().GetHex())); objGetUTXOResponse.push_back(Pair("bitmap", bitmapStringRepresentation)); UniValue utxos(UniValue::VARR); diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 42cf7f2b0..7f8984c63 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -38,10 +38,10 @@ double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficul // minimum difficulty = 1.0. if (blockindex == NULL) { - if (chainActive.Tip() == NULL) + if (chainActive.LastTip() == NULL) return 1.0; else - blockindex = chainActive.Tip(); + blockindex = chainActive.LastTip(); } uint32_t bits; @@ -326,7 +326,7 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp) ); LOCK(cs_main); - return chainActive.Tip()->GetBlockHash().GetHex(); + return chainActive.LastTip()->GetBlockHash().GetHex(); } UniValue getdifficulty(const UniValue& params, bool fHelp) @@ -803,13 +803,13 @@ UniValue kvsearch(const UniValue& params, bool fHelp) if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 ) { ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL))); - ret.push_back(Pair("currentheight", (int64_t)chainActive.Tip()->nHeight)); + ret.push_back(Pair("currentheight", (int64_t)chainActive.LastTip()->nHeight)); ret.push_back(Pair("key",params[0].get_str())); ret.push_back(Pair("keylen",keylen)); if ( keylen < sizeof(key) ) { memcpy(key,params[0].get_str().c_str(),keylen); - if ( (valuesize= komodo_kvsearch(&refpubkey,chainActive.Tip()->nHeight,&flags,&height,value,key,keylen)) >= 0 ) + if ( (valuesize= komodo_kvsearch(&refpubkey,chainActive.LastTip()->nHeight,&flags,&height,value,key,keylen)) >= 0 ) { std::string val; char *valuestr; val.resize(valuesize); @@ -837,7 +837,7 @@ UniValue minerids(const UniValue& params, bool fHelp) LOCK(cs_main); int32_t height = atoi(params[0].get_str().c_str()); if ( height <= 0 ) - height = chainActive.Tip()->nHeight; + height = chainActive.LastTip()->nHeight; else { CBlockIndex *pblockindex = chainActive[height]; @@ -899,8 +899,8 @@ UniValue notaries(const UniValue& params, bool fHelp) else timestamp = (uint32_t)time(NULL); if ( height < 0 ) { - height = chainActive.Tip()->nHeight; - timestamp = chainActive.Tip()->GetBlockTime(); + height = chainActive.LastTip()->nHeight; + timestamp = chainActive.LastTip()->GetBlockTime(); } else if ( params.size() < 2 ) { @@ -988,7 +988,7 @@ UniValue paxprice(const UniValue& params, bool fHelp) std::string rel = params[1].get_str(); int32_t height; if ( params.size() == 2 ) - height = chainActive.Tip()->nHeight; + height = chainActive.LastTip()->nHeight; else height = atoi(params[2].get_str().c_str()); //if ( params.size() == 3 || (basevolume= COIN * atof(params[3].get_str().c_str())) == 0 ) basevolume = 100000; @@ -1280,10 +1280,10 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) obj.push_back(Pair("chain", Params().NetworkIDString())); obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); - obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); + obj.push_back(Pair("bestblockhash", chainActive.LastTip()->GetBlockHash().GetHex())); obj.push_back(Pair("difficulty", (double)GetNetworkDifficulty())); - obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); - obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); + obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.LastTip()))); + obj.push_back(Pair("chainwork", chainActive.LastTip()->nChainWork.GetHex())); obj.push_back(Pair("pruned", fPruneMode)); ZCIncrementalMerkleTree tree; @@ -1294,7 +1294,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) obj.push_back(Pair("commitments", tree.size())); #endif - CBlockIndex* tip = chainActive.Tip(); + CBlockIndex* tip = chainActive.LastTip(); UniValue valuePools(UniValue::VARR); valuePools.push_back(ValuePoolDesc("sprout", tip->nChainSproutValue, boost::none)); obj.push_back(Pair("valuePools", valuePools)); @@ -1319,7 +1319,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) if (fPruneMode) { - CBlockIndex *block = chainActive.Tip(); + CBlockIndex *block = chainActive.LastTip(); while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) block = block->pprev; @@ -1394,7 +1394,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp) } // Always report the currently active tip. - setTips.insert(chainActive.Tip()); + setTips.insert(chainActive.LastTip()); /* Construct the output array. */ UniValue res(UniValue::VARR); const CBlockIndex *forked; diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index afe4e5a33..47fbeec30 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -39,7 +39,7 @@ using namespace std; * If 'height' is nonnegative, compute the estimate at the time when a given block was found. */ int64_t GetNetworkHashPS(int lookup, int height) { - CBlockIndex *pb = chainActive.Tip(); + CBlockIndex *pb = chainActive.LastTip(); if (height >= 0 && height < chainActive.Height()) pb = chainActive[height]; @@ -224,7 +224,7 @@ UniValue generate(const UniValue& params, bool fHelp) CBlock *pblock = &pblocktemplate->block; { LOCK(cs_main); - IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); + IncrementExtraNonce(pblock, chainActive.LastTip(), nExtraNonce); } // Hash state @@ -268,7 +268,7 @@ UniValue generate(const UniValue& params, bool fHelp) } endloop: CValidationState state; - if (!ProcessNewBlock(1,chainActive.Tip()->nHeight+1,state, NULL, pblock, true, NULL)) + if (!ProcessNewBlock(1,chainActive.LastTip()->nHeight+1,state, NULL, pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -550,7 +550,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) return "duplicate-inconclusive"; } - CBlockIndex* const pindexPrev = chainActive.Tip(); + CBlockIndex* const pindexPrev = chainActive.LastTip(); // TestBlockValidity only supports blocks built on the current Tip if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; @@ -589,7 +589,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) else { // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier - hashWatchedChain = chainActive.Tip()->GetBlockHash(); + hashWatchedChain = chainActive.LastTip()->GetBlockHash(); nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; } @@ -599,7 +599,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); boost::unique_lock lock(csBestBlock); - while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) + while (chainActive.LastTip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) { if (!cvBlockChange.timed_wait(lock, checktxtime)) { @@ -621,7 +621,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) static CBlockIndex* pindexPrev; static int64_t nStart; static CBlockTemplate* pblocktemplate; - if (pindexPrev != chainActive.Tip() || + if (pindexPrev != chainActive.LastTip() || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) { // Clear pindexPrev so future calls make a new block, despite any failures from here on @@ -629,7 +629,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) // Store the pindexBest used before CreateNewBlockWithKey, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrevNew = chainActive.Tip(); + CBlockIndex* pindexPrevNew = chainActive.LastTip(); nStart = GetTime(); // Create new block @@ -640,7 +640,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) } #ifdef ENABLE_WALLET CReserveKey reservekey(pwalletMain); - pblocktemplate = CreateNewBlockWithKey(reservekey,chainActive.Tip()->nHeight+1,KOMODO_MAXGPUCOUNT); + pblocktemplate = CreateNewBlockWithKey(reservekey,chainActive.LastTip()->nHeight+1,KOMODO_MAXGPUCOUNT); #else pblocktemplate = CreateNewBlockWithKey(); #endif @@ -693,7 +693,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) // Correct this if GetBlockTemplate changes the order // entry.push_back(Pair("foundersreward", (int64_t)tx.vout[1].nValue)); //} - CAmount nReward = GetBlockSubsidy(chainActive.Tip()->nHeight+1, Params().GetConsensus()); + CAmount nReward = GetBlockSubsidy(chainActive.LastTip()->nHeight+1, Params().GetConsensus()); entry.push_back(Pair("coinbasevalue", nReward)); entry.push_back(Pair("required", true)); txCoinbase = entry; @@ -726,7 +726,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("coinbaseaux", aux)); result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); } - result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); + result.push_back(Pair("longpollid", chainActive.LastTip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", hashTarget.GetHex())); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); result.push_back(Pair("mutable", aMutable)); @@ -809,7 +809,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(1,chainActive.Tip()->nHeight+1,state, NULL, &block, true, NULL); + bool fAccepted = ProcessNewBlock(1,chainActive.LastTip()->nHeight+1,state, NULL, &block, true, NULL); UnregisterValidationInterface(&sc); if (fBlockPresent) { diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 065739a9a..4405a407d 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -53,6 +53,7 @@ extern uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE; extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE,KOMODO_LONGESTCHAIN; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; uint32_t komodo_segid32(char *coinaddr); +int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height); int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp); #define KOMODO_VERSION "0.1.1" extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; @@ -132,8 +133,8 @@ UniValue getinfo(const UniValue& params, bool fHelp) //fprintf(stderr,"after longestchain %u\n",(uint32_t)time(NULL)); obj.push_back(Pair("longestchain", longestchain)); obj.push_back(Pair("timeoffset", GetTimeOffset())); - if ( chainActive.Tip() != 0 ) - obj.push_back(Pair("tiptime", (int)chainActive.Tip()->nTime)); + if ( chainActive.LastTip() != 0 ) + obj.push_back(Pair("tiptime", (int)chainActive.LastTip()->nTime)); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); @@ -151,7 +152,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("errors", GetWarnings("statusbar"))); { char pubkeystr[65]; int32_t notaryid; - if ( (notaryid= komodo_whoami(pubkeystr,(int32_t)chainActive.Tip()->nHeight,komodo_chainactive_timestamp())) >= 0 ) + if ( (notaryid= komodo_whoami(pubkeystr,(int32_t)chainActive.LastTip()->nHeight,komodo_chainactive_timestamp())) >= 0 ) { obj.push_back(Pair("notaryid", notaryid)); obj.push_back(Pair("pubkey", pubkeystr)); @@ -226,6 +227,26 @@ public: }; #endif +UniValue coinsupply(const UniValue& params, bool fHelp) +{ + int32_t height = 0; int64_t zfunds,supply = 0; UniValue result(UniValue::VOBJ); + if (fHelp || params.size() > 1) + throw runtime_error("coinsupply \n"); + if ( params.size() == 0 ) + height = chainActive.Height(); + else height = atoi(params[0].get_str()); + if ( (supply= komodo_coinsupply(&zfunds,height)) > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("coin", ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)); + result.push_back(Pair("height", (int)height)); + result.push_back(Pair("supply", ValueFromAmount(supply))); + result.push_back(Pair("zfunds", ValueFromAmount(zfunds))); + result.push_back(Pair("total", ValueFromAmount(zfunds + supply))); + } else result.push_back(Pair("error", "couldnt calculate supply")); + return(result); +} + UniValue jumblr_deposit(const UniValue& params, bool fHelp) { int32_t retval; UniValue result(UniValue::VOBJ); @@ -805,7 +826,7 @@ UniValue getaddressutxos(const UniValue& params, bool fHelp) result.push_back(Pair("utxos", utxos)); LOCK(cs_main); - result.push_back(Pair("hash", chainActive.Tip()->GetBlockHash().GetHex())); + result.push_back(Pair("hash", chainActive.LastTip()->GetBlockHash().GetHex())); result.push_back(Pair("height", (int)chainActive.Height())); return result; } else { diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index a9aff1b7f..525c35ca4 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -179,7 +179,7 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& const CTxOut& txout = tx.vout[i]; UniValue out(UniValue::VOBJ); out.push_back(Pair("value", ValueFromAmount(txout.nValue))); - if ( pindex != 0 && tx.nLockTime >= 500000000 && (tipindex= chainActive.Tip()) != 0 ) + if ( pindex != 0 && tx.nLockTime >= 500000000 && (tipindex= chainActive.LastTip()) != 0 ) { int64_t interest; int32_t txheight; uint32_t locktime; interest = komodo_accrued_interest(&txheight,&locktime,tx.GetHash(),i,0,txout.nValue,(int32_t)tipindex->nHeight); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index ed5110114..f37124d0c 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -280,6 +280,7 @@ static const CRPCCommand vRPCCommands[] = { "network", "clearbanned", &clearbanned, true }, /* Block chain and UTXO */ + { "blockchain", "coinsupply", &coinsupply, true }, { "blockchain", "getblockchaininfo", &getblockchaininfo, true }, { "blockchain", "getbestblockhash", &getbestblockhash, true }, { "blockchain", "getblockcount", &getblockcount, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index 5bb949299..586d79a88 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -207,6 +207,7 @@ extern UniValue getblocktemplate(const UniValue& params, bool fHelp); extern UniValue submitblock(const UniValue& params, bool fHelp); extern UniValue estimatefee(const UniValue& params, bool fHelp); extern UniValue estimatepriority(const UniValue& params, bool fHelp); +extern UniValue coinsupply(const UniValue& params, bool fHelp); extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp //extern UniValue getnewaddress64(const UniValue& params, bool fHelp); // in rpcwallet.cpp diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp deleted file mode 100644 index ef607dacc..000000000 --- a/src/test/alert_tests.cpp +++ /dev/null @@ -1,447 +0,0 @@ -// Copyright (c) 2013 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -// -// Unit tests for alert system -// - -#include "alert.h" -#include "chain.h" -#include "chainparams.h" -#include "clientversion.h" -#include "data/alertTests.raw.h" - -#include "main.h" -#include "rpcprotocol.h" -#include "rpcserver.h" -#include "serialize.h" -#include "streams.h" -#include "util.h" -#include "utilstrencodings.h" - -#include "test/test_bitcoin.h" - -#include - -#include -#include -#include - -#include "key.h" -#include "alertkeys.h" -#include - -/* - * If the alert key pairs have changed, the test suite will fail as the - * test data is now invalid. To create valid test data, signed with a - * new alert private key, follow these steps: - * - * 1. Copy your private key into alertkeys.h. Don't commit this file! - * See sendalert.cpp for more info. - * - * 2. Set the GENERATE_ALERTS_FLAG to true. - * - * 3. Build and run: - * test_bitcoin -t Generate_Alert_Test_Data - * - * 4. Test data is saved in your current directory as alertTests.raw.NEW - * Copy this file to: src/test/data/alertTests.raw - * - * For debugging purposes, terminal output can be copied into: - * src/test/data/alertTests.raw.h - * - * 5. Clean up... - * - Set GENERATE_ALERTS_FLAG back to false. - * - Remove your private key from alertkeys.h - * - * 6. Build and verify the new test data: - * test_bitcoin -t Alert_tests - * - */ -#define GENERATE_ALERTS_FLAG false - -#if GENERATE_ALERTS_FLAG - -// NOTE: -// A function SignAndSave() was used by Bitcoin Core to create alert test data -// but it has not been made publicly available. So instead, we have adapted -// some publicly available code which achieves the intended result: -// https://gist.github.com/lukem512/9b272bd35e2cdefbf386 - - -// Code to output a C-style array of values -template -std::string HexStrArray(const T itbegin, const T itend, int lineLength) -{ - std::string rv; - static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - rv.reserve((itend-itbegin)*3); - int i = 0; - for(T it = itbegin; it < itend; ++it) - { - unsigned char val = (unsigned char)(*it); - if(it != itbegin) - { - if (i % lineLength == 0) - rv.push_back('\n'); - else - rv.push_back(' '); - } - rv.push_back('0'); - rv.push_back('x'); - rv.push_back(hexmap[val>>4]); - rv.push_back(hexmap[val&15]); - rv.push_back(','); - i++; - } - - return rv; -} - -template -inline std::string HexStrArray(const T& vch, int lineLength) -{ - return HexStrArray(vch.begin(), vch.end(), lineLength); -} - - -// Sign CAlert with alert private key -bool SignAlert(CAlert &alert) -{ - // serialize alert data - CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION); - sMsg << *(CUnsignedAlert*)&alert; - alert.vchMsg = std::vector(sMsg.begin(), sMsg.end()); - - // sign alert - std::vector vchTmp(ParseHex(pszPrivKey)); - CPrivKey vchPrivKey(vchTmp.begin(), vchTmp.end()); - CKey key; - if (!key.SetPrivKey(vchPrivKey, false)) - { - printf("key.SetPrivKey failed\n"); - return false; - } - if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig)) - { - printf("SignAlert() : key.Sign failed\n"); - return false; - } - return true; -} - -// Sign a CAlert and serialize it -bool SignAndSerialize(CAlert &alert, CDataStream &buffer) -{ - // Sign - if(!SignAlert(alert)) - { - printf("SignAndSerialize() : could not sign alert\n"); - return false; - } - // ...and save! - buffer << alert; - return true; -} - -void GenerateAlertTests() -{ - CDataStream sBuffer(SER_DISK, CLIENT_VERSION); - - CAlert alert; - alert.nRelayUntil = 60; - alert.nExpiration = 24 * 60 * 60; - alert.nID = 1; - alert.nCancel = 0; // cancels previous messages up to this ID number - alert.nMinVer = 0; // These versions are protocol versions - alert.nMaxVer = 999001; - alert.nPriority = 1; - alert.strComment = "Alert comment"; - alert.strStatusBar = "Alert 1"; - - // Replace SignAndSave with SignAndSerialize - SignAndSerialize(alert, sBuffer); - - // More tests go here ... - alert.setSubVer.insert(std::string("/MagicBean:0.1.0/")); - alert.strStatusBar = "Alert 1 for MagicBean 0.1.0"; - SignAndSerialize(alert, sBuffer); - - alert.setSubVer.insert(std::string("/MagicBean:0.2.0/")); - alert.strStatusBar = "Alert 1 for MagicBean 0.1.0, 0.2.0"; - SignAndSerialize(alert, sBuffer); - - alert.setSubVer.clear(); - ++alert.nID; - alert.nCancel = 1; - alert.nPriority = 100; - alert.strStatusBar = "Alert 2, cancels 1"; - SignAndSerialize(alert, sBuffer); - - alert.nExpiration += 60; - ++alert.nID; - SignAndSerialize(alert, sBuffer); - - ++alert.nID; - alert.nPriority = 5000; - alert.strStatusBar = "Alert 3, disables RPC"; - alert.strRPCError = "RPC disabled"; - SignAndSerialize(alert, sBuffer); - - ++alert.nID; - alert.nPriority = 5000; - alert.strStatusBar = "Alert 4, re-enables RPC"; - alert.strRPCError = ""; - SignAndSerialize(alert, sBuffer); - - ++alert.nID; - alert.nMinVer = 11; - alert.nMaxVer = 22; - alert.nPriority = 100; - SignAndSerialize(alert, sBuffer); - - ++alert.nID; - alert.strStatusBar = "Alert 2 for MagicBean 0.1.0"; - alert.setSubVer.insert(std::string("/MagicBean:0.1.0/")); - SignAndSerialize(alert, sBuffer); - - ++alert.nID; - alert.nMinVer = 0; - alert.nMaxVer = 999999; - alert.strStatusBar = "Evil Alert'; /bin/ls; echo '"; - alert.setSubVer.clear(); - bool b = SignAndSerialize(alert, sBuffer); - - if (b) { - // Print the hex array, which will become the contents of alertTest.raw.h - std::vector vch = std::vector(sBuffer.begin(), sBuffer.end()); - printf("%s\n", HexStrArray(vch, 8).c_str()); - - // Write the data to alertTests.raw.NEW, to be copied to src/test/data/alertTests.raw - std::ofstream outfile("alertTests.raw.NEW", std::ios::out | std::ios::binary); - outfile.write((const char*)&vch[0], vch.size()); - outfile.close(); - } -} - - - -struct GenerateAlertTestsFixture : public TestingSetup { - GenerateAlertTestsFixture() {} - ~GenerateAlertTestsFixture() {} -}; - -BOOST_FIXTURE_TEST_SUITE(Generate_Alert_Test_Data, GenerateAlertTestsFixture); -BOOST_AUTO_TEST_CASE(GenerateTheAlertTests) -{ - GenerateAlertTests(); -} -BOOST_AUTO_TEST_SUITE_END() - - -#else - - -struct ReadAlerts : public TestingSetup -{ - ReadAlerts() - { - std::vector vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests)); - CDataStream stream(vch, SER_DISK, CLIENT_VERSION); - try { - while (!stream.eof()) - { - CAlert alert; - stream >> alert; - alerts.push_back(alert); - } - } - catch (const std::exception&) { } - } - ~ReadAlerts() { } - - static std::vector read_lines(boost::filesystem::path filepath) - { - std::vector result; - - std::ifstream f(filepath.string().c_str()); - std::string line; - while (std::getline(f,line)) - result.push_back(line); - - return result; - } - - std::vector alerts; -}; - -BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts) - - -BOOST_AUTO_TEST_CASE(AlertApplies) -{ - SetMockTime(11); - const std::vector& alertKey = Params(CBaseChainParams::MAIN).AlertKey(); - - BOOST_FOREACH(const CAlert& alert, alerts) - { - BOOST_CHECK(alert.CheckSignature(alertKey)); - } - - BOOST_CHECK(alerts.size() >= 3); - - // Matches: - BOOST_CHECK(alerts[0].AppliesTo(1, "")); - BOOST_CHECK(alerts[0].AppliesTo(999001, "")); - BOOST_CHECK(alerts[0].AppliesTo(1, "/MagicBean:11.11.11/")); - - BOOST_CHECK(alerts[1].AppliesTo(1, "/MagicBean:0.1.0/")); - BOOST_CHECK(alerts[1].AppliesTo(999001, "/MagicBean:0.1.0/")); - - BOOST_CHECK(alerts[2].AppliesTo(1, "/MagicBean:0.1.0/")); - BOOST_CHECK(alerts[2].AppliesTo(1, "/MagicBean:0.2.0/")); - - // Don't match: - BOOST_CHECK(!alerts[0].AppliesTo(-1, "")); - BOOST_CHECK(!alerts[0].AppliesTo(999002, "")); - - BOOST_CHECK(!alerts[1].AppliesTo(1, "")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "MagicBean:0.1.0")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "/MagicBean:0.1.0")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "MagicBean:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(-1, "/MagicBean:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(999002, "/MagicBean:0.1.0/")); - BOOST_CHECK(!alerts[1].AppliesTo(1, "/MagicBean:0.2.0/")); - - BOOST_CHECK(!alerts[2].AppliesTo(1, "/MagicBean:0.3.0/")); - - SetMockTime(0); -} - - -BOOST_AUTO_TEST_CASE(AlertNotify) -{ - SetMockTime(11); - const std::vector& alertKey = Params(CBaseChainParams::MAIN).AlertKey(); - - boost::filesystem::path temp = GetTempPath() / - boost::filesystem::unique_path("alertnotify-%%%%.txt"); - - mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string(); - - BOOST_FOREACH(CAlert alert, alerts) - alert.ProcessAlert(alertKey, false); - - std::vector r = read_lines(temp); - BOOST_CHECK_EQUAL(r.size(), 6u); - -// Windows built-in echo semantics are different than posixy shells. Quotes and -// whitespace are printed literally. - -#ifndef _WIN32 - BOOST_CHECK_EQUAL(r[0], "Alert 1"); - BOOST_CHECK_EQUAL(r[1], "Alert 2, cancels 1"); - BOOST_CHECK_EQUAL(r[2], "Alert 2, cancels 1"); - BOOST_CHECK_EQUAL(r[3], "Alert 3, disables RPC"); - BOOST_CHECK_EQUAL(r[4], "Alert 4, reenables RPC"); // dashes should be removed - BOOST_CHECK_EQUAL(r[5], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed -#else - BOOST_CHECK_EQUAL(r[0], "'Alert 1' "); - BOOST_CHECK_EQUAL(r[1], "'Alert 2, cancels 1' "); - BOOST_CHECK_EQUAL(r[2], "'Alert 2, cancels 1' "); - BOOST_CHECK_EQUAL(r[3], "'Alert 3, disables RPC' "); - BOOST_CHECK_EQUAL(r[4], "'Alert 4, reenables RPC' "); // dashes should be removed - BOOST_CHECK_EQUAL(r[5], "'Evil Alert; /bin/ls; echo ' "); -#endif - boost::filesystem::remove(temp); - - SetMockTime(0); - mapAlerts.clear(); -} - -BOOST_AUTO_TEST_CASE(AlertDisablesRPC) -{ - SetMockTime(11); - const std::vector& alertKey = Params(CBaseChainParams::MAIN).AlertKey(); - - // Command should work before alerts - BOOST_CHECK_EQUAL(GetWarnings("rpc"), ""); - - // First alert should disable RPC - alerts[5].ProcessAlert(alertKey, false); - BOOST_CHECK_EQUAL(alerts[5].strRPCError, "RPC disabled"); - BOOST_CHECK_EQUAL(GetWarnings("rpc"), "RPC disabled"); - - // Second alert should re-enable RPC - alerts[6].ProcessAlert(alertKey, false); - BOOST_CHECK_EQUAL(alerts[6].strRPCError, ""); - BOOST_CHECK_EQUAL(GetWarnings("rpc"), ""); - - SetMockTime(0); - mapAlerts.clear(); -} - -static bool falseFunc() { return false; } - -BOOST_AUTO_TEST_CASE(PartitionAlert) -{ - // Test PartitionCheck - CCriticalSection csDummy; - CBlockIndex indexDummy[400]; - CChainParams& params = Params(CBaseChainParams::MAIN); - int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing; - - // Generate fake blockchain timestamps relative to - // an arbitrary time: - int64_t now = 1427379054; - SetMockTime(now); - for (int i = 0; i < 400; i++) - { - indexDummy[i].phashBlock = NULL; - if (i == 0) indexDummy[i].pprev = NULL; - else indexDummy[i].pprev = &indexDummy[i-1]; - indexDummy[i].nHeight = i; - indexDummy[i].nTime = now - (400-i)*nPowTargetSpacing; - // Other members don't matter, the partition check code doesn't - // use them - } - - // Test 1: chain with blocks every nPowTargetSpacing seconds, - // as normal, no worries: - PartitionCheck(falseFunc, csDummy, &indexDummy[399], nPowTargetSpacing); - BOOST_CHECK(strMiscWarning.empty()); - - // Test 2: go 3.5 hours without a block, expect a warning: - now += 3*60*60+30*60; - SetMockTime(now); - PartitionCheck(falseFunc, csDummy, &indexDummy[399], nPowTargetSpacing); - BOOST_CHECK(!strMiscWarning.empty()); - BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); - strMiscWarning = ""; - - // Test 3: test the "partition alerts only go off once per day" - // code: - now += 60*10; - SetMockTime(now); - PartitionCheck(falseFunc, csDummy, &indexDummy[399], nPowTargetSpacing); - BOOST_CHECK(strMiscWarning.empty()); - - // Test 4: get 2.5 times as many blocks as expected: - now += 60*60*24; // Pretend it is a day later - SetMockTime(now); - int64_t quickSpacing = nPowTargetSpacing*2/5; - for (int i = 0; i < 400; i++) // Tweak chain timestamps: - indexDummy[i].nTime = now - (400-i)*quickSpacing; - PartitionCheck(falseFunc, csDummy, &indexDummy[399], nPowTargetSpacing); - BOOST_CHECK(!strMiscWarning.empty()); - BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); - strMiscWarning = ""; - - SetMockTime(0); -} - -BOOST_AUTO_TEST_SUITE_END() - -#endif diff --git a/src/txdb.cpp b/src/txdb.cpp index a0f764962..31af362ac 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -400,9 +400,9 @@ bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &addr int64_t CBlockTreeDB::Snapshot() { - char chType; int64_t total = -1; std::string address; + char chType; int64_t total = 0; std::string address; boost::scoped_ptr pcursor(NewIterator()); - pcursor->SeekToFirst(); + pcursor->SeekToLast(); fprintf(stderr,"pcursor iterate\n"); while (pcursor->Valid()) { @@ -428,7 +428,6 @@ int64_t CBlockTreeDB::Snapshot() total = (int64_t)nValue; else total += (int64_t)nValue; //addressIndex.push_back(make_pair(indexKey, nValue)); - pcursor->Next(); } catch (const std::exception& e) { return error("failed to get address index value"); } @@ -436,6 +435,7 @@ int64_t CBlockTreeDB::Snapshot() } catch (const std::exception& e) { break; } + pcursor->Prev(); } return(total); } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 51ed1103e..e96f0d975 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -437,7 +437,7 @@ void CTxMemPool::removeExpired(unsigned int nBlockHeight) for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->GetTx(); - tipindex = chainActive.Tip(); + tipindex = chainActive.LastTip(); if (IsExpiredTx(tx, nBlockHeight) || (ASSETCHAINS_SYMBOL[0] == 0 && tipindex != 0 && komodo_validate_interest(tx,tipindex->nHeight+1,tipindex->GetMedianTimePast() + 777,0)) < 0) { transactionsToRemove.push_back(tx); diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index cd3e30f3d..a8e15db99 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -51,3 +51,7 @@ void UnregisterAllValidationInterfaces() { void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) { g_signals.SyncTransaction(tx, pblock); } + +void EraseFromWallets(const uint256 &hash) { + g_signals.EraseTransaction(hash); +} diff --git a/src/validationinterface.h b/src/validationinterface.h index 1855dacd7..a1f111753 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -28,6 +28,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn); void UnregisterAllValidationInterfaces(); /** Push an updated transaction to all registered wallets */ void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL); +void EraseFromWallets(const uint256 &hash); class CValidationInterface { protected: diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 15caad846..c8dc7aa5b 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -278,7 +278,7 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); - int64_t nTimeBegin = chainActive.Tip()->GetBlockTime(); + int64_t nTimeBegin = chainActive.LastTip()->GetBlockTime(); bool fGood = true; @@ -364,7 +364,7 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys file.close(); pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI - CBlockIndex *pindex = chainActive.Tip(); + CBlockIndex *pindex = chainActive.LastTip(); while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200) pindex = pindex->pprev; @@ -509,8 +509,8 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys) // produce output file << strprintf("# Wallet dump created by Komodo %s (%s)\n", CLIENT_BUILD, CLIENT_DATE); file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime())); - file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); - file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime())); + file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.LastTip()->GetBlockHash().ToString()); + file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.LastTip()->GetBlockTime())); file << "\n"; for (std::vector >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { const CKeyID &keyid = it->second; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a1773f43b..084a4f752 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -574,7 +574,7 @@ UniValue kvupdate(const UniValue& params, bool fHelp) valuesize = (int32_t)strlen(params[1].get_str().c_str()); } memcpy(keyvalue,key,keylen); - if ( (refvaluesize= komodo_kvsearch(&refpubkey,chainActive.Tip()->nHeight,&tmpflags,&height,&keyvalue[keylen],key,keylen)) >= 0 ) + if ( (refvaluesize= komodo_kvsearch(&refpubkey,chainActive.LastTip()->nHeight,&tmpflags,&height,&keyvalue[keylen],key,keylen)) >= 0 ) { if ( (tmpflags & KOMODO_KVPROTECTED) != 0 ) { @@ -599,7 +599,7 @@ UniValue kvupdate(const UniValue& params, bool fHelp) // printf("%02x",((uint8_t *)&sig)[i]); //printf(" sig for keylen.%d + valuesize.%d\n",keylen,refvaluesize); ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL))); - height = chainActive.Tip()->nHeight; + height = chainActive.LastTip()->nHeight; if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 ) ret.push_back(Pair("owner",refpubkey.GetHex())); ret.push_back(Pair("height", (int64_t)height)); @@ -671,7 +671,7 @@ UniValue paxdeposit(const UniValue& params, bool fHelp) int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN; std::string base = params[2].get_str(); std::string dest; - height = chainActive.Tip()->nHeight; + height = chainActive.LastTip()->nHeight; if ( pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,(char *)base.c_str()) != 0 || available < fiatoshis ) { fprintf(stderr,"available %llu vs fiatoshis %llu\n",(long long)available,(long long)fiatoshis); @@ -1075,8 +1075,6 @@ UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp) UniValue movecmd(const UniValue& params, bool fHelp) { - if ( ASSETCHAINS_PRIVATE != 0 ) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain"); if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; @@ -1100,6 +1098,8 @@ UniValue movecmd(const UniValue& params, bool fHelp) "\nAs a json rpc call\n" + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"") ); + if ( ASSETCHAINS_PRIVATE != 0 ) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain"); LOCK2(cs_main, pwalletMain->cs_wallet); @@ -1150,8 +1150,6 @@ UniValue movecmd(const UniValue& params, bool fHelp) UniValue sendfrom(const UniValue& params, bool fHelp) { - if ( ASSETCHAINS_PRIVATE != 0 ) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain"); if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; @@ -1181,6 +1179,8 @@ UniValue sendfrom(const UniValue& params, bool fHelp) "\nAs a json rpc call\n" + HelpExampleRpc("sendfrom", "\"tabby\", \"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", 0.01, 6, \"donation\", \"seans outpost\"") ); + if ( ASSETCHAINS_PRIVATE != 0 ) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain"); LOCK2(cs_main, pwalletMain->cs_wallet); @@ -1217,8 +1217,6 @@ UniValue sendfrom(const UniValue& params, bool fHelp) UniValue sendmany(const UniValue& params, bool fHelp) { - if ( ASSETCHAINS_PRIVATE != 0 ) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain"); if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; @@ -1257,6 +1255,8 @@ UniValue sendmany(const UniValue& params, bool fHelp) "\nAs a json rpc call\n" + HelpExampleRpc("sendmany", "\"\", \"{\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.01,\\\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\\\":0.02}\", 6, \"testing\"") ); + if ( ASSETCHAINS_PRIVATE != 0 ) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain"); LOCK2(cs_main, pwalletMain->cs_wallet); @@ -2713,13 +2713,13 @@ UniValue listunspent(const UniValue& params, bool fHelp) BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); CBlockIndex *tipindex,*pindex = it->second; uint64_t interest; uint32_t locktime; int32_t txheight; - if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) + if ( pindex != 0 && (tipindex= chainActive.LastTip()) != 0 ) { interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight); //interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); entry.push_back(Pair("interest",ValueFromAmount(interest))); } - //fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.Tip(),locktime,txheight,pindex->nHeight); + //fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.LastTip(),locktime,txheight,pindex->nHeight); } entry.push_back(Pair("confirmations",out.nDepth)); entry.push_back(Pair("spendable", out.fSpendable)); @@ -2746,7 +2746,7 @@ uint64_t komodo_interestsum() { BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); CBlockIndex *tipindex,*pindex = it->second; - if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) + if ( pindex != 0 && (tipindex= chainActive.LastTip()) != 0 ) { interest = komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight); //interest = komodo_interest(pindex->nHeight,nValue,out.tx->nLockTime,tipindex->nTime); @@ -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; itertxtime+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 setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector 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 setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector 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,60 +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); + free(array); + array = 0; + maxkp = numkp = 0; + lasttime = 0; + } + BOOST_FOREACH(const COutput& out, vecOutputs) + { + 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); + } + 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= 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; inHeight+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; - } - if ( setAddress.size() ) + 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 ) { - CTxDestination address; - if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + besttime = m = 0; + if ( eligible == komodo_stake(1,bnTarget,nHeight,kp->txid,kp->vout,eligible,(uint32_t)tipindex->nTime+27,kp->address) ) { - fprintf(stderr,"komodo_staked ExtractDestination error\n"); + 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 (!setAddress.count(address)) + 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)) ) { - fprintf(stderr,"komodo_staked setAddress.count error\n"); - continue; + 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); } - } - CAmount nValue = out.tx->vout[out.i].nValue; - 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,(char *)CBitcoinAddress(address).ToString().c_str()); - if ( eligible > 0 ) - { - if ( eligible != komodo_stake(1,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,eligible,(uint32_t)tipindex->nTime,(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,"earliest.%u [%d] (%s) nValue %.8f locktime.%u\n",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"); + } //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 ) { @@ -4686,7 +4822,8 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt //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"); + } //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); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 10bf93598..ce5630fb6 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1819,7 +1819,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup double dProgressStart = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false); - double dProgressTip = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip(), false); + double dProgressTip = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.LastTip(), false); while (pindex) { if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) @@ -2112,7 +2112,7 @@ std::vector CWallet::ResendWalletTransactionsBefore(int64_t nTime) // Don't rebroadcast if newer than nTime: if (wtx.nTimeReceived > nTime) continue; - if ( ASSETCHAINS_SYMBOL[0] == 0 ) + //if ( ASSETCHAINS_SYMBOL[0] == 0 ) { if ( wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-KOMODO_MAXMEMPOOLTIME ) { @@ -2299,20 +2299,20 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const if ( KOMODO_EXCHANGEWALLET == 0 ) { uint32_t locktime; int32_t txheight; CBlockIndex *tipindex; - if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.Tip() != 0 && chainActive.Tip()->nHeight >= 60000 ) + if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.LastTip() != 0 && chainActive.LastTip()->nHeight >= 60000 ) { if ( pcoin->vout[i].nValue >= 10*COIN ) { - if ( (tipindex= chainActive.Tip()) != 0 ) + if ( (tipindex= chainActive.LastTip()) != 0 ) { komodo_accrued_interest(&txheight,&locktime,wtxid,i,0,pcoin->vout[i].nValue,(int32_t)tipindex->nHeight); interest = komodo_interestnew(txheight,pcoin->vout[i].nValue,locktime,tipindex->nTime); } else interest = 0; - //interest = komodo_interestnew(chainActive.Tip()->nHeight+1,pcoin->vout[i].nValue,pcoin->nLockTime,chainActive.Tip()->nTime); + //interest = komodo_interestnew(chainActive.LastTip()->nHeight+1,pcoin->vout[i].nValue,pcoin->nLockTime,chainActive.LastTip()->nTime); if ( interest != 0 ) { //printf("wallet nValueRet %.8f += interest %.8f ht.%d lock.%u/%u tip.%u\n",(double)pcoin->vout[i].nValue/COIN,(double)interest/COIN,txheight,locktime,pcoin->nLockTime,tipindex->nTime); - //fprintf(stderr,"wallet nValueRet %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)pcoin->vout[i].nValue/COIN,(double)interest/COIN,chainActive.Tip()->nHeight+1,pcoin->nLockTime,chainActive.Tip()->nTime); + //fprintf(stderr,"wallet nValueRet %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)pcoin->vout[i].nValue/COIN,(double)interest/COIN,chainActive.LastTip()->nHeight+1,pcoin->nLockTime,chainActive.LastTip()->nTime); //ptr = (uint64_t *)&pcoin->vout[i].nValue; //(*ptr) += interest; ptr = (uint64_t *)&pcoin->vout[i].interest; @@ -2687,7 +2687,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt int nextBlockHeight = chainActive.Height() + 1; CMutableTransaction txNew = CreateNewContextualCMutableTransaction( Params().GetConsensus(), nextBlockHeight); - txNew.nLockTime = (uint32_t)chainActive.Tip()->nTime + 1; // set to a time close to now + txNew.nLockTime = (uint32_t)chainActive.LastTip()->nTime + 1; // set to a time close to now // Activates after Overwinter network upgrade // Set nExpiryHeight to expiryDelta (default 20) blocks past current block height diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index f77a55a04..0c6a90840 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -995,9 +995,9 @@ public: bool UpdateNullifierNoteMap(); void UpdateNullifierNoteMapWithTx(const CWalletTx& wtx); bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb); + void EraseFromWallet(const uint256 &hash); void SyncTransaction(const CTransaction& tx, const CBlock* pblock); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate); - void EraseFromWallet(const uint256 &hash); void WitnessNoteCommitment( std::vector commitments, std::vector>& witnesses,