aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
authorNell Hardcastle <[email protected]>2014-04-11 00:01:49 -0700
committerPatrick Lodder <[email protected]>2014-08-01 16:42:50 +0200
commit8808f237aa8281746e4f5fe4444e0057bd4b6058 (patch)
tree0d6279b217f03dc1e43dfe7153732c4985f77199 /src/main.cpp
parentImport Vince Durham's aux proof of work implementation. (diff)
downloaddiscoin-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.cpp137
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) {