Merge pull request #98 from VerusCoin/dev

Dev
This commit is contained in:
Asher Dawes
2018-07-22 20:03:05 -07:00
committed by GitHub
17 changed files with 350 additions and 80 deletions

View File

@@ -191,6 +191,7 @@ BITCOIN_CORE_H = \
pow.h \ pow.h \
primitives/block.h \ primitives/block.h \
primitives/transaction.h \ primitives/transaction.h \
primitives/nonce.h \
protocol.h \ protocol.h \
pubkey.h \ pubkey.h \
random.h \ random.h \
@@ -270,6 +271,7 @@ libbitcoin_server_a_SOURCES = \
crypto/haraka.h \ crypto/haraka.h \
crypto/haraka_portable.h \ crypto/haraka_portable.h \
crypto/verus_hash.h \ crypto/verus_hash.h \
crypto/verus_hash.cpp \
deprecation.cpp \ deprecation.cpp \
httprpc.cpp \ httprpc.cpp \
httpserver.cpp \ httpserver.cpp \
@@ -409,12 +411,14 @@ libbitcoin_common_a_SOURCES = \
crypto/haraka.h \ crypto/haraka.h \
crypto/haraka_portable.h \ crypto/haraka_portable.h \
crypto/verus_hash.h \ crypto/verus_hash.h \
crypto/verus_hash.cpp \
hash.cpp \ hash.cpp \
key.cpp \ key.cpp \
keystore.cpp \ keystore.cpp \
netbase.cpp \ netbase.cpp \
primitives/block.cpp \ primitives/block.cpp \
primitives/transaction.cpp \ primitives/transaction.cpp \
primitives/nonce.cpp \
protocol.cpp \ protocol.cpp \
pubkey.cpp \ pubkey.cpp \
scheduler.cpp \ scheduler.cpp \
@@ -624,6 +628,7 @@ libzcashconsensus_la_SOURCES = \
crypto/sha512.cpp \ crypto/sha512.cpp \
hash.cpp \ hash.cpp \
primitives/transaction.cpp \ primitives/transaction.cpp \
primitives/nonce.cpp \
pubkey.cpp \ pubkey.cpp \
script/zcashconsensus.cpp \ script/zcashconsensus.cpp \
script/interpreter.cpp \ script/interpreter.cpp \

View File

