@ -940,20 +940,34 @@ bool IsStandardTx(const CTransaction& tx, string& reason, const int nHeight)
bool IsFinalTx ( const CTransaction & tx , int nBlockHeight , int64_t nBlockTime )
{
int32_t i ;
if ( tx . nLockTime = = 0 )
if ( tx . nLockTime = = 0 )
return true ;
if ( ( int64_t ) tx . nLockTime < ( ( int64_t ) tx . nLockTime < LOCKTIME_THRESHOLD ? ( int64_t ) nBlockHeight : nBlockTime ) )
return true ;
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
{
if ( txin . nSequence = = 0xfffffffe & & ( ( ( int64_t ) tx . nLockTime > = LOCKTIME_THRESHOLD & & ( int64_t ) tx . nLockTime > nBlockTime ) | | ( ( int64_t ) tx . nLockTime < LOCKTIME_THRESHOLD & & ( int64_t ) tx . nLockTime > nBlockHeight ) ) )
if ( ! komodo_hardfork_active ( nBlockTime ) & & txin . nSequence = = 0xfffffffe & &
//if ( (nBlockTime <= ASSETCHAINS_STAKED_HF_TIMESTAMP ) && txin.nSequence == 0xfffffffe &&
(
( ( int64_t ) tx . nLockTime > = LOCKTIME_THRESHOLD & & ( int64_t ) tx . nLockTime > nBlockTime ) | |
( ( int64_t ) tx . nLockTime < LOCKTIME_THRESHOLD & & ( int64_t ) tx . nLockTime > nBlockHeight )
)
)
{
}
//else if ( nBlockTime > ASSETCHAINS_STAKED_HF_TIMESTAMP && txin.nSequence == 0xfffffffe &&
else if ( komodo_hardfork_active ( nBlockTime ) & & txin . nSequence = = 0xfffffffe & &
(
( ( int64_t ) tx . nLockTime > = LOCKTIME_THRESHOLD & & ( int64_t ) tx . nLockTime < = nBlockTime ) | |
( ( int64_t ) tx . nLockTime < LOCKTIME_THRESHOLD & & ( int64_t ) tx . nLockTime < = nBlockHeight ) )
)
{
}
else if ( ! txin . IsFinal ( ) )
{
//printf("non-final txin seq.%x locktime.%u vs nTime.%u\n",txin.nSequence,(uint32_t)tx.nLockTime,(uint32_t)nBlockTime);
LogPrintf ( " non-final txin seq.%x locktime.%u vs nTime.%u \n " , txin . nSequence , ( uint32_t ) tx . nLockTime , ( uint32_t ) nBlockTime ) ;
return false ;
}
}
@ -1160,6 +1174,7 @@ bool ContextualCheckTransaction(int32_t slowflag,const CBlock *block, CBlockInde
if ( tx . fOverwintered & & tx . nVersionGroupId ! = SAPLING_VERSION_GROUP_ID )
{
//return state.DoS(dosLevel, error("CheckTransaction(): invalid Sapling tx version"),REJECT_INVALID, "bad-sapling-tx-version-group-id");
if ( 0 )
{
string strHex = EncodeHexTx ( tx ) ;
fprintf ( stderr , " invalid Sapling rawtx.%s \n " , strHex . c_str ( ) ) ;
@ -1332,7 +1347,7 @@ bool ContextualCheckTransaction(int32_t slowflag,const CBlock *block, CBlockInde
}
bool CheckTransaction ( uint32_t tiptime , const CTransaction & tx , CValidationState & state ,
libzcash : : ProofVerifier & verifier )
libzcash : : ProofVerifier & verifier , int32_t txIndex , int32_t numTxs )
{
static uint256 array [ 64 ] ; static int32_t numbanned , indallvouts ; int32_t j , k , n ;
if ( * ( int32_t * ) & array [ 0 ] = = 0 )
@ -1732,7 +1747,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
}
bool AcceptToMemoryPool ( CTxMemPool & pool , CValidationState & state , const CTransaction & tx , bool fLimitFree , bool * pfMissingInputs , bool fRejectAbsurdFee , int dosLevel , bool fSkipExpiry )
bool AcceptToMemoryPool ( CTxMemPool & pool , CValidationState & state , const CTransaction & tx , bool fLimitFree , bool * pfMissingInputs , bool fRejectAbsurdFee , int dosLevel )
{
AssertLockHeld ( cs_main ) ;
if ( pfMissingInputs )
@ -1743,14 +1758,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if ( nextBlockHeight < = 1 | | chainActive . LastTip ( ) = = 0 )
tiptime = ( uint32_t ) time ( NULL ) ;
else tiptime = ( uint32_t ) chainActive . LastTip ( ) - > nTime ;
// is it already in the memory pool?
uint256 hash = tx . GetHash ( ) ;
if ( pool . exists ( hash ) )
{
//fprintf(stderr,"already in mempool\n");
return state . Invalid ( false , REJECT_DUPLICATE , " already in mempool " ) ;
}
//fprintf(stderr,"addmempool 0\n");
// Node operator can choose to reject tx by number of transparent inputs
static_assert ( std : : numeric_limits < size_t > : : max ( ) > = std : : numeric_limits < int64_t > : : max ( ) , " size_t too small " ) ;
@ -1766,21 +1773,21 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
}
}
//fprintf(stderr,"addmempool 1\n");
auto verifier = libzcash : : ProofVerifier : : Strict ( ) ;
if ( ASSETCHAINS_SYMBOL [ 0 ] = = 0 & & komodo_validate_interest ( tx , chainActive . LastTip ( ) - > GetHeight ( ) + 1 , chainActive . LastTip ( ) - > GetMedianTimePast ( ) + 777 , 0 ) < 0 )
{
//fprintf(stderr," AcceptToMemoryPool komodo_validate_interest failure\n");
fprintf ( stderr , " AcceptToMemoryPool komodo_validate_interest failure \n " ) ;
return error ( " AcceptToMemoryPool: komodo_validate_interest failed " ) ;
}
if ( ! CheckTransaction ( tiptime , tx , state , verifier ) )
if ( ! CheckTransaction ( tiptime , tx , state , verifier , 0 , 0 ) )
{
return error ( " AcceptToMemoryPool: CheckTransaction failed " ) ;
}
// DoS level set to 10 to be more forgiving.
// Check transaction contextually against the set of consensus rules which apply in the next block to be mined.
if ( ! fSkipExpiry & & ! ContextualCheckTransaction ( 0 , 0 , 0 , tx , state , nextBlockHeight , ( dosLevel = = - 1 ) ? 10 : dosLevel ) )
if ( ! ContextualCheckTransaction ( 0 , 0 , 0 , tx , state , nextBlockHeight , ( dosLevel = = - 1 ) ? 10 : dosLevel ) )
{
return error ( " AcceptToMemoryPool: ContextualCheckTransaction failed " ) ;
}
@ -1791,26 +1798,34 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
fprintf ( stderr , " AcceptToMemoryPool coinbase as individual tx \n " ) ;
return state . DoS ( 100 , error ( " AcceptToMemoryPool: coinbase as individual tx " ) , REJECT_INVALID , " coinbase " ) ;
}
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
string reason ;
if ( ! fSkipExpiry & & Params ( ) . RequireStandard ( ) & & ! IsStandardTx ( tx , reason , nextBlockHeight ) )
if ( Params ( ) . RequireStandard ( ) & & ! IsStandardTx ( tx , reason , nextBlockHeight ) )
{
//
//fprintf(stderr,"AcceptToMemoryPool reject nonstandard transaction: %s\nscriptPubKey: %s\n",reason.c_str(),tx.vout[0].scriptPubKey.ToString().c_str());
return state . DoS ( 0 , error ( " AcceptToMemoryPool: nonstandard transaction: %s " , reason ) , REJECT_NONSTANDARD , reason ) ;
}
// Only accept nLockTime-using transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
if ( ! fSkipExpiry & & ! CheckFinalTx ( tx , STANDARD_LOCKTIME_VERIFY_FLAGS ) )
if ( ! CheckFinalTx ( tx , STANDARD_LOCKTIME_VERIFY_FLAGS ) )
{
//fprintf(stderr,"AcceptToMemoryPool reject non-final\n");
return state . DoS ( 0 , false , REJECT_NONSTANDARD , " non-final " ) ;
}
//fprintf(stderr,"addmempool 3\n");
// is it already in the memory pool?
uint256 hash = tx . GetHash ( ) ;
if ( pool . exists ( hash ) )
{
//fprintf(stderr,"already in mempool\n");
return state . Invalid ( false , REJECT_DUPLICATE , " already in mempool " ) ;
}
// Check for conflicts with in-memory transactions
if ( ! fSkipExpiry )
{
LOCK ( pool . cs ) ; // protect pool.mapNextTx
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + )
@ -1837,7 +1852,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
}
}
//fprintf(stderr,"addmempool 4\n");
{
CCoinsView dummy ;
CCoinsViewCache view ( & dummy ) ;
@ -1861,7 +1875,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if ( ExistsImportTombstone ( tx , view ) )
return state . Invalid ( false , REJECT_DUPLICATE , " import tombstone exists " ) ;
}
else if ( ! fSkipExpiry )
else
{
// do all inputs exist?
// Note that this does not check for the presence of actual outputs (see the next check for that),
@ -1873,10 +1887,13 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if ( pfMissingInputs )
* pfMissingInputs = true ;
//fprintf(stderr,"missing inputs\n");
return state . DoS ( 0 , error ( " AcceptToMemoryPool: tx inputs not found " ) , REJECT_INVALID , " bad-txns-inputs-missing " ) ;
return false ;
/*
https : //github.com/zcash/zcash/blob/master/src/main.cpp#L1490
state . DoS ( 0 , error ( " AcceptToMemoryPool: tx inputs not found " ) , REJECT_INVALID , " bad-txns-inputs-missing " ) ;
*/
}
}
// are the actual inputs available?
if ( ! view . HaveInputs ( tx ) )
{
@ -1884,59 +1901,50 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return state . Invalid ( error ( " AcceptToMemoryPool: inputs already spent " ) , REJECT_DUPLICATE , " bad-txns-inputs-spent " ) ;
}
}
// are the joinsplit's requirements met?
if ( ! view . HaveJoinSplitRequirements ( tx ) )
{
//fprintf(stderr,"accept failure.2\n");
return state . Invalid ( error ( " AcceptToMemoryPool: joinsplit requirements not met " ) , REJECT_DUPLICATE , " bad-txns-joinsplit-requirements-not-met " ) ;
}
// Bring the best block into scope
view . GetBestBlock ( ) ;
if ( ! fSkipExpiry )
nValueIn = view . GetValueIn ( chainActive . LastTip ( ) - > GetHeight ( ) , & interest , tx , chainActive . LastTip ( ) - > nTime ) ;
nValueIn = view . GetValueIn ( chainActive . LastTip ( ) - > GetHeight ( ) , & interest , tx , chainActive . LastTip ( ) - > nTime ) ;
if ( 0 & & interest ! = 0 )
fprintf ( stderr , " add interest %.8f \n " , ( double ) interest / COIN ) ;
// we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
view . SetBackend ( dummy ) ;
}
// Check for non-standard pay-to-script-hash in inputs
if ( ! fSkipExpiry & & Params ( ) . RequireStandard ( ) & & ! AreInputsStandard ( tx , view , consensusBranchId ) )
if ( Params ( ) . RequireStandard ( ) & & ! AreInputsStandard ( tx , view , consensusBranchId ) )
return error ( " AcceptToMemoryPool: reject nonstandard transaction input " ) ;
// Check that the transaction doesn't have an excessive number of
// sigops, making it impossible to mine. Since the coinbase transaction
// itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
// MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
// merely non-standard transaction.
unsigned int nSigOps = GetLegacySigOpCount ( tx ) ;
if ( ! fSkipExpiry )
nSigOps + = GetP2SHSigOpCount ( tx , view ) ;
nSigOps + = GetP2SHSigOpCount ( tx , view ) ;
if ( nSigOps > MAX_STANDARD_TX_SIGOPS )
{
fprintf ( stderr , " accept failure.4 \n " ) ;
return state . DoS ( 1 , error ( " AcceptToMemoryPool: too many sigops %s, %d > %d " , hash . ToString ( ) , nSigOps , MAX_STANDARD_TX_SIGOPS ) , REJECT_NONSTANDARD , " bad-txns-too-many-sigops " ) ;
}
CAmount nValueOut = tx . GetValueOut ( ) ;
double dPriority = 0 ;
CAmount nFees = 0 ;
if ( ! fSkipExpiry )
{
dPriority = view . GetPriority ( tx , chainActive . Height ( ) ) ;
nFees = nValueIn - nValueOut ;
}
CAmount nFees = nValueIn - nValueOut ;
double dPriority = view . GetPriority ( tx , chainActive . Height ( ) ) ;
if ( nValueOut > 777777 * COIN & & KOMODO_VALUETOOBIG ( nValueOut - 777777 * COIN ) ! = 0 ) // some room for blockreward and txfees
return state . DoS ( 100 , error ( " AcceptToMemoryPool: GetValueOut too big " ) , REJECT_INVALID , " tx valueout is too big " ) ;
// Keep track of transactions that spend a coinbase, which we re-scan
// during reorgs to ensure COINBASE_MATURITY is still met.
bool fSpendsCoinbase = false ;
if ( ! fSkipExpiry & & ! tx . IsCoinImport ( ) & & ! tx . IsPegsImport ( ) ) {
if ( ! tx . IsCoinImport ( ) & & ! tx . IsPegsImport ( ) ) {
BOOST_FOREACH ( const CTxIn & txin , tx . vin ) {
const CCoins * coins = view . AccessCoins ( txin . prevout . hash ) ;
if ( coins - > IsCoinBase ( ) ) {
@ -1945,15 +1953,15 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
}
}
}
//fprintf(stderr,"addmempool 5\n");
// Grab the branch ID we expect this transaction to commit to. We don't
// yet know if it does, but if the entry gets added to the mempool, then
// it has passed ContextualCheckInputs and therefore this is correct.
auto consensusBranchId = CurrentEpochBranchId ( chainActive . Height ( ) + 1 , Params ( ) . GetConsensus ( ) ) ;
CTxMemPoolEntry entry ( tx , nFees , GetTime ( ) , dPriority , chainActive . Height ( ) , mempool . HasNoInputsOf ( tx ) , fSpendsCoinbase , consensusBranchId ) ;
unsigned int nSize = entry . GetTxSize ( ) ;
// Accept a tx if it contains joinsplits and has at least the default fee specified by z_sendmany.
if ( tx . vjoinsplit . size ( ) > 0 & & nFees > = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE ) {
// In future we will we have more accurate and dynamic computation of fees for tx with joinsplits.
@ -1966,17 +1974,17 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return state . DoS ( 0 , error ( " AcceptToMemoryPool: not enough fees %s, %d < %d " , hash . ToString ( ) , nFees , txMinFee ) , REJECT_INSUFFICIENTFEE , " insufficient fee " ) ;
}
}
// Require that free transactions have sufficient priority to be mined in the next block.
if ( GetBoolArg ( " -relaypriority " , false ) & & nFees < : : minRelayTxFee . GetFee ( nSize ) & & ! AllowFree ( view . GetPriority ( tx , chainActive . Height ( ) + 1 ) ) ) {
fprintf ( stderr , " accept failure.6 \n " ) ;
return state . DoS ( 0 , false , REJECT_INSUFFICIENTFEE , " insufficient priority " ) ;
}
// Continuously rate-limit free (really, very-low-fee) transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
if ( ! fSkipExpiry & & fLimitFree & & nFees < : : minRelayTxFee . GetFee ( nSize ) & & ! tx . IsCoinImport ( ) & & ! tx . IsPegsImport ( ) )
if ( fLimitFree & & nFees < : : minRelayTxFee . GetFee ( nSize ) & & ! tx . IsCoinImport ( ) & & ! tx . IsPegsImport ( ) )
{
static CCriticalSection csFreeLimiter ;
static double dFreeCount ;
@ -1998,8 +2006,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
LogPrint ( " mempool " , " Rate limit dFreeCount: %g => %g \n " , dFreeCount , dFreeCount + nSize ) ;
dFreeCount + = nSize ;
}
if ( ! fSkipExpiry & & ! tx . IsCoinImport ( ) & & ! tx . IsPegsImport ( ) & & fRejectAbsurdFee & & nFees > : : minRelayTxFee . GetFee ( nSize ) * 10000 & & nFees > nValueOut / 19 )
if ( ! tx . IsCoinImport ( ) & & ! tx . IsPegsImport ( ) & & fRejectAbsurdFee & & nFees > : : minRelayTxFee . GetFee ( nSize ) * 10000 & & nFees > nValueOut / 19 )
{
string errmsg = strprintf ( " absurdly high fees %s, %d > %d " ,
hash . ToString ( ) ,
@ -2012,12 +2020,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
PrecomputedTransactionData txdata ( tx ) ;
if ( ! fSkipExpiry & & ! ContextualCheckInputs ( tx , state , view , true , STANDARD_SCRIPT_VERIFY_FLAGS , true , txdata , Params ( ) . GetConsensus ( ) , consensusBranchId ) )
if ( ! ContextualCheckInputs ( tx , state , view , true , STANDARD_SCRIPT_VERIFY_FLAGS , true , txdata , Params ( ) . GetConsensus ( ) , consensusBranchId ) )
{
//fprintf(stderr,"accept failure.9\n");
return error ( " AcceptToMemoryPool: ConnectInputs failed %s " , hash . ToString ( ) ) ;
}
// Check again against just the consensus-critical mandatory script
// verification flags, in case of bugs in the standard flags that cause
// transactions to pass as valid when they're actually invalid. For
@ -2034,7 +2042,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
KOMODO_CONNECTING = ( 1 < < 30 ) + ( int32_t ) chainActive . LastTip ( ) - > GetHeight ( ) + 1 ;
}
//fprintf(stderr,"addmempool 7\n");
if ( ! fSkipExpiry & & ! ContextualCheckInputs ( tx , state , view , true , MANDATORY_SCRIPT_VERIFY_FLAGS , true , txdata , Params ( ) . GetConsensus ( ) , consensusBranchId ) )
if ( ! ContextualCheckInputs ( tx , state , view , true , MANDATORY_SCRIPT_VERIFY_FLAGS , true , txdata , Params ( ) . GetConsensus ( ) , consensusBranchId ) )
{
if ( flag ! = 0 )
KOMODO_CONNECTING = - 1 ;
@ -2043,24 +2052,36 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if ( flag ! = 0 )
KOMODO_CONNECTING = - 1 ;
// Store transaction in memory
pool . addUnchecked ( hash , entry , ! IsInitialBlockDownload ( ) ) ;
if ( ! fSkipExpiry & & ! tx . IsCoinImport ( ) )
{
// Add memory address index
if ( fAddressIndex ) {
pool . addAddressIndex ( entry , view ) ;
}
LOCK ( pool . cs ) ;
// Store transaction in memory
pool . addUnchecked ( hash , entry , ! IsInitialBlockDownload ( ) ) ;
if ( ! tx . IsCoinImport ( ) )
{
// Add memory address index
if ( fAddressIndex ) {
pool . addAddressIndex ( entry , view ) ;
}
// Add memory spent index
if ( fSpentIndex ) {
pool . addSpentIndex ( entry , view ) ;
// Add memory spent index
if ( fSpentIndex ) {
pool . addSpentIndex ( entry , view ) ;
}
}
}
}
//SyncWithWallets(tx,NULL);
// This should be here still?
//SyncWithWallets(tx, NULL);
return true ;
}
bool CCTxFixAcceptToMemPoolUnchecked ( CTxMemPool & pool , const CTransaction & tx )
{
// called from CheckBlock which is in cs_main and mempool.cs locks already.
auto consensusBranchId = CurrentEpochBranchId ( chainActive . Height ( ) + 1 , Params ( ) . GetConsensus ( ) ) ;
CTxMemPoolEntry entry ( tx , 0 , GetTime ( ) , 0 , chainActive . Height ( ) , mempool . HasNoInputsOf ( tx ) , false , consensusBranchId ) ;
//fprintf(stderr, "adding %s to mempool from block %d\n",tx.GetHash().ToString().c_str(),chainActive.GetHeight());
pool . addUnchecked ( tx . GetHash ( ) , entry , false ) ;
return true ;
}
@ -2127,59 +2148,6 @@ struct CompareBlocksByHeightMain
}
} ;
bool RemoveOrphanedBlocks ( int32_t notarized_height )
{
LOCK ( cs_main ) ;
std : : vector < const CBlockIndex * > prunedblocks ;
std : : set < const CBlockIndex * , CompareBlocksByHeightMain > setTips ;
int32_t m = 0 , n = 0 ;
// get notarised timestamp and use this as a backup incase the forked block has no height.
// we -600 to make sure the time is within future block constraints.
uint32_t notarized_timestamp = komodo_heightstamp ( notarized_height ) - 600 ;
// Most of this code is a direct copy from GetChainTips RPC. Which gives a return of all
// blocks that are not in the main chain.
BOOST_FOREACH ( const PAIRTYPE ( const uint256 , CBlockIndex * ) & item , mapBlockIndex )
{
n + + ;
setTips . insert ( item . second ) ;
}
n = 0 ;
BOOST_FOREACH ( const PAIRTYPE ( const uint256 , CBlockIndex * ) & item , mapBlockIndex )
{
const CBlockIndex * pprev = 0 ;
n + + ;
if ( item . second ! = 0 )
pprev = item . second - > pprev ;
if ( pprev )
setTips . erase ( pprev ) ;
}
const CBlockIndex * forked ;
BOOST_FOREACH ( const CBlockIndex * block , setTips )
{
// We skip anything over notarised height to avoid breaking normal consensus rules.
if ( block - > GetHeight ( ) > notarized_height | | block - > nTime > notarized_timestamp )
continue ;
// We can also check if the block is in the active chain as a backup test.
forked = chainActive . FindFork ( block ) ;
// Here we save each forked block to a vector for removal later.
if ( forked ! = 0 )
prunedblocks . push_back ( block ) ;
}
if ( prunedblocks . size ( ) > 0 & & pblocktree - > EraseBatchSync ( prunedblocks ) )
{
// Blocks cleared from disk succesfully, using internal DB batch erase function. Which exists, but has never been used before.
// We need to try and clear the block index from mapBlockIndex now, otherwise node will need a restart.
BOOST_FOREACH ( const CBlockIndex * block , prunedblocks )
{
m + + ;
mapBlockIndex . erase ( block - > GetBlockHash ( ) ) ;
}
fprintf ( stderr , " %s removed %d orphans from %d blocks before %d \n " , ASSETCHAINS_SYMBOL , m , n , notarized_height ) ;
return true ;
}
return false ;
}
/*uint64_t myGettxout(uint256 hash,int32_t n)
{
CCoins coins ;
@ -2199,7 +2167,12 @@ bool myAddtomempool(CTransaction &tx, CValidationState *pstate, bool fSkipExpiry
pstate = & state ;
CTransaction Ltx ; bool fMissingInputs , fOverrideFees = false ;
if ( mempool . lookup ( tx . GetHash ( ) , Ltx ) = = 0 )
return ( AcceptToMemoryPool ( mempool , * pstate , tx , false , & fMissingInputs , ! fOverrideFees , - 1 , fSkipExpiry ) ) ;
{
if ( ! fSkipExpiry )
return ( AcceptToMemoryPool ( mempool , * pstate , tx , false , & fMissingInputs , ! fOverrideFees , - 1 ) ) ;
else
return ( CCTxFixAcceptToMemPoolUnchecked ( mempool , tx ) ) ;
}
else return ( true ) ;
}
@ -3413,9 +3386,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
auto verifier = libzcash : : ProofVerifier : : Strict ( ) ;
auto disabledVerifier = libzcash : : ProofVerifier : : Disabled ( ) ;
int32_t futureblock ;
CAmount blockReward = 0 ; uint64_t notarypaycheque = 0 ;
CAmount blockReward = GetBlockSubsidy ( pindex - > GetHeight ( ) , chainparams . GetConsensus ( ) ) ;
uint64_t notarypaycheque = 0 ;
// Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in
if ( ! CheckBlock ( & futureblock , pindex - > GetHeight ( ) , pindex , block , state , fExpensiveChecks ? verifier : disabledVerifier , fCheckPOW , ! fJustCheck ) | | futureblock ! = 0 )
if ( ! CheckBlock ( & futureblock , pindex - > GetHeight ( ) , pindex , block , state , fExpensiveChecks ? verifier : disabledVerifier , fCheckPOW , ! fJustCheck ) | | futureblock ! = 0 )
{
//fprintf(stderr,"checkblock failure in connectblock futureblock.%d\n",futureblock);
return false ;
@ -3532,7 +3506,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
CAmount nFees = 0 ;
int nInputs = 0 ;
uint64_t valueout ;
int64_t voutsum = 0 , prevsum = 0 , interest , sum = 0 ;
int64_t voutsum = 0 , prevsum = 0 , interest , sum = 0 , stakeTxValue = 0 ;
unsigned int nSigOps = 0 ;
CDiskTxPos pos ( pindex - > GetBlockPos ( ) , GetSizeOfCompactSize ( block . vtx . size ( ) ) ) ;
std : : vector < std : : pair < uint256 , CDiskTxPos > > vPos ;
@ -3731,7 +3705,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
int64_t nTime1 = GetTimeMicros ( ) ; nTimeConnect + = nTime1 - nTimeStart ;
LogPrint ( " bench " , " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs] \n " , ( unsigned ) block . vtx . size ( ) , 0.001 * ( nTime1 - nTimeStart ) , 0.001 * ( nTime1 - nTimeStart ) / block . vtx . size ( ) , nInputs < = 1 ? 0 : 0.001 * ( nTime1 - nTimeStart ) / ( nInputs - 1 ) , nTimeConnect * 0.000001 ) ;
blockReward + = nFees + GetBlockSubsidy ( pindex - > GetHeight ( ) , chainparams . GetConsensus ( ) ) + sum ;
blockReward + = nFees + sum ;
if ( ASSETCHAINS_COMMISSION ! = 0 | | ASSETCHAINS_FOUNDERS_REWARD ! = 0 ) //ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 &&
{
uint64_t checktoshis ;
@ -4016,6 +3990,9 @@ void static UpdateTip(CBlockIndex *pindexNew) {
pcoinsTip - > DynamicMemoryUsage ( ) * ( 1.0 / ( 1 < < 20 ) ) , pcoinsTip - > GetCacheSize ( ) ) ;
cvBlockChange . notify_all ( ) ;
/*
// https://github.com/zcash/zcash/issues/3992 -> https://github.com/zcash/zcash/commit/346d11d3eb2f8162df0cb00b1d1f49d542495198
// Check the version of the last 100 blocks to see if we need to upgrade:
static bool fWarned = false ;
@ -4039,6 +4016,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
fWarned = true ;
}
}
*/
}
/**
@ -4127,17 +4105,15 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
for ( int i = 0 ; i < block . vtx . size ( ) ; i + + )
{
CTransaction & tx = block . vtx [ i ] ;
if ( ( i = = ( block . vtx . size ( ) - 1 ) ) & & ( ASSETCHAINS_STAKED ! = 0 & & ( komodo_isPoS ( ( CBlock * ) & block , pindexDelete - > GetHeight ( ) , true ) ! = 0 ) ) )
//if ((i == (block.vtx.size() - 1)) && ((ASSETCHAINS_LWMAPOS && block.IsVerusPOSBlock()) || (ASSETCHAINS_STAKED != 0 && (komodo_isPoS((CBlock *)&block) != 0))))
if ( komodo_newStakerActive ( 0 , pindexDelete - > nTime ) = = 0 & & i = = block . vtx . size ( ) - 1 & & komodo_isPoS ( ( CBlock * ) & block , pindexDelete - > GetHeight ( ) , 0 ) ! = 0 )
{
# ifdef ENABLE_WALLET
if ( ! GetBoolArg ( " -disablewallet " , false ) & & KOMODO_NSPV_FULLNODE )
pwalletMain - > EraseFromWallet ( tx . GetHash ( ) ) ;
// new staking tx cannot be accepted to mempool and expires in 1 block, so no need for this! :D
if ( ! GetBoolArg ( " -disablewallet " , false ) & & KOMODO_NSPV_FULLNODE )
pwalletMain - > EraseFromWallet ( tx . GetHash ( ) ) ;
# endif
}
else
{
SyncWithWallets ( tx , NULL ) ;
}
} else SyncWithWallets ( tx , NULL ) ;
}
// Update cached incremental witnesses
GetMainSignals ( ) . ChainTip ( pindexDelete , & block , newSproutTree , newSaplingTree , false ) ;
@ -4232,8 +4208,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
pblock = & block ;
}
KOMODO_CONNECTING = ( int32_t ) pindexNew - > GetHeight ( ) ;
fprintf ( stderr , " %s connecting ht.%d maxsize.%d vs %d \n " , ASSETCHAINS_SYMBOL , ( int32_t ) pindexNew - > GetHeight ( ) , MAX_BLOCK_SIZE ( pindexNew - > GetHeight ( ) ) , ( int32_t ) : : GetSerializeSize ( * pblock , SER_NETWORK , PROTOCOL_VERSION ) ) ;
//fprintf(stderr,"%s connecting ht.%d maxsize.%d vs %d\n",ASSETCHAINS_SYMBOL,(int32_t)pindexNew->GetHeight(),MAX_BLOCK_SIZE(pindexNew->GetHeight()),(int32_t)::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
// Get the current commitment tree
SproutMerkleTree oldSproutTree ;
SaplingMerkleTree oldSaplingTree ;
@ -4417,7 +4392,6 @@ static void PruneBlockIndexCandidates() {
* pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork .
*/
static bool ActivateBestChainStep ( bool fSkipdpow , CValidationState & state , CBlockIndex * pindexMostWork , CBlock * pblock ) {
//fprintf(stderr,"%s: fSkipdpow=%d\n", __FUNCTION__, fSkipdpow);
AssertLockHeld ( cs_main ) ;
bool fInvalidFound = false ;
const CBlockIndex * pindexOldTip = chainActive . Tip ( ) ;
@ -4429,9 +4403,37 @@ static bool ActivateBestChainStep(bool fSkipdpow, CValidationState &state, CBloc
notarizedht = komodo_notarized_height ( & prevMoMheight , & notarizedhash , & txid ) ;
if ( ! fSkipdpow & & pindexFork ! = 0 & & pindexOldTip - > GetHeight ( ) > notarizedht & & pindexFork - > GetHeight ( ) < notarizedht )
{
fprintf ( stderr , " pindexOldTip->GetHeight().%d > notarizedht %d && pindexFork->GetHeight().%d is < notarizedht %d, so ignore it \n " , ( int32_t ) pindexOldTip - > GetHeight ( ) , notarizedht , ( int32_t ) pindexFork - > GetHeight ( ) , notarizedht ) ;
LogPrintf ( " pindexOldTip->GetHeight().%d > notarizedht %d && pindexFork->GetHeight().%d is < notarizedht %d, so ignore it \n " , ( int32_t ) pindexOldTip - > GetHeight ( ) , notarizedht , ( int32_t ) pindexFork - > GetHeight ( ) , notarizedht ) ;
// *** DEBUG ***
if ( 1 )
{
const CBlockIndex * pindexLastNotarized = mapBlockIndex [ notarizedhash ] ;
auto msg = " - " + strprintf ( _ ( " Current tip : %s, height %d, work %s " ) ,
pindexOldTip - > phashBlock - > GetHex ( ) , pindexOldTip - > GetHeight ( ) , pindexOldTip - > chainPower . chainWork . GetHex ( ) ) + " \n " +
" - " + strprintf ( _ ( " New tip : %s, height %d, work %s " ) ,
pindexMostWork - > phashBlock - > GetHex ( ) , pindexMostWork - > GetHeight ( ) , pindexMostWork - > chainPower . chainWork . GetHex ( ) ) + " \n " +
" - " + strprintf ( _ ( " Fork point : %s, height %d " ) ,
pindexFork - > phashBlock - > GetHex ( ) , pindexFork - > GetHeight ( ) ) + " \n " +
" - " + strprintf ( _ ( " Last ntrzd : %s, height %d " ) ,
pindexLastNotarized - > phashBlock - > GetHex ( ) , pindexLastNotarized - > GetHeight ( ) ) ;
LogPrintf ( " [ Debug ] \n %s \n " , msg ) ;
int nHeight = pindexFork ? pindexFork - > GetHeight ( ) : - 1 ;
int nTargetHeight = std : : min ( nHeight + 32 , pindexMostWork - > GetHeight ( ) ) ;
LogPrintf ( " [ Debug ] nHeight = %d, nTargetHeight = %d \n " , nHeight , nTargetHeight ) ;
CBlockIndex * pindexIter = pindexMostWork - > GetAncestor ( nTargetHeight ) ;
while ( pindexIter & & pindexIter - > GetHeight ( ) ! = nHeight ) {
LogPrintf ( " [ Debug -> New blocks list ] %s, height %d \n " , pindexIter - > phashBlock - > GetHex ( ) , pindexIter - > GetHeight ( ) ) ;
pindexIter = pindexIter - > pprev ;
}
}
CValidationState tmpstate ;
InvalidateBlock ( tmpstate , pindexMostWork ) ; // trying to invalidate longest chain, which tried to reorg notarized chain (in case of fork point below last notarized block)
return state . DoS ( 100 , error ( " ActivateBestChainStep(): pindexOldTip->GetHeight().%d > notarizedht %d && pindexFork->GetHeight().%d is < notarizedht %d, so ignore it " , ( int32_t ) pindexOldTip - > GetHeight ( ) , notarizedht , ( int32_t ) pindexFork - > GetHeight ( ) , notarizedht ) ,
REJECT_INVALID , " past-notarized-height " ) ;
REJECT_INVALID , " past-notarized-height " ) ;
}
// - On ChainDB initialization, pindexOldTip will be null, so there are no removable blocks.
// - If pindexMostWork is in a chain that doesn't have the same genesis block as our chain,
@ -4553,7 +4555,6 @@ static bool ActivateBestChainStep(bool fSkipdpow, CValidationState &state, CBloc
* that is already loaded ( to avoid loading it again from disk ) .
*/
bool ActivateBestChain ( bool fSkipdpow , CValidationState & state , CBlock * pblock ) {
//fprintf(stderr,"%s: fSkipdpow=%d\n", __FUNCTION__, fSkipdpow);
CBlockIndex * pindexNewTip = NULL ;
CBlockIndex * pindexMostWork = NULL ;
const CChainParams & chainParams = Params ( ) ;
@ -4762,8 +4763,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
sproutValue + = js . vpub_old ;
sproutValue - = js . vpub_new ;
}
}
}
pindexNew - > nSproutValue = sproutValue ;
pindexNew - > nChainSproutValue = boost : : none ;
pindexNew - > nSaplingValue = saplingValue ;
@ -4773,7 +4773,6 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
pindexNew - > nUndoPos = 0 ;
pindexNew - > nStatus | = BLOCK_HAVE_DATA ;
pindexNew - > RaiseValidity ( BLOCK_VALID_TRANSACTIONS ) ;
setDirtyBlockIndex . insert ( pindexNew ) ;
if ( pindexNew - > pprev = = NULL | | pindexNew - > pprev - > nChainTx ) {
@ -4786,10 +4785,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
CBlockIndex * pindex = queue . front ( ) ;
queue . pop_front ( ) ;
pindex - > nChainTx = ( pindex - > pprev ? pindex - > pprev - > nChainTx : 0 ) + pindex - > nTx ;
if ( pindex - > pprev ) {
pindex - > nChainTx = pindex - > pprev - > nChainTx + pindex - > nTx ;
if ( pindex - > pprev - > nChainSproutValue & & pindex - > nSproutValue ) {
pindex - > nChainSproutValue = * pindex - > pprev - > nChainSproutValue + * pindex - > nSproutValue ;
} else {
@ -5073,7 +5069,7 @@ bool CheckBlockHeader(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,
}
int32_t komodo_check_deposit ( int32_t height , const CBlock & block , uint32_t prevtime ) ;
int32_t komodo_checkPOW ( int32_t slowflag , CBlock * pblock , int32_t height ) ;
int32_t komodo_checkPOW ( int64_t stakeTxValue , int 32_t slowflag , CBlock * pblock , int32_t height ) ;
bool CheckBlock ( int32_t * futureblockp , int32_t height , CBlockIndex * pindex , const CBlock & block , CValidationState & state ,
libzcash : : ProofVerifier & verifier ,
@ -5105,9 +5101,24 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
fprintf ( stderr , " failed hash ht.%d \n " , height ) ;
return state . DoS ( 50 , error ( " CheckBlock: proof of work failed " ) , REJECT_INVALID , " high-hash " ) ;
}
if ( komodo_checkPOW ( 1 , ( CBlock * ) & block , height ) < 0 ) // checks Equihash
if ( ASSETCHAINS_STAKED = = 0 & & komodo_checkPOW ( 0 , 1 , ( CBlock * ) & block , height ) < 0 ) // checks Equihash
return state . DoS ( 100 , error ( " CheckBlock: failed slow_checkPOW " ) , REJECT_INVALID , " failed-slow_checkPOW " ) ;
}
if ( height > nDecemberHardforkHeight & & ASSETCHAINS_SYMBOL [ 0 ] = = 0 ) // December 2019 hardfork
{
int32_t notaryid ;
int32_t special = komodo_chosennotary ( & notaryid , height , pubkey33 , tiptime ) ;
if ( notaryid > 0 ) {
CScript merkleroot = CScript ( ) ;
CBlock blockcopy = block ; // block shouldn't be changed below, so let's make it's copy
CBlock * pblockcopy = ( CBlock * ) & blockcopy ;
if ( ! komodo_checkopret ( pblockcopy , merkleroot ) ) {
fprintf ( stderr , " failed or missing merkleroot expected.%s != merkleroot.%s \n " , komodo_makeopret ( pblockcopy , false ) . ToString ( ) . c_str ( ) , merkleroot . ToString ( ) . c_str ( ) ) ;
return state . DoS ( 100 , error ( " CheckBlock: failed or missing merkleroot opret in easy-mined " ) , REJECT_INVALID , " failed-merkle-opret-in-easy-mined " ) ;
}
}
}
// Check the merkle root.
if ( fCheckMerkleRoot ) {
bool mutated ;
@ -5177,10 +5188,9 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
list < CTransaction > removed ;
for ( i = 0 ; i < block . vtx . size ( ) ; i + + )
{
CValidationState state ;
CTransaction Tx ;
CValidationState state ; CTransaction Tx ;
const CTransaction & tx = ( CTransaction ) block . vtx [ i ] ;
if ( tx . IsCoinBase ( ) | | ! tx . vjoinsplit . empty ( ) | | ! tx . vShieldedSpend . empty ( ) | | ( ( i = = ( block . vtx . size ( ) - 1 ) ) & & ( ASSETCHAINS_STAKED & & komodo_isPoS ( ( CBlock * ) & block , height , true ) ! = 0 ) ) )
if ( tx . IsCoinBase ( ) | | ! tx . vjoinsplit . empty ( ) | | ! tx . vShieldedSpend . empty ( ) | | ( i = = block . vtx . size ( ) - 1 & & komodo_isPoS ( ( CBlock * ) & block , height , 0 ) ! = 0 ) )
continue ;
Tx = tx ;
if ( myAddtomempool ( Tx , & state , true ) = = false ) // happens with out of order tx in block on resync
@ -5215,8 +5225,11 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
{
const CTransaction & tx = block . vtx [ i ] ;
if ( komodo_validate_interest ( tx , height = = 0 ? komodo_block2height ( ( CBlock * ) & block ) : height , block . nTime , 0 ) < 0 )
{
fprintf ( stderr , " validate intrest failed for txnum.%i tx.%s \n " , i , tx . ToString ( ) . c_str ( ) ) ;
return error ( " CheckBlock: komodo_validate_interest failed " ) ;
if ( ! CheckTransaction ( tiptime , tx , state , verifier ) )
}
if ( ! CheckTransaction ( tiptime , tx , state , verifier , i , ( int32_t ) block . vtx . size ( ) ) )
return error ( " CheckBlock: CheckTransaction failed " ) ;
}
@ -5737,7 +5750,7 @@ bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNo
}
}
fRequested | = fForceProcessing ;
if ( checked ! = 0 & & komodo_checkPOW ( 0 , pblock , height ) < 0 ) //from_miner && ASSETCHAINS_STAKED == 0
if ( checked ! = 0 & & komodo_checkPOW ( 0 , 0 , pblock , height ) < 0 ) //from_miner && ASSETCHAINS_STAKED == 0
{
checked = 0 ;
//fprintf(stderr,"passed checkblock but failed checkPOW.%d\n",from_miner && ASSETCHAINS_STAKED == 0);
@ -6043,9 +6056,9 @@ bool static LoadBlockIndexDB()
vSortedByHeight . push_back ( make_pair ( pindex - > GetHeight ( ) , pindex ) ) ;
//komodo_pindex_init(pindex,(int32_t)pindex->GetHeight());
}
fprintf ( stderr , " load blockindexDB paired %u \n " , ( uint32_t ) time ( NULL ) ) ;
//fprintf(stderr,"load blockindexDB paired %u\n",(uint32_t)time(NULL));
sort ( vSortedByHeight . begin ( ) , vSortedByHeight . end ( ) ) ;
fprintf ( stderr , " load blockindexDB sorted %u \n " , ( uint32_t ) time ( NULL ) ) ;
//fprintf(stderr,"load blockindexDB sorted %u\n",(uint32_t)time(NULL));
BOOST_FOREACH ( const PAIRTYPE ( int , CBlockIndex * ) & item , vSortedByHeight )
{
CBlockIndex * pindex = item . second ;