Merge branch 'master' into replay-protection
This commit is contained in:
commit
94a1db4294
54
README.md
54
README.md
|
@ -35,7 +35,16 @@ Install:
|
||||||
```
|
```
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
Get dependencies:
|
There are two proven ways to build BTCP for Windows:
|
||||||
|
|
||||||
|
* On Linux using [Mingw-w64](https://mingw-w64.org/doku.php) cross compiler tool chain. Ubuntu 16.04 Xenial is proven to work and the instructions is for such release.
|
||||||
|
* On Windows 10 (64-bit version) using [Windows Subsystem for Linux (WSL)](https://msdn.microsoft.com/commandline/wsl/about) and Mingw-w64 cross compiler tool chain.
|
||||||
|
|
||||||
|
With Windows 10, Microsoft released a feature called WSL. It basically allows you to run a bash shell directly on Windows in an ubuntu environment. WSL can be installed with other Linux variants, but as mentioned before, the distro proven to work is Ubuntu.
|
||||||
|
Follow this [link](https://msdn.microsoft.com/en-us/commandline/wsl/install_guide) for installing WSL first
|
||||||
|
|
||||||
|
### Building for Windows 64-Bit
|
||||||
|
1. Get the usual dependencies:
|
||||||
```{r, engine='bash'}
|
```{r, engine='bash'}
|
||||||
sudo apt-get install \
|
sudo apt-get install \
|
||||||
build-essential pkg-config libc6-dev m4 g++-multilib \
|
build-essential pkg-config libc6-dev m4 g++-multilib \
|
||||||
|
@ -43,12 +52,45 @@ sudo apt-get install \
|
||||||
zlib1g-dev wget bsdmainutils automake mingw-w64
|
zlib1g-dev wget bsdmainutils automake mingw-w64
|
||||||
```
|
```
|
||||||
|
|
||||||
Install (Cross-Compiled, building on Windows is not supported yet):
|
2. Set the default ming32 gcc/g++ compiler option to posix, fix problem with packages in Xenial
|
||||||
|
|
||||||
```{r, engine='bash'}
|
```{r, engine='bash'}
|
||||||
# Build
|
sudo update-alternatives --config x86_64-w64-mingw32-gcc
|
||||||
|
sudo update-alternatives --config x86_64-w64-mingw32-g++
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Install Rust
|
||||||
|
```{r, engine='bash'}
|
||||||
|
curl https://sh.rustup.rs -sSf | sh
|
||||||
|
source ~/.cargo/env
|
||||||
|
rustup install stable-x86_64-unknown-linux-gnu
|
||||||
|
rustup install stable-x86_64-pc-windows-gnu
|
||||||
|
rustup target add x86_64-pc-windows-gnu
|
||||||
|
vi ~/.cargo/config
|
||||||
|
```
|
||||||
|
and add:
|
||||||
|
```
|
||||||
|
[target.x86_64-pc-windows-gnu]
|
||||||
|
linker = "/usr/bin/x86_64-w64-mingw32-gcc"
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that in WSL, the BTCPrivate source code must be somewhere in the default mount file system. i.e /usr/src/BTCPrivate, and not on /mnt/d/. What this means is that you cannot build directly on the windows system
|
||||||
|
|
||||||
|
4. Build for Windows
|
||||||
|
|
||||||
|
```{r, engine='bash'}
|
||||||
|
PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var
|
||||||
./btcputil/build-win.sh -j$(nproc)
|
./btcputil/build-win.sh -j$(nproc)
|
||||||
```
|
```
|
||||||
The exe will save to `src` which you can then move to a windows machine
|
|
||||||
|
5. Installation
|
||||||
|
|
||||||
|
After building in WSL, you can make a copy of the compiled executables to a directory on your Windows file system. This is done the following way
|
||||||
|
|
||||||
|
```{r, engine='bash'}
|
||||||
|
make install DESTDIR=/mnt/c/btcp/BTCPrivate
|
||||||
|
```
|
||||||
|
This will install the executables to `c:\btcp\BTCPrivate
|
||||||
|
|
||||||
### Mac
|
### Mac
|
||||||
Get dependencies:
|
Get dependencies:
|
||||||
|
@ -72,6 +114,10 @@ Install:
|
||||||
./src/btcpd
|
./src/btcpd
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Additional notes
|
||||||
|
|
||||||
|
If you plan to build for windows and linux at the same time, be sure to delete all the built files for whatever you build first. An easy way to do this is by taking the binaries out of the repo, delete all files except the .git folder and then do a git hard reset.
|
||||||
|
|
||||||
About
|
About
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,21 @@ $(package)_download_file=$($(package)_git_commit).tar.gz
|
||||||
$(package)_sha256_hash=a5760a90d4a1045c8944204f29fa2a3cf2f800afee400f88bf89bbfe2cce1279
|
$(package)_sha256_hash=a5760a90d4a1045c8944204f29fa2a3cf2f800afee400f88bf89bbfe2cce1279
|
||||||
$(package)_git_commit=91348647a86201a9482ad4ad68398152dc3d635e
|
$(package)_git_commit=91348647a86201a9482ad4ad68398152dc3d635e
|
||||||
$(package)_dependencies=rust
|
$(package)_dependencies=rust
|
||||||
|
ifeq ($(host_os),mingw32)
|
||||||
|
rust_build=cargo build --release --lib --target="x86_64-pc-windows-gnu"
|
||||||
|
rust_target=target/x86_64-pc-windows-gnu/release/rustzcash.lib $($(package)_staging_dir)$(host_prefix)/lib/librustzcash.a
|
||||||
|
else
|
||||||
|
rust_build=cargo build --release
|
||||||
|
rust_target=target/release/librustzcash.a $($(package)_staging_dir)$(host_prefix)/lib/
|
||||||
|
endif
|
||||||
|
|
||||||
define $(package)_build_cmds
|
define $(package)_build_cmds
|
||||||
cargo build --release
|
$(rust_build)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define $(package)_stage_cmds
|
define $(package)_stage_cmds
|
||||||
mkdir $($(package)_staging_dir)$(host_prefix)/lib/ && \
|
mkdir $($(package)_staging_dir)$(host_prefix)/lib/ && \
|
||||||
mkdir $($(package)_staging_dir)$(host_prefix)/include/ && \
|
mkdir $($(package)_staging_dir)$(host_prefix)/include/ && \
|
||||||
cp target/release/librustzcash.a $($(package)_staging_dir)$(host_prefix)/lib/ && \
|
cp $(rust_target) && \
|
||||||
cp include/librustzcash.h $($(package)_staging_dir)$(host_prefix)/include/
|
cp include/librustzcash.h $($(package)_staging_dir)$(host_prefix)/include/
|
||||||
endef
|
endef
|
|
@ -5,7 +5,9 @@ $(package)_file_name_linux=rust-$($(package)_version)-x86_64-unknown-linux-gnu.t
|
||||||
$(package)_sha256_hash_linux=48621912c242753ba37cad5145df375eeba41c81079df46f93ffb4896542e8fd
|
$(package)_sha256_hash_linux=48621912c242753ba37cad5145df375eeba41c81079df46f93ffb4896542e8fd
|
||||||
$(package)_file_name_darwin=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz
|
$(package)_file_name_darwin=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz
|
||||||
$(package)_sha256_hash_darwin=2d08259ee038d3a2c77a93f1a31fc59e7a1d6d1bbfcba3dba3c8213b2e5d1926
|
$(package)_sha256_hash_darwin=2d08259ee038d3a2c77a93f1a31fc59e7a1d6d1bbfcba3dba3c8213b2e5d1926
|
||||||
|
$(package)_file_name_mingw32=rust-$($(package)_version)-x86_64-pc-windows-gnu.tar.gz
|
||||||
|
$(package)_sha256_hash_mingw32=523cd248363afdc4e2c0e1f219607897b6925294a33154d7e67224addfd15eb0
|
||||||
|
|
||||||
define $(package)_stage_cmds
|
define $(package)_stage_cmds
|
||||||
./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig
|
./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig
|
||||||
endef
|
endef
|
|
@ -58,6 +58,7 @@ testScriptsExt=(
|
||||||
'smartfees.py'
|
'smartfees.py'
|
||||||
'maxblocksinflight.py'
|
'maxblocksinflight.py'
|
||||||
'invalidblockrequest.py'
|
'invalidblockrequest.py'
|
||||||
|
'p2p-versionbits-warning.py'
|
||||||
# 'forknotify.py'
|
# 'forknotify.py'
|
||||||
'p2p-acceptblock.py'
|
'p2p-acceptblock.py'
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
#!/usr/bin/env python2
|
||||||
|
# Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
# Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
#
|
||||||
|
|
||||||
|
from test_framework.mininode import *
|
||||||
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
from test_framework.util import *
|
||||||
|
import time
|
||||||
|
from test_framework.blocktools import create_block, create_coinbase
|
||||||
|
|
||||||
|
'''
|
||||||
|
Test version bits' warning system.
|
||||||
|
|
||||||
|
Generate chains with block versions that appear to be signalling unknown
|
||||||
|
soft-forks, and test that warning alerts are generated.
|
||||||
|
'''
|
||||||
|
|
||||||
|
VB_PERIOD = 144 # versionbits period length for regtest
|
||||||
|
VB_THRESHOLD = 108 # versionbits activation threshold for regtest
|
||||||
|
VB_TOP_BITS = 0x20000000
|
||||||
|
VB_UNKNOWN_BIT = 27 # Choose a bit unassigned to any deployment
|
||||||
|
|
||||||
|
# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending
|
||||||
|
# p2p messages to a node, generating the messages in the main testing logic.
|
||||||
|
class TestNode(NodeConnCB):
|
||||||
|
def __init__(self):
|
||||||
|
NodeConnCB.__init__(self)
|
||||||
|
self.connection = None
|
||||||
|
self.ping_counter = 1
|
||||||
|
self.last_pong = msg_pong()
|
||||||
|
|
||||||
|
def add_connection(self, conn):
|
||||||
|
self.connection = conn
|
||||||
|
|
||||||
|
def on_inv(self, conn, message):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Wrapper for the NodeConn's send_message function
|
||||||
|
def send_message(self, message):
|
||||||
|
self.connection.send_message(message)
|
||||||
|
|
||||||
|
def on_pong(self, conn, message):
|
||||||
|
self.last_pong = message
|
||||||
|
|
||||||
|
# Sync up with the node after delivery of a block
|
||||||
|
def sync_with_ping(self, timeout=30):
|
||||||
|
self.connection.send_message(msg_ping(nonce=self.ping_counter))
|
||||||
|
received_pong = False
|
||||||
|
sleep_time = 0.05
|
||||||
|
while not received_pong and timeout > 0:
|
||||||
|
time.sleep(sleep_time)
|
||||||
|
timeout -= sleep_time
|
||||||
|
with mininode_lock:
|
||||||
|
if self.last_pong.nonce == self.ping_counter:
|
||||||
|
received_pong = True
|
||||||
|
self.ping_counter += 1
|
||||||
|
return received_pong
|
||||||
|
|
||||||
|
|
||||||
|
class VersionBitsWarningTest(BitcoinTestFramework):
|
||||||
|
def setup_chain(self):
|
||||||
|
initialize_chain_clean(self.options.tmpdir, 1)
|
||||||
|
|
||||||
|
def setup_network(self):
|
||||||
|
self.nodes = []
|
||||||
|
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
|
||||||
|
# Open and close to create zero-length file
|
||||||
|
with open(self.alert_filename, 'w') as f:
|
||||||
|
pass
|
||||||
|
self.node_options = ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]
|
||||||
|
self.nodes.append(start_node(0, self.options.tmpdir, self.node_options))
|
||||||
|
|
||||||
|
import re
|
||||||
|
self.vb_pattern = re.compile("^Warning.*versionbit")
|
||||||
|
|
||||||
|
# Send numblocks blocks via peer with nVersionToUse set.
|
||||||
|
def send_blocks_with_version(self, peer, numblocks, nVersionToUse):
|
||||||
|
tip = self.nodes[0].getbestblockhash()
|
||||||
|
height = self.nodes[0].getblockcount()
|
||||||
|
block_time = self.nodes[0].getblockheader(tip)["time"]+1
|
||||||
|
tip = int(tip, 16)
|
||||||
|
|
||||||
|
for i in xrange(numblocks):
|
||||||
|
block = create_block(tip, create_coinbase(height+1), block_time)
|
||||||
|
block.nVersion = nVersionToUse
|
||||||
|
block.solve()
|
||||||
|
peer.send_message(msg_block(block))
|
||||||
|
block_time += 1
|
||||||
|
height += 1
|
||||||
|
tip = block.sha256
|
||||||
|
peer.sync_with_ping()
|
||||||
|
|
||||||
|
def test_versionbits_in_alert_file(self):
|
||||||
|
with open(self.alert_filename, 'r') as f:
|
||||||
|
alert_text = f.read()
|
||||||
|
assert(self.vb_pattern.match(alert_text))
|
||||||
|
|
||||||
|
def run_test(self):
|
||||||
|
# Setup the p2p connection and start up the network thread.
|
||||||
|
test_node = TestNode()
|
||||||
|
|
||||||
|
connections = []
|
||||||
|
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node))
|
||||||
|
test_node.add_connection(connections[0])
|
||||||
|
|
||||||
|
NetworkThread().start() # Start up network handling in another thread
|
||||||
|
|
||||||
|
# Test logic begins here
|
||||||
|
test_node.wait_for_verack()
|
||||||
|
|
||||||
|
# 1. Have the node mine one period worth of blocks
|
||||||
|
self.nodes[0].generate(VB_PERIOD)
|
||||||
|
|
||||||
|
# 2. Now build one period of blocks on the tip, with < VB_THRESHOLD
|
||||||
|
# blocks signaling some unknown bit.
|
||||||
|
nVersion = VB_TOP_BITS | (1<<VB_UNKNOWN_BIT)
|
||||||
|
self.send_blocks_with_version(test_node, VB_THRESHOLD-1, nVersion)
|
||||||
|
|
||||||
|
# Fill rest of period with regular version blocks
|
||||||
|
self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD + 1)
|
||||||
|
# Check that we're not getting any versionbit-related errors in
|
||||||
|
# getinfo()
|
||||||
|
assert(not self.vb_pattern.match(self.nodes[0].getinfo()["errors"]))
|
||||||
|
|
||||||
|
# 3. Now build one period of blocks with >= VB_THRESHOLD blocks signaling
|
||||||
|
# some unknown bit
|
||||||
|
self.send_blocks_with_version(test_node, VB_THRESHOLD, nVersion)
|
||||||
|
self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD)
|
||||||
|
# Might not get a versionbits-related alert yet, as we should
|
||||||
|
# have gotten a different alert due to more than 51/100 blocks
|
||||||
|
# being of unexpected version.
|
||||||
|
# Check that getinfo() shows some kind of error.
|
||||||
|
assert(len(self.nodes[0].getinfo()["errors"]) != 0)
|
||||||
|
|
||||||
|
# Mine a period worth of expected blocks so the generic block-version warning
|
||||||
|
# is cleared, and restart the node. This should move the versionbit state
|
||||||
|
# to ACTIVE.
|
||||||
|
self.nodes[0].generate(VB_PERIOD)
|
||||||
|
stop_node(self.nodes[0], 0)
|
||||||
|
wait_bitcoinds()
|
||||||
|
# Empty out the alert file
|
||||||
|
with open(self.alert_filename, 'w') as f:
|
||||||
|
pass
|
||||||
|
self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""])
|
||||||
|
|
||||||
|
# Connecting one block should be enough to generate an error.
|
||||||
|
self.nodes[0].generate(1)
|
||||||
|
assert(len(self.nodes[0].getinfo()["errors"]) != 0)
|
||||||
|
stop_node(self.nodes[0], 0)
|
||||||
|
wait_bitcoinds()
|
||||||
|
self.test_versionbits_in_alert_file()
|
||||||
|
|
||||||
|
# Test framework expects the node to still be running...
|
||||||
|
self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
VersionBitsWarningTest().main()
|
|
@ -184,6 +184,7 @@ BITCOIN_CORE_H = \
|
||||||
utiltime.h \
|
utiltime.h \
|
||||||
validationinterface.h \
|
validationinterface.h \
|
||||||
version.h \
|
version.h \
|
||||||
|
versionbits.h \
|
||||||
wallet/asyncrpcoperation_sendmany.h \
|
wallet/asyncrpcoperation_sendmany.h \
|
||||||
wallet/crypter.h \
|
wallet/crypter.h \
|
||||||
wallet/db.h \
|
wallet/db.h \
|
||||||
|
@ -240,6 +241,7 @@ libbitcoin_server_a_SOURCES = \
|
||||||
txdb.cpp \
|
txdb.cpp \
|
||||||
txmempool.cpp \
|
txmempool.cpp \
|
||||||
validationinterface.cpp \
|
validationinterface.cpp \
|
||||||
|
versionbits.cpp \
|
||||||
$(BITCOIN_CORE_H) \
|
$(BITCOIN_CORE_H) \
|
||||||
$(LIBZCASH_H)
|
$(LIBZCASH_H)
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ BITCOIN_TESTS =\
|
||||||
test/timedata_tests.cpp \
|
test/timedata_tests.cpp \
|
||||||
test/torcontrol_tests.cpp \
|
test/torcontrol_tests.cpp \
|
||||||
test/transaction_tests.cpp \
|
test/transaction_tests.cpp \
|
||||||
|
test/versionbits_tests.cpp \
|
||||||
test/uint256_tests.cpp \
|
test/uint256_tests.cpp \
|
||||||
test/univalue_tests.cpp \
|
test/univalue_tests.cpp \
|
||||||
test/util_tests.cpp \
|
test/util_tests.cpp \
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
|
||||||
|
|
||||||
struct CDiskBlockPos
|
struct CDiskBlockPos
|
||||||
{
|
{
|
||||||
int nFile;
|
int nFile;
|
||||||
|
|
|
@ -37,7 +37,7 @@ public:
|
||||||
CMainParams() {
|
CMainParams() {
|
||||||
strNetworkID = "main";
|
strNetworkID = "main";
|
||||||
strCurrencyUnits = "BTCP";
|
strCurrencyUnits = "BTCP";
|
||||||
consensus.fCoinbaseMustBeProtected = false;
|
consensus.fCoinbaseMustBeProtected = true;
|
||||||
consensus.nSubsidySlowStartInterval = 2;
|
consensus.nSubsidySlowStartInterval = 2;
|
||||||
consensus.nSubsidyHalvingInterval = 840000;
|
consensus.nSubsidyHalvingInterval = 840000;
|
||||||
consensus.nMajorityEnforceBlockUpgrade = 750;
|
consensus.nMajorityEnforceBlockUpgrade = 750;
|
||||||
|
@ -50,6 +50,14 @@ public:
|
||||||
consensus.nPowMaxAdjustUp = 16; // 16% adjustment up
|
consensus.nPowMaxAdjustUp = 16; // 16% adjustment up
|
||||||
consensus.nPowTargetSpacing = 2.5 * 60;
|
consensus.nPowTargetSpacing = 2.5 * 60;
|
||||||
consensus.fPowAllowMinDifficultyBlocks = false;
|
consensus.fPowAllowMinDifficultyBlocks = false;
|
||||||
|
consensus.nPowDifficultyBombHeight = 600000;
|
||||||
|
|
||||||
|
consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016
|
||||||
|
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
|
||||||
|
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
|
||||||
|
|
||||||
pchMessageStart[0] = 0xa8;
|
pchMessageStart[0] = 0xa8;
|
||||||
pchMessageStart[1] = 0xea;
|
pchMessageStart[1] = 0xea;
|
||||||
|
@ -188,8 +196,12 @@ public:
|
||||||
//// "t3fmYHU2DnVaQgPhDs6TMFVmyC3qbWEWgXN", /* main-index: 52*/
|
//// "t3fmYHU2DnVaQgPhDs6TMFVmyC3qbWEWgXN", /* main-index: 52*/
|
||||||
//// "t3T4WmAp6nrLkJ24iPpGeCe1fSWTPv47ASG", /* main-index: 53*/
|
//// "t3T4WmAp6nrLkJ24iPpGeCe1fSWTPv47ASG", /* main-index: 53*/
|
||||||
//// "t3fP6GrDM4QVwdjFhmCxGNbe7jXXXSDQ5dv", /* main-index: 54*/
|
//// "t3fP6GrDM4QVwdjFhmCxGNbe7jXXXSDQ5dv", /* main-index: 54*/
|
||||||
};
|
};
|
||||||
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
|
assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight());
|
||||||
|
|
||||||
|
//current ZCL height is 200K-300K, this value here is placeholder, it will have to be changed to correct fork block height
|
||||||
|
nForkStartHeight = 1000000;
|
||||||
|
nForkHeightRange = 65000;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static CMainParams mainParams;
|
static CMainParams mainParams;
|
||||||
|
@ -202,17 +214,28 @@ public:
|
||||||
CTestNetParams() {
|
CTestNetParams() {
|
||||||
strNetworkID = "test";
|
strNetworkID = "test";
|
||||||
strCurrencyUnits = "BTCPT";
|
strCurrencyUnits = "BTCPT";
|
||||||
consensus.fCoinbaseMustBeProtected = false;
|
consensus.fCoinbaseMustBeProtected = true;
|
||||||
consensus.nMajorityEnforceBlockUpgrade = 51;
|
consensus.nMajorityEnforceBlockUpgrade = 51;
|
||||||
consensus.nMajorityRejectBlockOutdated = 75;
|
consensus.nMajorityRejectBlockOutdated = 75;
|
||||||
consensus.nMajorityWindow = 400;
|
consensus.nMajorityWindow = 400;
|
||||||
consensus.powLimit = uint256S("07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
consensus.powLimit = uint256S("07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||||
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
|
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
|
||||||
consensus.fPowAllowMinDifficultyBlocks = true;
|
consensus.fPowAllowMinDifficultyBlocks = true;
|
||||||
|
|
||||||
|
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
|
||||||
|
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
|
||||||
|
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
|
||||||
|
|
||||||
|
consensus.nPowDifficultyBombHeight = 600000;
|
||||||
|
|
||||||
pchMessageStart[0] = 0xf6;
|
pchMessageStart[0] = 0xf6;
|
||||||
pchMessageStart[1] = 0x1b;
|
pchMessageStart[1] = 0x1b;
|
||||||
pchMessageStart[2] = 0xf6;
|
pchMessageStart[2] = 0xf6;
|
||||||
pchMessageStart[3] = 0xd6;
|
pchMessageStart[3] = 0xd6;
|
||||||
|
|
||||||
vAlertPubKey = ParseHex("048679fb891b15d0cada9692047fd0ae26ad8bfb83fabddbb50334ee5bc0683294deb410be20513c5af6e7b9cec717ade82b27080ee6ef9a245c36a795ab044bb3");
|
vAlertPubKey = ParseHex("048679fb891b15d0cada9692047fd0ae26ad8bfb83fabddbb50334ee5bc0683294deb410be20513c5af6e7b9cec717ade82b27080ee6ef9a245c36a795ab044bb3");
|
||||||
nDefaultPort = 17933;
|
nDefaultPort = 17933;
|
||||||
nPruneAfterHeight = 1000;
|
nPruneAfterHeight = 1000;
|
||||||
|
@ -300,6 +323,15 @@ public:
|
||||||
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
|
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
|
||||||
consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down
|
consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down
|
||||||
consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up
|
consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up
|
||||||
|
|
||||||
|
consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains
|
||||||
|
consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
|
||||||
|
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL;
|
||||||
|
|
||||||
|
consensus.nPowDifficultyBombHeight = 600000;
|
||||||
|
|
||||||
pchMessageStart[0] = 0xaa;
|
pchMessageStart[0] = 0xaa;
|
||||||
pchMessageStart[1] = 0xe8;
|
pchMessageStart[1] = 0xe8;
|
||||||
pchMessageStart[2] = 0x3f;
|
pchMessageStart[2] = 0x3f;
|
||||||
|
|
|
@ -81,6 +81,9 @@ public:
|
||||||
std::string GetFoundersRewardAddressAtIndex(int i) const;
|
std::string GetFoundersRewardAddressAtIndex(int i) const;
|
||||||
/** Enforce coinbase consensus rule in regtest mode */
|
/** Enforce coinbase consensus rule in regtest mode */
|
||||||
void SetRegTestCoinbaseMustBeProtected() { consensus.fCoinbaseMustBeProtected = true; }
|
void SetRegTestCoinbaseMustBeProtected() { consensus.fCoinbaseMustBeProtected = true; }
|
||||||
|
|
||||||
|
uint64_t ForkStartHeight() const { return nForkStartHeight; };
|
||||||
|
uint64_t ForkHeightRange() const { return nForkHeightRange; };
|
||||||
protected:
|
protected:
|
||||||
CChainParams() {}
|
CChainParams() {}
|
||||||
|
|
||||||
|
@ -106,6 +109,9 @@ protected:
|
||||||
bool fTestnetToBeDeprecatedFieldRPC = false;
|
bool fTestnetToBeDeprecatedFieldRPC = false;
|
||||||
Checkpoints::CCheckpointData checkpointData;
|
Checkpoints::CCheckpointData checkpointData;
|
||||||
std::vector<std::string> vFoundersRewardAddress;
|
std::vector<std::string> vFoundersRewardAddress;
|
||||||
|
|
||||||
|
uint64_t nForkStartHeight;
|
||||||
|
uint64_t nForkHeightRange;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,7 +13,7 @@ static const int32_t MIN_TX_VERSION = 1;
|
||||||
/** The maximum allowed size for a serialized block, in bytes (network rule) */
|
/** The maximum allowed size for a serialized block, in bytes (network rule) */
|
||||||
static const unsigned int MAX_BLOCK_SIZE = 2000000;
|
static const unsigned int MAX_BLOCK_SIZE = 2000000;
|
||||||
/** The maximum allowed number of signature check operations in a block (network rule) */
|
/** The maximum allowed number of signature check operations in a block (network rule) */
|
||||||
static const unsigned int MAX_BLOCK_SIGOPS = 20000;
|
static const unsigned int MAX_BLOCK_SIGOPS = 50000;
|
||||||
/** The maximum size of a transaction (network rule) */
|
/** The maximum size of a transaction (network rule) */
|
||||||
static const unsigned int MAX_TX_SIZE = 100000;
|
static const unsigned int MAX_TX_SIZE = 100000;
|
||||||
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
|
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
|
||||||
|
|
|
@ -9,6 +9,25 @@
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
|
|
||||||
namespace Consensus {
|
namespace Consensus {
|
||||||
|
|
||||||
|
enum DeploymentPos
|
||||||
|
{
|
||||||
|
DEPLOYMENT_TESTDUMMY,
|
||||||
|
MAX_VERSION_BITS_DEPLOYMENTS
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct for each individual consensus rule change using BIP9.
|
||||||
|
*/
|
||||||
|
struct BIP9Deployment {
|
||||||
|
/** Bit position to select the particular bit in nVersion. */
|
||||||
|
int bit;
|
||||||
|
/** Start MedianTime for version bits miner confirmation. Can be a date in the past */
|
||||||
|
int64_t nStartTime;
|
||||||
|
/** Timeout/expiry MedianTime for the deployment attempt. */
|
||||||
|
int64_t nTimeout;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameters that influence chain consensus.
|
* Parameters that influence chain consensus.
|
||||||
*/
|
*/
|
||||||
|
@ -40,6 +59,16 @@ struct Params {
|
||||||
int nMajorityEnforceBlockUpgrade;
|
int nMajorityEnforceBlockUpgrade;
|
||||||
int nMajorityRejectBlockOutdated;
|
int nMajorityRejectBlockOutdated;
|
||||||
int nMajorityWindow;
|
int nMajorityWindow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimum blocks including miner confirmation of the total of 2016 blocks in a retargetting period,
|
||||||
|
* (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments.
|
||||||
|
* Examples: 1916 for 95%, 1512 for testchains.
|
||||||
|
*/
|
||||||
|
uint32_t nRuleChangeActivationThreshold;
|
||||||
|
uint32_t nMinerConfirmationWindow;
|
||||||
|
BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS];
|
||||||
|
|
||||||
/** Proof of work parameters */
|
/** Proof of work parameters */
|
||||||
uint256 powLimit;
|
uint256 powLimit;
|
||||||
bool fPowAllowMinDifficultyBlocks;
|
bool fPowAllowMinDifficultyBlocks;
|
||||||
|
@ -47,9 +76,10 @@ struct Params {
|
||||||
int64_t nPowMaxAdjustDown;
|
int64_t nPowMaxAdjustDown;
|
||||||
int64_t nPowMaxAdjustUp;
|
int64_t nPowMaxAdjustUp;
|
||||||
int64_t nPowTargetSpacing;
|
int64_t nPowTargetSpacing;
|
||||||
int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; }
|
|
||||||
int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; }
|
int64_t AveragingWindowTimespan(bool isFork = false) const { return nPowAveragingWindow * nPowTargetSpacing / (isFork ? 20 : 1); }
|
||||||
int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; }
|
int64_t MinActualTimespan(bool isFork = false) const { return (AveragingWindowTimespan(isFork) * (100 - nPowMaxAdjustUp )) / 100; }
|
||||||
|
int64_t MaxActualTimespan(bool isFork = false) const { return (AveragingWindowTimespan(isFork) * (100 + nPowMaxAdjustDown)) / 100; }
|
||||||
};
|
};
|
||||||
} // namespace Consensus
|
} // namespace Consensus
|
||||||
|
|
||||||
|
|
|
@ -490,7 +490,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||||
strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
|
strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
|
||||||
strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE));
|
strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE));
|
||||||
if (GetBoolArg("-help-debug", false))
|
if (GetBoolArg("-help-debug", false))
|
||||||
strUsage += HelpMessageOpt("-blockversion=<n>", strprintf("Override block version to test forking scenarios (default: %d)", (int)CBlock::CURRENT_VERSION));
|
strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios");
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
#ifdef FORK_CB_INPUT
|
||||||
strUsage += HelpMessageGroup(_("Fork :"));
|
strUsage += HelpMessageGroup(_("Fork :"));
|
||||||
|
@ -898,8 +898,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
#ifdef FORK_CB_INPUT
|
||||||
forkUtxoPath = GetArg("-utxo-path", "");
|
forkUtxoPath = GetArg("-utxo-path", "");
|
||||||
forkStartHeight = GetArg("-fork-startheight", FORK_BLOCK_HEIGHT_START);
|
forkStartHeight = GetArg("-fork-startheight", chainparams.ForkStartHeight());
|
||||||
forkHeightRange = GetArg("-fork-heightrange", FORK_BLOCK_HEIGHT_RANGE);
|
forkHeightRange = GetArg("-fork-heightrange", chainparams.ForkHeightRange());
|
||||||
forkCBPerBlock = GetArg("-fork-cbperblock", FORK_COINBASE_PER_BLOCK);
|
forkCBPerBlock = GetArg("-fork-cbperblock", FORK_COINBASE_PER_BLOCK);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
156
src/main.cpp
156
src/main.cpp
|
@ -27,6 +27,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utilmoneystr.h"
|
#include "utilmoneystr.h"
|
||||||
#include "validationinterface.h"
|
#include "validationinterface.h"
|
||||||
|
#include "versionbits.h"
|
||||||
#include "wallet/asyncrpcoperation_sendmany.h"
|
#include "wallet/asyncrpcoperation_sendmany.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -76,9 +77,11 @@ bool fAlerts = DEFAULT_ALERTS;
|
||||||
#include <boost/range/combine.hpp>
|
#include <boost/range/combine.hpp>
|
||||||
|
|
||||||
std::string forkUtxoPath;
|
std::string forkUtxoPath;
|
||||||
int64_t forkStartHeight = FORK_BLOCK_HEIGHT_START;
|
int64_t forkStartHeight;
|
||||||
int64_t forkHeightRange = FORK_BLOCK_HEIGHT_RANGE;
|
int64_t forkHeightRange;
|
||||||
int64_t forkCBPerBlock = FORK_COINBASE_PER_BLOCK;
|
int64_t forkCBPerBlock;
|
||||||
|
uint256 forkExtraHashSentinel = uint256S("f0f0f0f0fafafafaffffffffffffffffffffffffffffffffafafafaf0f0f0f0f");
|
||||||
|
uint256 hashPid = GetRandHash();
|
||||||
|
|
||||||
std::string GetUTXOFileName(int nHeight)
|
std::string GetUTXOFileName(int nHeight)
|
||||||
{
|
{
|
||||||
|
@ -1413,19 +1416,11 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos
|
||||||
return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString());
|
return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
if (!isForkBlock(nHeight)) { //when block is in fork region - don't check Solution and PoW
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check the header
|
// Check the header
|
||||||
if (!(CheckEquihashSolution(&block, Params()) &&
|
if (!(CheckEquihashSolution(&block, Params()) &&
|
||||||
CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())))
|
CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())))
|
||||||
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
|
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1712,6 +1707,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
|
||||||
// Ensure that coinbases cannot be spent to transparent outputs
|
// Ensure that coinbases cannot be spent to transparent outputs
|
||||||
// Disabled on regtest
|
// Disabled on regtest
|
||||||
if (fCoinbaseEnforcedProtectionEnabled &&
|
if (fCoinbaseEnforcedProtectionEnabled &&
|
||||||
|
!isForkBlock(coins->nHeight) &&
|
||||||
consensusParams.fCoinbaseMustBeProtected &&
|
consensusParams.fCoinbaseMustBeProtected &&
|
||||||
!tx.vout.empty()) {
|
!tx.vout.empty()) {
|
||||||
return state.Invalid(
|
return state.Invalid(
|
||||||
|
@ -2102,6 +2098,51 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Protected by cs_main
|
||||||
|
VersionBitsCache versionbitscache;
|
||||||
|
|
||||||
|
int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
int32_t nVersion = VERSIONBITS_TOP_BITS;
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
|
||||||
|
ThresholdState state = VersionBitsState(pindexPrev, params, (Consensus::DeploymentPos)i, versionbitscache);
|
||||||
|
if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) {
|
||||||
|
nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Threshold condition checker that triggers when unknown versionbits are seen on the network.
|
||||||
|
*/
|
||||||
|
class WarningBitsConditionChecker : public AbstractThresholdConditionChecker
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int bit;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
|
||||||
|
|
||||||
|
int64_t BeginTime(const Consensus::Params& params) const { return 0; }
|
||||||
|
int64_t EndTime(const Consensus::Params& params) const { return std::numeric_limits<int64_t>::max(); }
|
||||||
|
int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; }
|
||||||
|
int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; }
|
||||||
|
|
||||||
|
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const
|
||||||
|
{
|
||||||
|
return ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) &&
|
||||||
|
((pindex->nVersion >> bit) & 1) != 0 &&
|
||||||
|
((ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Protected by cs_main
|
||||||
|
static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS];
|
||||||
|
|
||||||
static int64_t nTimeVerify = 0;
|
static int64_t nTimeVerify = 0;
|
||||||
static int64_t nTimeConnect = 0;
|
static int64_t nTimeConnect = 0;
|
||||||
static int64_t nTimeIndex = 0;
|
static int64_t nTimeIndex = 0;
|
||||||
|
@ -2465,24 +2506,43 @@ void static UpdateTip(CBlockIndex *pindexNew) {
|
||||||
|
|
||||||
// Check the version of the last 100 blocks to see if we need to upgrade:
|
// Check the version of the last 100 blocks to see if we need to upgrade:
|
||||||
static bool fWarned = false;
|
static bool fWarned = false;
|
||||||
if (!IsInitialBlockDownload() && !fWarned)
|
if (!IsInitialBlockDownload())
|
||||||
{
|
{
|
||||||
int nUpgraded = 0;
|
int nUpgraded = 0;
|
||||||
const CBlockIndex* pindex = chainActive.Tip();
|
const CBlockIndex* pindex = chainActive.Tip();
|
||||||
|
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
|
||||||
|
WarningBitsConditionChecker checker(bit);
|
||||||
|
ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]);
|
||||||
|
if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) {
|
||||||
|
if (state == THRESHOLD_ACTIVE) {
|
||||||
|
strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
|
||||||
|
if (!fWarned) {
|
||||||
|
CAlert::Notify(strMiscWarning, true);
|
||||||
|
fWarned = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LogPrintf("%s: unknown new rules are about to activate (versionbit %i)\n", __func__, bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 100 && pindex != NULL; i++)
|
for (int i = 0; i < 100 && pindex != NULL; i++)
|
||||||
{
|
{
|
||||||
if (pindex->nVersion > CBlock::CURRENT_VERSION)
|
int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus());
|
||||||
|
if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0)
|
||||||
++nUpgraded;
|
++nUpgraded;
|
||||||
pindex = pindex->pprev;
|
pindex = pindex->pprev;
|
||||||
}
|
}
|
||||||
if (nUpgraded > 0)
|
if (nUpgraded > 0)
|
||||||
LogPrintf("%s: %d of last 100 blocks above version %d\n", __func__, nUpgraded, (int)CBlock::CURRENT_VERSION);
|
LogPrintf("%s: %d of last 100 blocks have unexpected version\n", __func__, nUpgraded);
|
||||||
if (nUpgraded > 100/2)
|
if (nUpgraded > 100/2)
|
||||||
{
|
{
|
||||||
// strMiscWarning is read by GetWarnings(), called by the JSON-RPC code to warn the user:
|
// strMiscWarning is read by GetWarnings(), called by the JSON-RPC code to warn the user:
|
||||||
strMiscWarning = _("Warning: This version is obsolete; upgrade required!");
|
strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect");
|
||||||
CAlert::Notify(strMiscWarning, true);
|
if (!fWarned) {
|
||||||
fWarned = true;
|
CAlert::Notify(strMiscWarning, true);
|
||||||
|
fWarned = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2595,6 +2655,10 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
|
||||||
mempool.check(pcoinsTip);
|
mempool.check(pcoinsTip);
|
||||||
// Update chainActive & related variables.
|
// Update chainActive & related variables.
|
||||||
UpdateTip(pindexNew);
|
UpdateTip(pindexNew);
|
||||||
|
LogPrintf("NEWTIP %s %d %d %s %s\n",
|
||||||
|
hashPid.ToString(), pindexNew->nHeight, GetTime(),
|
||||||
|
pblock->vtx[0].vin[0].scriptSig.ToString(), pblock->GetHash().ToString());
|
||||||
|
|
||||||
// Tell wallet about transactions that went from mempool
|
// Tell wallet about transactions that went from mempool
|
||||||
// to conflicted:
|
// to conflicted:
|
||||||
BOOST_FOREACH(const CTransaction &tx, txConflicted) {
|
BOOST_FOREACH(const CTransaction &tx, txConflicted) {
|
||||||
|
@ -3054,10 +3118,6 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
|
||||||
return state.DoS(100, error("CheckBlockHeader(): block version too low"),
|
return state.DoS(100, error("CheckBlockHeader(): block version too low"),
|
||||||
REJECT_INVALID, "version-too-low");
|
REJECT_INVALID, "version-too-low");
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
if (!isTipInForkRange()) { //when in FORK mode (tip is in forking region) - don't check Solution and PoW
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check Equihash solution is valid
|
// Check Equihash solution is valid
|
||||||
if (fCheckPOW && !CheckEquihashSolution(&block, Params()))
|
if (fCheckPOW && !CheckEquihashSolution(&block, Params()))
|
||||||
return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),
|
return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),
|
||||||
|
@ -3068,10 +3128,6 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
|
||||||
return state.DoS(50, error("CheckBlockHeader(): proof of work failed"),
|
return state.DoS(50, error("CheckBlockHeader(): proof of work failed"),
|
||||||
REJECT_INVALID, "high-hash");
|
REJECT_INVALID, "high-hash");
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check timestamp
|
// Check timestamp
|
||||||
if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
|
if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
|
||||||
return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),
|
return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),
|
||||||
|
@ -3121,20 +3177,22 @@ bool CheckBlock(const CBlock& block, CValidationState& state,
|
||||||
return state.DoS(100, error("CheckBlock(): first tx is not coinbase"),
|
return state.DoS(100, error("CheckBlock(): first tx is not coinbase"),
|
||||||
REJECT_INVALID, "bad-cb-missing");
|
REJECT_INVALID, "bad-cb-missing");
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
//fork blocks might have up to fork pre-defined value coinbases and nothing else
|
||||||
if (isTipInForkRange()) { //when in FORK mode (tip is in forking region) blocks might have up to fork pre-defined value coinbases
|
if (looksLikeForkBlockHeader(block)) {
|
||||||
if (block.vtx.size() > forkCBPerBlock)
|
if (block.vtx.size() > forkCBPerBlock)
|
||||||
return state.DoS(100, error("CheckBlock(): it is forking block but there are more than %d coinbase txns", forkCBPerBlock),
|
return state.DoS(100, error("CheckBlock(): fork block: too many txns %d > %d coinbase txns", block.vtx.size(), forkCBPerBlock),
|
||||||
REJECT_INVALID, "bad-cb-multiple");
|
REJECT_INVALID, "bad-fork-too-many-tx");
|
||||||
|
|
||||||
|
for (unsigned int i = 1; i < block.vtx.size(); i++)
|
||||||
|
if (!block.vtx[i].IsCoinBase())
|
||||||
|
return state.DoS(100, error("CheckBlock(): fork block: non-coinbase found"),
|
||||||
|
REJECT_INVALID, "bad-fork-non-cb");
|
||||||
} else {
|
} else {
|
||||||
#endif
|
|
||||||
for (unsigned int i = 1; i < block.vtx.size(); i++)
|
for (unsigned int i = 1; i < block.vtx.size(); i++)
|
||||||
if (block.vtx[i].IsCoinBase())
|
if (block.vtx[i].IsCoinBase())
|
||||||
return state.DoS(100, error("CheckBlock(): more than one coinbase"),
|
return state.DoS(100, error("CheckBlock(): more than one coinbase"),
|
||||||
REJECT_INVALID, "bad-cb-multiple");
|
REJECT_INVALID, "bad-cb-multiple");
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check transactions
|
// Check transactions
|
||||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||||
|
@ -3165,16 +3223,21 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
|
||||||
|
|
||||||
int nHeight = pindexPrev->nHeight+1;
|
int nHeight = pindexPrev->nHeight+1;
|
||||||
|
|
||||||
|
// because we bypass checks using the indicia in the header
|
||||||
|
// we reject any blocks that look like fork blocks but really
|
||||||
|
// are non-fork blocks
|
||||||
|
if(looksLikeForkBlockHeader(block) && !isForkBlock(nHeight))
|
||||||
|
return state.DoS(100, error("%s: non-fork block looks like fork block", __func__),
|
||||||
|
REJECT_INVALID, "bad-fork-hashreserved");
|
||||||
|
|
||||||
|
if(!looksLikeForkBlockHeader(block) && isForkBlock(nHeight))
|
||||||
|
return state.DoS(100, error("%s: fork block does not look like fork block", __func__),
|
||||||
|
REJECT_INVALID, "bad-fork-hashreserved");
|
||||||
|
|
||||||
// Check proof of work
|
// Check proof of work
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
if (!isForkBlock(nHeight)) { //If current block is FORK, don't check work required
|
|
||||||
#endif
|
|
||||||
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
|
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
|
||||||
return state.DoS(100, error("%s: incorrect proof of work", __func__),
|
return state.DoS(100, error("%s: incorrect proof of work", __func__),
|
||||||
REJECT_INVALID, "bad-diffbits");
|
REJECT_INVALID, "bad-diffbits");
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check timestamp against prev
|
// Check timestamp against prev
|
||||||
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
|
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
|
||||||
|
@ -3329,7 +3392,8 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
|
||||||
if (!if_utxo.is_open()) {
|
if (!if_utxo.is_open()) {
|
||||||
LogPrintf("AcceptBlock(): FORK Block - Cannot open UTXO file - %s\n", utxo_file_path);
|
LogPrintf("AcceptBlock(): FORK Block - Cannot open UTXO file - %s\n", utxo_file_path);
|
||||||
} else {
|
} else {
|
||||||
LogPrintf("AcceptBlock(): FORK Block - Validating block - %u with UTXO file - %s\n", nHeight, utxo_file_path);
|
LogPrintf("AcceptBlock(): FORK Block - Validating block - %u / %s with UTXO file - %s\n",
|
||||||
|
nHeight, block.GetHash().ToString(), utxo_file_path);
|
||||||
|
|
||||||
vector<pair<uint64_t, CScript> > txFromFile;
|
vector<pair<uint64_t, CScript> > txFromFile;
|
||||||
txFromFile.reserve(forkCBPerBlock);
|
txFromFile.reserve(forkCBPerBlock);
|
||||||
|
@ -3689,11 +3753,7 @@ bool static LoadBlockIndexDB()
|
||||||
{
|
{
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
if (!pblocktree->LoadBlockIndexGuts(forkStartHeight, forkStartHeight+forkHeightRange))
|
|
||||||
#else
|
|
||||||
if (!pblocktree->LoadBlockIndexGuts())
|
if (!pblocktree->LoadBlockIndexGuts())
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
boost::this_thread::interruption_point();
|
boost::this_thread::interruption_point();
|
||||||
|
@ -3931,6 +3991,10 @@ void UnloadBlockIndex()
|
||||||
setDirtyFileInfo.clear();
|
setDirtyFileInfo.clear();
|
||||||
mapNodeState.clear();
|
mapNodeState.clear();
|
||||||
recentRejects.reset(NULL);
|
recentRejects.reset(NULL);
|
||||||
|
versionbitscache.Clear();
|
||||||
|
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
|
||||||
|
warningcache[b].clear();
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) {
|
BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) {
|
||||||
delete entry.second;
|
delete entry.second;
|
||||||
|
@ -5746,7 +5810,11 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos)
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache);
|
||||||
|
}
|
||||||
|
|
||||||
class CMainCleanup
|
class CMainCleanup
|
||||||
{
|
{
|
||||||
|
|
26
src/main.h
26
src/main.h
|
@ -25,6 +25,7 @@
|
||||||
#include "tinyformat.h"
|
#include "tinyformat.h"
|
||||||
#include "txmempool.h"
|
#include "txmempool.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
|
#include "versionbits.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
@ -257,6 +258,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||||
bool* pfMissingInputs, bool fRejectAbsurdFee=false);
|
bool* pfMissingInputs, bool fRejectAbsurdFee=false);
|
||||||
|
|
||||||
|
|
||||||
|
/** Get the BIP9 state for a given deployment at the current tip. */
|
||||||
|
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);
|
||||||
|
|
||||||
struct CNodeStateStats {
|
struct CNodeStateStats {
|
||||||
int nMisbehavior;
|
int nMisbehavior;
|
||||||
int nSyncHeight;
|
int nSyncHeight;
|
||||||
|
@ -538,19 +542,25 @@ extern CBlockTreeDB *pblocktree;
|
||||||
*/
|
*/
|
||||||
int GetSpendHeight(const CCoinsViewCache& inputs);
|
int GetSpendHeight(const CCoinsViewCache& inputs);
|
||||||
|
|
||||||
|
extern VersionBitsCache versionbitscache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine what nVersion a new block should use.
|
||||||
|
*/
|
||||||
|
int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params);
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
#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
|
|
||||||
#define FORK_COINBASE_PER_BLOCK 10000
|
#define FORK_COINBASE_PER_BLOCK 10000
|
||||||
|
|
||||||
extern std::string forkUtxoPath;
|
extern std::string forkUtxoPath;
|
||||||
extern int64_t forkStartHeight;
|
extern int64_t forkStartHeight;
|
||||||
extern int64_t forkHeightRange;
|
extern int64_t forkHeightRange;
|
||||||
extern int64_t forkCBPerBlock;
|
extern int64_t forkCBPerBlock;
|
||||||
|
extern uint256 forkExtraHashSentinel;
|
||||||
|
|
||||||
std::string GetUTXOFileName(int nHeight);
|
std::string GetUTXOFileName(int nHeight);
|
||||||
|
|
||||||
|
@ -587,14 +597,12 @@ inline bool isForkBlock(int nHeight)
|
||||||
{
|
{
|
||||||
return (nHeight > forkStartHeight && nHeight <= forkStartHeight + forkHeightRange);
|
return (nHeight > forkStartHeight && nHeight <= forkStartHeight + forkHeightRange);
|
||||||
}
|
}
|
||||||
inline bool isTipInForkRange()
|
|
||||||
|
inline bool looksLikeForkBlockHeader(const CBlockHeader& header)
|
||||||
{
|
{
|
||||||
return chainActive.Tip()? isForkBlock(chainActive.Tip()->nHeight): false;
|
return header.hashReserved == forkExtraHashSentinel;
|
||||||
}
|
|
||||||
inline bool isNextTipInForkRange()
|
|
||||||
{
|
|
||||||
return chainActive.Tip()? isForkBlock(chainActive.Tip()->nHeight + 1): false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t bytes2uint64(char *array)
|
inline uint64_t bytes2uint64(char *array)
|
||||||
{
|
{
|
||||||
uint64_t x =
|
uint64_t x =
|
||||||
|
@ -615,4 +623,6 @@ inline bool isForkEnabled(int nHeight)
|
||||||
return nHeight > forkStartHeight;
|
return nHeight > forkStartHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern uint256 hashPid;
|
||||||
|
|
||||||
#endif // BITCOIN_MAIN_H
|
#endif // BITCOIN_MAIN_H
|
||||||
|
|
285
src/miner.cpp
285
src/miner.cpp
|
@ -114,72 +114,120 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams,
|
||||||
#ifdef FORK_CB_INPUT
|
#ifdef FORK_CB_INPUT
|
||||||
CBlockTemplate* CreateNewForkBlock(bool& bFileNotFound)
|
CBlockTemplate* CreateNewForkBlock(bool& bFileNotFound)
|
||||||
{
|
{
|
||||||
CBlockIndex* pindexPrev = chainActive.Tip();
|
/*
|
||||||
const int nHeight = pindexPrev->nHeight + 1;
|
Because CreateNewForkBlock does file io when
|
||||||
|
reading utxos, we grab the main lock to peek
|
||||||
|
at the tip, release it to read the file and
|
||||||
|
fill in the template and then reacquire it
|
||||||
|
at the end to check if the active tip changed
|
||||||
|
while we were doing the above
|
||||||
|
*/
|
||||||
|
|
||||||
|
CBlockTemplate * ret;
|
||||||
|
int tipHeight;
|
||||||
|
int snappedHeight;
|
||||||
|
const CChainParams& chainparams = Params();
|
||||||
|
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
tipHeight = chainActive.Tip()->nHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
snappedHeight = tipHeight;
|
||||||
|
ret = CreateNewForkBlock(bFileNotFound, snappedHeight + 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
CBlockIndex* pindexPrev = chainActive.Tip();
|
||||||
|
CBlock *pblock = &ret->block; // pointer for convenience
|
||||||
|
|
||||||
|
tipHeight = pindexPrev->nHeight;
|
||||||
|
if(tipHeight != snappedHeight)
|
||||||
|
{
|
||||||
|
LogPrintf("WARN: tip changed from %u to %u while generating block template\n",
|
||||||
|
snappedHeight, tipHeight);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are good then fill in the final details
|
||||||
|
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
|
||||||
|
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
|
||||||
|
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
|
||||||
|
|
||||||
|
CValidationState state;
|
||||||
|
if (!TestBlockValidity(state, *pblock, pindexPrev, false, false))
|
||||||
|
throw std::runtime_error("CreateNewForkBlock(): TestBlockValidity failed");
|
||||||
|
}
|
||||||
|
} while(snappedHeight != tipHeight);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBlockTemplate* CreateNewForkBlock(bool& bFileNotFound, const int nHeight)
|
||||||
|
{
|
||||||
|
const CChainParams& chainparams = Params();
|
||||||
|
|
||||||
|
const int nForkHeight = nHeight - forkStartHeight;
|
||||||
|
|
||||||
string utxo_file_path = GetUTXOFileName(nHeight);
|
string utxo_file_path = GetUTXOFileName(nHeight);
|
||||||
|
|
||||||
std::ifstream if_utxo(utxo_file_path, std::ios::binary | std::ios::in);
|
std::ifstream if_utxo(utxo_file_path, std::ios::binary | std::ios::in);
|
||||||
if (!if_utxo.is_open()) {
|
if (!if_utxo.is_open()) {
|
||||||
bFileNotFound = true;
|
bFileNotFound = true;
|
||||||
LogPrintf("CreateNewForkBlock(): Cannot open UTXO file - %s\n", utxo_file_path);
|
LogPrintf("ERROR: CreateNewForkBlock(): [%u, %u of %u]: Cannot open UTXO file - %s\n",
|
||||||
|
nHeight, nForkHeight, forkHeightRange, utxo_file_path);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CChainParams& chainparams = Params();
|
|
||||||
// Create new block
|
// Create new block
|
||||||
std::unique_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
|
std::unique_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
|
||||||
if(!pblocktemplate.get())
|
if(!pblocktemplate.get())
|
||||||
return NULL;
|
return NULL;
|
||||||
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
|
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
|
||||||
|
|
||||||
// -regtest only: allow overriding block.nVersion with
|
|
||||||
// -blockversion=N to test forking scenarios
|
|
||||||
if (Params().MineBlocksOnDemand())
|
|
||||||
pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
|
|
||||||
|
|
||||||
// Largest block you're willing to create:
|
// Largest block you're willing to create:
|
||||||
unsigned int nBlockMaxSize = (unsigned int)(MAX_BLOCK_SIZE-1000);
|
unsigned int nBlockMaxSize = (unsigned int)(MAX_BLOCK_SIZE-1000);
|
||||||
|
|
||||||
// Minimum block size you want to create; block will be filled with free transactions
|
|
||||||
// until there are no more or the block reaches this size:
|
|
||||||
unsigned int nBlockMinSize = DEFAULT_BLOCK_MIN_SIZE;
|
|
||||||
|
|
||||||
|
uint64_t nBlockTotalAmount = 0;
|
||||||
uint64_t nBlockSize = 1000;
|
uint64_t nBlockSize = 1000;
|
||||||
uint64_t nBlockTx = 0;
|
uint64_t nBlockTx = 0;
|
||||||
|
uint64_t nBlockSigOps = 100;
|
||||||
|
|
||||||
while (if_utxo && nBlockTx < forkCBPerBlock) {
|
while (if_utxo && nBlockTx < forkCBPerBlock) {
|
||||||
char term = 0;
|
char term = 0;
|
||||||
|
|
||||||
char coin[8] = {};
|
char coin[8] = {};
|
||||||
if (!if_utxo.read(coin, 8)) {
|
if (!if_utxo.read(coin, 8)) {
|
||||||
LogPrintf("CreateNewForkBlock(): UTXO file corrupted? - No more data (Amount)\n");
|
// the last file may be shorter than forkCBPerBlock
|
||||||
|
if(!if_utxo.eof() || nForkHeight != forkHeightRange)
|
||||||
|
LogPrintf("ERROR: CreateNewForkBlock(): [%u, %u of %u]: UTXO file corrupted? - No more data (Amount)\n",
|
||||||
|
nHeight, nForkHeight, forkHeightRange);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
char pubkeysize[8] = {};
|
char pubkeysize[8] = {};
|
||||||
if (!if_utxo.read(pubkeysize, 8)) {
|
if (!if_utxo.read(pubkeysize, 8)) {
|
||||||
LogPrintf("CreateNewForkBlock(): UTXO file corrupted? - Not more data (PubKeyScript size)\n");
|
LogPrintf("ERROR: CreateNewForkBlock(): [%u, %u of %u]: UTXO file corrupted? - Not more data (PubKeyScript size)\n",
|
||||||
|
nHeight, nForkHeight, forkHeightRange);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pbsize = bytes2uint64(pubkeysize);
|
int pbsize = bytes2uint64(pubkeysize);
|
||||||
|
|
||||||
//LogPrintf("CreateNewForkBlock():PubKeyScript size = %d\n", pbsize);
|
|
||||||
|
|
||||||
if (pbsize == 0) {
|
if (pbsize == 0) {
|
||||||
LogPrintf("CreateNewForkBlock(): Warning! UTXO file corrupted? PubKeyScript size = 0\n");
|
LogPrintf("ERROR: CreateNewForkBlock(): [%u, %u of %u]: UTXO file corrupted? - PubKeyScript size = 0\n",
|
||||||
|
nHeight, nForkHeight, forkHeightRange);
|
||||||
//but proceed
|
//but proceed
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<char[]> pubKeyScript(new char[pbsize]);
|
std::unique_ptr<char[]> pubKeyScript(new char[pbsize]);
|
||||||
if (!if_utxo.read(&pubKeyScript[0], pbsize)) {
|
if (!if_utxo.read(&pubKeyScript[0], pbsize)) {
|
||||||
LogPrintf("CreateNewForkBlock(): UTXO file corrupted? Not more data (PubKeyScript)\n");
|
LogPrintf("ERROR: CreateNewForkBlock(): [%u, %u of %u]: UTXO file corrupted? Not more data (PubKeyScript)\n",
|
||||||
|
nHeight, nForkHeight, forkHeightRange);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t amount = bytes2uint64(coin);
|
uint64_t amount = bytes2uint64(coin);
|
||||||
//LogPrintf("CreateNewForkBlock(): txn %u has ammount %u\n", nBlockTx, amount);
|
|
||||||
|
|
||||||
// Add coinbase tx's
|
// Add coinbase tx's
|
||||||
CMutableTransaction txNew;
|
CMutableTransaction txNew;
|
||||||
|
@ -190,34 +238,45 @@ CBlockTemplate* CreateNewForkBlock(bool& bFileNotFound)
|
||||||
unsigned char* pks = (unsigned char*)pubKeyScript.get();
|
unsigned char* pks = (unsigned char*)pubKeyScript.get();
|
||||||
txNew.vout[0].scriptPubKey = CScript(pks, pks+pbsize);
|
txNew.vout[0].scriptPubKey = CScript(pks, pks+pbsize);
|
||||||
|
|
||||||
//LogPrintf("CreateNewForkBlock(): ScriptPubKey: %s\n", txNew.vout[0].scriptPubKey.ToString());
|
|
||||||
|
|
||||||
|
|
||||||
txNew.vout[0].nValue = amount;
|
txNew.vout[0].nValue = amount;
|
||||||
txNew.vin[0].scriptSig = CScript() << nHeight+nBlockTx << OP_0;
|
if(nBlockTx == 0)
|
||||||
|
txNew.vin[0].scriptSig = CScript() << nHeight << CScriptNum(nBlockTx) << ToByteVector(hashPid) << OP_0;
|
||||||
|
else
|
||||||
|
txNew.vin[0].scriptSig = CScript() << nHeight << CScriptNum(nBlockTx) << OP_0;
|
||||||
|
|
||||||
unsigned int nTxSize = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
|
unsigned int nTxSize = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
if (nBlockSize + nTxSize >= nBlockMaxSize)
|
if (nBlockSize + nTxSize >= nBlockMaxSize)
|
||||||
break;//We cannot skip transaction here as in regular case - or we will loose that skipped transaction
|
{
|
||||||
|
LogPrintf("ERROR: CreateNewForkBlock(): [%u, %u of %u]: %u: block would exceed max size\n",
|
||||||
pblock->vtx.push_back(txNew);
|
nHeight, nForkHeight, forkHeightRange, nBlockTx);
|
||||||
pblocktemplate->vTxFees.push_back(-1); // updated at end
|
|
||||||
pblocktemplate->vTxSigOps.push_back(-1); // updated at end
|
|
||||||
nBlockSize += nTxSize;
|
|
||||||
++nBlockTx;
|
|
||||||
|
|
||||||
|
|
||||||
if (!if_utxo.read(&term, 1)) {
|
|
||||||
LogPrintf("CreateNewForkBlock(): No more data (record separator)\n");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (term != '\n') {
|
|
||||||
//This maybe not an error, but warning none the less
|
// Legacy limits on sigOps:
|
||||||
LogPrintf("CreateNewForkBlock(): Warning! No record separator ('0xA') was found\n");
|
unsigned int nTxSigOps = GetLegacySigOpCount(txNew);
|
||||||
if_utxo.seekg(-1, ios_base::cur); //move one char back - if it is not a separator, maybe there is not separators at all
|
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
|
||||||
|
{
|
||||||
|
LogPrintf("ERROR: CreateNewForkBlock(): [%u, %u of %u]: %u: block would exceed max sigops\n",
|
||||||
|
nHeight, nForkHeight, forkHeightRange, nBlockTx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pblock->vtx.push_back(txNew);
|
||||||
|
pblocktemplate->vTxFees.push_back(0);
|
||||||
|
pblocktemplate->vTxSigOps.push_back(nTxSigOps);
|
||||||
|
nBlockSize += nTxSize;
|
||||||
|
nBlockSigOps += nTxSigOps;
|
||||||
|
nBlockTotalAmount += amount;
|
||||||
|
++nBlockTx;
|
||||||
|
|
||||||
|
if (!if_utxo.read(&term, 1) || term != '\n') {
|
||||||
|
LogPrintf("ERROR: CreateNewForkBlock(): [%u, %u of %u]: invalid record separator\n",
|
||||||
|
nHeight, nForkHeight, forkHeightRange);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrintf("CreateNewForkBlock(): %u tnxs and total size %u\n", nBlockTx, nBlockSize);
|
LogPrintf("CreateNewForkBlock(): [%u, %u of %u]: txns=%u size=%u amount=%u sigops=%u\n",
|
||||||
|
nHeight, nForkHeight, forkHeightRange, nBlockTx, nBlockSize, nBlockTotalAmount, nBlockSigOps);
|
||||||
|
|
||||||
// Randomise nonce
|
// Randomise nonce
|
||||||
arith_uint256 nonce = UintToArith256(GetRandHash());
|
arith_uint256 nonce = UintToArith256(GetRandHash());
|
||||||
|
@ -227,22 +286,8 @@ CBlockTemplate* CreateNewForkBlock(bool& bFileNotFound)
|
||||||
pblock->nNonce = ArithToUint256(nonce);
|
pblock->nNonce = ArithToUint256(nonce);
|
||||||
|
|
||||||
// Fill in header
|
// Fill in header
|
||||||
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
|
pblock->hashReserved = forkExtraHashSentinel;
|
||||||
pblock->hashReserved = uint256();
|
|
||||||
UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
|
|
||||||
pblock->nBits = 0x207fffff; // Difficulty = 1
|
|
||||||
//0x207fffff -> 0x 7fffff00 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
|
||||||
//alternativly
|
|
||||||
//0x1d00ffff -> 0x 00000000 ffff0000 00000000 00000000 00000000 00000000 00000000 00000000
|
|
||||||
// or
|
|
||||||
//0x1f07ffff -> 0x 007fffff 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
|
||||||
|
|
||||||
pblock->nSolution.clear();
|
pblock->nSolution.clear();
|
||||||
pblocktemplate->vTxSigOps[0] = 0; //NO SigOps
|
|
||||||
|
|
||||||
CValidationState state;
|
|
||||||
if (!TestBlockValidity(state, *pblock, pindexPrev, false, false))
|
|
||||||
throw std::runtime_error("CreateNewForkBlock(): TestBlockValidity failed");
|
|
||||||
|
|
||||||
return pblocktemplate.release();
|
return pblocktemplate.release();
|
||||||
}
|
}
|
||||||
|
@ -257,11 +302,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||||
return NULL;
|
return NULL;
|
||||||
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
|
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
|
||||||
|
|
||||||
// -regtest only: allow overriding block.nVersion with
|
|
||||||
// -blockversion=N to test forking scenarios
|
|
||||||
if (Params().MineBlocksOnDemand())
|
|
||||||
pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
|
|
||||||
|
|
||||||
// Add dummy coinbase tx as first transaction
|
// Add dummy coinbase tx as first transaction
|
||||||
pblock->vtx.push_back(CTransaction());
|
pblock->vtx.push_back(CTransaction());
|
||||||
pblocktemplate->vTxFees.push_back(-1); // updated at end
|
pblocktemplate->vTxFees.push_back(-1); // updated at end
|
||||||
|
@ -291,6 +331,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||||
const int nHeight = pindexPrev->nHeight + 1;
|
const int nHeight = pindexPrev->nHeight + 1;
|
||||||
pblock->nTime = GetAdjustedTime();
|
pblock->nTime = GetAdjustedTime();
|
||||||
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
|
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
|
||||||
|
pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
|
||||||
|
// -regtest only: allow overriding block.nVersion with
|
||||||
|
// -blockversion=N to test forking scenarios
|
||||||
|
if (chainparams.MineBlocksOnDemand())
|
||||||
|
pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
|
||||||
|
|
||||||
CCoinsViewCache view(pcoinsTip);
|
CCoinsViewCache view(pcoinsTip);
|
||||||
|
|
||||||
// Priority order to process transactions
|
// Priority order to process transactions
|
||||||
|
@ -593,13 +639,10 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
|
||||||
static bool ProcessBlockFound(CBlock* pblock)
|
static bool ProcessBlockFound(CBlock* pblock)
|
||||||
#endif // ENABLE_WALLET
|
#endif // ENABLE_WALLET
|
||||||
{
|
{
|
||||||
#ifdef FORK_CB_INPUT
|
if (!looksLikeForkBlockHeader(*pblock)) {
|
||||||
if (!isNextTipInForkRange()) {
|
LogPrintf("%s\n", pblock->ToString());
|
||||||
#endif
|
|
||||||
LogPrintf("%s\n", pblock->ToString());
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
|
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
|
||||||
|
|
||||||
// Found a solution
|
// Found a solution
|
||||||
|
@ -642,7 +685,7 @@ void static BitcoinMiner(CWallet *pwallet)
|
||||||
void static BitcoinMiner()
|
void static BitcoinMiner()
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
LogPrintf("BTCPrivate Miner started\n");
|
LogPrintf("BTCPrivate Miner started %s\n");
|
||||||
SetThreadPriority(THREAD_PRIORITY_LOWEST);
|
SetThreadPriority(THREAD_PRIORITY_LOWEST);
|
||||||
RenameThread("btcp-miner");
|
RenameThread("btcp-miner");
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
|
@ -672,10 +715,7 @@ void static BitcoinMiner()
|
||||||
);
|
);
|
||||||
miningTimer.start();
|
miningTimer.start();
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
bool bForkModeStarted = false;
|
bool bForkModeStarted = false;
|
||||||
#endif
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (chainparams.MiningRequiresPeers()) {
|
if (chainparams.MiningRequiresPeers()) {
|
||||||
|
@ -704,8 +744,19 @@ void static BitcoinMiner()
|
||||||
//
|
//
|
||||||
unique_ptr<CBlockTemplate> pblocktemplate;
|
unique_ptr<CBlockTemplate> pblocktemplate;
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
bool isNextBlockFork = isForkBlock(pindexPrev->nHeight+1);
|
bool isNextBlockFork = isForkBlock(pindexPrev->nHeight+1);
|
||||||
|
|
||||||
|
bool mineOnlyFork = GetBoolArg("-forkmineonly", false);
|
||||||
|
if(mineOnlyFork && !isNextBlockFork) {
|
||||||
|
miningTimer.stop();
|
||||||
|
do {
|
||||||
|
MilliSleep(100);
|
||||||
|
pindexPrev = chainActive.Tip();
|
||||||
|
isNextBlockFork = isForkBlock(pindexPrev->nHeight + 1);
|
||||||
|
} while(!isNextBlockFork);
|
||||||
|
miningTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
if (isNextBlockFork) {
|
if (isNextBlockFork) {
|
||||||
if (!bForkModeStarted) {
|
if (!bForkModeStarted) {
|
||||||
LogPrintf("BTCPrivate Miner: switching into fork mode\n");
|
LogPrintf("BTCPrivate Miner: switching into fork mode\n");
|
||||||
|
@ -717,28 +768,26 @@ void static BitcoinMiner()
|
||||||
if (!pblocktemplate.get()) {
|
if (!pblocktemplate.get()) {
|
||||||
if (bFileNotFound) {
|
if (bFileNotFound) {
|
||||||
MilliSleep(1000);
|
MilliSleep(1000);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
LogPrintf("Error in BTCPrivate Miner: Cannot create Fork Block\n");
|
LogPrintf("Error in BTCPrivate Miner: Cannot create Fork Block\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pblock = &pblocktemplate->block;
|
pblock = &pblocktemplate->block;
|
||||||
|
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
|
||||||
|
|
||||||
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(),
|
||||||
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),
|
||||||
::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION),
|
n, k);
|
||||||
n, k);
|
|
||||||
} else {
|
} else {
|
||||||
//if not in forking mode and/or provided file is read to the end - exit
|
//if not in forking mode and/or provided file is read to the end - exit
|
||||||
if (bForkModeStarted) {
|
if (bForkModeStarted) {
|
||||||
LogPrintf("BTCPrivate Miner: Fork is done - switching back to regular miner\n");
|
LogPrintf("BTCPrivate Miner: Fork is done - switching back to regular miner\n");
|
||||||
n = chainparams.EquihashN();
|
|
||||||
k = chainparams.EquihashK();
|
|
||||||
bForkModeStarted = false;
|
bForkModeStarted = false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
||||||
|
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
|
@ -759,13 +808,12 @@ void static BitcoinMiner()
|
||||||
pblock = &pblocktemplate->block;
|
pblock = &pblocktemplate->block;
|
||||||
|
|
||||||
LogPrintf("Running BTCPrivate Miner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
|
LogPrintf("Running BTCPrivate Miner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
|
||||||
::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
|
::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
|
||||||
} //else
|
} //else
|
||||||
#endif
|
|
||||||
|
|
||||||
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Search
|
// Search
|
||||||
|
@ -798,38 +846,31 @@ void static BitcoinMiner()
|
||||||
solver, pblock->nNonce.ToString());
|
solver, pblock->nNonce.ToString());
|
||||||
|
|
||||||
std::function<bool(std::vector<unsigned char>)> validBlock =
|
std::function<bool(std::vector<unsigned char>)> validBlock =
|
||||||
|
[&pblock, &hashTarget, &m_cs, &cancelSolver, &chainparams
|
||||||
[&pblock, &hashTarget, &m_cs, &cancelSolver, &chainparams
|
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
, &pwallet, &reservekey
|
, &pwallet, &reservekey
|
||||||
#endif
|
#endif
|
||||||
#ifdef FORK_CB_INPUT
|
, &isNextBlockFork] (std::vector<unsigned char> soln) {
|
||||||
, &isNextBlockFork
|
|
||||||
#endif
|
|
||||||
] (std::vector<unsigned char> soln) {
|
|
||||||
// Write the solution to the hash and compute the result.
|
// Write the solution to the hash and compute the result.
|
||||||
LogPrint("pow", "- Checking solution against target\n");
|
LogPrint("pow", "- Checking solution against target\n");
|
||||||
pblock->nSolution = soln;
|
pblock->nSolution = soln;
|
||||||
solutionTargetChecks.increment();
|
solutionTargetChecks.increment();
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
if (!isNextBlockFork) {
|
|
||||||
#endif
|
|
||||||
if (UintToArith256(pblock->GetHash()) > hashTarget) {
|
if (UintToArith256(pblock->GetHash()) > hashTarget) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// Found a solution
|
// Found a solution
|
||||||
SetThreadPriority(THREAD_PRIORITY_NORMAL);
|
SetThreadPriority(THREAD_PRIORITY_NORMAL);
|
||||||
LogPrintf("BTCPrivate Miner:\n");
|
LogPrintf("BTCPrivate Miner:\n");
|
||||||
LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", pblock->GetHash().GetHex(), hashTarget.GetHex());
|
LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", pblock->GetHash().GetHex(), hashTarget.GetHex());
|
||||||
|
|
||||||
|
if (ProcessBlockFound(pblock
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
if (ProcessBlockFound(pblock, *pwallet, reservekey)) {
|
, *pwallet, reservekey
|
||||||
#else
|
|
||||||
if (ProcessBlockFound(pblock)) {
|
|
||||||
#endif
|
#endif
|
||||||
|
)) {
|
||||||
|
|
||||||
// Ignore chain updates caused by us
|
// Ignore chain updates caused by us
|
||||||
std::lock_guard<std::mutex> lock{m_cs};
|
std::lock_guard<std::mutex> lock{m_cs};
|
||||||
cancelSolver = false;
|
cancelSolver = false;
|
||||||
|
@ -837,7 +878,7 @@ void static BitcoinMiner()
|
||||||
SetThreadPriority(THREAD_PRIORITY_LOWEST);
|
SetThreadPriority(THREAD_PRIORITY_LOWEST);
|
||||||
|
|
||||||
// In regression test mode, stop mining after a block is found.
|
// In regression test mode, stop mining after a block is found.
|
||||||
if (chainparams.MineBlocksOnDemand()) {
|
if (chainparams.MineBlocksOnDemand() && !isNextBlockFork) {
|
||||||
// Increment here because throwing skips the call below
|
// Increment here because throwing skips the call below
|
||||||
ehSolverRuns.increment();
|
ehSolverRuns.increment();
|
||||||
throw boost::thread_interrupted();
|
throw boost::thread_interrupted();
|
||||||
|
@ -845,6 +886,7 @@ void static BitcoinMiner()
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::function<bool(EhSolverCancelCheck)> cancelled = [&m_cs, &cancelSolver](EhSolverCancelCheck pos) {
|
std::function<bool(EhSolverCancelCheck)> cancelled = [&m_cs, &cancelSolver](EhSolverCancelCheck pos) {
|
||||||
std::lock_guard<std::mutex> lock{m_cs};
|
std::lock_guard<std::mutex> lock{m_cs};
|
||||||
return cancelSolver;
|
return cancelSolver;
|
||||||
|
@ -901,20 +943,13 @@ void static BitcoinMiner()
|
||||||
// Check for stop or if block needs to be rebuilt
|
// Check for stop or if block needs to be rebuilt
|
||||||
boost::this_thread::interruption_point();
|
boost::this_thread::interruption_point();
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
// Regtest mode doesn't require peers
|
||||||
if (!isNextBlockFork) {
|
if (vNodes.empty() && chainparams.MiningRequiresPeers())
|
||||||
#endif
|
break;
|
||||||
// Regtest mode doesn't require peers
|
if ((UintToArith256(pblock->nNonce) & 0xffff) == 0xffff)
|
||||||
if (vNodes.empty() && chainparams.MiningRequiresPeers())
|
break;
|
||||||
break;
|
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
|
||||||
if ((UintToArith256(pblock->nNonce) & 0xffff) == 0xffff)
|
break;
|
||||||
break;
|
|
||||||
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
|
|
||||||
break;
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (pindexPrev != chainActive.Tip())
|
if (pindexPrev != chainActive.Tip())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -922,17 +957,11 @@ void static BitcoinMiner()
|
||||||
pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1);
|
pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1);
|
||||||
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
|
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
|
||||||
if (!isNextBlockFork) {
|
{
|
||||||
#endif
|
// Changing pblock->nTime can change work required on testnet:
|
||||||
if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
|
hashTarget.SetCompact(pblock->nBits);
|
||||||
{
|
|
||||||
// Changing pblock->nTime can change work required on testnet:
|
|
||||||
hashTarget.SetCompact(pblock->nBits);
|
|
||||||
}
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,8 @@ void GenerateBitcoins(bool fGenerate, int nThreads);
|
||||||
void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
|
void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
#ifdef FORK_CB_INPUT
|
||||||
CBlockTemplate* CreateNewForkBlock();
|
CBlockTemplate* CreateNewForkBlock(bool&);
|
||||||
|
CBlockTemplate* CreateNewForkBlock(bool&,const int);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // BITCOIN_MINER_H
|
#endif // BITCOIN_MINER_H
|
||||||
|
|
27
src/pow.cpp
27
src/pow.cpp
|
@ -9,6 +9,7 @@
|
||||||
#include "chain.h"
|
#include "chain.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "crypto/equihash.h"
|
#include "crypto/equihash.h"
|
||||||
|
#include "main.h"
|
||||||
#include "primitives/block.h"
|
#include "primitives/block.h"
|
||||||
#include "streams.h"
|
#include "streams.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
|
@ -23,11 +24,20 @@
|
||||||
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
|
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
|
||||||
{
|
{
|
||||||
unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
|
unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
|
||||||
|
unsigned int nProofOfWorkBomb = UintToArith256(uint256S("000000000000000000000000000000000000000000000000000000000000ffff")).GetCompact();
|
||||||
|
|
||||||
// Genesis block
|
// Genesis block
|
||||||
if (pindexLast == NULL)
|
if (pindexLast == NULL)
|
||||||
return nProofOfWorkLimit;
|
return nProofOfWorkLimit;
|
||||||
|
|
||||||
|
// right post fork
|
||||||
|
else if(!isForkBlock(pindexLast->nHeight + 1) && isForkBlock(pindexLast->nHeight + 1 - params.nPowAveragingWindow))
|
||||||
|
return nProofOfWorkLimit;
|
||||||
|
|
||||||
|
// difficulty bomb
|
||||||
|
else if(pindexLast->nHeight > params.nPowDifficultyBombHeight)
|
||||||
|
return nProofOfWorkBomb;
|
||||||
|
|
||||||
// Find the first block in the averaging interval
|
// Find the first block in the averaging interval
|
||||||
const CBlockIndex* pindexFirst = pindexLast;
|
const CBlockIndex* pindexFirst = pindexLast;
|
||||||
arith_uint256 bnTot {0};
|
arith_uint256 bnTot {0};
|
||||||
|
@ -44,29 +54,30 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
||||||
|
|
||||||
arith_uint256 bnAvg {bnTot / params.nPowAveragingWindow};
|
arith_uint256 bnAvg {bnTot / params.nPowAveragingWindow};
|
||||||
|
|
||||||
return CalculateNextWorkRequired(bnAvg, pindexLast->GetMedianTimePast(), pindexFirst->GetMedianTimePast(), params);
|
bool isFork = isForkBlock(pindexLast->nHeight + 1);
|
||||||
|
return CalculateNextWorkRequired(bnAvg, pindexLast->GetMedianTimePast(), pindexFirst->GetMedianTimePast(), params, isFork);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
|
unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
|
||||||
int64_t nLastBlockTime, int64_t nFirstBlockTime,
|
int64_t nLastBlockTime, int64_t nFirstBlockTime,
|
||||||
const Consensus::Params& params)
|
const Consensus::Params& params, bool isFork)
|
||||||
{
|
{
|
||||||
// Limit adjustment step
|
// Limit adjustment step
|
||||||
// Use medians to prevent time-warp attacks
|
// Use medians to prevent time-warp attacks
|
||||||
int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime;
|
int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime;
|
||||||
LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan);
|
LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan);
|
||||||
nActualTimespan = params.AveragingWindowTimespan() + (nActualTimespan - params.AveragingWindowTimespan())/4;
|
nActualTimespan = params.AveragingWindowTimespan(isFork) + (nActualTimespan - params.AveragingWindowTimespan(isFork))/4;
|
||||||
LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan);
|
LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan);
|
||||||
|
|
||||||
if (nActualTimespan < params.MinActualTimespan())
|
if (nActualTimespan < params.MinActualTimespan(isFork))
|
||||||
nActualTimespan = params.MinActualTimespan();
|
nActualTimespan = params.MinActualTimespan(isFork);
|
||||||
if (nActualTimespan > params.MaxActualTimespan())
|
if (nActualTimespan > params.MaxActualTimespan(isFork))
|
||||||
nActualTimespan = params.MaxActualTimespan();
|
nActualTimespan = params.MaxActualTimespan(isFork);
|
||||||
|
|
||||||
// Retarget
|
// Retarget
|
||||||
const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
|
const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
|
||||||
arith_uint256 bnNew {bnAvg};
|
arith_uint256 bnNew {bnAvg};
|
||||||
bnNew /= params.AveragingWindowTimespan();
|
bnNew /= params.AveragingWindowTimespan(isFork);
|
||||||
bnNew *= nActualTimespan;
|
bnNew *= nActualTimespan;
|
||||||
|
|
||||||
if (bnNew > bnPowLimit)
|
if (bnNew > bnPowLimit)
|
||||||
|
|
|
@ -19,7 +19,7 @@ class arith_uint256;
|
||||||
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&);
|
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&);
|
||||||
unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
|
unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
|
||||||
int64_t nLastBlockTime, int64_t nFirstBlockTime,
|
int64_t nLastBlockTime, int64_t nFirstBlockTime,
|
||||||
const Consensus::Params&);
|
const Consensus::Params&, bool isFork = false);
|
||||||
|
|
||||||
/** Check whether the Equihash solution in a block header is valid */
|
/** Check whether the Equihash solution in a block header is valid */
|
||||||
bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams&);
|
bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams&);
|
||||||
|
|
|
@ -22,7 +22,7 @@ class CBlockHeader
|
||||||
public:
|
public:
|
||||||
// header
|
// header
|
||||||
static const size_t HEADER_SIZE=4+32+32+32+4+4+32; // excluding Equihash solution
|
static const size_t HEADER_SIZE=4+32+32+32+4+4+32; // excluding Equihash solution
|
||||||
static const int32_t CURRENT_VERSION=4;
|
|
||||||
int32_t nVersion;
|
int32_t nVersion;
|
||||||
uint256 hashPrevBlock;
|
uint256 hashPrevBlock;
|
||||||
uint256 hashMerkleRoot;
|
uint256 hashMerkleRoot;
|
||||||
|
@ -54,7 +54,7 @@ public:
|
||||||
|
|
||||||
void SetNull()
|
void SetNull()
|
||||||
{
|
{
|
||||||
nVersion = CBlockHeader::CURRENT_VERSION;
|
nVersion = 0;
|
||||||
hashPrevBlock.SetNull();
|
hashPrevBlock.SetNull();
|
||||||
hashMerkleRoot.SetNull();
|
hashMerkleRoot.SetNull();
|
||||||
hashReserved.SetNull();
|
hashReserved.SetNull();
|
||||||
|
|
|
@ -634,6 +634,20 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex*
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UniValue BIP9SoftForkDesc(const std::string& name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
|
||||||
|
{
|
||||||
|
UniValue rv(UniValue::VOBJ);
|
||||||
|
rv.push_back(Pair("id", name));
|
||||||
|
switch (VersionBitsTipState(consensusParams, id)) {
|
||||||
|
case THRESHOLD_DEFINED: rv.push_back(Pair("status", "defined")); break;
|
||||||
|
case THRESHOLD_STARTED: rv.push_back(Pair("status", "started")); break;
|
||||||
|
case THRESHOLD_LOCKED_IN: rv.push_back(Pair("status", "locked_in")); break;
|
||||||
|
case THRESHOLD_ACTIVE: rv.push_back(Pair("status", "active")); break;
|
||||||
|
case THRESHOLD_FAILED: rv.push_back(Pair("status", "failed")); break;
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
UniValue getblockchaininfo(const UniValue& params, bool fHelp)
|
UniValue getblockchaininfo(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (fHelp || params.size() != 0)
|
if (fHelp || params.size() != 0)
|
||||||
|
@ -662,6 +676,12 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
|
||||||
" },\n"
|
" },\n"
|
||||||
" \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
|
" \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
|
||||||
" }, ...\n"
|
" }, ...\n"
|
||||||
|
" ],\n"
|
||||||
|
" \"bip9_softforks\": [ (array) status of BIP9 softforks in progress\n"
|
||||||
|
" {\n"
|
||||||
|
" \"id\": \"xxxx\", (string) name of the softfork\n"
|
||||||
|
" \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"lockedin\", \"active\", \"failed\"\n"
|
||||||
|
" }\n"
|
||||||
" ]\n"
|
" ]\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"\nExamples:\n"
|
"\nExamples:\n"
|
||||||
|
@ -688,10 +708,12 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
|
||||||
const Consensus::Params& consensusParams = Params().GetConsensus();
|
const Consensus::Params& consensusParams = Params().GetConsensus();
|
||||||
CBlockIndex* tip = chainActive.Tip();
|
CBlockIndex* tip = chainActive.Tip();
|
||||||
UniValue softforks(UniValue::VARR);
|
UniValue softforks(UniValue::VARR);
|
||||||
|
UniValue bip9_softforks(UniValue::VARR);
|
||||||
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
|
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
|
||||||
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
|
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
|
||||||
softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
|
softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
|
||||||
obj.push_back(Pair("softforks", softforks));
|
obj.push_back(Pair("softforks", softforks));
|
||||||
|
obj.push_back(Pair("bip9_softforks", bip9_softforks));
|
||||||
|
|
||||||
if (fPruneMode)
|
if (fPruneMode)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
|
#include "consensus/params.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#ifdef ENABLE_MINING
|
#ifdef ENABLE_MINING
|
||||||
|
@ -425,6 +426,15 @@ static UniValue BIP22ValidationResult(const CValidationState& state)
|
||||||
return "valid?";
|
return "valid?";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
|
||||||
|
const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
|
||||||
|
std::string s = vbinfo.name;
|
||||||
|
if (!vbinfo.gbt_force) {
|
||||||
|
s.insert(s.begin(), '!');
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (fHelp || params.size() > 1)
|
if (fHelp || params.size() > 1)
|
||||||
|
@ -432,7 +442,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
"getblocktemplate ( \"jsonrequestobject\" )\n"
|
"getblocktemplate ( \"jsonrequestobject\" )\n"
|
||||||
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
|
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
|
||||||
"It returns data needed to construct a block to work on.\n"
|
"It returns data needed to construct a block to work on.\n"
|
||||||
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n"
|
"For full specification, see BIPs 22 and 9:\n"
|
||||||
|
" https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n"
|
||||||
|
" https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
|
||||||
|
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n"
|
"1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n"
|
||||||
|
@ -448,6 +460,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
"\nResult:\n"
|
"\nResult:\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" \"version\" : n, (numeric) The block version\n"
|
" \"version\" : n, (numeric) The block version\n"
|
||||||
|
" \"rules\" : [ \"rulename\", ... ], (array of strings) specific block rules that are to be enforced\n"
|
||||||
|
" \"vbavailable\" : { (json object) set of pending, supported versionbit (BIP 9) softfork deployments\n"
|
||||||
|
" \"rulename\" : bitnumber (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule\n"
|
||||||
|
" ,...\n"
|
||||||
|
" },\n"
|
||||||
|
" \"vbrequired\" : n, (numeric) bit mask of versionbits the server requires set in submissions\n"
|
||||||
" \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
|
" \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
|
||||||
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
|
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
|
@ -502,8 +520,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
std::string strMode = "template";
|
std::string strMode = "template";
|
||||||
UniValue lpval = NullUniValue;
|
UniValue lpval = NullUniValue;
|
||||||
|
|
||||||
// TODO: Re-enable coinbasevalue once a specification has been written
|
// TODO: Re-enable coinbasevalue once a specification has been written
|
||||||
bool coinbasetxn = true;
|
bool coinbasetxn = true;
|
||||||
|
std::set<std::string> setClientRules;
|
||||||
if (params.size() > 0)
|
if (params.size() > 0)
|
||||||
{
|
{
|
||||||
const UniValue& oparam = params[0].get_obj();
|
const UniValue& oparam = params[0].get_obj();
|
||||||
|
@ -547,6 +567,14 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
TestBlockValidity(state, block, pindexPrev, false, true);
|
TestBlockValidity(state, block, pindexPrev, false, true);
|
||||||
return BIP22ValidationResult(state);
|
return BIP22ValidationResult(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UniValue& aClientRules = find_value(oparam, "rules");
|
||||||
|
if (aClientRules.isArray()) {
|
||||||
|
for (unsigned int i = 0; i < aClientRules.size(); ++i) {
|
||||||
|
const UniValue& v = aClientRules[i];
|
||||||
|
setClientRules.insert(v.get_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strMode != "template")
|
if (strMode != "template")
|
||||||
|
@ -640,9 +668,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
pindexPrev = pindexPrevNew;
|
pindexPrev = pindexPrevNew;
|
||||||
}
|
}
|
||||||
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
|
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
|
||||||
|
const Consensus::Params& consensusParams = Params().GetConsensus();
|
||||||
|
|
||||||
// Update nTime
|
// Update nTime
|
||||||
UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
|
UpdateTime(pblock, consensusParams, pindexPrev);
|
||||||
pblock->nNonce = uint256();
|
pblock->nNonce = uint256();
|
||||||
|
|
||||||
UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
|
UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
|
||||||
|
@ -704,7 +733,53 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
UniValue result(UniValue::VOBJ);
|
UniValue result(UniValue::VOBJ);
|
||||||
result.push_back(Pair("capabilities", aCaps));
|
result.push_back(Pair("capabilities", aCaps));
|
||||||
|
|
||||||
|
UniValue aRules(UniValue::VARR);
|
||||||
|
UniValue vbavailable(UniValue::VOBJ);
|
||||||
|
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) {
|
||||||
|
Consensus::DeploymentPos pos = Consensus::DeploymentPos(i);
|
||||||
|
ThresholdState state = VersionBitsState(pindexPrev, consensusParams, pos, versionbitscache);
|
||||||
|
switch (state) {
|
||||||
|
case THRESHOLD_DEFINED:
|
||||||
|
case THRESHOLD_FAILED:
|
||||||
|
// Not exposed to GBT at all
|
||||||
|
break;
|
||||||
|
case THRESHOLD_LOCKED_IN:
|
||||||
|
// Ensure bit is set in block version
|
||||||
|
pblock->nVersion |= VersionBitsMask(consensusParams, pos);
|
||||||
|
// FALL THROUGH to get vbavailable set...
|
||||||
|
case THRESHOLD_STARTED:
|
||||||
|
{
|
||||||
|
const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
|
||||||
|
vbavailable.push_back(Pair(gbt_vb_name(pos), consensusParams.vDeployments[pos].bit));
|
||||||
|
if (setClientRules.find(vbinfo.name) == setClientRules.end()) {
|
||||||
|
if (!vbinfo.gbt_force) {
|
||||||
|
// If the client doesn't support this, don't indicate it in the [default] version
|
||||||
|
pblock->nVersion &= ~VersionBitsMask(consensusParams, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case THRESHOLD_ACTIVE:
|
||||||
|
{
|
||||||
|
// Add to rules only
|
||||||
|
const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
|
||||||
|
aRules.push_back(gbt_vb_name(pos));
|
||||||
|
if (setClientRules.find(vbinfo.name) == setClientRules.end()) {
|
||||||
|
// Not supported by the client; make sure it's safe to proceed
|
||||||
|
if (!vbinfo.gbt_force) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Support for '%s' rule requires explicit client support", vbinfo.name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
result.push_back(Pair("version", pblock->nVersion));
|
result.push_back(Pair("version", pblock->nVersion));
|
||||||
|
result.push_back(Pair("rules", aRules));
|
||||||
|
result.push_back(Pair("vbavailable", vbavailable));
|
||||||
|
result.push_back(Pair("vbrequired", int(0)));
|
||||||
|
|
||||||
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
|
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
|
||||||
result.push_back(Pair("transactions", transactions));
|
result.push_back(Pair("transactions", transactions));
|
||||||
if (coinbasetxn) {
|
if (coinbasetxn) {
|
||||||
|
|
|
@ -378,13 +378,40 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||||
|
|
||||||
// subsidy changing
|
// subsidy changing
|
||||||
int nHeight = chainActive.Height();
|
int nHeight = chainActive.Height();
|
||||||
chainActive.Tip()->nHeight = 209999;
|
// Create an actual 209999-long block chain (without valid blocks).
|
||||||
|
while (chainActive.Tip()->nHeight < 209999) {
|
||||||
|
CBlockIndex* prev = chainActive.Tip();
|
||||||
|
CBlockIndex* next = new CBlockIndex();
|
||||||
|
next->phashBlock = new uint256(GetRandHash());
|
||||||
|
pcoinsTip->SetBestBlock(next->GetBlockHash());
|
||||||
|
next->pprev = prev;
|
||||||
|
next->nHeight = prev->nHeight + 1;
|
||||||
|
next->BuildSkip();
|
||||||
|
chainActive.SetTip(next);
|
||||||
|
}
|
||||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
delete pblocktemplate;
|
delete pblocktemplate;
|
||||||
chainActive.Tip()->nHeight = 210000;
|
// Extend to a 210000-long block chain.
|
||||||
|
while (chainActive.Tip()->nHeight < 210000) {
|
||||||
|
CBlockIndex* prev = chainActive.Tip();
|
||||||
|
CBlockIndex* next = new CBlockIndex();
|
||||||
|
next->phashBlock = new uint256(GetRandHash());
|
||||||
|
pcoinsTip->SetBestBlock(next->GetBlockHash());
|
||||||
|
next->pprev = prev;
|
||||||
|
next->nHeight = prev->nHeight + 1;
|
||||||
|
next->BuildSkip();
|
||||||
|
chainActive.SetTip(next);
|
||||||
|
}
|
||||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
|
||||||
delete pblocktemplate;
|
delete pblocktemplate;
|
||||||
chainActive.Tip()->nHeight = nHeight;
|
// Delete the dummy blocks again.
|
||||||
|
while (chainActive.Tip()->nHeight > nHeight) {
|
||||||
|
CBlockIndex* del = chainActive.Tip();
|
||||||
|
chainActive.SetTip(del->pprev);
|
||||||
|
pcoinsTip->SetBestBlock(del->pprev->GetBlockHash());
|
||||||
|
delete del->phashBlock;
|
||||||
|
delete del;
|
||||||
|
}
|
||||||
|
|
||||||
// non-final txs in mempool
|
// non-final txs in mempool
|
||||||
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);
|
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);
|
||||||
|
|
|
@ -0,0 +1,316 @@
|
||||||
|
// Copyright (c) 2014-2015 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "chain.h"
|
||||||
|
#include "random.h"
|
||||||
|
#include "versionbits.h"
|
||||||
|
#include "test/test_bitcoin.h"
|
||||||
|
#include "chainparams.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "consensus/params.h"
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
/* Define a virtual block time, one block per 10 minutes after Nov 14 2014, 0:55:36am */
|
||||||
|
int32_t TestTime(int nHeight) { return 1415926536 + 600 * nHeight; }
|
||||||
|
|
||||||
|
static const Consensus::Params paramsDummy = Consensus::Params();
|
||||||
|
|
||||||
|
class TestConditionChecker : public AbstractThresholdConditionChecker
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
mutable ThresholdConditionCache cache;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int64_t BeginTime(const Consensus::Params& params) const { return TestTime(10000); }
|
||||||
|
int64_t EndTime(const Consensus::Params& params) const { return TestTime(20000); }
|
||||||
|
int Period(const Consensus::Params& params) const { return 1000; }
|
||||||
|
int Threshold(const Consensus::Params& params) const { return 900; }
|
||||||
|
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const { return (pindex->nVersion & 0x100); }
|
||||||
|
|
||||||
|
ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, paramsDummy, cache); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CHECKERS 6
|
||||||
|
|
||||||
|
class VersionBitsTester
|
||||||
|
{
|
||||||
|
// A fake blockchain
|
||||||
|
std::vector<CBlockIndex*> vpblock;
|
||||||
|
|
||||||
|
// 6 independent checkers for the same bit.
|
||||||
|
// The first one performs all checks, the second only 50%, the third only 25%, etc...
|
||||||
|
// This is to test whether lack of cached information leads to the same results.
|
||||||
|
TestConditionChecker checker[CHECKERS];
|
||||||
|
|
||||||
|
// Test counter (to identify failures)
|
||||||
|
int num;
|
||||||
|
|
||||||
|
public:
|
||||||
|
VersionBitsTester() : num(0) {}
|
||||||
|
|
||||||
|
VersionBitsTester& Reset() {
|
||||||
|
for (unsigned int i = 0; i < vpblock.size(); i++) {
|
||||||
|
delete vpblock[i];
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i < CHECKERS; i++) {
|
||||||
|
checker[i] = TestConditionChecker();
|
||||||
|
}
|
||||||
|
vpblock.clear();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~VersionBitsTester() {
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionBitsTester& Mine(unsigned int height, int32_t nTime, int32_t nVersion) {
|
||||||
|
while (vpblock.size() < height) {
|
||||||
|
CBlockIndex* pindex = new CBlockIndex();
|
||||||
|
pindex->nHeight = vpblock.size();
|
||||||
|
pindex->pprev = vpblock.size() > 0 ? vpblock.back() : NULL;
|
||||||
|
pindex->nTime = nTime;
|
||||||
|
pindex->nVersion = nVersion;
|
||||||
|
pindex->BuildSkip();
|
||||||
|
vpblock.push_back(pindex);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionBitsTester& TestDefined() {
|
||||||
|
for (int i = 0; i < CHECKERS; i++) {
|
||||||
|
if ((insecure_rand() & ((1 << i) - 1)) == 0) {
|
||||||
|
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_DEFINED, strprintf("Test %i for DEFINED", num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionBitsTester& TestStarted() {
|
||||||
|
for (int i = 0; i < CHECKERS; i++) {
|
||||||
|
if ((insecure_rand() & ((1 << i) - 1)) == 0) {
|
||||||
|
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_STARTED, strprintf("Test %i for STARTED", num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionBitsTester& TestLockedIn() {
|
||||||
|
for (int i = 0; i < CHECKERS; i++) {
|
||||||
|
if ((insecure_rand() & ((1 << i) - 1)) == 0) {
|
||||||
|
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_LOCKED_IN, strprintf("Test %i for LOCKED_IN", num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionBitsTester& TestActive() {
|
||||||
|
for (int i = 0; i < CHECKERS; i++) {
|
||||||
|
if ((insecure_rand() & ((1 << i) - 1)) == 0) {
|
||||||
|
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE", num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionBitsTester& TestFailed() {
|
||||||
|
for (int i = 0; i < CHECKERS; i++) {
|
||||||
|
if ((insecure_rand() & ((1 << i) - 1)) == 0) {
|
||||||
|
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? NULL : vpblock.back()) == THRESHOLD_FAILED, strprintf("Test %i for FAILED", num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBlockIndex * Tip() { return vpblock.size() ? vpblock.back() : NULL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_SUITE(versionbits_tests, TestingSetup)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(versionbits_test)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
// DEFINED -> FAILED
|
||||||
|
VersionBitsTester().TestDefined()
|
||||||
|
.Mine(1, TestTime(1), 0x100).TestDefined()
|
||||||
|
.Mine(11, TestTime(11), 0x100).TestDefined()
|
||||||
|
.Mine(989, TestTime(989), 0x100).TestDefined()
|
||||||
|
.Mine(999, TestTime(20000), 0x100).TestDefined()
|
||||||
|
.Mine(1000, TestTime(20000), 0x100).TestFailed()
|
||||||
|
.Mine(1999, TestTime(30001), 0x100).TestFailed()
|
||||||
|
.Mine(2000, TestTime(30002), 0x100).TestFailed()
|
||||||
|
.Mine(2001, TestTime(30003), 0x100).TestFailed()
|
||||||
|
.Mine(2999, TestTime(30004), 0x100).TestFailed()
|
||||||
|
.Mine(3000, TestTime(30005), 0x100).TestFailed()
|
||||||
|
|
||||||
|
// DEFINED -> STARTED -> FAILED
|
||||||
|
.Reset().TestDefined()
|
||||||
|
.Mine(1, TestTime(1), 0).TestDefined()
|
||||||
|
.Mine(1000, TestTime(10000) - 1, 0x100).TestDefined() // One second more and it would be defined
|
||||||
|
.Mine(2000, TestTime(10000), 0x100).TestStarted() // So that's what happens the next period
|
||||||
|
.Mine(2051, TestTime(10010), 0).TestStarted() // 51 old blocks
|
||||||
|
.Mine(2950, TestTime(10020), 0x100).TestStarted() // 899 new blocks
|
||||||
|
.Mine(3000, TestTime(20000), 0).TestFailed() // 50 old blocks (so 899 out of the past 1000)
|
||||||
|
.Mine(4000, TestTime(20010), 0x100).TestFailed()
|
||||||
|
|
||||||
|
// DEFINED -> STARTED -> FAILED while threshold reached
|
||||||
|
.Reset().TestDefined()
|
||||||
|
.Mine(1, TestTime(1), 0).TestDefined()
|
||||||
|
.Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined
|
||||||
|
.Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period
|
||||||
|
.Mine(2999, TestTime(30000), 0x100).TestStarted() // 999 new blocks
|
||||||
|
.Mine(3000, TestTime(30000), 0x100).TestFailed() // 1 new block (so 1000 out of the past 1000 are new)
|
||||||
|
.Mine(3999, TestTime(30001), 0).TestFailed()
|
||||||
|
.Mine(4000, TestTime(30002), 0).TestFailed()
|
||||||
|
.Mine(14333, TestTime(30003), 0).TestFailed()
|
||||||
|
.Mine(24000, TestTime(40000), 0).TestFailed()
|
||||||
|
|
||||||
|
// DEFINED -> STARTED -> LOCKEDIN at the last minute -> ACTIVE
|
||||||
|
.Reset().TestDefined()
|
||||||
|
.Mine(1, TestTime(1), 0).TestDefined()
|
||||||
|
.Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined
|
||||||
|
.Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period
|
||||||
|
.Mine(2050, TestTime(10010), 0x200).TestStarted() // 50 old blocks
|
||||||
|
.Mine(2950, TestTime(10020), 0x100).TestStarted() // 900 new blocks
|
||||||
|
.Mine(2999, TestTime(19999), 0x200).TestStarted() // 49 old blocks
|
||||||
|
.Mine(3000, TestTime(29999), 0x200).TestLockedIn() // 1 old block (so 900 out of the past 1000)
|
||||||
|
.Mine(3999, TestTime(30001), 0).TestLockedIn()
|
||||||
|
.Mine(4000, TestTime(30002), 0).TestActive()
|
||||||
|
.Mine(14333, TestTime(30003), 0).TestActive()
|
||||||
|
.Mine(24000, TestTime(40000), 0).TestActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity checks of version bit deployments
|
||||||
|
const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus();
|
||||||
|
for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
|
||||||
|
uint32_t bitmask = VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)i);
|
||||||
|
// Make sure that no deployment tries to set an invalid bit.
|
||||||
|
BOOST_CHECK_EQUAL(bitmask & ~(uint32_t)VERSIONBITS_TOP_MASK, bitmask);
|
||||||
|
|
||||||
|
// Verify that the deployment windows of different deployment using the
|
||||||
|
// same bit are disjoint.
|
||||||
|
// This test may need modification at such time as a new deployment
|
||||||
|
// is proposed that reuses the bit of an activated soft fork, before the
|
||||||
|
// end time of that soft fork. (Alternatively, the end time of that
|
||||||
|
// activated soft fork could be later changed to be earlier to avoid
|
||||||
|
// overlap.)
|
||||||
|
for (int j=i+1; j<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; j++) {
|
||||||
|
if (VersionBitsMask(mainnetParams, (Consensus::DeploymentPos)j) == bitmask) {
|
||||||
|
BOOST_CHECK(mainnetParams.vDeployments[j].nStartTime > mainnetParams.vDeployments[i].nTimeout ||
|
||||||
|
mainnetParams.vDeployments[i].nStartTime > mainnetParams.vDeployments[j].nTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
|
||||||
|
{
|
||||||
|
// Check that ComputeBlockVersion will set the appropriate bit correctly
|
||||||
|
// on mainnet.
|
||||||
|
const Consensus::Params &mainnetParams = Params(CBaseChainParams::MAIN).GetConsensus();
|
||||||
|
|
||||||
|
// Use the TESTDUMMY deployment for testing purposes.
|
||||||
|
int64_t bit = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit;
|
||||||
|
int64_t nStartTime = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime;
|
||||||
|
int64_t nTimeout = mainnetParams.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout;
|
||||||
|
|
||||||
|
assert(nStartTime < nTimeout);
|
||||||
|
|
||||||
|
// In the first chain, test that the bit is set by CBV until it has failed.
|
||||||
|
// In the second chain, test the bit is set by CBV while STARTED and
|
||||||
|
// LOCKED-IN, and then no longer set while ACTIVE.
|
||||||
|
VersionBitsTester firstChain, secondChain;
|
||||||
|
|
||||||
|
// Start generating blocks before nStartTime
|
||||||
|
int64_t nTime = nStartTime - 1;
|
||||||
|
|
||||||
|
// Before MedianTimePast of the chain has crossed nStartTime, the bit
|
||||||
|
// should not be set.
|
||||||
|
CBlockIndex *lastBlock = NULL;
|
||||||
|
lastBlock = firstChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
|
||||||
|
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
|
||||||
|
|
||||||
|
// Mine 2011 more blocks at the old time, and check that CBV isn't setting the bit yet.
|
||||||
|
for (int i=1; i<2012; i++) {
|
||||||
|
lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
|
||||||
|
// This works because VERSIONBITS_LAST_OLD_BLOCK_VERSION happens
|
||||||
|
// to be 4, and the bit we're testing happens to be bit 28.
|
||||||
|
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
|
||||||
|
}
|
||||||
|
// Now mine 5 more blocks at the start time -- MTP should not have passed yet, so
|
||||||
|
// CBV should still not yet set the bit.
|
||||||
|
nTime = nStartTime;
|
||||||
|
for (int i=2012; i<=2016; i++) {
|
||||||
|
lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
|
||||||
|
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance to the next period and transition to STARTED,
|
||||||
|
lastBlock = firstChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
|
||||||
|
// so ComputeBlockVersion should now set the bit,
|
||||||
|
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
|
||||||
|
// and should also be using the VERSIONBITS_TOP_BITS.
|
||||||
|
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS);
|
||||||
|
|
||||||
|
// Check that ComputeBlockVersion will set the bit until nTimeout
|
||||||
|
nTime += 600;
|
||||||
|
int blocksToMine = 4032; // test blocks for up to 2 time periods
|
||||||
|
int nHeight = 6048;
|
||||||
|
// These blocks are all before nTimeout is reached.
|
||||||
|
while (nTime < nTimeout && blocksToMine > 0) {
|
||||||
|
lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
|
||||||
|
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
|
||||||
|
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS);
|
||||||
|
blocksToMine--;
|
||||||
|
nTime += 600;
|
||||||
|
nHeight += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
nTime = nTimeout;
|
||||||
|
// FAILED is only triggered at the end of a period, so CBV should be setting
|
||||||
|
// the bit until the period transition.
|
||||||
|
for (int i=0; i<2015; i++) {
|
||||||
|
lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
|
||||||
|
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
|
||||||
|
nHeight += 1;
|
||||||
|
}
|
||||||
|
// The next block should trigger no longer setting the bit.
|
||||||
|
lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
|
||||||
|
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
|
||||||
|
|
||||||
|
// On a new chain:
|
||||||
|
// verify that the bit will be set after lock-in, and then stop being set
|
||||||
|
// after activation.
|
||||||
|
nTime = nStartTime;
|
||||||
|
|
||||||
|
// Mine one period worth of blocks, and check that the bit will be on for the
|
||||||
|
// next period.
|
||||||
|
lastBlock = secondChain.Mine(2016, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
|
||||||
|
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
|
||||||
|
|
||||||
|
// Mine another period worth of blocks, signaling the new bit.
|
||||||
|
lastBlock = secondChain.Mine(4032, nStartTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
|
||||||
|
// After one period of setting the bit on each block, it should have locked in.
|
||||||
|
// We keep setting the bit for one more period though, until activation.
|
||||||
|
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
|
||||||
|
|
||||||
|
// Now check that we keep mining the block until the end of this period, and
|
||||||
|
// then stop at the beginning of the next period.
|
||||||
|
lastBlock = secondChain.Mine(6047, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
|
||||||
|
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
|
||||||
|
lastBlock = secondChain.Mine(6048, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
|
||||||
|
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
|
||||||
|
|
||||||
|
// Finally, verify that after a soft fork has activated, CBV no longer uses
|
||||||
|
// VERSIONBITS_LAST_OLD_BLOCK_VERSION.
|
||||||
|
//BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
11
src/txdb.cpp
11
src/txdb.cpp
|
@ -272,11 +272,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
bool CBlockTreeDB::LoadBlockIndexGuts(int64_t forkStart, int64_t forkStop)
|
|
||||||
#else
|
|
||||||
bool CBlockTreeDB::LoadBlockIndexGuts()
|
bool CBlockTreeDB::LoadBlockIndexGuts()
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
|
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
|
||||||
|
|
||||||
|
@ -308,6 +304,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
||||||
pindexNew->hashAnchor = diskindex.hashAnchor;
|
pindexNew->hashAnchor = diskindex.hashAnchor;
|
||||||
pindexNew->nVersion = diskindex.nVersion;
|
pindexNew->nVersion = diskindex.nVersion;
|
||||||
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
|
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
|
||||||
|
pindexNew->hashReserved = diskindex.hashReserved;
|
||||||
pindexNew->nTime = diskindex.nTime;
|
pindexNew->nTime = diskindex.nTime;
|
||||||
pindexNew->nBits = diskindex.nBits;
|
pindexNew->nBits = diskindex.nBits;
|
||||||
pindexNew->nNonce = diskindex.nNonce;
|
pindexNew->nNonce = diskindex.nNonce;
|
||||||
|
@ -315,14 +312,8 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
||||||
pindexNew->nStatus = diskindex.nStatus;
|
pindexNew->nStatus = diskindex.nStatus;
|
||||||
pindexNew->nTx = diskindex.nTx;
|
pindexNew->nTx = diskindex.nTx;
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
if (pindexNew->nHeight < forkStart || pindexNew->nHeight >= forkStop) {
|
|
||||||
#endif
|
|
||||||
if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus()))
|
if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus()))
|
||||||
return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString());
|
return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString());
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pcursor->Next();
|
pcursor->Next();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -68,12 +68,7 @@ public:
|
||||||
bool WriteFlag(const std::string &name, bool fValue);
|
bool WriteFlag(const std::string &name, bool fValue);
|
||||||
bool ReadFlag(const std::string &name, bool &fValue);
|
bool ReadFlag(const std::string &name, bool &fValue);
|
||||||
|
|
||||||
#ifdef FORK_CB_INPUT
|
|
||||||
bool LoadBlockIndexGuts(int64_t forkStart, int64_t forkStop);
|
|
||||||
#else
|
|
||||||
bool LoadBlockIndexGuts();
|
bool LoadBlockIndexGuts();
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_TXDB_H
|
#endif // BITCOIN_TXDB_H
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
// Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "versionbits.h"
|
||||||
|
|
||||||
|
#include "consensus/params.h"
|
||||||
|
|
||||||
|
const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = {
|
||||||
|
{
|
||||||
|
/*.name =*/ "testdummy",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
|
||||||
|
{
|
||||||
|
int nPeriod = Period(params);
|
||||||
|
int nThreshold = Threshold(params);
|
||||||
|
int64_t nTimeStart = BeginTime(params);
|
||||||
|
int64_t nTimeTimeout = EndTime(params);
|
||||||
|
|
||||||
|
// A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
|
||||||
|
if (pindexPrev != NULL) {
|
||||||
|
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk backwards in steps of nPeriod to find a pindexPrev whose information is known
|
||||||
|
std::vector<const CBlockIndex*> vToCompute;
|
||||||
|
while (cache.count(pindexPrev) == 0) {
|
||||||
|
if (pindexPrev == NULL) {
|
||||||
|
// The genesis block is by definition defined.
|
||||||
|
cache[pindexPrev] = THRESHOLD_DEFINED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pindexPrev->GetMedianTimePast() < nTimeStart) {
|
||||||
|
// Optimization: don't recompute down further, as we know every earlier block will be before the start time
|
||||||
|
cache[pindexPrev] = THRESHOLD_DEFINED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vToCompute.push_back(pindexPrev);
|
||||||
|
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, cache[pindexPrev] is known
|
||||||
|
assert(cache.count(pindexPrev));
|
||||||
|
ThresholdState state = cache[pindexPrev];
|
||||||
|
|
||||||
|
// Now walk forward and compute the state of descendants of pindexPrev
|
||||||
|
while (!vToCompute.empty()) {
|
||||||
|
ThresholdState stateNext = state;
|
||||||
|
pindexPrev = vToCompute.back();
|
||||||
|
vToCompute.pop_back();
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case THRESHOLD_DEFINED: {
|
||||||
|
if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
|
||||||
|
stateNext = THRESHOLD_FAILED;
|
||||||
|
} else if (pindexPrev->GetMedianTimePast() >= nTimeStart) {
|
||||||
|
stateNext = THRESHOLD_STARTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case THRESHOLD_STARTED: {
|
||||||
|
if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
|
||||||
|
stateNext = THRESHOLD_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// We need to count
|
||||||
|
const CBlockIndex* pindexCount = pindexPrev;
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < nPeriod; i++) {
|
||||||
|
if (Condition(pindexCount, params)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
pindexCount = pindexCount->pprev;
|
||||||
|
}
|
||||||
|
if (count >= nThreshold) {
|
||||||
|
stateNext = THRESHOLD_LOCKED_IN;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case THRESHOLD_LOCKED_IN: {
|
||||||
|
// Always progresses into ACTIVE.
|
||||||
|
stateNext = THRESHOLD_ACTIVE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case THRESHOLD_FAILED:
|
||||||
|
case THRESHOLD_ACTIVE: {
|
||||||
|
// Nothing happens, these are terminal states.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cache[pindexPrev] = state = stateNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Class to implement versionbits logic.
|
||||||
|
*/
|
||||||
|
class VersionBitsConditionChecker : public AbstractThresholdConditionChecker {
|
||||||
|
private:
|
||||||
|
const Consensus::DeploymentPos id;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int64_t BeginTime(const Consensus::Params& params) const { return params.vDeployments[id].nStartTime; }
|
||||||
|
int64_t EndTime(const Consensus::Params& params) const { return params.vDeployments[id].nTimeout; }
|
||||||
|
int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; }
|
||||||
|
int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; }
|
||||||
|
|
||||||
|
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const
|
||||||
|
{
|
||||||
|
return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
|
||||||
|
uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)
|
||||||
|
{
|
||||||
|
return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos)
|
||||||
|
{
|
||||||
|
return VersionBitsConditionChecker(pos).Mask(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionBitsCache::Clear()
|
||||||
|
{
|
||||||
|
for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) {
|
||||||
|
caches[d].clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
// Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_CONSENSUS_VERSIONBITS
|
||||||
|
#define BITCOIN_CONSENSUS_VERSIONBITS
|
||||||
|
|
||||||
|
#include "chain.h"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
/** What block version to use for new blocks (pre versionbits) */
|
||||||
|
static const int32_t VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4;
|
||||||
|
/** What bits to set in version for versionbits blocks */
|
||||||
|
static const int32_t VERSIONBITS_TOP_BITS = 0x20000000UL;
|
||||||
|
/** What bitmask determines whether versionbits is in use */
|
||||||
|
static const int32_t VERSIONBITS_TOP_MASK = 0xE0000000UL;
|
||||||
|
/** Total bits available for versionbits */
|
||||||
|
static const int32_t VERSIONBITS_NUM_BITS = 29;
|
||||||
|
|
||||||
|
enum ThresholdState {
|
||||||
|
THRESHOLD_DEFINED,
|
||||||
|
THRESHOLD_STARTED,
|
||||||
|
THRESHOLD_LOCKED_IN,
|
||||||
|
THRESHOLD_ACTIVE,
|
||||||
|
THRESHOLD_FAILED,
|
||||||
|
};
|
||||||
|
|
||||||
|
// A map that gives the state for blocks whose height is a multiple of Period().
|
||||||
|
// The map is indexed by the block's parent, however, so all keys in the map
|
||||||
|
// will either be NULL or a block with (height + 1) % Period() == 0.
|
||||||
|
typedef std::map<const CBlockIndex*, ThresholdState> ThresholdConditionCache;
|
||||||
|
|
||||||
|
struct BIP9DeploymentInfo {
|
||||||
|
/** Deployment name */
|
||||||
|
const char *name;
|
||||||
|
/** Whether GBT clients can safely ignore this rule in simplified usage */
|
||||||
|
bool gbt_force;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class that implements BIP9-style threshold logic, and caches results.
|
||||||
|
*/
|
||||||
|
class AbstractThresholdConditionChecker {
|
||||||
|
protected:
|
||||||
|
virtual bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const =0;
|
||||||
|
virtual int64_t BeginTime(const Consensus::Params& params) const =0;
|
||||||
|
virtual int64_t EndTime(const Consensus::Params& params) const =0;
|
||||||
|
virtual int Period(const Consensus::Params& params) const =0;
|
||||||
|
virtual int Threshold(const Consensus::Params& params) const =0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Note that the function below takes a pindexPrev as input: they compute information for block B based on its parent.
|
||||||
|
ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VersionBitsCache
|
||||||
|
{
|
||||||
|
ThresholdConditionCache caches[Consensus::MAX_VERSION_BITS_DEPLOYMENTS];
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);
|
||||||
|
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue