Difficulty is reduced to >1 sec per block; eanc fork block is read from corresponding file; AcceptBlock is verifying received fork blocks by records in the corresponding files

This commit is contained in:
airk42 2018-01-05 04:24:27 -05:00
parent 9d8b64ccfe
commit dbe41f28e3
4 changed files with 312 additions and 126 deletions

View File

@ -494,7 +494,7 @@ std::string HelpMessage(HelpMessageMode mode)
#ifdef FORK_CB_INPUT
strUsage += HelpMessageGroup(_("Fork :"));
strUsage += HelpMessageOpt("-utxo-file=<file>", _("Specify input utxo file"));
strUsage += HelpMessageOpt("-utxo-path=<path>", _("Specify location of utxo files"));
#endif
#ifdef ENABLE_MINING
@ -897,6 +897,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
#ifdef FORK_CB_INPUT
forkUtxoPath = GetArg("-utxo-path", "");
forkStartHeight = GetArg("-fork-startheight", FORK_BLOCK_HEIGHT_START);
forkHeightRange = GetArg("-fork-heightrange", FORK_BLOCK_HEIGHT_RANGE);
forkCBPerBlock = GetArg("-fork-cbperblock", FORK_COINBASE_PER_BLOCK);

View File

@ -72,9 +72,30 @@ uint64_t nPruneTarget = 0;
bool fAlerts = DEFAULT_ALERTS;
#ifdef FORK_CB_INPUT
#include <boost/format.hpp>
#include <boost/range/combine.hpp>
std::string forkUtxoPath;
int64_t forkStartHeight = FORK_BLOCK_HEIGHT_START;
int64_t forkHeightRange = FORK_BLOCK_HEIGHT_RANGE;
int64_t forkCBPerBlock = FORK_COINBASE_PER_BLOCK;
std::string GetUTXOFileName(int nHeight)
{
boost::filesystem::path utxo_path(forkUtxoPath);
if (utxo_path.empty() || !utxo_path.has_filename())
{
LogPrintf("GetUTXOFileName(): UTXO path is not specified, add utxo-path=<path-to-utxop-files> to your btcprivate.conf and restart");
return "";
}
std::stringstream ss;
ss << boost::format("utxo-%05i.bin") % (nHeight - forkStartHeight);
boost::filesystem::path utxo_file = utxo_path;
utxo_file /= ss.str();
return utxo_file.generic_string();
}
#endif
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
@ -1360,7 +1381,11 @@ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::M
return true;
}
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos
#ifdef FORK_CB_INPUT
, int nHeight = -1
#endif
)
{
block.SetNull();
@ -1378,7 +1403,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
}
#ifdef FORK_CB_INPUT
if (!isForking()) {
if (!isFork(nHeight)) { //when block is un fork region - don't check Solution and PoW
#endif
// Check the header
@ -1396,7 +1421,12 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
{
if (!ReadBlockFromDisk(block, pindex->GetBlockPos()))
if (!ReadBlockFromDisk(block, pindex->GetBlockPos()
#ifdef FORK_CB_INPUT
, pindex->nHeight
#endif
)
)
return false;
if (block.GetHash() != pindex->GetBlockHash())
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s",
@ -1902,20 +1932,30 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
const CTransaction &tx = block.vtx[i];
uint256 hash = tx.GetHash();
int nNonCBIdx = 0;
// restore inputs
#ifdef FORK_CB_INPUT
if (isFork(pindex->nHeight)){ //when block in forking region - all transcations are coinbase
nNonCBIdx = forkCBPerBlock;
}
else
#endif
// Check that all outputs are available and match the outputs in the block itself
// exactly.
{
CCoinsModifier outs = view.ModifyCoins(hash);
outs->ClearUnspendable();
{
CCoinsModifier outs = view.ModifyCoins(hash);
outs->ClearUnspendable();
CCoins outsBlock(tx, pindex->nHeight);
// The CCoins serialization does not serialize negative numbers.
// No network rules currently depend on the version here, so an inconsistency is harmless
// but it must be corrected before txout nversion ever influences a network rule.
if (outsBlock.nVersion < 0)
outs->nVersion = outsBlock.nVersion;
if (*outs != outsBlock)
fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted");
CCoins outsBlock(tx, pindex->nHeight);
// The CCoins serialization does not serialize negative numbers.
// No network rules currently depend on the version here, so an inconsistency is harmless
// but it must be corrected before txout nversion ever influences a network rule.
if (outsBlock.nVersion < 0)
outs->nVersion = outsBlock.nVersion;
if (*outs != outsBlock) {
fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted");
LogPrintf("Transaction mismatch?: id: %d: Amount: %d; ScriptPubKey: %s\n", i, tx.vout[0].nValue, tx.vout[0].scriptPubKey.ToString());
}
// remove outputs
outs->Clear();
@ -1928,14 +1968,6 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
}
}
int nNonCBIdx = 0;
// restore inputs
#ifdef FORK_CB_INPUT
if (isForking()){
nNonCBIdx = forkCBPerBlock;
}
#endif
if (i > nNonCBIdx) { // not coinbases
const CTxUndo &txundo = blockUndo.vtxundo[i-1];
if (txundo.vprevout.size() != tx.vin.size())
@ -2211,7 +2243,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001);
#ifdef FORK_CB_INPUT
if (!isForking()){
if (!isFork(pindex->nHeight)){ //when block is in forking region - don't check coinbase amount
#endif
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
if (block.vtx[0].GetValueOut() > blockReward)
@ -2998,15 +3030,15 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
return state.DoS(100, error("CheckBlockHeader(): block version too low"),
REJECT_INVALID, "version-too-low");
#ifdef FORK_CB_INPUT
if (!isFork()) { //when in FORK mode (tip is in forking region) - don't check Solution and PoW
#endif
// Check Equihash solution is valid
if (fCheckPOW && !CheckEquihashSolution(&block, Params()))
return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),
REJECT_INVALID, "invalid-solution");
#ifdef FORK_CB_INPUT
if (!isForking()) {
#endif
// Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus()))
return state.DoS(50, error("CheckBlockHeader(): proof of work failed"),
@ -3066,11 +3098,9 @@ bool CheckBlock(const CBlock& block, CValidationState& state,
REJECT_INVALID, "bad-cb-missing");
#ifdef FORK_CB_INPUT
if (isForking()) {
//This blocks might have up to fork pre-defined value coinbases
for (unsigned int i = forkCBPerBlock; i < block.vtx.size(); i++)
if (block.vtx[i].IsCoinBase())
return state.DoS(100, error("CheckBlock(): it is forking block - more than 1000 coinbase"),
if (isFork()) { //when in FORK mode (tip is in forking region) blocks might have up to fork pre-defined value coinbases
if (block.vtx.size() > forkCBPerBlock)
return state.DoS(100, error("CheckBlock(): it is forking block but there are more than %d coinbase txns", forkCBPerBlock),
REJECT_INVALID, "bad-cb-multiple");
} else {
#endif
@ -3081,6 +3111,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state,
#ifdef FORK_CB_INPUT
}
#endif
// Check transactions
BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!CheckTransaction(tx, state, verifier))
@ -3112,7 +3143,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
// Check proof of work
#ifdef FORK_CB_INPUT
if (!isForking()) {
if (!isFork(nHeight)) { //If current block is FORK, don't check work required
#endif
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.DoS(100, error("%s: incorrect proof of work", __func__),
@ -3218,7 +3249,11 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
return true;
}
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp)
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp
#ifdef FORK_CB_INPUT
, bool fCalledFromMiner
#endif
)
{
const CChainParams& chainparams = Params();
AssertLockHeld(cs_main);
@ -3261,6 +3296,88 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
int nHeight = pindex->nHeight;
#ifdef FORK_CB_INPUT
if (isFork(nHeight)) { //if block is in forking region validate it agains file records
if (!fCalledFromMiner && !forkUtxoPath.empty()) {
std::string utxo_file_path = GetUTXOFileName(nHeight);
std::ifstream if_utxo(utxo_file_path, std::ios::binary | std::ios::in);
if (!if_utxo.is_open()) {
LogPrintf("AcceptBlock(): FORK Block - Cannot open UTXO file - %s\n", utxo_file_path);
} else {
LogPrintf("AcceptBlock(): FORK Block - Validating block - %u with UTXO file - %s\n", nHeight, utxo_file_path);
vector<pair<uint64_t, CScript> > txFromFile;
txFromFile.reserve(forkCBPerBlock);
int recs = 0;
while (if_utxo && recs < forkCBPerBlock) {
char term = 0;
char coin[8] = {};
if (!if_utxo.read(coin, 8)) {
LogPrintf("AcceptBlock(): FORK Block - UTXO file corrupted? - No more data (Amount)\n");
break;
}
uint64_t amount = bytes2uint64(coin);
char pubkeysize[8] = {};
if (!if_utxo.read(pubkeysize, 8)) {
LogPrintf("AcceptBlock(): FORK Block - UTXO file corrupted? - Not more data (PubKeyScript size)\n");
break;
}
int pbsize = bytes2uint64(pubkeysize);
if (pbsize == 0) {
LogPrintf("AcceptBlock(): FORK Block - UTXO file corrupted? - Warning! PubKeyScript size = 0\n");
//but proceed
}
std::unique_ptr<char[]> pubKeyScript(new char[pbsize]);
if (!if_utxo.read(&pubKeyScript[0], pbsize)) {
LogPrintf("AcceptBlock(): FORK Block - UTXO file corrupted? - Not more data (PubKeyScript)\n");
break;
}
unsigned char* pks = (unsigned char*)pubKeyScript.get();
CScript script = CScript(pks, pks+pbsize);
txFromFile.push_back(make_pair(amount, script));
if (!if_utxo.read(&term, 1)) {
LogPrintf("AcceptBlock(): FORK Block - UTXO file corrupted? - No more data (record separator)\n");
break;
}
if (term != '\n') {
//This maybe not an error, but warning none the less
LogPrintf("AcceptBlock(): FORK Block - UTXO file corrupted? - Warning! No record separator ('0xA') was found\n");
if_utxo.seekg(-1, ios_base::cur); //move one char back - if it is not a separator, maybe there is not separators at all
}
recs++;
}
LogPrintf("AcceptBlock(): FORK Block - %d records read from UTXO file\n", recs);
int txid = 0;
typedef boost::tuple<pair<uint64_t, CScript>&, const CTransaction&> fork_cmp_tuple;
BOOST_FOREACH(fork_cmp_tuple cmp, boost::combine(txFromFile, block.vtx)) {
pair<uint64_t, CScript>& rec = cmp.get<0>();
const CTransaction& tx = cmp.get<1>();
if (rec.first != tx.vout[0].nValue ||
rec.second != tx.vout[0].scriptPubKey)
{
LogPrintf("AcceptBlock(): FORK Block - Error: Transaction (%d) mismatch\n", txid);
LogPrintf("AcceptBlock(): Transaction: Amount: %d; scriptPubKey: %s\n", tx.vout[0].nValue, tx.vout[0].scriptPubKey.ToString());
LogPrintf("AcceptBlock(): File Record: Amount: %d; scriptPubKey: %s\n", rec.first, rec.second.ToString());
state.DoS(100, error("AcceptBlock(): FORK Block - Transaction (%d) doesn't match record in the UTXO file", txid),
REJECT_INVALID, "bad-fork-block");
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
return false;
}
}
txid++;
}
}
}
#endif
// Write block to history file
try {
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
@ -3297,7 +3414,11 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
}
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp)
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp
#ifdef FORK_CB_INPUT
, bool fCalledFromMiner
#endif
)
{
// Preliminary checks
auto verifier = libzcash::ProofVerifier::Disabled();
@ -3313,7 +3434,11 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool
// Store to disk
CBlockIndex *pindex = NULL;
bool ret = AcceptBlock(*pblock, state, &pindex, fRequested, dbp);
bool ret = AcceptBlock(*pblock, state, &pindex, fRequested, dbp
#ifdef FORK_CB_INPUT
, fCalledFromMiner
#endif
);
if (pindex && pfrom) {
mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
}

View File

@ -37,6 +37,10 @@
#include <boost/unordered_map.hpp>
#ifndef FORK_CB_INPUT
#define FORK_CB_INPUT
#endif
class CBlockIndex;
class CBlockTreeDB;
class CBloomFilter;
@ -174,7 +178,12 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
* @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location.
* @return True if state.IsValid()
*/
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp);
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp
#ifdef FORK_CB_INPUT
, bool fCalledFromMiner = false
#endif
);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
@ -396,7 +405,11 @@ public:
/** Functions for disk access for blocks */
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos);
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos
#ifdef FORK_CB_INPUT
, int nHeight = -1
#endif
);
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
@ -413,6 +426,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
/** Context-independent validity checks */
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
bool CheckBlock(const CBlock& block, CValidationState& state,
libzcash::ProofVerifier& verifier,
bool fCheckPOW = true, bool fCheckMerkleRoot = true);
@ -431,7 +445,11 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
* - The only caller of AcceptBlock verifies JoinSplit proofs elsewhere.
* If dbp is non-NULL, the file is known to already reside on disk
*/
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp);
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp
#ifdef FORK_CB_INPUT
, bool fCalledFromMiner = false
#endif
);
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
@ -527,25 +545,43 @@ namespace Consensus {
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams);
}
#ifndef FORK_CB_INPUT
#define FORK_CB_INPUT
#endif
#ifdef FORK_CB_INPUT
#define FORK_BLOCK_HEIGHT_START 1000000 //current ZCL height is 200K-300K, this value here is placeholder, it will have to be changed to correct fork block height
#define FORK_BLOCK_HEIGHT_RANGE 65000 //assumption
#define FORK_COINBASE_PER_BLOCK 1000
#define FORK_BLOCK_HEIGHT_RANGE 65000
#define FORK_COINBASE_PER_BLOCK 10000
extern std::string forkUtxoPath;
extern int64_t forkStartHeight;
extern int64_t forkHeightRange;
extern int64_t forkCBPerBlock;
inline bool isForking()
{
int nNextHeight = chainActive.Tip()->nHeight + 1;
return chainActive.Tip()? (nNextHeight >= forkStartHeight && nNextHeight < (forkStartHeight+forkHeightRange)): false;
}
std::string GetUTXOFileName(int nHeight);
inline bool isFork(int nHeight)
{
return (nHeight >= forkStartHeight && nHeight < forkStartHeight + forkHeightRange);
}
inline bool isFork()
{
return chainActive.Tip()? isFork(chainActive.Tip()->nHeight): false;
}
inline bool isNextFork()
{
return chainActive.Tip()? isFork(chainActive.Tip()->nHeight+1): false;
}
inline uint64_t bytes2uint64(char *array)
{
uint64_t x =
static_cast<uint64_t>(array[0]) & 0x00000000000000ff |
static_cast<uint64_t>(array[1]) << 8 & 0x000000000000ff00 |
static_cast<uint64_t>(array[2]) << 16 & 0x0000000000ff0000 |
static_cast<uint64_t>(array[3]) << 24 & 0x00000000ff000000 |
static_cast<uint64_t>(array[4]) << 32 & 0x000000ff00000000 |
static_cast<uint64_t>(array[5]) << 40 & 0x0000ff0000000000 |
static_cast<uint64_t>(array[6]) << 48 & 0x00ff000000000000 |
static_cast<uint64_t>(array[7]) << 56 & 0xff00000000000000;
return x;
}
#endif
#endif // BITCOIN_MAIN_H

