# error "Zcash cannot be compiled without assertions."
#endif
+
/**
* Global state
*/
CCriticalSection cs_main;
+extern uint8_t NOTARY_PUBKEY33[33];
BlockMap mapBlockIndex;
CChain chainActive;
uint64_t nPruneTarget = 0;
bool fAlerts = DEFAULT_ALERTS;
+unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA;
+
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS;
-const string strMessageMagic = "Zcash Signed Message:\n";
+const string strMessageMagic = "Komodo Signed Message:\n";
// Internal stuff
namespace {
mapNodeState.erase(nodeid);
}
-
+
+void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
+{
+/* int expired = pool.Expire(GetTime() - age);
+ if (expired != 0)
+ LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired);
+
+ std::vector<uint256> vNoSpendsRemaining;
+ pool.TrimToSize(limit, &vNoSpendsRemaining);
+ BOOST_FOREACH(const uint256& removed, vNoSpendsRemaining)
+ pcoinsTip->Uncache(removed);*/
+}
+
// Requires cs_main.
// Returns a bool indicating whether we requested this block.
bool MarkBlockAsReceived(const uint256& hash) {
if (!state->hashLastUnknownBlock.IsNull()) {
BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock);
- if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) {
+ if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0)
+ {
if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
state->pindexBestKnownBlock = itOld->second;
state->hashLastUnknownBlock.SetNull();
CNodeState *state = State(nodeid);
assert(state != NULL);
- ProcessBlockAvailability(nodeid);
+ /*ProcessBlockAvailability(nodeid);
BlockMap::iterator it = mapBlockIndex.find(hash);
if (it != mapBlockIndex.end() && it->second->nChainWork > 0) {
// An actually better block was announced.
if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork)
state->pindexBestKnownBlock = it->second;
- } else {
+ } else*/
+ {
// An unknown block was announced; just assume that the latest one is the best one.
state->hashLastUnknownBlock = hash;
}
}
// Iterate over those blocks in vToFetch (in forward direction), adding the ones that
- // are not yet downloaded and not in flight to vBlocks. In the mean time, update
+ // are not yet downloaded and not in flight to vBlocks. In the meantime, update
// pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's
// already part of our chain (and therefore don't need it even if pruned).
BOOST_FOREACH(CBlockIndex* pindex, vToFetch) {
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
- if (chain.Contains(pindex))
+ if (pindex != 0 && chain.Contains(pindex))
return pindex;
if (pindex->GetAncestor(chain.Height()) == chain.Tip()) {
return chain.Tip();
CCoinsViewCache *pcoinsTip = NULL;
CBlockTreeDB *pblocktree = NULL;
+// Komodo globals
+
+#define KOMODO_ZCASH
+#include "komodo.h"
+
//////////////////////////////////////////////////////////////////////////////
//
// mapOrphanTransactions
}
}
- unsigned int nDataOut = 0;
+ unsigned int v=0,nDataOut = 0;
txnouttype whichType;
- BOOST_FOREACH(const CTxOut& txout, tx.vout) {
- if (!::IsStandard(txout.scriptPubKey, whichType)) {
+ BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ {
+ if (!::IsStandard(txout.scriptPubKey, whichType))
+ {
reason = "scriptpubkey";
+ fprintf(stderr,">>>>>>>>>>>>>>> vout.%d nDataout.%d\n",v,nDataOut);
return false;
}
-
+
if (whichType == TX_NULL_DATA)
+ {
nDataOut++;
+ //fprintf(stderr,"is OP_RETURN\n");
+ }
else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
reason = "bare-multisig";
return false;
reason = "dust";
return false;
}
+ v++;
}
// only one OP_RETURN txout is permitted
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
{
+ int32_t i;
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.IsFinal())
+ {
+ 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)) )
+ {
+
+ }
+ 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);
return false;
+ }
+ }
return true;
}
+bool IsExpiredTx(const CTransaction &tx, int nBlockHeight)
+{
+ if (tx.nExpiryHeight == 0 || tx.IsCoinBase()) {
+ return false;
+ }
+ return static_cast<uint32_t>(nBlockHeight) > tx.nExpiryHeight;
+}
+
bool CheckFinalTx(const CTransaction &tx, int flags)
{
AssertLockHeld(cs_main);
* 2. P2SH scripts with a crazy number of expensive
* CHECKSIG/CHECKMULTISIG operations
*/
-bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId)
{
if (tx.IsCoinBase())
return true; // Coinbases don't use vin normally
// IsStandardTx() will have already returned false
// and this method isn't called.
vector<vector<unsigned char> > stack;
- if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE))
+ if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), consensusBranchId))
return false;
if (whichType == TX_SCRIPTHASH)
return state.DoS(dosLevel, error("ContextualCheckTransaction: overwinter is active"),
REJECT_INVALID, "tx-overwinter-active");
}
+
+ // Check that all transactions are unexpired
+ if (IsExpiredTx(tx, nHeight)) {
+ return state.DoS(dosLevel, error("ContextualCheckTransaction(): transaction is expired"), REJECT_INVALID, "tx-overwinter-expired");
+ }
}
+ if (!(tx.IsCoinBase() || tx.vjoinsplit.empty())) {
+ auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus());
+ // Empty output script.
+ CScript scriptCode;
+ uint256 dataToBeSigned;
+ try {
+ dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
+ } catch (std::logic_error ex) {
+ return state.DoS(100, error("CheckTransaction(): error computing signature hash"),
+ REJECT_INVALID, "error-computing-signature-hash");
+ }
+
+ BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32);
+
+ // We rely on libsodium to check that the signature is canonical.
+ // https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0
+ if (crypto_sign_verify_detached(&tx.joinSplitSig[0],
+ dataToBeSigned.begin(), 32,
+ tx.joinSplitPubKey.begin()
+ ) != 0) {
+ return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"),
+ REJECT_INVALID, "bad-txns-invalid-joinsplit-signature");
+ }
+ }
return true;
}
-
bool CheckTransaction(const CTransaction& tx, CValidationState &state,
libzcash::ProofVerifier& verifier)
{
- // Don't count coinbase transactions because mining skews the count
+ static uint256 array[64]; static int32_t numbanned,indallvouts; int32_t j,k,n;
+ if ( *(int32_t *)&array[0] == 0 )
+ numbanned = komodo_bannedset(&indallvouts,array,(int32_t)(sizeof(array)/sizeof(*array)));
+ n = tx.vin.size();
+ for (j=0; j<n; j++)
+ {
+ for (k=0; k<numbanned; k++)
+ {
+ if ( tx.vin[j].prevout.hash == array[k] && (tx.vin[j].prevout.n == 1 || k >= indallvouts) )
+ {
+ static uint32_t counter;
+ if ( counter++ < 100 )
+ printf("MEMPOOL: banned tx.%d being used at ht.%d vout.%d\n",k,(int32_t)chainActive.Tip()->nHeight,j);
+ return(false);
+ }
+ }
+ }
+ // Don't count coinbase transactions because mining skews the count
if (!tx.IsCoinBase()) {
transactionsValidated.increment();
}
return state.DoS(100, error("CheckTransaction(): txout.nValue negative"),
REJECT_INVALID, "bad-txns-vout-negative");
if (txout.nValue > MAX_MONEY)
- return state.DoS(100, error("CheckTransaction(): txout.nValue too high"),
- REJECT_INVALID, "bad-txns-vout-toolarge");
+ {
+ fprintf(stderr,"%.8f > max %.8f\n",(double)txout.nValue/COIN,(double)MAX_MONEY/COIN);
+ return state.DoS(100, error("CheckTransaction(): txout.nValue too high"),REJECT_INVALID, "bad-txns-vout-toolarge");
+ }
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
return state.DoS(100, error("CheckTransaction(): txout total out of range"),
if (txin.prevout.IsNull())
return state.DoS(10, error("CheckTransaction(): prevout is null"),
REJECT_INVALID, "bad-txns-prevout-null");
-
- if (tx.vjoinsplit.size() > 0) {
- // Empty output script.
- CScript scriptCode;
- uint256 dataToBeSigned;
- try {
- dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_BASE);
- } catch (std::logic_error ex) {
- return state.DoS(100, error("CheckTransaction(): error computing signature hash"),
- REJECT_INVALID, "error-computing-signature-hash");
- }
-
- BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32);
-
- // We rely on libsodium to check that the signature is canonical.
- // https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0
- if (crypto_sign_verify_detached(&tx.joinSplitSig[0],
- dataToBeSigned.begin(), 32,
- tx.joinSplitPubKey.begin()
- ) != 0) {
- return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"),
- REJECT_INVALID, "bad-txns-invalid-joinsplit-signature");
- }
- }
}
return true;
CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree)
{
+ extern int32_t KOMODO_ON_DEMAND;
{
LOCK(mempool.cs);
uint256 hash = tx.GetHash();
}
-bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fRejectAbsurdFee)
+bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee)
{
AssertLockHeld(cs_main);
if (pfMissingInputs)
*pfMissingInputs = false;
-
+
+ int nextBlockHeight = chainActive.Height() + 1;
+ auto consensusBranchId = CurrentEpochBranchId(nextBlockHeight, Params().GetConsensus());
+
// 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");
size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0);
return false;
}
}
-
+
auto verifier = libzcash::ProofVerifier::Strict();
+ if ( komodo_validate_interest(tx,chainActive.Tip()->nHeight+1,chainActive.Tip()->GetMedianTimePast() + 777,0) < 0 )
+ {
+ //fprintf(stderr,"AcceptToMemoryPool komodo_validate_interest failure\n");
+ return error("AcceptToMemoryPool: komodo_validate_interest failed");
+ }
if (!CheckTransaction(tx, state, verifier))
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.
- int nextBlockHeight = chainActive.Height() + 1;
if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) {
return error("AcceptToMemoryPool: ContextualCheckTransaction failed");
}
-
+
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase())
- return state.DoS(100, error("AcceptToMemoryPool: coinbase as individual tx"),
- REJECT_INVALID, "coinbase");
-
+ {
+ 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 (Params().RequireStandard() && !IsStandardTx(tx, reason, nextBlockHeight))
- return state.DoS(0,
- error("AcceptToMemoryPool: nonstandard transaction: %s", reason),
- REJECT_NONSTANDARD, reason);
-
+ {
+ fprintf(stderr,"AcceptToMemoryPool reject nonstandard transaction: %s\n",reason.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 (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
+ {
+ //fprintf(stderr,"AcceptToMemoryPool reject non-final\n");
return state.DoS(0, false, REJECT_NONSTANDARD, "non-final");
-
+ }
// is it already in the memory pool?
uint256 hash = tx.GetHash();
if (pool.exists(hash))
+ {
+ fprintf(stderr,"already in mempool\n");
return false;
-
+ }
+
// Check for conflicts with in-memory transactions
{
- LOCK(pool.cs); // protect pool.mapNextTx
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
- COutPoint outpoint = tx.vin[i].prevout;
- if (pool.mapNextTx.count(outpoint))
+ LOCK(pool.cs); // protect pool.mapNextTx
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
{
- // Disable replacement feature for now
- return false;
- }
- }
- BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
- BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) {
- if (pool.mapNullifiers.count(nf))
+ COutPoint outpoint = tx.vin[i].prevout;
+ if (pool.mapNextTx.count(outpoint))
{
+ static uint32_t counter;
+ // Disable replacement feature for now
+ //if ( counter++ < 100 )
+ fprintf(stderr,"Disable replacement feature for now\n");
return false;
}
}
- }
+ BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit)
+ {
+ BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers)
+ {
+ if (pool.mapNullifiers.count(nf))
+ {
+ fprintf(stderr,"pool.mapNullifiers.count\n");
+ return false;
+ }
+ }
+ }
}
{
CCoinsView dummy;
CCoinsViewCache view(&dummy);
-
+ int64_t interest;
CAmount nValueIn = 0;
{
- LOCK(pool.cs);
- CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
- view.SetBackend(viewMemPool);
-
- // do we already have it?
- if (view.HaveCoins(hash))
- return false;
-
- // do all inputs exist?
- // Note that this does not check for the presence of actual outputs (see the next check for that),
- // and only helps with filling in pfMissingInputs (to determine missing vs spent).
- BOOST_FOREACH(const CTxIn txin, tx.vin) {
- if (!view.HaveCoins(txin.prevout.hash)) {
- if (pfMissingInputs)
- *pfMissingInputs = true;
+ LOCK(pool.cs);
+ CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
+ view.SetBackend(viewMemPool);
+
+ // do we already have it?
+ if (view.HaveCoins(hash))
+ {
+ fprintf(stderr,"view.HaveCoins(hash) error\n");
return false;
}
- }
-
- // are the actual inputs available?
- if (!view.HaveInputs(tx))
- return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),
- REJECT_DUPLICATE, "bad-txns-inputs-spent");
-
- // are the joinsplit's requirements met?
- if (!view.HaveJoinSplitRequirements(tx))
- 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();
-
- nValueIn = view.GetValueIn(tx);
-
- // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
- view.SetBackend(dummy);
- }
-
+
+ // do all inputs exist?
+ // Note that this does not check for the presence of actual outputs (see the next check for that),
+ // and only helps with filling in pfMissingInputs (to determine missing vs spent).
+ BOOST_FOREACH(const CTxIn txin, tx.vin)
+ {
+ if (!view.HaveCoins(txin.prevout.hash))
+ {
+ if (pfMissingInputs)
+ *pfMissingInputs = true;
+ //fprintf(stderr,"missing inputs\n");
+ return false;
+ }
+ }
+
+ // are the actual inputs available?
+ if (!view.HaveInputs(tx))
+ {
+ //fprintf(stderr,"accept failure.1\n");
+ 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();
+
+ nValueIn = view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->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 (Params().RequireStandard() && !AreInputsStandard(tx, view))
- return error("AcceptToMemoryPool: nonstandard transaction input");
-
+ 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
unsigned int nSigOps = GetLegacySigOpCount(tx);
nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_STANDARD_TX_SIGOPS)
- return state.DoS(0,
- error("AcceptToMemoryPool: too many sigops %s, %d > %d",
- hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS),
- REJECT_NONSTANDARD, "bad-txns-too-many-sigops");
+ {
+ fprintf(stderr,"accept failure.4\n");
+ return state.DoS(0, 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();
CAmount nFees = nValueIn-nValueOut;
double dPriority = view.GetPriority(tx, chainActive.Height());
-
+
// Keep track of transactions that spend a coinbase, which we re-scan
// during reorgs to ensure COINBASE_MATURITY is still met.
bool fSpendsCoinbase = false;
break;
}
}
-
+
// 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.
// Don't accept it if it can't get into a block
CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
if (fLimitFree && nFees < txMinFee)
- return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",
- hash.ToString(), nFees, txMinFee),
- REJECT_INSUFFICIENTFEE, "insufficient fee");
+ {
+ fprintf(stderr,"accept failure.5\n");
+ 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.
static double dFreeCount;
static int64_t nLastTime;
int64_t nNow = GetTime();
-
+
LOCK(csFreeLimiter);
-
+
// Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
- return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"),
- REJECT_INSUFFICIENTFEE, "rate limited free transaction");
+ {
+ fprintf(stderr,"accept failure.7\n");
+ return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"), REJECT_INSUFFICIENTFEE, "rate limited free transaction");
+ }
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
}
-
- if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
- return error("AcceptToMemoryPool: absurdly high fees %s, %d > %d",
- hash.ToString(),
- nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
-
+
+ if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000 && nFees > nValueOut/19 )
+ {
+ fprintf(stderr,"accept failure.8\n");
+ return error("AcceptToMemoryPool: absurdly high fees %s, %d > %d",hash.ToString(), nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
+ }
+
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus()))
+ PrecomputedTransactionData txdata(tx);
+ 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
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
- if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus()))
+ if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
{
+ fprintf(stderr,"accept failure.10\n");
return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString());
}
-
+
// Store transaction in memory
+ if ( komodo_is_notarytx(tx) == 0 )
+ KOMODO_ON_DEMAND++;
pool.addUnchecked(hash, entry, !IsInitialBlockDownload());
}
-
+
SyncWithWallets(tx, NULL);
-
+
return true;
}
return false;
}
-
-
-
+/*char *komodo_getspendscript(uint256 hash,int32_t n)
+{
+ CTransaction tx; uint256 hashBlock;
+ if ( !GetTransaction(hash,tx,hashBlock,true) )
+ {
+ printf("null GetTransaction\n");
+ return(0);
+ }
+ if ( n >= 0 && n < tx.vout.size() )
+ return((char *)tx.vout[n].scriptPubKey.ToString().c_str());
+ else printf("getspendscript illegal n.%d\n",n);
+ return(0);
+}*/
//////////////////////////////////////////////////////////////////////////////
return true;
}
-bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
+bool ReadBlockFromDisk(int32_t height,CBlock& block, const CDiskBlockPos& pos)
{
+ uint8_t pubkey33[33];
block.SetNull();
// Open history file to read
CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
- return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString());
+ {
+ //fprintf(stderr,"readblockfromdisk err A\n");
+ return false;//error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString());
+ }
// Read block
try {
filein >> block;
}
catch (const std::exception& e) {
+ fprintf(stderr,"readblockfromdisk err B\n");
return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString());
}
-
// Check the header
- if (!(CheckEquihashSolution(&block, Params()) &&
- CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())))
+ komodo_block2pubkey33(pubkey33,block);
+ if (!(CheckEquihashSolution(&block, Params()) && CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus())))
+ {
+ int32_t i; for (i=0; i<33; i++)
+ printf("%02x",pubkey33[i]);
+ fprintf(stderr," warning unexpected diff at ht.%d\n",height);
+
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
-
+ }
return true;
}
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
{
- if (!ReadBlockFromDisk(block, pindex->GetBlockPos()))
+ if ( pindex == 0 )
+ return false;
+ if (!ReadBlockFromDisk(pindex->nHeight,block, pindex->GetBlockPos()))
return false;
if (block.GetHash() != pindex->GetBlockHash())
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s",
return true;
}
+//uint64_t komodo_moneysupply(int32_t height);
+extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
+extern uint32_t ASSETCHAINS_MAGIC;
+extern uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY;
+
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
{
- CAmount nSubsidy = 12.5 * COIN;
-
+ static uint64_t cached_subsidy; static int32_t cached_numhalvings;
+ int32_t numhalvings,i; uint64_t numerator; CAmount nSubsidy = 3 * COIN;
+ if ( ASSETCHAINS_SYMBOL[0] == 0 )
+ {
+ if ( nHeight == 1 )
+ return(100000000 * COIN); // ICO allocation
+ else if ( nHeight < KOMODO_ENDOFERA ) //komodo_moneysupply(nHeight) < MAX_MONEY )
+ return(3 * COIN);
+ else return(0);
+ }
+ else
+ {
+ if ( nHeight == 1 )
+ return(ASSETCHAINS_SUPPLY * COIN + (ASSETCHAINS_MAGIC & 0xffffff));
+ else if ( ASSETCHAINS_ENDSUBSIDY == 0 || nHeight < ASSETCHAINS_ENDSUBSIDY )
+ {
+ if ( ASSETCHAINS_REWARD == 0 )
+ return(10000);
+ else if ( ASSETCHAINS_ENDSUBSIDY != 0 && nHeight >= ASSETCHAINS_ENDSUBSIDY )
+ return(0);
+ else
+ {
+ nSubsidy = ASSETCHAINS_REWARD;
+ if ( ASSETCHAINS_HALVING != 0 )
+ {
+ if ( (numhalvings= (nHeight / ASSETCHAINS_HALVING)) > 0 )
+ {
+ if ( numhalvings >= 64 && ASSETCHAINS_DECAY == 0 )
+ return(0);
+ if ( ASSETCHAINS_DECAY == 0 )
+ nSubsidy >>= numhalvings;
+ else if ( ASSETCHAINS_DECAY == 100000000 && ASSETCHAINS_ENDSUBSIDY != 0 )
+ {
+ numerator = (ASSETCHAINS_ENDSUBSIDY - nHeight);
+ nSubsidy = (nSubsidy * numerator) / ASSETCHAINS_ENDSUBSIDY;
+ }
+ else
+ {
+ if ( cached_subsidy > 0 && cached_numhalvings == numhalvings )
+ nSubsidy = cached_subsidy;
+ else
+ {
+ for (i=0; i<numhalvings&&nSubsidy!=0; i++)
+ nSubsidy = (nSubsidy * ASSETCHAINS_DECAY) / 100000000;
+ cached_subsidy = nSubsidy;
+ cached_numhalvings = numhalvings;
+ }
+ }
+ }
+ }
+ }
+ return(nSubsidy);
+ } else return(0);
+ }
+/*
// Mining slow start
// The subsidy is ramped up linearly, skipping the middle payout of
// MAX_SUBSIDY/2 to keep the monetary curve consistent with no slow start.
}
assert(nHeight > consensusParams.SubsidySlowStartShift());
- int halvings = (nHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nSubsidyHalvingInterval;
+ int halvings = (nHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nSubsidyHalvingInterval;*/
// Force block reward to zero when right shift is undefined.
- if (halvings >= 64)
- return 0;
+ //int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
+ //if (halvings >= 64)
+ // return 0;
// Subsidy is cut in half every 840,000 blocks which will occur approximately every 4 years.
- nSubsidy >>= halvings;
+ //nSubsidy >>= halvings;
return nSubsidy;
}
const CChainParams& chainParams = Params();
LOCK(cs_main);
if (fImporting || fReindex)
+ {
+ //fprintf(stderr,"IsInitialBlockDownload: fImporting %d || %d fReindex\n",(int32_t)fImporting,(int32_t)fReindex);
return true;
+ }
if (fCheckpointsEnabled && chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints()))
+ {
+ //fprintf(stderr,"IsInitialBlockDownload: checkpoint -> initialdownload\n");
return true;
+ }
static bool lockIBDState = false;
if (lockIBDState)
+ {
+ //fprintf(stderr,"lockIBDState true %d < %d\n",chainActive.Height(),pindexBestHeader->nHeight - 10);
return false;
- bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 ||
- pindexBestHeader->GetBlockTime() < GetTime() - chainParams.MaxTipAge());
+ }
+ bool state; CBlockIndex *ptr = chainActive.Tip();
+ if ( ptr == 0 )
+ ptr = pindexBestHeader;
+ else if ( pindexBestHeader != 0 && pindexBestHeader->nHeight > ptr->nHeight )
+ ptr = pindexBestHeader;
+ //if ( ASSETCHAINS_SYMBOL[0] == 0 )
+ state = ((chainActive.Height() < ptr->nHeight - 24*60) ||
+ ptr->GetBlockTime() < (GetTime() - chainParams.MaxTipAge()));
+ //else state = (chainActive.Height() < ptr->nHeight - 24*60);
+ //fprintf(stderr,"state.%d ht.%d vs %d, t.%u %u\n",state,(int32_t)chainActive.Height(),(uint32_t)ptr->nHeight,(int32_t)ptr->GetBlockTime(),(uint32_t)(GetTime() - chainParams.MaxTipAge()));
if (!state)
+ {
lockIBDState = true;
+ }
return state;
}
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight)
{
- // mark inputs spent
- if (!tx.IsCoinBase()) {
+ if (!tx.IsCoinBase()) // mark inputs spent
+ {
txundo.vprevout.reserve(tx.vin.size());
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash);
}
}
}
-
- // spend nullifiers
- BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
+ BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { // spend nullifiers
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) {
inputs.SetNullifier(nf, true);
}
}
-
- // add outputs
- inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight);
+ inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); // add outputs
}
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
- if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore), &error)) {
+ if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), consensusBranchId, &error)) {
return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
}
return true;
// Check for negative or overflow input values
nValueIn += coins->vout[prevout.n].nValue;
+#ifdef KOMODO_ENABLE_INTEREST
+ if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.Tip() != 0 && chainActive.Tip()->nHeight >= 60000 )
+ {
+ if ( coins->vout[prevout.n].nValue >= 10*COIN )
+ {
+ int64_t interest; int32_t txheight; uint32_t locktime;
+ if ( (interest= komodo_accrued_interest(&txheight,&locktime,prevout.hash,prevout.n,0,coins->vout[prevout.n].nValue)) != 0 )
+ {
+ //fprintf(stderr,"checkResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueIn/COIN,(double)coins->vout[prevout.n].nValue/COIN,(double)interest/COIN,txheight,locktime,chainActive.Tip()->nTime);
+ nValueIn += interest;
+ }
+ }
+ }
+#endif
if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return state.DoS(100, error("CheckInputs(): txin values out of range"),
REJECT_INVALID, "bad-txns-inputvalues-outofrange");
REJECT_INVALID, "bad-txns-inputvalues-outofrange");
if (nValueIn < tx.GetValueOut())
- return state.DoS(100, error("CheckInputs(): %s value in (%s) < value out (%s)",
- tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())),
- REJECT_INVALID, "bad-txns-in-belowout");
+ return state.DoS(100, error("CheckInputs(): %s value in (%s) < value out (%s) diff %.8f",
+ tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut()),((double)nValueIn - tx.GetValueOut())/COIN),REJECT_INVALID, "bad-txns-in-belowout");
// Tally transaction fees
CAmount nTxFee = nValueIn - tx.GetValueOut();
}
}// namespace Consensus
-bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
+bool ContextualCheckInputs(
+ const CTransaction& tx,
+ CValidationState &state,
+ const CCoinsViewCache &inputs,
+ bool fScriptChecks,
+ unsigned int flags,
+ bool cacheStore,
+ PrecomputedTransactionData& txdata,
+ const Consensus::Params& consensusParams,
+ uint32_t consensusBranchId,
+ std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
assert(coins);
// Verify signature
- CScriptCheck check(*coins, tx, i, flags, cacheStore);
+ CScriptCheck check(*coins, tx, i, flags, cacheStore, consensusBranchId, &txdata);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
// avoid splitting the network between upgraded and
// non-upgraded nodes.
CScriptCheck check2(*coins, tx, i,
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, consensusBranchId, &txdata);
if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
return true;
}
+
+/*bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
+{
+ if (!NonContextualCheckInputs(tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks)) {
+ fprintf(stderr,"ContextualCheckInputs failure.0\n");
+ return false;
+ }
+
+ if (!tx.IsCoinBase())
+ {
+ // While checking, GetBestBlock() refers to the parent block.
+ // This is also true for mempool checks.
+ CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
+ int nSpendHeight = pindexPrev->nHeight + 1;
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ {
+ const COutPoint &prevout = tx.vin[i].prevout;
+ const CCoins *coins = inputs.AccessCoins(prevout.hash);
+ // Assertion is okay because NonContextualCheckInputs ensures the inputs
+ // are available.
+ assert(coins);
+
+ // If prev is coinbase, check that it's matured
+ if (coins->IsCoinBase()) {
+ if ( ASSETCHAINS_SYMBOL[0] == 0 )
+ COINBASE_MATURITY = _COINBASE_MATURITY;
+ if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) {
+ fprintf(stderr,"ContextualCheckInputs failure.1 i.%d of %d\n",i,(int32_t)tx.vin.size());
+
+ return state.Invalid(
+ error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
+ }
+ }
+ }
+ }
+
+ return true;
+}*/
+
namespace {
bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
*pfClean = false;
bool fClean = true;
-
+ komodo_disconnect(pindex,block);
CBlockUndo blockUndo;
CDiskBlockPos pos = pindex->GetUndoPos();
if (pos.IsNull())
while (i->GetBlockTime() >= startTime) {
++nBlocks;
i = i->pprev;
- if (i == NULL) return; // Ran out of chain, we must not be fully sync'ed
+ if (i == NULL) return; // Ran out of chain, we must not be fully synced
}
// How likely is it to find that many by chance?
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck)
{
const CChainParams& chainparams = Params();
+ //fprintf(stderr,"connectblock ht.%d\n",(int32_t)pindex->nHeight);
AssertLockHeld(cs_main);
-
bool fExpensiveChecks = true;
if (fCheckpointsEnabled) {
CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints());
fExpensiveChecks = false;
}
}
-
auto verifier = libzcash::ProofVerifier::Strict();
auto disabledVerifier = libzcash::ProofVerifier::Disabled();
// Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in
- if (!CheckBlock(block, state, fExpensiveChecks ? verifier : disabledVerifier, !fJustCheck, !fJustCheck))
+ if (!CheckBlock(pindex->nHeight,pindex,block, state, fExpensiveChecks ? verifier : disabledVerifier, !fJustCheck, !fJustCheck))
return false;
// verify that the view's current state corresponds to the previous block
return true;
}
+ bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()));
+ //if ( KOMODO_TESTNET_EXPIRATION != 0 && pindex->nHeight > KOMODO_TESTNET_EXPIRATION ) // "testnet"
+ // return(false);
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
BOOST_FOREACH(const CTransaction& tx, block.vtx) {
int64_t nTimeStart = GetTimeMicros();
CAmount nFees = 0;
int nInputs = 0;
+ int64_t interest,sum = 0;
unsigned int nSigOps = 0;
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
assert(tree.root() == old_tree_root);
}
+ // Grab the consensus branch ID for the block's height
+ auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, Params().GetConsensus());
+
+ std::vector<PrecomputedTransactionData> txdata;
+ txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
const CTransaction &tx = block.vtx[i];
-
nInputs += tx.vin.size();
nSigOps += GetLegacySigOpCount(tx);
if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops");
-
+//fprintf(stderr,"ht.%d vout0 t%u\n",pindex->nHeight,tx.nLockTime);
if (!tx.IsCoinBase())
{
if (!view.HaveInputs(tx))
if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops");
+ }
- nFees += view.GetValueIn(tx)-tx.GetValueOut();
+ txdata.emplace_back(tx);
+
+ if (!tx.IsCoinBase())
+ {
+ nFees += view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime) - tx.GetValueOut();
+ sum += interest;
std::vector<CScriptCheck> vChecks;
- if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL))
+ if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), consensusBranchId, nScriptCheckThreads ? &vChecks : NULL))
return false;
control.Add(vChecks);
}
-
+ //if ( ASSETCHAINS_SYMBOL[0] == 0 )
+ // komodo_earned_interest(pindex->nHeight,sum);
CTxUndo undoDummy;
if (i > 0) {
blockundo.vtxundo.push_back(CTxUndo());
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);
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
- if (block.vtx[0].GetValueOut() > blockReward)
+ if (block.vtx[0].vout[0].nValue > blockReward)
+ //if (block.vtx[0].GetValueOut() > blockReward)
return state.DoS(100,
error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)",
block.vtx[0].GetValueOut(), blockReward),
int64_t nTime4 = GetTimeMicros(); nTimeCallbacks += nTime4 - nTime3;
LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeCallbacks * 0.000001);
-
+
+ //FlushStateToDisk();
+ komodo_connectblock(pindex,*(CBlock *)&block);
return true;
}
SyncWithWallets(tx, NULL);
}
// Update cached incremental witnesses
+ //fprintf(stderr,"chaintip false\n");
GetMainSignals().ChainTip(pindexDelete, &block, newTree, false);
return true;
}
* You probably want to call mempool.removeWithoutBranchId after this, with cs_main held.
*/
bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) {
+
assert(pindexNew->pprev == chainActive.Tip());
// Read block from disk.
int64_t nTime1 = GetTimeMicros();
// Remove conflicting transactions from the mempool.
list<CTransaction> txConflicted;
mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload());
+
+ // Remove transactions that expire at new block height from mempool
+ mempool.removeExpired(pindexNew->nHeight);
+
// Update chainActive & related variables.
UpdateTip(pindexNew);
// Tell wallet about transactions that went from mempool
SyncWithWallets(tx, pblock);
}
// Update cached incremental witnesses
+ //fprintf(stderr,"chaintip true\n");
GetMainSignals().ChainTip(pindexNew, pblock, oldTree, true);
EnforceNodeDeprecation(pindexNew->nHeight);
const CBlockIndex *pindexOldTip = chainActive.Tip();
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
+ // - 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,
+ // then pindexFork will be null, and we would need to remove the entire chain including
+ // our genesis block. In practice this (probably) won't happen because of checks elsewhere.
+ auto reorgLength = pindexOldTip ? pindexOldTip->nHeight - (pindexFork ? pindexFork->nHeight : -1) : 0;
+ static_assert(MAX_REORG_LENGTH > 0, "We must be able to reorg some distance");
+ if (reorgLength > MAX_REORG_LENGTH) {
+ auto msg = strprintf(_(
+ "A block chain reorganization has been detected that would roll back %d blocks! "
+ "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety."
+ ), reorgLength, MAX_REORG_LENGTH) + "\n\n" +
+ _("Reorganization details") + ":\n" +
+ "- " + strprintf(_("Current tip: %s, height %d, work %s"),
+ pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight, pindexOldTip->nChainWork.GetHex()) + "\n" +
+ "- " + strprintf(_("New tip: %s, height %d, work %s"),
+ pindexMostWork->phashBlock->GetHex(), pindexMostWork->nHeight, pindexMostWork->nChainWork.GetHex()) + "\n" +
+ "- " + strprintf(_("Fork point: %s, height %d"),
+ pindexFork->phashBlock->GetHex(), pindexFork->nHeight) + "\n\n" +
+ _("Please help, human!");
+ LogPrintf("*** %s\n", msg);
+ uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR);
+ StartShutdown();
+ return false;
+ }
+
// Disconnect active blocks which are no longer in the best chain.
bool fBlocksDisconnected = false;
while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
return false;
fBlocksDisconnected = true;
}
-
+ if ( KOMODO_REWIND != 0 )
+ {
+ fprintf(stderr,"rewind start ht.%d\n",chainActive.Tip()->nHeight);
+ while ( KOMODO_REWIND > 0 && chainActive.Tip()->nHeight > KOMODO_REWIND )
+ {
+ if ( !DisconnectTip(state) )
+ {
+ InvalidateBlock(state,chainActive.Tip());
+ break;
+ }
+ }
+ fprintf(stderr,"reached rewind.%d, best to do: ./komodo-cli stop\n",KOMODO_REWIND);
+ sleep(60);
+ KOMODO_REWIND = 0;
+ return(true);
+ }
// Build list of new blocks to connect.
std::vector<CBlockIndex*> vpindexToConnect;
bool fContinue = true;
if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL))
return false;
-
pindexNewTip = chainActive.Tip();
fInitialDownload = IsInitialBlockDownload();
}
// Notify external listeners about the new tip.
GetMainSignals().UpdatedBlockTip(pindexNewTip);
uiInterface.NotifyBlockTip(hashNewTip);
- }
+ } //else fprintf(stderr,"initial download skips propagation\n");
} while(pindexMostWork != chainActive.Tip());
CheckBlockIndex();
return false;
}
}
+ //LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
// The resulting new best tip may not be in setBlockIndexCandidates anymore, so
// add it again.
BlockMap::iterator it = mapBlockIndex.begin();
- while (it != mapBlockIndex.end()) {
+ while (it != mapBlockIndex.end() && it->second != 0 ) {
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) {
setBlockIndexCandidates.insert(it->second);
}
return true;
}
-bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW)
+bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& blockhdr, CValidationState& state, bool fCheckPOW)
{
+ uint8_t pubkey33[33];
+ // Check timestamp
+ if ( 0 )
+ {
+ uint256 hash; int32_t i;
+ hash = blockhdr.GetHash();
+ for (i=31; i>=0; i--)
+ fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
+ fprintf(stderr," <- CheckBlockHeader\n");
+ if ( chainActive.Tip() != 0 )
+ {
+ hash = chainActive.Tip()->GetBlockHash();
+ for (i=31; i>=0; i--)
+ fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
+ fprintf(stderr," <- chainTip\n");
+ }
+ }
+ if (blockhdr.GetBlockTime() > GetAdjustedTime() + 60)
+ return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new");
// Check block version
- if (block.nVersion < MIN_BLOCK_VERSION)
- return state.DoS(100, error("CheckBlockHeader(): block version too low"),
- REJECT_INVALID, "version-too-low");
+ //if (block.nVersion < MIN_BLOCK_VERSION)
+ // return state.DoS(100, error("CheckBlockHeader(): block version too low"),REJECT_INVALID, "version-too-low");
// Check Equihash solution is valid
- if (fCheckPOW && !CheckEquihashSolution(&block, Params()))
- return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),
- REJECT_INVALID, "invalid-solution");
-
+ if ( fCheckPOW && !CheckEquihashSolution(&blockhdr, Params()) )
+ return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),REJECT_INVALID, "invalid-solution");
+
// Check proof of work matches claimed amount
- if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus()))
- return state.DoS(50, error("CheckBlockHeader(): proof of work failed"),
- REJECT_INVALID, "high-hash");
-
- // Check timestamp
- if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
- return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),
- REJECT_INVALID, "time-too-new");
-
+ komodo_index2pubkey33(pubkey33,pindex,height);
+ if ( fCheckPOW && !CheckProofOfWork(height,pubkey33,blockhdr.GetHash(), blockhdr.nBits, Params().GetConsensus()) )
+ return state.DoS(50, error("CheckBlockHeader(): proof of work failed"),REJECT_INVALID, "high-hash");
return true;
}
-bool CheckBlock(const CBlock& block, CValidationState& state,
+int32_t komodo_check_deposit(int32_t height,const CBlock& block);
+bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state,
libzcash::ProofVerifier& verifier,
bool fCheckPOW, bool fCheckMerkleRoot)
{
// Check that the header is valid (particularly PoW). This is mostly
// redundant with the call in AcceptBlockHeader.
- if (!CheckBlockHeader(block, state, fCheckPOW))
+ if (!CheckBlockHeader(height,pindex,block,state,fCheckPOW))
return false;
// Check the merkle root.
// Check transactions
BOOST_FOREACH(const CTransaction& tx, block.vtx)
+ {
+ if ( komodo_validate_interest(tx,komodo_block2height((CBlock *)&block),block.nTime,1) < 0 )
+ return error("CheckBlock: komodo_validate_interest failed");
if (!CheckTransaction(tx, state, verifier))
return error("CheckBlock(): CheckTransaction failed");
-
+ }
unsigned int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, block.vtx)
{
if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("CheckBlock(): out-of-bounds SigOpCount"),
REJECT_INVALID, "bad-blk-sigops", true);
-
+ if ( komodo_check_deposit(ASSETCHAINS_SYMBOL[0] == 0 ? height : pindex != 0 ? (int32_t)pindex->nHeight : chainActive.Tip()->nHeight+1,block) < 0 )
+ {
+ static uint32_t counter;
+ if ( counter++ < 100 )
+ fprintf(stderr,"check deposit rejection\n");
+ return(false);
+ }
return true;
}
int nHeight = pindexPrev->nHeight+1;
// Check proof of work
- if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
+ if ( (nHeight < 235300 || nHeight > 236000) && block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
+ {
+ cout << block.nBits << " block.nBits vs. calc " << GetNextWorkRequired(pindexPrev, &block, consensusParams) << endl;
return state.DoS(100, error("%s: incorrect proof of work", __func__),
REJECT_INVALID, "bad-diffbits");
+ }
// Check timestamp against prev
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
if (fCheckpointsEnabled)
{
+ // Check that the block chain matches the known block chain up to a checkpoint
+ if (!Checkpoints::CheckBlock(chainParams.Checkpoints(), nHeight, hash))
+ return state.DoS(100, error("%s: rejected by checkpoint lock-in at %d", __func__, nHeight),REJECT_CHECKPOINT, "checkpoint mismatch");
+
// Don't accept any forks from the main chain prior to last checkpoint
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints());
- if (pcheckpoint && nHeight < pcheckpoint->nHeight)
- return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
+ int32_t notarized_height;
+ if (pcheckpoint && (nHeight < pcheckpoint->nHeight || nHeight == 1 && chainActive.Tip() != 0 && chainActive.Tip()->nHeight > 1) )
+ return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d) vs %d", __func__, nHeight,pcheckpoint->nHeight));
+ else if ( komodo_checkpoint(¬arized_height,nHeight,hash) < 0 )
+ {
+ CBlockIndex *heightblock = chainActive[nHeight];
+ if ( heightblock != 0 && heightblock->GetBlockHash() == hash )
+ {
+ //fprintf(stderr,"got a pre notarization block that matches height.%d\n",(int32_t)nHeight);
+ return true;
+ } else return state.DoS(100, error("%s: forked chain %d older than last notarized (height %d) vs %d", __func__,nHeight, notarized_height));
+ }
}
-
// Reject block.nVersion < 4 blocks
if (block.nVersion < 4)
return state.Invalid(error("%s : rejected nVersion<4 block", __func__),
}
}
- // Coinbase transaction must include an output sending 20% of
- // the block reward to a founders reward script, until the last founders
- // reward block is reached, with exception of the genesis block.
- // The last founders reward block is defined as the block just before the
- // first subsidy halving block, which occurs at halving_interval + slow_start_shift
- if ((nHeight > 0) && (nHeight <= consensusParams.GetLastFoundersRewardBlockHeight())) {
- bool found = false;
-
- BOOST_FOREACH(const CTxOut& output, block.vtx[0].vout) {
- if (output.scriptPubKey == Params().GetFoundersRewardScriptAtHeight(nHeight)) {
- if (output.nValue == (GetBlockSubsidy(nHeight, consensusParams) / 5)) {
- found = true;
- break;
- }
- }
- }
-
- if (!found) {
- return state.DoS(100, error("%s: founders reward missing", __func__), REJECT_INVALID, "cb-no-founders-reward");
- }
- }
-
return true;
}
pindex = miSelf->second;
if (ppindex)
*ppindex = pindex;
- if (pindex->nStatus & BLOCK_FAILED_MASK)
+ if (pindex != 0 && pindex->nStatus & BLOCK_FAILED_MASK)
return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate");
+ if ( pindex != 0 && IsInitialBlockDownload() == 0 ) // jl777 debug test
+ {
+ if (!CheckBlockHeader(pindex->nHeight,pindex, block, state))
+ {
+ pindex->nStatus |= BLOCK_FAILED_MASK;
+ fprintf(stderr,"known block failing CheckBlockHeader %d\n",(int32_t)pindex->nHeight);
+ return false;
+ }
+ CBlockIndex* pindexPrev = NULL;
+ if (hash != chainparams.GetConsensus().hashGenesisBlock)
+ {
+ BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
+ if (mi == mapBlockIndex.end())
+ {
+ pindex->nStatus |= BLOCK_FAILED_MASK;
+ fprintf(stderr,"known block.%d failing to find prevblock\n",(int32_t)pindex->nHeight);
+ return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk");
+ }
+ pindexPrev = (*mi).second;
+ if (pindexPrev == 0 || (pindexPrev->nStatus & BLOCK_FAILED_MASK) )
+ {
+ pindex->nStatus |= BLOCK_FAILED_MASK;
+ fprintf(stderr,"known block.%d found invalid prevblock\n",(int32_t)pindex->nHeight);
+ return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
+ }
+ }
+ if (!ContextualCheckBlockHeader(block, state, pindexPrev))
+ {
+ pindex->nStatus |= BLOCK_FAILED_MASK;
+ fprintf(stderr,"known block.%d failing ContextualCheckBlockHeader\n",(int32_t)pindex->nHeight);
+ return false;
+ }
+ }
+
return true;
}
- if (!CheckBlockHeader(block, state))
+ if (!CheckBlockHeader(*ppindex!=0?(*ppindex)->nHeight:0,*ppindex, block, state))
return false;
// Get prev block index
if (hash != chainparams.GetConsensus().hashGenesisBlock) {
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end())
+ {
return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk");
+ }
pindexPrev = (*mi).second;
- if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
+ if (pindexPrev == 0 || (pindexPrev->nStatus & BLOCK_FAILED_MASK) )
return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
}
-
if (!ContextualCheckBlockHeader(block, state, pindexPrev))
return false;
-
if (pindex == NULL)
pindex = AddToBlockIndex(block);
-
if (ppindex)
*ppindex = pindex;
-
return true;
}
AssertLockHeld(cs_main);
CBlockIndex *&pindex = *ppindex;
-
if (!AcceptBlockHeader(block, state, &pindex))
return false;
-
+ if ( pindex == 0 )
+ {
+ fprintf(stderr,"AcceptBlock error null pindex\n");
+ return false;
+ }
// Try to process all requested blocks that we don't have, but only
// process an unrequested block if it's new and has enough work to
// advance our tip, and isn't too many blocks ahead.
// See method docstring for why this is always disabled
auto verifier = libzcash::ProofVerifier::Disabled();
- if ((!CheckBlock(block, state, verifier)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
+ if ((!CheckBlock(pindex->nHeight,pindex,block, state, verifier)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
if (state.IsInvalid() && !state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
return (nFound >= nRequired);
}
+void komodo_currentheight_set(int32_t height);
-bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp)
+bool ProcessNewBlock(int32_t height,CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp)
{
// Preliminary checks
+ bool checked;
auto verifier = libzcash::ProofVerifier::Disabled();
- bool checked = CheckBlock(*pblock, state, verifier);
-
+ if ( chainActive.Tip() != 0 )
+ komodo_currentheight_set(chainActive.Tip()->nHeight);
+ if ( ASSETCHAINS_SYMBOL[0] == 0 )
+ checked = CheckBlock(height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier);
+ else checked = CheckBlock(height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier);
{
LOCK(cs_main);
bool fRequested = MarkBlockAsReceived(pblock->GetHash());
fRequested |= fForceProcessing;
if (!checked) {
+ if ( pfrom != 0 )
+ Misbehaving(pfrom->GetId(), 1);
return error("%s: CheckBlock FAILED", __func__);
}
// NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, pindexPrev))
+ {
+ fprintf(stderr,"TestBlockValidity failure A\n");
return false;
- if (!CheckBlock(block, state, verifier, fCheckPOW, fCheckMerkleRoot))
+ }
+ if (!CheckBlock(indexDummy.nHeight,0,block, state, verifier, fCheckPOW, fCheckMerkleRoot))
+ {
+ //fprintf(stderr,"TestBlockValidity failure B\n");
return false;
+ }
if (!ContextualCheckBlock(block, state, pindexPrev))
+ {
+ fprintf(stderr,"TestBlockValidity failure C\n");
return false;
+ }
if (!ConnectBlock(block, state, &indexDummy, viewNew, true))
+ {
+ fprintf(stderr,"TestBlockValidity failure D\n");
return false;
+ }
assert(state.IsValid());
return true;
pindex->nCachedBranchId = pindex->pprev->nCachedBranchId;
}
} else {
- pindex->nCachedBranchId = NetworkUpgradeInfo[Consensus::BASE_SPROUT].nBranchId;
+ pindex->nCachedBranchId = SPROUT_BRANCH_ID;
}
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL))
setBlockIndexCandidates.insert(pindex);
if (!ReadBlockFromDisk(block, pindex))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 1: verify block validity
- if (nCheckLevel >= 1 && !CheckBlock(block, state, verifier))
+ if (nCheckLevel >= 1 && !CheckBlock(pindex->nHeight,pindex,block, state, verifier))
return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) {
}
// nHeight is now the height of the first insufficiently-validated block, or tipheight + 1
+ auto rewindLength = chainActive.Height() - nHeight;
+ if (rewindLength > 0 && rewindLength > MAX_REORG_LENGTH) {
+ auto pindexOldTip = chainActive.Tip();
+ auto pindexRewind = chainActive[nHeight - 1];
+ auto msg = strprintf(_(
+ "A block chain rewind has been detected that would roll back %d blocks! "
+ "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety."
+ ), rewindLength, MAX_REORG_LENGTH) + "\n\n" +
+ _("Rewind details") + ":\n" +
+ "- " + strprintf(_("Current tip: %s, height %d"),
+ pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight) + "\n" +
+ "- " + strprintf(_("Rewinding to: %s, height %d"),
+ pindexRewind->phashBlock->GetHex(), pindexRewind->nHeight) + "\n\n" +
+ _("Please help, human!");
+ LogPrintf("*** %s\n", msg);
+ uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR);
+ StartShutdown();
+ return false;
+ }
+
CValidationState state;
CBlockIndex* pindex = chainActive.Tip();
while (chainActive.Height() >= nHeight) {
bool LoadBlockIndex()
{
+ extern int32_t KOMODO_LOADINGBLOCKS;
// Load block index from databases
+ KOMODO_LOADINGBLOCKS = 1;
if (!fReindex && !LoadBlockIndexDB())
+ {
+ KOMODO_LOADINGBLOCKS = 0;
return false;
+ }
+ KOMODO_LOADINGBLOCKS = 0;
+ fprintf(stderr,"finished loading blocks %s\n",ASSETCHAINS_SYMBOL);
return true;
}
return true;
// Use the provided setting for -txindex in the new database
- fTxIndex = GetBoolArg("-txindex", false);
+ fTxIndex = GetBoolArg("-txindex", true);
pblocktree->WriteFlag("txindex", fTxIndex);
LogPrintf("Initializing databases...\n");
// process in case the block isn't known yet
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
CValidationState state;
- if (ProcessNewBlock(state, NULL, &block, true, dbp))
+ if (ProcessNewBlock(0,state, NULL, &block, true, dbp))
nLoaded++;
if (state.IsError())
break;
std::pair<std::multimap<uint256, CDiskBlockPos>::iterator, std::multimap<uint256, CDiskBlockPos>::iterator> range = mapBlocksUnknownParent.equal_range(head);
while (range.first != range.second) {
std::multimap<uint256, CDiskBlockPos>::iterator it = range.first;
- if (ReadBlockFromDisk(block, it->second))
+ if (ReadBlockFromDisk(mapBlockIndex[hash]!=0?mapBlockIndex[hash]->nHeight:0,block, it->second))
{
LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
head.ToString());
CValidationState dummy;
- if (ProcessNewBlock(dummy, NULL, &block, true, &it->second))
+ if (ProcessNewBlock(0,dummy, NULL, &block, true, &it->second))
{
nLoaded++;
queue.push_back(block.GetHash());
// Build forward-pointing map of the entire block tree.
std::multimap<CBlockIndex*,CBlockIndex*> forward;
for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) {
- forward.insert(std::make_pair(it->second->pprev, it->second));
+ forward.insert(std::make_pair(it->second->pprev, it->second));
}
assert(forward.size() == mapBlockIndex.size());
// Send block from disk
CBlock block;
if (!ReadBlockFromDisk(block, (*mi).second))
+ {
assert(!"cannot load block from disk");
- if (inv.type == MSG_BLOCK)
- pfrom->PushMessage("block", block);
- else // MSG_FILTERED_BLOCK)
+ }
+ else
{
- LOCK(pfrom->cs_filter);
- if (pfrom->pfilter)
+ if (inv.type == MSG_BLOCK)
{
- CMerkleBlock merkleBlock(block, *pfrom->pfilter);
- pfrom->PushMessage("merkleblock", merkleBlock);
- // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
- // This avoids hurting performance by pointlessly requiring a round-trip
- // Note that there is currently no way for a node to request any single transactions we didn't send here -
- // they must either disconnect and retry or request the full block.
- // Thus, the protocol spec specified allows for us to provide duplicate txn here,
- // however we MUST always provide at least what the remote peer needs
- typedef std::pair<unsigned int, uint256> PairType;
- BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
+ //uint256 hash; int32_t z;
+ //hash = block.GetHash();
+ //for (z=31; z>=0; z--)
+ // fprintf(stderr,"%02x",((uint8_t *)&hash)[z]);
+ //fprintf(stderr," send block %d\n",komodo_block2height(&block));
+ pfrom->PushMessage("block", block);
+ }
+ else // MSG_FILTERED_BLOCK)
+ {
+ LOCK(pfrom->cs_filter);
+ if (pfrom->pfilter)
+ {
+ CMerkleBlock merkleBlock(block, *pfrom->pfilter);
+ pfrom->PushMessage("merkleblock", merkleBlock);
+ // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
+ // This avoids hurting performance by pointlessly requiring a round-trip
+ // Note that there is currently no way for a node to request any single transactions we didn't send here -
+ // they must either disconnect and retry or request the full block.
+ // Thus, the protocol spec specified allows for us to provide duplicate txn here,
+ // however we MUST always provide at least what the remote peer needs
+ typedef std::pair<unsigned int, uint256> PairType;
+ BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second)))
pfrom->PushMessage("tx", block.vtx[pair.first]);
- }
- // else
+ }
+ // else
// no response
+ }
}
-
// Trigger the peer node to send a getblocks request for the next batch of inventory
if (inv.hash == pfrom->hashContinue)
{
{
const CChainParams& chainparams = Params();
LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
+ //fprintf(stderr, "recv: %s peer=%d\n", SanitizeString(strCommand).c_str(), (int32_t)pfrom->GetId());
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n");
return false;
}
+ // When Overwinter is active, reject incoming connections from non-Overwinter nodes
+ const Consensus::Params& params = Params().GetConsensus();
+ if (NetworkUpgradeActive(GetHeight(), params, Consensus::UPGRADE_OVERWINTER)
+ && pfrom->nVersion < params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)
+ {
+ LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion);
+ pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE,
+ strprintf("Version must be %d or greater",
+ params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion));
+ pfrom->fDisconnect = true;
+ return false;
+ }
+
if (pfrom->nVersion == 10300)
pfrom->nVersion = 300;
if (!vRecv.empty())
}
+ // Disconnect existing peer connection when:
+ // 1. The version message has been received
+ // 2. Overwinter is active
+ // 3. Peer version is pre-Overwinter
+ else if (NetworkUpgradeActive(GetHeight(), chainparams.GetConsensus(), Consensus::UPGRADE_OVERWINTER)
+ && (pfrom->nVersion < chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion))
+ {
+ LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion);
+ pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE,
+ strprintf("Version must be %d or greater",
+ chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion));
+ pfrom->fDisconnect = true;
+ return false;
+ }
+
+
else if (strCommand == "addr")
{
vector<CAddress> vAddr;
vector<CBlock> vHeaders;
int nLimit = MAX_HEADERS_RESULTS;
LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id);
- for (; pindex; pindex = chainActive.Next(pindex))
+ if ( pfrom->lasthdrsreq >= chainActive.Height()-MAX_HEADERS_RESULTS || pfrom->lasthdrsreq != (int32_t)(pindex ? pindex->nHeight : -1) )
{
- vHeaders.push_back(pindex->GetBlockHeader());
- if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
- break;
+ pfrom->lasthdrsreq = (int32_t)(pindex ? pindex->nHeight : -1);
+ for (; pindex; pindex = chainActive.Next(pindex))
+ {
+ vHeaders.push_back(pindex->GetBlockHeader());
+ if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
+ break;
+ }
+ pfrom->PushMessage("headers", vHeaders);
+ }
+ else if ( NOTARY_PUBKEY33[0] != 0 )
+ {
+ static uint32_t counter;
+ if ( counter++ < 3 )
+ fprintf(stderr,"you can ignore redundant getheaders from peer.%d %d prev.%d\n",(int32_t)pfrom->id,(int32_t)(pindex ? pindex->nHeight : -1),pfrom->lasthdrsreq);
}
- pfrom->PushMessage("headers", vHeaders);
}
int nDoS;
if (state.IsInvalid(nDoS)) {
if (nDoS > 0)
- Misbehaving(pfrom->GetId(), nDoS);
+ Misbehaving(pfrom->GetId(), nDoS/nDoS);
return error("invalid header received");
}
}
// Headers message had its maximum size; the peer may have more headers.
// TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
// from there instead.
- LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight);
- pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexLast), uint256());
+ if ( pfrom->sendhdrsreq >= chainActive.Height()-MAX_HEADERS_RESULTS || pindexLast->nHeight != pfrom->sendhdrsreq )
+ {
+ pfrom->sendhdrsreq = (int32_t)pindexLast->nHeight;
+ LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight);
+ pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexLast), uint256());
+ }
}
CheckBlockIndex();
// Such an unrequested block may still be processed, subject to the
// conditions in AcceptBlock().
bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
- ProcessNewBlock(state, pfrom, &block, forceProcessing, NULL);
+ ProcessNewBlock(0,state, pfrom, &block, forceProcessing, NULL);
int nDoS;
if (state.IsInvalid(nDoS)) {
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
}
}
}
-
else if (strCommand == "notfound") {
// We do not care about the NOTFOUND message, but logging an Unknown Command
// message would be undesirable as we transmit it ourselves.
}
else
{
- PrintExceptionContinue(&e, "ProcessMessages()");
+ //PrintExceptionContinue(&e, "ProcessMessages()");
}
}
catch (const boost::thread_interrupted&) {
}
} instance_of_cmaincleanup;
+extern "C" const char* getDataDir()
+{
+ return GetDataDir().string().c_str();
+}
+
// Set default values of new CMutableTransaction based on consensus rules at given height.
CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight)