mirror of
https://github.com/jwinterm/myriadcoin.git
synced 2026-10-18 05:51:27 +02:00
auxpow update
This commit is contained in:
+137
@@ -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<unsigned char>& 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<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) != 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<unsigned char>& vchAux)
|
||||
{
|
||||
vector<unsigned char> 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<unsigned char>& 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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<uint256> 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 <typename Stream>
|
||||
int ReadWriteAuxPow(Stream& s, const boost::shared_ptr<CAuxPow>& auxpow, int nType, int nVersion, CSerActionGetSerializeSize ser_action)
|
||||
{
|
||||
if (nVersion & BLOCK_VERSION_AUXPOW)
|
||||
{
|
||||
return ::GetSerializeSize(*auxpow, nType, nVersion);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
int ReadWriteAuxPow(Stream& s, const boost::shared_ptr<CAuxPow>& auxpow, int nType, int nVersion, CSerActionSerialize ser_action)
|
||||
{
|
||||
if (nVersion & BLOCK_VERSION_AUXPOW)
|
||||
{
|
||||
return SerReadWrite(s, *auxpow, nType, nVersion, ser_action);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
int ReadWriteAuxPow(Stream& s, boost::shared_ptr<CAuxPow>& 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<unsigned char>& vchAux);
|
||||
extern CScript MakeCoinbaseWithAux(unsigned int nBits, unsigned int nExtraNonce, std::vector<unsigned char>& vchAux);
|
||||
#endif
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-9
@@ -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);
|
||||
|
||||
+37
-19
@@ -69,12 +69,14 @@ bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &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
|
||||
|
||||
Reference in New Issue
Block a user