diff --git a/.gitignore b/.gitignore index bf4b6794c..a9f65fbe0 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,4 @@ xcuserdata/ .vscode/ # mypy .mypy_cache/ - +venv diff --git a/contrib/build-wine/deterministic.spec b/contrib/build-wine/deterministic.spec index b9fe85bdc..df93bb047 100644 --- a/contrib/build-wine/deterministic.spec +++ b/contrib/build-wine/deterministic.spec @@ -54,6 +54,7 @@ datas = [ (home+'electroncash/servers_testnet.json', 'electroncash'), (home+'electroncash/servers_testnet4.json', 'electroncash'), (home+'electroncash/servers_scalenet.json', 'electroncash'), + (home+'electroncash/servers_regtest.json', 'electroncash'), (home+'electroncash/wordlist/english.txt', 'electroncash/wordlist'), (home+'electroncash/locale', 'electroncash/locale'), (home+'electroncash_gui/qt/data/ecsupplemental_win.ttf', 'electroncash_gui/qt/data'), diff --git a/contrib/osx/osx.spec b/contrib/osx/osx.spec index 82cf5e9ff..95720b001 100644 --- a/contrib/osx/osx.spec +++ b/contrib/osx/osx.spec @@ -33,6 +33,7 @@ datas = [ (home+'electroncash/servers_testnet.json', PYPKG), (home+'electroncash/servers_testnet4.json', PYPKG), (home+'electroncash/servers_scalenet.json', PYPKG), + (home+'electroncash/servers_regtest.json', PYPKG), (home+'electroncash/wordlist/english.txt', PYPKG + '/wordlist'), (home+'electroncash/locale', PYPKG + '/locale'), (home+'electroncash_plugins', PYPKG + '_plugins'), diff --git a/electron-radiant b/electron-radiant old mode 100755 new mode 100644 index e4a272017..76143018b --- a/electron-radiant +++ b/electron-radiant @@ -468,9 +468,11 @@ def process_config_options(args): have_testnet = config_options.get("testnet", False) have_testnet4 = config_options.get("testnet4", False) have_scalenet = config_options.get("scalenet", False) - if have_testnet + have_testnet4 + have_scalenet > 1: + have_chipnet = config_options.get("chipnet", False) + have_regtest = config_options.get("regtest", False) + if have_testnet + have_testnet4 + have_scalenet + have_chipnet + have_regtest > 1: sys.exit( - "Invalid combination of --testnet, --testnet4, and/or --scalenet" + "Invalid combination of --testnet, --testnet4, --scalenet, --chipnet and/or --regtest" ) elif have_testnet: networks.set_testnet() @@ -478,6 +480,10 @@ def process_config_options(args): networks.set_testnet4() elif have_scalenet: networks.set_scalenet() + elif have_chipnet: + networks.set_chipnet() + elif have_regtest: + networks.set_regtest() # check uri uri = config_options.get("url") diff --git a/electroncash/blockchain.py b/electroncash/blockchain.py index 5f53c650c..1616cc29f 100644 --- a/electroncash/blockchain.py +++ b/electroncash/blockchain.py @@ -48,6 +48,7 @@ class VerifyError(Exception): # see https://gitlab.com/bitcoin-cash-node/bitcoin-cash-node/-/blob/v24.0.0/src/chainparams.cpp#L98 # Note: If we decide to support REGTEST this will need to come from regtest's networks.py params! MAX_TARGET = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff # compact: 0x1d00ffff +MAX_BITS_REGTEST = 0x207fffff # FIXME: if it is always constant, move to network constants # indicates no header in data file NULL_HEADER = bytes([0]) * HEADER_SIZE NULL_HASH_BYTES = bytes([0]) * 32 @@ -518,8 +519,10 @@ def get_bits(self, header, chunk=None): prevheight = height - 1 daa_mtp = self.get_median_time_past(prevheight, chunk) - # ASERTi3-2d DAA activated on (1657404000) Sat Jul 09 2022 22:00:00 GMT+0000 ASERT DAA enabled - if daa_mtp >= networks.net.asert_daa.MTP_ACTIVATION_TIME: + + # ASERTi3-2d DAA activated on Nov. 15th 2020 HF + # on regtest it is disabled as documented in BCHN code + if daa_mtp >= networks.net.asert_daa.MTP_ACTIVATION_TIME and not networks.net.REGTEST: header_ts = header['timestamp'] prev_ts = prior['timestamp'] if networks.net.TESTNET: @@ -544,6 +547,8 @@ def get_bits(self, header, chunk=None): return MAX_BITS # special case for a newly started testnet (such as testnet4) if height < N_BLOCKS: + if networks.net.REGTEST: + return MAX_BITS_REGTEST return MAX_BITS return self.read_header(height // N_BLOCKS * N_BLOCKS, chunk)['bits'] diff --git a/electroncash/commands.py b/electroncash/commands.py index d548b4565..3077c3b27 100644 --- a/electroncash/commands.py +++ b/electroncash/commands.py @@ -1009,6 +1009,8 @@ def add_global_options(parser): group.add_argument("--testnet", action="store_true", dest="testnet", default=False, help="Use Testnet") group.add_argument("--testnet4", action="store_true", dest="testnet4", default=False, help="Use Testnet4") group.add_argument("--scalenet", action="store_true", dest="scalenet", default=False, help="Use Scalenet") + group.add_argument("--chipnet", action="store_true", dest="chipnet", default=False, help="Use Chipnet") + group.add_argument("--regtest", action="store_true", dest="regtest", default=False, help="Use Regtest") def get_parser(): # create main parser diff --git a/electroncash/network.py b/electroncash/network.py index a16e3e5d8..bf2797bf2 100644 --- a/electroncash/network.py +++ b/electroncash/network.py @@ -1255,7 +1255,12 @@ def on_block_headers(self, interface, request, response): return verification_top_height = self.checkpoint_servers_verified.get(interface.server, {}).get('height', None) - was_verification_request = verification_top_height and request_base_height == verification_top_height - 147 + 1 and actual_header_count == 147 + was_verification_request = False + if verification_top_height is not None: + if not networks.net.REGTEST: + was_verification_request = request_base_height == verification_top_height - 147 + 1 and actual_header_count == 147 + else: + was_verification_request = request_base_height == verification_top_height - 50 + 1 and actual_header_count == 50 initial_interface_mode = interface.mode if interface.mode == Interface.MODE_VERIFICATION: @@ -1696,7 +1701,10 @@ def request_initial_proof_and_headers(self, interface): self.checkpoint_height = interface.tip - 100 self.checkpoint_servers_verified[interface.server] = { 'root': None, 'height': self.checkpoint_height } # We need at least 147 headers before the post checkpoint headers for daa calculations. - self._request_headers(interface, self.checkpoint_height - 147 + 1, 147, self.checkpoint_height) + if not networks.net.REGTEST: + self._request_headers(interface, self.checkpoint_height - 147 + 1, 147, self.checkpoint_height) + else: + self._request_headers(interface, self.checkpoint_height - 50 + 1, 50, self.checkpoint_height) else: # We already have them verified, maybe we got disconnected. interface.print_error("request_initial_proof_and_headers bypassed") diff --git a/electroncash/networks.py b/electroncash/networks.py index 00f3143be..4619a15e1 100644 --- a/electroncash/networks.py +++ b/electroncash/networks.py @@ -37,6 +37,7 @@ def _read_json_dict(filename): class AbstractNet: TESTNET = False + REGTEST = False LEGACY_POW_TARGET_TIMESPAN = 14 * 24 * 60 * 60 # 2 weeks LEGACY_POW_TARGET_INTERVAL = 10 * 60 # 10 minutes LEGACY_POW_RETARGET_BLOCKS = LEGACY_POW_TARGET_TIMESPAN // LEGACY_POW_TARGET_INTERVAL # 2016 blocks @@ -49,10 +50,10 @@ class MainNet(AbstractNet): WIF_PREFIX = 0x80 ADDRTYPE_P2PKH = 0 ADDRTYPE_P2SH = 5 - CASHADDR_PREFIX = "bitcoincash" + CASHADDR_PREFIX = "radaddr" RPA_PREFIX = "paycode" HEADERS_URL = "http://bitcoincash.com/files/blockchain_headers" # Unused - GENESIS = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" + GENESIS = "0000000065d8ed5d8be28d6876b3ffb660ac2a6c0ca59e437e1f7a6f4e003fb4" DEFAULT_PORTS = {'t': '50001', 's': '50002'} DEFAULT_SERVERS = _read_json_dict('servers.json') # DO NOT MODIFY IN CLIENT CODE TITLE = 'Electron Radiant' @@ -173,6 +174,21 @@ class ScaleNet(TestNet): asert_daa = ASERTDaa(is_testnet=False) # Despite being a "testnet", ScaleNet uses 2d half-life asert_daa.anchor = None # Intentionally not specified because it's after checkpoint; blockchain.py will calculate +class RegtestNet(TestNet): + GENESIS = "000000002008a2f4a76b850a838ae084994c200dc2fd354f73102298fe063a91" + TITLE = 'Electron Radiant Regtest' + CASHADDR_PREFIX = "radreg" + REGTEST = True + + BITCOIN_CASH_FORK_BLOCK_HEIGHT = 0 + BITCOIN_CASH_FORK_BLOCK_HASH = GENESIS + + VERIFICATION_BLOCK_HEIGHT = 100 + VERIFICATION_BLOCK_MERKLE_ROOT = None + asert_daa = ASERTDaa(is_testnet=True) # not used on regtest + + DEFAULT_SERVERS = _read_json_dict('servers_regtest.json') # DO NOT MODIFY IN CLIENT CODE + # All new code should access this to get the current network config. net = MainNet @@ -208,6 +224,11 @@ def set_scalenet(): net = ScaleNet _set_units() +def set_regtest(): + global net + net = RegtestNet + _set_units() + # Compatibility def _instancer(cls): diff --git a/electroncash/servers_regtest.json b/electroncash/servers_regtest.json new file mode 100644 index 000000000..f1fea946b --- /dev/null +++ b/electroncash/servers_regtest.json @@ -0,0 +1,8 @@ +{ + "127.0.0.1": { + "pruning": "-", + "s": "50110", + "t": "50112", + "version": "1.4" + } +} diff --git a/electroncash/simple_config.py b/electroncash/simple_config.py index e3b5e31c5..b8071d90c 100644 --- a/electroncash/simple_config.py +++ b/electroncash/simple_config.py @@ -104,6 +104,11 @@ def electrum_path(self): elif self.get('scalenet'): path = os.path.join(path, 'scalenet') make_dir(path) + elif self.get('chipnet'): + path = os.path.join(path, 'chipnet') + elif self.get('regtest'): + path = os.path.join(path, 'regtest') + make_dir(path) obsolete_file = os.path.join(path, 'recent_servers') if os.path.exists(obsolete_file): diff --git a/setup.py b/setup.py index e37ba0466..f0c478a64 100755 --- a/setup.py +++ b/setup.py @@ -185,6 +185,7 @@ def run(self): 'servers_testnet.json', 'servers_testnet4.json', 'servers_scalenet.json', + 'servers_regtest.json', 'currencies.json', 'www/index.html', 'wordlist/*.txt',