Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delayed block penalization #62

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 12)
define(_CLIENT_VERSION_REVISION, 5)
define(_CLIENT_VERSION_BUILD, 1)
define(_CLIENT_VERSION_REVISION, 6)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2018)
define(_COPYRIGHT_YEAR, 2019)
AC_INIT([Paccoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/PACCommunity/PAC/issues],[paccoincore])
AC_CONFIG_SRCDIR([src/validation.cpp])
AC_CONFIG_HEADERS([src/config/paccoin-config.h])
Expand Down
1 change: 1 addition & 0 deletions qa/pull-tester/rpc-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
'invalidtxrequest.py', # NOTE: needs paccoin_hash to pass
'abandonconflict.py',
'p2p-versionbits-warning.py',
'blockdelay.py',
]
if ENABLE_ZMQ:
testScripts.append('zmq_test.py')
Expand Down
169 changes: 169 additions & 0 deletions qa/rpc-tests/blockdelay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#!/usr/bin/env python2
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2018 The Zencash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, initialize_chain_clean, \
start_nodes, start_node, connect_nodes, stop_node, stop_nodes, \
sync_blocks, sync_mempools, connect_nodes_bi, wait_bitcoinds, p2p_port, check_json_precision
import traceback
import os,sys
import shutil
from random import randint
from decimal import Decimal
import logging

import time
class blockdelay(BitcoinTestFramework):

alert_filename = None

def setup_chain(self, split=False):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
with open(self.alert_filename, 'w'):
pass # Just open then close to create zero-length file

def setup_network(self, split=False):
self.nodes = []
self.nodes = start_nodes(4, self.options.tmpdir)

if not split:
connect_nodes_bi(self.nodes, 1, 2)
sync_blocks(self.nodes[1:3])
sync_mempools(self.nodes[1:3])

connect_nodes_bi(self.nodes, 0, 1)
connect_nodes_bi(self.nodes, 2, 3)
self.is_network_split = split
self.sync_all()

def disconnect_nodes(self, from_connection, node_num):
ip_port = "127.0.0.1:"+str(p2p_port(node_num))
from_connection.disconnectnode(ip_port)
# poll until version handshake complete to avoid race conditions
# with transaction relaying
while any(peer['version'] == 0 for peer in from_connection.getpeerinfo()):
time.sleep(0.1)

def split_network(self):
# Split the network of four nodes into nodes 0/1 and 2/3.
assert not self.is_network_split
self.disconnect_nodes(self.nodes[1], 2)
self.disconnect_nodes(self.nodes[2], 1)
self.is_network_split = True


def join_network(self):
#Join the (previously split) network halves together.
assert self.is_network_split
connect_nodes_bi(self.nodes, 0, 3)
connect_nodes_bi(self.nodes, 3, 0)
connect_nodes_bi(self.nodes, 1, 3)
connect_nodes_bi(self.nodes, 3, 1)
#sync_blocks(self.nodes[0:3],1,True)
#sync_mempools(self.nodes[1:3])
self.sync_all()
self.is_network_split = False


def run_test(self):
blocks = []

blocks.append(self.nodes[0].getblockhash(0))
print("\n\nGenesis block is: " + blocks[0])
# raw_input("press enter to start..")

print("\n\nGenerating initial blockchain of 4 blocks")
blocks.extend(self.nodes[0].generate(1)) # block height 1
self.sync_all()
blocks.extend(self.nodes[1].generate(1)) # block height 2
self.sync_all()
blocks.extend(self.nodes[2].generate(1)) # block height 3
self.sync_all()
blocks.extend(self.nodes[3].generate(1)) # block height 4
self.sync_all()
print("Four blocks generated.")


print("\n\nSplit network")
self.split_network()
print("The network is split")


# Main chain
print("\n\nGenerating 2 parallel chains with different length")

print("\nGenerating 12 honest blocks (blocks 5-16)")
blocks.extend(self.nodes[0].generate(6)) # block height 5 -6 -7 -8 - 9 - 10
self.sync_all()
blocks.extend(self.nodes[1].generate(6)) # block height 11-12-13-14-15-16
last_main_blockhash=blocks[len(blocks)-1]
self.sync_all()
print("Honest blocks generated.")

assert self.nodes[0].getbestblockhash() == last_main_blockhash

