Sync main.cpp to jl777
This commit is contained in:
244
src/main.cpp
244
src/main.cpp
@@ -53,7 +53,8 @@ using namespace std;
|
|||||||
|
|
||||||
CCriticalSection cs_main;
|
CCriticalSection cs_main;
|
||||||
extern uint8_t NOTARY_PUBKEY33[33];
|
extern uint8_t NOTARY_PUBKEY33[33];
|
||||||
extern int32_t KOMODO_LOADINGBLOCKS;
|
extern int32_t KOMODO_LOADINGBLOCKS,KOMODO_LONGESTCHAIN;
|
||||||
|
void komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block);
|
||||||
|
|
||||||
BlockMap mapBlockIndex;
|
BlockMap mapBlockIndex;
|
||||||
CChain chainActive;
|
CChain chainActive;
|
||||||
@@ -219,19 +220,19 @@ namespace {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct CBlockReject {
|
struct CBlockReject {
|
||||||
unsigned char chRejectCode;
|
unsigned char chRejectCode;
|
||||||
string strRejectReason;
|
string strRejectReason;
|
||||||
uint256 hashBlock;
|
uint256 hashBlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintain validation-specific state about nodes, protected by cs_main, instead
|
* Maintain validation-specific state about nodes, protected by cs_main, instead
|
||||||
* by CNode's own locks. This simplifies asynchronous operation, where
|
* by CNode's own locks. This simplifies asynchronous operation, where
|
||||||
* processing of incoming data is done after the ProcessMessage call returns,
|
* processing of incoming data is done after the ProcessMessage call returns,
|
||||||
* and we're no longer holding the node's locks.
|
* and we're no longer holding the node's locks.
|
||||||
*/
|
*/
|
||||||
struct CNodeState {
|
struct CNodeState {
|
||||||
//! The peer's address
|
//! The peer's address
|
||||||
CService address;
|
CService address;
|
||||||
//! Whether we have a fully established connection.
|
//! Whether we have a fully established connection.
|
||||||
@@ -273,49 +274,49 @@ struct CNodeState {
|
|||||||
nBlocksInFlightValidHeaders = 0;
|
nBlocksInFlightValidHeaders = 0;
|
||||||
fPreferredDownload = false;
|
fPreferredDownload = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Map maintaining per-node state. Requires cs_main. */
|
/** Map maintaining per-node state. Requires cs_main. */
|
||||||
map<NodeId, CNodeState> mapNodeState;
|
map<NodeId, CNodeState> mapNodeState;
|
||||||
|
|
||||||
// Requires cs_main.
|
// Requires cs_main.
|
||||||
CNodeState *State(NodeId pnode) {
|
CNodeState *State(NodeId pnode) {
|
||||||
map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode);
|
map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode);
|
||||||
if (it == mapNodeState.end())
|
if (it == mapNodeState.end())
|
||||||
return NULL;
|
return NULL;
|
||||||
return &it->second;
|
return &it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetHeight()
|
int GetHeight()
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
return chainActive.Height();
|
return chainActive.Height();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdatePreferredDownload(CNode* node, CNodeState* state)
|
void UpdatePreferredDownload(CNode* node, CNodeState* state)
|
||||||
{
|
{
|
||||||
nPreferredDownload -= state->fPreferredDownload;
|
nPreferredDownload -= state->fPreferredDownload;
|
||||||
|
|
||||||
// Whether this node should be marked as a preferred download node.
|
// Whether this node should be marked as a preferred download node.
|
||||||
state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient;
|
state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient;
|
||||||
|
|
||||||
nPreferredDownload += state->fPreferredDownload;
|
nPreferredDownload += state->fPreferredDownload;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns time at which to timeout block request (nTime in microseconds)
|
// Returns time at which to timeout block request (nTime in microseconds)
|
||||||
int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consensus::Params &consensusParams)
|
int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consensus::Params &consensusParams)
|
||||||
{
|
{
|
||||||
return nTime + 500000 * consensusParams.nPowTargetSpacing * (4 + nValidatedQueuedBefore);
|
return nTime + 500000 * consensusParams.nPowTargetSpacing * (4 + nValidatedQueuedBefore);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeNode(NodeId nodeid, const CNode *pnode) {
|
void InitializeNode(NodeId nodeid, const CNode *pnode) {
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
|
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
|
||||||
state.name = pnode->addrName;
|
state.name = pnode->addrName;
|
||||||
state.address = pnode->addr;
|
state.address = pnode->addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FinalizeNode(NodeId nodeid) {
|
void FinalizeNode(NodeId nodeid) {
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CNodeState *state = State(nodeid);
|
CNodeState *state = State(nodeid);
|
||||||
|
|
||||||
@@ -332,11 +333,11 @@ void FinalizeNode(NodeId nodeid) {
|
|||||||
nPreferredDownload -= state->fPreferredDownload;
|
nPreferredDownload -= state->fPreferredDownload;
|
||||||
|
|
||||||
mapNodeState.erase(nodeid);
|
mapNodeState.erase(nodeid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
|
void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
|
||||||
{
|
{
|
||||||
/* int expired = pool.Expire(GetTime() - age);
|
/* int expired = pool.Expire(GetTime() - age);
|
||||||
if (expired != 0)
|
if (expired != 0)
|
||||||
LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired);
|
LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired);
|
||||||
|
|
||||||
@@ -344,11 +345,11 @@ void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
|
|||||||
pool.TrimToSize(limit, &vNoSpendsRemaining);
|
pool.TrimToSize(limit, &vNoSpendsRemaining);
|
||||||
BOOST_FOREACH(const uint256& removed, vNoSpendsRemaining)
|
BOOST_FOREACH(const uint256& removed, vNoSpendsRemaining)
|
||||||
pcoinsTip->Uncache(removed);*/
|
pcoinsTip->Uncache(removed);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Requires cs_main.
|
// Requires cs_main.
|
||||||
// Returns a bool indicating whether we requested this block.
|
// Returns a bool indicating whether we requested this block.
|
||||||
bool MarkBlockAsReceived(const uint256& hash) {
|
bool MarkBlockAsReceived(const uint256& hash) {
|
||||||
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
|
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
|
||||||
if (itInFlight != mapBlocksInFlight.end()) {
|
if (itInFlight != mapBlocksInFlight.end()) {
|
||||||
CNodeState *state = State(itInFlight->second.first);
|
CNodeState *state = State(itInFlight->second.first);
|
||||||
@@ -361,10 +362,10 @@ bool MarkBlockAsReceived(const uint256& hash) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Requires cs_main.
|
// Requires cs_main.
|
||||||
void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL) {
|
void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL) {
|
||||||
CNodeState *state = State(nodeid);
|
CNodeState *state = State(nodeid);
|
||||||
assert(state != NULL);
|
assert(state != NULL);
|
||||||
|
|
||||||
@@ -378,10 +379,10 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Pa
|
|||||||
state->nBlocksInFlight++;
|
state->nBlocksInFlight++;
|
||||||
state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders;
|
state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders;
|
||||||
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
|
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check whether the last unknown block a peer advertized is not yet known. */
|
/** Check whether the last unknown block a peer advertized is not yet known. */
|
||||||
void ProcessBlockAvailability(NodeId nodeid) {
|
void ProcessBlockAvailability(NodeId nodeid) {
|
||||||
CNodeState *state = State(nodeid);
|
CNodeState *state = State(nodeid);
|
||||||
assert(state != NULL);
|
assert(state != NULL);
|
||||||
|
|
||||||
@@ -394,10 +395,10 @@ void ProcessBlockAvailability(NodeId nodeid) {
|
|||||||
state->hashLastUnknownBlock.SetNull();
|
state->hashLastUnknownBlock.SetNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update tracking information about which blocks a peer is assumed to have. */
|
/** Update tracking information about which blocks a peer is assumed to have. */
|
||||||
void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
|
void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
|
||||||
CNodeState *state = State(nodeid);
|
CNodeState *state = State(nodeid);
|
||||||
assert(state != NULL);
|
assert(state != NULL);
|
||||||
|
|
||||||
@@ -413,11 +414,11 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
|
|||||||
// An unknown block was announced; just assume that the latest one is the best one.
|
// An unknown block was announced; just assume that the latest one is the best one.
|
||||||
state->hashLastUnknownBlock = hash;
|
state->hashLastUnknownBlock = hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Find the last common ancestor two blocks have.
|
/** Find the last common ancestor two blocks have.
|
||||||
* Both pa and pb must be non-NULL. */
|
* Both pa and pb must be non-NULL. */
|
||||||
CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) {
|
CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) {
|
||||||
if (pa->nHeight > pb->nHeight) {
|
if (pa->nHeight > pb->nHeight) {
|
||||||
pa = pa->GetAncestor(pb->nHeight);
|
pa = pa->GetAncestor(pb->nHeight);
|
||||||
} else if (pb->nHeight > pa->nHeight) {
|
} else if (pb->nHeight > pa->nHeight) {
|
||||||
@@ -432,11 +433,11 @@ CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) {
|
|||||||
// Eventually all chain branches meet at the genesis block.
|
// Eventually all chain branches meet at the genesis block.
|
||||||
assert(pa == pb);
|
assert(pa == pb);
|
||||||
return pa;
|
return pa;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
|
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
|
||||||
* at most count entries. */
|
* at most count entries. */
|
||||||
void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller) {
|
void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller) {
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -516,7 +517,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anon namespace
|
} // anon namespace
|
||||||
|
|
||||||
@@ -1241,11 +1242,14 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||||||
return error("AcceptToMemoryPool: komodo_validate_interest failed");
|
return error("AcceptToMemoryPool: komodo_validate_interest failed");
|
||||||
}
|
}
|
||||||
if (!CheckTransaction(tx, state, verifier))
|
if (!CheckTransaction(tx, state, verifier))
|
||||||
return error("AcceptToMemoryPool: CheckTransaction failed");
|
{
|
||||||
|
|
||||||
|
return error("AcceptToMemoryPool: CheckTransaction failed");
|
||||||
|
}
|
||||||
// DoS level set to 10 to be more forgiving.
|
// DoS level set to 10 to be more forgiving.
|
||||||
// Check transaction contextually against the set of consensus rules which apply in the next block to be mined.
|
// Check transaction contextually against the set of consensus rules which apply in the next block to be mined.
|
||||||
if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) {
|
if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10))
|
||||||
|
{
|
||||||
return error("AcceptToMemoryPool: ContextualCheckTransaction failed");
|
return error("AcceptToMemoryPool: ContextualCheckTransaction failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1408,7 +1412,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||||||
CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
|
CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
|
||||||
if (fLimitFree && nFees < txMinFee)
|
if (fLimitFree && nFees < txMinFee)
|
||||||
{
|
{
|
||||||
fprintf(stderr,"accept failure.5\n");
|
//fprintf(stderr,"accept failure.5\n");
|
||||||
return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",hash.ToString(), nFees, txMinFee),REJECT_INSUFFICIENTFEE, "insufficient fee");
|
return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",hash.ToString(), nFees, txMinFee),REJECT_INSUFFICIENTFEE, "insufficient fee");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1548,7 +1552,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*char *komodo_getspendscript(uint256 hash,int32_t n)
|
/*char *komodo_getspendscript(uint256 hash,int32_t n)
|
||||||
{
|
{
|
||||||
CTransaction tx; uint256 hashBlock;
|
CTransaction tx; uint256 hashBlock;
|
||||||
if ( !GetTransaction(hash,tx,hashBlock,true) )
|
if ( !GetTransaction(hash,tx,hashBlock,true) )
|
||||||
{
|
{
|
||||||
@@ -1559,7 +1563,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
|
|||||||
return((char *)tx.vout[n].scriptPubKey.ToString().c_str());
|
return((char *)tx.vout[n].scriptPubKey.ToString().c_str());
|
||||||
else printf("getspendscript illegal n.%d\n",n);
|
else printf("getspendscript illegal n.%d\n",n);
|
||||||
return(0);
|
return(0);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -1614,7 +1618,7 @@ bool ReadBlockFromDisk(int32_t height,CBlock& block, const CDiskBlockPos& pos)
|
|||||||
if (!(CheckEquihashSolution(&block, Params()) && CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus())))
|
if (!(CheckEquihashSolution(&block, Params()) && CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus())))
|
||||||
{
|
{
|
||||||
int32_t i; for (i=0; i<33; i++)
|
int32_t i; for (i=0; i<33; i++)
|
||||||
printf("%02x",pubkey33[i]);
|
fprintf(stderr,"%02x",pubkey33[i]);
|
||||||
fprintf(stderr," warning unexpected diff at ht.%d\n",height);
|
fprintf(stderr," warning unexpected diff at ht.%d\n",height);
|
||||||
|
|
||||||
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
|
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
|
||||||
@@ -1695,7 +1699,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
|
|||||||
return(nSubsidy);
|
return(nSubsidy);
|
||||||
} else return(0);
|
} else return(0);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
// Mining slow start
|
// Mining slow start
|
||||||
// The subsidy is ramped up linearly, skipping the middle payout of
|
// The subsidy is ramped up linearly, skipping the middle payout of
|
||||||
// MAX_SUBSIDY/2 to keep the monetary curve consistent with no slow start.
|
// MAX_SUBSIDY/2 to keep the monetary curve consistent with no slow start.
|
||||||
@@ -1849,7 +1853,7 @@ void Misbehaving(NodeId pnode, int howmuch)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
state->nMisbehavior += howmuch;
|
state->nMisbehavior += howmuch;
|
||||||
int banscore = GetArg("-banscore", 100);
|
int banscore = GetArg("-banscore", 101);
|
||||||
if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore)
|
if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore)
|
||||||
{
|
{
|
||||||
LogPrintf("%s: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior);
|
LogPrintf("%s: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior);
|
||||||
@@ -1946,8 +1950,8 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace Consensus {
|
namespace Consensus {
|
||||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams)
|
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams)
|
||||||
{
|
{
|
||||||
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
|
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
|
||||||
// for an attacker to attempt to split the network.
|
// for an attacker to attempt to split the network.
|
||||||
if (!inputs.HaveInputs(tx))
|
if (!inputs.HaveInputs(tx))
|
||||||
@@ -1994,7 +1998,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
|
|||||||
int64_t interest; int32_t txheight; uint32_t locktime;
|
int64_t interest; int32_t txheight; uint32_t locktime;
|
||||||
if ( (interest= komodo_accrued_interest(&txheight,&locktime,prevout.hash,prevout.n,0,coins->vout[prevout.n].nValue,(int32_t)nSpendHeight-1)) != 0 )
|
if ( (interest= komodo_accrued_interest(&txheight,&locktime,prevout.hash,prevout.n,0,coins->vout[prevout.n].nValue,(int32_t)nSpendHeight-1)) != 0 )
|
||||||
{
|
{
|
||||||
//fprintf(stderr,"checkResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueIn/COIN,(double)coins->vout[prevout.n].nValue/COIN,(double)interest/COIN,txheight,locktime,chainActive.Tip()->nTime);
|
//fprintf(stderr,"checkResult %.8f += val %.8f interest %.8f ht.%d lock.%u tip.%u\n",(double)nValueIn/COIN,(double)coins->vout[prevout.n].nValue/COIN,(double)interest/COIN,txheight,locktime,chainActive.Tip()->nTime);
|
||||||
nValueIn += interest;
|
nValueIn += interest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2027,7 +2031,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
|
|||||||
return state.DoS(100, error("CheckInputs(): nFees out of range"),
|
return state.DoS(100, error("CheckInputs(): nFees out of range"),
|
||||||
REJECT_INVALID, "bad-txns-fee-outofrange");
|
REJECT_INVALID, "bad-txns-fee-outofrange");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}// namespace Consensus
|
}// namespace Consensus
|
||||||
|
|
||||||
bool ContextualCheckInputs(
|
bool ContextualCheckInputs(
|
||||||
@@ -2100,7 +2104,7 @@ bool ContextualCheckInputs(
|
|||||||
|
|
||||||
|
|
||||||
/*bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
|
/*bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
|
||||||
{
|
{
|
||||||
if (!NonContextualCheckInputs(tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks)) {
|
if (!NonContextualCheckInputs(tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks)) {
|
||||||
fprintf(stderr,"ContextualCheckInputs failure.0\n");
|
fprintf(stderr,"ContextualCheckInputs failure.0\n");
|
||||||
return false;
|
return false;
|
||||||
@@ -2135,12 +2139,12 @@ bool ContextualCheckInputs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
|
bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
|
||||||
{
|
{
|
||||||
// Open history file to append
|
// Open history file to append
|
||||||
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
|
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
|
||||||
if (fileout.IsNull())
|
if (fileout.IsNull())
|
||||||
@@ -2164,10 +2168,10 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint
|
|||||||
fileout << hasher.GetHash();
|
fileout << hasher.GetHash();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock)
|
bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock)
|
||||||
{
|
{
|
||||||
// Open history file to read
|
// Open history file to read
|
||||||
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
|
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
|
||||||
if (filein.IsNull())
|
if (filein.IsNull())
|
||||||
@@ -2191,11 +2195,11 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
|
|||||||
return error("%s: Checksum mismatch", __func__);
|
return error("%s: Checksum mismatch", __func__);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Abort with a message */
|
/** Abort with a message */
|
||||||
bool AbortNode(const std::string& strMessage, const std::string& userMessage="")
|
bool AbortNode(const std::string& strMessage, const std::string& userMessage="")
|
||||||
{
|
{
|
||||||
strMiscWarning = strMessage;
|
strMiscWarning = strMessage;
|
||||||
LogPrintf("*** %s\n", strMessage);
|
LogPrintf("*** %s\n", strMessage);
|
||||||
uiInterface.ThreadSafeMessageBox(
|
uiInterface.ThreadSafeMessageBox(
|
||||||
@@ -2203,13 +2207,13 @@ bool AbortNode(const std::string& strMessage, const std::string& userMessage="")
|
|||||||
"", CClientUIInterface::MSG_ERROR);
|
"", CClientUIInterface::MSG_ERROR);
|
||||||
StartShutdown();
|
StartShutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage="")
|
bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage="")
|
||||||
{
|
{
|
||||||
AbortNode(strMessage, userMessage);
|
AbortNode(strMessage, userMessage);
|
||||||
return state.Error(strMessage);
|
return state.Error(strMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anon namespace
|
} // anon namespace
|
||||||
|
|
||||||
@@ -2427,6 +2431,7 @@ static int64_t nTimeTotal = 0;
|
|||||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck)
|
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck)
|
||||||
{
|
{
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
|
|
||||||
//fprintf(stderr,"connectblock ht.%d\n",(int32_t)pindex->nHeight);
|
//fprintf(stderr,"connectblock ht.%d\n",(int32_t)pindex->nHeight);
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
bool fExpensiveChecks = true;
|
bool fExpensiveChecks = true;
|
||||||
@@ -2523,7 +2528,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||||||
if (nSigOps > MAX_BLOCK_SIGOPS)
|
if (nSigOps > MAX_BLOCK_SIGOPS)
|
||||||
return state.DoS(100, error("ConnectBlock(): too many sigops"),
|
return state.DoS(100, error("ConnectBlock(): too many sigops"),
|
||||||
REJECT_INVALID, "bad-blk-sigops");
|
REJECT_INVALID, "bad-blk-sigops");
|
||||||
//fprintf(stderr,"ht.%d vout0 t%u\n",pindex->nHeight,tx.nLockTime);
|
//fprintf(stderr,"ht.%d vout0 t%u\n",pindex->nHeight,tx.nLockTime);
|
||||||
if (!tx.IsCoinBase())
|
if (!tx.IsCoinBase())
|
||||||
{
|
{
|
||||||
if (!view.HaveInputs(tx))
|
if (!view.HaveInputs(tx))
|
||||||
@@ -3080,21 +3085,21 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
|
|||||||
}
|
}
|
||||||
if ( KOMODO_REWIND != 0 )
|
if ( KOMODO_REWIND != 0 )
|
||||||
{
|
{
|
||||||
|
CBlockIndex *tipindex;
|
||||||
fprintf(stderr,">>>>>>>>>>> rewind start ht.%d -> KOMODO_REWIND.%d\n",chainActive.Tip()->nHeight,KOMODO_REWIND);
|
fprintf(stderr,">>>>>>>>>>> rewind start ht.%d -> KOMODO_REWIND.%d\n",chainActive.Tip()->nHeight,KOMODO_REWIND);
|
||||||
while ( KOMODO_REWIND > 0 && chainActive.Tip()->nHeight > KOMODO_REWIND )
|
while ( KOMODO_REWIND > 0 && (tipindex= chainActive.Tip()) != 0 && tipindex->nHeight > KOMODO_REWIND )
|
||||||
{
|
{
|
||||||
fprintf(stderr,"%d ",(int32_t)chainActive.Tip()->nHeight);
|
fBlocksDisconnected = true;
|
||||||
|
fprintf(stderr,"%d ",(int32_t)tipindex->nHeight);
|
||||||
|
InvalidateBlock(state,tipindex);
|
||||||
if ( !DisconnectTip(state) )
|
if ( !DisconnectTip(state) )
|
||||||
{
|
|
||||||
InvalidateBlock(state,chainActive.Tip());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
fprintf(stderr,"reached rewind.%d, best to do: ./komodo-cli -ac_name=%s stop\n",KOMODO_REWIND,ASSETCHAINS_SYMBOL);
|
fprintf(stderr,"reached rewind.%d, best to do: ./komodo-cli -ac_name=%s stop\n",KOMODO_REWIND,ASSETCHAINS_SYMBOL);
|
||||||
sleep(60);
|
sleep(20);
|
||||||
fprintf(stderr,"resuming normal operations\n");
|
fprintf(stderr,"resuming normal operations\n");
|
||||||
KOMODO_REWIND = 0;
|
KOMODO_REWIND = 0;
|
||||||
return(true);
|
//return(true);
|
||||||
}
|
}
|
||||||
// Build list of new blocks to connect.
|
// Build list of new blocks to connect.
|
||||||
std::vector<CBlockIndex*> vpindexToConnect;
|
std::vector<CBlockIndex*> vpindexToConnect;
|
||||||
@@ -3475,7 +3480,6 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
|
|||||||
|
|
||||||
bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& blockhdr, CValidationState& state, bool fCheckPOW)
|
bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& blockhdr, CValidationState& state, bool fCheckPOW)
|
||||||
{
|
{
|
||||||
uint8_t pubkey33[33];
|
|
||||||
// Check timestamp
|
// Check timestamp
|
||||||
if ( 0 )
|
if ( 0 )
|
||||||
{
|
{
|
||||||
@@ -3516,6 +3520,36 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl
|
|||||||
|
|
||||||
int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtime);
|
int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtime);
|
||||||
|
|
||||||
|
int32_t komodo_reverify_blockcheck(CValidationState& state,int32_t height,CBlockIndex *pindex)
|
||||||
|
{
|
||||||
|
static int32_t oneshot;
|
||||||
|
CBlockIndex *tipindex; int32_t rewindtarget;
|
||||||
|
if ( oneshot == 0 && IsInitialBlockDownload() == 0 && (tipindex= chainActive.Tip()) != 0 )
|
||||||
|
{
|
||||||
|
// if 200 blocks behind longestchain and no blocks for 2 hours
|
||||||
|
if ( KOMODO_LONGESTCHAIN > height+200 )
|
||||||
|
{
|
||||||
|
if ( GetAdjustedTime() > tipindex->nTime+3600*2 )
|
||||||
|
{
|
||||||
|
fprintf(stderr,"tip.%d longest.%d newblock.%d lag.%d blocktime.%u\n",tipindex->nHeight,KOMODO_LONGESTCHAIN,height,(int32_t)(GetAdjustedTime() - tipindex->nTime),tipindex->nTime);
|
||||||
|
rewindtarget = tipindex->nHeight - 11;
|
||||||
|
fprintf(stderr,"rewindtarget <- %d\n",rewindtarget);
|
||||||
|
oneshot = 1;
|
||||||
|
while ( rewindtarget > 0 && (tipindex= chainActive.Tip()) != 0 && tipindex->nHeight > rewindtarget )
|
||||||
|
{
|
||||||
|
fprintf(stderr,"%d ",(int32_t)tipindex->nHeight);
|
||||||
|
InvalidateBlock(state,tipindex);
|
||||||
|
if ( !DisconnectTip(state) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tipindex = chainActive.Tip();
|
||||||
|
fprintf(stderr,"rewind done to %d\n",tipindex!=0?tipindex->nHeight:-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state,
|
bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state,
|
||||||
libzcash::ProofVerifier& verifier,
|
libzcash::ProofVerifier& verifier,
|
||||||
bool fCheckPOW, bool fCheckMerkleRoot)
|
bool fCheckPOW, bool fCheckMerkleRoot)
|
||||||
@@ -3527,10 +3561,13 @@ bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidat
|
|||||||
// redundant with the call in AcceptBlockHeader.
|
// redundant with the call in AcceptBlockHeader.
|
||||||
if (!CheckBlockHeader(height,pindex,block,state,fCheckPOW))
|
if (!CheckBlockHeader(height,pindex,block,state,fCheckPOW))
|
||||||
return false;
|
return false;
|
||||||
|
//komodo_index2pubkey33(pubkey33,pindex,height);
|
||||||
komodo_block2pubkey33(pubkey33,(CBlock *)&block);
|
komodo_block2pubkey33(pubkey33,(CBlock *)&block);
|
||||||
if ( fCheckPOW && !CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus()) )
|
if ( fCheckPOW && !CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus()) )
|
||||||
return state.DoS(50, error("CheckBlock(): proof of work failed"),REJECT_INVALID, "high-hash");
|
{
|
||||||
|
komodo_reverify_blockcheck(state,height,pindex);
|
||||||
|
return state.DoS(33, error("CheckBlock(): proof of work failed"),REJECT_INVALID, "high-hash");
|
||||||
|
}
|
||||||
// Check the merkle root.
|
// Check the merkle root.
|
||||||
if (fCheckMerkleRoot) {
|
if (fCheckMerkleRoot) {
|
||||||
bool mutated;
|
bool mutated;
|
||||||
@@ -3703,8 +3740,11 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
|
|||||||
pindex = miSelf->second;
|
pindex = miSelf->second;
|
||||||
if (ppindex)
|
if (ppindex)
|
||||||
*ppindex = pindex;
|
*ppindex = pindex;
|
||||||
if (pindex != 0 && pindex->nStatus & BLOCK_FAILED_MASK)
|
if ( pindex != 0 && pindex->nStatus & BLOCK_FAILED_MASK )
|
||||||
|
{
|
||||||
|
komodo_reverify_blockcheck(state,pindex->nHeight,pindex);
|
||||||
return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate");
|
return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate");
|
||||||
|
}
|
||||||
if ( pindex != 0 && IsInitialBlockDownload() == 0 ) // jl777 debug test
|
if ( pindex != 0 && IsInitialBlockDownload() == 0 ) // jl777 debug test
|
||||||
{
|
{
|
||||||
if (!CheckBlockHeader(pindex->nHeight,pindex, block, state))
|
if (!CheckBlockHeader(pindex->nHeight,pindex, block, state))
|
||||||
@@ -3734,11 +3774,10 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
|
|||||||
if (!ContextualCheckBlockHeader(block, state, pindexPrev))
|
if (!ContextualCheckBlockHeader(block, state, pindexPrev))
|
||||||
{
|
{
|
||||||
pindex->nStatus |= BLOCK_FAILED_MASK;
|
pindex->nStatus |= BLOCK_FAILED_MASK;
|
||||||
fprintf(stderr,"known block.%d failing ContextualCheckBlockHeader\n",(int32_t)pindex->nHeight);
|
//fprintf(stderr,"known block.%d failing ContextualCheckBlockHeader\n",(int32_t)pindex->nHeight);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3776,7 +3815,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
|
|||||||
return false;
|
return false;
|
||||||
if ( pindex == 0 )
|
if ( pindex == 0 )
|
||||||
{
|
{
|
||||||
fprintf(stderr,"AcceptBlock error null pindex\n");
|
//fprintf(stderr,"AcceptBlock error null pindex\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Try to process all requested blocks that we don't have, but only
|
// Try to process all requested blocks that we don't have, but only
|
||||||
@@ -3863,9 +3902,12 @@ bool ProcessNewBlock(int32_t height,CValidationState &state, CNode* pfrom, CBloc
|
|||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
bool fRequested = MarkBlockAsReceived(pblock->GetHash());
|
bool fRequested = MarkBlockAsReceived(pblock->GetHash());
|
||||||
fRequested |= fForceProcessing;
|
fRequested |= fForceProcessing;
|
||||||
if (!checked) {
|
if (!checked)
|
||||||
|
{
|
||||||
if ( pfrom != 0 )
|
if ( pfrom != 0 )
|
||||||
|
{
|
||||||
Misbehaving(pfrom->GetId(), 1);
|
Misbehaving(pfrom->GetId(), 1);
|
||||||
|
}
|
||||||
return error("%s: CheckBlock FAILED", __func__);
|
return error("%s: CheckBlock FAILED", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4040,6 +4082,7 @@ bool CheckDiskSpace(uint64_t nAdditionalBytes)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly)
|
FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly)
|
||||||
{
|
{
|
||||||
static int32_t didinit[1000]; long fsize,fpos; int32_t incr = 16*1024*1024;
|
static int32_t didinit[1000]; long fsize,fpos; int32_t incr = 16*1024*1024;
|
||||||
@@ -4117,6 +4160,8 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
|
|||||||
return pindexNew;
|
return pindexNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//void komodo_pindex_init(CBlockIndex *pindex,int32_t height);
|
||||||
|
|
||||||
bool static LoadBlockIndexDB()
|
bool static LoadBlockIndexDB()
|
||||||
{
|
{
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
@@ -4132,6 +4177,7 @@ bool static LoadBlockIndexDB()
|
|||||||
{
|
{
|
||||||
CBlockIndex* pindex = item.second;
|
CBlockIndex* pindex = item.second;
|
||||||
vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
|
vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
|
||||||
|
//komodo_pindex_init(pindex,(int32_t)pindex->nHeight);
|
||||||
}
|
}
|
||||||
sort(vSortedByHeight.begin(), vSortedByHeight.end());
|
sort(vSortedByHeight.begin(), vSortedByHeight.end());
|
||||||
BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
|
BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
|
||||||
@@ -4180,6 +4226,7 @@ bool static LoadBlockIndexDB()
|
|||||||
pindex->BuildSkip();
|
pindex->BuildSkip();
|
||||||
if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == NULL || CBlockIndexWorkComparator()(pindexBestHeader, pindex)))
|
if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == NULL || CBlockIndexWorkComparator()(pindexBestHeader, pindex)))
|
||||||
pindexBestHeader = pindex;
|
pindexBestHeader = pindex;
|
||||||
|
//komodo_pindex_init(pindex,(int32_t)pindex->nHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load block file info
|
// Load block file info
|
||||||
@@ -4208,6 +4255,7 @@ bool static LoadBlockIndexDB()
|
|||||||
if (pindex->nStatus & BLOCK_HAVE_DATA) {
|
if (pindex->nStatus & BLOCK_HAVE_DATA) {
|
||||||
setBlkDataFiles.insert(pindex->nFile);
|
setBlkDataFiles.insert(pindex->nFile);
|
||||||
}
|
}
|
||||||
|
//komodo_pindex_init(pindex,(int32_t)pindex->nHeight);
|
||||||
}
|
}
|
||||||
for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++)
|
for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++)
|
||||||
{
|
{
|
||||||
@@ -4243,6 +4291,7 @@ bool static LoadBlockIndexDB()
|
|||||||
if (pindex->pprev) {
|
if (pindex->pprev) {
|
||||||
pindex->pprev->hashAnchorEnd = pindex->hashAnchor;
|
pindex->pprev->hashAnchorEnd = pindex->hashAnchor;
|
||||||
}
|
}
|
||||||
|
//komodo_pindex_init(pindex,(int32_t)pindex->nHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load pointer to end of best chain
|
// Load pointer to end of best chain
|
||||||
@@ -4458,6 +4507,12 @@ bool RewindBlockIndex(const CChainParams& params)
|
|||||||
pindexIter->nSequenceId = 0;
|
pindexIter->nSequenceId = 0;
|
||||||
// Make sure it gets written
|
// Make sure it gets written
|
||||||
setDirtyBlockIndex.insert(pindexIter);
|
setDirtyBlockIndex.insert(pindexIter);
|
||||||
|
if (pindexIter == pindexBestInvalid)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Reset invalid block marker if it was pointing to this block\n");
|
||||||
|
pindexBestInvalid = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Update indices
|
// Update indices
|
||||||
setBlockIndexCandidates.erase(pindexIter);
|
setBlockIndexCandidates.erase(pindexIter);
|
||||||
auto ret = mapBlocksUnlinked.equal_range(pindexIter->pprev);
|
auto ret = mapBlocksUnlinked.equal_range(pindexIter->pprev);
|
||||||
@@ -5699,7 +5754,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
}
|
}
|
||||||
if (!AcceptBlockHeader(header, state, &pindexLast)) {
|
if (!AcceptBlockHeader(header, state, &pindexLast)) {
|
||||||
int nDoS;
|
int nDoS;
|
||||||
if (state.IsInvalid(nDoS)) {
|
if (state.IsInvalid(nDoS))
|
||||||
|
{
|
||||||
if (nDoS > 0)
|
if (nDoS > 0)
|
||||||
Misbehaving(pfrom->GetId(), nDoS/nDoS);
|
Misbehaving(pfrom->GetId(), nDoS/nDoS);
|
||||||
return error("invalid header received");
|
return error("invalid header received");
|
||||||
@@ -6379,9 +6435,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CBlockFileInfo::ToString() const {
|
std::string CBlockFileInfo::ToString() const {
|
||||||
return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast));
|
return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user