aboutsummaryrefslogtreecommitdiff
path: root/src/auxpow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/auxpow.cpp')
-rw-r--r--src/auxpow.cpp192
1 files changed, 192 insertions, 0 deletions
diff --git a/src/auxpow.cpp b/src/auxpow.cpp
new file mode 100644
index 000000000..3c350a67a
--- /dev/null
+++ b/src/auxpow.cpp
@@ -0,0 +1,192 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2011 Vince Durham
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Copyright (c) 2014-2015 Daniel Kraft
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+
+#include "auxpow.h"
+
+#include "consensus/validation.h"
+#include "main.h"
+#include "script/script.h"
+#include "util.h"
+
+#include <algorithm>
+
+/* Moved from wallet.cpp. CMerkleTx is necessary for auxpow, independent
+ of an enabled (or disabled) wallet. Always include the code. */
+
+int CMerkleTx::SetMerkleBranch(const CBlock& block)
+{
+ AssertLockHeld(cs_main);
+ CBlock blockTmp;
+
+ // Update the tx's hashBlock
+ hashBlock = block.GetHash();
+
+ // Locate the transaction
+ for (nIndex = 0; nIndex < (int)block.vtx.size(); nIndex++)
+ if (block.vtx[nIndex] == *(CTransaction*)this)
+ break;
+ if (nIndex == (int)block.vtx.size()) {
+ vMerkleBranch.clear();
+ nIndex = -1;
+ LogPrintf("ERROR: SetMerkleBranch(): couldn't find tx in block\n");
+ return 0;
+ }
+
+ // Fill in merkle branch
+ vMerkleBranch = block.GetMerkleBranch(nIndex);
+
+ // Is the tx in a block that's in the main chain
+ BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
+ if (mi == mapBlockIndex.end())
+ return 0;
+ const CBlockIndex* pindex = (*mi).second;
+ if (!pindex || !chainActive.Contains(pindex))
+ return 0;
+
+ return chainActive.Height() - pindex->nHeight + 1;
+}
+
+int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex*& pindexRet) const
+{
+ if (hashBlock.IsNull() || nIndex == -1)
+ return 0;
+ AssertLockHeld(cs_main);
+
+ // Find the block it claims to be in
+ BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
+ if (mi == mapBlockIndex.end())
+ return 0;
+ CBlockIndex* pindex = (*mi).second;
+ if (!pindex || !chainActive.Contains(pindex))
+ return 0;
+
+ // Make sure the merkle branch connects to this block
+ if (!fMerkleVerified) {
+ if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
+ return 0;
+ fMerkleVerified = true;
+ }
+
+ pindexRet = pindex;
+ return chainActive.Height() - pindex->nHeight + 1;
+}
+
+int CMerkleTx::GetDepthInMainChain(const CBlockIndex*& pindexRet) const
+{
+ AssertLockHeld(cs_main);
+ int nResult = GetDepthInMainChainINTERNAL(pindexRet);
+ if (nResult == 0 && !mempool.exists(GetHash()))
+ return -1; // Not in chain, not in mempool
+
+ return nResult;
+}
+
+int CMerkleTx::GetBlocksToMaturity() const
+{
+ if (!IsCoinBase())
+ return 0;
+ return std::max(0, (COINBASE_MATURITY + 1) - GetDepthInMainChain());
+}
+
+
+bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
+{
+ CValidationState state;
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee);
+}
+
+/* ************************************************************************** */
+
+bool
+CAuxPow::check(const uint256& hashAuxBlock, int nChainId, const Consensus::Params& params) const
+{
+ if (nIndex != 0)
+ return error("AuxPow is not a generate");
+
+ if (params.fStrictChainId && parentBlock.nVersion.GetChainId() == nChainId)
+ return error("Aux POW parent has our chain ID");
+
+ if (vChainMerkleBranch.size() > 30)
+ return error("Aux POW chain merkle branch too long");
+
+ // Check that the chain merkle root is in the coinbase
+ const uint256 nRootHash = CBlock::CheckMerkleBranch(hashAuxBlock, vChainMerkleBranch, nChainIndex);
+ std::vector<unsigned char> vchRootHash(nRootHash.begin(), nRootHash.end());
+ std::reverse(vchRootHash.begin(), vchRootHash.end()); // correct endian
+
+ // Check that we are in the parent block merkle tree
+ if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != parentBlock.hashMerkleRoot)
+ return error("Aux POW merkle root incorrect");
+
+ const CScript script = vin[0].scriptSig;
+
+ // Check that the same work is not submitted twice to our chain.
+ //
+
+ CScript::const_iterator pcHead =
+ std::search(script.begin(), script.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader));
+
+ CScript::const_iterator pc =
+ std::search(script.begin(), script.end(), vchRootHash.begin(), vchRootHash.end());
+
+ if (pc == script.end())
+ return error("Aux POW missing chain merkle root in parent coinbase");
+
+ if (pcHead != script.end()) {
+ // Enforce only one chain merkle root by checking that a single instance of the merged
+ // mining header exists just before.
+ if (script.end() != std::search(pcHead + 1, script.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader)))
+ return error("Multiple merged mining headers in coinbase");
+ if (pcHead + sizeof(pchMergedMiningHeader) != pc)
+ return error("Merged mining header is not just before chain merkle root");
+ } else {
+ // For backward compatibility.
+ // Enforce only one chain merkle root by checking that it starts early in the coinbase.
+ // 8-12 bytes are enough to encode extraNonce and nBits.
+ if (pc - script.begin() > 20)
+ return error("Aux POW chain merkle root must start in the first 20 bytes of the parent coinbase");
+ }
+
+
+ // Ensure we are at a deterministic point in the merkle leaves by hashing
+ // a nonce and our chain ID and comparing to the index.
+ pc += vchRootHash.size();
+ if (script.end() - pc < 8)
+ return error("Aux POW missing chain merkle tree size and nonce in parent coinbase");
+
+ int nSize;
+ memcpy(&nSize, &pc[0], 4);
+ const unsigned merkleHeight = vChainMerkleBranch.size();
+ if (nSize != (1 << merkleHeight))
+ return error("Aux POW merkle branch size does not match parent coinbase");
+
+ int nNonce;
+ memcpy(&nNonce, &pc[4], 4);
+
+ if (nChainIndex != getExpectedIndex(nNonce, nChainId, merkleHeight))
+ return error("Aux POW wrong index");
+
+ return true;
+}
+
+int
+CAuxPow::getExpectedIndex(int nNonce, int nChainId, unsigned h)
+{
+ // Choose a pseudo-random slot in the chain merkle tree
+ // but have it be fixed for a size/nonce/chain combination.
+ //
+ // This prevents the same work from being used twice for the
+ // same chain while reducing the chance that two chains clash
+ // for the same slot.
+
+ unsigned rand = nNonce;
+ rand = rand * 1103515245 + 12345;
+ rand += nChainId;
+ rand = rand * 1103515245 + 12345;
+
+ return rand % (1 << h);
+}