# Malicious nodes mining privately faster
print("\nGenerating 13 malicious blocks (blocks 5-17)")
self.nodes[2].generate(10) # block height 5 - 6 -7 -8 -9-10 -11 12 13 14
self.sync_all()
self.nodes[3].generate(3) # block height 15 - 16 - 17
self.sync_all()
print("Malicious blocks generated.")


print("\n\nJoin network")
# raw_input("press enter to join the netorks..")
self.join_network()
time.sleep(2)
print("\nNetwork joined")

print("\nTesting if the current chain is still the honest chain")
assert self.nodes[0].getbestblockhash() == last_main_blockhash
print("Confirmed: malicious chain is under penalty")

print("\nTesting chaintips")
current_chain_tips = self.nodes[0].getchaintips()
assert (current_chain_tips[0]['penalization'] == 65)
print("Malicious chain is correctly penalized with 65 blocks after generating 12 old blocks + 1 new block.")

print("\nGenerating 64 malicious blocks (New height = 81)")
self.nodes[3].generate(64)
print("Malicious blocks generated")

time.sleep(10)

print("\nTesting if the current chain is still the honest chain")
assert self.nodes[0].getbestblockhash() == last_main_blockhash
print("Confirmed: malicious chain is under penalty")

print("\nGenerating 65 more honest blocks (New height = 81)")
self.nodes[0].generate(65)
print("Honest blocks generated")

print("\nGenerating 1 more malicious block (New height = 82)")
last_malicious_blockhash=self.nodes[3].generate(1)[0]
print("Malicious blocks generated")

print("\nWaiting that all network nodes are synced with same chain length")
sync_blocks(self.nodes, 1, True)
print("Network nodes are synced")

print("\nTesting if all the nodes/chains have the same best tip")
assert (self.nodes[0].getbestblockhash() == self.nodes[1].getbestblockhash()
== self.nodes[2].getbestblockhash() == self.nodes[3].getbestblockhash())
print("Confirmed: all the nodes have the same best tip")

print("\nTesting if the current chain switched to the malicious chain")
assert self.nodes[0].getbestblockhash() == last_malicious_blockhash
print("Confirmed: malicious chain is the best chain")

time.sleep(2)
sync_mempools(self.nodes)

if __name__ == '__main__':
blockdelay().main()
2 changes: 1 addition & 1 deletion qa/rpc-tests/test_framework/authproxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@

USER_AGENT = "AuthServiceProxy/0.1"

HTTP_TIMEOUT = 30
HTTP_TIMEOUT = 600

log = logging.getLogger("BitcoinRPC")

Expand Down
6 changes: 3 additions & 3 deletions qa/rpc-tests/test_framework/test_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ def split_network(self):

def sync_all(self):
if self.is_network_split:
sync_blocks(self.nodes[:2])
sync_blocks(self.nodes[2:])
sync_blocks(self.nodes[:2], p=False)
sync_blocks(self.nodes[2:], p=False)
sync_mempools(self.nodes[:2])
sync_mempools(self.nodes[2:])
else:
sync_blocks(self.nodes)
sync_blocks(self.nodes, p=False)
sync_mempools(self.nodes)

def join_network(self):
Expand Down
6 changes: 4 additions & 2 deletions qa/rpc-tests/test_framework/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,14 @@ def hex_str_to_bytes(hex_str):
def str_to_b64str(string):
return b64encode(string.encode('utf-8')).decode('ascii')

def sync_blocks(rpc_connections, wait=1):
def sync_blocks(rpc_connections, wait=1, p=False):
"""
Wait until everybody has the same block count
"""
while True:
counts = [ x.getblockcount() for x in rpc_connections ]
if p:
print counts
if counts == [ counts[0] ]*len(counts):
break
time.sleep(wait)
Expand Down Expand Up @@ -294,7 +296,7 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=
url = rpc_url(i, rpchost)
wait_for_bitcoind_start(bitcoind_processes[i], url, i)
if os.getenv("PYTHON_DEBUG", ""):
print "start_node: RPC succesfully started"
print "start_node: RPC succesfully started at: " + url
proxy = get_rpc_proxy(url, i, timeout=timewait)

