diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 4e010d28e..68e0da8b3 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -70,6 +70,8 @@ void WaitForShutdown(boost::thread_group* threadGroup) { int32_t i; bool fShutdown = ShutdownRequested(); // Tell the main threads to shutdown. + if ( ASSETCHAINS_CBOPRET != 0 ) + komodo_pricesinit(); while (!fShutdown) { //fprintf(stderr,"call passport iteration\n"); diff --git a/src/komodo.h b/src/komodo.h index 3ceb29cc3..15c1e5c02 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -691,7 +691,7 @@ int32_t komodo_voutupdate(bool fJustCheck,int32_t *isratificationp,int32_t notar else { komodo_rwccdata(ASSETCHAINS_SYMBOL,1,&ccdata,&MoMoMdata); - if ( !fJustCheck && matched != 0 ) + if ( matched != 0 ) printf("[%s] matched.%d VALID (%s) MoM.%s [%d] CCid.%u\n",ASSETCHAINS_SYMBOL,matched,ccdata.symbol,MoM.ToString().c_str(),MoMdepth&0xffff,(MoMdepth>>16)&0xffff); } if ( MoMoMdata.pairs != 0 ) @@ -747,7 +747,7 @@ int32_t komodo_voutupdate(bool fJustCheck,int32_t *isratificationp,int32_t notar } else if ( matched != 0 && i == 0 && j == 1 && opretlen == 149 ) { - if ( !fJustCheck && notaryid >= 0 && notaryid < 64 ) + if ( notaryid >= 0 && notaryid < 64 ) komodo_paxpricefeed(height,&scriptbuf[len],opretlen); } else if ( matched != 0 ) diff --git a/src/komodo_defs.h b/src/komodo_defs.h index 9377ea276..ebfadee69 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -84,6 +84,9 @@ extern char NOTARYADDRS[64][64]; int tx_height( const uint256 &hash ); extern std::vector vWhiteListAddress; void komodo_netevent(std::vector payload); + +#define PRICES_SMOOTHWIDTH 1 int32_t komodo_priceind(char *symbol); +void komodo_pricesinit(); #endif diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 9afc9845c..ce89cea35 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1548,11 +1548,13 @@ void komodo_passport_iteration() } } + extern std::vector Mineropret; // opreturn data set by the data gathering code -#define PRICES_MAXCHANGE (COIN / 100) // maximum acceptable change, set at 1% +#define PRICES_ERRORRATE (COIN / 100) // maximum acceptable change, set at 1% #define PRICES_SIZEBIT0 (sizeof(uint32_t) * 4) // 4 uint32_t unixtimestamp, BTCUSD, BTCGBP and BTCEUR #define KOMODO_LOCALPRICE_CACHESIZE 13 #define KOMODO_MAXPRICES 2048 +#define PRICES_SMOOTHWIDTH 1 #define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0) @@ -1562,6 +1564,20 @@ const char *Forex[] = { "BGN","NZD","ILS","RUB","CAD","PHP","CHF","AUD","JPY","TRY","HKD","MYR","HRK","CZK","IDR","DKK","NOK","HUF","GBP","MXN","THB","ISK","ZAR","BRL","SGD","PLN","INR","KRW","RON","CNY","SEK","EUR" }; // must be in ECB list +struct komodo_extremeprice +{ + uint256 blockhash; + uint32_t pricebits,timestamp; + int32_t height; + int16_t dir,ind; +} ExtremePrice; + +struct komodo_priceinfo +{ + FILE *fp; + char symbol[64]; +} PRICES[KOMODO_MAXPRICES]; + uint32_t PriceCache[KOMODO_LOCALPRICE_CACHESIZE][KOMODO_MAXPRICES];//4+sizeof(Cryptos)/sizeof(*Cryptos)+sizeof(Forex)/sizeof(*Forex)]; int64_t PriceMult[KOMODO_MAXPRICES]; int32_t komodo_cbopretsize(uint64_t flags); @@ -1574,26 +1590,33 @@ void komodo_PriceCache_shift() memcpy(PriceCache[0],Mineropret.data(),Mineropret.size()); } +int32_t _komodo_heightpricebits(uint64_t *seedp,uint32_t *heightbits,CBlock *block) +{ + CTransaction tx; int32_t numvouts; std::vector vopret; + tx = block->vtx[0]; + numvouts = (int32_t)tx.vout.size(); + GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); + if ( vopret.size() >= PRICES_SIZEBIT0 ) + { + if ( seedp != 0 ) + memcpy(seedp,&block->hashMerkleRoot,sizeof(*seedp)); + memcpy(heightbits,vopret.data(),vopret.size()); + return((int32_t)(vopret.size()/sizeof(uint32_t))); + } + return(-1); +} + // komodo_heightpricebits() extracts the price data in the coinbase for nHeight int32_t komodo_heightpricebits(uint64_t *seedp,uint32_t *heightbits,int32_t nHeight) { - CBlockIndex *pindex; CBlock block; CTransaction tx; int32_t numvouts; std::vector vopret; + CBlockIndex *pindex; CBlock block; if ( seedp != 0 ) *seedp = 0; if ( (pindex= komodo_chainactive(nHeight)) != 0 ) { if ( komodo_blockload(block,pindex) == 0 ) { - tx = block.vtx[0]; - numvouts = (int32_t)tx.vout.size(); - GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); - if ( vopret.size() >= PRICES_SIZEBIT0 ) - { - if ( seedp != 0 ) - memcpy(seedp,&pindex->hashMerkleRoot,sizeof(*seedp)); - memcpy(heightbits,vopret.data(),vopret.size()); - return((int32_t)(vopret.size()/sizeof(uint32_t))); - } + return(_komodo_heightpricebits(seedp,heightbits,&block)); } } fprintf(stderr,"couldnt get pricebits for %d\n",nHeight); @@ -1696,10 +1719,10 @@ CScript komodo_mineropret(int32_t nHeight) { memcpy(pricebits,Mineropret.data(),Mineropret.size()); memset(maxflags,0,sizeof(maxflags)); - if ( komodo_pricecmp(0,n,maxflags,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(0,n,maxflags,pricebits,prevbits,PRICES_ERRORRATE) < 0 ) { // if the new prices are outside tolerance, update Mineropret with clamped prices - komodo_priceclamp(n,pricebits,prevbits,PRICES_MAXCHANGE); + komodo_priceclamp(n,pricebits,prevbits,PRICES_ERRORRATE); //fprintf(stderr,"update Mineropret to clamped prices\n"); memcpy(Mineropret.data(),pricebits,Mineropret.size()); } @@ -1721,13 +1744,6 @@ CScript komodo_mineropret(int32_t nHeight) */ -struct komodo_extremeprice -{ - uint256 blockhash; - uint32_t pricebits,timestamp; - int32_t height; - int16_t dir,ind; -} ExtremePrice; void komodo_queuelocalprice(int32_t dir,int32_t height,uint32_t timestamp,uint256 blockhash,int32_t ind,uint32_t pricebits) { @@ -1788,7 +1804,7 @@ int32_t komodo_opretvalidate(const CBlock *block,CBlockIndex * const previndex,i if ( pricebits[i] == 0 ) pricebits[i] = prevbits[i]; } - if ( komodo_pricecmp(nHeight,n,maxflags,pricebits,prevbits,PRICES_MAXCHANGE) < 0 ) + if ( komodo_pricecmp(nHeight,n,maxflags,pricebits,prevbits,PRICES_ERRORRATE) < 0 ) { for (i=1; i 0 && PRICES[0].fp != 0 ) + { + fseek(PRICES[0].fp,(2*PRICES_DAYWINDOW+PRICES_SMOOTHWIDTH) * sizeof(uint32_t) * i,SEEK_SET); + fputc(0,PRICES[0].fp); + fflush(PRICES[0].fp); + } + } +} + +void komodo_pricesupdate(int32_t height,CBlock *pblock) +{ + static int numprices; static uint32_t *ptr32; static int64_t *ptr64; + int32_t ind,offset,width; int64_t correlated,smoothed; uint64_t seed,rngval; uint32_t rawprices[KOMODO_MAXPRICES],buf[4]; + width = (2*PRICES_DAYWINDOW + PRICES_SMOOTHWIDTH); + if ( numprices == 0 ) + { + numprices = (int32_t)(komodo_cbopretsize(ASSETCHAINS_CBOPRET) / sizeof(uint32_t)); + ptr32 = (uint32_t *)calloc(sizeof(uint32_t),numprices * width); + ptr64 = (int64_t *)calloc(sizeof(int64_t),PRICES_DAYWINDOW*3); + } + if ( _komodo_heightpricebits(&seed,rawprices,pblock) == numprices ) + { + //for (i=0; i width ) + { + fseek(PRICES[0].fp,(height-width+1) * numprices * sizeof(uint32_t),SEEK_SET); + if ( fread(ptr32,sizeof(uint32_t),width*numprices,PRICES[0].fp) == width*numprices ) + { + rngval = seed; + for (ind=1; ind 0 ) + { + fseek(PRICES[ind].fp,height * sizeof(int64_t) * 3,SEEK_SET); + buf[0] = rawprices[ind]; + buf[1] = rawprices[0]; // timestamp + memcpy(&buf[2],&correlated,sizeof(correlated)); + if ( fwrite(buf,1,sizeof(buf),PRICES[ind].fp) != sizeof(buf) ) + fprintf(stderr,"error fwrite buf for ht.%d ind.%d\n",height,ind); + else + { + fseek(PRICES[ind].fp,(height-PRICES_DAYWINDOW+1) * 3 * sizeof(int64_t),SEEK_SET); + if ( fread(ptr64,sizeof(int64_t),PRICES_DAYWINDOW*3,PRICES[ind].fp) == PRICES_DAYWINDOW*3 ) + { + if ( (smoothed= komodo_priceave(&ptr64[PRICES_DAYWINDOW*3-1],-3)) > 0 ) + { + fseek(PRICES[ind].fp,(height * 3 + 2) * sizeof(int64_t),SEEK_SET); + if ( fwrite(&smoothed,1,sizeof(smoothed),PRICES[ind].fp) != sizeof(smoothed) ) + fprintf(stderr,"error fwrite smoothed for ht.%d ind.%d\n",height,ind); + else + { + fprintf(stderr,"%.4f ",(double)smoothed/COIN); + fflush(PRICES[ind].fp); + } + } else fprintf(stderr,"error price_smoothed ht.%d ind.%d\n",height,ind); + } else fprintf(stderr,"error fread ptr64 for ht.%d ind.%d\n",height,ind); + } + } else fprintf(stderr,"error komodo_pricecorrelated for ht.%d ind.%d\n",height,ind); + } + fprintf(stderr,"height.%d\n",height); + } else fprintf(stderr,"error reading rawprices for ht.%d\n",height); + } + } + } else fprintf(stderr,"numprices mismatch\n"); + +} + + diff --git a/src/main.cpp b/src/main.cpp index faa9e6a9c..593a41e3f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -85,6 +85,7 @@ int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block); //void komodo_broadcast(CBlock *pblock,int32_t limit); bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey); void komodo_setactivation(int32_t height); +void komodo_pricesupdate(int32_t height,CBlock *pblock); BlockMap mapBlockIndex; CChain chainActive; @@ -3904,7 +3905,8 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { if ( block.GetHash() == notarizedhash ) { fprintf(stderr,"DisconnectTip trying to disconnect notarized block at ht.%d\n",(int32_t)pindexDelete->GetHeight()); - return(false); + return state.DoS(100, error("AcceptBlock(): DisconnectTip trying to disconnect notarized blockht.%d",(int32_t)pindexDelete->GetHeight()), + REJECT_INVALID, "past-notarized-height"); } } // Apply the block atomically to the chain state. @@ -4148,6 +4150,8 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * komodo_broadcast(pblock,8); else if ( ASSETCHAINS_SYMBOL[0] != 0 ) komodo_broadcast(pblock,4);*/ + if ( ASSETCHAINS_CBOPRET != 0 ) + komodo_pricesupdate(pindexNew->GetHeight(),pblock); if ( ASSETCHAINS_SAPLING <= 0 && pindexNew->nTime > KOMODO_SAPLING_ACTIVATION - 24*3600 ) komodo_activate_sapling(pindexNew); return true; @@ -4233,43 +4237,43 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo const CBlockIndex *pindexOldTip = chainActive.Tip(); const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); + // stop trying to reorg if the reorged chain is before last notarized height. + // stay on the same chain tip! + int32_t notarizedht,prevMoMheight; uint256 notarizedhash,txid; + notarizedht = komodo_notarized_height(&prevMoMheight,¬arizedhash,&txid); + if ( pindexFork->GetHeight() < notarizedht ) + { + fprintf(stderr,"pindexFork->GetHeight().%d is < notarizedht %d, so ignore it\n",(int32_t)pindexFork->GetHeight(),notarizedht); + return state.DoS(100, error("ActivateBestChainStep(): pindexFork->GetHeight().%d is < notarizedht %d, so ignore it",(int32_t)pindexFork->GetHeight(),notarizedht), + REJECT_INVALID, "past-notarized-height"); + } // - On ChainDB initialization, pindexOldTip will be null, so there are no removable blocks. // - If pindexMostWork is in a chain that doesn't have the same genesis block as our chain, // then pindexFork will be null, and we would need to remove the entire chain including // our genesis block. In practice this (probably) won't happen because of checks elsewhere. auto reorgLength = pindexOldTip ? pindexOldTip->GetHeight() - (pindexFork ? pindexFork->GetHeight() : -1) : 0; assert(MAX_REORG_LENGTH > 0);//, "We must be able to reorg some distance"); - if (reorgLength > MAX_REORG_LENGTH) + if ( reorgLength > MAX_REORG_LENGTH) { - int32_t notarizedht,prevMoMheight; uint256 notarizedhash,txid; - notarizedht = komodo_notarized_height(&prevMoMheight,¬arizedhash,&txid); - if ( pindexFork->GetHeight() < notarizedht ) - { - fprintf(stderr,"pindexFork->GetHeight().%d is < notarizedht %d, so ignore it\n",(int32_t)pindexFork->GetHeight(),notarizedht); - pindexFork = pindexOldTip; - } - else - { - auto msg = strprintf(_( - "A block chain reorganization has been detected that would roll back %d blocks! " - "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." - ), reorgLength, MAX_REORG_LENGTH) + "\n\n" + - _("Reorganization details") + ":\n" + - "- " + strprintf(_("Current tip: %s, height %d, work %s\nstake %s"), - pindexOldTip->phashBlock->GetHex(), pindexOldTip->GetHeight(), pindexOldTip->chainPower.chainWork.GetHex(), - pindexOldTip->chainPower.chainStake.GetHex()) + "\n" + - "- " + strprintf(_("New tip: %s, height %d, work %s\nstake %s"), - pindexMostWork->phashBlock->GetHex(), pindexMostWork->GetHeight(), pindexMostWork->chainPower.chainWork.GetHex(), - pindexMostWork->chainPower.chainStake.GetHex()) + "\n" + - "- " + strprintf(_("Fork point: %s %s, height %d"), - ASSETCHAINS_SYMBOL,pindexFork->phashBlock->GetHex(), pindexFork->GetHeight()) + "\n\n" + - _("Please help, human!"); - LogPrintf("*** %s\nif you launch with -maxreorg=%d it might be able to resolve this automatically", msg,reorgLength+10); - fprintf(stderr,"*** %s\nif you launch with -maxreorg=%d it might be able to resolve this automatically", msg.c_str(),reorgLength+10); - uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); - StartShutdown(); - return false; - } + auto msg = strprintf(_( + "A block chain reorganization has been detected that would roll back %d blocks! " + "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." + ), reorgLength, MAX_REORG_LENGTH) + "\n\n" + + _("Reorganization details") + ":\n" + + "- " + strprintf(_("Current tip: %s, height %d, work %s\nstake %s"), + pindexOldTip->phashBlock->GetHex(), pindexOldTip->GetHeight(), pindexOldTip->chainPower.chainWork.GetHex(), + pindexOldTip->chainPower.chainStake.GetHex()) + "\n" + + "- " + strprintf(_("New tip: %s, height %d, work %s\nstake %s"), + pindexMostWork->phashBlock->GetHex(), pindexMostWork->GetHeight(), pindexMostWork->chainPower.chainWork.GetHex(), + pindexMostWork->chainPower.chainStake.GetHex()) + "\n" + + "- " + strprintf(_("Fork point: %s %s, height %d"), + ASSETCHAINS_SYMBOL,pindexFork->phashBlock->GetHex(), pindexFork->GetHeight()) + "\n\n" + + _("Please help, human!"); + LogPrintf("*** %s\nif you launch with -maxreorg=%d it might be able to resolve this automatically", msg,reorgLength+10); + fprintf(stderr,"*** %s\nif you launch with -maxreorg=%d it might be able to resolve this automatically", msg.c_str(),reorgLength+10); + uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return false; } // Disconnect active blocks which are no longer in the best chain. diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index fc9a71fe2..07cb8a26d 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1176,7 +1176,7 @@ UniValue paxprice(const UniValue& params, bool fHelp) int32_t komodo_heightpricebits(uint64_t *seedp,uint32_t *heightbits,int32_t nHeight); char *komodo_pricename(char *name,int32_t ind); -int64_t komodo_pricesmoothed(int64_t *correlated,int32_t cskip,int64_t *correlated2,int32_t numprices); +int64_t komodo_priceave(int64_t *correlated,int32_t cskip); int64_t komodo_pricecorrelated(uint64_t seed,int32_t ind,uint32_t *rawprices,int32_t rawskip,uint32_t *nonzprices,int32_t smoothwidth); int32_t komodo_nextheight(); uint32_t komodo_heightstamp(int32_t height); @@ -1185,9 +1185,7 @@ int64_t komodo_pricemult(int32_t ind); int32_t prices_extract(int64_t *pricedata,int32_t firstheight,int32_t numblocks,int32_t ind) { - int32_t height,i,n,width,numpricefeeds = -1; uint64_t seed,ignore,rngval; int64_t *correlated2; uint32_t rawprices[1440*6],*ptr; - //daywindow = (3600*24/ASSETCHAINS_BLOCKTIME) + 1; - //pricedata = (uint32_t *)calloc(sizeof(*prices)*3,numblocks + daywindow*2 + PRICES_SMOOTHWIDTH); + int32_t height,i,n,width,numpricefeeds = -1; uint64_t seed,ignore,rngval; uint32_t rawprices[1440*6],*ptr; width = numblocks+PRICES_DAYWINDOW*2+PRICES_SMOOTHWIDTH; komodo_heightpricebits(&seed,rawprices,firstheight + numblocks - 1); if ( firstheight < width ) @@ -1205,20 +1203,15 @@ int32_t prices_extract(int64_t *pricedata,int32_t firstheight,int32_t numblocks, ptr[1] = rawprices[0]; // timestamp } rngval = seed; - correlated2 = (int64_t *)calloc(sizeof(*correlated2),width); for (i=0; i2; i++,ht--) { @@ -1287,14 +1278,13 @@ UniValue prices(const UniValue& params, bool fHelp) { offset = j*width + i; rngval = (rngval*11109 + 13849); - correlated2[i] = prices[offset]; if ( (correlated[i]= komodo_pricecorrelated(rngval,j,&prices[offset],1,0,PRICES_SMOOTHWIDTH)) < 0 ) throw JSONRPCError(RPC_INVALID_PARAMETER, "null correlated price"); } for (i=0; i