Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions qa/rpc-tests/test_framework/mininode.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,25 @@ def sha256(s):
def ripemd160(s):
return hashlib.new('ripemd160', s).digest()

def hash160(s):
return ripemd160(sha256(s))

def hash256(s):
return sha256(sha256(s))

def upgrade_160_hash_to_256(algo):
def algowrapper(s):
return algo(s) + (b'\0' * 12)
return algowrapper

powalgos = (sha256, hash256, upgrade_160_hash_to_256(ripemd160), upgrade_160_hash_to_256(hash160))
def powhash(s, nTime):
if nTime < 1296688603:
algo = hash256
else:
algo = powalgos[int(nTime / 3600) % len(powalgos)]
return algo(s)

def ser_compact_size(l):
r = b""
if l < 253:
Expand Down Expand Up @@ -577,8 +593,9 @@ def calc_sha256(self):
r += struct.pack("<I", self.nTime)
r += struct.pack("<I", self.nBits)
r += struct.pack("<I", self.nNonce)
self.sha256 = uint256_from_str(hash256(r))
self.hash = encode(hash256(r)[::-1], 'hex_codec').decode('ascii')
rawhash = powhash(r, self.nTime)
self.sha256 = uint256_from_str(rawhash)
self.hash = encode(rawhash[::-1], 'hex_codec').decode('ascii')

def rehash(self):
self.sha256 = None
Expand Down
2 changes: 1 addition & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,6 @@ libbitcoin_consensus_a_SOURCES = \
hash.cpp \
hash.h \
prevector.h \
primitives/block.cpp \
primitives/block.h \
primitives/transaction.cpp \
primitives/transaction.h \
Expand Down Expand Up @@ -306,6 +305,7 @@ libbitcoin_common_a_SOURCES = \
keystore.cpp \
netaddress.cpp \
netbase.cpp \
primitives/block.cpp \
protocol.cpp \
scheduler.cpp \
script/sign.cpp \
Expand Down
22 changes: 22 additions & 0 deletions src/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "chain.h"
#include "chainparams.h"
#include "consensus/params.h"

