From e87673bd387dc1d3994d14fc83d428d5ad9a8acb Mon Sep 17 00:00:00 2001 From: Nell Hardcastle Date: Tue, 8 Apr 2014 17:54:56 -0700 Subject: [PATCH] Import Vince Durham's aux proof of work implementation. --- src/auxpow.cpp | 132 +++++++++++++++++++++++++++++++++++++++++++++++++ src/auxpow.h | 84 +++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 src/auxpow.cpp create mode 100644 src/auxpow.h diff --git a/src/auxpow.cpp b/src/auxpow.cpp new file mode 100644 index 000000000..4994b9a02 --- /dev/null +++ b/src/auxpow.cpp @@ -0,0 +1,132 @@ +// Copyright (c) 2011 Vince Durham +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. +#include "script.h" +#include "auxpow.h" +#include "init.h" + +using namespace std; +using namespace boost; + +unsigned char pchMergedMiningHeader[] = { 0xfa, 0xbe, 'm', 'm' } ; + +void RemoveMergedMiningHeader(vector& vchAux) +{ + if (vchAux.begin() != std::search(vchAux.begin(), vchAux.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader))) + throw runtime_error("merged mining aux too short"); + vchAux.erase(vchAux.begin(), vchAux.begin() + sizeof(pchMergedMiningHeader)); +} + +bool CAuxPow::Check(uint256 hashAuxBlock, int nChainID) +{ + if (nIndex != 0) + return error("AuxPow is not a generate"); + + if (!TestNet() && parentBlockHeader.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 + uint256 nRootHash = CBlock::CheckMerkleBranch(hashAuxBlock, vChainMerkleBranch, nChainIndex); + vector 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) != parentBlockHeader.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 (pcHead == script.end()) + return error("MergedMiningHeader missing from parent coinbase"); + + 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); + if (nSize != (1 << vChainMerkleBranch.size())) + return error("Aux POW merkle branch size does not match parent coinbase"); + + int nNonce; + memcpy(&nNonce, &pc[4], 4); + + // 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 int rand = nNonce; + rand = rand * 1103515245 + 12345; + rand += nChainID; + rand = rand * 1103515245 + 12345; + + if (nChainIndex != (rand % nSize)) + return error("Aux POW wrong index"); + + return true; +} + +CScript MakeCoinbaseWithAux(unsigned int nBits, unsigned int nExtraNonce, vector& vchAux) +{ + vector vchAuxWithHeader(UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader)); + vchAuxWithHeader.insert(vchAuxWithHeader.end(), vchAux.begin(), vchAux.end()); + + // Push OP_2 just in case we want versioning later + return CScript() << nBits << nExtraNonce << OP_2 << vchAuxWithHeader; +} + + +void IncrementExtraNonceWithAux(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, vector& vchAux) +{ + // Update nExtraNonce + static uint256 hashPrevBlock; + if (hashPrevBlock != pblock->hashPrevBlock) + { + nExtraNonce = 0; + hashPrevBlock = pblock->hashPrevBlock; + } + ++nExtraNonce; + + pblock->vtx[0].vin[0].scriptSig = MakeCoinbaseWithAux(pblock->nBits, nExtraNonce, vchAux); + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); +} + + diff --git a/src/auxpow.h b/src/auxpow.h new file mode 100644 index 000000000..aec5cd4de --- /dev/null +++ b/src/auxpow.h @@ -0,0 +1,84 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_AUXPOW_H +#define BITCOIN_AUXPOW_H + +#include "main.h" + +class CAuxPow : public CMerkleTx +{ +public: + CAuxPow(const CTransaction& txIn) : CMerkleTx(txIn) + { + } + + CAuxPow() :CMerkleTx() + { + } + + // Merkle branch with root vchAux + // root must be present inside the coinbase + std::vector vChainMerkleBranch; + // Index of chain in chains merkle tree + unsigned int nChainIndex; + CBlockHeader parentBlockHeader; + + IMPLEMENT_SERIALIZE + ( + nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion, ser_action); + nVersion = this->nVersion; + READWRITE(vChainMerkleBranch); + READWRITE(nChainIndex); + + // Always serialize the saved parent block as header so that the size of CAuxPow + // is consistent. + nSerSize += SerReadWrite(s, parentBlockHeader, nType, nVersion, ser_action); + ) + + bool Check(uint256 hashAuxBlock, int nChainID); + + uint256 GetParentBlockHash() + { + return parentBlockHeader.GetPoWHash(); + } +}; + +template +int ReadWriteAuxPow(Stream& s, const boost::shared_ptr& auxpow, int nType, int nVersion, CSerActionGetSerializeSize ser_action) +{ + if (nVersion & BLOCK_VERSION_AUXPOW) + { + return ::GetSerializeSize(*auxpow, nType, nVersion); + } + return 0; +} + +template +int ReadWriteAuxPow(Stream& s, const boost::shared_ptr& auxpow, int nType, int nVersion, CSerActionSerialize ser_action) +{ + if (nVersion & BLOCK_VERSION_AUXPOW) + { + return SerReadWrite(s, *auxpow, nType, nVersion, ser_action); + } + return 0; +} + +template +int ReadWriteAuxPow(Stream& s, boost::shared_ptr& auxpow, int nType, int nVersion, CSerActionUnserialize ser_action) +{ + if (nVersion & BLOCK_VERSION_AUXPOW) + { + auxpow.reset(new CAuxPow()); + return SerReadWrite(s, *auxpow, nType, nVersion, ser_action); + } + else + { + auxpow.reset(); + return 0; + } +} + +extern void RemoveMergedMiningHeader(std::vector& vchAux); +extern CScript MakeCoinbaseWithAux(unsigned int nBits, unsigned int nExtraNonce, std::vector& vchAux); +#endif