View File

@ -112,27 +112,18 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams,
}
#ifdef FORK_CB_INPUT
uint64_t bytes2uint64(char *array)
CBlockTemplate* CreateNewForkBlock(bool& bFileNotFound)
{
uint64_t x =
static_cast<uint64_t>(array[0]) & 0x00000000000000ff |
static_cast<uint64_t>(array[1]) << 8 & 0x000000000000ff00 |
static_cast<uint64_t>(array[2]) << 16 & 0x0000000000ff0000 |
static_cast<uint64_t>(array[3]) << 24 & 0x00000000ff000000 |
static_cast<uint64_t>(array[4]) << 32 & 0x000000ff00000000 |
static_cast<uint64_t>(array[5]) << 40 & 0x0000ff0000000000 |
static_cast<uint64_t>(array[6]) << 48 & 0x00ff000000000000 |
static_cast<uint64_t>(array[7]) << 56 & 0xff00000000000000;
return x;
}
CBlockTemplate* CreateNewForkBlock(int& utxoFileCurPos)
{
std::string utxo_path = GetArg("-utxo-file","");
CBlockIndex* pindexPrev = chainActive.Tip();
const int nHeight = pindexPrev->nHeight + 1;
boost::filesystem::path utxo_file(utxo_path);
if (utxo_file.empty() || !utxo_file.has_filename())
{
throw std::runtime_error("CreateNewForkBlock(): UTXO file is not provided, add utxo-file=<path-to-utxop-file> to ypur btcprivate.conf and restart");
string utxo_file_path = GetUTXOFileName(nHeight);
std::ifstream if_utxo(utxo_file_path, std::ios::binary | std::ios::in);
if (!if_utxo.is_open()) {
bFileNotFound = true;
LogPrintf("CreateNewForkBlock(): Cannot open UTXO file - %s\n", utxo_file_path);
return NULL;
}
const CChainParams& chainparams = Params();
@ -154,52 +145,41 @@ CBlockTemplate* CreateNewForkBlock(int& utxoFileCurPos)
// until there are no more or the block reaches this size:
unsigned int nBlockMinSize = DEFAULT_BLOCK_MIN_SIZE;
CBlockIndex* pindexPrev = chainActive.Tip();
const int nHeight = pindexPrev->nHeight + 1;
uint64_t nBlockSize = 1000;
uint64_t nBlockTx = 0;
std::ifstream if_utxo(utxo_path, std::ios::binary | std::ios::in);
if (!if_utxo.is_open()) {
throw std::runtime_error("CreateNewForkBlock(): Cannot open UTXO file - " + utxo_path);
}
if_utxo.seekg(utxoFileCurPos, ios_base::beg);
LogPrintf("CreateNewForkBlock(): Reading UTXO file from %d\n", utxoFileCurPos);
while (if_utxo && nBlockTx < forkCBPerBlock) {
char term = 0;
char coin[8] = {};
if (!if_utxo.read(coin, 8)) {
LogPrintf("CreateNewForkBlock(): No more data (Amount)\n");
LogPrintf("CreateNewForkBlock(): UTXO file corrupted? - No more data (Amount)\n");
break;
}
char pubkeysize[8] = {};
if (!if_utxo.read(pubkeysize, 8)) {
LogPrintf("CreateNewForkBlock(): Not more data (PubKeyScript size)\n");
LogPrintf("CreateNewForkBlock(): UTXO file corrupted? - Not more data (PubKeyScript size)\n");
break;
}
int pbsize = bytes2uint64(pubkeysize);
LogPrintf("CreateNewForkBlock():PubKeyScript size = %d\n", pbsize);
//LogPrintf("CreateNewForkBlock():PubKeyScript size = %d\n", pbsize);
if (pbsize == 0) {
LogPrintf("CreateNewForkBlock(): Warning! PubKeyScript size = 0\n");
LogPrintf("CreateNewForkBlock(): Warning! UTXO file corrupted? PubKeyScript size = 0\n");
//but proceed
}
std::unique_ptr<char[]> pubKeyScript(new char[pbsize]);
if (!if_utxo.read(&pubKeyScript[0], pbsize)) {
LogPrintf("CreateNewForkBlock(): Not more data (PubKeyScript)\n");
LogPrintf("CreateNewForkBlock(): UTXO file corrupted? Not more data (PubKeyScript)\n");
break;
}
uint64_t amount = bytes2uint64(coin);
LogPrintf("CreateNewForkBlock(): txn %u has ammount %u\n", nBlockTx, amount);
//LogPrintf("CreateNewForkBlock(): txn %u has ammount %u\n", nBlockTx, amount);
// Add coinbase tx's
CMutableTransaction txNew;
@ -210,7 +190,7 @@ CBlockTemplate* CreateNewForkBlock(int& utxoFileCurPos)
unsigned char* pks = (unsigned char*)pubKeyScript.get();
txNew.vout[0].scriptPubKey = CScript(pks, pks+pbsize);
LogPrintf("CreateNewForkBlock(): ScriptPubKey: %s\n", txNew.vout[0].scriptPubKey.ToString());
//LogPrintf("CreateNewForkBlock(): ScriptPubKey: %s\n", txNew.vout[0].scriptPubKey.ToString());
txNew.vout[0].nValue = amount;
@ -237,7 +217,7 @@ CBlockTemplate* CreateNewForkBlock(int& utxoFileCurPos)
if_utxo.seekg(-1, ios_base::cur); //move one char back - if it is not a separator, maybe there is not separators at all
}
}
LogPrintf("CreateNewForkBlock(): total size %u\n", nBlockSize);
LogPrintf("CreateNewForkBlock(): %u tnxs and total size %u\n", nBlockTx, nBlockSize);
// Randomise nonce
arith_uint256 nonce = UintToArith256(GetRandHash());
@ -264,8 +244,6 @@ CBlockTemplate* CreateNewForkBlock(int& utxoFileCurPos)
if (!TestBlockValidity(state, *pblock, pindexPrev, false, false))
throw std::runtime_error("CreateNewForkBlock(): TestBlockValidity failed");
utxoFileCurPos = if_utxo.tellg(); //-1, if end of data
return pblocktemplate.release();
}
#endif
@ -615,7 +593,13 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
static bool ProcessBlockFound(CBlock* pblock)
#endif // ENABLE_WALLET
{
#ifdef FORK_CB_INPUT
if (!isNextFork()) {
#endif
LogPrintf("%s\n", pblock->ToString());
#ifdef FORK_CB_INPUT
}
#endif
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
// Found a solution
@ -640,7 +624,11 @@ static bool ProcessBlockFound(CBlock* pblock)
// Process this block the same as if we had received it from another node
CValidationState state;
if (!ProcessNewBlock(state, NULL, pblock, true, NULL))
if (!ProcessNewBlock(state, NULL, pblock, true, NULL
#ifdef FORK_CB_INPUT
, true
#endif
))
return error("BTCPrivate Miner: ProcessNewBlock, block not accepted");
TrackMinedBlock(pblock->GetHash());
@ -664,10 +652,6 @@ void static BitcoinMiner()
CReserveKey reservekey(pwallet);
#endif
#ifdef FORK_CB_INPUT
int forkFilePos = 0; //TODO: make it percistent
#endif
// Each thread has its own counter
unsigned int nExtraNonce = 0;
@ -688,8 +672,13 @@ void static BitcoinMiner()
);
miningTimer.start();
#ifdef FORK_CB_INPUT
bool bForkModeStarted = false;
#endif
try {
while (true) {
#ifndef FORK_CB_INPUT ///!!!! this is only for TESTING
if (chainparams.MiningRequiresPeers()) {
// Busy-wait for the network to come online so we don't waste time mining
// on an obsolete chain. In regtest mode we expect to fly solo.
@ -706,6 +695,7 @@ void static BitcoinMiner()
} while (true);
miningTimer.start();
}
#endif
CBlockIndex* pindexPrev = chainActive.Tip();
CBlock *pblock = nullptr;
@ -717,24 +707,42 @@ void static BitcoinMiner()
unique_ptr<CBlockTemplate> pblocktemplate;
#ifdef FORK_CB_INPUT
bool bForking = isForking(); //(pindexPrev->nHeight >= forkStartHeight);
if (bForking) {
if (forkFilePos != -1) {
pblocktemplate.reset(CreateNewForkBlock(forkFilePos));
if (!pblocktemplate.get()) {
LogPrintf("Error in BTCPrivate Miner: Cannot create Fork Block\n");
}
pblock = &pblocktemplate->block;
LogPrintf("Running BTCPrivate Miner with %u forking transactions in block (%u bytes)\n", pblock->vtx.size(),
::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
bool isNextBlockFork = isFork(pindexPrev->nHeight+1);
if (isNextBlockFork) {
if (!bForkModeStarted) {
LogPrintf("BTCPrivate Miner: switching into fork mode\n");
bForkModeStarted = true;
}
bool bFileNotFound = false;
pblocktemplate.reset(CreateNewForkBlock(bFileNotFound));
if (!pblocktemplate.get()) {
if (bFileNotFound) {
MilliSleep(1000);
continue;
} else {
LogPrintf("Error in BTCPrivate Miner: Cannot create Fork Block\n");
return;
}
}
pblock = &pblocktemplate->block;
n = 48; k = 5;
LogPrintf("Running BTCPrivate Miner with %u forking transactions in block (%u bytes) and N = %d, K = %d\n", pblock->vtx.size(),
::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION),
n, k);
} else {
//if not in forking mode and/or provided file is read to the end - exit
if (bForkModeStarted) {
LogPrintf("BTCPrivate Miner: Fork is done - switching back to regular miner\n");
n = chainparams.EquihashN();
k = chainparams.EquihashK();
bForkModeStarted = false;
}
#endif
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
#ifdef ENABLE_WALLET
pblocktemplate.reset(CreateNewBlockWithKey(reservekey));
#else
@ -792,21 +800,29 @@ void static BitcoinMiner()
solver, pblock->nNonce.ToString());
std::function<bool(std::vector<unsigned char>)> validBlock =
[&pblock, &hashTarget, &m_cs, &cancelSolver, &chainparams
#ifdef ENABLE_WALLET
[&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams]
#else
[&pblock, &hashTarget, &m_cs, &cancelSolver, &chainparams]
, &pwallet, &reservekey
#endif
(std::vector<unsigned char> soln) {
#ifdef FORK_CB_INPUT
, &isNextBlockFork
#endif
] (std::vector<unsigned char> soln) {
// Write the solution to the hash and compute the result.
LogPrint("pow", "- Checking solution against target\n");
pblock->nSolution = soln;
solutionTargetChecks.increment();
#ifdef FORK_CB_INPUT
if (!isNextBlockFork) {
#endif
if (UintToArith256(pblock->GetHash()) > hashTarget) {
return false;
}
#ifdef FORK_CB_INPUT
}
#endif
// Found a solution
SetThreadPriority(THREAD_PRIORITY_NORMAL);
LogPrintf("BTCPrivate Miner:\n");
@ -886,16 +902,17 @@ void static BitcoinMiner()
// Check for stop or if block needs to be rebuilt
boost::this_thread::interruption_point();
// Regtest mode doesn't require peers
if (vNodes.empty() && chainparams.MiningRequiresPeers())
break;
if ((UintToArith256(pblock->nNonce) & 0xffff) == 0xffff)
break;
#ifdef FORK_CB_INPUT
if (!bForking) {
if (!isNextBlockFork) {
#endif
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
break;
// Regtest mode doesn't require peers
if (vNodes.empty() && chainparams.MiningRequiresPeers())
break;
if ((UintToArith256(pblock->nNonce) & 0xffff) == 0xffff)
break;
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
break;
#ifdef FORK_CB_INPUT
}
#endif
@ -906,11 +923,18 @@ void static BitcoinMiner()
// Update nNonce and nTime
pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1);
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
{
// Changing pblock->nTime can change work required on testnet:
hashTarget.SetCompact(pblock->nBits);
#ifdef FORK_CB_INPUT
if (!isNextBlockFork) {
#endif
if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
{
// Changing pblock->nTime can change work required on testnet:
hashTarget.SetCompact(pblock->nBits);
}
#ifdef FORK_CB_INPUT
}
#endif
}
}
}