Merge pull request #584 from patricklodder/1.8-dev-auxpow
Enable auxpow for Dogecoin
This commit is contained in:
commit
98b93577d2
|
@ -29,6 +29,7 @@ DIST_SUBDIRS = . qt test
|
|||
BITCOIN_CORE_H = \
|
||||
addrman.h \
|
||||
alert.h \
|
||||
auxpow.h \
|
||||
allocators.h \
|
||||
base58.h bignum.h \
|
||||
bloom.h \
|
||||
|
@ -93,6 +94,7 @@ version.o: obj/build.h
|
|||
libbitcoin_server_a_SOURCES = \
|
||||
addrman.cpp \
|
||||
alert.cpp \
|
||||
auxpow.cpp \
|
||||
bloom.cpp \
|
||||
checkpoints.cpp \
|
||||
coins.cpp \
|
||||
|
|
132
src/auxpow.cpp
Normal file
132
src/auxpow.cpp
Normal file
|
@ -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<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 nBits, unsigned int nExtraNonce, vector<unsigned char>& vchAux)
|
||||
{
|
||||
vector<unsigned char> 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<unsigned char>& 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();
|
||||
}
|
||||
|
||||
|
84
src/auxpow.h
Normal file
84
src/auxpow.h
Normal file
|
@ -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()
|
||||
{
|
||||
return parentBlockHeader.GetPoWHash();
|
||||
}
|
||||
};
|
||||
|
||||
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
|
|
@ -4,6 +4,7 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "core.h"
|
||||
#include "auxpow.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
|
35
src/core.h
35
src/core.h
|
@ -17,6 +17,27 @@
|
|||
#include <stdint.h>
|
||||
|
||||
class CTransaction;
|
||||
class CAuxPow;
|
||||
|
||||
template <typename Stream>
|
||||
int ReadWriteAuxPow(Stream& s, const boost::shared_ptr<CAuxPow>& auxpow, int nType, int nVersion, CSerActionSerialize ser_action);
|
||||
|
||||
template <typename Stream>
|
||||
int ReadWriteAuxPow(Stream& s, boost::shared_ptr<CAuxPow>& auxpow, int nType, int nVersion, CSerActionUnserialize ser_action);
|
||||
|
||||
template <typename Stream>
|
||||
int ReadWriteAuxPow(Stream& s, const boost::shared_ptr<CAuxPow>& auxpow, int nType, int nVersion, CSerActionGetSerializeSize ser_action);
|
||||
|
||||
// primary version
|
||||
static const int BLOCK_VERSION_DEFAULT = (1 << 0);
|
||||
static const int BLOCK_VERSION_AUXPOW = (1 << 8);
|
||||
static const int BLOCK_VERSION_CHAIN_START = (1 << 16);
|
||||
static const int BLOCK_VERSION_CHAIN_END = (1 << 30);
|
||||
|
||||
// DogeCoin aux chain ID = 0x0062 (98)
|
||||
static const int AUXPOW_CHAIN_ID = 0x0062;
|
||||
static const int AUXPOW_START_MAINNET = INT_MAX; //TODO change me
|
||||
static const int AUXPOW_START_TESTNET = 158100;
|
||||
|
||||
/** No amount larger than this (in satoshi) is valid */
|
||||
static const int64_t MAX_MONEY = 10000000000 * COIN; // Dogecoin: maximum of 100B coins (given some randomness), max transaction 10,000,000,000
|
||||
|
@ -350,6 +371,7 @@ public:
|
|||
unsigned int nTime;
|
||||
unsigned int nBits;
|
||||
unsigned int nNonce;
|
||||
boost::shared_ptr<CAuxPow> auxpow;
|
||||
|
||||
CBlockHeader()
|
||||
{
|
||||
|
@ -365,11 +387,20 @@ public:
|
|||
READWRITE(nTime);
|
||||
READWRITE(nBits);
|
||||
READWRITE(nNonce);
|
||||
|
||||
nSerSize += ReadWriteAuxPow(s, auxpow, nType, nVersion, ser_action);
|
||||
)
|
||||
|
||||
int GetChainID() const
|
||||
{
|
||||
return nVersion / BLOCK_VERSION_CHAIN_START;
|
||||
}
|
||||
|
||||
void SetAuxPow(CAuxPow* pow);
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
nVersion = CBlockHeader::CURRENT_VERSION;
|
||||
nVersion = CBlockHeader::CURRENT_VERSION | (AUXPOW_CHAIN_ID * BLOCK_VERSION_CHAIN_START);
|
||||
hashPrevBlock = 0;
|
||||
hashMerkleRoot = 0;
|
||||
nTime = 0;
|
||||
|
@ -395,6 +426,8 @@ public:
|
|||
{
|
||||
return (int64_t)nTime;
|
||||
}
|
||||
|
||||
bool CheckProofOfWork(int nHeight) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
139
src/main.cpp
139
src/main.cpp
|
@ -14,6 +14,7 @@
|
|||
#include "checkpoints.h"
|
||||
#include "checkqueue.h"
|
||||
#include "init.h"
|
||||
#include "auxpow.h"
|
||||
#include "net.h"
|
||||
#include "txdb.h"
|
||||
#include "txmempool.h"
|
||||
|
@ -1133,7 +1134,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
|
|||
}
|
||||
|
||||
// Check the header
|
||||
if (!CheckProofOfWork(block.GetPoWHash(), block.nBits))
|
||||
if (!block.CheckProofOfWork(mapBlockIndex[block.GetHash()]->nHeight))
|
||||
return error("ReadBlockFromDisk : Errors in block header");
|
||||
|
||||
return true;
|
||||
|
@ -1148,6 +1149,15 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
|
|||
return true;
|
||||
}
|
||||
|
||||
void CBlockHeader::SetAuxPow(CAuxPow* pow)
|
||||
{
|
||||
if (pow != NULL)
|
||||
nVersion |= BLOCK_VERSION_AUXPOW;
|
||||
else
|
||||
nVersion &= ~BLOCK_VERSION_AUXPOW;
|
||||
auxpow.reset(pow);
|
||||
}
|
||||
|
||||
uint256 static GetOrphanRoot(const uint256& hash)
|
||||
{
|
||||
map<uint256, COrphanBlock*>::iterator it = mapOrphanBlocks.find(hash);
|
||||
|
@ -1543,7 +1553,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
|
|||
}
|
||||
if (!state.CorruptionPossible()) {
|
||||
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||
pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex));
|
||||
pblocktree->WriteBlockIndex(*pindex);
|
||||
setBlockIndexValid.erase(pindex);
|
||||
InvalidChainFound(pindex);
|
||||
}
|
||||
|
@ -1840,7 +1850,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
|||
{
|
||||
AssertLockHeld(cs_main);
|
||||
// Check it again in case a previous version let a bad block in
|
||||
if (!CheckBlock(block, state, !fJustCheck, !fJustCheck))
|
||||
if (!CheckBlock(block, state, pindex->nHeight, !fJustCheck, !fJustCheck))
|
||||
return false;
|
||||
|
||||
// verify that the view's current state corresponds to the previous block
|
||||
|
@ -1985,8 +1995,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
|||
|
||||
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);
|
||||
|
||||
CDiskBlockIndex blockindex(pindex);
|
||||
if (!pblocktree->WriteBlockIndex(blockindex))
|
||||
if (!pblocktree->WriteBlockIndex(*pindex))
|
||||
return state.Abort(_("Failed to write block index"));
|
||||
}
|
||||
|
||||
|
@ -2050,7 +2059,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
|
|||
const CBlockIndex* pindex = chainActive.Tip();
|
||||
for (int i = 0; i < 100 && pindex != NULL; i++)
|
||||
{
|
||||
if (pindex->nVersion > CBlock::CURRENT_VERSION)
|
||||
if (pindex->nVersion > CBlock::CURRENT_VERSION && pindex->nVersion != BLOCK_VERSION_AUXPOW)
|
||||
++nUpgraded;
|
||||
pindex = pindex->pprev;
|
||||
}
|
||||
|
@ -2312,7 +2321,8 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
|
|||
if (pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS))
|
||||
setBlockIndexValid.insert(pindexNew);
|
||||
|
||||
if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew)))
|
||||
/* write both the immutible data (CDiskBlockIndex) and the mutable data (BlockIndex) */
|
||||
if (!pblocktree->WriteDiskBlockIndex(CDiskBlockIndex(pindexNew, block.auxpow)) || !pblocktree->WriteBlockIndex(*pindexNew))
|
||||
return state.Abort(_("Failed to write block index"));
|
||||
|
||||
// New best?
|
||||
|
@ -2338,6 +2348,58 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
|
|||
return true;
|
||||
}
|
||||
|
||||
// to enable merged mining:
|
||||
// - set a block from which it will be enabled
|
||||
// - set a unique chain ID
|
||||
// each merged minable scrypt_1024_1_1_256 coin should have a different one
|
||||
// (if two have the same ID, they can't be merge mined together)
|
||||
int GetAuxPowStartBlock()
|
||||
{
|
||||
if (TestNet())
|
||||
return AUXPOW_START_TESTNET;
|
||||
else
|
||||
return AUXPOW_START_MAINNET;
|
||||
}
|
||||
|
||||
bool CBlockHeader::CheckProofOfWork(int nHeight) const
|
||||
{
|
||||
if (nHeight >= GetAuxPowStartBlock())
|
||||
{
|
||||
// Prevent same work from being submitted twice:
|
||||
// - this block must have our chain ID
|
||||
// - parent block must not have the same chain ID (see CAuxPow::Check)
|
||||
// - index of this chain in chain merkle tree must be pre-determined (see CAuxPow::Check)
|
||||
if (!TestNet() && nHeight != INT_MAX && GetChainID() != AUXPOW_CHAIN_ID)
|
||||
return error("CheckProofOfWork() : block does not have our chain ID");
|
||||
|
||||
if (auxpow.get() != NULL)
|
||||
{
|
||||
if (!auxpow->Check(GetHash(), GetChainID()))
|
||||
return error("CheckProofOfWork() : AUX POW is not valid");
|
||||
// Check proof of work matches claimed amount
|
||||
if (!::CheckProofOfWork(auxpow->GetParentBlockHash(), nBits))
|
||||
return error("CheckProofOfWork() : AUX proof of work failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check proof of work matches claimed amount
|
||||
if (!::CheckProofOfWork(GetPoWHash(), nBits))
|
||||
return error("CheckProofOfWork() : proof of work failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auxpow.get() != NULL)
|
||||
{
|
||||
return error("CheckProofOfWork() : AUX POW is not allowed at this block");
|
||||
}
|
||||
|
||||
// Check if proof of work marches claimed amount
|
||||
if (!::CheckProofOfWork(GetPoWHash(), nBits))
|
||||
return error("CheckProofOfWork() : proof of work failed");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)
|
||||
{
|
||||
|
@ -2433,11 +2495,10 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW)
|
||||
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, int nHeight, bool fCheckPOW)
|
||||
{
|
||||
// Check proof of work matches claimed amount
|
||||
if (fCheckPOW && !CheckProofOfWork(block.GetPoWHash(), block.nBits))
|
||||
if (fCheckPOW && !block.CheckProofOfWork(nHeight))
|
||||
return state.DoS(50, error("CheckBlockHeader() : proof of work failed"),
|
||||
REJECT_INVALID, "high-hash");
|
||||
|
||||
|
@ -2470,12 +2531,12 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot)
|
||||
bool CheckBlock(const CBlock& block, CValidationState& state, int nHeight, bool fCheckPOW, bool fCheckMerkleRoot)
|
||||
{
|
||||
// These are checks that are independent of context
|
||||
// that can be verified before saving an orphan block.
|
||||
|
||||
if (!CheckBlockHeader(block, state, fCheckPOW))
|
||||
if (!CheckBlockHeader(block, state, nHeight, fCheckPOW))
|
||||
return false;
|
||||
|
||||
// Size limits
|
||||
|
@ -2602,14 +2663,15 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
|
|||
if (!AcceptBlockHeader(block, state, &pindex))
|
||||
return false;
|
||||
|
||||
if (!CheckBlock(block, state)) {
|
||||
int nHeight = pindex->nHeight;
|
||||
|
||||
if (!CheckBlock(block, state, nHeight)) {
|
||||
if (state.Invalid() && !state.CorruptionPossible()) {
|
||||
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int nHeight = pindex->nHeight;
|
||||
uint256 hash = pindex->GetBlockHash();
|
||||
|
||||
// Check that all transactions are finalized
|
||||
|
@ -2695,6 +2757,48 @@ int64_t CBlockIndex::GetMedianTime() const
|
|||
return pindex->GetMedianTimePast();
|
||||
}
|
||||
|
||||
std::string CBlockIndex::ToString() const
|
||||
{
|
||||
return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
|
||||
pprev, nHeight,
|
||||
hashMerkleRoot.ToString().substr(0,10).c_str(),
|
||||
GetBlockHash().ToString().c_str());
|
||||
}
|
||||
|
||||
std::string CDiskBlockIndex::ToString() const
|
||||
{
|
||||
std::string str = "CDiskBlockIndex(";
|
||||
str += CBlockIndex::ToString();
|
||||
str += strprintf("\n hashBlock=%s, hashPrev=%s, hashParentBlock=%s)",
|
||||
GetBlockHash().ToString().c_str(),
|
||||
hashPrev.ToString().c_str(),
|
||||
(auxpow.get() != NULL) ? auxpow->GetParentBlockHash().ToString().substr(0,20).c_str() : "-");
|
||||
return str;
|
||||
}
|
||||
|
||||
CBlockHeader CBlockIndex::GetBlockHeader() const
|
||||
{
|
||||
CBlockHeader block;
|
||||
|
||||
if (nVersion & BLOCK_VERSION_AUXPOW) {
|
||||
CDiskBlockIndex diskblockindex;
|
||||
// auxpow is not in memory, load CDiskBlockHeader
|
||||
// from database to get it
|
||||
|
||||
pblocktree->ReadDiskBlockIndex(*phashBlock, diskblockindex);
|
||||
block.auxpow = diskblockindex.auxpow;
|
||||
}
|
||||
|
||||
block.nVersion = nVersion;
|
||||
if (pprev)
|
||||
block.hashPrevBlock = pprev->GetBlockHash();
|
||||
block.hashMerkleRoot = hashMerkleRoot;
|
||||
block.nTime = nTime;
|
||||
block.nBits = nBits;
|
||||
block.nNonce = nNonce;
|
||||
return block;
|
||||
}
|
||||
|
||||
void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
@ -2719,8 +2823,11 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
|||
return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString()), 0, "duplicate");
|
||||
|
||||
// Preliminary checks
|
||||
if (!CheckBlock(*pblock, state))
|
||||
if (!CheckBlock(*pblock, state, INT_MAX)) {
|
||||
if (state.CorruptionPossible())
|
||||
mapAlreadyAskedFor.erase(CInv(MSG_BLOCK, hash));
|
||||
return error("ProcessBlock() : CheckBlock FAILED");
|
||||
}
|
||||
|
||||
// If we don't already have its previous block (with full data), shunt it off to holding area until we get it
|
||||
std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(pblock->hashPrevBlock);
|
||||
|
@ -3098,7 +3205,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
|
|||
if (!ReadBlockFromDisk(block, pindex))
|
||||
return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
|
||||
// check level 1: verify block validity
|
||||
if (nCheckLevel >= 1 && !CheckBlock(block, state))
|
||||
if (nCheckLevel >= 1 && !CheckBlock(block, state, pindex->nHeight))
|
||||
return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
|
||||
// check level 2: verify undo validity
|
||||
if (nCheckLevel >= 2 && pindex) {
|
||||
|
|
70
src/main.h
70
src/main.h
|
@ -622,8 +622,8 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
|||
bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos);
|
||||
|
||||
// Context-independent validity checks
|
||||
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
|
||||
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, int nHeight, bool fCheckPOW = true);
|
||||
bool CheckBlock(const CBlock& block, CValidationState& state, int nHeight, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||
|
||||
// Store block on disk
|
||||
// if dbp is provided, the file is known to already reside on disk
|
||||
|
@ -794,6 +794,22 @@ public:
|
|||
nNonce = block.nNonce;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
/* mutable stuff goes here, immutable stuff
|
||||
* has SERIALIZE functions in CDiskBlockIndex */
|
||||
if (!(nType & SER_GETHASH))
|
||||
READWRITE(VARINT(nVersion));
|
||||
|
||||
READWRITE(VARINT(nStatus));
|
||||
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));
|
||||
)
|
||||
|
||||
CDiskBlockPos GetBlockPos() const {
|
||||
CDiskBlockPos ret;
|
||||
if (nStatus & BLOCK_HAVE_DATA) {
|
||||
|
@ -812,18 +828,7 @@ public:
|
|||
return ret;
|
||||
}
|
||||
|
||||
CBlockHeader GetBlockHeader() const
|
||||
{
|
||||
CBlockHeader block;
|
||||
block.nVersion = nVersion;
|
||||
if (pprev)
|
||||
block.hashPrevBlock = pprev->GetBlockHash();
|
||||
block.hashMerkleRoot = hashMerkleRoot;
|
||||
block.nTime = nTime;
|
||||
block.nBits = nBits;
|
||||
block.nNonce = nNonce;
|
||||
return block;
|
||||
}
|
||||
CBlockHeader GetBlockHeader() const;
|
||||
|
||||
uint256 GetBlockHash() const
|
||||
{
|
||||
|
@ -876,13 +881,7 @@ public:
|
|||
static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart,
|
||||
unsigned int nRequired, unsigned int nToCheck);
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
|
||||
pprev, nHeight,
|
||||
hashMerkleRoot.ToString().c_str(),
|
||||
GetBlockHash().ToString().c_str());
|
||||
}
|
||||
std::string ToString() const; //moved code to main.cpp because new method required access to auxpow
|
||||
|
||||
void print() const
|
||||
{
|
||||
|
@ -921,28 +920,28 @@ class CDiskBlockIndex : public CBlockIndex
|
|||
public:
|
||||
uint256 hashPrev;
|
||||
|
||||
// if this is an aux work block
|
||||
boost::shared_ptr<CAuxPow> auxpow;
|
||||
|
||||
CDiskBlockIndex() {
|
||||
hashPrev = 0;
|
||||
auxpow.reset();
|
||||
}
|
||||
|
||||
explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) {
|
||||
explicit CDiskBlockIndex(CBlockIndex* pindex, boost::shared_ptr<CAuxPow> auxpow) : CBlockIndex(*pindex) {
|
||||
hashPrev = (pprev ? pprev->GetBlockHash() : 0);
|
||||
this->auxpow = auxpow;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
/* immutable stuff goes here, mutable stuff
|
||||
* has SERIALIZE functions in CBlockIndex */
|
||||
if (!(nType & SER_GETHASH))
|
||||
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);
|
||||
|
@ -951,9 +950,10 @@ public:
|
|||
READWRITE(nTime);
|
||||
READWRITE(nBits);
|
||||
READWRITE(nNonce);
|
||||
ReadWriteAuxPow(s, auxpow, nType, this->nVersion, ser_action);
|
||||
)
|
||||
|
||||
uint256 GetBlockHash() const
|
||||
uint256 CalcBlockHash() const
|
||||
{
|
||||
CBlockHeader block;
|
||||
block.nVersion = nVersion;
|
||||
|
@ -966,15 +966,7 @@ public:
|
|||
}
|
||||
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
std::string str = "CDiskBlockIndex(";
|
||||
str += CBlockIndex::ToString();
|
||||
str += strprintf("\n hashBlock=%s, hashPrev=%s)",
|
||||
GetBlockHash().ToString().c_str(),
|
||||
hashPrev.ToString().c_str());
|
||||
return str;
|
||||
}
|
||||
std::string ToString() const; // moved code to main.cpp
|
||||
|
||||
void print() const
|
||||
{
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "main.h"
|
||||
#include "net.h"
|
||||
#include "scrypt.h"
|
||||
#include "auxpow.h"
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "wallet.h"
|
||||
#endif
|
||||
|
@ -472,12 +473,30 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
|
|||
uint256 hash = pblock->GetPoWHash();
|
||||
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
|
||||
|
||||
if (hash > hashTarget)
|
||||
return false;
|
||||
CAuxPow *auxpow = pblock->auxpow.get();
|
||||
|
||||
//// debug print
|
||||
LogPrintf("DogecoinMiner:\n");
|
||||
LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
|
||||
if (auxpow != NULL) {
|
||||
if (!auxpow->Check(pblock->GetHash(), pblock->GetChainID()))
|
||||
return error("AUX POW is not valid");
|
||||
|
||||
if (auxpow->GetParentBlockHash() > hashTarget)
|
||||
return error("AUX POW parent hash %s is not under target %s", auxpow->GetParentBlockHash().GetHex().c_str(), hashTarget.GetHex().c_str());
|
||||
|
||||
// print to log
|
||||
LogPrintf("DogecoinMiner: AUX proof-of-work found; our hash: %s ; parent hash: %s ; target: %s\n",
|
||||
hash.GetHex().c_str(),
|
||||
auxpow->GetParentBlockHash().GetHex().c_str(),
|
||||
hashTarget.GetHex().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hash > hashTarget)
|
||||
return false;
|
||||
|
||||
// print to log
|
||||
LogPrintf("DogecoinMiner: proof-of-work found; hash: %s ; target: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
|
||||
}
|
||||
|
||||
pblock->print();
|
||||
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define BITCOIN_MINER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
class CBlock;
|
||||
class CBlockIndex;
|
||||
|
@ -14,6 +15,7 @@ struct CBlockTemplate;
|
|||
class CReserveKey;
|
||||
class CScript;
|
||||
class CWallet;
|
||||
class CAuxPow;
|
||||
|
||||
/** Run the miner threads */
|
||||
void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads);
|
||||
|
@ -22,6 +24,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn);
|
|||
CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey);
|
||||
/** Modify the extranonce in a block */
|
||||
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
|
||||
void IncrementExtraNonceWithAux(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, std::vector<unsigned char>& vchAux);
|
||||
/** Do mining precalculation */
|
||||
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
|
||||
/** Check mined block */
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "main.h"
|
||||
#include "sync.h"
|
||||
#include "checkpoints.h"
|
||||
#include "auxpow.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -15,6 +16,9 @@
|
|||
using namespace json_spirit;
|
||||
using namespace std;
|
||||
|
||||
// from rpcraw.cpp
|
||||
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry);
|
||||
|
||||
void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex);
|
||||
|
||||
double GetDifficulty(const CBlockIndex* blockindex)
|
||||
|
@ -60,6 +64,38 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
|
|||
result.push_back(Pair("height", blockindex->nHeight));
|
||||
result.push_back(Pair("version", block.nVersion));
|
||||
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
|
||||
if (block.nVersion & BLOCK_VERSION_AUXPOW) {
|
||||
// this block includes auxpow
|
||||
Object auxpow;
|
||||
auxpow.push_back(Pair("size", (int)::GetSerializeSize(*block.auxpow, SER_NETWORK, PROTOCOL_VERSION)));
|
||||
|
||||
Object coinbasetx;
|
||||
TxToJSON(*block.auxpow, 0, coinbasetx);
|
||||
auxpow.push_back(Pair("coinbasetx", Value(coinbasetx)));
|
||||
|
||||
Array coinbaseMerkle;
|
||||
BOOST_FOREACH(const uint256 &hash, block.auxpow->vMerkleBranch)
|
||||
coinbaseMerkle.push_back(hash.GetHex());
|
||||
auxpow.push_back(Pair("coinbaseMerkleBranch", coinbaseMerkle));
|
||||
auxpow.push_back(Pair("coinbaseIndex", block.auxpow->nIndex));
|
||||
|
||||
Array chainMerkle;
|
||||
BOOST_FOREACH(const uint256 &hash, block.auxpow->vChainMerkleBranch)
|
||||
chainMerkle.push_back(hash.GetHex());
|
||||
auxpow.push_back(Pair("chainMerkleBranch", chainMerkle));
|
||||
auxpow.push_back(Pair("chainIndex", (boost::uint64_t)block.auxpow->nChainIndex));
|
||||
|
||||
Object parent_block;
|
||||
parent_block.push_back(Pair("hash", block.auxpow->parentBlockHeader.GetHash().GetHex()));
|
||||
parent_block.push_back(Pair("version", (boost::uint64_t)block.auxpow->parentBlockHeader.nVersion));
|
||||
parent_block.push_back(Pair("previousblockhash", block.auxpow->parentBlockHeader.hashPrevBlock.GetHex()));
|
||||
parent_block.push_back(Pair("merkleroot", block.auxpow->parentBlockHeader.hashMerkleRoot.GetHex()));
|
||||
parent_block.push_back(Pair("time", (boost::int64_t)block.auxpow->parentBlockHeader.nTime));
|
||||
parent_block.push_back(Pair("bits", HexBits(block.auxpow->parentBlockHeader.nBits)));
|
||||
parent_block.push_back(Pair("nonce", (boost::uint64_t)block.auxpow->parentBlockHeader.nNonce));
|
||||
auxpow.push_back(Pair("parent_block", Value(parent_block)));
|
||||
result.push_back(Pair("auxpow", Value(auxpow)));
|
||||
}
|
||||
Array txs;
|
||||
BOOST_FOREACH(const CTransaction&tx, block.vtx)
|
||||
txs.push_back(tx.GetHash().GetHex());
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "rpcserver.h"
|
||||
#include "chainparams.h"
|
||||
#include "auxpow.h"
|
||||
#include "init.h"
|
||||
#include "net.h"
|
||||
#include "main.h"
|
||||
|
@ -629,3 +630,278 @@ Value submitblock(const Array& params, bool fHelp)
|
|||
|
||||
return Value::null;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
Value getworkaux(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 1)
|
||||
throw runtime_error(
|
||||
"getworkaux <aux>\n"
|
||||
"getworkaux '' <data>\n"
|
||||
"getworkaux 'submit' <data>\n"
|
||||
"getworkaux '' <data> <chain-index> <branch>*\n"
|
||||
" get work with auxiliary data in coinbase, for multichain mining\n"
|
||||
"<aux> is the merkle root of the auxiliary chain block hashes, concatenated with the aux chain merkle tree size and a nonce\n"
|
||||
"<chain-index> is the aux chain index in the aux chain merkle tree\n"
|
||||
"<branch> is the optional merkle branch of the aux chain\n"
|
||||
"If <data> is not specified, returns formatted hash data to work on:\n"
|
||||
" \"midstate\" : precomputed hash state after hashing the first half of the data\n"
|
||||
" \"data\" : block data\n"
|
||||
" \"hash1\" : formatted hash buffer for second hash\n"
|
||||
" \"target\" : little endian hash target\n"
|
||||
"If <data> is specified and 'submit', tries to solve the block for this (parent) chain and returns true if it was successful."
|
||||
"If <data> is specified and empty first argument, returns the aux merkle root, with size and nonce."
|
||||
"If <data> and <chain-index> are specified, creates an auxiliary proof of work for the chain specified and returns:\n"
|
||||
" \"aux\" : merkle root of auxiliary chain block hashes\n"
|
||||
" \"auxpow\" : aux proof of work to submit to aux chain\n"
|
||||
);
|
||||
|
||||
if (vNodes.empty())
|
||||
throw JSONRPCError(-9, "Dogecoin is not connected!");
|
||||
|
||||
if (IsInitialBlockDownload())
|
||||
throw JSONRPCError(-10, "Dogecoin is downloading blocks...");
|
||||
|
||||
static map<uint256, pair<CBlock*, unsigned int> > mapNewBlock;
|
||||
static vector<CBlockTemplate*> vNewBlockTemplate;
|
||||
static CReserveKey reservekey(pwalletMain);
|
||||
|
||||
if (params.size() == 1)
|
||||
{
|
||||
static vector<unsigned char> vchAuxPrev;
|
||||
vector<unsigned char> vchAux = ParseHex(params[0].get_str());
|
||||
|
||||
// Update block
|
||||
static unsigned int nTransactionsUpdatedLast;
|
||||
static CBlockIndex* pindexPrev;
|
||||
static uint64_t nStart;
|
||||
static CBlockTemplate* pblocktemplate;
|
||||
if (pindexPrev != chainActive.Tip() ||
|
||||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60))
|
||||
{
|
||||
if (pindexPrev != chainActive.Tip())
|
||||
{
|
||||
// Deallocate old blocks since they're obsolete now
|
||||
mapNewBlock.clear();
|
||||
BOOST_FOREACH(CBlockTemplate* pblocktemplate, vNewBlockTemplate)
|
||||
delete pblocktemplate;
|
||||
vNewBlockTemplate.clear();
|
||||
}
|
||||
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
||||
pindexPrev = chainActive.Tip();
|
||||
vchAuxPrev = vchAux;
|
||||
nStart = GetTime();
|
||||
|
||||
// Create new block
|
||||
pblocktemplate = CreateNewBlockWithKey(*pMiningKey);
|
||||
if (!pblocktemplate)
|
||||
throw JSONRPCError(-7, "Out of memory");
|
||||
vNewBlockTemplate.push_back(pblocktemplate);
|
||||
}
|
||||
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
|
||||
|
||||
// Update nTime
|
||||
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
||||
pblock->nNonce = 0;
|
||||
|
||||
// Update nExtraNonce
|
||||
static unsigned int nExtraNonce = 0;
|
||||
IncrementExtraNonceWithAux(pblock, pindexPrev, nExtraNonce, vchAux);
|
||||
|
||||
// Save
|
||||
mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, nExtraNonce);
|
||||
|
||||
// Prebuild hash buffers
|
||||
char pmidstate[32];
|
||||
char pdata[128];
|
||||
char phash1[64];
|
||||
FormatHashBuffers(pblock, pmidstate, pdata, phash1);
|
||||
|
||||
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
|
||||
|
||||
Object result;
|
||||
result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
|
||||
result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
|
||||
result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
|
||||
result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (params[0].get_str() != "submit" && params[0].get_str() != "")
|
||||
throw JSONRPCError(-8, "<aux> must be the empty string or 'submit' if work is being submitted");
|
||||
// Parse parameters
|
||||
vector<unsigned char> vchData = ParseHex(params[1].get_str());
|
||||
if (vchData.size() != 128)
|
||||
throw JSONRPCError(-8, "Invalid parameter");
|
||||
CBlock* pdata = (CBlock*)&vchData[0];
|
||||
|
||||
// Byte reverse
|
||||
for (int i = 0; i < 128/4; i++)
|
||||
((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
|
||||
|
||||
// Get saved block
|
||||
if (!mapNewBlock.count(pdata->hashMerkleRoot))
|
||||
return false;
|
||||
CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
|
||||
unsigned int nExtraNonce = mapNewBlock[pdata->hashMerkleRoot].second;
|
||||
|
||||
pblock->nTime = pdata->nTime;
|
||||
pblock->nNonce = pdata->nNonce;
|
||||
|
||||
// Get the aux merkle root from the coinbase
|
||||
CScript script = pblock->vtx[0].vin[0].scriptSig;
|
||||
opcodetype opcode;
|
||||
CScript::const_iterator pc = script.begin();
|
||||
script.GetOp(pc, opcode);
|
||||
script.GetOp(pc, opcode);
|
||||
script.GetOp(pc, opcode);
|
||||
if (opcode != OP_2)
|
||||
throw runtime_error("invalid aux pow script");
|
||||
vector<unsigned char> vchAux;
|
||||
script.GetOp(pc, opcode, vchAux);
|
||||
|
||||
RemoveMergedMiningHeader(vchAux);
|
||||
|
||||
pblock->vtx[0].vin[0].scriptSig = MakeCoinbaseWithAux(pblock->nBits, nExtraNonce, vchAux);
|
||||
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
|
||||
|
||||
if (params.size() > 2)
|
||||
{
|
||||
// Requested aux proof of work
|
||||
int nChainIndex = params[2].get_int();
|
||||
|
||||
CAuxPow pow(pblock->vtx[0]);
|
||||
|
||||
for (unsigned int i = 3 ; i < params.size() ; i++)
|
||||
{
|
||||
uint256 nHash;
|
||||
nHash.SetHex(params[i].get_str());
|
||||
pow.vChainMerkleBranch.push_back(nHash);
|
||||
}
|
||||
|
||||
pow.SetMerkleBranch(pblock);
|
||||
pow.nChainIndex = nChainIndex;
|
||||
pow.parentBlockHeader = *pblock;
|
||||
CDataStream ss(SER_GETHASH, PROTOCOL_VERSION);
|
||||
ss << pow;
|
||||
Object result;
|
||||
result.push_back(Pair("auxpow", HexStr(ss.begin(), ss.end())));
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (params[0].get_str() == "submit")
|
||||
{
|
||||
return CheckWork(pblock, *pwalletMain, reservekey);
|
||||
}
|
||||
else
|
||||
{
|
||||
Object result;
|
||||
result.push_back(Pair("aux", HexStr(vchAux.begin(), vchAux.end())));
|
||||
result.push_back(Pair("hash", pblock->GetHash().GetHex()));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Value getauxblock(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || (params.size() != 0 && params.size() != 2))
|
||||
throw runtime_error(
|
||||
"getauxblock [<hash> <auxpow>]\n"
|
||||
" create a new block"
|
||||
"If <hash>, <auxpow> is not specified, returns a new block hash.\n"
|
||||
"If <hash>, <auxpow> is specified, tries to solve the block based on "
|
||||
"the aux proof of work and returns true if it was successful.");
|
||||
|
||||
if (vNodes.empty())
|
||||
throw JSONRPCError(-9, "Dogecoin is not connected!");
|
||||
|
||||
if (IsInitialBlockDownload())
|
||||
throw JSONRPCError(-10, "Dogecoin is downloading blocks...");
|
||||
|
||||
static map<uint256, CBlock*> mapNewBlock;
|
||||
static vector<CBlockTemplate*> vNewBlockTemplate;
|
||||
static CReserveKey reservekey(pwalletMain);
|
||||
|
||||
if (params.size() == 0)
|
||||
{
|
||||
// Update block
|
||||
static unsigned int nTransactionsUpdatedLast;
|
||||
static CBlockIndex* pindexPrev;
|
||||
static uint64_t nStart;
|
||||
static CBlock* pblock;
|
||||
static CBlockTemplate* pblocktemplate;
|
||||
if (pindexPrev != chainActive.Tip() ||
|
||||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60))
|
||||
{
|
||||
if (pindexPrev != chainActive.Tip())
|
||||
{
|
||||
// Deallocate old blocks since they're obsolete now
|
||||
mapNewBlock.clear();
|
||||
BOOST_FOREACH(CBlockTemplate* pblocktemplate, vNewBlockTemplate)
|
||||
delete pblocktemplate;
|
||||
vNewBlockTemplate.clear();
|
||||
}
|
||||
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
||||
pindexPrev = chainActive.Tip();
|
||||
nStart = GetTime();
|
||||
|
||||
// Create new block with nonce = 0 and extraNonce = 1
|
||||
pblocktemplate = CreateNewBlockWithKey(*pMiningKey);
|
||||
if (!pblocktemplate)
|
||||
throw JSONRPCError(-7, "Out of memory");
|
||||
|
||||
pblock = &pblocktemplate->block;
|
||||
// Update nTime
|
||||
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
||||
pblock->nNonce = 0;
|
||||
|
||||
// Push OP_2 just in case we want versioning later
|
||||
pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CScriptNum(1) << OP_2;
|
||||
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
|
||||
|
||||
// Sets the version
|
||||
pblock->SetAuxPow(new CAuxPow());
|
||||
|
||||
// Save
|
||||
mapNewBlock[pblock->GetHash()] = pblock;
|
||||
|
||||
vNewBlockTemplate.push_back(pblocktemplate);
|
||||
}
|
||||
|
||||
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
|
||||
|
||||
Object result;
|
||||
result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
|
||||
result.push_back(Pair("hash", pblock->GetHash().GetHex()));
|
||||
result.push_back(Pair("chainid", pblock->GetChainID()));
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint256 hash;
|
||||
hash.SetHex(params[0].get_str());
|
||||
vector<unsigned char> vchAuxPow = ParseHex(params[1].get_str());
|
||||
CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION);
|
||||
CAuxPow* pow = new CAuxPow();
|
||||
ss >> *pow;
|
||||
if (!mapNewBlock.count(hash))
|
||||
return ::error("getauxblock() : block not found");
|
||||
|
||||
CBlock* pblock = mapNewBlock[hash];
|
||||
pblock->SetAuxPow(pow);
|
||||
|
||||
if (!CheckWork(pblock, *pwalletMain, reservekey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -317,6 +317,9 @@ static const CRPCCommand vRPCCommands[] =
|
|||
{ "gethashespersec", &gethashespersec, true, false, false },
|
||||
{ "getwork", &getwork, true, false, true },
|
||||
{ "setgenerate", &setgenerate, true, true, false },
|
||||
{ "getwork", &getwork, true, false, true },
|
||||
{ "getworkaux", &getworkaux, true, false, true },
|
||||
{ "getauxblock", &getauxblock, true, false, true }
|
||||
#endif // ENABLE_WALLET
|
||||
};
|
||||
|
||||
|
|
|
@ -134,6 +134,9 @@ extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp);
|
|||
extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp);
|
||||
|
||||
extern json_spirit::Value getworkaux(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value getauxblock(const json_spirit::Array& params, bool fHelp);
|
||||
|
||||
extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
|
||||
extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value getrawchangeaddress(const json_spirit::Array& params, bool fHelp);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "base58.h"
|
||||
#include "key.h"
|
||||
#include "main.h"
|
||||
#include "auxpow.h"
|
||||
#include "serialize.h"
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
|
||||
#include "main.h"
|
||||
#include "auxpow.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
|
56
src/txdb.cpp
56
src/txdb.cpp
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "core.h"
|
||||
#include "uint256.h"
|
||||
#include "auxpow.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -68,9 +69,19 @@ 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::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)
|
||||
{
|
||||
return Write(boost::tuples::make_tuple('b', blockindex.GetBlockHash(), 'b'), blockindex);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadDiskBlockIndex(const uint256 &blkid, CDiskBlockIndex &diskblockindex)
|
||||
{
|
||||
return Read(boost::tuples::make_tuple('b', blkid, 'a'), diskblockindex);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteBestInvalidWork(const CBigNum& bnBestInvalidWork)
|
||||
|
@ -186,7 +197,9 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
|||
leveldb::Iterator *pcursor = NewIterator();
|
||||
|
||||
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
|
||||
ssKeySet << make_pair('b', uint256(0));
|
||||
ssKeySet << boost::tuples::make_tuple('b', uint256(0), 'a'); // 'b' is the prefix for BlockIndex, 'a' sigifies the first part
|
||||
uint256 hash;
|
||||
char cType;
|
||||
pcursor->Seek(ssKeySet.str());
|
||||
|
||||
// Load mapBlockIndex
|
||||
|
@ -195,32 +208,41 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
|||
try {
|
||||
leveldb::Slice slKey = pcursor->key();
|
||||
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
|
||||
char chType;
|
||||
ssKey >> chType;
|
||||
if (chType == 'b') {
|
||||
leveldb::Slice slValue = pcursor->value();
|
||||
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
|
||||
CDiskBlockIndex diskindex;
|
||||
ssValue >> diskindex;
|
||||
ssKey >> cType;
|
||||
if (cType == 'b') {
|
||||
ssKey >> hash;
|
||||
|
||||
leveldb::Slice slValue = pcursor->value();
|
||||
CDataStream ssValue_immutable(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
|
||||
CDiskBlockIndex diskindex;
|
||||
ssValue_immutable >> diskindex; // read all immutable data
|
||||
|
||||
// Construct immutable parts of block index objecty
|
||||
CBlockIndex* pindexNew = InsertBlockIndex(hash);
|
||||
assert(diskindex.CalcBlockHash() == *pindexNew->phashBlock); // paranoia check
|
||||
|
||||
// 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->nVersion = diskindex.nVersion;
|
||||
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
|
||||
pindexNew->nTime = diskindex.nTime;
|
||||
pindexNew->nBits = diskindex.nBits;
|
||||
pindexNew->nNonce = diskindex.nNonce;
|
||||
pindexNew->nStatus = diskindex.nStatus;
|
||||
pindexNew->nTx = diskindex.nTx;
|
||||
|
||||
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
|
||||
|
|
|
@ -51,7 +51,9 @@ private:
|
|||
CBlockTreeDB(const CBlockTreeDB&);
|
||||
void operator=(const CBlockTreeDB&);
|
||||
public:
|
||||
bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
|
||||
bool WriteDiskBlockIndex(const CDiskBlockIndex& diskblockindex);
|
||||
bool WriteBlockIndex(const CBlockIndex& blockindex);
|
||||
bool ReadDiskBlockIndex(const uint256 &blkid, CDiskBlockIndex& diskblockindex);
|
||||
bool WriteBestInvalidWork(const CBigNum& bnBestInvalidWork);
|
||||
bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);
|
||||
bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo);
|
||||
|
|
Loading…
Reference in a new issue