X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.cpp;h=2a97e49d50ebaa37698af420e656d179479ce678;hb=f94158ea104e435166e6e6074f0d941b903267eb;hp=008f209ad2f45dd89e9eb1aaee755b692cd89922;hpb=90852995d1c9872f87c9a155c5f6d01fd1a35934;p=novacoin.git diff --git a/src/main.cpp b/src/main.cpp index 008f209..2a97e49 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -79,6 +79,10 @@ const string strMessageMagic = "NovaCoin Signed Message:\n"; int64_t nTransactionFee = MIN_TX_FEE; int64_t nMinimumInputValue = MIN_TX_FEE; +// Ping and address broadcast intervals +int64_t nPingInterval = 30 * 60; +int64_t nBroadcastInterval = 24 * 60 * 60; + extern enum Checkpoints::CPMode CheckpointsMode; ////////////////////////////////////////////////////////////////////////////// @@ -1055,7 +1059,7 @@ int64_t GetProofOfWorkReward(unsigned int nBits, int64_t nFees) } // miner's coin stake reward based on nBits and coin age spent (coin-days) -int64_t GetProofOfStakeReward(int64_t nCoinAge, unsigned int nBits, unsigned int nTime, bool bCoinYearOnly) +int64_t GetProofOfStakeReward(int64_t nCoinAge, unsigned int nBits, int64_t nTime, bool bCoinYearOnly) { int64_t nRewardCoinYear, nSubsidy, nSubsidyLimit = 10 * COIN; @@ -2228,38 +2232,31 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c // These are checks that are independent of context // that can be verified before saving an orphan block. + set uniqueTx; // tx hashes + unsigned int nSigOps = 0; // total sigops + // Size limits if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return DoS(100, error("CheckBlock() : size limits failed")); - // Check proof of work matches claimed amount - if (fCheckPOW && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits)) - return DoS(50, error("CheckBlock() : proof of work failed")); - - // Check timestamp - if (GetBlockTime() > FutureDrift(GetAdjustedTime())) - return error("CheckBlock() : block timestamp too far in the future"); + bool fProofOfStake = IsProofOfStake(); // First transaction must be coinbase, the rest must not be - if (vtx.empty() || !vtx[0].IsCoinBase()) + if (!vtx[0].IsCoinBase()) return DoS(100, error("CheckBlock() : first tx is not coinbase")); - // Check coinbase timestamp - if (GetBlockTime() < PastDrift((int64_t)vtx[0].nTime)) - return DoS(50, error("CheckBlock() : coinbase timestamp is too late")); - - for (unsigned int i = 1; i < vtx.size(); i++) - { - if (vtx[i].IsCoinBase()) - return DoS(100, error("CheckBlock() : more than one coinbase")); + if (!vtx[0].CheckTransaction()) + return DoS(vtx[0].nDoS, error("CheckBlock() : CheckTransaction failed on coinbase")); - // Check transaction timestamp - if (GetBlockTime() < (int64_t)vtx[i].nTime) - return DoS(50, error("CheckBlock() : block timestamp earlier than transaction timestamp")); - } + uniqueTx.insert(vtx[0].GetHash()); + nSigOps += vtx[0].GetLegacySigOpCount(); - if (IsProofOfStake()) + if (fProofOfStake) { + // Proof-of-STake related checkings. Note that we know here that 1st transactions is coinstake. We don't need + // check the type of 1st transaction because it's performed earlier by IsProofOfStake() + + // nNonce must be zero for proof-of-stake blocks if (nNonce != 0) return DoS(100, error("CheckBlock() : non-zero nonce in proof-of-stake block")); @@ -2267,13 +2264,6 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c if (vtx[0].vout.size() != 1 || !vtx[0].vout[0].IsEmpty()) return DoS(100, error("CheckBlock() : coinbase output not empty for proof-of-stake block")); - // Second transaction must be coinstake, the rest must not be - if (vtx.empty() || !vtx[1].IsCoinStake()) - return DoS(100, error("CheckBlock() : second tx is not coinstake")); - for (unsigned int i = 2; i < vtx.size(); i++) - if (vtx[i].IsCoinStake()) - return DoS(100, error("CheckBlock() : more than one coinstake")); - // Check coinstake timestamp if (GetBlockTime() != (int64_t)vtx[1].nTime) return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%" PRId64 " nTimeTx=%u", GetBlockTime(), vtx[1].nTime)); @@ -2281,30 +2271,63 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c // NovaCoin: check proof-of-stake block signature if (fCheckSig && !CheckBlockSignature()) return DoS(100, error("CheckBlock() : bad proof-of-stake block signature")); + + if (!vtx[1].CheckTransaction()) + return DoS(vtx[1].nDoS, error("CheckBlock() : CheckTransaction failed on coinstake")); + + uniqueTx.insert(vtx[1].GetHash()); + nSigOps += vtx[1].GetLegacySigOpCount(); } + else + { + // Check proof of work matches claimed amount + if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits)) + return DoS(50, error("CheckBlock() : proof of work failed")); - // Check transactions - BOOST_FOREACH(const CTransaction& tx, vtx) + // Check timestamp + if (GetBlockTime() > FutureDrift(GetAdjustedTime())) + return error("CheckBlock() : block timestamp too far in the future"); + + // Check coinbase timestamp + if (GetBlockTime() < PastDrift((int64_t)vtx[0].nTime)) + return DoS(50, error("CheckBlock() : coinbase timestamp is too late")); + } + + // Iterate all transactions starting from second for proof-of-stake block + // or first for proof-of-work block + for (unsigned int i = fProofOfStake ? 2 : 1; i < vtx.size(); i++) { + const CTransaction& tx = vtx[i]; + + // Reject coinbase transactions at non-zero index + if (tx.IsCoinBase()) + return DoS(100, error("CheckBlock() : coinbase at wrong index")); + + // Reject coinstake transactions at index != 1 + if (tx.IsCoinStake()) + return DoS(100, error("CheckBlock() : coinstake at wrong index")); + + // Check transaction timestamp + if (GetBlockTime() < (int64_t)tx.nTime) + return DoS(50, error("CheckBlock() : block timestamp earlier than transaction timestamp")); + + // Check transaction consistency if (!tx.CheckTransaction()) return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed")); + + // Add transaction hash into list of unique transaction IDs + uniqueTx.insert(tx.GetHash()); + + // Calculate sigops count + nSigOps += tx.GetLegacySigOpCount(); } // Check for duplicate txids. This is caught by ConnectInputs(), // but catching it earlier avoids a potential DoS attack: - set uniqueTx; - BOOST_FOREACH(const CTransaction& tx, vtx) - { - uniqueTx.insert(tx.GetHash()); - } if (uniqueTx.size() != vtx.size()) return DoS(100, error("CheckBlock() : duplicate transaction")); - unsigned int nSigOps = 0; - BOOST_FOREACH(const CTransaction& tx, vtx) - { - nSigOps += tx.GetLegacySigOpCount(); - } + // Reject block if validation would consume too much resources. if (nSigOps > MAX_BLOCK_SIGOPS) return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); @@ -2312,7 +2335,6 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree()) return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); - return true; } @@ -2500,7 +2522,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for block %s", pblock->GetProofOfStake().first.ToString().c_str(), pblock->GetProofOfStake().second, hash.ToString().c_str()); // Preliminary checks - if (!pblock->CheckBlock()) + if (!pblock->CheckBlock(true, true, (pblock->nTime > Checkpoints::GetLastCheckpointTime()))) return error("ProcessBlock() : CheckBlock FAILED"); // ppcoin: verify hash target and signature of coinstake tx @@ -2618,11 +2640,11 @@ bool CBlock::SignBlock(CWallet& wallet) if (IsProofOfStake()) return true; - static int64_t nLastCoinStakeSearchTime = GetAdjustedTime(); // startup timestamp + static uint32_t nLastCoinStakeSearchTime = GetAdjustedTime(); // startup timestamp CKey key; CTransaction txCoinStake; - int64_t nSearchTime = txCoinStake.nTime; // search to current time + uint32_t nSearchTime = txCoinStake.nTime; // search to current time if (nSearchTime > nLastCoinStakeSearchTime) { @@ -2746,6 +2768,18 @@ FILE* AppendBlockFile(unsigned int& nFileRet) } } +void UnloadBlockIndex() +{ + mapBlockIndex.clear(); + setStakeSeen.clear(); + pindexGenesisBlock = NULL; + nBestHeight = 0; + nBestChainTrust = 0; + nBestInvalidTrust = 0; + hashBestChain = 0; + pindexBest = NULL; +} + bool LoadBlockIndex(bool fAllowNew) { if (fTestNet) @@ -3914,7 +3948,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Keep-alive ping. We send a nonce of zero because we don't use it anywhere // right now. - if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) { + if (pto->nLastSend && GetTime() - pto->nLastSend > nPingInterval && pto->vSend.empty()) { uint64_t nonce = 0; if (pto->nVersion > BIP0031_VERSION) pto->PushMessage("ping", nonce); @@ -3933,7 +3967,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Address refresh broadcast static int64_t nLastRebroadcast; - if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) + if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > nBroadcastInterval)) { { LOCK(cs_vNodes);