/**
* CChain implementation
Expand Down Expand Up @@ -111,6 +113,26 @@ const CBlockIndex* CBlockIndex::GetAncestor(int height) const
return const_cast<CBlockIndex*>(this)->GetAncestor(height);
}

int64_t CBlockIndex::GetEarliestNextBlockTime(const Consensus::Params& consensusParams) const
{
int64_t nMinTime = GetMedianTimePast() + 1;
int64_t nMaxTime = GetBlockTime();
const auto current_pow_algo = consensusParams.PowAlgorithmForTime(nMaxTime);
if (nMinTime < nMaxTime && current_pow_algo != consensusParams.PowAlgorithmForTime(nMinTime)) {
int64_t nTryTime;
++nMinTime;
while (nMinTime < nMaxTime) {
nTryTime = nMinTime + ((nMaxTime - nMinTime) / 2);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) May be more readable as nTryTime = (nMinTime + nMaxTime) / 2;

if (current_pow_algo != consensusParams.PowAlgorithmForTime(nTryTime)) {
nMinTime = nTryTime + 1;
} else {
nMaxTime = nTryTime - 1;
}
}
}
return nMinTime;
}

void CBlockIndex::BuildSkip()
{
if (pprev)
Expand Down
2 changes: 2 additions & 0 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ class CBlockIndex
return pbegin[(pend - pbegin)/2];
}

int64_t GetEarliestNextBlockTime(const Consensus::Params&) const;

std::string ToString() const
{
return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
Expand Down
16 changes: 13 additions & 3 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ class CMainParams : public CChainParams {
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000003f94d1ad391682fe038bf5");

consensus.HardforkTime = std::numeric_limits<int64_t>::max();
consensus.nPowChangeTargetShift = 20;

// By default assume that the signatures in ancestors of this block are valid.
consensus.defaultAssumeValid = uint256S("0x00000000000000000013176bf8d7dfeab4e1db31dc93bc311b436e82ab226b90"); //453354

Expand All @@ -115,7 +118,7 @@ class CMainParams : public CChainParams {
nPruneAfterHeight = 100000;

genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
consensus.hashGenesisBlock = genesis.GetHash(consensus);
assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));

Expand Down Expand Up @@ -203,6 +206,9 @@ class CTestNetParams : public CChainParams {
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000001f057509eba81aed91");

consensus.HardforkTime = std::numeric_limits<int64_t>::max();
consensus.nPowChangeTargetShift = 20;

// By default assume that the signatures in ancestors of this block are valid.
consensus.defaultAssumeValid = uint256S("0x00000000000128796ee387cf110ccb9d2f36cffaf7f73079c995377c65ac0dcc"); //1079274

Expand All @@ -214,7 +220,7 @@ class CTestNetParams : public CChainParams {
nPruneAfterHeight = 1000;

genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
consensus.hashGenesisBlock = genesis.GetHash(consensus);
assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));

Expand Down Expand Up @@ -288,6 +294,10 @@ class CRegTestParams : public CChainParams {
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");

consensus.HardforkTime = 1296688603; // Just past the genesis block
consensus.PowChangeAlgo = HashAlgorithm::NUM_HASH_ALGOS;
consensus.nPowChangeTargetShift = 20;

// By default assume that the signatures in ancestors of this block are valid.
consensus.defaultAssumeValid = uint256S("0x00");

Expand All @@ -299,7 +309,7 @@ class CRegTestParams : public CChainParams {
nPruneAfterHeight = 1000;

genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
consensus.hashGenesisBlock = genesis.GetHash(consensus);
assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));

Expand Down
18 changes: 18 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#ifndef BITCOIN_CONSENSUS_PARAMS_H
#define BITCOIN_CONSENSUS_PARAMS_H

#include "hash.h"
#include "uint256.h"
#include <map>
#include <string>
Expand Down Expand Up @@ -62,6 +63,23 @@ struct Params {
int64_t nPowTargetTimespan;
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
uint256 nMinimumChainWork;

/** Hardfork parameters */
int64_t HardforkTime;
HashAlgorithm PowChangeAlgo;
int nPowChangeTargetShift;
HashAlgorithm PowAlgorithmForTime(int64_t nTime) const {
if (nTime >= HardforkTime) {
if (PowChangeAlgo == HashAlgorithm::NUM_HASH_ALGOS) {
// Indicates a rotating hash algo, for testing
return (HashAlgorithm)((nTime / 3600) % (unsigned int)HashAlgorithm::NUM_HASH_ALGOS);
}
return PowChangeAlgo;
} else {
return HashAlgorithm::SHA256d;
}
}

uint256 defaultAssumeValid;
};
} // namespace Consensus
Expand Down
8 changes: 8 additions & 0 deletions src/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@

#include <vector>

enum class HashAlgorithm: unsigned int {
SHA256,
SHA256d,
RIPEMD160,
HASH160,
NUM_HASH_ALGOS,
};

typedef uint256 ChainCode;

/** A hasher class for Bitcoin's 256-bit hash (double SHA-256). */
Expand Down
2 changes: 1 addition & 1 deletion src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class ScoreCompare
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
int64_t nOldTime = pblock->nTime;
int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
int64_t nNewTime = std::max(pindexPrev->GetEarliestNextBlockTime(consensusParams), GetAdjustedTime());

if (nOldTime < nNewTime)
pblock->nTime = nNewTime;
Expand Down
35 changes: 26 additions & 9 deletions src/pow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
if (pindexLast == NULL)
return nProofOfWorkLimit;

uint32_t nBits;

// Only change once per difficulty adjustment interval
if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
{
Expand All @@ -30,23 +32,38 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
return nProofOfWorkLimit;
else
{
// Return the last non-special-min-difficulty-rules-block
// Look back to the last non-special-min-difficulty-rules-block
const CBlockIndex* pindex = pindexLast;
while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit)
pindex = pindex->pprev;
return pindex->nBits;
nBits = pindex->nBits;
}
} else {
nBits = pindexLast->nBits;
}
return pindexLast->nBits;
} else {
// Go back by what we want to be 14 days worth of blocks
int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) Would this be more readable as pindexLast->nHeight + 1 - params.DifficultyAdjustmentInterval() or is it intentionally considering just 2015 of the 2016 blocks?

assert(nHeightFirst >= 0);
const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
assert(pindexFirst);

nBits = CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
}

