diff options
| author | Nell Hardcastle <[email protected]> | 2014-04-11 00:01:49 -0700 |
|---|---|---|
| committer | Patrick Lodder <[email protected]> | 2014-08-01 16:42:50 +0200 |
| commit | 8808f237aa8281746e4f5fe4444e0057bd4b6058 (patch) | |
| tree | 0d6279b217f03dc1e43dfe7153732c4985f77199 /src/main.cpp | |
| parent | Import Vince Durham's aux proof of work implementation. (diff) | |
| download | discoin-8808f237aa8281746e4f5fe4444e0057bd4b6058.tar.xz discoin-8808f237aa8281746e4f5fe4444e0057bd4b6058.zip | |
Support auxillary proof of work.
Rebased from 1.7.1 into 1.7.2, moved AuxPoW checks from AcceptBlock()
into AcceptBlockHeader()
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 137 |
1 files changed, 122 insertions, 15 deletions
diff --git a/src/main.cpp b/src/main.cpp index cfab94e65..2735fc6d4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,7 @@ #include "checkpoints.h" #include "checkqueue.h" #include "init.h" +#include "auxpow.h" #include "net.h" #include "txdb.h" #include "txmempool.h" @@ -1133,7 +1134,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) } // Check the header - if (!CheckProofOfWork(block.GetPoWHash(), block.nBits)) + if (!block.CheckProofOfWork(mapBlockIndex[block.GetHash()]->nHeight)) return error("ReadBlockFromDisk : Errors in block header"); return true; @@ -1148,6 +1149,15 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex) return true; } +void CBlockHeader::SetAuxPow(CAuxPow* pow) +{ + if (pow != NULL) + nVersion |= BLOCK_VERSION_AUXPOW; + else + nVersion &= ~BLOCK_VERSION_AUXPOW; + auxpow.reset(pow); +} + uint256 static GetOrphanRoot(const uint256& hash) { map<uint256, COrphanBlock*>::iterator it = mapOrphanBlocks.find(hash); @@ -1543,7 +1553,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state } if (!state.CorruptionPossible()) { pindex->nStatus |= BLOCK_FAILED_VALID; - pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex)); + pblocktree->WriteBlockIndex(*pindex); setBlockIndexValid.erase(pindex); InvalidChainFound(pindex); } @@ -1840,7 +1850,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C { AssertLockHeld(cs_main); // Check it again in case a previous version let a bad block in - if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) + if (!CheckBlock(block, state, pindex->nHeight, !fJustCheck, !fJustCheck)) return false; // verify that the view's current state corresponds to the previous block @@ -1985,8 +1995,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); - CDiskBlockIndex blockindex(pindex); - if (!pblocktree->WriteBlockIndex(blockindex)) + if (!pblocktree->WriteBlockIndex(*pindex)) return state.Abort(_("Failed to write block index")); } @@ -2312,7 +2321,8 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl if (pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS)) setBlockIndexValid.insert(pindexNew); - if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew))) + /* write both the immutible data (CDiskBlockIndex) and the mutable data (BlockIndex) */ + if (!pblocktree->WriteDiskBlockIndex(CDiskBlockIndex(pindexNew, block.auxpow)) || !pblocktree->WriteBlockIndex(*pindexNew)) return state.Abort(_("Failed to write block index")); // New best? @@ -2338,6 +2348,58 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl return true; } +// to enable merged mining: +// - set a block from which it will be enabled +// - set a unique chain ID +// each merged minable scrypt_1024_1_1_256 coin should have a different one +// (if two have the same ID, they can't be merge mined together) +int GetAuxPowStartBlock() +{ + if (TestNet()) + return INT_MAX; // never + else + return INT_MAX; // never +} + +bool CBlockHeader::CheckProofOfWork(int nHeight) const +{ + if (nHeight >= GetAuxPowStartBlock()) + { + // Prevent same work from being submitted twice: + // - this block must have our chain ID + // - parent block must not have the same chain ID (see CAuxPow::Check) + // - index of this chain in chain merkle tree must be pre-determined (see CAuxPow::Check) + if (!TestNet() && nHeight != INT_MAX && GetChainID() != GetOurChainID()) + return error("CheckProofOfWork() : block does not have our chain ID"); + + if (auxpow.get() != NULL) + { + if (!auxpow->Check(GetHash(), GetChainID())) + return error("CheckProofOfWork() : AUX POW is not valid"); + // Check proof of work matches claimed amount + if (!::CheckProofOfWork(auxpow->GetParentBlockHash(), nBits)) + return error("CheckProofOfWork() : AUX proof of work failed"); + } + else + { + // Check proof of work matches claimed amount + if (!::CheckProofOfWork(GetPoWHash(), nBits)) + return error("CheckProofOfWork() : proof of work failed"); + } + } + else + { + if (auxpow.get() != NULL) + { + return error("CheckProofOfWork() : AUX POW is not allowed at this block"); + } + + // Check if proof of work marches claimed amount + if (!::CheckProofOfWork(GetPoWHash(), nBits)) + return error("CheckProofOfWork() : proof of work failed"); + } + return true; +} bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false) { @@ -2433,11 +2495,10 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne return true; } - -bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW) +bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, int nHeight, bool fCheckPOW) { // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetPoWHash(), block.nBits)) + if (fCheckPOW && !block.CheckProofOfWork(nHeight)) return state.DoS(50, error("CheckBlockHeader() : proof of work failed"), REJECT_INVALID, "high-hash"); @@ -2470,12 +2531,12 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f return true; } -bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) +bool CheckBlock(const CBlock& block, CValidationState& state, int nHeight, bool fCheckPOW, bool fCheckMerkleRoot) { // These are checks that are independent of context // that can be verified before saving an orphan block. - if (!CheckBlockHeader(block, state, fCheckPOW)) + if (!CheckBlockHeader(block, state, nHeight, fCheckPOW)) return false; // Size limits @@ -2602,14 +2663,15 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, if (!AcceptBlockHeader(block, state, &pindex)) return false; - if (!CheckBlock(block, state)) { + int nHeight = pindex->nHeight; + + if (!CheckBlock(block, state, nHeight)) { if (state.Invalid() && !state.CorruptionPossible()) { pindex->nStatus |= BLOCK_FAILED_VALID; } return false; } - int nHeight = pindex->nHeight; uint256 hash = pindex->GetBlockHash(); // Check that all transactions are finalized @@ -2695,6 +2757,48 @@ int64_t CBlockIndex::GetMedianTime() const return pindex->GetMedianTimePast(); } +std::string CBlockIndex::ToString() const +{ + return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)", + pprev, nHeight, + hashMerkleRoot.ToString().substr(0,10).c_str(), + GetBlockHash().ToString().c_str()); +} + +std::string CDiskBlockIndex::ToString() const +{ + std::string str = "CDiskBlockIndex("; + str += CBlockIndex::ToString(); + str += strprintf("\n hashBlock=%s, hashPrev=%s, hashParentBlock=%s)", + GetBlockHash().ToString().c_str(), + hashPrev.ToString().c_str(), + (auxpow.get() != NULL) ? auxpow->GetParentBlockHash().ToString().substr(0,20).c_str() : "-"); + return str; +} + +CBlockHeader CBlockIndex::GetBlockHeader() const +{ + CBlockHeader block; + + if (nVersion & BLOCK_VERSION_AUXPOW) { + CDiskBlockIndex diskblockindex; + // auxpow is not in memory, load CDiskBlockHeader + // from database to get it + + pblocktree->ReadDiskBlockIndex(*phashBlock, diskblockindex); + block.auxpow = diskblockindex.auxpow; + } + + block.nVersion = nVersion; + if (pprev) + block.hashPrevBlock = pprev->GetBlockHash(); + block.hashMerkleRoot = hashMerkleRoot; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block; +} + void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd) { AssertLockHeld(cs_main); @@ -2719,8 +2823,11 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString()), 0, "duplicate"); // Preliminary checks - if (!CheckBlock(*pblock, state)) + if (!CheckBlock(*pblock, state, INT_MAX)) { + if (state.CorruptionPossible()) + mapAlreadyAskedFor.erase(CInv(MSG_BLOCK, hash)); return error("ProcessBlock() : CheckBlock FAILED"); + } // If we don't already have its previous block (with full data), shunt it off to holding area until we get it std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(pblock->hashPrevBlock); @@ -3098,7 +3205,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth) 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)) + if (nCheckLevel >= 1 && !CheckBlock(block, state, pindex->nHeight)) 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) { |