...
 
Commits (140)
variables:
RELEASE_VERSION: "0.13.4.0"
RELEASE_VERSION: "0.13.9.0"
GIT_STRATEGY: "clone"
MAKEJOBS: "-j4"
CCACHE_SIZE: "100M"
......
......@@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 13)
define(_CLIENT_VERSION_REVISION, 4)
define(_CLIENT_VERSION_REVISION, 9)
define(_CLIENT_VERSION_BUILD, 0)
define(_COPYRIGHT_YEAR, 2019)
AC_INIT([Crown Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[[email protected]],[crown])
......@@ -37,7 +37,7 @@ else
CXXFLAGS_overridden=no
fi
AC_PROG_CXX
m4_ifdef([AC_PROG_OBJCXX],[AC_PROG_OBJCXX])
m4 ifdef([AC_PROG_OBJCXX],[AC_PROG_OBJCXX])
dnl By default, libtool for mingw refuses to link static libs into a dll for
dnl fear of mixing pic/non-pic objects, and import/export complications. Since
......
# Linearize
Construct a linear, no-fork, best version of the blockchain.
Construct a linear, no-fork, best version of the Crown blockchain.
## Step 1: Download hash list
$ ./linearize-hashes.py linearize.cfg > hashlist.txt
$ ./linearize-hashes.py crown.cfg > hashlist.txt
Required configuration file settings for linearize-hashes:
* RPC: rpcuser, rpcpassword
* RPC: `datadir` (Required if `rpcuser` and `rpcpassword` are not specified)
* RPC: `rpcuser`, `rpcpassword` (Required if `datadir` is not specified)
Optional config file setting for linearize-hashes:
* RPC: host, port
* Block chain: min_height, max_height
* RPC: `host` (Default: `127.0.0.1`)
* RPC: `port` (Default: `9341`)
* Blockchain: `min_height`, `max_height`
* `rev_hash_bytes`: If true, the written block hash list will be
byte-reversed. (In other words, the hash returned by getblockhash will have its
bytes reversed.) False by default. Intended for generation of
standalone hash lists but safe to use with linearize-data.py, which will output
the same data no matter which byte format is chosen.
The `linearize-hashes` script requires a connection, local or remote, to a
JSON-RPC server. Running `crownd` or `crown-qt -server` will be sufficient.
## Step 2: Copy local block data
$ ./linearize-data.py linearize.cfg
$ ./linearize-data.py crown.cfg
Required configuration file settings:
* "input": bitcoind blocks/ directory containing blkNNNNN.dat
* "hashlist": text file containing list of block hashes, linearized-hashes.py
output.
* "output_file": bootstrap.dat
* `output_file`: The file that will contain the final blockchain.
or
* "output": output directory for linearized blocks/blkNNNNN.dat output
* `output`: Output directory for linearized `blocks/blkNNNNN.dat` output.
Optional config file setting for linearize-data:
* "netmagic": network magic number
* "max_out_sz": maximum output file size (default 1000*1000*1000)
* "split_timestamp": Split files when a new month is first seen, in addition to
reaching a maximum file size.
* "file_timestamp": Set each file's last-modified time to that of the
most recent block in that file.
* `debug_output`: Some printouts may not always be desired. If true, such output
will be printed.
* `file_timestamp`: Set each file's last-accessed and last-modified times,
respectively, to the current time and to the timestamp of the most recent block
written to the script's blockchain.
* `genesis`: The hash of the genesis block in the blockchain.
* `input`: crownd blocks/ directory containing blkNNNNN.dat
* `hashlist`: text file containing list of block hashes created by
linearize-hashes.py.
* `max_out_sz`: Maximum size for files created by the `output_file` option.
(Default: `1000*1000*1000 bytes`)
* `netmagic`: Network magic number.
* `out_of_order_cache_sz`: If out-of-order blocks are being read, the block can
be written to a cache so that the blockchain doesn't have to be sought again.
This option specifies the cache size. (Default: `100*1000*1000 bytes`)
* `rev_hash_bytes`: If true, the block hash list written by linearize-hashes.py
will be byte-reversed when read by linearize-data.py. See the linearize-hashes
entry for more information.
* `split_timestamp`: Split blockchain files when a new month is first seen, in
addition to reaching a maximum file size (`max_out_sz`).
# crownd RPC settings (linearize-hashes)
host=127.0.0.1
port=9341
rpcuser=crownuser
rpcpassword=crownuserpassword
# bootstrap.dat hashlist settings (linearize-hashes)
max_height=2340250
# bootstrap.dat input/output settings (linearize-data)
netmagic=b8ebb3df
genesis=0000000085370d5e122f64f4ab19c68614ff3df78c8d13cb814fd7e69a1dc6da
input=/home/crown/.crown/blocks
output_file=/home/crown/bootstrap.dat
hashlist=hashlist.txt
split_year=1
file_timestamp=1
# Maxmimum size in bytes of out-of-order blocks cache in memory
out_of_order_cache_sz = 100000000
# Do we want the reverse the hash bytes coming from getblockhash?
rev_hash_bytes = false
# Do we want debug printouts?
debug_output = true
# bitcoind RPC settings (linearize-hashes)
rpcuser=someuser
rpcpassword=somepassword
#datadir=~/.bitcoin
host=127.0.0.1
port=9998
#mainnet default
port=8332
#testnet default
#port=18332
#regtest default
#port=18443
# bootstrap.dat hashlist settings (linearize-hashes)
max_height=313000
# bootstrap.dat input/output settings (linearize-data)
# mainnet
netmagic=f9beb4d9
genesis=000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
input=/home/example/.bitcoin/blocks
# testnet
#netmagic=0b110907
#genesis=000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943
#input=/home/example/.bitcoin/testnet3/blocks
# "output" option causes blockchain files to be written to the given location,
# with "output_file" ignored. If not used, "output_file" is used instead.
# output=/home/example/blockchain_directory
output_file=/home/example/Downloads/bootstrap.dat
hashlist=hashlist.txt
split_year=1
# Maxmimum size in bytes of out-of-order blocks cache in memory
# Maximum size in bytes of out-of-order blocks cache in memory
out_of_order_cache_sz = 100000000
# Do we want the reverse the hash bytes coming from getblockhash?
rev_hash_bytes = False
# On a new month, do we want to set the access and modify times of the new
# blockchain file?
file_timestamp = 0
# Do we want to split the blockchain files given a new month or specific height?
split_timestamp = 0
# Do we want debug printouts?
debug_output = False
This diff is collapsed.
#!/usr/bin/python
#!/usr/bin/env python3
#
# linearize-hashes.py: List blocks in a linear, no-fork version of the chain.
#
# Copyright (c) 2013-2014 The Bitcoin developers
# Distributed under the MIT/X11 software license, see the accompanying
# Copyright (c) 2013-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
from __future__ import print_function
from http.client import HTTPConnection
import json
import struct
import re
import base64
import httplib
import sys
import os
import os.path
settings = {}
def hex_switchEndian(s):
""" Switches the endianness of a hex string (in pairs of hex chars) """
pairList = [s[i:i+2].encode() for i in range(0, len(s), 2)]
return b''.join(pairList[::-1]).decode()
class BitcoinRPC:
def __init__(self, host, port, username, password):
authpair = "%s:%s" % (username, password)
self.authhdr = "Basic %s" % (base64.b64encode(authpair))
self.conn = httplib.HTTPConnection(host, port, False, 30)
def execute(self, obj):
self.conn.request('POST', '/', json.dumps(obj),
{ 'Authorization' : self.authhdr,
'Content-type' : 'application/json' })
resp = self.conn.getresponse()
if resp is None:
print("JSON-RPC: no response", file=sys.stderr)
return None
body = resp.read()
resp_obj = json.loads(body)
return resp_obj
@staticmethod
def build_request(idx, method, params):
obj = { 'version' : '1.1',
'method' : method,
'id' : idx }
if params is None:
obj['params'] = []
else:
obj['params'] = params
return obj
@staticmethod
def response_is_error(resp_obj):
return 'error' in resp_obj and resp_obj['error'] is not None
def __init__(self, host, port, username, password):
authpair = "%s:%s" % (username, password)
authpair = authpair.encode('utf-8')
self.authhdr = b"Basic " + base64.b64encode(authpair)
self.conn = HTTPConnection(host, port=port, timeout=30)
def execute(self, obj):
try:
self.conn.request('POST', '/', json.dumps(obj),
{ 'Authorization' : self.authhdr,
'Content-type' : 'application/json' })
except ConnectionRefusedError:
print('RPC connection refused. Check RPC settings and the server status.',
file=sys.stderr)
return None
resp = self.conn.getresponse()
if resp is None:
print("JSON-RPC: no response", file=sys.stderr)
return None
body = resp.read().decode('utf-8')
resp_obj = json.loads(body)
return resp_obj
@staticmethod
def build_request(idx, method, params):
obj = { 'version' : '1.1',
'method' : method,
'id' : idx }
if params is None:
obj['params'] = []
else:
obj['params'] = params
return obj
@staticmethod
def response_is_error(resp_obj):
return 'error' in resp_obj and resp_obj['error'] is not None
def get_block_hashes(settings, max_blocks_per_call=10000):
rpc = BitcoinRPC(settings['host'], settings['port'],
settings['rpcuser'], settings['rpcpassword'])
height = settings['min_height']
while height < settings['max_height']+1:
num_blocks = min(settings['max_height']+1-height, max_blocks_per_call)
batch = []
for x in range(num_blocks):
batch.append(rpc.build_request(x, 'getblockhash', [height + x]))
reply = rpc.execute(batch)
for x,resp_obj in enumerate(reply):
if rpc.response_is_error(resp_obj):
print('JSON-RPC: error at height', height+x, ': ', resp_obj['error'], file=sys.stderr)
exit(1)
assert(resp_obj['id'] == x) # assume replies are in-sequence
print(resp_obj['result'])
height += num_blocks
rpc = BitcoinRPC(settings['host'], settings['port'],
settings['rpcuser'], settings['rpcpassword'])
height = settings['min_height']
while height < settings['max_height']+1:
num_blocks = min(settings['max_height']+1-height, max_blocks_per_call)
batch = []
for x in range(num_blocks):
batch.append(rpc.build_request(x, 'getblockhash', [height + x]))
reply = rpc.execute(batch)
if reply is None:
print('Cannot continue. Program will halt.')
return None
for x,resp_obj in enumerate(reply):
if rpc.response_is_error(resp_obj):
print('JSON-RPC: error at height', height+x, ': ', resp_obj['error'], file=sys.stderr)
sys.exit(1)
assert(resp_obj['id'] == x) # assume replies are in-sequence
if settings['rev_hash_bytes'] == 'true':
resp_obj['result'] = hex_switchEndian(resp_obj['result'])
print(resp_obj['result'])
height += num_blocks
def get_rpc_cookie():
# Open the cookie file
with open(os.path.join(os.path.expanduser(settings['datadir']), '.cookie'), 'r', encoding="ascii") as f:
combined = f.readline()
combined_split = combined.split(":")
settings['rpcuser'] = combined_split[0]
settings['rpcpassword'] = combined_split[1]
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: linearize-hashes.py CONFIG-FILE")
sys.exit(1)
f = open(sys.argv[1])
for line in f:
# skip comment lines
m = re.search('^\s*#', line)
if m:
continue
# parse key=value lines
m = re.search('^(\w+)\s*=\s*(\S.*)$', line)
if m is None:
continue
settings[m.group(1)] = m.group(2)
f.close()
if 'host' not in settings:
settings['host'] = '127.0.0.1'
if 'port' not in settings:
settings['port'] = 9998
if 'min_height' not in settings:
settings['min_height'] = 0
if 'max_height' not in settings:
settings['max_height'] = 313000
if 'rpcuser' not in settings or 'rpcpassword' not in settings:
print("Missing username and/or password in cfg file", file=stderr)
sys.exit(1)
settings['port'] = int(settings['port'])
settings['min_height'] = int(settings['min_height'])
settings['max_height'] = int(settings['max_height'])
get_block_hashes(settings)
if len(sys.argv) != 2:
print("Usage: linearize-hashes.py CONFIG-FILE")
sys.exit(1)
f = open(sys.argv[1], encoding="utf8")
for line in f:
# skip comment lines
m = re.search('^\s*#', line)
if m:
continue
# parse key=value lines
m = re.search('^(\w+)\s*=\s*(\S.*)$', line)
if m is None:
continue
settings[m.group(1)] = m.group(2)
f.close()
if 'host' not in settings:
settings['host'] = '127.0.0.1'
if 'port' not in settings:
settings['port'] = 9341
if 'min_height' not in settings:
settings['min_height'] = 0
if 'max_height' not in settings:
settings['max_height'] = 2340250
if 'rev_hash_bytes' not in settings:
settings['rev_hash_bytes'] = 'false'
use_userpass = True
use_datadir = False
if 'rpcuser' not in settings or 'rpcpassword' not in settings:
use_userpass = False
if 'datadir' in settings and not use_userpass:
use_datadir = True
if not use_userpass and not use_datadir:
print("Missing datadir or username and/or password in cfg file", file=sys.stderr)
sys.exit(1)
settings['port'] = int(settings['port'])
settings['min_height'] = int(settings['min_height'])
settings['max_height'] = int(settings['max_height'])
# Force hash byte format setting to be lowercase to make comparisons easier.
settings['rev_hash_bytes'] = settings['rev_hash_bytes'].lower()
# Get the rpc user and pass from the cookie if the datadir is set
if use_datadir:
get_rpc_cookie()
get_block_hashes(settings)
......@@ -295,16 +295,11 @@ class Sandbox:
return out.strip()
def get_transaction(self, node, txhash, binary='crown-cli'):
rtx, err = self.client_command(node, binary, 'getrawtransaction', txhash)
tx, err = self.client_command(node, binary, 'getrawtransaction', txhash, '1')
if len(err) != 0:
print err
assert (len(err) == 0)
dtx, err = self.client_command(node, binary, 'decoderawtransaction', rtx.strip())
if len(err) != 0:
print err
print rtx
assert (len(err) == 0)
return json.loads(dtx)
return json.loads(tx)
def create_key(self, node, binary='crown-cli'):
out, err = self.client_command(node, binary, 'node', 'genkey')
......@@ -354,8 +349,24 @@ class Sandbox:
self.write_config(masternode)
self.start_node(masternode)
time.sleep(1)
self.start_masternode(control_node, masternode)
while 'confirmations' not in colltx or colltx['confirmations'] < 15:
print '{0} confirmations, waiting'.format(colltx['confirmations'] if 'confirmations' in colltx else 0)
time.sleep(2)
colltx = self.get_transaction(control_node, txhash)
out, err = self.start_masternode(control_node, masternode)
print err
print out
def stop_nodes(self, nodes=None):
if nodes is None:
nodes = []
nodes = nodes if nodes != [] else self.network['nodes'].iterkeys()
for name in nodes:
try:
self.stop_node(name)
except RuntimeError as e:
print e
def stop_node(self, node):
return self.client_command(node, 'crown-cli', 'stop')
......@@ -367,7 +378,7 @@ class Sandbox:
return [k for k, v in self.network['nodes'].iteritems() if v['masternodes'] != []]
def start_masternode(self, control_node, masternode):
self.client_command(control_node, 'crown-cli', 'masternode', 'start-alias', masternode)
return self.client_command(control_node, 'crown-cli', 'masternode', 'start-alias', masternode)
def gen_or_reuse_address(self, node):
if 'receive_with' in self.network['nodes'][node]:
......@@ -376,6 +387,14 @@ class Sandbox:
self.network['nodes'][node]['receive_with'] = self.gen_address(node)
return self.network['nodes'][node]['receive_with']
def get_block_height(self, node):
try:
out, err = self.client_command(node, 'crown-cli', 'getinfo')
info = json.loads(out)
return int(info['blocks'])
except ValueError:
return 0
def prepare(json_desc_file, target_dir, bin_dir):
sb = Sandbox(bin_dir, target_dir, open(json_desc_file))
......@@ -387,6 +406,11 @@ def start(json_desc_file, target_dir, bin_dir, nodes):
sb.start_nodes(nodes)
def stop(json_desc_file, target_dir, bin_dir, nodes):
sb = Sandbox(bin_dir, target_dir, open(json_desc_file))
sb.stop_nodes(nodes)
def command(json_desc_file, target_dir, bin_dir, node, *args):
sb = Sandbox(bin_dir, target_dir, open(json_desc_file))
if node == '_':
......@@ -442,6 +466,21 @@ def run_simulation(json_desc_file, target_dir, bin_dir):
print 'Setting up masternode {0}'.format(mn)
sb.setup_masternode(node, mn)
blockheight = sb.get_block_height(node)
while blockheight == 0:
print 'Cannot get block height. Retrying...'
time.sleep(2)
blockheight = sb.get_block_height(node)
while True:
time.sleep(2)
if sb.get_block_height(node) > blockheight + 15:
break
out, err = sb.start_masternode(node, mn)
print err
print out
print 'Next masternode is {0}'.format(sb.next_masternode_to_setup()[0])
except RuntimeError:
......@@ -469,6 +508,8 @@ if __name__ == '__main__':
prepare(parsed.file, parsed.directory, parsed.bin_directory)
elif parsed.command[0] == 'start':
start(parsed.file, parsed.directory, parsed.bin_directory, parsed.command[1:])
elif parsed.command[0] == 'stop':
stop(parsed.file, parsed.directory, parsed.bin_directory, parsed.command[1:])
elif parsed.command[0] == 'cmd':
command(parsed.file, parsed.directory, parsed.bin_directory, parsed.command[1], *parsed.command[2:])
elif parsed.command[0] == 'sim':
......
......@@ -149,6 +149,23 @@ BITCOIN_CORE_H = \
mn-pos/stakeminer.h \
mn-pos/stakevalidation.h \
nodeconfig.h \
platform/specialtx-common.h \
platform/specialtx.h \
platform/platform-db.h \
platform/platform-utils.h \
platform/rpc/rpcagents.h \
platform/rpc/rpc-nf-token.h \
platform/rpc/specialtx-rpc-utils.h \
platform/nf-token/nf-token-multiindex-utils.h \
platform/nf-token/nf-tokens-single-protocol-manager.h \
platform/nf-token/nf-tokens-manager.h \
platform/nf-token/nf-token-tx-mem-pool-handler.h \
platform/nf-token/nf-token-reg-tx-builder.h \
platform/nf-token/nf-token-reg-tx.h \
platform/nf-token/nf-token-protocol-reg-tx.h \
platform/nf-token/nf-token-protocol.h \
platform/nf-token/nf-token.h \
platform/nf-token/nf-token-index.h \
systemnode.h \
systemnode-payments.h \
systemnode-sync.h \
......@@ -232,7 +249,26 @@ libbitcoin_server_a_SOURCES = \
txdb.cpp \
txmempool.cpp \
dbdetails.cpp \
$(JSON_H) \
platform/agent.cpp \
platform/agent.h \
platform/governance.cpp \
platform/governance.h \
platform/governance-approval-voting.h \
platform/governance-approval-voting.cpp \
platform/governance-vote.cpp \
platform/governance-vote.h \
platform/specialtx.cpp \
platform/platform-db.cpp \
platform/rpc/specialtx-rpc-utils.cpp \
platform/rpc/rpcagents.cpp \
platform/rpc/rpc-nf-token.cpp \
platform/nf-token/nf-token-multiindex-utils.cpp \
platform/nf-token/nf-tokens-single-protocol-manager.cpp \
platform/nf-token/nf-tokens-manager.cpp \
platform/nf-token/nf-token-tx-mem-pool-handler.cpp \
platform/nf-token/nf-token-reg-tx.cpp \
platform/nf-token/nf-token-protocol-reg-tx.cpp \
$(JSON_H) \
$(BITCOIN_CORE_H)
# wallet: shared between crownd and crown-qt, but only linked
......
......@@ -34,7 +34,7 @@ RAW_TEST_FILES = test/data/alertTests.raw
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
BITCOIN_TESTS =\
test/governance-test.cpp \
test/mnbudget-test.cpp \
test/arith_uint256_tests.cpp \
test/bignum.h \
test/alert_tests.cpp \
......
......@@ -16,7 +16,7 @@
//! These need to be macros, as clientversion.cpp's and crown*-res.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 0
#define CLIENT_VERSION_MINOR 13
#define CLIENT_VERSION_REVISION 4
#define CLIENT_VERSION_REVISION 9
#define CLIENT_VERSION_BUILD 0
/**
......
......@@ -6,12 +6,26 @@
#define BITCOIN_COINCONTROL_H
#include "primitives/transaction.h"
#include "script/standard.h"
/** Coin Control Features. */
class CCoinControl
{
public:
CTxDestination destChange;
bool fUseInstantSend;
//! If false, allows unselected inputs, but requires all selected inputs be used
bool fAllowOtherInputs;
//! Includes watch only addresses which match the ISMINE_WATCH_SOLVABLE criteria
bool fAllowWatchOnly;
//! Minimum absolute fee (not per kilobyte)
CAmount nMinimumTotalFee;
//! Override estimated feerate
bool fOverrideFeeRate;
//! Feerate to use if overrideFeeRate is true
CFeeRate nFeeRate;
//! Override the default confirmation target, 0 = use default
int nConfirmTarget;
CCoinControl()
{
......@@ -21,7 +35,14 @@ public:
void SetNull()
{
destChange = CNoDestination();
fAllowOtherInputs = false;
fAllowWatchOnly = false;
setSelected.clear();
fUseInstantSend = false;
nMinimumTotalFee = 0;
nFeeRate = CFeeRate(0);
fOverrideFeeRate = false;
nConfirmTarget = 0;
}
bool HasSelected() const
......@@ -35,6 +56,11 @@ public:
return (setSelected.count(outpt) > 0);
}
bool IsSelected(const COutPoint& output) const
{
return (setSelected.count(output) > 0);
}
void Select(const COutPoint& output)
{
setSelected.insert(output);
......
......@@ -39,6 +39,7 @@
#include "utilmoneystr.h"
#include "dbmanager.h"
#include "instantx.h"
#include "platform/platform-db.h"
#ifdef ENABLE_WALLET
#include "db.h"
#include "wallet.h"
......@@ -216,6 +217,7 @@ void PrepareShutdown()
pcoinsdbview = NULL;
delete pblocktree;
pblocktree = NULL;
Platform::PlatformDb::DestroyInstance();
}
#ifdef ENABLE_WALLET
if (pwalletMain)
......@@ -243,6 +245,9 @@ void Shutdown()
PrepareShutdown();
}
// Unregister NFT special transaction mempool handler
g_nfTokenTxMemPoolHandler.UnregisterSelf(mempool);
// Shutdown part 2: delete wallet instance
#ifdef ENABLE_WALLET
delete pwalletMain;
......@@ -465,6 +470,9 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -rpcthreads=<n> " + strprintf(_("Set the number of threads to service RPC calls (default: %d)"), 4) + "\n";
strUsage += " -rpckeepalive " + strprintf(_("RPC support for HTTP persistent connections (default: %d)"), 1) + "\n";
strUsage += "\n" + _("Platform options:") + "\n";
strUsage += " -platformoptram=<n> " + strprintf(_("Optimize the platform server RAM usage (but respond much slower) or optimize speed (server latency) (0-1, default: %u)"), 0) + "\n";
strUsage += "\n" + _("RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
strUsage += " -rpcsslcertificatechainfile=<file.cert> " + strprintf(_("Server certificate file (default: %s)"), "server.cert") + "\n";
......@@ -828,6 +836,8 @@ bool AppInit2(boost::thread_group& threadGroup)
if (GetBoolArg("-benchmark", false))
InitWarning(_("Warning: Unsupported argument -benchmark ignored, use -debug=bench."));
// Register NFT special transaction mempool handler
g_nfTokenTxMemPoolHandler.RegisterSelf(mempool);
// Checkmempool and checkblockindex default to true in regtest mode
mempool.setSanityCheck(GetBoolArg("-checkmempool", Params().DefaultConsistencyChecks()));
fCheckBlockIndex = GetBoolArg("-checkblockindex", Params().DefaultConsistencyChecks());
......@@ -1245,6 +1255,9 @@ bool AppInit2(boost::thread_group& threadGroup)
}
}
bool platformOptRam = GetBoolArg("-platformoptram", false);
Platform::PlatformOpt opt = platformOptRam ? Platform::PlatformOpt::OptRam : Platform::PlatformOpt::OptSpeed;
// cache size calculations
int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
......@@ -1257,6 +1270,7 @@ bool AppInit2(boost::thread_group& threadGroup)
nTotalCache -= nCoinDBCache;
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
int64_t nMempoolSizeMax = GetArg("-maxmempool", 300) * 1000000;
int64_t nPlatformDbCache = 1024 * 1024 * 10; //TODO: set appropriate platform db cache size
LogPrintf("Cache configuration:\n");
LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
......@@ -1277,7 +1291,9 @@ bool AppInit2(boost::thread_group& threadGroup)
delete pcoinsdbview;
delete pcoinscatcher;
delete pblocktree;
Platform::PlatformDb::DestroyInstance();
Platform::PlatformDb::CreateInstance(nPlatformDbCache, opt, false, fReindex);
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
......@@ -1313,7 +1329,7 @@ bool AppInit2(boost::thread_group& threadGroup)
uiInterface.InitMessage(_("Verifying blocks..."));
fVerifying = true;
if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", 3),
if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", 4),
GetArg("-checkblocks", 288))) {
strLoadError = _("Corrupted block database detected");
fVerifying = false;
......
// Copyright (c) 2014-2015 The Crown developers
// Copyright (c) 2014-2017 The Dash Core developers
// Copyright (c) 2014-2018 The Crown developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
......@@ -167,3 +168,32 @@ void ThreadCheckLegacySigner()
}
}
bool CHashSigner::SignHash(const uint256& hash, const CKey& key, std::vector<unsigned char>& vchSigRet)
{
return key.SignCompact(hash, vchSigRet);
}
bool CHashSigner::VerifyHash(const uint256& hash, const CPubKey& pubkey, const std::vector<unsigned char>& vchSig, std::string& strErrorRet)
{
return VerifyHash(hash, pubkey.GetID(), vchSig, strErrorRet);
}
bool CHashSigner::VerifyHash(const uint256& hash, const CKeyID& keyID, const std::vector<unsigned char>& vchSig, std::string& strErrorRet)
{
CPubKey pubkeyFromSig;
if(!pubkeyFromSig.RecoverCompact(hash, vchSig)) {
strErrorRet = "Error recovering public key.";
return false;
}
if(pubkeyFromSig.GetID() != keyID) {
strErrorRet = strprintf("Keys don't match: pubkey=%s, pubkeyFromSig=%s, hash=%s, vchSig=%s",
keyID.ToString(), pubkeyFromSig.GetID().ToString(), hash.ToString(),
EncodeBase64(&vchSig[0], vchSig.size()));
return false;
}
return true;
}
// Copyright (c) 2014-2015 The Crown developers
// Copyright (c) 2014-2017 The Dash Core developers
// Copyright (c) 2014-2018 The Crown developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
......@@ -54,6 +55,19 @@ public:
CSystemnode* pSubmittedToSystemnode;
};
/** Helper class for signing hashes and checking their signatures
*/
class CHashSigner
{
public:
/// Sign the hash, returns true if successful
static bool SignHash(const uint256& hash, const CKey& key, std::vector<unsigned char>& vchSigRet);
/// Verify the hash signature, returns true if succcessful
static bool VerifyHash(const uint256& hash, const CPubKey& pubkey, const std::vector<unsigned char>& vchSig, std::string& strErrorRet);
/// Verify the hash signature, returns true if succcessful
static bool VerifyHash(const uint256& hash, const CKeyID& keyID, const std::vector<unsigned char>& vchSig, std::string& strErrorRet);
};
void ThreadCheckLegacySigner();
#endif
......@@ -87,3 +87,9 @@ bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) // throw(leve
HandleError(status);
return true;
}
TransactionLevelDBWrapper::TransactionLevelDBWrapper(const std::string & dbName, size_t nCacheSize, bool fMemory, bool fWipe)
: m_db(GetDataDir() / dbName, nCacheSize, fMemory, fWipe)
, m_dbTransaction(m_db)
{
}
......@@ -10,6 +10,9 @@
#include "streams.h"
#include "util.h"
#include "version.h"
#include "sync.h"
#include <typeindex>
#include <boost/filesystem/path.hpp>
......@@ -170,4 +173,268 @@ public:
}
};
class CDBTransaction {
private:
CLevelDBWrapper &db;
struct KeyHolder {
virtual ~KeyHolder() = default;
virtual bool Less(const KeyHolder &b) const = 0;
virtual void Erase(CLevelDBBatch &batch) = 0;
};
typedef std::unique_ptr<KeyHolder> KeyHolderPtr;
template <typename K>
struct KeyHolderImpl : KeyHolder {
KeyHolderImpl(const K &_key)
: key(_key) {
}
virtual bool Less(const KeyHolder &b) const {
auto *b2 = dynamic_cast<const KeyHolderImpl<K>*>(&b);
assert(b2 != nullptr);
return key < b2->key;
}
virtual void Erase(CLevelDBBatch &batch) {
batch.Erase(key);
}
K key;
};
struct KeyValueHolder {
virtual ~KeyValueHolder() = default;
virtual void Write(CLevelDBBatch &batch) = 0;
};
typedef std::unique_ptr<KeyValueHolder> KeyValueHolderPtr;
template <typename K, typename V>
struct KeyValueHolderImpl : KeyValueHolder {
KeyValueHolderImpl(const KeyHolderImpl<K> &_key, const V &_value)
: key(_key),
value(_value) { }
virtual void Write(CLevelDBBatch &batch) {
batch.Write(key.key, value);
}
const KeyHolderImpl<K> &key;
V value;
};
struct keyCmp {
bool operator()(const KeyHolderPtr &a, const KeyHolderPtr &b) const {
return a->Less(*b);
}
};
typedef std::map<KeyHolderPtr, KeyValueHolderPtr, keyCmp> KeyValueMap;
typedef std::map<std::type_index, KeyValueMap> TypeKeyValueMap;
TypeKeyValueMap writes;
TypeKeyValueMap deletes;
template <typename K>
KeyValueMap *getMapForType(TypeKeyValueMap &m, bool create) {
auto it = m.find(typeid(K));
if (it != m.end()) {
return &it->second;
}
if (!create)
return nullptr;
auto it2 = m.emplace(typeid(K), KeyValueMap());
return &it2.first->second;
}
template <typename K>
KeyValueMap *getWritesMap(bool create) {
return getMapForType<K>(writes, create);
}
template <typename K>
KeyValueMap *getDeletesMap(bool create) {
return getMapForType<K>(deletes, create);
}
public:
CDBTransaction(CLevelDBWrapper &_db) : db(_db) {}
template <typename K, typename V>
void Write(const K& key, const V& value) {
KeyHolderPtr k(new KeyHolderImpl<K>(key));
KeyHolderImpl<K>* k2 = dynamic_cast<KeyHolderImpl<K>*>(k.get());
KeyValueHolderPtr kv(new KeyValueHolderImpl<K,V>(*k2, value));
KeyValueMap *ds = getDeletesMap<K>(false);
if (ds)
ds->erase(k);
KeyValueMap *ws = getWritesMap<K>(true);
ws->erase(k);
ws->emplace(std::make_pair(std::move(k), std::move(kv)));
}
template <typename K, typename V>
bool Read(const K& key, V& value) {
KeyHolderPtr k(new KeyHolderImpl<K>(key));
KeyValueMap *ds = getDeletesMap<K>(false);
if (ds && ds->count(k))
return false;
KeyValueMap *ws = getWritesMap<K>(false);
if (ws) {
auto it = ws->find(k);
if (it != ws->end()) {
auto *impl = dynamic_cast<KeyValueHolderImpl<K, V> *>(it->second.get());
if (!impl)
return false;
value = impl->value;
return true;
}
}
return db.Read(key, value);
}
template <typename K>
bool Exists(const K& key) {
KeyHolderPtr k(new KeyHolderImpl<K>(key));
KeyValueMap *ds = getDeletesMap<K>(false);
if (ds && ds->count(k))
return false;
KeyValueMap *ws = getWritesMap<K>(false);
if (ws && ws->count(k))
return true;
return db.Exists(key);
}
template <typename K>
void Erase(const K& key) {
KeyHolderPtr k(new KeyHolderImpl<K>(key));
KeyValueMap *ws = getWritesMap<K>(false);
if (ws)
ws->erase(k);
KeyValueMap *ds = getDeletesMap<K>(true);
ds->emplace(std::move(k), nullptr);
}
void Clear() {
writes.clear();
deletes.clear();
}
bool Commit() {
CLevelDBBatch batch;
for (auto &p : deletes) {
for (auto &p2 : p.second) {
p2.first->Erase(batch);
}
}
for (auto &p : writes) {
for (auto &p2 : p.second) {
p2.second->Write(batch);
}
}
bool ret = db.WriteBatch(batch, true);
Clear();
return ret;
}
bool IsClean() {
return writes.empty() && deletes.empty();
}
};
class CScopedDBTransaction {
private:
CDBTransaction &dbTransaction;
std::function<void ()> commitHandler;
std::function<void ()> rollbackHandler;
bool didCommitOrRollback{};
public:
CScopedDBTransaction(CDBTransaction &dbTx) : dbTransaction(dbTx) {}
~CScopedDBTransaction() {
if (!didCommitOrRollback)
Rollback();
}
bool Commit() {
assert(!didCommitOrRollback);
didCommitOrRollback = true;
bool result = dbTransaction.Commit();
if (commitHandler)
commitHandler();
return result;
}
void Rollback() {
assert(!didCommitOrRollback);
didCommitOrRollback = true;
dbTransaction.Clear();
if (rollbackHandler)
rollbackHandler();
}
static std::unique_ptr<CScopedDBTransaction> Begin(CDBTransaction &dbTx) {
assert(dbTx.IsClean());
return std::unique_ptr<CScopedDBTransaction>(new CScopedDBTransaction(dbTx));
}
void SetCommitHandler(const std::function<void ()> &h) {
commitHandler = h;
}
void SetRollbackHandler(const std::function<void ()> &h) {
rollbackHandler = h;
}
};
class TransactionLevelDBWrapper
{
public:
TransactionLevelDBWrapper(const std::string & dbName, size_t nCacheSize, bool fMemory = false, bool fWipe = false);
std::unique_ptr<CScopedDBTransaction> BeginTransaction()
{
LOCK(m_cs);
auto t = CScopedDBTransaction::Begin(m_dbTransaction);
return t;
}
template<typename K, typename V>
bool Read(const K& key, V& value)
{
LOCK(m_cs);
return m_dbTransaction.Read(key, value);
}
template<typename K, typename V>
void Write(const K& key, const V& value)
{
LOCK(m_cs);
m_dbTransaction.Write(key, value);
}
template <typename K>
bool Exists(const K& key)
{
LOCK(m_cs);
return m_dbTransaction.Exists(key);
}
template <typename K>
void Erase(const K& key)
{
LOCK(m_cs);
m_dbTransaction.Erase(key);
}
CLevelDBWrapper& GetRawDB() { return m_db; }
protected:
CCriticalSection m_cs;
CLevelDBWrapper m_db;
CDBTransaction m_dbTransaction;
};
#endif // BITCOIN_LEVELDBWRAPPER_H
......@@ -30,6 +30,8 @@
#include "util.h"
#include "spork.h"
#include "utilmoneystr.h"
#include "platform/specialtx.h"
#include "platform/platform-db.h"
#include <sstream>
......@@ -82,6 +84,7 @@ int nLastStakeAttempt = 0;
CFeeRate minRelayTxFee = CFeeRate(10000);
CTxMemPool mempool(::minRelayTxFee);
Platform::NfTokenTxMemPoolHandler g_nfTokenTxMemPoolHandler;
struct COrphanTx {
CTransaction tx;
......@@ -951,6 +954,22 @@ int GetIXConfirmations(uint256 nTXHash)
bool CheckTransaction(const CTransaction& tx, CValidationState &state)
{
// check version 3 transaction types
if (tx.nVersion >= 3)
{
if (tx.nType != TRANSACTION_NORMAL &&
tx.nType != TRANSACTION_GOVERNANCE_VOTE &&
tx.nType != TRANSACTION_NF_TOKEN_REGISTER)
{
return state.DoS(100, false, REJECT_INVALID, "bad-txns-type");
}
if (tx.IsCoinBase() && tx.nType != TRANSACTION_NORMAL)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-cb-type");
}
// all version 1 transactions are normal
else if (tx.nType != TRANSACTION_NORMAL)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-type");
// Basic checks that don't depend on any context
if (tx.vin.empty())
return state.DoS(10, error("CheckTransaction() : vin empty"),
......@@ -963,6 +982,9 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return state.DoS(100, error("CheckTransaction() : size limits failed"),
REJECT_INVALID, "bad-txns-oversize");
if (tx.extraPayload.size() > MAX_TX_EXTRA_PAYLOAD)
return state.DoS(100, false, REJECT_INVALID, "bad-txns-payload-oversize");
// Check for negative or overflow output values
CAmount nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, tx.vout)
......@@ -1052,6 +1074,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if (!CheckTransaction(tx, state))
return error("AcceptToMemoryPool: : CheckTransaction failed");
if (!Platform::CheckSpecialTx(tx, chainActive.Tip(), state))
return false;
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase() || tx.IsCoinStake())
return state.DoS(100, error("AcceptToMemoryPool: : coinbase/coinstake as individual tx"),
......@@ -1064,6 +1089,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
error("AcceptToMemoryPool : nonstandard transaction: %s", reason),
REJECT_NONSTANDARD, reason);
if (pool.ExistsSpecTxConflict(tx))
return state.DoS(0, false, REJECT_DUPLICATE, "spec-tx-dup");
// is it already in the memory pool?
uint256 hash = tx.GetHash();
if (pool.exists(hash))
......@@ -1849,7 +1877,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
if (state.IsInvalid(nDoS)) {
std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash());
if (it != mapBlockSource.end() && State(it->second)) {
CBlockReject reject = {state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
CBlockReject reject = {static_cast<unsigned char>(state.GetRejectCode()), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
State(it->second)->rejects.push_back(reject);
if (nDoS > 0)
Misbehaving(it->second, nDoS);
......@@ -2029,6 +2057,10 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
if (nSizeCheck != block.vtx.size())
return error("DisconnectBlock() : block and undo data inconsistent, check=%d size=%d", nSizeCheck, block.vtx.size());
if (!Platform::UndoSpecialTxsInBlock(block, pindex)) {
return error("DisconnectBlock() : failed to undo special tx");;
}
// undo transactions in reverse order
for (int i = block.vtx.size() - 1; i >= 0; i--) {
const CTransaction &tx = block.vtx[i];
......@@ -2379,6 +2411,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart;
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001);
if (!Platform::ProcessSpecialTxsInBlock(fJustCheck, block, pindex, state))
return false;
// Check that block's created coins is under the maximum allowed amount
if (!IsBlockValueValid(block, GetBlockValue(pindex->pprev->nHeight, nFees))){
CAmount nValueCreated = block.vtx[0].GetValueOut();
......@@ -2548,6 +2583,9 @@ void FlushStateToDisk() {
void static UpdateTip(CBlockIndex *pindexNew) {
chainActive.SetTip(pindexNew);
// Update block tip for special txs handlers
Platform::UpdateSpecialTxsBlockTip(pindexNew);
// New best block
nTimeBestReceived = GetTime();
mempool.AddTransactionsUpdated(1);
......@@ -2595,10 +2633,16 @@ bool static DisconnectTip(CValidationState &state) {
// Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros();
{
auto platformDbTx = Platform::PlatformDb::Instance().BeginTransaction();
CCoinsViewCache view(pcoinsTip);
if (!DisconnectBlock(block, state, pindexDelete, view))
return error("DisconnectTip() : DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
assert(view.Flush());
bool flushed = view.Flush();
assert(flushed);
bool committed = platformDbTx->Commit();
assert(committed);
}
LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
// Write the chain state to disk, if necessary.
......@@ -2650,6 +2694,8 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, const CB
int64_t nTime3;
LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
{
auto platformDbTx = Platform::PlatformDb::Instance().BeginTransaction();
CCoinsViewCache view(pcoinsTip);
g_signals.BlockChecked(*pblock, state);
if (!ConnectBlock(*pblock, state, pindexNew, view)) {
......@@ -2660,7 +2706,11 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, const CB
mapBlockSource.erase(pindexNew->GetBlockHash());
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
assert(view.Flush());
bool flushed = view.Flush();
assert(flushed);
bool committed = platformDbTx->Commit();
assert(committed);
}
int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3;
LogPrint("bench", " - Flush: %.2fms [%.2fs]\n", (nTime4 - nTime3) * 0.001, nTimeFlush * 0.000001);
......@@ -3690,6 +3740,9 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1;
// begin tx and let it rollback
auto platformDbTx = Platform::PlatformDb::Instance().BeginTransaction();
// NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, pindexPrev))
return false;
......@@ -3910,6 +3963,9 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL)
return true;
// begin tx and let it rollback
auto platformDbTx = Platform::PlatformDb::Instance().BeginTransaction();
// Verify blocks in the best chain
if (nCheckDepth <= 0)
nCheckDepth = 1000000000; // suffices until the year 19000
......@@ -6087,3 +6143,12 @@ public:
mapOrphanTransactionsByPrev.clear();
}
} instance_of_cmaincleanup;
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state)
{
return strprintf("%s%s (code %i)",
state.GetRejectReason(),
state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(),
state.GetRejectCode());
}
......@@ -26,6 +26,7 @@
#include "sync.h"
#include "tinyformat.h"
#include "txmempool.h"
#include "platform/nf-token/nf-token-tx-mem-pool-handler.h"
#include "uint256.h"
#include "undo.h"
......@@ -101,6 +102,8 @@ static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
/** The maximum allowed size of version 2 extra payload */
static const unsigned int MAX_TX_EXTRA_PAYLOAD = 10000;
/** "reject" message codes */
static const unsigned char REJECT_MALFORMED = 0x01;
......@@ -126,6 +129,7 @@ struct SPHasher
extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
extern CTxMemPool mempool;
extern Platform::NfTokenTxMemPoolHandler g_nfTokenTxMemPoolHandler;
typedef boost::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
extern BlockMap mapBlockIndex;
extern uint64_t nLastBlockTx;
......@@ -512,16 +516,19 @@ private:
} mode;
int nDoS;
std::string strRejectReason;
unsigned char chRejectCode;
unsigned int chRejectCode;
bool corruptionPossible;
std::string strDebugMessage;
public:
CValidationState() : mode(MODE_VALID), nDoS(0), chRejectCode(0), corruptionPossible(false) {}
bool DoS(int level, bool ret = false,
unsigned char chRejectCodeIn=0, std::string strRejectReasonIn="",
bool corruptionIn=false) {
unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="",
bool corruptionIn=false,
const std::string &strDebugMessageIn="") {
chRejectCode = chRejectCodeIn;
strRejectReason = strRejectReasonIn;
corruptionPossible = corruptionIn;
strDebugMessage = strDebugMessageIn;
if (mode == MODE_ERROR)
return ret;
nDoS += level;
......@@ -529,10 +536,11 @@ public:
return ret;
}
bool Invalid(bool ret = false,
unsigned char _chRejectCode=0, std::string _strRejectReason="") {
return DoS(0, ret, _chRejectCode, _strRejectReason);
unsigned int _chRejectCode=0, const std::string &_strRejectReason="",
const std::string &_strDebugMessage="") {
return DoS(0, ret, _chRejectCode, _strRejectReason, false, _strDebugMessage);
}
bool Error(std::string strRejectReasonIn="") {
bool Error(const std::string& strRejectReasonIn) {
if (mode == MODE_VALID)
strRejectReason = strRejectReasonIn;
mode = MODE_ERROR;
......@@ -568,10 +576,15 @@ public:
bool CorruptionPossible() const {
return corruptionPossible;
}
unsigned char GetRejectCode() const { return chRejectCode; }
unsigned int GetRejectCode() const { return chRejectCode; }
std::string GetRejectReason() const { return strRejectReason; }
std::string GetDebugMessage() const { return strDebugMessage; }
};
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */
class CVerifyDB {
public:
......
#include "agent.h"
#include "arith_uint256.h"
#include "governance.h"
#include "governance-approval-voting.h"
#include <boost/foreach.hpp>
#include <memory>
namespace std // TODO: remove this when we switch to C++14
{
template<typename T, typename... Args>
unique_ptr<T> make_unique(Args &&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}
namespace Platform
{
class AgentRegistryIteratorImpl:
public boost::iterator_facade<AgentRegistryIteratorImpl, Identity, boost::single_pass_traversal_tag>
{
public:
using ClientIterator = std::map<uint256, Identity>::const_iterator;
AgentRegistryIteratorImpl(ClientIterator begin, ClientIterator end)
: m_current(begin)
, m_end(end)