@ -1,25 +1,101 @@
# ifdef reference
// modify time.1462237906 modifier.baed58b98a00e41d
// modify time.1462237906 modifier.baed58b98a00e41d
# include "iguana777.h"
# define CENT (SATOSHIDEN / 100)
# define COIN_YEAR_REWARD ((int64_t)5 * CENT) // 5% per year
# define NCOINBASEMATURITY 100
# define STAKE_TIMESTAMP_MASK 15
# define NTARGETSPACING 60 // BitcoinDark - 1 minute
# define NTARGETTIMESPAN (60 * NTARGETSPACING) // BitcoinDark - every 1 hour
# define NINTERVAL_MSPACING (((NTARGETTIMESPAN / NTARGETSPACING) - 1) * NTARGETSPACING)
# define NINTERVAL_PSPACING (((NTARGETTIMESPAN / NTARGETSPACING) + 1) * NTARGETSPACING)
static const int64_t COIN_YEAR_REWARD = 5 * CENT ; // 5% per year
# define NSTAKESPLITAGE (1 * 24 * NTARGETTIMESPAN)
int nCoinbaseMaturity = 100 ;
# define NSTAKE_MINAGE (8 * NTARGETTIMESPAN) // BitcoinDark - 8 hours
static const int STAKE_TIMESTAMP_MASK = 15 ;
# define NSTAKEMAXAGE ((int64_t)-1)
# define NMAXSTAKESEARCHINTERVAL 60
# define NSTAKECOMBINETHRESHOLD (1000 * COIN)
// MODIFIER_INTERVAL_RATIO:
// ratio of group interval length between the last group and the first group
// ratio of group interval length between the last group and the first group
static const int MODIFIER_INTERVAL_RATIO = 3 ;
# define MODIFIER_INTERVAL_RATIO 3
# define NMODIFIERINTERVAL (10 * NTARGETSPACING) // BitcoinDark - time to elapse before new modifier is
CBigNum bnProofOfStakeLimit ( ~ uint256 ( 0 ) > > 20 ) ;
// miner's coin stake reward based on coin age spent (coin-days)
CBigNum bnProofOfStakeLimitV2 ( ~ uint256 ( 0 ) > > 48 ) ;
int64_t iguana_POSreward ( int64_t nCoinAge , int64_t nFees )
{
int64_t nSubsidy = ( nCoinAge * COIN_YEAR_REWARD * 33 ) / ( 365 * 33 + 8 ) ;
return ( nSubsidy + nFees ) ;
}
unsigned int nTargetSpacing = 1 * 60 ; // BitcoinDark - 1 minute
// maximum nBits value could possible be required nTime after
static const int64_t nTargetTimespan = 60 * 60 ; // BitcoinDark - every 1 hour
uint32_t iguana_maxbits ( bits256 targetval , uint32_t nBits , int64_t nTime )
unsigned int nStakeMinAge = 8 * 60 * 60 ; // BitcoinDark - 8 hours
{
unsigned int nStakeMaxAge = - 1 ;
bits256 bitsval ;
unsigned int nModifierInterval = 10 * 60 ; // BitcoinDark - time to elapse before new modifier is
bitsval = bits256_from_compact ( nBits ) ;
bitsval = bits256_lshift ( bitsval ) ;
while ( nTime > 0 & & bits256_cmp ( bitsval , targetval ) < 0 )
{
bitsval = bits256_rshift ( bitsval ) ; // Maximum 200% adjustment per day...
nTime - = 24 * 60 * 60 ;
}
if ( bits256_cmp ( bitsval , targetval ) > 0 )
bitsval = targetval ;
return ( bits256_to_compact ( bitsval ) ) ;
}
unsigned int nStakeSplitAge = 1 * 24 * 60 * 60 ;
bits256 iguana_targetval ( struct iguana_info * coin , int32_t height , int32_t PoSflag )
int64_t nStakeCombineThreshold = 1000 * COIN ;
{
int32_t i ; bits256 targetval ;
if ( PoSflag = = 0 )
return ( coin - > chain - > PoWtarget ) ;
else
{
targetval = coin - > chain - > PoStargets [ 0 ] ;
for ( i = 0 ; i < coin - > chain - > numPoStargets ; i + + )
{
if ( height < coin - > chain - > PoSheights [ i ] )
break ;
targetval = coin - > chain - > PoStargets [ i ] ;
}
}
return ( targetval ) ;
}
// minimum amount of stake that could possibly be required nTime after
// minimum proof-of-stake required was nBase
uint32_t iguana_minstake ( struct iguana_info * coin , int32_t height , uint32_t nBits , int64_t nTime , uint32_t nBlockTime )
{
return ( iguana_maxbits ( iguana_targetval ( coin , height , 1 ) , nBits , nTime ) ) ;
}
uint32_t iguana_targetbits ( struct iguana_info * coin , struct iguana_block * hwmchain , struct iguana_block * prev , struct iguana_block * prev2 , int32_t PoSflag )
{
bits256 mpz_muldivcmp ( bits256 oldval , int32_t mulval , int32_t divval , bits256 cmpval ) ;
bits256 targetval ; int32_t gap ;
if ( hwmchain - > height < = 2 )
return ( hwmchain - > RO . bits ) ;
targetval = iguana_targetval ( coin , hwmchain - > height , PoSflag ) ;
if ( prev ! = 0 )
{
if ( prev2 ! = 0 )
{
//if ( prev->RO.timestamp != 0 && prev2->RO.timestamp != 0 ) skip check for compatiblity
{
if ( ( gap = prev - > RO . timestamp - prev2 - > RO . timestamp ) < 0 )
gap = NTARGETSPACING ;
// ppcoin: target change every block, retarget with exponential moving toward target spacing
targetval = mpz_muldivcmp ( bits256_from_compact ( prev - > RO . bits ) , NINTERVAL_MSPACING + ( gap < < 1 ) , NINTERVAL_PSPACING , targetval ) ;
}
}
}
return ( bits256_to_compact ( targetval ) ) ;
}
# ifdef reference
CBigNum bnProofOfStakeLimit ( ~ uint256 ( 0 ) > > 20 ) ;
CBigNum bnProofOfStakeLimitV2 ( ~ uint256 ( 0 ) > > 48 ) ;
enum
enum
{
{
@ -29,26 +105,24 @@ enum
} ;
} ;
uint64_t nStakeModifier ; // hash modifier for proof-of-stake
uint64_t nStakeModifier ; // hash modifier for proof-of-stake
unsigned in t nStakeModifierChecksum ; // checksum of index; in-meme ory only
uint32_ t nStakeModifierChecksum ; // checksum of index; in-memory only
uint256 CBlockIndex : : GetBlockTrust ( ) const
uint256 CBlockIndex : : GetBlockTrust ( ) const
{
{
CBigNum bnTarget ;
CBigNum bnTarget ;
bnTarget . SetCompact ( nBits ) ;
bnTarget . SetCompact ( nBits ) ;
if ( bnTarget < = 0 )
if ( bnTarget < = 0 )
return 0 ;
return 0 ;
return ( ( CBigNum ( 1 ) < < 256 ) / ( bnTarget + 1 ) ) . getuint256 ( ) ;
return ( ( CBigNum ( 1 ) < < 256 ) / ( bnTarget + 1 ) ) . getuint256 ( ) ;
}
}
unsigned in t GetStakeEntropyBit ( ) const
uint32_ t GetStakeEntropyBit ( ) const
{
{
return ( ( nFlags & BLOCK_STAKE_ENTROPY ) > > 1 ) ;
return ( ( nFlags & BLOCK_STAKE_ENTROPY ) > > 1 ) ;
}
}
bool SetStakeEntropyBit ( unsigned in t nEntropyBit )
bool SetStakeEntropyBit ( uint32_ t nEntropyBit )
{
{
if ( nEntropyBit > 1 )
if ( nEntropyBit > 1 )
return false ;
return false ;
@ -68,80 +142,6 @@ void SetStakeModifier(uint64_t nModifier, bool fGeneratedStakeModifier)
nFlags | = BLOCK_STAKE_MODIFIER ;
nFlags | = BLOCK_STAKE_MODIFIER ;
}
}
// miner's coin stake reward based on coin age spent (coin-days)
int64_t GetProofOfStakeReward ( int64_t nCoinAge , int64_t nFees )
{
int64_t nSubsidy = nCoinAge * COIN_YEAR_REWARD * 33 / ( 365 * 33 + 8 ) ;
return ( nSubsidy + nFees ) ;
}
//
// maximum nBits value could possible be required nTime after
//
unsigned int ComputeMaxBits ( CBigNum bnTargetLimit , unsigned int nBase , int64_t nTime )
{
CBigNum bnResult ;
bnResult . SetCompact ( nBase ) ;
bnResult * = 2 ;
while ( nTime > 0 & & bnResult < bnTargetLimit )
{
// Maximum 200% adjustment per day...
bnResult * = 2 ;
nTime - = 24 * 60 * 60 ;
}
if ( bnResult > bnTargetLimit )
bnResult = bnTargetLimit ;
return bnResult . GetCompact ( ) ;
}
//
// minimum amount of stake that could possibly be required nTime after
// minimum proof-of-stake required was nBase
//
unsigned int ComputeMinStake ( unsigned int nBase , int64_t nTime , unsigned int nBlockTime )
{
return ComputeMaxBits ( bnProofOfStakeLimit , nBase , nTime ) ;
}
static CBigNum GetProofOfStakeLimit ( int nHeight )
{
if ( IsPoSV2 ( nHeight ) )
return bnProofOfStakeLimitV2 ;
else
return bnProofOfStakeLimit ;
}
unsigned int GetNextTargetRequired ( const CBlockIndex * pindexLast , bool fProofOfStake )
{
CBigNum bnTargetLimit = fProofOfStake ? GetProofOfStakeLimit ( pindexLast - > nHeight ) : bnProofOfWorkLimit ;
if ( pindexLast = = NULL )
return bnTargetLimit . GetCompact ( ) ; // genesis block
const CBlockIndex * pindexPrev = GetLastBlockIndex ( pindexLast , fProofOfStake ) ;
if ( pindexPrev - > pprev = = NULL )
return bnTargetLimit . GetCompact ( ) ; // first block
const CBlockIndex * pindexPrevPrev = GetLastBlockIndex ( pindexPrev - > pprev , fProofOfStake ) ;
if ( pindexPrevPrev - > pprev = = NULL )
return bnTargetLimit . GetCompact ( ) ; // second block
int64_t nActualSpacing = pindexPrev - > GetBlockTime ( ) - pindexPrevPrev - > GetBlockTime ( ) ;
if ( nActualSpacing < 0 )
nActualSpacing = nTargetSpacing ;
// ppcoin: target change every block
// ppcoin: retarget with exponential moving toward target spacing
CBigNum bnNew ;
bnNew . SetCompact ( pindexPrev - > nBits ) ;
int64_t nInterval = nTargetTimespan / nTargetSpacing ;
bnNew * = ( ( nInterval - 1 ) * nTargetSpacing + nActualSpacing + nActualSpacing ) ;
bnNew / = ( ( nInterval + 1 ) * nTargetSpacing ) ;
if ( bnNew < = 0 | | bnNew > bnTargetLimit )
bnNew = bnTargetLimit ;
return bnNew . GetCompact ( ) ;
}
// ppcoin: total coin age spent in transaction, in the unit of coin-days.
// ppcoin: total coin age spent in transaction, in the unit of coin-days.
// Only those coins meeting minimum age requirement counts. As those
// Only those coins meeting minimum age requirement counts. As those
// transactions not in main chain are not currently indexed so we
// transactions not in main chain are not currently indexed so we
@ -168,7 +168,7 @@ bool CTransaction::GetCoinAge(CTxDB& txdb, uint64_t& nCoinAge) const
CBlock block ;
CBlock block ;
if ( ! block . ReadFromDisk ( txindex . pos . nFile , txindex . pos . nBlockPos , false ) )
if ( ! block . ReadFromDisk ( txindex . pos . nFile , txindex . pos . nBlockPos , false ) )
return false ; // unable to read block of previous transaction
return false ; // unable to read block of previous transaction
if ( block . GetBlockTime ( ) + nStakeMinAge > nTime )
if ( block . GetBlockTime ( ) + NSTAKE_MINAGE > nTime )
continue ; // only count coins meeting min age requirement
continue ; // only count coins meeting min age requirement
int64_t nValueIn = txPrev . vout [ txin . prevout . n ] . nValue ;
int64_t nValueIn = txPrev . vout [ txin . prevout . n ] . nValue ;
@ -206,13 +206,12 @@ bool CBlock::GetCoinAge(uint64_t& nCoinAge) const
}
}
// Get time weight
// Get time weight
int64_t GetWeight ( int64_t nIntervalBeginning , int64_t nIntervalEnd )
int64_t GetWeight ( int64_t nIntervalBeginning , int64_t nIntervalEnd )
{
{
// Kernel hash weight starts from 0 at the min age
// Kernel hash weight starts from 0 at the min age
// this change increases active coins participating the hash and helps
// this change increases active coins participating the hash and helps
// to secure the network when proof-of-stake difficulty is low
// to secure the network when proof-of-stake difficulty is low
return min ( nIntervalEnd - nIntervalBeginning - NSTAKE_MINAGE , NSTAKEMAXAGE ) ;
return min ( nIntervalEnd - nIntervalBeginning - nStakeMinAge , ( int64_t ) nStakeMaxAge ) ;
}
}
// Get the last stake modifier and its generation time from a given block
// Get the last stake modifier and its generation time from a given block
@ -230,50 +229,44 @@ static bool GetLastStakeModifier(const CBlockIndex* pindex, uint64_t& nStakeModi
}
}
// Get selection interval section (in seconds)
// Get selection interval section (in seconds)
static int64_t GetStakeModifierSelectionIntervalSection ( int nSection )
static int64_t GetStakeModifierSelectionIntervalSection ( int32_t nSection )
{
{
assert ( nSection > = 0 & & nSection < 64 ) ;
assert ( nSection > = 0 & & nSection < 64 ) ;
return ( nModifierInterval * 63 / ( 63 + ( ( 63 - nSection ) * ( MODIFIER_INTERVAL_RATIO - 1 ) ) ) ) ;
return ( NMODIFIERINTERVAL * 63 / ( 63 + ( ( 63 - nSection ) * ( MODIFIER_INTERVAL_RATIO - 1 ) ) ) ) ;
}
}
// Get stake modifier selection interval (in seconds)
// Get stake modifier selection interval (in seconds)
static int64_t GetStakeModifierSelectionInterval ( )
static int64_t GetStakeModifierSelectionInterval ( )
{
{
int64_t nSelectionInterval = 0 ;
int64_t nSelectionInterval = 0 ;
for ( int nSection = 0 ; nSection < 64 ; nSection + + )
for ( int32_t nSection = 0 ; nSection < 64 ; nSection + + )
nSelectionInterval + = GetStakeModifierSelectionIntervalSection ( nSection ) ;
nSelectionInterval + = GetStakeModifierSelectionIntervalSection ( nSection ) ;
return nSelectionInterval ;
return nSelectionInterval ;
}
}
// select a block from the candidate blocks in vSortedByTimestamp, excluding
// select a block from the candidate blocks in vSortedByTimestamp, excluding
// already selected blocks in vSelectedBlocks, and with timestamp up to
// already selected blocks in vSelectedBlocks, and with timestamp up to nSelectionIntervalStop.
// nSelectionIntervalStop.
static bool SelectBlockFromCandidates ( vector < pair < int64_t , uint256 > > & vSortedByTimestamp , map < uint256 , const CBlockIndex * > & mapSelectedBlocks , int64_t nSelectionIntervalStop , uint64_t nStakeModifierPrev , const CBlockIndex * * pindexSelected )
static bool SelectBlockFromCandidates ( vector < pair < int64_t , uint256 > > & vSortedByTimestamp , map < uint256 , const CBlockIndex * > & mapSelectedBlocks ,
int64_t nSelectionIntervalStop , uint64_t nStakeModifierPrev , const CBlockIndex * * pindexSelected )
{
{
bool fSelected = false ;
bool fSelected = false ; uint256 hashBest = 0 ;
uint256 hashBest = 0 ;
* pindexSelected = ( const CBlockIndex * ) 0 ;
* pindexSelected = ( const CBlockIndex * ) 0 ;
BOOST_FOREACH ( const PAIRTYPE ( int64_t , uint256 ) & item , vSortedByTimestamp )
BOOST_FOREACH ( const PAIRTYPE ( int64_t , uint256 ) & item , vSortedByTimestamp )
{
{
if ( ! mapBlockIndex . count ( item . second ) )
if ( ! mapBlockIndex . count ( item . second ) )
return error ( " SelectBlockFromCandidates: failed to find block index for candidate block %s " , item . second . ToString ( ) . c_str ( ) ) ;
return error ( " SelectBlockFromCandidates: failed to find block index for candidate block %s " , item . second . ToString ( ) . c_str ( ) ) ;
const CBlockIndex * pindex = mapBlockIndex [ item . second ] ;
const CBlockIndex * pindex = mapBlockIndex [ item . second ] ;
if ( fSelected & & pindex - > GetBlockTime ( ) > nSelectionIntervalStop )
if ( fSelected & & pindex - > GetBlockTime ( ) > nSelectionIntervalStop )
break ;
break ;
if ( mapSelectedBlocks . count ( pindex - > GetBlockHash ( ) ) > 0 )
if ( mapSelectedBlocks . count ( pindex - > GetBlockHash ( ) ) > 0 )
continue ;
continue ;
// compute the selection hash by hashing its proof-hash and the
// compute the selection hash by hashing its proof-hash and the previous proof-of-stake modifier
// previous proof-of-stake modifier
CDataStream ss ( SER_GETHASH , 0 ) ;
CDataStream ss ( SER_GETHASH , 0 ) ;
ss < < pindex - > hashProof < < nStakeModifierPrev ;
ss < < pindex - > hashProof < < nStakeModifierPrev ;
uint256 hashSelection = Hash ( ss . begin ( ) , ss . end ( ) ) ;
uint256 hashSelection = Hash ( ss . begin ( ) , ss . end ( ) ) ;
// the selection hash is divided by 2**32 so that proof-of-stake block
// the selection hash is divided by 2**32 so that proof-of-stake block is always favored over proof-of-work block. this is to preserve the energy efficiency property
// is always favored over proof-of-work block. this is to preserve
if ( pindex - > IsProofOfStake ( ) )
// the energy efficiency property
if ( pindex - > IsProofOfStake ( ) )
hashSelection > > = 32 ;
hashSelection > > = 32 ;
if ( fSelected & & hashSelection < hashBest )
if ( fSelected & & hashSelection < hashBest )
{
{
hashBest = hashSelection ;
hashBest = hashSelection ;
* pindexSelected = ( const CBlockIndex * ) pindex ;
* pindexSelected = ( const CBlockIndex * ) pindex ;
@ -321,21 +314,21 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeMod
{
{
printf ( " ComputeNextStakeModifier: prev modifier=0x%016 " PRIx64 " time=%s \n " , nStakeModifier , DateTimeStrFormat ( nModifierTime ) . c_str ( ) ) ;
printf ( " ComputeNextStakeModifier: prev modifier=0x%016 " PRIx64 " time=%s \n " , nStakeModifier , DateTimeStrFormat ( nModifierTime ) . c_str ( ) ) ;
}
}
if ( nModifierTime / nModifierInterval > = pindexPrev - > GetBlockTime ( ) / nModifierInterval )
if ( nModifierTime / NMODIFIERINTERVAL > = pindexPrev - > GetBlockTime ( ) / NMODIFIERINTERVAL )
return true ;
return true ;
// Sort candidate blocks by timestamp
// Sort candidate blocks by timestamp
vector < pair < int64_t , uint256 > > vSortedByTimestamp ;
vector < pair < int64_t , uint256 > > vSortedByTimestamp ;
vSortedByTimestamp . reserve ( 64 * nModifierInterval / nTargetSpacing ) ;
vSortedByTimestamp . reserve ( 64 * ( NMODIFIERINTERVAL / NTARGETSPACING ) ) ;
int64_t nSelectionInterval = GetStakeModifierSelectionInterval ( ) ;
int64_t nSelectionInterval = GetStakeModifierSelectionInterval ( ) ;
int64_t nSelectionIntervalStart = ( pindexPrev - > GetBlockTime ( ) / nModifierInterval ) * nModifierInterval - nSelectionInterval ;
int64_t nSelectionIntervalStart = ( pindexPrev - > GetBlockTime ( ) / NMODIFIERINTERVAL ) * NMODIFIERINTERVAL - nSelectionInterval ;
const CBlockIndex * pindex = pindexPrev ;
const CBlockIndex * pindex = pindexPrev ;
while ( pindex & & pindex - > GetBlockTime ( ) > = nSelectionIntervalStart )
while ( pindex & & pindex - > GetBlockTime ( ) > = nSelectionIntervalStart )
{
{
vSortedByTimestamp . push_back ( make_pair ( pindex - > GetBlockTime ( ) , pindex - > GetBlockHash ( ) ) ) ;
vSortedByTimestamp . push_back ( make_pair ( pindex - > GetBlockTime ( ) , pindex - > GetBlockHash ( ) ) ) ;
pindex = pindex - > pprev ;
pindex = pindex - > pprev ;
}
}
int nHeightFirstCandidate = pindex ? ( pindex - > nHeight + 1 ) : 0 ;
int32_t nHeightFirstCandidate = pindex ? ( pindex - > nHeight + 1 ) : 0 ;
reverse ( vSortedByTimestamp . begin ( ) , vSortedByTimestamp . end ( ) ) ;
reverse ( vSortedByTimestamp . begin ( ) , vSortedByTimestamp . end ( ) ) ;
sort ( vSortedByTimestamp . begin ( ) , vSortedByTimestamp . end ( ) ) ;
sort ( vSortedByTimestamp . begin ( ) , vSortedByTimestamp . end ( ) ) ;
@ -343,7 +336,7 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeMod
uint64_t nStakeModifierNew = 0 ;
uint64_t nStakeModifierNew = 0 ;
int64_t nSelectionIntervalStop = nSelectionIntervalStart ;
int64_t nSelectionIntervalStop = nSelectionIntervalStart ;
map < uint256 , const CBlockIndex * > mapSelectedBlocks ;
map < uint256 , const CBlockIndex * > mapSelectedBlocks ;
for ( int nRound = 0 ; nRound < min ( 64 , ( int ) vSortedByTimestamp . size ( ) ) ; nRound + + )
for ( int32_t nRound = 0 ; nRound < min ( 64 , ( int ) vSortedByTimestamp . size ( ) ) ; nRound + + )
{
{
// add an interval section to the current selection round
// add an interval section to the current selection round
nSelectionIntervalStop + = GetStakeModifierSelectionIntervalSection ( nRound ) ;
nSelectionIntervalStop + = GetStakeModifierSelectionIntervalSection ( nRound ) ;
@ -407,11 +400,9 @@ static bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64_t& nStakeModifi
{
{
if ( ! pindex - > pnext )
if ( ! pindex - > pnext )
{ // reached best block; may happen if node is behind on block chain
{ // reached best block; may happen if node is behind on block chain
if ( fPrintProofOfStake | | ( pindex - > GetBlockTime ( ) + nStakeMinAge - nStakeModifierSelectionInterval > GetAdjustedTime ( ) ) )
if ( fPrintProofOfStake | | ( pindex - > GetBlockTime ( ) + NSTAKE_MINAGE - nStakeModifierSelectionInterval > GetAdjustedTime ( ) ) )
return error ( " GetKernelStakeModifier() : reached best block %s at height %d from block %s " ,
return error ( " GetKernelStakeModifier() : reached best block % s at height % d from block % s " ,pindex->GetBlockHash().ToString().c_str(), pindex->nHeight, hashBlockFrom.ToString().c_str()) ;
pindex - > GetBlockHash ( ) . ToString ( ) . c_str ( ) , pindex - > nHeight , hashBlockFrom . ToString ( ) . c_str ( ) ) ;
else return false ;
else
return false ;
}
}
pindex = pindex - > pnext ;
pindex = pindex - > pnext ;
if ( pindex - > GeneratedStakeModifier ( ) )
if ( pindex - > GeneratedStakeModifier ( ) )
@ -445,13 +436,13 @@ static bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64_t& nStakeModifi
// quantities so as to generate blocks faster, degrading the system back into
// quantities so as to generate blocks faster, degrading the system back into
// a proof-of-work situation.
// a proof-of-work situation.
//
//
bool CheckStakeKernelHashV1 ( unsigned in t nBits , const CBlock & blockFrom , unsigned in t nTxPrevOffset , const CTransaction & txPrev , const COutPoint & prevout , unsigned in t nTimeTx , uint256 & hashProofOfStake , uint256 & targetProofOfStake , bool fPrintProofOfStake )
bool CheckStakeKernelHashV1 ( uint32_ t nBits , const CBlock & blockFrom , uint32_ t nTxPrevOffset , const CTransaction & txPrev , const COutPoint & prevout , uint32_ t nTimeTx , uint256 & hashProofOfStake , uint256 & targetProofOfStake , bool fPrintProofOfStake )
{
{
if ( nTimeTx < txPrev . nTime ) // Transaction timestamp violation
if ( nTimeTx < txPrev . nTime ) // Transaction timestamp violation
return error ( " CheckStakeKernelHash() : nTime violation " ) ;
return error ( " CheckStakeKernelHash() : nTime violation " ) ;
unsigned in t nTimeBlockFrom = blockFrom . GetBlockTime ( ) ;
uint32_ t nTimeBlockFrom = blockFrom . GetBlockTime ( ) ;
if ( nTimeBlockFrom + nStakeMinAge > nTimeTx ) // Min age requirement
if ( nTimeBlockFrom + NSTAKE_MINAGE > nTimeTx ) // Min age requirement
return error ( " CheckStakeKernelHash() : min age violation " ) ;
return error ( " CheckStakeKernelHash() : min age violation " ) ;
CBigNum bnTargetPerCoinDay ;
CBigNum bnTargetPerCoinDay ;
@ -466,7 +457,7 @@ bool CheckStakeKernelHashV1(unsigned int nBits, const CBlock& blockFrom, unsigne
// Calculate hash
// Calculate hash
CDataStream ss ( SER_GETHASH , 0 ) ;
CDataStream ss ( SER_GETHASH , 0 ) ;
uint64_t nStakeModifier = 0 ;
uint64_t nStakeModifier = 0 ;
int nStakeModifierHeight = 0 ;
int32_t nStakeModifierHeight = 0 ;
int64_t nStakeModifierTime = 0 ;
int64_t nStakeModifierTime = 0 ;
if ( ! GetKernelStakeModifier ( hashBlockFrom , nStakeModifier , nStakeModifierHeight , nStakeModifierTime , fPrintProofOfStake ) )
if ( ! GetKernelStakeModifier ( hashBlockFrom , nStakeModifier , nStakeModifierHeight , nStakeModifierTime , fPrintProofOfStake ) )
@ -504,7 +495,7 @@ bool CheckStakeKernelHashV1(unsigned int nBits, const CBlock& blockFrom, unsigne
return true ;
return true ;
}
}
bool CheckStakeKernelHash ( CBlockIndex * pindexPrev , unsigned in t nBits , const CBlock & blockFrom , unsigned in t nTxPrevOffset , const CTransaction & txPrev , const COutPoint & prevout , unsigned in t nTimeTx , uint256 & hashProofOfStake , uint256 & targetProofOfStake , bool fPrintProofOfStake )
bool CheckStakeKernelHash ( CBlockIndex * pindexPrev , uint32_ t nBits , const CBlock & blockFrom , uint32_ t nTxPrevOffset , const CTransaction & txPrev , const COutPoint & prevout , uint32_ t nTimeTx , uint256 & hashProofOfStake , uint256 & targetProofOfStake , bool fPrintProofOfStake )
{
{
if ( IsPoSV2 ( pindexPrev - > nHeight + 1 ) )
if ( IsPoSV2 ( pindexPrev - > nHeight + 1 ) )
return CheckStakeKernelHashV2 ( pindexPrev , nBits , blockFrom . GetBlockTime ( ) , txPrev , prevout , nTimeTx , hashProofOfStake , targetProofOfStake , fPrintProofOfStake ) ;
return CheckStakeKernelHashV2 ( pindexPrev , nBits , blockFrom . GetBlockTime ( ) , txPrev , prevout , nTimeTx , hashProofOfStake , targetProofOfStake , fPrintProofOfStake ) ;
@ -512,10 +503,9 @@ bool CheckStakeKernelHash(CBlockIndex* pindexPrev, unsigned int nBits, const CBl
return CheckStakeKernelHashV1 ( nBits , blockFrom , nTxPrevOffset , txPrev , prevout , nTimeTx , hashProofOfStake , targetProofOfStake , fPrintProofOfStake ) ;
return CheckStakeKernelHashV1 ( nBits , blockFrom , nTxPrevOffset , txPrev , prevout , nTimeTx , hashProofOfStake , targetProofOfStake , fPrintProofOfStake ) ;
}
}
bool CWallet : : CreateCoinStake ( const CKeyStore & keystore , unsigned in t nBits , int64_t nSearchInterval , int64_t nFees , CTransaction & txNew , CKey & key )
bool CWallet : : CreateCoinStake ( const CKeyStore & keystore , uint32_ t nBits , int64_t nSearchInterval , int64_t nFees , CTransaction & txNew , CKey & key )
{
{
CBlockIndex * pindexPrev = pindexBest ;
CBigNum bnTargetPerCoinDay ; CBlockIndex * pindexPrev = pindexBest ;
CBigNum bnTargetPerCoinDay ;
bnTargetPerCoinDay . SetCompact ( nBits ) ;
bnTargetPerCoinDay . SetCompact ( nBits ) ;
txNew . vin . clear ( ) ;
txNew . vin . clear ( ) ;
@ -528,12 +518,10 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int
// Choose coins to use
// Choose coins to use
int64_t nBalance = GetBalance ( ) ;
int64_t nBalance = GetBalance ( ) ;
if ( nBalance < = nReserveBalance )
if ( nBalance < = nReserveBalance )
return false ;
return false ;
vector < const CWalletTx * > vwtxPrev ;
vector < const CWalletTx * > vwtxPrev ;
set < pair < const CWalletTx * , unsigned int > > setCoins ;
set < pair < const CWalletTx * , unsigned int > > setCoins ;
int64_t nValueIn = 0 ;
int64_t nValueIn = 0 ;
@ -564,15 +552,14 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int
continue ;
continue ;
}
}
static int nMaxStakeSearchInterval = 60 ;
if ( block . GetBlockTime ( ) + NSTAKE_MINAGE > txNew . nTime - NMAXSTAKESEARCHINTERVAL )
if ( block . GetBlockTime ( ) + nStakeMinAge > txNew . nTime - nMaxStakeSearchInterval )
continue ; // only count coins meeting min age requirement
continue ; // only count coins meeting min age requirement
bool fKernelFound = false ;
bool fKernelFound = false ;
for ( unsigned in t n = 0 ; n < min ( nSearchInterval , ( int64_t ) nMaxStakeSearchInterval ) & & ! fKernelFound & & ! fShutdown & & pindexPrev = = pindexBest ; n + + )
for ( uint32_ t n = 0 ; n < min ( nSearchInterval , ( int64_t ) NMAXSTAKESEARCHINTERVAL ) & & ! fKernelFound & & ! fShutdown & & pindexPrev = = pindexBest ; n + + )
{
{
// Search backward in time from the given txNew timestamp
// Search backward in time from the given txNew timestamp
// Search nSearchInterval seconds back up to nMaxStakeSearchInterval
// Search nSearchInterval seconds back up to NMAXSTAKESEARCHINTERVAL
uint256 hashProofOfStake = 0 , targetProofOfStake = 0 ;
uint256 hashProofOfStake = 0 , targetProofOfStake = 0 ;
COutPoint prevoutStake = COutPoint ( pcoin . first - > GetHash ( ) , pcoin . second ) ;
COutPoint prevoutStake = COutPoint ( pcoin . first - > GetHash ( ) , pcoin . second ) ;
if ( CheckStakeKernelHash ( pindexPrev , nBits , block , txindex . pos . nTxPos - txindex . pos . nBlockPos , * pcoin . first , prevoutStake , txNew . nTime - n , hashProofOfStake , targetProofOfStake ) )
if ( CheckStakeKernelHash ( pindexPrev , nBits , block , txindex . pos . nTxPos - txindex . pos . nBlockPos , * pcoin . first , prevoutStake , txNew . nTime - n , hashProofOfStake , targetProofOfStake ) )
@ -653,29 +640,26 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int
BOOST_FOREACH ( PAIRTYPE ( const CWalletTx * , unsigned int ) pcoin , setCoins )
BOOST_FOREACH ( PAIRTYPE ( const CWalletTx * , unsigned int ) pcoin , setCoins )
{
{
// Attempt to add more inputs
// Attempt to add more inputs: Only add coins of the same key/address as kernel
// Only add coins of the same key/address as kernel
if ( txNew . vout . size ( ) = = 2 & & ( ( pcoin . first - > vout [ pcoin . second ] . scriptPubKey = = scriptPubKeyKernel | | pcoin . first - > vout [ pcoin . second ] . scriptPubKey = = txNew . vout [ 1 ] . scriptPubKey ) )
if ( txNew . vout . size ( ) = = 2 & & ( ( pcoin . first - > vout [ pcoin . second ] . scriptPubKey = = scriptPubKeyKernel | | pcoin . first - > vout [ pcoin . second ] . scriptPubKey = = txNew . vout [ 1 ] . scriptPubKey ) )
& & pcoin . first - > GetHash ( ) ! = txNew . vin [ 0 ] . prevout . hash )
& & pcoin . first - > GetHash ( ) ! = txNew . vin [ 0 ] . prevout . hash )
{
{
int64_t nTimeWeight = GetWeight ( ( int64_t ) pcoin . first - > nTime , ( int64_t ) txNew . nTime ) ;
int64_t nTimeWeight = GetWeight ( ( int64_t ) pcoin . first - > nTime , ( int64_t ) txNew . nTime ) ;
// Stop adding more inputs if already too many inputs
// Stop adding more inputs if already too many inputs
if ( txNew . vin . size ( ) > = 100 )
if ( txNew . vin . size ( ) > = 100 )
break ;
break ;
// Stop adding more inputs if value is already pretty significant
// Stop adding more inputs if value is already pretty significant
if ( nCredit > = nStakeCombineThreshold )
if ( nCredit > = NSTAKECOMBINETHRESHOLD )
break ;
break ;
// Stop adding inputs if reached reserve limit
// Stop adding inputs if reached reserve limit
if ( nCredit + pcoin . first - > vout [ pcoin . second ] . nValue > nBalance - nReserveBalance )
if ( nCredit + pcoin . first - > vout [ pcoin . second ] . nValue > nBalance - nReserveBalance )
break ;
break ;
// Do not add additional significant input
// Do not add additional significant input
if ( pcoin . first - > vout [ pcoin . second ] . nValue > = nStakeCombineThreshold )
if ( pcoin . first - > vout [ pcoin . second ] . nValue > = NSTAKECOMBINETHRESHOLD )
continue ;
continue ;
// Do not add input that is still too young
// Do not add input that is still too young
if ( nTimeWeight < nStakeMinAge )
if ( nTimeWeight < NSTAKE_MINAGE )
continue ;
continue ;
txNew . vin . push_back ( CTxIn ( pcoin . first - > GetHash ( ) , pcoin . second ) ) ;
txNew . vin . push_back ( CTxIn ( pcoin . first - > GetHash ( ) , pcoin . second ) ) ;
nCredit + = pcoin . first - > vout [ pcoin . second ] . nValue ;
nCredit + = pcoin . first - > vout [ pcoin . second ] . nValue ;
vwtxPrev . push_back ( pcoin . first ) ;
vwtxPrev . push_back ( pcoin . first ) ;
@ -689,7 +673,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int
if ( ! txNew . GetCoinAge ( txdb , nCoinAge ) )
if ( ! txNew . GetCoinAge ( txdb , nCoinAge ) )
return error ( " CreateCoinStake : failed to calculate coin age " ) ;
return error ( " CreateCoinStake : failed to calculate coin age " ) ;
int64_t nReward = GetProofOfStakeR eward( nCoinAge , nFees ) ;
int64_t nReward = iguana_POSr eward( nCoinAge , nFees ) ;
if ( nReward < = 0 )
if ( nReward < = 0 )
return false ;
return false ;
@ -701,12 +685,10 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int
{
{
txNew . vout [ 1 ] . nValue = ( nCredit / 2 / CENT ) * CENT ;
txNew . vout [ 1 ] . nValue = ( nCredit / 2 / CENT ) * CENT ;
txNew . vout [ 2 ] . nValue = nCredit - txNew . vout [ 1 ] . nValue ;
txNew . vout [ 2 ] . nValue = nCredit - txNew . vout [ 1 ] . nValue ;
}
} else txNew . vout [ 1 ] . nValue = nCredit ;
else
txNew . vout [ 1 ] . nValue = nCredit ;
// Sign
// Sign
int nIn = 0 ;
int32_t nIn = 0 ;
BOOST_FOREACH ( const CWalletTx * pcoin , vwtxPrev )
BOOST_FOREACH ( const CWalletTx * pcoin , vwtxPrev )
{
{
if ( ! SignSignature ( * this , * pcoin , txNew , nIn + + ) )
if ( ! SignSignature ( * this , * pcoin , txNew , nIn + + ) )
@ -714,7 +696,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int
}
}
// Limit size
// Limit size
unsigned in t nBytes = : : GetSerializeSize ( txNew , SER_NETWORK , PROTOCOL_VERSION ) ;
uint32_ t nBytes = : : GetSerializeSize ( txNew , SER_NETWORK , PROTOCOL_VERSION ) ;
if ( nBytes > = MAX_BLOCK_SIZE_GEN / 5 )
if ( nBytes > = MAX_BLOCK_SIZE_GEN / 5 )
return error ( " CreateCoinStake : exceeded coinstake size limit " ) ;
return error ( " CreateCoinStake : exceeded coinstake size limit " ) ;
@ -723,7 +705,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int
}
}
// Check kernel hash target and coinstake signature
// Check kernel hash target and coinstake signature
bool CheckProofOfStake ( CBlockIndex * pindexPrev , const CTransaction & tx , unsigned in t nBits , uint256 & hashProofOfStake , uint256 & targetProofOfStake )
bool CheckProofOfStake ( CBlockIndex * pindexPrev , const CTransaction & tx , uint32_ t nBits , uint256 & hashProofOfStake , uint256 & targetProofOfStake )
{
{
if ( ! tx . IsCoinStake ( ) )
if ( ! tx . IsCoinStake ( ) )
return error ( " CheckProofOfStake() : called on non - coinstake % s " , tx.GetHash().ToString().c_str()) ;
return error ( " CheckProofOfStake() : called on non - coinstake % s " , tx.GetHash().ToString().c_str()) ;
@ -761,7 +743,7 @@ bool CheckCoinStakeTimestamp(int64_t nTimeBlock, int64_t nTimeTx)
}
}
// Get stake modifier checksum
// Get stake modifier checksum
unsigned in t GetStakeModifierChecksum ( const CBlockIndex * pindex )
uint32_ t GetStakeModifierChecksum ( const CBlockIndex * pindex )
{
{
//assert (pindex->pprev || pindex->GetBlockHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet));
//assert (pindex->pprev || pindex->GetBlockHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet));
// Hash previous checksum with flags, hashProofOfStake and nStakeModifier
// Hash previous checksum with flags, hashProofOfStake and nStakeModifier
@ -775,7 +757,7 @@ unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex)
}
}
// Check stake modifier hard checkpoints
// Check stake modifier hard checkpoints
bool CheckStakeModifierCheckpoints ( int nHeight , unsigned in t nStakeModifierChecksum )
bool CheckStakeModifierCheckpoints ( int32_t nHeight , uint32_ t nStakeModifierChecksum )
{
{
MapModifierCheckpoints & checkpoints = ( fTestNet ? mapStakeModifierCheckpointsTestNet : mapStakeModifierCheckpoints ) ;
MapModifierCheckpoints & checkpoints = ( fTestNet ? mapStakeModifierCheckpointsTestNet : mapStakeModifierCheckpoints ) ;
@ -783,47 +765,36 @@ bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierCheck
return nStakeModifierChecksum = = checkpoints [ nHeight ] ;
return nStakeModifierChecksum = = checkpoints [ nHeight ] ;
return true ;
return true ;
}
}
// novacoin: attempt to generate suitable proof-of-stake
// novacoin: attempt to generate suitable proof-of-stake
bool CBlock : : SignBlock ( CWallet & wallet , int64_t nFees )
bool CBlock : : SignBlock ( CWallet & wallet , int64_t nFees )
{
{
// if we are trying to sign
// if we are trying to sign something except proof-of-stake block template
// something except proof-of-stake block template
if ( ! vtx [ 0 ] . vout [ 0 ] . IsEmpty ( ) )
if ( ! vtx [ 0 ] . vout [ 0 ] . IsEmpty ( ) )
return false ;
return false ;
// if we are trying to sign a complete proof-of-stake block
// if we are trying to sign
// a complete proof-of-stake block
if ( IsProofOfStake ( ) )
if ( IsProofOfStake ( ) )
return true ;
return true ;
static int64_t nLastCoinStakeSearchTime = GetAdjustedTime ( ) ; // startup timestamp
static int64_t nLastCoinStakeSearchTime = GetAdjustedTime ( ) ; // startup timestamp
CKey key ; CTransaction txCoinStake ; int64_t nSearchTime = txCoinStake . nTime ; // search to current time
CKey key ;
CTransaction txCoinStake ;
int64_t nSearchTime = txCoinStake . nTime ; // search to current time
if ( nSearchTime > nLastCoinStakeSearchTime )
if ( nSearchTime > nLastCoinStakeSearchTime )
{
{
if ( wallet . CreateCoinStake ( wallet , nBits , nSearchTime - nLastCoinStakeSearchTime , nFees , txCoinStake , key ) )
if ( wallet . CreateCoinStake ( wallet , nBits , nSearchTime - nLastCoinStakeSearchTime , nFees , txCoinStake , key ) )
{
{
if ( txCoinStake . nTime > = max ( pindexBest - > GetPastTimeLimit ( ) + 1 , PastDrift ( pindexBest - > GetBlockTime ( ) ) ) )
if ( txCoinStake . nTime > = max ( pindexBest - > GetPastTimeLimit ( ) + 1 , PastDrift ( pindexBest - > GetBlockTime ( ) ) ) )
{
{
// make sure coinstake would meet timestamp protocol
// make sure coinstake would meet timestamp protocol as it would be the same as the block timestamp
// as it would be the same as the block timestamp
vtx [ 0 ] . nTime = nTime = txCoinStake . nTime ;
vtx [ 0 ] . nTime = nTime = txCoinStake . nTime ;
nTime = max ( pindexBest - > GetPastTimeLimit ( ) + 1 , GetMaxTransactionTime ( ) ) ;
nTime = max ( pindexBest - > GetPastTimeLimit ( ) + 1 , GetMaxTransactionTime ( ) ) ;
nTime = max ( GetBlockTime ( ) , PastDrift ( pindexBest - > GetBlockTime ( ) ) ) ;
nTime = max ( GetBlockTime ( ) , PastDrift ( pindexBest - > GetBlockTime ( ) ) ) ;
// we have to make sure that we have no future timestamps in our transactions set
// we have to make sure that we have no future timestamps in
for ( vector < CTransaction > : : iterator it = vtx . begin ( ) ; it ! = vtx . end ( ) ; )
// our transactions set
if ( it - > nTime > nTime ) { it = vtx . erase ( it ) ; } else { + + it ; }
for ( vector < CTransaction > : : iterator it = vtx . begin ( ) ; it ! = vtx . end ( ) ; )
vtx . insert ( vtx . begin ( ) + 1 , txCoinStake ) ;
if ( it - > nTime > nTime ) { it = vtx . erase ( it ) ; } else { + + it ; }
hashMerkleRoot = BuildMerkleTree ( ) ;
// append a signature to our block
vtx . insert ( vtx . begin ( ) + 1 , txCoinStake ) ;
return key . Sign ( GetHash ( ) , vchBlockSig ) ;
hashMerkleRoot = BuildMerkleTree ( ) ;
}
// append a signature to our block
return key . Sign ( GetHash ( ) , vchBlockSig ) ;
}
}
}
nLastCoinStakeSearchInterval = nSearchTime - nLastCoinStakeSearchTime ;
nLastCoinStakeSearchInterval = nSearchTime - nLastCoinStakeSearchTime ;
nLastCoinStakeSearchTime = nSearchTime ;
nLastCoinStakeSearchTime = nSearchTime ;
@ -836,15 +807,11 @@ bool CBlock::CheckBlockSignature() const
{
{
if ( IsProofOfWork ( ) )
if ( IsProofOfWork ( ) )
return vchBlockSig . empty ( ) ;
return vchBlockSig . empty ( ) ;
vector < valtype > vSolutions ;
vector < valtype > vSolutions ;
txnouttype whichType ;
txnouttype whichType ;
const CTxOut & txout = vtx [ 1 ] . vout [ 1 ] ;
const CTxOut & txout = vtx [ 1 ] . vout [ 1 ] ;
if ( ! Solver ( txout . scriptPubKey , whichType , vSolutions ) )
if ( ! Solver ( txout . scriptPubKey , whichType , vSolutions ) )
return false ;
return false ;
if ( whichType = = TX_PUBKEY )
if ( whichType = = TX_PUBKEY )
{
{
valtype & vchPubKey = vSolutions [ 0 ] ;
valtype & vchPubKey = vSolutions [ 0 ] ;
@ -855,7 +822,6 @@ bool CBlock::CheckBlockSignature() const
return false ;
return false ;
return key . Verify ( GetHash ( ) , vchBlockSig ) ;
return key . Verify ( GetHash ( ) , vchBlockSig ) ;
}
}
return false ;
return false ;
}
}