196 lines
6.6 KiB
C++
196 lines
6.6 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2011 Vince Durham
|
|
// Copyright (c) 2009-2014 The Bitcoin developers
|
|
// Copyright (c) 2014-2015 Daniel Kraft
|
|
// Copyright (c) 2014-2015 The Dogecoin Core developers
|
|
// 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 "chainparams.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;
|
|
int nCoinbaseMaturity = Params().GetConsensus(chainActive.Height()).nCoinbaseMaturity;
|
|
return std::max(0, (nCoinbaseMaturity + 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);
|
|
}
|