// Go back by what we want to be 14 days worth of blocks
int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1);
assert(nHeightFirst >= 0);
const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
assert(pindexFirst);
if (params.PowAlgorithmForTime(pblock->nTime) != params.PowAlgorithmForTime(pindexLast->nTime)) {
// Adjust target for PoW change
arith_uint256 bnNew;
bnNew.SetCompact(nBits);
bnNew <<= params.nPowChangeTargetShift;
const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
if (bnNew > bnPowLimit) {
bnNew = bnPowLimit;
}
nBits = bnNew.GetCompact();
}

return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
return nBits;
}

unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
Expand Down
38 changes: 37 additions & 1 deletion src/primitives/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,47 @@
#include "hash.h"
#include "tinyformat.h"
#include "utilstrencodings.h"
#include "chainparams.h"
#include "consensus/params.h"
#include "crypto/common.h"
#include "streams.h"

#include <cstdlib>

uint256 CBlockHeader::GetHash(const Consensus::Params& consensusParams) const
{
CDataStream ss(SER_GETHASH, PROTOCOL_VERSION);
ss << *this;

const auto pbegin = (const unsigned char *)&ss.begin()[0];
uint256 hash;

const HashAlgorithm algo = consensusParams.PowAlgorithmForTime(nTime);
switch (algo) {
case HashAlgorithm::SHA256:
CSHA256().Write(pbegin, ss.size()).Finalize((unsigned char*)&hash);
break;
case HashAlgorithm::SHA256d:
CHash256().Write(pbegin, ss.size()).Finalize((unsigned char*)&hash);
break;
case HashAlgorithm::RIPEMD160:
CRIPEMD160().Write(pbegin, ss.size()).Finalize((unsigned char*)&hash);
break;
case HashAlgorithm::HASH160:
CHash160().Write(pbegin, ss.size()).Finalize((unsigned char*)&hash);
break;
case HashAlgorithm::NUM_HASH_ALGOS:
// Should be impossible
abort();
}

return hash;
}

uint256 CBlockHeader::GetHash() const
{
return SerializeHash(*this);
const Consensus::Params& consensusParams = Params().GetConsensus();
return GetHash(consensusParams);
}

std::string CBlock::ToString() const
Expand Down
5 changes: 5 additions & 0 deletions src/primitives/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
#include "serialize.h"
#include "uint256.h"

namespace Consensus {
struct Params;
}

/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
* requirements. When they solve the proof-of-work, they broadcast the block
Expand Down Expand Up @@ -60,6 +64,7 @@ class CBlockHeader
return (nBits == 0);
}

uint256 GetHash(const Consensus::Params&) const;
uint256 GetHash() const;

int64_t GetBlockTime() const
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue));
result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)));
result.push_back(Pair("target", hashTarget.GetHex()));
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetEarliestNextBlockTime(consensusParams)));
result.push_back(Pair("mutable", aMutable));
result.push_back(Pair("noncerange", "00000000ffffffff"));
int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST;
Expand Down
6 changes: 4 additions & 2 deletions src/test/miner_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "coins.h"
#include "consensus/consensus.h"
#include "consensus/merkle.h"
#include "consensus/params.h"
#include "consensus/validation.h"
#include "validation.h"
#include "miner.h"
Expand Down Expand Up @@ -187,6 +188,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
// Note that by default, these tests run with size accounting enabled.
const CChainParams& chainparams = Params(CBaseChainParams::MAIN);
const Consensus::Params& consensusParams = chainparams.GetConsensus();
CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
std::unique_ptr<CBlockTemplate> pblocktemplate;
CMutableTransaction tx,tx2;
Expand All @@ -211,7 +213,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
pblock->nVersion = 1;
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
pblock->nTime = chainActive.Tip()->GetEarliestNextBlockTime(consensusParams);
CMutableTransaction txCoinbase(*pblock->vtx[0]);
txCoinbase.nVersion = 1;
txCoinbase.vin[0].scriptSig = CScript();
Expand Down Expand Up @@ -393,7 +395,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
}

// non-final txs in mempool
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);
SetMockTime(chainActive.Tip()->GetEarliestNextBlockTime(consensusParams));
int flags = LOCKTIME_VERIFY_SEQUENCE|LOCKTIME_MEDIAN_TIME_PAST;
// height map
std::vector<int> prevheights;
Expand Down
Loading