diff --git a/.gitignore b/.gitignore index c77303f50e2ee..b8d783ea21ec2 100644 --- a/.gitignore +++ b/.gitignore @@ -135,7 +135,6 @@ test/.mypy_cache/ /doc/doxygen/ -libbitcoinconsensus.pc contrib/devtools/split-debug.sh # Output from running db4 installation diff --git a/Makefile.am b/Makefile.am index eec498dc0e937..2329fad9b974d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,11 +14,6 @@ endif .PHONY: deploy FORCE .INTERMEDIATE: $(COVERAGE_INFO) -if BUILD_BITCOIN_LIBS -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libbitcoinconsensus.pc -endif - BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT) BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT) BITCOIN_TEST_BIN=$(top_builddir)/src/test/$(BITCOIN_TEST_NAME)$(EXEEXT) diff --git a/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj b/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj index 95fdcdb79b4ef..a34ef41d164be 100644 --- a/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj +++ b/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj @@ -15,7 +15,6 @@ - diff --git a/ci/test/00_setup_env_native_previous_releases.sh b/ci/test/00_setup_env_native_previous_releases.sh index 94e88f872f577..6d536170e2dd9 100755 --- a/ci/test/00_setup_env_native_previous_releases.sh +++ b/ci/test/00_setup_env_native_previous_releases.sh @@ -16,5 +16,5 @@ export RUN_UNIT_TESTS_SEQUENTIAL="true" export RUN_UNIT_TESTS="false" export GOAL="install" export DOWNLOAD_PREVIOUS_RELEASES="true" -export BITCOIN_CONFIG="--enable-zmq --with-libs=no --with-gui=qt5 --enable-reduce-exports --enable-debug \ +export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports --enable-debug \ CFLAGS=\"-g0 -O2 -funsigned-char\" CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE' CXXFLAGS=\"-g0 -O2 -funsigned-char\"" diff --git a/configure.ac b/configure.ac index 0305918bc4bf1..4e31ccaf24d71 100644 --- a/configure.ac +++ b/configure.ac @@ -626,15 +626,9 @@ AC_ARG_ENABLE([experimental-util-chainstate], [build_bitcoin_chainstate=$enableval], [build_bitcoin_chainstate=no]) -AC_ARG_WITH([libs], - [AS_HELP_STRING([--with-libs], - [build libraries (default=yes)])], - [build_bitcoin_libs=$withval], - [build_bitcoin_libs=yes]) - AC_ARG_WITH([experimental-kernel-lib], [AS_HELP_STRING([--with-experimental-kernel-lib], - [build experimental bitcoinkernel library (default is to build if we're building libraries and the experimental build-chainstate executable)])], + [build experimental bitcoinkernel library (default is to build if we're building the experimental build-chainstate executable)])], [build_experimental_kernel_lib=$withval], [build_experimental_kernel_lib=auto]) @@ -1246,7 +1240,6 @@ if test "$enable_fuzz" = "yes"; then build_bitcoin_chainstate=no build_bitcoin_wallet=no build_bitcoind=no - build_bitcoin_libs=no bitcoin_enable_qt=no bitcoin_enable_qt_test=no bitcoin_enable_qt_dbus=no @@ -1405,7 +1398,7 @@ if test "$use_boost" = "yes"; then dnl Check for Boost headers AX_BOOST_BASE([1.73.0],[],[AC_MSG_ERROR([Boost is not available!])]) if test "$want_boost" = "no"; then - AC_MSG_ERROR([only libbitcoinconsensus can be built without Boost]) + AC_MSG_ERROR([Boost is required]) fi dnl we don't use multi_index serialization @@ -1619,18 +1612,8 @@ fi AM_CONDITIONAL([BUILD_BITCOIN_CHAINSTATE], [test $build_bitcoin_chainstate = "yes"]) AC_MSG_RESULT($build_bitcoin_chainstate) -AC_MSG_CHECKING([whether to build libraries]) -AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test $build_bitcoin_libs = "yes"]) - -if test "$build_bitcoin_libs" = "yes"; then - AC_DEFINE([HAVE_CONSENSUS_LIB], [1], [Define this symbol if the consensus lib has been built]) - AC_CONFIG_FILES([libbitcoinconsensus.pc:libbitcoinconsensus.pc.in]) -fi - AM_CONDITIONAL([BUILD_BITCOIN_KERNEL_LIB], [test "$build_experimental_kernel_lib" != "no" && ( test "$build_experimental_kernel_lib" = "yes" || test "$build_bitcoin_chainstate" = "yes" )]) -AC_MSG_RESULT($build_bitcoin_libs) - AC_LANG_POP if test "$use_ccache" != "no"; then @@ -1764,8 +1747,8 @@ else AC_MSG_RESULT([no]) fi -if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nononononononononono"; then - AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests]) +if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nonononononononono"; then + AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests]) fi AM_CONDITIONAL([TARGET_DARWIN], [test "$TARGET_OS" = "darwin"]) @@ -1925,7 +1908,6 @@ echo echo "Options used to compile and link:" echo " external signer = $use_external_signer" echo " multiprocess = $build_multiprocess" -echo " with libs = $build_bitcoin_libs" echo " with wallet = $enable_wallet" if test "$enable_wallet" != "no"; then echo " with sqlite = $use_sqlite" diff --git a/contrib/signet/miner b/contrib/signet/miner index e5daf9f993eaa..02a2f1b70dcad 100755 --- a/contrib/signet/miner +++ b/contrib/signet/miner @@ -21,7 +21,7 @@ sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL) from test_framework.blocktools import get_witness_script, script_BIP34_coinbase_height # noqa: E402 from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_binary, from_hex, ser_string, ser_uint256, tx_from_hex # noqa: E402 from test_framework.psbt import PSBT, PSBTMap, PSBT_GLOBAL_UNSIGNED_TX, PSBT_IN_FINAL_SCRIPTSIG, PSBT_IN_FINAL_SCRIPTWITNESS, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_SIGHASH_TYPE # noqa: E402 -from test_framework.script import CScriptOp # noqa: E402 +from test_framework.script import CScript, CScriptOp # noqa: E402 logging.basicConfig( format='%(asctime)s %(levelname)s %(message)s', @@ -32,12 +32,6 @@ SIGNET_HEADER = b"\xec\xc7\xda\xa2" PSBT_SIGNET_BLOCK = b"\xfc\x06signetb" # proprietary PSBT global field holding the block being signed RE_MULTIMINER = re.compile(r"^(\d+)(-(\d+))?/(\d+)$") -def create_coinbase(height, value, spk): - cb = CTransaction() - cb.vin = [CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), 0xffffffff)] - cb.vout = [CTxOut(value, spk)] - return cb - def signet_txs(block, challenge): # assumes signet solution has not been added yet so does not need # to be removed @@ -72,18 +66,7 @@ def signet_txs(block, challenge): return spend, to_spend -def do_createpsbt(block, signme, spendme): - psbt = PSBT() - psbt.g = PSBTMap( {PSBT_GLOBAL_UNSIGNED_TX: signme.serialize(), - PSBT_SIGNET_BLOCK: block.serialize() - } ) - psbt.i = [ PSBTMap( {PSBT_IN_NON_WITNESS_UTXO: spendme.serialize(), - PSBT_IN_SIGHASH_TYPE: bytes([1,0,0,0])}) - ] - psbt.o = [ PSBTMap() ] - return psbt.to_base64() - -def do_decode_psbt(b64psbt): +def decode_psbt(b64psbt): psbt = PSBT.from_base64(b64psbt) assert len(psbt.tx.vin) == 1 @@ -110,11 +93,17 @@ def finish_block(block, signet_solution, grind_cmd): block.rehash() return block -def generate_psbt(tmpl, reward_spk, *, blocktime=None): +def generate_psbt(tmpl, reward_spk, *, blocktime=None, poolid=None): signet_spk = tmpl["signet_challenge"] signet_spk_bin = bytes.fromhex(signet_spk) - cbtx = create_coinbase(height=tmpl["height"], value=tmpl["coinbasevalue"], spk=reward_spk) + scriptSig = script_BIP34_coinbase_height(tmpl["height"]) + if poolid is not None: + scriptSig = CScript(b"" + scriptSig + CScriptOp.encode_op_pushdata(poolid)) + + cbtx = CTransaction() + cbtx.vin = [CTxIn(COutPoint(0, 0xffffffff), scriptSig, 0xffffffff)] + cbtx.vout = [CTxOut(tmpl["coinbasevalue"], reward_spk)] cbtx.vin[0].nSequence = 2**32-2 cbtx.rehash() @@ -137,29 +126,26 @@ def generate_psbt(tmpl, reward_spk, *, blocktime=None): signme, spendme = signet_txs(block, signet_spk_bin) - return do_createpsbt(block, signme, spendme) - -def get_reward_address(args, height): - if args.address is not None: - return args.address - - if '*' not in args.descriptor: - addr = json.loads(args.bcli("deriveaddresses", args.descriptor))[0] - args.address = addr - return addr - - remove = [k for k in args.derived_addresses.keys() if k+20 <= height] - for k in remove: - del args.derived_addresses[k] - - addr = args.derived_addresses.get(height, None) - if addr is None: - addrs = json.loads(args.bcli("deriveaddresses", args.descriptor, "[%d,%d]" % (height, height+20))) - addr = addrs[0] - for k, a in enumerate(addrs): - args.derived_addresses[height+k] = a + psbt = PSBT() + psbt.g = PSBTMap( {PSBT_GLOBAL_UNSIGNED_TX: signme.serialize(), + PSBT_SIGNET_BLOCK: block.serialize() + } ) + psbt.i = [ PSBTMap( {PSBT_IN_NON_WITNESS_UTXO: spendme.serialize(), + PSBT_IN_SIGHASH_TYPE: bytes([1,0,0,0])}) + ] + psbt.o = [ PSBTMap() ] + return psbt.to_base64() - return addr +def get_poolid(args): + if args.poolid is not None: + if args.poolnum is not None: + logging.error("Can only specify one of --poolid and --poolnum") + raise Exception("bad arguments") + return args.poolid.encode('utf8') + elif args.poolnum is not None: + return b"/signet:%d/" % (args.poolnum) + else: + return None def get_reward_addr_spk(args, height): assert args.address is not None or args.descriptor is not None @@ -167,7 +153,20 @@ def get_reward_addr_spk(args, height): if hasattr(args, "reward_spk"): return args.address, args.reward_spk - reward_addr = get_reward_address(args, height) + if args.address is not None: + reward_addr = args.address + elif '*' not in args.descriptor: + reward_addr = args.address = json.loads(args.bcli("deriveaddresses", args.descriptor))[0] + else: + remove = [k for k in args.derived_addresses.keys() if k+20 <= height] + for k in remove: + del args.derived_addresses[k] + if height not in args.derived_addresses: + addrs = json.loads(args.bcli("deriveaddresses", args.descriptor, "[%d,%d]" % (height, height+20))) + for k, a in enumerate(addrs): + args.derived_addresses[height+k] = a + reward_addr = args.derived_addresses[height] + reward_spk = bytes.fromhex(json.loads(args.bcli("getaddressinfo", reward_addr))["scriptPubKey"]) if args.address is not None: # will always be the same, so cache @@ -176,13 +175,14 @@ def get_reward_addr_spk(args, height): return reward_addr, reward_spk def do_genpsbt(args): + poolid = get_poolid(args) tmpl = json.load(sys.stdin) _, reward_spk = get_reward_addr_spk(args, tmpl["height"]) - psbt = generate_psbt(tmpl, reward_spk) + psbt = generate_psbt(tmpl, reward_spk, poolid=poolid) print(psbt) def do_solvepsbt(args): - block, signet_solution = do_decode_psbt(sys.stdin.read()) + block, signet_solution = decode_psbt(sys.stdin.read()) block = finish_block(block, signet_solution, args.grind_cmd) print(block.serialize().hex()) @@ -225,36 +225,115 @@ def seconds_to_hms(s): out = "-" + out return out -def next_block_delta(last_nbits, last_hash, ultimate_target, do_poisson, max_interval): - # strategy: - # 1) work out how far off our desired target we are - # 2) cap it to a factor of 4 since that's the best we can do in a single retarget period - # 3) use that to work out the desired average interval in this retarget period - # 4) if doing poisson, use the last hash to pick a uniformly random number in [0,1), and work out a random multiplier to vary the average by - # 5) cap the resulting interval between 1 second and 1 hour to avoid extremes - +class Generate: INTERVAL = 600.0*2016/2015 # 10 minutes, adjusted for the off-by-one bug - current_target = nbits_to_target(last_nbits) - retarget_factor = ultimate_target / current_target - retarget_factor = max(0.25, min(retarget_factor, 4.0)) - avg_interval = INTERVAL * retarget_factor + def __init__(self, multiminer=None, ultimate_target=None, poisson=False, max_interval=1800, + standby_delay=0, backup_delay=0, set_block_time=None, + poolid=None): + if multiminer is None: + multiminer = (0, 1, 1) + (self.multi_low, self.multi_high, self.multi_period) = multiminer + self.ultimate_target = ultimate_target + self.poisson = poisson + self.max_interval = max_interval + self.standby_delay = standby_delay + self.backup_delay = backup_delay + self.set_block_time = set_block_time + self.poolid = poolid + + def next_block_delta(self, last_nbits, last_hash): + # strategy: + # 1) work out how far off our desired target we are + # 2) cap it to a factor of 4 since that's the best we can do in a single retarget period + # 3) use that to work out the desired average interval in this retarget period + # 4) if doing poisson, use the last hash to pick a uniformly random number in [0,1), and work out a random multiplier to vary the average by + # 5) cap the resulting interval between 1 second and 1 hour to avoid extremes + + current_target = nbits_to_target(last_nbits) + retarget_factor = self.ultimate_target / current_target + retarget_factor = max(0.25, min(retarget_factor, 4.0)) + + avg_interval = self.INTERVAL * retarget_factor + + if self.poisson: + det_rand = int(last_hash[-8:], 16) * 2**-32 + this_interval_variance = -math.log1p(-det_rand) + else: + this_interval_variance = 1 - if do_poisson: - det_rand = int(last_hash[-8:], 16) * 2**-32 - this_interval_variance = -math.log1p(-det_rand) - else: - this_interval_variance = 1 + this_interval = avg_interval * this_interval_variance + this_interval = max(1, min(this_interval, self.max_interval)) + + return this_interval + + def next_block_is_mine(self, last_hash): + det_rand = int(last_hash[-16:-8], 16) + return self.multi_low <= (det_rand % self.multi_period) < self.multi_high + + def next_block_time(self, now, bestheader, is_first_block): + if self.set_block_time is not None: + logging.debug("Setting start time to %d", self.set_block_time) + self.mine_time = self.set_block_time + self.action_time = now + self.is_mine = True + elif bestheader["height"] == 0: + time_delta = self.INTERVAL * 100 # plenty of time to mine 100 blocks + logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60)) + self.mine_time = now - time_delta + self.action_time = now + self.is_mine = True + else: + time_delta = self.next_block_delta(int(bestheader["bits"], 16), bestheader["hash"]) + self.mine_time = bestheader["time"] + time_delta + + self.is_mine = self.next_block_is_mine(bestheader["hash"]) + + self.action_time = self.mine_time + if not self.is_mine: + self.action_time += self.backup_delay + + if self.standby_delay > 0: + self.action_time += self.standby_delay + elif is_first_block: + # for non-standby, always mine immediately on startup, + # even if the next block shouldn't be ours + self.action_time = now - this_interval = avg_interval * this_interval_variance - this_interval = max(1, min(this_interval, max_interval)) + # don't want fractional times so round down + self.mine_time = int(self.mine_time) + self.action_time = int(self.action_time) - return this_interval + # can't mine a block 2h in the future; 1h55m for some safety + self.action_time = max(self.action_time, self.mine_time - 6900) -def next_block_is_mine(last_hash, my_blocks): - det_rand = int(last_hash[-16:-8], 16) - return my_blocks[0] <= (det_rand % my_blocks[2]) < my_blocks[1] + def gbt(self, bcli, bestblockhash, now): + tmpl = json.loads(bcli("getblocktemplate", '{"rules":["signet","segwit"]}')) + if tmpl["previousblockhash"] != bestblockhash: + logging.warning("GBT based off unexpected block (%s not %s), retrying", tmpl["previousblockhash"], bci["bestblockhash"]) + time.sleep(1) + return None + + if tmpl["mintime"] > self.mine_time: + logging.info("Updating block time from %d to %d", self.mine_time, tmpl["mintime"]) + self.mine_time = tmpl["mintime"] + if self.mine_time > now: + logging.error("GBT mintime is in the future: %d is %d seconds later than %d", self.mine_time, (self.mine_time-now), now) + return None + + return tmpl + + def mine(self, bcli, grind_cmd, tmpl, reward_spk): + psbt = generate_psbt(tmpl, reward_spk, blocktime=self.mine_time, poolid=self.poolid) + input_stream = os.linesep.join([psbt, "true", "ALL"]).encode('utf8') + psbt_signed = json.loads(bcli("-stdin", "walletprocesspsbt", input=input_stream)) + if not psbt_signed.get("complete",False): + logging.debug("Generated PSBT: %s" % (psbt,)) + sys.stderr.write("PSBT signing failed\n") + return None + block, signet_solution = decode_psbt(psbt_signed["psbt"]) + return finish_block(block, signet_solution, grind_cmd) def do_generate(args): if args.max_blocks is not None: @@ -312,8 +391,13 @@ def do_generate(args): logging.error("--max-interval must be at least 960 (16 minutes)") return 1 + poolid = get_poolid(args) + ultimate_target = nbits_to_target(int(args.nbits,16)) + gen = Generate(multiminer=my_blocks, ultimate_target=ultimate_target, poisson=args.poisson, max_interval=args.max_interval, + standby_delay=args.standby_delay, backup_delay=args.backup_delay, set_block_time=args.set_block_time, poolid=poolid) + mined_blocks = 0 bestheader = {"hash": None} lastheader = None @@ -328,104 +412,55 @@ def do_generate(args): if lastheader is None: lastheader = bestheader["hash"] elif bestheader["hash"] != lastheader: - next_delta = next_block_delta(int(bestheader["bits"], 16), bestheader["hash"], ultimate_target, args.poisson, args.max_interval) + next_delta = gen.next_block_delta(int(bestheader["bits"], 16), bestheader["hash"]) next_delta += bestheader["time"] - time.time() - next_is_mine = next_block_is_mine(bestheader["hash"], my_blocks) + next_is_mine = gen.next_block_is_mine(bestheader["hash"]) logging.info("Received new block at height %d; next in %s (%s)", bestheader["height"], seconds_to_hms(next_delta), ("mine" if next_is_mine else "backup")) lastheader = bestheader["hash"] # when is the next block due to be mined? now = time.time() - if args.set_block_time is not None: - logging.debug("Setting start time to %d", args.set_block_time) - mine_time = args.set_block_time - action_time = now - is_mine = True - elif bestheader["height"] == 0: - time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson, args.max_interval) - time_delta *= 100 # 100 blocks - logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60)) - mine_time = now - time_delta - action_time = now - is_mine = True - else: - time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson, args.max_interval) - mine_time = bestheader["time"] + time_delta - - is_mine = next_block_is_mine(bci["bestblockhash"], my_blocks) - - action_time = mine_time - if not is_mine: - action_time += args.backup_delay - - if args.standby_delay > 0: - action_time += args.standby_delay - elif mined_blocks == 0: - # for non-standby, always mine immediately on startup, - # even if the next block shouldn't be ours - action_time = now - - # don't want fractional times so round down - mine_time = int(mine_time) - action_time = int(action_time) - - # can't mine a block 2h in the future; 1h55m for some safety - action_time = max(action_time, mine_time - 6900) + gen.next_block_time(now, bestheader, (mined_blocks == 0)) # ready to go? otherwise sleep and check for new block - if now < action_time: - sleep_for = min(action_time - now, 60) - if mine_time < now: + if now < gen.action_time: + sleep_for = min(gen.action_time - now, 60) + if gen.mine_time < now: # someone else might have mined the block, # so check frequently, so we don't end up late # mining the next block if it's ours sleep_for = min(20, sleep_for) - minestr = "mine" if is_mine else "backup" - logging.debug("Sleeping for %s, next block due in %s (%s)" % (seconds_to_hms(sleep_for), seconds_to_hms(mine_time - now), minestr)) + minestr = "mine" if gen.is_mine else "backup" + logging.debug("Sleeping for %s, next block due in %s (%s)" % (seconds_to_hms(sleep_for), seconds_to_hms(gen.mine_time - now), minestr)) time.sleep(sleep_for) continue # gbt - tmpl = json.loads(args.bcli("getblocktemplate", '{"rules":["signet","segwit"]}')) - if tmpl["previousblockhash"] != bci["bestblockhash"]: - logging.warning("GBT based off unexpected block (%s not %s), retrying", tmpl["previousblockhash"], bci["bestblockhash"]) - time.sleep(1) + tmpl = gen.gbt(args.bcli, bci["bestblockhash"], now) + if tmpl is None: continue logging.debug("GBT template: %s", tmpl) - if tmpl["mintime"] > mine_time: - logging.info("Updating block time from %d to %d", mine_time, tmpl["mintime"]) - mine_time = tmpl["mintime"] - if mine_time > now: - logging.error("GBT mintime is in the future: %d is %d seconds later than %d", mine_time, (mine_time-now), now) - return 1 - # address for reward reward_addr, reward_spk = get_reward_addr_spk(args, tmpl["height"]) # mine block - logging.debug("Mining block delta=%s start=%s mine=%s", seconds_to_hms(mine_time-bestheader["time"]), mine_time, is_mine) + logging.debug("Mining block delta=%s start=%s mine=%s", seconds_to_hms(gen.mine_time-bestheader["time"]), gen.mine_time, gen.is_mine) mined_blocks += 1 - psbt = generate_psbt(tmpl, reward_spk, blocktime=mine_time) - input_stream = os.linesep.join([psbt, "true", "ALL"]).encode('utf8') - psbt_signed = json.loads(args.bcli("-stdin", "walletprocesspsbt", input=input_stream)) - if not psbt_signed.get("complete",False): - logging.debug("Generated PSBT: %s" % (psbt,)) - sys.stderr.write("PSBT signing failed\n") + block = gen.mine(args.bcli, args.grind_cmd, tmpl, reward_spk) + if block is None: return 1 - block, signet_solution = do_decode_psbt(psbt_signed["psbt"]) - block = finish_block(block, signet_solution, args.grind_cmd) # submit block r = args.bcli("-stdin", "submitblock", input=block.serialize().hex().encode('utf8')) # report - bstr = "block" if is_mine else "backup block" + bstr = "block" if gen.is_mine else "backup block" - next_delta = next_block_delta(block.nBits, block.hash, ultimate_target, args.poisson, args.max_interval) + next_delta = gen.next_block_delta(block.nBits, block.hash) next_delta += block.nTime - time.time() - next_is_mine = next_block_is_mine(block.hash, my_blocks) + next_is_mine = gen.next_block_is_mine(block.hash) logging.debug("Block hash %s payout to %s", block.hash, reward_addr) logging.info("Mined %s at height %d; next in %s (%s)", bstr, tmpl["height"], seconds_to_hms(next_delta), ("mine" if next_is_mine else "backup")) @@ -486,6 +521,8 @@ def main(): cmds = parser.add_subparsers(help="sub-commands") genpsbt = cmds.add_parser("genpsbt", help="Generate a block PSBT for signing") genpsbt.set_defaults(fn=do_genpsbt) + genpsbt.add_argument("--poolnum", default=None, type=int, help="Identify blocks that you mine") + genpsbt.add_argument("--poolid", default=None, type=str, help="Identify blocks that you mine (eg: /signet:1/)") solvepsbt = cmds.add_parser("solvepsbt", help="Solve a signed block PSBT") solvepsbt.set_defaults(fn=do_solvepsbt) @@ -502,6 +539,8 @@ def main(): generate.add_argument("--backup-delay", default=300, type=int, help="Seconds to delay before mining blocks reserved for other miners (default=300)") generate.add_argument("--standby-delay", default=0, type=int, help="Seconds to delay before mining blocks (default=0)") generate.add_argument("--max-interval", default=1800, type=int, help="Maximum interblock interval (seconds)") + generate.add_argument("--poolnum", default=None, type=int, help="Identify blocks that you mine") + generate.add_argument("--poolid", default=None, type=str, help="Identify blocks that you mine (eg: /signet:1/)") calibrate = cmds.add_parser("calibrate", help="Calibrate difficulty") calibrate.set_defaults(fn=do_calibrate) diff --git a/doc/README.md b/doc/README.md index 446684b4821ea..7b6dacaf4f704 100644 --- a/doc/README.md +++ b/doc/README.md @@ -59,7 +59,6 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th - [Translation Strings Policy](translation_strings_policy.md) - [JSON-RPC Interface](JSON-RPC-interface.md) - [Unauthenticated REST Interface](REST-interface.md) -- [Shared Libraries](shared-libraries.md) - [BIPS](bips.md) - [Dnsseed Policy](dnsseed-policy.md) - [Benchmarking](benchmarking.md) diff --git a/doc/design/libraries.md b/doc/design/libraries.md index 7cda64e713a05..3346c8e81b544 100644 --- a/doc/design/libraries.md +++ b/doc/design/libraries.md @@ -4,10 +4,9 @@ |--------------------------|-------------| | *libbitcoin_cli* | RPC client functionality used by *bitcoin-cli* executable | | *libbitcoin_common* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_util*, but higher-level (see [Dependencies](#dependencies)). | -| *libbitcoin_consensus* | Stable, backwards-compatible consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet* and also exposed as a [shared library](../shared-libraries.md). | -| *libbitcoinconsensus* | Shared library build of static *libbitcoin_consensus* library | -| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node* and also exposed as a [shared library](../shared-libraries.md). | -| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables | +| *libbitcoin_consensus* | Stable, backwards-compatible consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet*. | +| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node*. | +| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables. | | *libbitcoin_ipc* | IPC functionality used by *bitcoin-node*, *bitcoin-wallet*, *bitcoin-gui* executables to communicate when [`--enable-multiprocess`](multiprocess.md) is used. | | *libbitcoin_node* | P2P and RPC server functionality used by *bitcoind* and *bitcoin-qt* executables. | | *libbitcoin_util* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_common*, but lower-level (see [Dependencies](#dependencies)). | @@ -17,7 +16,7 @@ ## Conventions -- Most libraries are internal libraries and have APIs which are completely unstable! There are few or no restrictions on backwards compatibility or rules about external dependencies. Exceptions are *libbitcoin_consensus* and *libbitcoin_kernel* which have external interfaces documented at [../shared-libraries.md](../shared-libraries.md). +- Most libraries are internal libraries and have APIs which are completely unstable! There are few or no restrictions on backwards compatibility or rules about external dependencies. An exception is *libbitcoin_kernel*, which, at some future point, will have a documented external interface. - Generally each library should have a corresponding source directory and namespace. Source code organization is a work in progress, so it is true that some namespaces are applied inconsistently, and if you look at [`libbitcoin_*_SOURCES`](../../src/Makefile.am) lists you can see that many libraries pull in files from outside their source directory. But when working with libraries, it is good to follow a consistent pattern like: diff --git a/doc/shared-libraries.md b/doc/shared-libraries.md deleted file mode 100644 index 3a448c655612e..0000000000000 --- a/doc/shared-libraries.md +++ /dev/null @@ -1,78 +0,0 @@ -Shared Libraries -================ - -## bitcoinconsensus -***This library is deprecated and will be removed in v28*** - -The purpose of this library is to make the verification functionality that is critical to Bitcoin's consensus available to other applications, e.g. to language bindings. - -### API - -The interface is defined in the C header `bitcoinconsensus.h` located in `src/script/bitcoinconsensus.h`. - -#### Version - -`bitcoinconsensus_version` returns an `unsigned int` with the API version *(currently `2`)*. - -#### Script Validation - -`bitcoinconsensus_verify_script`, `bitcoinconsensus_verify_script_with_amount` and `bitcoinconsensus_verify_script_with_spent_outputs` return an `int` with the status of the verification. It will be `1` if the input script correctly spends the previous output `scriptPubKey`. - -##### Parameters -###### bitcoinconsensus_verify_script -- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending. -- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`. -- `const unsigned char *txTo` - The transaction with the input that is spending the previous output. -- `unsigned int txToLen` - The number of bytes for the `txTo`. -- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`. -- `unsigned int flags` - The script validation flags *(see below)*. -- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*. - -###### bitcoinconsensus_verify_script_with_amount -- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending. -- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`. -- `int64_t amount` - The amount spent in the input -- `const unsigned char *txTo` - The transaction with the input that is spending the previous output. -- `unsigned int txToLen` - The number of bytes for the `txTo`. -- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`. -- `unsigned int flags` - The script validation flags *(see below)*. -- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*. - -###### bitcoinconsensus_verify_script_with_spent_outputs -- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending. -- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`. -- `int64_t amount` - The amount spent in the input -- `const unsigned char *txTo` - The transaction with the input that is spending the previous output. -- `unsigned int txToLen` - The number of bytes for the `txTo`. -- `UTXO *spentOutputs` - Previous outputs spent in the transaction. `UTXO` is a struct composed by `const unsigned char *scriptPubKey`, `unsigned int scriptPubKeySize` (the number of bytes for the `scriptPubKey`) and `unsigned int value`. -- `unsigned int spentOutputsLen` - The number of bytes for the `spentOutputs`. -- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`. -- `unsigned int flags` - The script validation flags *(see below)*. -- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*. - -##### Script Flags -- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE` -- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH` - Evaluate P2SH ([BIP16](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki)) subscripts -- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG` - Enforce strict DER ([BIP66](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki)) compliance -- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NULLDUMMY` - Enforce NULLDUMMY ([BIP147](https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki)) -- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY` - Enable CHECKLOCKTIMEVERIFY ([BIP65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki)) -- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY` - Enable CHECKSEQUENCEVERIFY ([BIP112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki)) -- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS` - Enable WITNESS ([BIP141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki)) -- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT` - Enable TAPROOT ([BIP340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki), [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki), [BIP342](https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki)) - -##### Errors -- `bitcoinconsensus_ERR_OK` - No errors with input parameters *(see the return value of `bitcoinconsensus_verify_script` for the verification status)* -- `bitcoinconsensus_ERR_TX_INDEX` - An invalid index for `txTo` -- `bitcoinconsensus_ERR_TX_SIZE_MISMATCH` - `txToLen` did not match with the size of `txTo` -- `bitcoinconsensus_ERR_DESERIALIZE` - An error deserializing `txTo` -- `bitcoinconsensus_ERR_AMOUNT_REQUIRED` - Input amount is required if WITNESS is used -- `bitcoinconsensus_ERR_INVALID_FLAGS` - Script verification `flags` are invalid (i.e. not part of the libconsensus interface) -- `bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED` - Spent outputs are required if TAPROOT is used -- `bitcoinconsensus_ERR_SPENT_OUTPUTS_MISMATCH` - Spent outputs size doesn't match tx inputs size - -### Example Implementations -- [NBitcoin](https://github.com/MetacoSA/NBitcoin/blob/5e1055cd7c4186dee4227c344af8892aea54faec/NBitcoin/Script.cs#L979-#L1031) (.NET Bindings) -- [node-libbitcoinconsensus](https://github.com/bitpay/node-libbitcoinconsensus) (Node.js Bindings) -- [java-libbitcoinconsensus](https://github.com/dexX7/java-libbitcoinconsensus) (Java Bindings) -- [bitcoinconsensus-php](https://github.com/Bit-Wasp/bitcoinconsensus-php) (PHP Bindings) -- [rust-bitcoinconsensus](https://github.com/rust-bitcoin/rust-bitcoinconsensus) (Rust Bindings) \ No newline at end of file diff --git a/libbitcoinconsensus.pc.in b/libbitcoinconsensus.pc.in deleted file mode 100644 index 1ceab280bb114..0000000000000 --- a/libbitcoinconsensus.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: @PACKAGE_NAME@ consensus library -Description: Library for the Bitcoin consensus protocol. -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lbitcoinconsensus -Cflags: -I${includedir} diff --git a/src/Makefile.am b/src/Makefile.am index b5d5c4652ab0c..3e142943c5aa8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -38,9 +38,6 @@ LIBSECP256K1=secp256k1/libsecp256k1.la if ENABLE_ZMQ LIBBITCOIN_ZMQ=libbitcoin_zmq.a endif -if BUILD_BITCOIN_LIBS -LIBBITCOINCONSENSUS=libbitcoinconsensus.la -endif if BUILD_BITCOIN_KERNEL_LIB LIBBITCOINKERNEL=libbitcoinkernel.la endif @@ -646,7 +643,6 @@ libbitcoin_consensus_a_SOURCES = \ primitives/transaction.h \ pubkey.cpp \ pubkey.h \ - script/bitcoinconsensus.cpp \ script/interpreter.cpp \ script/interpreter.h \ script/script.cpp \ @@ -1008,21 +1004,6 @@ libbitcoinkernel_la-clientversion.l$(OBJEXT): obj/build.h endif # BUILD_BITCOIN_KERNEL_LIB # -# bitcoinconsensus library # -if BUILD_BITCOIN_LIBS -lib_LTLIBRARIES += $(LIBBITCOINCONSENSUS) - -include_HEADERS = script/bitcoinconsensus.h -libbitcoinconsensus_la_SOURCES = support/cleanse.cpp $(crypto_libbitcoin_crypto_base_la_SOURCES) $(libbitcoin_consensus_a_SOURCES) - -libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS) -libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) -libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL -DDISABLE_OPTIMIZED_SHA256 -libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) - -endif -# - CTAES_DIST = crypto/ctaes/bench.c CTAES_DIST += crypto/ctaes/ctaes.c CTAES_DIST += crypto/ctaes/ctaes.h diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 9f9bdbbd0cd4b..8d44e8df0a405 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -362,7 +362,6 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/rpc.cpp \ test/fuzz/script.cpp \ test/fuzz/script_assets_test_minimizer.cpp \ - test/fuzz/script_bitcoin_consensus.cpp \ test/fuzz/script_descriptor_cache.cpp \ test/fuzz/script_flags.cpp \ test/fuzz/script_format.cpp \ diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp index e7166a91cf4eb..ee750bc1f8a35 100644 --- a/src/bench/verify_script.cpp +++ b/src/bench/verify_script.cpp @@ -2,15 +2,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include -#endif - #include #include -#if defined(HAVE_CONSENSUS_LIB) -#include