@@ -11,6 +11,7 @@ using namespace std;
* CChain implementation * CChain implementation
*/ */
void CChain::SetTip(CBlockIndex *pindex) { void CChain::SetTip(CBlockIndex *pindex) {
lastTip = pindex;
if (pindex == NULL) { if (pindex == NULL) {
vChain.clear(); vChain.clear();
return; return;

View File

@@ -424,6 +424,7 @@ public:
class CChain { class CChain {
private: private:
std::vector<CBlockIndex*> vChain; std::vector<CBlockIndex*> vChain;
CBlockIndex *lastTip;
public: public:
/** Returns the index entry for the genesis block of this chain, or NULL if none. */ /** 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; 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. */ /** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */
CBlockIndex *operator[](int nHeight) const { CBlockIndex *operator[](int nHeight) const {
if (nHeight < 0 || nHeight >= (int)vChain.size()) if (nHeight < 0 || nHeight >= (int)vChain.size())

View File

@@ -253,7 +253,16 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
uint256 CCoinsViewCache::GetBestBlock() const { uint256 CCoinsViewCache::GetBestBlock() const {
if (hashBlock.IsNull()) if (hashBlock.IsNull())
hashBlock = base->GetBestBlock(); {
if (base)
{
hashBlock = base->GetBestBlock();
}
else
{
hashBlock = uint256();
}
}
return hashBlock; return hashBlock;
} }

View File

@@ -27,7 +27,7 @@ class CVerusHash
static void init(); static void init();
CVerusHash() {} CVerusHash() { }
CVerusHash &Write(const unsigned char *data, size_t len); CVerusHash &Write(const unsigned char *data, size_t len);
@@ -37,6 +37,7 @@ class CVerusHash
result = buf2; result = buf2;
curPos = 0; curPos = 0;
std::fill(buf1, buf1 + sizeof(buf1), 0); std::fill(buf1, buf1 + sizeof(buf1), 0);
return *this;
} }
int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); } int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); }

View File

@@ -203,7 +203,8 @@ public:
int nType; int nType;
int nVersion; int nVersion;
CVerusHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn), state() {} CVerusHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn), state() { }
void Reset() { state.Reset(); }
CVerusHashWriter& write(const char *pch, size_t size) { CVerusHashWriter& write(const char *pch, size_t size) {
state.Write((const unsigned char*)pch, size); state.Write((const unsigned char*)pch, size);
@@ -239,6 +240,7 @@ public:
int nVersion; int nVersion;
CVerusHashV2Writer(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn), state() {} CVerusHashV2Writer(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn), state() {}
void Reset() { state.Reset(); }
CVerusHashV2Writer& write(const char *pch, size_t size) { CVerusHashV2Writer& write(const char *pch, size_t size) {
state.Write((const unsigned char*)pch, size); state.Write((const unsigned char*)pch, size);

View File

@@ -1258,7 +1258,7 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_
return(isPoS); 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) bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
{ {
CBlockIndex *pastBlockIndex; CBlockIndex *pastBlockIndex;
@@ -1271,15 +1271,20 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
CTransaction tx; CTransaction tx;
if (!pblock->IsVerusPOSBlock()) 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; return false;
}
char voutaddr[64], destaddr[64], cbaddr[64]; char voutaddr[64], destaddr[64], cbaddr[64];
target.SetCompact(pblock->GetVerusPOSTarget());
txn_count = pblock->vtx.size(); txn_count = pblock->vtx.size();
if ( txn_count > 1 ) if ( txn_count > 1 )
{ {
target.SetCompact(pblock->GetVerusPOSTarget());
txid = pblock->vtx[txn_count-1].vin[0].prevout.hash; txid = pblock->vtx[txn_count-1].vin[0].prevout.hash;
voutNum = pblock->vtx[txn_count-1].vin[0].prevout.n; voutNum = pblock->vtx[txn_count-1].vin[0].prevout.n;
@@ -1291,20 +1296,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()); 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 else
{ {
hash = UintToArith256(tx.GetVerusPOSHash(voutNum, height, pastBlockIndex->GetBlockHash())); CBlockHeader bh = pastBlockIndex->GetBlockHeader();
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
// they are 100 blocks apart
CPOSNonce nonce = pblock->nNonce;
hash = UintToArith256(tx.GetVerusPOSHash(&nonce, voutNum, height, pastHash));
if (hash <= target) if (hash <= target)
{ {
if ((mapBlockIndex.count(blkHash) == 0) || if ((mapBlockIndex.count(blkHash) == 0) ||
!(pastBlockIndex = mapBlockIndex[blkHash]) || !(pastBlockIndex = mapBlockIndex[blkHash]) ||
(height - pastBlockIndex->nHeight) < VERUS_MIN_STAKEAGE) (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 ) else if ( slowflag != 0 )
{ {
@@ -1317,13 +1330,24 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
else else
{ {
arith_uint256 cTarget; arith_uint256 cTarget;
cTarget.SetCompact(lwmaGetNextPOSRequired(previndex, Params().GetConsensus())); uint32_t nBits = lwmaGetNextPOSRequired(previndex, Params().GetConsensus());
cTarget.SetCompact(nBits);
bool nonceOK = true;
if (cTarget != target) 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) && ExtractDestination(tx.vout[voutNum].scriptPubKey, destaddress) &&
CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) ) CScriptExt::ExtractVoutDestination(pblock->vtx[0], 0, cbaddress) )
{ {

View File

@@ -3149,7 +3149,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
list<CTransaction> removed; list<CTransaction> removed;
CValidationState stateDummy; CValidationState stateDummy;
// don't keep staking or invalid transactions // 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); 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++) for (int i = 0; i < block.vtx.size(); i++)
{ {
CTransaction &tx = block.vtx[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()); EraseFromWallets(tx.GetHash());
} }

View File

@@ -128,7 +128,7 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_
int64_t komodo_block_unlocktime(uint32_t nHeight); int64_t komodo_block_unlocktime(uint32_t nHeight);
uint64_t komodo_commission(const CBlock *block); 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 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); int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33);
CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, bool isStake) CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, bool isStake)
@@ -370,7 +370,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, bool isStake)
//fprintf(stderr,"dont have inputs\n"); //fprintf(stderr,"dont have inputs\n");
continue; 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); nTxSigOps += GetP2SHSigOpCount(tx, view);
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1) if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1)
@@ -462,9 +462,9 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, bool isStake)
{ {
uint32_t nBitsPOS; uint32_t nBitsPOS;
arith_uint256 posHash; arith_uint256 posHash;
siglen = verus_staked(key, txStaked, nBitsPOS, posHash, utxosig);
siglen = verus_staked(pblock, key, txStaked, nBitsPOS, posHash, utxosig);
blocktime = GetAdjustedTime(); blocktime = GetAdjustedTime();
pblock->SetVerusPOSTarget(nBitsPOS);
// change the scriptPubKeyIn to the same output script exactly as the staking transaction // change the scriptPubKeyIn to the same output script exactly as the staking transaction
if (siglen > 0) if (siglen > 0)
@@ -485,7 +485,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, bool isStake)
pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txStaked)); pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txStaked));
nFees += txfees; nFees += txfees;
pblock->nTime = blocktime; 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"); } else return(0); //fprintf(stderr,"no utxos eligible for staking\n");
} }
@@ -723,11 +723,11 @@ static bool ProcessBlockFound(CBlock* pblock)
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
{ {
LogPrintf("%s\n", pblock->ToString()); 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 // Found a solution
{ {
LOCK(cs_main); 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()) if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash())
{ {
uint256 hash; int32_t i; 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 // Process this block the same as if we had received it from another node
CValidationState state; 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"); return error("KomodoMiner: ProcessNewBlock, block not accepted");
TrackMinedBlock(pblock->GetHash()); TrackMinedBlock(pblock->GetHash());
@@ -804,6 +804,18 @@ int32_t waitForPeers(const CChainParams &chainparams)
} }
#ifdef ENABLE_WALLET #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. * A separate thread to stake, while the miner threads mine.
*/ */
@@ -852,9 +864,10 @@ void static VerusStaker(CWallet *pwallet)
sleep(5); sleep(5);
{ {
LOCK(cs_main);
printf("Staking height %d for %s\n", chainActive.Tip()->nHeight + 1, ASSETCHAINS_SYMBOL); 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(); miningTimer.start();
@@ -867,7 +880,7 @@ void static VerusStaker(CWallet *pwallet)
// Create new block // Create new block
unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrev = chainActive.Tip(); CBlockIndex* pindexPrev = chainActive.LastTip();
if ( Mining_height != pindexPrev->nHeight+1 ) if ( Mining_height != pindexPrev->nHeight+1 )
{ {
Mining_height = pindexPrev->nHeight+1; Mining_height = pindexPrev->nHeight+1;
@@ -885,8 +898,8 @@ void static VerusStaker(CWallet *pwallet)
if ( ptr == 0 ) if ( ptr == 0 )
{ {
// wait to try another staking block until after the tip moves again // wait to try another staking block until after the tip moves again
while ( chainActive.Tip() == pindexPrev ) while ( chainActive.LastTip() == pindexPrev )
sleep(5); sleep(1);
continue; continue;
} }
@@ -932,9 +945,9 @@ void static VerusStaker(CWallet *pwallet)
continue; 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); MilliSleep(250);
continue; continue;
} }
@@ -958,7 +971,9 @@ void static VerusStaker(CWallet *pwallet)
printf("staking reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL); printf("staking reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL);
arith_uint256 post; arith_uint256 post;
post.SetCompact(pblock->GetVerusPOSTarget()); 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()); 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) if (unlockTime > Mining_height && subsidy >= ASSETCHAINS_TIMELOCKGTE)
printf("- timelocked until block %i\n", unlockTime); printf("- timelocked until block %i\n", unlockTime);
else else
@@ -1024,9 +1039,9 @@ void static BitcoinMiner_noeq()
waitForPeers(chainparams); waitForPeers(chainparams);
CBlockIndex *pindexPrev, *pindexCur; CBlockIndex *pindexPrev, *pindexCur;
do { do {
pindexPrev = chainActive.Tip(); pindexPrev = chainActive.LastTip();
MilliSleep(5000 + rand() % 5000); MilliSleep(5000 + rand() % 5000);
pindexCur = chainActive.Tip(); pindexCur = chainActive.LastTip();
} while (pindexPrev != pindexCur); } while (pindexPrev != pindexCur);
// this will not stop printing more than once in all cases, but it will allow us to print in all cases // this will not stop printing more than once in all cases, but it will allow us to print in all cases
@@ -1042,16 +1057,16 @@ void static BitcoinMiner_noeq()
miningTimer.stop(); miningTimer.stop();
waitForPeers(chainparams); waitForPeers(chainparams);
pindexPrev = chainActive.Tip(); pindexPrev = chainActive.LastTip();
sleep(1); sleep(1);
// prevent forking on startup before the diff algorithm kicks in // 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 { do {
pindexPrev = chainActive.Tip(); pindexPrev = chainActive.LastTip();
MilliSleep(5000 + rand() % 5000); MilliSleep(5000 + rand() % 5000);
} while (pindexPrev != chainActive.Tip()); } while (pindexPrev != chainActive.LastTip());
} }
// Create new block // Create new block
@@ -1125,11 +1140,11 @@ void static BitcoinMiner_noeq()
Mining_start = 0; 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); printf("Block %d added to chain\n", lastChainTipPrinted->nHeight);
} }
MilliSleep(250); MilliSleep(250);
@@ -1200,11 +1215,11 @@ void static BitcoinMiner_noeq()
// check periodically if we're stale // check periodically if we're stale
if (!--hashesToGo) 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); printf("Block %d added to chain\n", lastChainTipPrinted->nHeight);
} }
break; break;
@@ -1236,11 +1251,11 @@ void static BitcoinMiner_noeq()
break; 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); printf("Block %d added to chain\n", lastChainTipPrinted->nHeight);
} }
break; break;

