Updates from to main.cpp from kmd master 1f874d46c5ddd24c0fd32ae6800f16d8006b9059
This commit is contained in:
327
src/main.cpp
327
src/main.cpp
@@ -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 = █
|
||||
}
|
||||
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,¬arizedhash,&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,int32_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(¬aryid,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;
|
||||
|
||||
Reference in New Issue
Block a user