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:
parent
9d8b64ccfe
commit
dbe41f28e3
|
@ -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);
|
||||
|
|
177
src/main.cpp
177
src/main.cpp
|
@ -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,6 +1932,14 @@ 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.
|
||||
{
|
||||
|
@ -1914,8 +1952,10 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|||
// but it must be corrected before txout nversion ever influences a network rule.
|
||||
if (outsBlock.nVersion < 0)
|
||||
outs->nVersion = outsBlock.nVersion;
|
||||
if (*outs != outsBlock)
|
||||
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();
|
||||
}
|
||||
|
|
64
src/main.h
64
src/main.h
|
@ -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
|
||||
|
|
148
src/miner.cpp
148
src/miner.cpp
|
@ -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));
|
||||
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;
|
||||
|
||||
LogPrintf("Running BTCPrivate Miner with %u forking transactions in block (%u bytes)\n", pblock->vtx.size(),
|
||||
::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
|
||||
}
|
||||
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,14 +902,15 @@ void static BitcoinMiner()
|
|||
|
||||
// Check for stop or if block needs to be rebuilt
|
||||
boost::this_thread::interruption_point();
|
||||
|
||||
#ifdef FORK_CB_INPUT
|
||||
if (!isNextBlockFork) {
|
||||
#endif
|
||||
// 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) {
|
||||
#endif
|
||||
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
|
||||
break;
|
||||
#ifdef FORK_CB_INPUT
|
||||
|
@ -906,11 +923,18 @@ void static BitcoinMiner()
|
|||
// Update nNonce and nTime
|
||||
pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1);
|
||||
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
|
||||
|
||||
#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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue