From 876f2fd9ab51580e2dc491e352f342406756d018 Mon Sep 17 00:00:00 2001 From: myriadcoin Date: Sat, 11 Jul 2015 10:20:09 +0200 Subject: [PATCH] auxpow update --- src/auxpow.cpp | 137 +++++++++++++++++++++++++++++++++++++++++++++++++ src/auxpow.h | 84 ++++++++++++++++++++++++++++++ src/main.cpp | 2 +- src/main.h | 10 +--- src/txdb.cpp | 56 +++++++++++++------- 5 files changed, 260 insertions(+), 29 deletions(-) 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 00000000..a59d6987 --- /dev/null +++ b/src/auxpow.cpp @@ -0,0 +1,137 @@ +// 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 nHeight, unsigned int nExtraNonce, vector& vchAux) +{ + vector vchAuxWithHeader(UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader)); + vchAuxWithHeader.insert(vchAuxWithHeader.end(), vchAux.begin(), vchAux.end()); + + CScript script = (CScript() << nHeight << CBigNum(nExtraNonce)) + COINBASE_FLAGS; + + // Push OP_2 just in case we want versioning later + script = script << OP_2 << vchAuxWithHeader; + + return script; +} + + +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; + + unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 + pblock->vtx[0].vin[0].scriptSig = MakeCoinbaseWithAux(nHeight, nExtraNonce, vchAux); + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); +} + + diff --git a/src/auxpow.h b/src/auxpow.h new file mode 100644 index 00000000..156bb6e7 --- /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(int algo) + { + return parentBlockHeader.GetPoWHash(algo); + } +}; + +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 diff --git a/src/main.cpp b/src/main.cpp index 1db43e93..0278fb1f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1511,7 +1511,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, int algo) bool CBlockHeader::CheckProofOfWork(int nHeight) const { int algo = GetAlgo(); - if ((nHeight >= GetAuxPowStartBlock()) && (algo == ALGO_SHA256D)) + if ((nHeight >= GetAuxPowStartBlock()) && (algo == ALGO_SHA256D && algo == ALGO_SCRYPT)) { // Prevent same work from being submitted twice: // - this block must have our chain ID diff --git a/src/main.h b/src/main.h index c2852b17..ae5bef7b 100644 --- a/src/main.h +++ b/src/main.h @@ -815,8 +815,6 @@ public: IMPLEMENT_SERIALIZE ( - /* mutable stuff goes here, immutable stuff - * has SERIALIZE functions in CDiskBlockIndex */ if (!(nType & SER_GETHASH)) READWRITE(VARINT(nVersion)); @@ -1056,6 +1054,7 @@ public: CDiskBlockIndex() { hashPrev = 0; + auxpow.reset(); } //CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) { @@ -1072,14 +1071,7 @@ public: READWRITE(VARINT(nVersion)); READWRITE(VARINT(nHeight)); - READWRITE(VARINT(nStatus)); READWRITE(VARINT(nTx)); - if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO)) - READWRITE(VARINT(nFile)); - if (nStatus & BLOCK_HAVE_DATA) - READWRITE(VARINT(nDataPos)); - if (nStatus & BLOCK_HAVE_UNDO) - READWRITE(VARINT(nUndoPos)); // block header READWRITE(this->nVersion); diff --git a/src/txdb.cpp b/src/txdb.cpp index f25e9cec..b155b3ad 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -69,12 +69,14 @@ bool CCoinsViewDB::BatchWrite(const std::map &mapCoins, const u CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) { } -/* -bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) +// bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) +// { + // return Write(make_pair('b', blockindex.GetBlockHash()), blockindex); +// } +bool CBlockTreeDB::WriteDiskBlockIndex(const CDiskBlockIndex& diskblockindex) { - return Write(make_pair('b', blockindex.GetBlockHash()), blockindex); + return Write(boost::tuples::make_tuple('b', *diskblockindex.phashBlock, 'a'), diskblockindex); } -*/ bool CBlockTreeDB::WriteBlockIndex(const CBlockIndex& blockindex) { @@ -86,11 +88,6 @@ bool CBlockTreeDB::ReadDiskBlockIndex(const uint256 &blkid, CDiskBlockIndex &dis return Read(boost::tuples::make_tuple('b', blkid, 'a'), diskblockindex); } -bool CBlockTreeDB::WriteDiskBlockIndex(const CDiskBlockIndex& diskblockindex) -{ - return Write(boost::tuples::make_tuple('b', *diskblockindex.phashBlock, 'a'), diskblockindex); -} - bool CBlockTreeDB::WriteBestInvalidWork(const CBigNum& bnBestInvalidWork) { // Obsolete; only written for backward compatibility. @@ -204,7 +201,9 @@ bool CBlockTreeDB::LoadBlockIndexGuts() leveldb::Iterator *pcursor = NewIterator(); CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); - ssKeySet << make_pair('b', uint256(0)); + // ssKeySet << make_pair('b', uint256(0)); + uint256 hash; + ssKeySet << boost::tuples::make_tuple('b', uint256(0), 'a'); // 'b' is the prefix for BlockIndex, 'a' sigifies the first part pcursor->Seek(ssKeySet.str()); // Load mapBlockIndex @@ -216,29 +215,48 @@ bool CBlockTreeDB::LoadBlockIndexGuts() char chType; ssKey >> chType; if (chType == 'b') { + ssKey >> hash; + leveldb::Slice slValue = pcursor->value(); - CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION); + // CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION); + CDataStream ssValue_immutable(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION); CDiskBlockIndex diskindex; - ssValue >> diskindex; + // ssValue >> diskindex; + ssValue_immutable >> diskindex; // read all immutable data + + // Construct immutable parts of block index objecty + CBlockIndex* pindexNew = InsertBlockIndex(hash); + assert(diskindex.GetBlockHash() == *pindexNew->phashBlock); // paranoia check - // Construct block index object - CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); + // // Construct block index object + // CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); pindexNew->nHeight = diskindex.nHeight; - pindexNew->nFile = diskindex.nFile; - pindexNew->nDataPos = diskindex.nDataPos; - pindexNew->nUndoPos = diskindex.nUndoPos; + // pindexNew->nFile = diskindex.nFile; + // pindexNew->nDataPos = diskindex.nDataPos; + // pindexNew->nUndoPos = diskindex.nUndoPos; pindexNew->nVersion = diskindex.nVersion; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->nTime = diskindex.nTime; pindexNew->nBits = diskindex.nBits; pindexNew->nNonce = diskindex.nNonce; - pindexNew->nStatus = diskindex.nStatus; + // pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; - if (!pindexNew->CheckIndex()) + // if (!pindexNew->CheckIndex()) + // CheckIndex need phashBlock to be set + diskindex.phashBlock = pindexNew->phashBlock; + if (!diskindex.CheckIndex()) return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString()); + pcursor->Next(); // now we should be on the 'b' subkey + + assert(pcursor->Valid()); + + slValue = pcursor->value(); + CDataStream ssValue_mutable(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION); + ssValue_mutable >> *pindexNew; // read all mutable data + pcursor->Next(); } else { break; // if shutdown requested or finished loading block index