if COVERAGE_DIR:
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ BITCOIN_CORE_H = \
wallet/wallet.h \
wallet/wallet_ismine.h \
wallet/walletdb.h \
zen/delay.h \
zmq/zmqabstractnotifier.h \
zmq/zmqconfig.h\
zmq/zmqnotificationinterface.h \
Expand Down Expand Up @@ -266,6 +267,7 @@ libbitcoin_server_a_SOURCES = \
validation.cpp \
validationinterface.cpp \
versionbits.cpp \
zen/delay.cpp \
$(BITCOIN_CORE_H)

if ENABLE_ZMQ
Expand Down
3 changes: 3 additions & 0 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ class CBlockIndex
//! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block
arith_uint256 nChainWork;

int64_t nChainDelay;

//! Number of transactions in this block.
//! Note: in a potential headers-first mode, this number cannot be relied upon
unsigned int nTx;
Expand Down Expand Up @@ -210,6 +212,7 @@ class CBlockIndex
nDataPos = 0;
nUndoPos = 0;
nChainWork = arith_uint256();
nChainDelay = 0;
nTx = 0;
nChainTx = 0;
nStatus = 0;
Expand Down
12 changes: 6 additions & 6 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
#define TESTNET_GENESIS_NONCE 2279587UL
#define TESTNET_GENESIS_TIMESTAMP 1517541975UL

#define REGTEST_GENESIS_HASH "0x084c58211fe102add2fb5c3976f14f997e3c27a3a6fd5ab15a1929f7b5db9d95"
#define REGTEST_GENESIS_NONCE 1UL
#define REGTEST_GENESIS_TIMESTAMP 1517542062UL
#define REGTEST_GENESIS_HASH "0x03ddaf131760ea9614a00fd504b035061b6ad367dc91be7a8821bd787484cba0"
#define REGTEST_GENESIS_NONCE 2UL
#define REGTEST_GENESIS_TIMESTAMP 1548210160UL

static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward, const Consensus::Params& consensus)
{
Expand Down Expand Up @@ -402,10 +402,10 @@ class CRegTestParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0001].nTimeout = 999999999999ULL;

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000000000000000100010");
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000000000000000000002");

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

pchMessageStart[0] = 0x96;
pchMessageStart[1] = 0xa6;
Expand Down Expand Up @@ -434,7 +434,7 @@ class CRegTestParams : public CChainParams {

checkpointData = (CCheckpointData){
boost::assign::map_list_of
( 0, uint256S("0x084c58211fe102add2fb5c3976f14f997e3c27a3a6fd5ab15a1929f7b5db9d95")),
( 0, uint256S("0x03ddaf131760ea9614a00fd504b035061b6ad367dc91be7a8821bd787484cba0")),
0,
0,
0
Expand Down
6 changes: 3 additions & 3 deletions src/clientversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
//! These need to be macros, as clientversion.cpp's and paccoin*-res.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 0
#define CLIENT_VERSION_MINOR 12
#define CLIENT_VERSION_REVISION 5
#define CLIENT_VERSION_BUILD 1
#define CLIENT_VERSION_REVISION 6
#define CLIENT_VERSION_BUILD 0

//! Set to true for release, false for prerelease or test build
#define CLIENT_VERSION_IS_RELEASE true
Expand All @@ -26,7 +26,7 @@
* Copyright year (2009-this)
* Todo: update this when changing our copyright comments in the source
*/
#define COPYRIGHT_YEAR 2018
#define COPYRIGHT_YEAR 2019

#endif //HAVE_CONFIG_H

Expand Down
4 changes: 3 additions & 1 deletion src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp)
" \"chainwork\" : \"0000...1f3\" (string) Expected number of hashes required to produce the current chain (in hex)\n"
" \"branchlen\": 0 (numeric) zero for main chain\n"
" \"status\": \"active\" (string) \"active\" for the main chain\n"
" \"penalization\": 0 (numeric) zero for main chain\n"
" },\n"
" {\n"
" \"height\": xxxx,\n"
Expand All @@ -932,6 +933,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp)
" \"chainwork\" : \"0000...1f3\"\n"
" \"branchlen\": 1 (numeric) length of branch connecting the tip to the main chain\n"
" \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
" \"penalization\": 0 (numeric) penalization of the chain, zero for the main chain.\n"
" }\n"
"]\n"
"Possible values for status:\n"
Expand Down Expand Up @@ -1009,7 +1011,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp)
status = "unknown";
}
obj.push_back(Pair("status", status));

obj.push_back(Pair("penalization", block->nChainDelay));
res.push_back(obj);
}

Expand Down
Loading