mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-13 11:35:20 +01:00
Inspired by https://github.com/bitcoin/bitcoin/pull/27446, this commit implements the proposal detailed in the comment https://github.com/bitcoin/bitcoin/pull/27446#issuecomment-1516600820. Rationale. Introduce the ability to configure a custom target time between blocks in a custom Bitcoin signet network. This enhancement enables users to create a signet that is more conducive to testing. The change enhances the flexibility of signet, rendering it more versatile for various testing scenarios. For instance, I am currently working on setting up a signet with a 30-second block time. However, this caused numerous difficulty adjustments, resulting in an inconsistent network state. Regtest isn't a viable alternative for me in this context since we prefer defaults to utilize our custom signet when configured, without impeding local regtest development. Implementation. If the challenge format is "OP_RETURN PUSHDATA<params> PUSHDATA<actual challenge>", the actual challenge from the second data push is used as the signet challenge, and the parameters from the first push are used to configure the network. Otherwise the challenge is used as is. Under the previous rules, such a signet challenge would always evaluate to false, suggesting that it is likely not in use by anyone. Updating bitcoind to a version that includes this change will not cause any disruptions - existing signet challenges will retain their original meaning without alteration. The only parameter currently available is "target_spacing" (default 600 seconds). To set it, place "0x01<target_spacing as uint64_t, little endian>" in the params. Empty params are also valid. If other network parameters are added in the future, they should use "0x02<option 2 value>", "0x03<option 3 value>", etc., following the protobuf style. Two public functions were added to chainparams.h: - ParseWrappedSignetChallenge: Extracts signet params and signet challenge from a wrapped signet challenge. - ParseSignetParams: Parses <params> bytes of the first data push. Function ReadSigNetArgs calls ParseWrappedSignetChallenge and ParseSignetParams to implement the new meaning of signetchallenge. The description of the flag -signetchallenge was updated to reflect the changes. A new unit tests file, chainparams_tests.cpp, was added, containing tests for ParseWrappedSignetChallenge and ParseSignetParams. The test signet_parse_tests from the file validation_tests.cpp was modified to ensure proper understanding of the new logic. In the functional test feature_signet.py, a test case was added with the value of -signetchallenge set to the wrapped challenge, setting spacing to 30 seconds and having the actual challenge OP_TRUE. The Signet miner was updated, introducing a new option --target-spacing with a default of 600 seconds. It must be set to the value used by the network. Example. I tested this commit against Mutinynet, a signet running on a custom fork of Bitcoin Core, implementing 30s target spacing. I successfully synchronized the blockchain using the following config: signet=1 [signet] signetchallenge=6a4c09011e000000000000004c25512102f7561d208dd9ae99bf497273e16f389bdbd6c4742ddb8e6b216e64fa2928ad8f51ae addnode=45.79.52.207:38333 dnsseed=0 The content of this wrapped challenge: 6a OP_RETURN 4c OP_PUSHDATA1 09 (length of signet params = 9) 011e00000000000000 (signet params: 0x01, pow_target_spacing=30) 4c OP_PUSHDATA1 25 (length of challenge = 37) 512102f7561d208dd9ae99bf497273e16f389bdbd6c4742ddb8e6b216e64fa2928ad8f51ae (original Mutinynet challenge, can be found here: https://blog.mutinywallet.com/mutinynet/ )
125 lines
12 KiB
Python
Executable file
125 lines
12 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# Copyright (c) 2019-2022 The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
"""Test basic signet functionality"""
|
|
|
|
from decimal import Decimal
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
from test_framework.util import assert_equal
|
|
|
|
SIGNET_DEFAULT_CHALLENGE = '512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae'
|
|
|
|
signet_blocks = [
|
|
'00000020f61eee3b63a380a477a063af32b2bbc97c9ff9f01f2c4225e973988108000000f575c83235984e7dc4afc1f30944c170462e84437ab6f2d52e16878a79e4678bd1914d5fae77031eccf4070001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025151feffffff0200f2052a010000001600149243f727dd5343293eb83174324019ec16c2630f0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402205e423a8754336ca99dbe16509b877ef1bf98d008836c725005b3c787c41ebe46022047246e4467ad7cc7f1ad98662afcaf14c115e0095a227c7b05c5182591c23e7e01000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
'00000020533b53ded9bff4adc94101d32400a144c54edc5ed492a3b26c63b2d686000000b38fef50592017cfafbcab88eb3d9cf50b2c801711cad8299495d26df5e54812e7914d5fae77031ecfdd0b0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025251feffffff0200f2052a01000000160014fd09839740f0e0b4fc6d5e2527e4022aa9b89dfa0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022031d64a1692cdad1fc0ced69838169fe19ae01be524d831b95fcf5ea4e6541c3c02204f9dea0801df8b4d0cd0857c62ab35c6c25cc47c930630dc7fe723531daa3e9b01000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
'000000202960f3752f0bfa8858a3e333294aedc7808025e868c9dc03e71d88bb320000007765fcd3d5b4966beb338bba2675dc2cf2ad28d4ad1d83bdb6f286e7e27ac1f807924d5fae77031e81d60b0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025351feffffff0200f2052a010000001600141e5fb426042692ae0e87c070e78c39307a5661c20000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402205de93694763a42954865bcf1540cb82958bc62d0ec4eee02070fb7937cd037f4022067f333753bce47b10bc25eb6e1f311482e994c862a7e0b2d41ab1c8679fd1b1101000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
'00000020b06443a13ae1d3d50faef5ecad38c6818194dc46abca3e972e2aacdae800000069a5829097e80fee00ac49a56ea9f82d741a6af84d32b3bc455cf31871e2a8ac27924d5fae77031e9c91050001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025451feffffff0200f2052a0100000016001430db2f8225dcf7751361ab38735de08190318cb70000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402200936f5f9872f6df5dd242026ad52241a68423f7f682e79169a8d85a374eab9b802202cd2979c48b321b3453e65e8f92460db3fca93cbea8539b450c959f4fbe630c601000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
'000000207ed403758a4f228a1939418a155e2ebd4ae6b26e5ffd0ae433123f7694010000542e80b609c5bc58af5bdf492e26d4f60cd43a3966c2e063c50444c29b3757a636924d5fae77031ee8601d0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025551feffffff0200f2052a01000000160014edc207e014df34fa3885dff97d1129d356e1186a0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022021a3656609f85a66a2c5672ed9322c2158d57251040d2716ed202a1fe14f0c12022057d68bc6611f7a9424a7e00bbf3e27e6ae6b096f60bac624a094bc97a59aa1ff01000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
'000000205bea0a88d1422c3df08d766ad72df95084d0700e6f873b75dd4e986c7703000002b57516d33ed60c2bdd9f93d6d5614083324c837e68e5ba6e04287a7285633585924d5fae77031ed171960001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025651feffffff0200f2052a010000001600143ae612599cf96f2442ce572633e0251116eaa52f0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022059a7c54de76bfdbb1dd44c78ea2dbd2bb4e97f4abad38965f41e76433e56423c022054bf17f04fe17415c0141f60eebd2b839200f574d8ad8d55a0917b92b0eb913401000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
'00000020daf3b60d374b19476461f97540498dcfa2eb7016238ec6b1d022f82fb60100007a7ae65b53cb988c2ec92d2384996713821d5645ffe61c9acea60da75cd5edfa1a944d5fae77031e9dbb050001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025751feffffff0200f2052a01000000160014ef2dceae02e35f8137de76768ae3345d99ca68860000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402202b3f946d6447f9bf17d00f3696cede7ee70b785495e5498274ee682a493befd5022045fc0bcf9332243168b5d35507175f9f374a8eba2336873885d12aada67ea5f601000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
'00000020457cc5f3c2e1a5655bc20e20e48d33e1b7ea68786c614032b5c518f0b6000000541f36942d82c6e7248275ff15c8933487fbe1819c67a9ecc0f4b70bb7e6cf672a944d5fae77031e8f39860001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025851feffffff0200f2052a0100000016001472a27906947c06d034b38ba2fa13c6391a4832790000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402202d62805ce60cbd60591f97f949b5ea5bd7e2307bcde343e6ea8394da92758e72022053a25370b0aa20da100189b7899a8f8675a0fdc60e38ece6b8a4f98edd94569e01000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
'00000020a2eb61eb4f3831baa3a3363e1b42db4462663f756f07423e81ed30322102000077224de7dea0f8d0ec22b1d2e2e255f0a987b96fe7200e1a2e6373f48a2f5b7894954d5fae77031e36867e0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025951feffffff0200f2052a01000000160014aa0ad9f26801258382e0734dceec03a4a75f60240000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402206fa0d59990eed369bd7375767c9a6c9369fae209152b8674e520da270605528c0220749eed3b12dbe3f583f505d21803e4aef59c8e24c5831951eafa4f15a8f92c4e01000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
'00000020a868e8514be5e46dabd6a122132f423f36a43b716a40c394e2a8d063e1010000f4c6c717e99d800c699c25a2006a75a0c5c09f432a936f385e6fce139cdbd1a5e9964d5fae77031e7d026e0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025a51feffffff0200f2052a01000000160014aaa671c82b138e3b8f510cd801e5f2bd0aa305940000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022042309f4c3c7a1a2ac8c24f890f962df1c0086cec10be0868087cfc427520cb2702201dafee8911c269b7e786e242045bb57cef3f5b0f177010c6159abae42f646cc501000120000000000000000000000000000000000000000000000000000000000000000000000000',
|
|
]
|
|
|
|
class SignetParams:
|
|
def __init__(self, challenge=None, internal_challenge=None):
|
|
if challenge is None:
|
|
self.challenge = SIGNET_DEFAULT_CHALLENGE
|
|
self.shared_args = []
|
|
else:
|
|
self.challenge = challenge
|
|
self.shared_args = [f"-signetchallenge={challenge}"]
|
|
|
|
if internal_challenge is None:
|
|
internal_challenge = self.challenge
|
|
self.internal_challenge = internal_challenge
|
|
|
|
class SignetBasicTest(BitcoinTestFramework):
|
|
def set_test_params(self):
|
|
self.chain = "signet"
|
|
self.num_nodes = 8
|
|
self.setup_clean_chain = True
|
|
self.signets = [
|
|
SignetParams(challenge='51'), # OP_TRUE
|
|
SignetParams(), # default challenge
|
|
# default challenge as a 2-of-2, which means it should fail
|
|
SignetParams(challenge='522103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae'),
|
|
SignetParams(challenge='6a4c09011e000000000000004c0151', internal_challenge='51'), # OP_TRUE, target_spacing=30
|
|
]
|
|
|
|
self.extra_args = [
|
|
self.signets[0].shared_args, self.signets[0].shared_args,
|
|
self.signets[1].shared_args, self.signets[1].shared_args,
|
|
self.signets[2].shared_args, self.signets[2].shared_args,
|
|
self.signets[3].shared_args, self.signets[3].shared_args,
|
|
]
|
|
|
|
def setup_network(self):
|
|
self.setup_nodes()
|
|
|
|
# Setup the three signets, which are incompatible with each other
|
|
self.connect_nodes(0, 1)
|
|
self.connect_nodes(2, 3)
|
|
self.connect_nodes(4, 5)
|
|
self.connect_nodes(6, 7)
|
|
|
|
def run_test(self):
|
|
self.log.info("basic tests using OP_TRUE challenge")
|
|
|
|
self.log.info('getblockchaininfo')
|
|
def check_getblockchaininfo(node_idx, signet_idx):
|
|
blockchain_info = self.nodes[node_idx].getblockchaininfo()
|
|
assert_equal(blockchain_info['chain'], 'signet')
|
|
assert_equal(blockchain_info['signet_challenge'], self.signets[signet_idx].internal_challenge)
|
|
check_getblockchaininfo(node_idx=1, signet_idx=0)
|
|
check_getblockchaininfo(node_idx=2, signet_idx=1)
|
|
check_getblockchaininfo(node_idx=5, signet_idx=2)
|
|
check_getblockchaininfo(node_idx=6, signet_idx=3)
|
|
|
|
self.log.info('getmininginfo')
|
|
def check_getmininginfo(node_idx, signet_idx):
|
|
mining_info = self.nodes[node_idx].getmininginfo()
|
|
assert_equal(mining_info['blocks'], 0)
|
|
assert_equal(mining_info['chain'], 'signet')
|
|
assert 'currentblocktx' not in mining_info
|
|
assert 'currentblockweight' not in mining_info
|
|
assert_equal(mining_info['networkhashps'], Decimal('0'))
|
|
assert_equal(mining_info['pooledtx'], 0)
|
|
assert_equal(mining_info['signet_challenge'], self.signets[signet_idx].internal_challenge)
|
|
check_getmininginfo(node_idx=0, signet_idx=0)
|
|
check_getmininginfo(node_idx=3, signet_idx=1)
|
|
check_getmininginfo(node_idx=4, signet_idx=2)
|
|
check_getmininginfo(node_idx=7, signet_idx=3)
|
|
|
|
self.generate(self.nodes[0], 1, sync_fun=self.no_op)
|
|
|
|
self.log.info("pregenerated signet blocks check")
|
|
|
|
# Verify that nodes accept blocks mined using the default signet challenge.
|
|
# This test includes one default signet node (2) and another node (6)
|
|
# configured with an extended signet challenge that uses the actual script
|
|
# OP_TRUE (accepts all blocks).
|
|
for node_idx in [2, 6]:
|
|
height = 0
|
|
for block in signet_blocks:
|
|
assert_equal(self.nodes[node_idx].submitblock(block), None)
|
|
height += 1
|
|
assert_equal(self.nodes[node_idx].getblockcount(), height)
|
|
|
|
self.log.info("pregenerated signet blocks check (incompatible solution)")
|
|
|
|
assert_equal(self.nodes[4].submitblock(signet_blocks[0]), 'bad-signet-blksig')
|
|
|
|
self.log.info("test that signet logs the network magic on node start")
|
|
with self.nodes[0].assert_debug_log(["Signet derived magic (message start)"]):
|
|
self.restart_node(0)
|
|
self.stop_node(0)
|
|
self.nodes[0].assert_start_raises_init_error(extra_args=["-signetchallenge=abc"], expected_msg="Error: -signetchallenge must be hex, not 'abc'.")
|
|
self.nodes[0].assert_start_raises_init_error(extra_args=["-signetchallenge=abc"] * 2, expected_msg="Error: -signetchallenge cannot be multiple values.")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
SignetBasicTest(__file__).main()
|