From 37ad68866827bf0f9b03267a4a37532e6c900e23 Mon Sep 17 00:00:00 2001 From: Michael Toutonghi Date: Sat, 14 Jul 2018 21:45:38 -0700 Subject: [PATCH 1/6] Protect from null ptr on chain tip --- src/chain.cpp | 1 + src/chain.h | 6 ++++++ src/coins.cpp | 11 ++++++++++- src/miner.cpp | 51 ++++++++++++++++++++++++++------------------------- 4 files changed, 43 insertions(+), 26 deletions(-) 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 8276b2596..15036325a 100644 --- a/src/chain.h +++ b/src/chain.h @@ -424,6 +424,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. */ @@ -436,6 +437,11 @@ public: 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 { if (nHeight < 0 || nHeight >= (int)vChain.size()) diff --git a/src/coins.cpp b/src/coins.cpp index 3deabc6ef..990ee3d12 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -253,7 +253,16 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) const { uint256 CCoinsViewCache::GetBestBlock() const { if (hashBlock.IsNull()) - hashBlock = base->GetBestBlock(); + { + if (base) + { + hashBlock = base->GetBestBlock(); + } + else + { + hashBlock = uint256(); + } + } return hashBlock; } diff --git a/src/miner.cpp b/src/miner.cpp index 4854b9a28..63c11dcf7 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -370,7 +370,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, bool isStake) //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) @@ -485,7 +485,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, bool isStake) pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txStaked)); nFees += txfees; pblock->nTime = blocktime; - //printf("PoS ht.%d t%u\n",(int32_t)chainActive.Tip()->nHeight+1,blocktime); + //printf("PoS ht.%d t%u\n",(int32_t)chainActive.LastTip()->nHeight+1,blocktime); } else return(0); //fprintf(stderr,"no utxos eligible for staking\n"); } @@ -723,11 +723,11 @@ 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); // Found a solution { LOCK(cs_main); + LogPrintf("generated %s height.%d\n", FormatMoney(pblock->vtx[0].vout[0].nValue),chainActive.Tip()->nHeight+1); if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) { uint256 hash; int32_t i; @@ -763,7 +763,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()); @@ -852,9 +852,10 @@ void static VerusStaker(CWallet *pwallet) sleep(5); { + LOCK(cs_main); printf("Staking height %d for %s\n", chainActive.Tip()->nHeight + 1, ASSETCHAINS_SYMBOL); + //fprintf(stderr,"Staking height %d for %s\n", chainActive.Tip()->nHeight + 1, ASSETCHAINS_SYMBOL); } - //fprintf(stderr,"Staking height %d for %s\n", chainActive.Tip()->nHeight + 1, ASSETCHAINS_SYMBOL); miningTimer.start(); @@ -867,7 +868,7 @@ void static VerusStaker(CWallet *pwallet) // 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; @@ -885,8 +886,8 @@ void static VerusStaker(CWallet *pwallet) if ( ptr == 0 ) { // wait to try another staking block until after the tip moves again - while ( chainActive.Tip() == pindexPrev ) - sleep(5); + while ( chainActive.LastTip() == pindexPrev ) + sleep(1); continue; } @@ -932,9 +933,9 @@ void static VerusStaker(CWallet *pwallet) continue; } - if ( pindexPrev != chainActive.Tip() ) + if ( pindexPrev != chainActive.LastTip() ) { - printf("Block %d added to chain\n", chainActive.Tip()->nHeight); + printf("Block %d added to chain\n", chainActive.LastTip()->nHeight); MilliSleep(250); continue; } @@ -1024,9 +1025,9 @@ void static BitcoinMiner_noeq() waitForPeers(chainparams); CBlockIndex *pindexPrev, *pindexCur; do { - pindexPrev = chainActive.Tip(); + pindexPrev = chainActive.LastTip(); MilliSleep(5000 + rand() % 5000); - pindexCur = chainActive.Tip(); + pindexCur = chainActive.LastTip(); } while (pindexPrev != pindexCur); // this will not stop printing more than once in all cases, but it will allow us to print in all cases @@ -1042,16 +1043,16 @@ void static BitcoinMiner_noeq() miningTimer.stop(); waitForPeers(chainparams); - pindexPrev = chainActive.Tip(); + pindexPrev = chainActive.LastTip(); sleep(1); // prevent forking on startup before the diff algorithm kicks in - if (pindexPrev->nHeight < 50 || pindexPrev != chainActive.Tip()) + if (pindexPrev->nHeight < 50 || pindexPrev != chainActive.LastTip()) { do { - pindexPrev = chainActive.Tip(); + pindexPrev = chainActive.LastTip(); MilliSleep(5000 + rand() % 5000); - } while (pindexPrev != chainActive.Tip()); + } while (pindexPrev != chainActive.LastTip()); } // Create new block @@ -1125,11 +1126,11 @@ void static BitcoinMiner_noeq() Mining_start = 0; - if ( pindexPrev != chainActive.Tip() ) + if ( pindexPrev != chainActive.LastTip() ) { - if (lastChainTipPrinted != chainActive.Tip()) + if (lastChainTipPrinted != chainActive.LastTip()) { - lastChainTipPrinted = chainActive.Tip(); + lastChainTipPrinted = chainActive.LastTip(); printf("Block %d added to chain\n", lastChainTipPrinted->nHeight); } MilliSleep(250); @@ -1200,11 +1201,11 @@ void static BitcoinMiner_noeq() // check periodically if we're stale if (!--hashesToGo) { - if ( pindexPrev != chainActive.Tip() ) + if ( pindexPrev != chainActive.LastTip() ) { - if (lastChainTipPrinted != chainActive.Tip()) + if (lastChainTipPrinted != chainActive.LastTip()) { - lastChainTipPrinted = chainActive.Tip(); + lastChainTipPrinted = chainActive.LastTip(); printf("Block %d added to chain\n", lastChainTipPrinted->nHeight); } break; @@ -1236,11 +1237,11 @@ void static BitcoinMiner_noeq() break; } - if ( pindexPrev != chainActive.Tip() ) + if ( pindexPrev != chainActive.LastTip() ) { - if (lastChainTipPrinted != chainActive.Tip()) + if (lastChainTipPrinted != chainActive.LastTip()) { - lastChainTipPrinted = chainActive.Tip(); + lastChainTipPrinted = chainActive.LastTip(); printf("Block %d added to chain\n", lastChainTipPrinted->nHeight); } break; From c5325a32560fa5f23f72456db44772e6d7c0b5f0 Mon Sep 17 00:00:00 2001 From: Michael Toutonghi Date: Wed, 18 Jul 2018 17:42:15 -0700 Subject: [PATCH 2/6] PoS improvements --- src/Makefile.am | 3 ++ src/komodo_bitcoind.h | 41 ++++++++++++++++------ src/main.cpp | 4 +-- src/miner.cpp | 6 ++-- src/primitives/block.cpp | 43 +++++++++++++++++++++++ src/primitives/block.h | 12 +++---- src/primitives/nonce.cpp | 68 ++++++++++++++++++++++++++++++++++++ src/primitives/nonce.h | 66 ++++++++++++++++++++++++++++++++++ src/primitives/transaction.h | 31 +++++++++++----- src/wallet/rpcwallet.cpp | 4 +-- src/wallet/wallet.cpp | 21 ++++++----- src/wallet/wallet.h | 4 +-- 12 files changed, 260 insertions(+), 43 deletions(-) create mode 100644 src/primitives/nonce.cpp create mode 100644 src/primitives/nonce.h diff --git a/src/Makefile.am b/src/Makefile.am index fbc8bf73d..a8d7b1bbc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -191,6 +191,7 @@ BITCOIN_CORE_H = \ pow.h \ primitives/block.h \ primitives/transaction.h \ + primitives/nonce.h \ protocol.h \ pubkey.h \ random.h \ @@ -415,6 +416,7 @@ libbitcoin_common_a_SOURCES = \ netbase.cpp \ primitives/block.cpp \ primitives/transaction.cpp \ + primitives/nonce.cpp \ protocol.cpp \ pubkey.cpp \ scheduler.cpp \ @@ -624,6 +626,7 @@ libzcashconsensus_la_SOURCES = \ crypto/sha512.cpp \ hash.cpp \ primitives/transaction.cpp \ + primitives/nonce.cpp \ pubkey.cpp \ script/zcashconsensus.cpp \ script/interpreter.cpp \ diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 2fb4b74c1..87c4875fb 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1258,7 +1258,7 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_ return(isPoS); } -// if slow flag is 1, this does a slower check that checks the target with consensus, otherwise quick, insecure check for internal integrity +// for now, we will ignore slowFlag in the interest of keeping success/fail simpler for security purposes bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height) { CBlockIndex *pastBlockIndex; @@ -1275,11 +1275,11 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height) char voutaddr[64], destaddr[64], cbaddr[64]; - target.SetCompact(pblock->GetVerusPOSTarget()); txn_count = pblock->vtx.size(); if ( txn_count > 1 ) { + target.SetCompact(pblock->GetVerusPOSTarget()); txid = pblock->vtx[txn_count-1].vin[0].prevout.hash; voutNum = pblock->vtx[txn_count-1].vin[0].prevout.n; @@ -1291,20 +1291,28 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height) { fprintf(stderr,"ERROR: invalid PoS block %s - no transaction\n",blkHash.ToString().c_str()); } - else if (!(pastBlockIndex = komodo_chainactive(height - COINBASE_MATURITY))) + else if (!(pastBlockIndex = komodo_chainactive(height - 100))) { - fprintf(stderr,"ERROR: invalid PoS block %s - no past block found\n",blkHash.ToString().c_str()); + fprintf(stderr,"WARNING: chain not fully loaded or invalid PoS block %s - no past block found\n",blkHash.ToString().c_str()); } else { - hash = UintToArith256(tx.GetVerusPOSHash(voutNum, height, pastBlockIndex->GetBlockHash())); + CBlockHeader bh = pastBlockIndex->GetBlockHeader(); + uint256 pastHash = bh.GetVerusEntropyHash(height); + + // if height is over when Nonce is required to be the new format, we check that the new format is correct + // if over when we have the new POS hash function, we validate that as well + // they are 100 blocks apart + CPOSNonce nonce = pblock->nNonce; + + hash = UintToArith256(tx.GetVerusPOSHash(&nonce, voutNum, height, pastHash)); if (hash <= target) { if ((mapBlockIndex.count(blkHash) == 0) || !(pastBlockIndex = mapBlockIndex[blkHash]) || (height - pastBlockIndex->nHeight) < VERUS_MIN_STAKEAGE) { - fprintf(stderr,"ERROR: invalid PoS block %s - no prev block found\n",blkHash.ToString().c_str()); + fprintf(stderr,"ERROR: invalid PoS block %s - stake transaction too new\n",blkHash.ToString().c_str()); } else if ( slowflag != 0 ) { @@ -1317,13 +1325,24 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height) else { arith_uint256 cTarget; - cTarget.SetCompact(lwmaGetNextPOSRequired(previndex, Params().GetConsensus())); - - if (cTarget != target) + uint32_t nBits = lwmaGetNextPOSRequired(previndex, Params().GetConsensus()); + cTarget.SetCompact(nBits); + bool nonceOK = true; + + if (CPOSNonce::NewNonceActive(height) && !nonce.CheckPOSEntropy(pastHash, txid, voutNum)) { - fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str()); + fprintf(stderr,"ERROR: invalid PoS block %s - nonce entropy corrupted or forged\n",blkHash.ToString().c_str()); + nonceOK = false; } - else if ( ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey, voutaddress) && + else + { + if (cTarget != target) + { + fprintf(stderr,"ERROR: invalid PoS block %s - invalid diff target\n",blkHash.ToString().c_str()); + nonceOK = false; + } + } + if ( nonceOK && ExtractDestination(pblock->vtx[txn_count-1].vout[0].scriptPubKey, voutaddress) && ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress) && CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) ) { diff --git a/src/main.cpp b/src/main.cpp index bef0d296d..91fe8e62f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3149,7 +3149,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { list removed; CValidationState stateDummy; // don't keep staking or invalid transactions - if (tx.IsCoinBase() || (block.IsVerusPOSBlock() && (i == (block.vtx.size() - 1))) || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) + if (tx.IsCoinBase() || ((i == (block.vtx.size() - 1)) && block.IsVerusPOSBlock()) || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) { mempool.remove(tx, removed, true); } @@ -3171,7 +3171,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { for (int i = 0; i < block.vtx.size(); i++) { CTransaction &tx = block.vtx[i]; - if (block.IsVerusPOSBlock() && (i == (block.vtx.size() - 1))) + if ((i == (block.vtx.size() - 1) && block.IsVerusPOSBlock())) { EraseFromWallets(tx.GetHash()); } diff --git a/src/miner.cpp b/src/miner.cpp index 63c11dcf7..2f71e0564 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -128,7 +128,7 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ int64_t komodo_block_unlocktime(uint32_t nHeight); uint64_t komodo_commission(const CBlock *block); int32_t komodo_staked(CPubKey &pubkey, CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig); -int32_t verus_staked(CPubKey &pubkey, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig); +int32_t verus_staked(CBlock *pBlock, CPubKey &pubkey, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig); int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33); CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, bool isStake) @@ -462,7 +462,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, bool isStake) { uint32_t nBitsPOS; arith_uint256 posHash; - siglen = verus_staked(key, txStaked, nBitsPOS, posHash, utxosig); + siglen = verus_staked(pblock, key, txStaked, nBitsPOS, posHash, utxosig); blocktime = GetAdjustedTime(); pblock->SetVerusPOSTarget(nBitsPOS); @@ -959,7 +959,7 @@ void static VerusStaker(CWallet *pwallet) printf("staking reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL); arith_uint256 post; post.SetCompact(pblock->GetVerusPOSTarget()); - printf(" hash: %s \ntarget: %s\n", pblock->vtx[pblock->vtx.size()-1].GetVerusPOSHash(0, Mining_height, pindexPrev->GetBlockHash()).GetHex().c_str(), ArithToUint256(post).GetHex().c_str()); + printf(" hash: %s \ntarget: %s\n", pblock->vtx[pblock->vtx.size()-1].GetVerusPOSHash(&(pblock->nNonce), 0, Mining_height, pindexPrev->GetBlockHeader().GetVerusEntropyHash(Mining_height)).GetHex().c_str(), ArithToUint256(post).GetHex().c_str()); if (unlockTime > Mining_height && subsidy >= ASSETCHAINS_TIMELOCKGTE) printf("- timelocked until block %i\n", unlockTime); else diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 752e94079..dbb477252 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -10,6 +10,8 @@ #include "utilstrencodings.h" #include "crypto/common.h" +extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH; + // default hash algorithm for block uint256 (CBlockHeader::*CBlockHeader::hashFunction)() const = &CBlockHeader::GetSHA256DHash; @@ -43,6 +45,47 @@ void CBlockHeader::SetVerusHash() CBlockHeader::hashFunction = &CBlockHeader::GetVerusHash; } +// returns false if unable to fast calculate the VerusPOSHash from the header. it can still be calculated from the block +// in that case +bool CBlockHeader::GetVerusPOSHash(uint256 &value, int32_t nHeight) const +{ + // if below the required height or no storage space in the solution, we can't get + // a cached txid value to calculate the POSHash from the header + if (!(CPOSNonce::NewNonceActive(nHeight) && IsVerusPOSBlock())) + return false; + + // if we can calculate, this assumes the protocol that the POSHash calculation is: + // hashWriter << ASSETCHAINS_MAGIC; + // hashWriter << nNonce; (nNonce is: + // (high 128 bits == low 128 bits of verus hash of low 128 bits of nonce) + // (low 32 bits == compact PoS difficult) + // (mid 96 bits == low 96 bits of HASH(pastHash, txid, voutnum) + // pastHash is hash of height - 100, either PoW hash of block or PoS hash, if new PoS + // ) + // hashWriter << height; + // return hashWriter.GetHash(); + CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); + + hashWriter << ASSETCHAINS_MAGIC; + hashWriter << nNonce; + hashWriter << nHeight; + value = hashWriter.GetHash(); + return true; +} + +// depending on the height of the block and its type, this returns the POS hash or the POW hash +uint256 CBlockHeader::GetVerusEntropyHash(int32_t height) const +{ + uint256 retVal; + // if we qualify as PoW, use PoW hash, regardless of PoS state + if (GetVerusPOSHash(retVal, height)) + { + // POS hash + return retVal; + } + return GetHash(); +} + uint256 CBlock::BuildMerkleTree(bool* fMutated) const { /* WARNING! If you're reading this because you're learning about crypto diff --git a/src/primitives/block.h b/src/primitives/block.h index fb92952f1..cf81a213b 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -7,6 +7,7 @@ #define BITCOIN_PRIMITIVES_BLOCK_H #include "primitives/transaction.h" +#include "primitives/nonce.h" #include "serialize.h" #include "uint256.h" #include "arith_uint256.h" @@ -33,7 +34,7 @@ public: uint256 hashReserved; uint32_t nTime; uint32_t nBits; - uint256 nNonce; + CPOSNonce nNonce; std::vector nSolution; CBlockHeader() @@ -84,6 +85,9 @@ public: uint256 GetVerusHash() const; static void SetVerusHash(); + bool GetVerusPOSHash(uint256 &value, int32_t nHeight) const; + uint256 GetVerusEntropyHash(int32_t nHeight) const; + uint256 GetVerusV2Hash() const; int64_t GetBlockTime() const @@ -105,11 +109,7 @@ public: bool IsVerusPOSBlock() const { - arith_uint256 arNonce = UintToArith256(nNonce); - arith_uint256 tmpNonce = ((arNonce << 128) >> 128); - CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); - hashWriter << ArithToUint256(tmpNonce); - return (nNonce == ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | tmpNonce)); + return nNonce.IsPOSNonce(); } void SetVerusPOSTarget(int32_t nBits) diff --git a/src/primitives/nonce.cpp b/src/primitives/nonce.cpp new file mode 100644 index 000000000..491146968 --- /dev/null +++ b/src/primitives/nonce.cpp @@ -0,0 +1,68 @@ +// Copyright (c) 2018 Michael Toutonghi +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "hash.h" +#include "nonce.h" +#include + +extern char ASSETCHAINS_SYMBOL[65]; + +bool CPOSNonce::NewPOSActive(int32_t height) +{ + if ((strcmp(ASSETCHAINS_SYMBOL, "VRSC") == 0) || (height < (96480 + 100))) + return false; + else if ((strcmp(ASSETCHAINS_SYMBOL, "VRSCTEST") == 0) && (height < (1000 + 100))) + return false; + else + return true; +} + +bool CPOSNonce::NewNonceActive(int32_t height) +{ + if ((strcmp(ASSETCHAINS_SYMBOL, "VRSC") == 0) || (height < 96480)) + return false; + else if ((strcmp(ASSETCHAINS_SYMBOL, "VRSCTEST") == 0) && (height < 1000)) + return false; + else + return true; +} + +void CPOSNonce::SetPOSEntropy(const uint256 &pastHash, uint256 txid, int32_t voutNum) +{ + // get low 96 bits of past hash and put it in top 96 bits of low 128 bits of nonce + CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); + + // first hash the pastHash, txid, and voutNum, to create a combined 96 bits, which will be used in the nonce + hashWriter << pastHash; + hashWriter << txid; + hashWriter << voutNum; + + arith_uint256 arNonce = (UintToArith256(*this) & 0xffffffff) | + ((UintToArith256(hashWriter.GetHash()) & UintToArith256(uint256S("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))) << 32); + + hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); + hashWriter << ArithToUint256(arNonce); + + *this = CPOSNonce(ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | arNonce)); +} + +bool CPOSNonce::CheckPOSEntropy(const uint256 &pastHash, uint256 txid, int32_t voutNum) +{ + // get low 96 bits of past hash and put it in top 96 bits of low 128 bits of nonce + CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); + + // first hash the pastHash, txid, and voutNum, to create a combined 96 bits, which will be used in the nonce + hashWriter << pastHash; + hashWriter << txid; + hashWriter << voutNum; + + arith_uint256 arNonce = (UintToArith256(*this) & 0xffffffff) | + ((UintToArith256(hashWriter.GetHash()) & UintToArith256(uint256S("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))) << 32); + + hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); + hashWriter << ArithToUint256(arNonce); + + return UintToArith256(*this) == (UintToArith256(hashWriter.GetHash()) << 128 | arNonce); +} + diff --git a/src/primitives/nonce.h b/src/primitives/nonce.h new file mode 100644 index 000000000..f92c983e5 --- /dev/null +++ b/src/primitives/nonce.h @@ -0,0 +1,66 @@ +// Copyright (c) 2018 Michael Toutonghi +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_PRIMITIVES_NONCE_H +#define BITCOIN_PRIMITIVES_NONCE_H + +#include "serialize.h" +#include "uint256.h" +#include "arith_uint256.h" + + +/** For POS blocks, the nNonce of a block header holds the entropy source for the POS contest + * in the latest VerusHash protocol, implemented at block below + * + * */ +class CPOSNonce : public uint256 +{ +public: + static bool NewPOSActive(int32_t height); + static bool NewNonceActive(int32_t height); + + CPOSNonce() {} + CPOSNonce(const base_blob<256> &b) : uint256(b) {} + CPOSNonce(const std::vector &vch) : uint256(vch) {} + + int32_t GetPOSTarget() const + { + uint32_t nBits = 0; + + for (const unsigned char *p = begin() + 3; p >= begin(); p--) + { + nBits <<= 8; + nBits += *p; + } + return nBits; + } + + bool IsPOSNonce() const + { + arith_uint256 arNonce = UintToArith256(*this); + arith_uint256 tmpNonce = ((arNonce << 128) >> 128); + CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); + hashWriter << ArithToUint256(tmpNonce); + return (*this == ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | tmpNonce)); + } + + void SetPOSTarget(int32_t nBits) + { + CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); + arith_uint256 tmpNonce; + + arith_uint256 arNonce = UintToArith256(*this); + arNonce = ((arNonce >> 32) << 32) | nBits; + + tmpNonce = ((arNonce << 128) >> 128); + hashWriter << ArithToUint256(tmpNonce); + + (uint256 &)(*this) = ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | tmpNonce); + } + + void SetPOSEntropy(const uint256 &pastHash, uint256 txid, int32_t voutNum); + bool CheckPOSEntropy(const uint256 &pastHash, uint256 txid, int32_t voutNum); +}; + +#endif // BITCOIN_PRIMITIVES_NONCE_H diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index d7a177fc4..8043fe5a5 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -14,6 +14,7 @@ #include "arith_uint256.h" #include "consensus/consensus.h" #include "hash.h" +#include "nonce.h" #ifndef __APPLE__ #include @@ -474,25 +475,39 @@ public: } // verus hash will be the same for a given txid, output number, block height, and blockhash of 100 blocks past - static uint256 _GetVerusPOSHash(const uint256 &txid, int32_t voutNum, int32_t height, const uint256 &pastHash, int64_t value) + static uint256 _GetVerusPOSHash(CPOSNonce *pNonce, const uint256 &txid, int32_t voutNum, int32_t height, const uint256 &pastHash, int64_t value) { + pNonce->SetPOSEntropy(pastHash, txid, voutNum); CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); hashWriter << ASSETCHAINS_MAGIC; - hashWriter << pastHash; - hashWriter << height; - hashWriter << txid; - hashWriter << voutNum; - return hashWriter.GetHash(); + + // we only use the new style of POS hash after changeover and 100 blocks of enforced proper nonce updating + if (CPOSNonce::NewPOSActive(height)) + { + hashWriter << *pNonce; + hashWriter << height; + return hashWriter.GetHash(); + } + else + { + hashWriter << pastHash; + hashWriter << height; + hashWriter << txid; + hashWriter << voutNum; + return hashWriter.GetHash(); + } } - uint256 GetVerusPOSHash(int32_t voutNum, int32_t height, const uint256 &pastHash) const + // Nonce is modified to include the transaction information + uint256 GetVerusPOSHash(CPOSNonce *pNonce, int32_t voutNum, int32_t height, const uint256 &pastHash) const { uint256 txid = GetHash(); + if (voutNum >= vout.size()) return uint256S("ff0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); - return ArithToUint256(UintToArith256(_GetVerusPOSHash(txid, voutNum, height, pastHash, (uint64_t)vout[voutNum].nValue)) / vout[voutNum].nValue); + return ArithToUint256(UintToArith256(_GetVerusPOSHash(pNonce, txid, voutNum, height, pastHash, (uint64_t)vout[voutNum].nValue)) / vout[voutNum].nValue); } std::string ToString() const; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 029730cb3..66fa30efa 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4667,7 +4667,7 @@ int32_t komodo_staked(CPubKey &pubkey, CMutableTransaction &txNew,uint32_t nBits return(siglen); } -int32_t verus_staked(CPubKey &pubkey, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig) +int32_t verus_staked(CBlock *pBlock, CPubKey &pubkey, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig) { - return pwalletMain->VerusStakeTransaction(txNew, nBits, hashResult, utxosig); + return pwalletMain->VerusStakeTransaction(pBlock, txNew, nBits, hashResult, utxosig); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 85ae03b26..275da8258 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -998,8 +998,9 @@ CWallet::TxItems CWallet::OrderedTxItems(std::list& acentries, // UTXO with the smallest coin age if there is more than one, as larger coin age will win more often and is worth saving // each attempt consists of taking a VerusHash of the following values: // ASSETCHAINS_MAGIC, nHeight, txid, voutNum -bool CWallet::VerusSelectStakeOutput(arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, const arith_uint256 &target) const +bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, uint32_t bnTarget) const { + arith_uint256 target; arith_uint256 curHash; vector vecOutputs; COutput *pwinner = NULL; @@ -1007,15 +1008,19 @@ bool CWallet::VerusSelectStakeOutput(arith_uint256 &hashResult, CTransaction &st txnouttype whichType; std:vector> vSolutions; + pBlock->nNonce.SetPOSTarget(bnTarget); + target.SetCompact(bnTarget); + pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false); - if (pastBlockIndex = komodo_chainactive(nHeight - COINBASE_MATURITY)) + if (pastBlockIndex = komodo_chainactive(nHeight - 100)) { - uint256 pastHash = pastBlockIndex->GetBlockHash(); + CBlockHeader bh = pastBlockIndex->GetBlockHeader(); + uint256 pastHash = bh.GetVerusEntropyHash(nHeight); BOOST_FOREACH(COutput &txout, vecOutputs) { - if (txout.fSpendable && (UintToArith256(txout.tx->GetVerusPOSHash(txout.i, nHeight, pastHash)) <= target) && (txout.nDepth >= VERUS_MIN_STAKEAGE)) + if (txout.fSpendable && (UintToArith256(txout.tx->GetVerusPOSHash(&(pBlock->nNonce), txout.i, nHeight, pastHash)) <= target) && (txout.nDepth >= VERUS_MIN_STAKEAGE)) { // get the smallest winner if (Solver(txout.tx->vout[txout.i].scriptPubKey, whichType, vSolutions) && (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH) && @@ -1033,9 +1038,8 @@ bool CWallet::VerusSelectStakeOutput(arith_uint256 &hashResult, CTransaction &st return false; } -int32_t CWallet::VerusStakeTransaction(CMutableTransaction &txNew, uint32_t &bnTarget, arith_uint256 &hashResult, uint8_t *utxosig) const +int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNew, uint32_t bnTarget, arith_uint256 &hashResult, uint8_t *utxosig) const { - arith_uint256 target; CTransaction stakeSource; int32_t voutNum, siglen = 0; int64_t nValue; @@ -1048,12 +1052,11 @@ int32_t CWallet::VerusStakeTransaction(CMutableTransaction &txNew, uint32_t &bnT tipindex = chainActive.Tip(); } bnTarget = lwmaGetNextPOSRequired(tipindex, Params().GetConsensus()); - target.SetCompact(bnTarget); - if (!VerusSelectStakeOutput(hashResult, stakeSource, voutNum, tipindex->nHeight + 1, target) || + if (!VerusSelectStakeOutput(pBlock, hashResult, stakeSource, voutNum, tipindex->nHeight + 1, bnTarget) || !Solver(stakeSource.vout[voutNum].scriptPubKey, whichType, vSolutions)) { - LogPrintf("No eligible staking transaction found\n"); + LogPrintf("Searched for eligible staking transactions, no winners found\n"); return 0; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 0df2cd4dc..8568bf9c2 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1149,8 +1149,8 @@ public: bool ignoreUnspendable=true); // staking functions - bool VerusSelectStakeOutput(arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, const arith_uint256 &target) const; - int32_t VerusStakeTransaction(CMutableTransaction &txNew, uint32_t &bnTarget, arith_uint256 &hashResult, uint8_t *utxosig) const; + bool VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, uint32_t bnTarget) const; + int32_t VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNew, uint32_t bnTarget, arith_uint256 &hashResult, uint8_t *utxosig) const; }; /** A key allocated from the key pool. */ From 503bd93fa8784cd8ca1019944a4705853cad9f38 Mon Sep 17 00:00:00 2001 From: Michael Toutonghi Date: Thu, 19 Jul 2018 01:02:54 -0700 Subject: [PATCH 3/6] Differentiate raw POSHash from full one adjusted by vout value --- src/primitives/block.cpp | 7 ++++--- src/primitives/block.h | 2 +- src/primitives/nonce.cpp | 4 ++-- src/primitives/nonce.h | 3 +-- src/primitives/transaction.h | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index dbb477252..39d338959 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -46,8 +46,9 @@ void CBlockHeader::SetVerusHash() } // returns false if unable to fast calculate the VerusPOSHash from the header. it can still be calculated from the block -// in that case -bool CBlockHeader::GetVerusPOSHash(uint256 &value, int32_t nHeight) const +// in that case. the only difference between this and the POS hash for the contest is that it is not divided by the value out +// this is used as a source of entropy +bool CBlockHeader::GetRawVerusPOSHash(uint256 &value, int32_t nHeight) const { // if below the required height or no storage space in the solution, we can't get // a cached txid value to calculate the POSHash from the header @@ -78,7 +79,7 @@ uint256 CBlockHeader::GetVerusEntropyHash(int32_t height) const { uint256 retVal; // if we qualify as PoW, use PoW hash, regardless of PoS state - if (GetVerusPOSHash(retVal, height)) + if (GetRawVerusPOSHash(retVal, height)) { // POS hash return retVal; diff --git a/src/primitives/block.h b/src/primitives/block.h index cf81a213b..06e26f4c5 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -85,7 +85,7 @@ public: uint256 GetVerusHash() const; static void SetVerusHash(); - bool GetVerusPOSHash(uint256 &value, int32_t nHeight) const; + bool GetRawVerusPOSHash(uint256 &value, int32_t nHeight) const; uint256 GetVerusEntropyHash(int32_t nHeight) const; uint256 GetVerusV2Hash() const; diff --git a/src/primitives/nonce.cpp b/src/primitives/nonce.cpp index 491146968..e7ad618ee 100644 --- a/src/primitives/nonce.cpp +++ b/src/primitives/nonce.cpp @@ -10,7 +10,7 @@ extern char ASSETCHAINS_SYMBOL[65]; bool CPOSNonce::NewPOSActive(int32_t height) { - if ((strcmp(ASSETCHAINS_SYMBOL, "VRSC") == 0) || (height < (96480 + 100))) + if ((strcmp(ASSETCHAINS_SYMBOL, "VRSC") == 0) && (height < (96480 + 100))) return false; else if ((strcmp(ASSETCHAINS_SYMBOL, "VRSCTEST") == 0) && (height < (1000 + 100))) return false; @@ -20,7 +20,7 @@ bool CPOSNonce::NewPOSActive(int32_t height) bool CPOSNonce::NewNonceActive(int32_t height) { - if ((strcmp(ASSETCHAINS_SYMBOL, "VRSC") == 0) || (height < 96480)) + if ((strcmp(ASSETCHAINS_SYMBOL, "VRSC") == 0) && (height < 96480)) return false; else if ((strcmp(ASSETCHAINS_SYMBOL, "VRSCTEST") == 0) && (height < 1000)) return false; diff --git a/src/primitives/nonce.h b/src/primitives/nonce.h index f92c983e5..97863e528 100644 --- a/src/primitives/nonce.h +++ b/src/primitives/nonce.h @@ -11,8 +11,7 @@ /** For POS blocks, the nNonce of a block header holds the entropy source for the POS contest - * in the latest VerusHash protocol, implemented at block below - * + * in the latest VerusHash protocol * */ class CPOSNonce : public uint256 { diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 8043fe5a5..852aa4181 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -487,7 +487,7 @@ public: { hashWriter << *pNonce; hashWriter << height; - return hashWriter.GetHash(); + return ArithToUint256(UintToArith256(hashWriter.GetHash()) / value); } else { @@ -495,7 +495,7 @@ public: hashWriter << height; hashWriter << txid; hashWriter << voutNum; - return hashWriter.GetHash(); + return ArithToUint256(UintToArith256(hashWriter.GetHash()) / value); } } @@ -507,7 +507,7 @@ public: if (voutNum >= vout.size()) return uint256S("ff0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); - return ArithToUint256(UintToArith256(_GetVerusPOSHash(pNonce, txid, voutNum, height, pastHash, (uint64_t)vout[voutNum].nValue)) / vout[voutNum].nValue); + return _GetVerusPOSHash(pNonce, txid, voutNum, height, pastHash, (uint64_t)vout[voutNum].nValue); } std::string ToString() const; From 17d0160a17f0e45f211fb2d0ddf4f2a97d296ab4 Mon Sep 17 00:00:00 2001 From: Michael Toutonghi Date: Fri, 20 Jul 2018 19:57:46 -0700 Subject: [PATCH 4/6] Cleanup nonce changes --- src/Makefile.am | 2 ++ src/crypto/verus_hash.h | 3 ++- src/hash.h | 2 +- src/komodo_bitcoind.h | 5 +++++ src/miner.cpp | 2 +- src/primitives/block.h | 19 +++++++++++-------- src/primitives/nonce.cpp | 21 ++++++++++++++------- src/primitives/nonce.h | 21 ++++++++++----------- src/wallet/wallet.cpp | 7 +++++-- src/wallet/wallet.h | 4 ++-- 10 files changed, 53 insertions(+), 33 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index a8d7b1bbc..e22e37137 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -271,6 +271,7 @@ libbitcoin_server_a_SOURCES = \ crypto/haraka.h \ crypto/haraka_portable.h \ crypto/verus_hash.h \ + crypto/verus_hash.cpp \ deprecation.cpp \ httprpc.cpp \ httpserver.cpp \ @@ -410,6 +411,7 @@ libbitcoin_common_a_SOURCES = \ crypto/haraka.h \ crypto/haraka_portable.h \ crypto/verus_hash.h \ + crypto/verus_hash.cpp \ hash.cpp \ key.cpp \ keystore.cpp \ diff --git a/src/crypto/verus_hash.h b/src/crypto/verus_hash.h index 33fc0ce5d..07c76d0f5 100644 --- a/src/crypto/verus_hash.h +++ b/src/crypto/verus_hash.h @@ -27,7 +27,7 @@ class CVerusHash static void init(); - CVerusHash() {} + CVerusHash() { } CVerusHash &Write(const unsigned char *data, size_t len); @@ -37,6 +37,7 @@ class CVerusHash result = buf2; curPos = 0; std::fill(buf1, buf1 + sizeof(buf1), 0); + return *this; } int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); } diff --git a/src/hash.h b/src/hash.h index 1a129b720..537ba3dcb 100644 --- a/src/hash.h +++ b/src/hash.h @@ -203,7 +203,7 @@ public: int nType; int nVersion; - CVerusHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn), state() {} + CVerusHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn), state() { } CVerusHashWriter& write(const char *pch, size_t size) { state.Write((const unsigned char*)pch, size); diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 87c4875fb..7af71828d 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1271,7 +1271,12 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height) CTransaction tx; if (!pblock->IsVerusPOSBlock()) + { + printf("%s, height %d not POS block\n", pblock->nNonce.GetHex().c_str(), height); + pblock->nNonce.SetPOSTarget(pblock->nNonce.GetPOSTarget()); + printf("%s after setting POS target\n", pblock->nNonce.GetHex().c_str()); return false; + } char voutaddr[64], destaddr[64], cbaddr[64]; diff --git a/src/miner.cpp b/src/miner.cpp index 2f71e0564..86235aa4b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -462,9 +462,9 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, bool isStake) { uint32_t nBitsPOS; arith_uint256 posHash; + siglen = verus_staked(pblock, key, txStaked, nBitsPOS, posHash, utxosig); blocktime = GetAdjustedTime(); - pblock->SetVerusPOSTarget(nBitsPOS); // change the scriptPubKeyIn to the same output script exactly as the staking transaction if (siglen > 0) diff --git a/src/primitives/block.h b/src/primitives/block.h index 06e26f4c5..12bffbeab 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -95,7 +95,7 @@ public: return (int64_t)nTime; } - int32_t GetVerusPOSTarget() const + uint32_t GetVerusPOSTarget() const { uint32_t nBits = 0; @@ -112,19 +112,22 @@ public: return nNonce.IsPOSNonce(); } - void SetVerusPOSTarget(int32_t nBits) + void SetVerusPOSTarget(uint32_t nBits) { CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); - uint256 hash; - arith_uint256 tmpNonce; arith_uint256 arNonce = UintToArith256(nNonce); - arNonce = ((arNonce >> 32) << 32) | nBits; - tmpNonce = ((arNonce << 128) >> 128); - hashWriter << ArithToUint256(tmpNonce); + // printf("before svpt: %s\n", ArithToUint256(arNonce).GetHex().c_str()); - nNonce = ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | tmpNonce); + arNonce = (arNonce & CPOSNonce::entropyMask) | nBits; + + // printf("after clear: %s\n", ArithToUint256(arNonce).GetHex().c_str()); + + hashWriter << ArithToUint256(arNonce); + nNonce = CPOSNonce(ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | arNonce)); + + // printf(" after svpt: %s\n", nNonce.GetHex().c_str()); } }; diff --git a/src/primitives/nonce.cpp b/src/primitives/nonce.cpp index e7ad618ee..58970a80f 100644 --- a/src/primitives/nonce.cpp +++ b/src/primitives/nonce.cpp @@ -8,6 +8,9 @@ extern char ASSETCHAINS_SYMBOL[65]; +arith_uint256 CPOSNonce::entropyMask = UintToArith256(uint256S("00000000000000000000000000000000ffffffffffffffffffffffff00000000")); +arith_uint256 CPOSNonce::posDiffMask = UintToArith256(uint256S("00000000000000000000000000000000000000000000000000000000ffffffff")); + bool CPOSNonce::NewPOSActive(int32_t height) { if ((strcmp(ASSETCHAINS_SYMBOL, "VRSC") == 0) && (height < (96480 + 100))) @@ -38,13 +41,17 @@ void CPOSNonce::SetPOSEntropy(const uint256 &pastHash, uint256 txid, int32_t vou hashWriter << txid; hashWriter << voutNum; - arith_uint256 arNonce = (UintToArith256(*this) & 0xffffffff) | - ((UintToArith256(hashWriter.GetHash()) & UintToArith256(uint256S("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))) << 32); + arith_uint256 arNonce = (UintToArith256(*this) & posDiffMask) | + (UintToArith256(hashWriter.GetHash()) & entropyMask); - hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); - hashWriter << ArithToUint256(arNonce); + // printf("before %s\n", ArithToUint256(arNonce).GetHex().c_str()); - *this = CPOSNonce(ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | arNonce)); + CVerusHashWriter newWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); + newWriter << ArithToUint256(arNonce); + + *this = CPOSNonce(ArithToUint256((UintToArith256(newWriter.GetHash()) << 128) | arNonce)); + + // printf("after %s\n", this->GetHex().c_str()); } bool CPOSNonce::CheckPOSEntropy(const uint256 &pastHash, uint256 txid, int32_t voutNum) @@ -57,8 +64,8 @@ bool CPOSNonce::CheckPOSEntropy(const uint256 &pastHash, uint256 txid, int32_t v hashWriter << txid; hashWriter << voutNum; - arith_uint256 arNonce = (UintToArith256(*this) & 0xffffffff) | - ((UintToArith256(hashWriter.GetHash()) & UintToArith256(uint256S("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))) << 32); + arith_uint256 arNonce = (UintToArith256(*this) & posDiffMask) | + (UintToArith256(hashWriter.GetHash()) & entropyMask); hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); hashWriter << ArithToUint256(arNonce); diff --git a/src/primitives/nonce.h b/src/primitives/nonce.h index 97863e528..a3da4b6b5 100644 --- a/src/primitives/nonce.h +++ b/src/primitives/nonce.h @@ -19,9 +19,12 @@ public: static bool NewPOSActive(int32_t height); static bool NewNonceActive(int32_t height); - CPOSNonce() {} - CPOSNonce(const base_blob<256> &b) : uint256(b) {} - CPOSNonce(const std::vector &vch) : uint256(vch) {} + static arith_uint256 entropyMask; + static arith_uint256 posDiffMask; + + CPOSNonce() : uint256() { } + CPOSNonce(const base_blob<256> &b) : uint256(b) { } + CPOSNonce(const std::vector &vch) : uint256(vch) { } int32_t GetPOSTarget() const { @@ -44,18 +47,14 @@ public: return (*this == ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | tmpNonce)); } - void SetPOSTarget(int32_t nBits) + void SetPOSTarget(uint32_t nBits) { CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); - arith_uint256 tmpNonce; - arith_uint256 arNonce = UintToArith256(*this); - arNonce = ((arNonce >> 32) << 32) | nBits; + arith_uint256 arNonce = (UintToArith256(*this) & entropyMask) | nBits; + hashWriter << ArithToUint256(arNonce); - tmpNonce = ((arNonce << 128) >> 128); - hashWriter << ArithToUint256(tmpNonce); - - (uint256 &)(*this) = ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | tmpNonce); + (uint256 &)(*this) = ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | arNonce); } void SetPOSEntropy(const uint256 &pastHash, uint256 txid, int32_t voutNum); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 275da8258..8c6b1eb50 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -998,7 +998,7 @@ CWallet::TxItems CWallet::OrderedTxItems(std::list& acentries, // UTXO with the smallest coin age if there is more than one, as larger coin age will win more often and is worth saving // each attempt consists of taking a VerusHash of the following values: // ASSETCHAINS_MAGIC, nHeight, txid, voutNum -bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, uint32_t bnTarget) const +bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, uint32_t &bnTarget) const { arith_uint256 target; arith_uint256 curHash; @@ -1017,6 +1017,7 @@ bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, { CBlockHeader bh = pastBlockIndex->GetBlockHeader(); uint256 pastHash = bh.GetVerusEntropyHash(nHeight); + CPOSNonce curNonce; BOOST_FOREACH(COutput &txout, vecOutputs) { @@ -1026,19 +1027,21 @@ bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, if (Solver(txout.tx->vout[txout.i].scriptPubKey, whichType, vSolutions) && (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH) && (!pwinner || pwinner->tx->vout[pwinner->i].nValue > txout.tx->vout[txout.i].nValue)) pwinner = &txout; + curNonce = pBlock->nNonce; } } if (pwinner) { stakeSource = *(pwinner->tx); voutNum = pwinner->i; + pBlock->nNonce = curNonce; return true; } } return false; } -int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNew, uint32_t bnTarget, arith_uint256 &hashResult, uint8_t *utxosig) const +int32_t CWallet::VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &bnTarget, arith_uint256 &hashResult, uint8_t *utxosig) const { CTransaction stakeSource; int32_t voutNum, siglen = 0; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 8568bf9c2..d42d3343c 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1149,8 +1149,8 @@ public: bool ignoreUnspendable=true); // staking functions - bool VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, uint32_t bnTarget) const; - int32_t VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNew, uint32_t bnTarget, arith_uint256 &hashResult, uint8_t *utxosig) const; + bool VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, uint32_t &bnTarget) const; + int32_t VerusStakeTransaction(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &bnTarget, arith_uint256 &hashResult, uint8_t *utxosig) const; }; /** A key allocated from the key pool. */ From 3f8720fabe0b06e5c14f0f6a7b491c61287b0cb5 Mon Sep 17 00:00:00 2001 From: Michael Toutonghi Date: Fri, 20 Jul 2018 20:57:28 -0700 Subject: [PATCH 5/6] Fix new nonce issue --- src/hash.h | 2 ++ src/primitives/nonce.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hash.h b/src/hash.h index 537ba3dcb..d288af305 100644 --- a/src/hash.h +++ b/src/hash.h @@ -204,6 +204,7 @@ public: int nVersion; CVerusHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn), state() { } + void Reset() { state.Reset(); } CVerusHashWriter& write(const char *pch, size_t size) { state.Write((const unsigned char*)pch, size); @@ -239,6 +240,7 @@ public: int nVersion; CVerusHashV2Writer(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn), state() {} + void Reset() { state.Reset(); } CVerusHashV2Writer& write(const char *pch, size_t size) { state.Write((const unsigned char*)pch, size); diff --git a/src/primitives/nonce.cpp b/src/primitives/nonce.cpp index 58970a80f..6ff258174 100644 --- a/src/primitives/nonce.cpp +++ b/src/primitives/nonce.cpp @@ -46,10 +46,10 @@ void CPOSNonce::SetPOSEntropy(const uint256 &pastHash, uint256 txid, int32_t vou // printf("before %s\n", ArithToUint256(arNonce).GetHex().c_str()); - CVerusHashWriter newWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); - newWriter << ArithToUint256(arNonce); + hashWriter.Reset(); + hashWriter << ArithToUint256(arNonce); - *this = CPOSNonce(ArithToUint256((UintToArith256(newWriter.GetHash()) << 128) | arNonce)); + *this = CPOSNonce(ArithToUint256((UintToArith256(hashWriter.GetHash()) << 128) | arNonce)); // printf("after %s\n", this->GetHex().c_str()); } @@ -67,7 +67,7 @@ bool CPOSNonce::CheckPOSEntropy(const uint256 &pastHash, uint256 txid, int32_t v arith_uint256 arNonce = (UintToArith256(*this) & posDiffMask) | (UintToArith256(hashWriter.GetHash()) & entropyMask); - hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); + hashWriter.Reset(); hashWriter << ArithToUint256(arNonce); return UintToArith256(*this) == (UintToArith256(hashWriter.GetHash()) << 128 | arNonce); From d7e6718dc89015afed82376388ceba65bb2040a7 Mon Sep 17 00:00:00 2001 From: Michael Toutonghi Date: Fri, 20 Jul 2018 22:59:33 -0700 Subject: [PATCH 6/6] More nonce and new PoS reporting improvements --- src/komodo_bitcoind.h | 2 +- src/miner.cpp | 16 +++++++++++++++- src/primitives/block.cpp | 2 +- src/wallet/wallet.cpp | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 7af71828d..2c1af165f 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1303,7 +1303,7 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height) else { CBlockHeader bh = pastBlockIndex->GetBlockHeader(); - uint256 pastHash = bh.GetVerusEntropyHash(height); + uint256 pastHash = bh.GetVerusEntropyHash(height - 100); // if height is over when Nonce is required to be the new format, we check that the new format is correct // if over when we have the new POS hash function, we validate that as well diff --git a/src/miner.cpp b/src/miner.cpp index 86235aa4b..53b69069e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -804,6 +804,18 @@ int32_t waitForPeers(const CChainParams &chainparams) } #ifdef ENABLE_WALLET +CBlockIndex *get_chainactive(int32_t height) +{ + if ( chainActive.Tip() != 0 ) + { + if ( height <= chainActive.Tip()->nHeight ) + return(chainActive[height]); + // else fprintf(stderr,"get_chainactive height %d > active.%d\n",height,chainActive.Tip()->nHeight); + } + //fprintf(stderr,"get_chainactive null chainActive.Tip() height %d\n",height); + return(0); +} + /* * A separate thread to stake, while the miner threads mine. */ @@ -959,7 +971,9 @@ void static VerusStaker(CWallet *pwallet) printf("staking reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL); arith_uint256 post; post.SetCompact(pblock->GetVerusPOSTarget()); - printf(" hash: %s \ntarget: %s\n", pblock->vtx[pblock->vtx.size()-1].GetVerusPOSHash(&(pblock->nNonce), 0, Mining_height, pindexPrev->GetBlockHeader().GetVerusEntropyHash(Mining_height)).GetHex().c_str(), ArithToUint256(post).GetHex().c_str()); + pindexPrev = get_chainactive(Mining_height - 100); + printf(" hash: %s \ntarget: %s\n", + CTransaction::_GetVerusPOSHash(&(pblock->nNonce), pblock->vtx[pblock->vtx.size()-1].vin[0].prevout.hash, 0, Mining_height, pindexPrev->GetBlockHeader().GetVerusEntropyHash(Mining_height - 100), pblock->vtx[pblock->vtx.size()-1].vout[0].nValue).GetHex().c_str(), ArithToUint256(post).GetHex().c_str()); if (unlockTime > Mining_height && subsidy >= ASSETCHAINS_TIMELOCKGTE) printf("- timelocked until block %i\n", unlockTime); else diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 39d338959..a638131a0 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -65,7 +65,7 @@ bool CBlockHeader::GetRawVerusPOSHash(uint256 &value, int32_t nHeight) const // ) // hashWriter << height; // return hashWriter.GetHash(); - CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); + CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); hashWriter << ASSETCHAINS_MAGIC; hashWriter << nNonce; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8c6b1eb50..e12a352a6 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1016,7 +1016,7 @@ bool CWallet::VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, if (pastBlockIndex = komodo_chainactive(nHeight - 100)) { CBlockHeader bh = pastBlockIndex->GetBlockHeader(); - uint256 pastHash = bh.GetVerusEntropyHash(nHeight); + uint256 pastHash = bh.GetVerusEntropyHash(nHeight - 100); CPOSNonce curNonce; BOOST_FOREACH(COutput &txout, vecOutputs)