PoS improvements
This commit is contained in:
@@ -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 \
|
||||||
@@ -415,6 +416,7 @@ libbitcoin_common_a_SOURCES = \
|
|||||||
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 +626,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 \
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -1275,11 +1275,11 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height)
|
|||||||
|
|
||||||
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 +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());
|
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);
|
||||||
|
|
||||||
|
// 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 +1325,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) )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -462,7 +462,7 @@ 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);
|
pblock->SetVerusPOSTarget(nBitsPOS);
|
||||||
|
|
||||||
@@ -959,7 +959,7 @@ 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());
|
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)
|
if (unlockTime > Mining_height && subsidy >= ASSETCHAINS_TIMELOCKGTE)
|
||||||
printf("- timelocked until block %i\n", unlockTime);
|
printf("- timelocked until block %i\n", unlockTime);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -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,47 @@ 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
|
||||||
|
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
|
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
|
||||||
|
|||||||
@@ -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 GetVerusPOSHash(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
|
||||||
@@ -105,11 +109,7 @@ 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(int32_t nBits)
|
||||||
|
|||||||
68
src/primitives/nonce.cpp
Normal file
68
src/primitives/nonce.cpp
Normal file
@@ -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 <cstring>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
66
src/primitives/nonce.h
Normal file
66
src/primitives/nonce.h
Normal file
@@ -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<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(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
|
||||||
@@ -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 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();
|
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 ArithToUint256(UintToArith256(_GetVerusPOSHash(pNonce, txid, voutNum, height, pastHash, (uint64_t)vout[voutNum].nValue)) / vout[voutNum].nValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ToString() const;
|
std::string ToString() const;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,15 +1008,19 @@ 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);
|
||||||
|
|
||||||
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) &&
|
||||||
@@ -1033,9 +1038,8 @@ bool CWallet::VerusSelectStakeOutput(arith_uint256 &hashResult, CTransaction &st
|
|||||||
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 +1052,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
Reference in New Issue
Block a user