View File

@@ -10,6 +10,8 @@
#include "utilstrencodings.h" #include "utilstrencodings.h"
#include "crypto/common.h" #include "crypto/common.h"
extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH;
// default hash algorithm for block // default hash algorithm for block
uint256 (CBlockHeader::*CBlockHeader::hashFunction)() const = &CBlockHeader::GetSHA256DHash; uint256 (CBlockHeader::*CBlockHeader::hashFunction)() const = &CBlockHeader::GetSHA256DHash;
@@ -43,6 +45,48 @@ void CBlockHeader::SetVerusHash()
CBlockHeader::hashFunction = &CBlockHeader::GetVerusHash; 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. 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
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 (GetRawVerusPOSHash(retVal, height))
{
// POS hash
return retVal;
}
return GetHash();
}
uint256 CBlock::BuildMerkleTree(bool* fMutated) const uint256 CBlock::BuildMerkleTree(bool* fMutated) const
{ {
/* WARNING! If you're reading this because you're learning about crypto /* WARNING! If you're reading this because you're learning about crypto

View File

@@ -7,6 +7,7 @@
#define BITCOIN_PRIMITIVES_BLOCK_H #define BITCOIN_PRIMITIVES_BLOCK_H
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include "primitives/nonce.h"
#include "serialize.h" #include "serialize.h"
#include "uint256.h" #include "uint256.h"
#include "arith_uint256.h" #include "arith_uint256.h"
@@ -33,7 +34,7 @@ public:
uint256 hashReserved; uint256 hashReserved;
uint32_t nTime; uint32_t nTime;
uint32_t nBits; uint32_t nBits;
uint256 nNonce; CPOSNonce nNonce;
std::vector<unsigned char> nSolution; std::vector<unsigned char> nSolution;
CBlockHeader() CBlockHeader()
@@ -84,6 +85,9 @@ public:
uint256 GetVerusHash() const; uint256 GetVerusHash() const;
static void SetVerusHash(); static void SetVerusHash();
bool GetRawVerusPOSHash(uint256 &value, int32_t nHeight) const;
uint256 GetVerusEntropyHash(int32_t nHeight) const;
uint256 GetVerusV2Hash() const; uint256 GetVerusV2Hash() const;
int64_t GetBlockTime() const int64_t GetBlockTime() const
@@ -91,7 +95,7 @@ public:
return (int64_t)nTime; return (int64_t)nTime;
} }
int32_t GetVerusPOSTarget() const uint32_t GetVerusPOSTarget() const
{ {
uint32_t nBits = 0; uint32_t nBits = 0;
@@ -105,26 +109,25 @@ public:
bool IsVerusPOSBlock() const bool IsVerusPOSBlock() const
{ {
arith_uint256 arNonce = UintToArith256(nNonce); return nNonce.IsPOSNonce();
arith_uint256 tmpNonce = ((arNonce << 128) >> 128);
CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
hashWriter << ArithToUint256(tmpNonce);
return (nNonce == ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | tmpNonce));
} }
void SetVerusPOSTarget(int32_t nBits) void SetVerusPOSTarget(uint32_t nBits)
{ {
CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
uint256 hash;
arith_uint256 tmpNonce;
arith_uint256 arNonce = UintToArith256(nNonce); arith_uint256 arNonce = UintToArith256(nNonce);
arNonce = ((arNonce >> 32) << 32) | nBits;
tmpNonce = ((arNonce << 128) >> 128); // printf("before svpt: %s\n", ArithToUint256(arNonce).GetHex().c_str());
hashWriter << ArithToUint256(tmpNonce);
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());
} }
}; };

75
src/primitives/nonce.cpp Normal file
View File

@@ -0,0 +1,75 @@
// 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 <cstring>
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)))
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) & posDiffMask) |
(UintToArith256(hashWriter.GetHash()) & entropyMask);
// printf("before %s\n", ArithToUint256(arNonce).GetHex().c_str());
hashWriter.Reset();
hashWriter << ArithToUint256(arNonce);
*this = CPOSNonce(ArithToUint256((UintToArith256(hashWriter.GetHash()) << 128) | arNonce));
// printf("after %s\n", this->GetHex().c_str());
}
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) & posDiffMask) |
(UintToArith256(hashWriter.GetHash()) & entropyMask);
hashWriter.Reset();
hashWriter << ArithToUint256(arNonce);
return UintToArith256(*this) == (UintToArith256(hashWriter.GetHash()) << 128 | arNonce);
}

64
src/primitives/nonce.h Normal file
View File

@@ -0,0 +1,64 @@
// 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
* */
class CPOSNonce : public uint256
{
public:
static bool NewPOSActive(int32_t height);
static bool NewNonceActive(int32_t height);
static arith_uint256 entropyMask;
static arith_uint256 posDiffMask;
CPOSNonce() : uint256() { }
CPOSNonce(const base_blob<256> &b) : uint256(b) { }
CPOSNonce(const std::vector<unsigned char> &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(uint32_t nBits)
{
CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
arith_uint256 arNonce = (UintToArith256(*this) & entropyMask) | nBits;
hashWriter << ArithToUint256(arNonce);
(uint256 &)(*this) = ArithToUint256(UintToArith256(hashWriter.GetHash()) << 128 | arNonce);
}
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

View File

@@ -14,6 +14,7 @@
#include "arith_uint256.h" #include "arith_uint256.h"
#include "consensus/consensus.h" #include "consensus/consensus.h"
#include "hash.h" #include "hash.h"
#include "nonce.h"
#ifndef __APPLE__ #ifndef __APPLE__
#include <stdint.h> #include <stdint.h>
@@ -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 // 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); CVerusHashWriter hashWriter = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
hashWriter << ASSETCHAINS_MAGIC; hashWriter << ASSETCHAINS_MAGIC;
hashWriter << pastHash;
hashWriter << height; // we only use the new style of POS hash after changeover and 100 blocks of enforced proper nonce updating
hashWriter << txid; if (CPOSNonce::NewPOSActive(height))
hashWriter << voutNum; {
return hashWriter.GetHash(); hashWriter << *pNonce;
hashWriter << height;
return ArithToUint256(UintToArith256(hashWriter.GetHash()) / value);
}
else
{
hashWriter << pastHash;
hashWriter << height;
hashWriter << txid;
hashWriter << voutNum;
return ArithToUint256(UintToArith256(hashWriter.GetHash()) / value);
}
} }
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(); uint256 txid = GetHash();
if (voutNum >= vout.size()) if (voutNum >= vout.size())
return uint256S("ff0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); return uint256S("ff0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f");
return ArithToUint256(UintToArith256(_GetVerusPOSHash(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; std::string ToString() const;

View File

@@ -4667,7 +4667,7 @@ int32_t komodo_staked(CPubKey &pubkey, CMutableTransaction &txNew,uint32_t nBits
return(siglen); 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);
} }

View File

@@ -998,8 +998,9 @@ CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& 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 // 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: // each attempt consists of taking a VerusHash of the following values:
// ASSETCHAINS_MAGIC, nHeight, txid, voutNum // 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; arith_uint256 curHash;
vector<COutput> vecOutputs; vector<COutput> vecOutputs;
COutput *pwinner = NULL; COutput *pwinner = NULL;
@@ -1007,35 +1008,41 @@ bool CWallet::VerusSelectStakeOutput(arith_uint256 &hashResult, CTransaction &st
txnouttype whichType; txnouttype whichType;
std:vector<std::vector<unsigned char>> vSolutions; std:vector<std::vector<unsigned char>> vSolutions;
pBlock->nNonce.SetPOSTarget(bnTarget);
target.SetCompact(bnTarget);
pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false); 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 - 100);
CPOSNonce curNonce;
BOOST_FOREACH(COutput &txout, vecOutputs) 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 // get the smallest winner
if (Solver(txout.tx->vout[txout.i].scriptPubKey, whichType, vSolutions) && (whichType == TX_PUBKEY || whichType == TX_PUBKEYHASH) && 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 || pwinner->tx->vout[pwinner->i].nValue > txout.tx->vout[txout.i].nValue))
pwinner = &txout; pwinner = &txout;
curNonce = pBlock->nNonce;
} }
} }
if (pwinner) if (pwinner)
{ {
stakeSource = *(pwinner->tx); stakeSource = *(pwinner->tx);
voutNum = pwinner->i; voutNum = pwinner->i;
pBlock->nNonce = curNonce;
return true; return true;
} }
} }
return false; 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; CTransaction stakeSource;
int32_t voutNum, siglen = 0; int32_t voutNum, siglen = 0;
int64_t nValue; int64_t nValue;
@@ -1048,12 +1055,11 @@ int32_t CWallet::VerusStakeTransaction(CMutableTransaction &txNew, uint32_t &bnT
tipindex = chainActive.Tip(); tipindex = chainActive.Tip();
} }
bnTarget = lwmaGetNextPOSRequired(tipindex, Params().GetConsensus()); 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)) !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; return 0;
} }

View File

@@ -1149,8 +1149,8 @@ public:
bool ignoreUnspendable=true); bool ignoreUnspendable=true);
// staking functions // staking functions
bool VerusSelectStakeOutput(arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, const arith_uint256 &target) const; bool VerusSelectStakeOutput(CBlock *pBlock, arith_uint256 &hashResult, CTransaction &stakeSource, int32_t &voutNum, int32_t nHeight, uint32_t &bnTarget) const;
int32_t VerusStakeTransaction(CMutableTransaction &txNew, uint32_t &bnTarget, arith_uint256 &hashResult, uint8_t *utxosig) 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. */ /** A key allocated from the key pool. */