diff --git a/contrib/android/buildozer.spec b/contrib/android/buildozer.spec index 16bee6519fa4..4b2a8512b76e 100644 --- a/contrib/android/buildozer.spec +++ b/contrib/android/buildozer.spec @@ -50,12 +50,10 @@ requirements = # (str) Presplash of the application #presplash.filename = %(source.dir)s/gui/kivy/theming/splash.png -presplash.filename = %(source.dir)s/electrum/gui/icons/electrum_presplash.png +presplash.filename = %(source.dir)s/electrum/gui/icons/electrumg_presplash.png # (str) Icon of the application -icon.filename = %(source.dir)s/electrum/gui/icons/android_electrum_icon_legacy.png -icon.adaptive_foreground.filename = %(source.dir)s/electrum/gui/icons/android_electrum_icon_foreground.png -icon.adaptive_background.filename = %(source.dir)s/electrum/gui/icons/android_electrum_icon_background.png +icon.filename = %(source.dir)s/electrum/gui/icons/electrumg_launcher.png # (str) Supported orientation (one of landscape, portrait or all) orientation = portrait diff --git a/contrib/build-linux/appimage/build.sh b/contrib/build-linux/appimage/build.sh index cf078bb904ee..8dd2b640b000 100755 --- a/contrib/build-linux/appimage/build.sh +++ b/contrib/build-linux/appimage/build.sh @@ -7,7 +7,7 @@ CONTRIB="$PROJECT_ROOT/contrib" CONTRIB_APPIMAGE="$CONTRIB/build-linux/appimage" DISTDIR="$PROJECT_ROOT/dist" BUILDDIR="$CONTRIB_APPIMAGE/build/appimage" -APPDIR="$BUILDDIR/electrum.AppDir" +APPDIR="$BUILDDIR/electrumg.AppDir" CACHEDIR="$CONTRIB_APPIMAGE/.cache/appimage" PIP_CACHE_DIR="$CACHEDIR/pip_cache" @@ -22,7 +22,7 @@ SQUASHFSKIT_COMMIT="ae0d656efa2d0df2fcac795b6823b44462f19386" VERSION=`git describe --tags --dirty --always` -APPIMAGE="$DISTDIR/electrum-$VERSION-x86_64.AppImage" +APPIMAGE="$DISTDIR/electrumg-$VERSION-x86_64.AppImage" . "$CONTRIB"/build_tools_util.sh @@ -149,7 +149,7 @@ cp "/usr/lib/x86_64-linux-gnu/libzbar.so.0" "$APPDIR/usr/lib/libzbar.so.0" info "desktop integration." cp "$PROJECT_ROOT/electrum.desktop" "$APPDIR/electrum.desktop" -cp "$PROJECT_ROOT/electrum/gui/icons/electrum.png" "$APPDIR/electrum.png" +cp "$PROJECT_ROOT/electrum/gui/icons/electrumg.png" "$APPDIR/electrumg.png" # add launcher diff --git a/contrib/build-wine/build-electrum-git.sh b/contrib/build-wine/build-electrum-git.sh index 991f5fec1dbc..aa7626a3f77f 100755 --- a/contrib/build-wine/build-electrum-git.sh +++ b/contrib/build-wine/build-electrum-git.sh @@ -1,6 +1,6 @@ #!/bin/bash -NAME_ROOT=electrum +NAME_ROOT=electrumg export PYTHONDONTWRITEBYTECODE=1 diff --git a/contrib/build-wine/deterministic.spec b/contrib/build-wine/deterministic.spec index 0e3e4e800e9f..a5b3334d77cb 100644 --- a/contrib/build-wine/deterministic.spec +++ b/contrib/build-wine/deterministic.spec @@ -114,11 +114,11 @@ exe_standalone = EXE( a.scripts, a.binaries, a.datas, - name=os.path.join('build\\pyi.win32\\electrum', cmdline_name + ".exe"), + name=os.path.join('build\\pyi.win32\\electrumg', cmdline_name + ".exe"), debug=False, strip=None, upx=False, - icon=home+'electrum/gui/icons/electrum.ico', + icon=home+'electrum/gui/icons/electrumg.ico', console=False) # console=True makes an annoying black box pop up, but it does make Electrum output command line commands, with this turned off no output will be given but commands can still be used @@ -127,11 +127,11 @@ exe_portable = EXE( a.scripts, a.binaries, a.datas + [('is_portable', 'README.md', 'DATA')], - name=os.path.join('build\\pyi.win32\\electrum', cmdline_name + "-portable.exe"), + name=os.path.join('build\\pyi.win32\\electrumg', cmdline_name + "-portable.exe"), debug=False, strip=None, upx=False, - icon=home+'electrum/gui/icons/electrum.ico', + icon=home+'electrum/gui/icons/electrumg.ico', console=False) ##### @@ -145,7 +145,7 @@ exe_inside_setup_noconsole = EXE( debug=False, strip=None, upx=False, - icon=home+'electrum/gui/icons/electrum.ico', + icon=home+'electrum/gui/icons/electrumg.ico', console=False) exe_inside_setup_console = EXE( @@ -156,7 +156,7 @@ exe_inside_setup_console = EXE( debug=False, strip=None, upx=False, - icon=home+'electrum/gui/icons/electrum.ico', + icon=home+'electrum/gui/icons/electrumg.ico', console=True) coll = COLLECT( @@ -168,6 +168,6 @@ coll = COLLECT( strip=None, upx=True, debug=False, - icon=home+'electrum/gui/icons/electrum.ico', + icon=home+'electrum/gui/icons/electrumg.ico', console=False, name=os.path.join('dist', 'electrum')) diff --git a/contrib/build-wine/electrum.nsi b/contrib/build-wine/electrum.nsi index 1946c7749178..17dc33ad3588 100644 --- a/contrib/build-wine/electrum.nsi +++ b/contrib/build-wine/electrum.nsi @@ -6,9 +6,9 @@ ;-------------------------------- ;Variables - !define PRODUCT_NAME "Electrum" - !define PRODUCT_WEB_SITE "https://github.com/spesmilo/electrum" - !define PRODUCT_PUBLISHER "Electrum Technologies GmbH" + !define PRODUCT_NAME "ElectrumG" + !define PRODUCT_WEB_SITE "https://github.com/BTCGPU/electrum" + !define PRODUCT_PUBLISHER "The BTG Organization" !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" ;-------------------------------- @@ -72,7 +72,7 @@ !define MUI_ABORTWARNING !define MUI_ABORTWARNING_TEXT "Are you sure you wish to abort the installation of ${PRODUCT_NAME}?" - !define MUI_ICON "c:\electrum\electrum\gui\icons\electrum.ico" + !define MUI_ICON "c:\electrum\electrum\gui\icons\electrumg.ico" ;-------------------------------- ;Pages @@ -111,7 +111,7 @@ Section ;Files to pack into the installer File /r "dist\electrum\*.*" - File "c:\electrum\electrum\gui\icons\electrum.ico" + File "c:\electrum\electrum\gui\icons\electrumg.ico" ;Store installation folder WriteRegStr HKCU "Software\${PRODUCT_NAME}" "" $INSTDIR @@ -122,21 +122,21 @@ Section ;Create desktop shortcut DetailPrint "Creating desktop shortcut..." - CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "" + CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\electrumg-${PRODUCT_VERSION}.exe" "" ;Create start-menu items DetailPrint "Creating start-menu items..." CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}" CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0 - CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" 0 - CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME} Testnet.lnk" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" "--testnet" "$INSTDIR\electrum-${PRODUCT_VERSION}.exe" 0 + CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk" "$INSTDIR\electrumg-${PRODUCT_VERSION}.exe" "" "$INSTDIR\electrumg-${PRODUCT_VERSION}.exe" 0 + CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME} Testnet.lnk" "$INSTDIR\electrumg-${PRODUCT_VERSION}.exe" "--testnet" "$INSTDIR\electrumg-${PRODUCT_VERSION}.exe" 0 ;Links bitcoin: URI's to Electrum - WriteRegStr HKCU "Software\Classes\bitcoin" "" "URL:bitcoin Protocol" - WriteRegStr HKCU "Software\Classes\bitcoin" "URL Protocol" "" - WriteRegStr HKCU "Software\Classes\bitcoin" "DefaultIcon" "$\"$INSTDIR\electrum.ico, 0$\"" - WriteRegStr HKCU "Software\Classes\bitcoin\shell\open\command" "" "$\"$INSTDIR\electrum-${PRODUCT_VERSION}.exe$\" $\"%1$\"" + WriteRegStr HKCU "Software\Classes\bitcoing" "" "URL:BitcoinGold" + WriteRegStr HKCU "Software\Classes\bitcoing" "URL Protocol" "" + WriteRegStr HKCU "Software\Classes\bitcoing" "DefaultIcon" "$\"$INSTDIR\electrumg.ico, 0$\"" + WriteRegStr HKCU "Software\Classes\bitcoing\shell\open\command" "" "$\"$INSTDIR\electrumg-${PRODUCT_VERSION}.exe$\" $\"%1$\"" ;Adds an uninstaller possibility to Windows Uninstall or change a program section WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" @@ -144,7 +144,7 @@ Section WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" - WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\electrum.ico" + WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\electrumg.ico" ;Fixes Windows broken size estimates ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 @@ -167,7 +167,7 @@ Section "Uninstall" Delete "$SMPROGRAMS\${PRODUCT_NAME}\*.*" RMDir "$SMPROGRAMS\${PRODUCT_NAME}" - DeleteRegKey HKCU "Software\Classes\bitcoin" + DeleteRegKey HKCU "Software\Classes\bitcoing" DeleteRegKey HKCU "Software\${PRODUCT_NAME}" DeleteRegKey HKCU "${PRODUCT_UNINST_KEY}" SectionEnd diff --git a/contrib/deterministic-build/requirements-hw.txt b/contrib/deterministic-build/requirements-hw.txt index 59efcf4adcaa..1a0738ad5e8b 100644 --- a/contrib/deterministic-build/requirements-hw.txt +++ b/contrib/deterministic-build/requirements-hw.txt @@ -173,4 +173,4 @@ urllib3==1.26.3 \ --hash=sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73 wheel==0.36.2 \ --hash=sha256:78b5b185f0e5763c26ca1e324373aadd49182ca90e825f7853f4b2509215dc0e \ - --hash=sha256:e11eefd162658ea59a60a0f6c7d493a7190ea4b9a85e335b33489d9f17e0245e \ No newline at end of file + --hash=sha256:e11eefd162658ea59a60a0f6c7d493a7190ea4b9a85e335b33489d9f17e0245e diff --git a/contrib/deterministic-build/requirements.txt b/contrib/deterministic-build/requirements.txt index 0a9860b3820e..1f86958040e1 100644 --- a/contrib/deterministic-build/requirements.txt +++ b/contrib/deterministic-build/requirements.txt @@ -200,4 +200,6 @@ zipp==3.4.1 \ --hash=sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098 colorama==0.4.4 \ --hash=sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b \ - --hash=sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2 \ No newline at end of file + --hash=sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2 +diskcache==4.1.0 \ + --hash=sha256:bcee5a59f9c264e2809e58d01be6569a3bbb1e36a1e0fb83f7ef9b2075f95ce0 diff --git a/contrib/make_download b/contrib/make_download index 737d0b1395e1..d925d8a5320d 100755 --- a/contrib/make_download +++ b/contrib/make_download @@ -30,13 +30,13 @@ string = string.replace("##VERSION_ANDROID##", version_android) string = string.replace("##VERSION_APK##", APK_VERSION) files = { - 'tgz': "Electrum-%s.tar.gz" % version, - 'appimage': "electrum-%s-x86_64.AppImage" % version, - 'zip': "Electrum-%s.zip" % version, - 'mac': "electrum-%s.dmg" % version_mac, - 'win': "electrum-%s.exe" % version_win, - 'win_setup': "electrum-%s-setup.exe" % version_win, - 'win_portable': "electrum-%s-portable.exe" % version_win, + 'tgz': "ElectrumG-%s.tar.gz" % version, + 'appimage': "electrumg-%s-x86_64.AppImage" % version, + 'zip': "ElectrumG-%s.zip" % version, + 'mac': "electrumg-%s.dmg" % version_mac, + 'win': "electrumg-%s.exe" % version_win, + 'win_setup': "electrumg-%s-setup.exe" % version_win, + 'win_portable': "electrumg-%s-portable.exe" % version_win, } for k, n in files.items(): diff --git a/contrib/osx/make_osx b/contrib/osx/make_osx index 3ace02c97ccc..5d2516025ba6 100755 --- a/contrib/osx/make_osx +++ b/contrib/osx/make_osx @@ -3,8 +3,8 @@ # Parameterize PYTHON_VERSION=3.7.10 BUILDDIR=/tmp/electrum-build -PACKAGE=Electrum -GIT_REPO=https://github.com/spesmilo/electrum +PACKAGE=ElectrumG +GIT_REPO=https://github.com/BTCGPU/electrum export GCC_STRIP_BINARIES="1" @@ -182,9 +182,9 @@ if [ ! -z "$CODESIGN_CERT" ]; then fi info "Creating .DMG" -hdiutil create -fs HFS+ -volname $PACKAGE -srcfolder dist/$PACKAGE.app dist/electrum-$VERSION.dmg || fail "Could not create .DMG" +hdiutil create -fs HFS+ -volname $PACKAGE -srcfolder dist/$PACKAGE.app dist/electrumg-$VERSION.dmg || fail "Could not create .DMG" -DoCodeSignMaybe ".DMG" "dist/electrum-${VERSION}.dmg" +DoCodeSignMaybe ".DMG" "dist/electrumg-${VERSION}.dmg" if [ -z "$CODESIGN_CERT" ]; then warn "App was built successfully but was not code signed. Users may get security warnings from macOS." diff --git a/contrib/osx/osx.spec b/contrib/osx/osx.spec index 950a576d533a..a47b1bfc877b 100644 --- a/contrib/osx/osx.spec +++ b/contrib/osx/osx.spec @@ -4,10 +4,10 @@ from PyInstaller.utils.hooks import collect_data_files, collect_submodules, coll import sys, os -PACKAGE='Electrum' +PACKAGE='ElectrumG' PYPKG='electrum' MAIN_SCRIPT='run_electrum' -ICONS_FILE=PYPKG + '/gui/icons/electrum.icns' +ICONS_FILE=PYPKG + '/gui/icons/electrumg.icns' APP_SIGN = os.environ.get('APP_SIGN', '') def fail(*msg): diff --git a/contrib/osx/package.sh b/contrib/osx/package.sh index 096ef02abdf3..d495776f76f3 100755 --- a/contrib/osx/package.sh +++ b/contrib/osx/package.sh @@ -73,16 +73,16 @@ ${genisoimage} \ -D \ -l \ -probe \ - -V "Electrum" \ + -V "ElectrumG" \ -no-pad \ -r \ -dir-mode 0755 \ -apple \ - -o Electrum_uncompressed.dmg \ + -o ElectrumG_uncompressed.dmg \ /tmp/electrum-macos/image || fail "Unable to create uncompressed dmg" -dmg dmg Electrum_uncompressed.dmg electrum-$VERSION.dmg || fail "Unable to create compressed dmg" -rm Electrum_uncompressed.dmg +dmg dmg ElectrumG_uncompressed.dmg electrumg-$VERSION.dmg || fail "Unable to create compressed dmg" +rm ElectrumG_uncompressed.dmg echo "Done." -sha256sum electrum-$VERSION.dmg +sha256sum electrumg-$VERSION.dmg diff --git a/contrib/requirements/requirements.txt b/contrib/requirements/requirements.txt index d6aeb0154d12..62005ff8ffd5 100644 --- a/contrib/requirements/requirements.txt +++ b/contrib/requirements/requirements.txt @@ -7,6 +7,7 @@ aiohttp_socks>=0.3 certifi bitstring attrs>=19.2.0 +diskcache>=4.1.0 # Note that we also need the dnspython[DNSSEC] extra which pulls in cryptography, # but as that is not pure-python it cannot be listed in this file! diff --git a/electrum.desktop b/electrum.desktop index e40106716580..d9c828a64c1c 100644 --- a/electrum.desktop +++ b/electrum.desktop @@ -2,13 +2,13 @@ # sudo desktop-file-install electrum.desktop [Desktop Entry] -Comment=Lightweight Bitcoin Client +Comment=Lightweight Bitcoin Gold Client Exec=sh -c "PATH=\"\\$HOME/.local/bin:\\$PATH\"; electrum %u" -GenericName[en_US]=Bitcoin Wallet -GenericName=Bitcoin Wallet -Icon=electrum -Name[en_US]=Electrum Bitcoin Wallet -Name=Electrum Bitcoin Wallet +GenericName[en_US]=BitcoinGold Wallet +GenericName=BitcoinGold Wallet +Icon=electrumg +Name[en_US]=Electrum BitcoinGold Wallet +Name=Electrum BitcoinGold Wallet Categories=Finance;Network; StartupNotify=true StartupWMClass=electrum diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py index ac400249a1a5..3ec00debd330 100644 --- a/electrum/base_wizard.py +++ b/electrum/base_wizard.py @@ -145,7 +145,8 @@ def new(self): ]) wallet_kinds = [ ('standard', _("Standard wallet")), - ('2fa', _("Wallet with two-factor authentication")), + # TODO: fix the 2fa + # ('2fa', _("Wallet with two-factor authentication")), ('multisig', _("Multi-signature wallet")), ('imported', _("Import Bitcoin addresses or private keys")), ] diff --git a/electrum/bip39_wallet_formats.json b/electrum/bip39_wallet_formats.json index 8fb92c17cfbe..cee5091a9139 100644 --- a/electrum/bip39_wallet_formats.json +++ b/electrum/bip39_wallet_formats.json @@ -1,19 +1,19 @@ [ { "description": "Standard BIP44 legacy", - "derivation_path": "m/44'/0'/0'", + "derivation_path": "m/44'/156'/0'", "script_type": "p2pkh", "iterate_accounts": true }, { "description": "Standard BIP49 compatibility segwit", - "derivation_path": "m/49'/0'/0'", + "derivation_path": "m/49'/156'/0'", "script_type": "p2wpkh-p2sh", "iterate_accounts": true }, { "description": "Standard BIP84 native segwit", - "derivation_path": "m/84'/0'/0'", + "derivation_path": "m/84'/156'/0'", "script_type": "p2wpkh", "iterate_accounts": true }, diff --git a/electrum/blockchain.py b/electrum/blockchain.py index f911d4b1e007..a6b00e811ac1 100644 --- a/electrum/blockchain.py +++ b/electrum/blockchain.py @@ -20,18 +20,21 @@ # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. + import os import threading import time from typing import Optional, Dict, Mapping, Sequence - +from .header_storage import HeaderStorage from . import util from .bitcoin import hash_encode, int_to_hex, rev_hex from .crypto import sha256d from . import constants -from .util import bfh, bh2u, with_lock +from .util import bfh, bh2u, to_bytes, with_lock +from struct import unpack_from, unpack from .simple_config import SimpleConfig from .logging import get_logger, Logger +from .equihash import is_gbp_valid _logger = get_logger(__name__) @@ -46,29 +49,133 @@ class MissingHeader(Exception): class InvalidHeader(Exception): pass +def averaging_window_timespan(): + return constants.net.DIGI_AVERAGING_WINDOW * constants.net.POW_TARGET_SPACING + +def min_actual_timespan(): + return (averaging_window_timespan() * (100 - constants.net.DIGI_MAX_ADJUST_UP)) // 100 + +def max_actual_timespan(): + return (averaging_window_timespan() * (100 + constants.net.DIGI_MAX_ADJUST_DOWN)) // 100 + +def is_post_btg_fork(height): + return height >= constants.net.BTG_HEIGHT + +def is_post_equihash_fork(height): + return height >= constants.net.EQUIHASH_FORK_HEIGHT + +def needs_retarget(height): + return is_post_btg_fork(height) or (height % difficulty_adjustment_interval() == 0) + + +def difficulty_adjustment_interval(): + return constants.net.POW_TARGET_TIMESPAN_LEGACY // constants.net.POW_TARGET_SPACING + +def get_header_size(height): + size = constants.net.HEADER_SIZE_LEGACY + + if is_post_btg_fork(height): + solution_size = get_equihash_params(height).get_solution_size() + solution_size_compact = len(var_int(solution_size)) // 2 - 1 + size += solution_size_compact + solution_size + + return size + +def var_int(i): + # https://en.bitcoin.it/wiki/Protocol_specification#Variable_length_integer + if i < 0xfd: + return int_to_hex(i) + elif i <= 0xffff: + return "fd"+int_to_hex(i, 2) + elif i <= 0xffffffff: + return "fe"+int_to_hex(i, 4) + else: + return "ff"+int_to_hex(i, 8) + + +def var_int_read(value, start): + size = value[start] + start += 1 + + if size == 253: + (size,) = unpack_from(' str: s = int_to_hex(header_dict['version'], 4) \ + rev_hex(header_dict['prev_block_hash']) \ - + rev_hex(header_dict['merkle_root']) \ - + int_to_hex(int(header_dict['timestamp']), 4) \ - + int_to_hex(int(header_dict['bits']), 4) \ - + int_to_hex(int(header_dict['nonce']), 4) + + rev_hex(header_dict['merkle_root']) + + # not legacy block + if header_dict.get('block_height') >= constants.net.BTG_HEIGHT: + s += int_to_hex(header_dict.get('block_height'), 4) \ + + rev_hex(header_dict.get('reserved')) + + s += int_to_hex(header_dict.get('timestamp'), 4) \ + + int_to_hex(header_dict.get('bits'), 4) + + # legacy block + if header_dict.get('block_height') < constants.net.BTG_HEIGHT: + # Bitcoin header nonce is 32 bits + s += rev_hex(header_dict.get('nonce'))[:8] + else: + # Bitcoin Gold header nonce is 256 bits + s += rev_hex(header_dict.get('nonce')) \ + + rev_hex(header_dict.get('solution')) + return s def deserialize_header(s: bytes, height: int) -> dict: if not s: raise InvalidHeader('Invalid header: {}'.format(s)) - if len(s) != HEADER_SIZE: - raise InvalidHeader('Invalid header length: {}'.format(len(s))) + + # original blok + if height < constants.net.BTG_HEIGHT: + if len(s) != constants.net.HEADER_SIZE_ORIGIN: + raise InvalidHeader('Invalid header length: {}'.format(len(s))) + else: + if len(s) < constants.net.HEADER_SIZE_LEGACY: + raise InvalidHeader('Invalid header length: {}'.format(len(s))) + hex_to_int = lambda s: int.from_bytes(s, byteorder='little') h = {} + h['block_height'] = height h['version'] = hex_to_int(s[0:4]) h['prev_block_hash'] = hash_encode(s[4:36]) h['merkle_root'] = hash_encode(s[36:68]) - h['timestamp'] = hex_to_int(s[68:72]) - h['bits'] = hex_to_int(s[72:76]) - h['nonce'] = hex_to_int(s[76:80]) - h['block_height'] = height + + # original block + if height < constants.net.BTG_HEIGHT: + h['timestamp'] = hex_to_int(s[68:72]) + h['bits'] = hex_to_int(s[72:76]) + h['nonce'] = hash_encode(s[76:80]) + else: + h['reserved'] = hash_encode(s[72:100]) + h['timestamp'] = hex_to_int(s[100:104]) + h['bits'] = hex_to_int(s[104:108]) + h['nonce'] = hash_encode(s[108:140]) + h['solution'] = hash_encode(s[140:]) + return h def hash_header(header: dict) -> str: @@ -82,7 +189,6 @@ def hash_header(header: dict) -> str: def hash_raw_header(header: str) -> str: return hash_encode(sha256d(bfh(header))) - # key: blockhash hex at forkpoint # the chain at some key is the best chain that includes the given hash blockchains = {} # type: Dict[str, Blockchain] @@ -91,11 +197,12 @@ def hash_raw_header(header: str) -> str: def read_blockchains(config: 'SimpleConfig'): best_chain = Blockchain(config=config, - forkpoint=0, + forkpoint=constants.net.max_checkpoint(), parent=None, - forkpoint_hash=constants.net.GENESIS, + forkpoint_hash=constants.net.get_checkpoint_hash(constants.net.max_checkpoint()), prev_hash=None) - blockchains[constants.net.GENESIS] = best_chain + best_chain.save_header(constants.net.MAX_CHECKPOINT_HEADER) + blockchains[constants.net.get_checkpoint_hash(constants.net.max_checkpoint())] = best_chain # consistency checks if best_chain.height() > constants.net.max_checkpoint(): header_after_cp = best_chain.read_header(constants.net.max_checkpoint()+1) @@ -103,6 +210,7 @@ def read_blockchains(config: 'SimpleConfig'): _logger.info("[blockchain] deleting best chain. cannot connect header after last cp to last cp.") os.unlink(best_chain.path()) best_chain.update_size() + # forks fdir = os.path.join(util.get_headers_dir(config), 'forks') util.make_dir(fdir) @@ -112,7 +220,10 @@ def read_blockchains(config: 'SimpleConfig'): def delete_chain(filename, reason): _logger.info(f"[blockchain] deleting chain {filename}: {reason}") - os.unlink(os.path.join(fdir, filename)) + if os.path.isdir(os.path.join(fdir, filename)): # maybe leveldb data dir + os.rmdir(os.path.join(fdir, filename)) + else: + os.unlink(os.path.join(fdir, filename)) def instantiate_chain(filename): __, forkpoint, prev_hash, first_hash = filename.split('_') @@ -152,7 +263,7 @@ def instantiate_chain(filename): def get_best_chain() -> 'Blockchain': - return blockchains[constants.net.GENESIS] + return blockchains[constants.net.get_checkpoint_hash(constants.net.max_checkpoint())] # block hash -> chain work; up to and including that block _CHAINWORK_CACHE = { @@ -162,14 +273,6 @@ def get_best_chain() -> 'Blockchain': def init_headers_file_for_best_chain(): b = get_best_chain() - filename = b.path() - length = HEADER_SIZE * len(constants.net.CHECKPOINTS) * 2016 - if not os.path.exists(filename) or os.path.getsize(filename) < length: - with open(filename, 'wb') as f: - if length > 0: - f.seek(length - 1) - f.write(b'\x00') - util.ensure_sparse_file(filename) with b.lock: b.update_size() @@ -178,21 +281,23 @@ class Blockchain(Logger): """ Manages blockchain headers and their verification """ - def __init__(self, config: SimpleConfig, forkpoint: int, parent: Optional['Blockchain'], forkpoint_hash: str, prev_hash: Optional[str]): + assert isinstance(forkpoint_hash, str) and len(forkpoint_hash) == 64, forkpoint_hash assert (prev_hash is None) or (isinstance(prev_hash, str) and len(prev_hash) == 64), prev_hash # assert (parent is None) == (forkpoint == 0) - if 0 < forkpoint <= constants.net.max_checkpoint(): + if 0 < forkpoint < constants.net.max_checkpoint(): raise Exception(f"cannot fork below max checkpoint. forkpoint: {forkpoint}") Logger.__init__(self) self.config = config self.forkpoint = forkpoint # height of first header + self._height = forkpoint # latest height of current chain self.parent = parent self._forkpoint_hash = forkpoint_hash # blockhash at forkpoint. "first hash" self._prev_hash = prev_hash # blockhash immediately before forkpoint self.lock = threading.RLock() + self.headerdb = HeaderStorage(self.path()) self.update_size() @property @@ -268,7 +373,6 @@ def fork(parent, header: dict) -> 'Blockchain': forkpoint_hash=hash_header(header), prev_hash=parent.get_hash(forkpoint-1)) self.assert_headers_file_available(parent.path()) - open(self.path(), 'w+').close() self.save_header(header) # put into global dict. note that in some cases # save_header might have already put it there but that's OK @@ -279,16 +383,19 @@ def fork(parent, header: dict) -> 'Blockchain': @with_lock def height(self) -> int: - return self.forkpoint + self.size() - 1 + # return self.headerdb.get_latest() + return self._height - @with_lock - def size(self) -> int: - return self._size + # @with_lock + # def size(self) -> int: + # return self._size @with_lock def update_size(self) -> None: - p = self.path() - self._size = os.path.getsize(p)//HEADER_SIZE if os.path.exists(p) else 0 + latest = self.headerdb.get_latest() + # restore _height if this is not the first time runing + if latest != 0 and latest > self.forkpoint: + self._height = latest @classmethod def verify_header(cls, header: dict, prev_hash: str, target: int, expected_header_hash: str=None) -> None: @@ -297,7 +404,7 @@ def verify_header(cls, header: dict, prev_hash: str, target: int, expected_heade raise Exception("hash mismatches with expected: {} vs {}".format(expected_header_hash, _hash)) if prev_hash != header.get('prev_block_hash'): raise Exception("prev hash mismatch: %s vs %s" % (prev_hash, header.get('prev_block_hash'))) - if constants.net.TESTNET: + if constants.net == constants.BitcoinGoldTestnet or constants.net == constants.BitcoinGoldRegtest: return bits = cls.target_to_bits(target) if bits != header.get('bits'): @@ -306,55 +413,69 @@ def verify_header(cls, header: dict, prev_hash: str, target: int, expected_heade if block_hash_as_num > target: raise Exception(f"insufficient proof of work: {block_hash_as_num} vs target {target}") - def verify_chunk(self, index: int, data: bytes) -> None: - num = len(data) // HEADER_SIZE - start_height = index * 2016 - prev_hash = self.get_hash(start_height - 1) - target = self.get_target(index-1) - for i in range(num): - height = start_height + i - try: - expected_header_hash = self.get_hash(height) - except MissingHeader: - expected_header_hash = None - raw_header = data[i*HEADER_SIZE : (i+1)*HEADER_SIZE] - header = deserialize_header(raw_header, index*2016 + i) - self.verify_header(header, prev_hash, target, expected_header_hash) + # only verify header post equihash fork + if is_post_equihash_fork(header.get('block_height')): + header_bytes = bytes.fromhex(serialize_header(header)) + nonce = uint256_from_bytes(bfh(header.get('nonce'))[::-1]) + solution = bfh(header.get('solution'))[::-1] + offset, length = var_int_read(solution, 0) + solution = solution[offset:] + + params = get_equihash_params(header.get('block_height')) + + if not is_gbp_valid(header_bytes, nonce, solution, params): + raise Exception("Invalid equihash solution") + + # verify chunk and return verified headers contained by this chunk + def verify_chunk(self, height: int, data: bytes) -> list: + + size = len(data) + offset = 0 + prev_hash = self.get_hash(height-1) + + headers = {} + target = 0 + + while offset < size: + header_size = get_header_size(height) + raw_header = data[offset:(offset + header_size)] + header = deserialize_header(raw_header, height) + headers[height] = header + + # Check retarget + if height > constants.net.EQUIHASH_FORK_HEIGHT and (needs_retarget(height) or target == 0): + target = self.get_target(height, headers) + + self.verify_header(header, prev_hash, target, None) prev_hash = hash_header(header) + offset += header_size + height += 1 + + return list(headers.values()) @with_lock def path(self): d = util.get_headers_dir(self.config) if self.parent is None: - filename = 'blockchain_headers' + filename = 'blockchain_headers.v4' else: assert self.forkpoint > 0, self.forkpoint prev_hash = self._prev_hash.lstrip('0') first_hash = self._forkpoint_hash.lstrip('0') basename = f'fork2_{self.forkpoint}_{prev_hash}_{first_hash}' filename = os.path.join('forks', basename) + filename = os.path.join(filename, '.v4') return os.path.join(d, filename) - @with_lock - def save_chunk(self, index: int, chunk: bytes): - assert index >= 0, index - chunk_within_checkpoint_region = index < len(self.checkpoints) + def save_chunk(self, height: int, headerlist: list) -> None: + + chunk_within_checkpoint_region = (height + len(headerlist)) < len(self.checkpoints) # chunks in checkpoint region are the responsibility of the 'main chain' - if chunk_within_checkpoint_region and self.parent is not None: - main_chain = get_best_chain() - main_chain.save_chunk(index, chunk) + if chunk_within_checkpoint_region: return - delta_height = (index * 2016 - self.forkpoint) - delta_bytes = delta_height * HEADER_SIZE - # if this chunk contains our forkpoint, only save the part after forkpoint - # (the part before is the responsibility of the parent) - if delta_bytes < 0: - chunk = chunk[-delta_bytes:] - delta_bytes = 0 - truncate = not chunk_within_checkpoint_region - self.write(chunk, delta_bytes, truncate) - self.swap_with_parent() + self.headerdb.save_header_chunk(headerlist) + self.update_size() def swap_with_parent(self) -> None: with self.lock, blockchains_lock: @@ -375,9 +496,9 @@ def swap_with_parent(self) -> None: def _swap_with_parent(self) -> bool: """Check if this chain became stronger than its parent, and swap - the underlying files if so. The Blockchain instances will keep + the underlying files(leveldb file for BTG) if so. The Blockchain instances will keep 'containing' the same headers, but their ids change and so - they will be stored in different files.""" + they will be stored in different files(leveldb file for BTG).""" if self.parent is None: return False if self.parent.get_chainwork() >= self.get_chainwork(): @@ -393,25 +514,15 @@ def _swap_with_parent(self) -> bool: # parent's new name will be something new (not child's old name) self.assert_headers_file_available(self.path()) child_old_name = self.path() - with open(self.path(), 'rb') as f: - my_data = f.read() self.assert_headers_file_available(parent.path()) - assert forkpoint > parent.forkpoint, (f"forkpoint of parent chain ({parent.forkpoint}) " - f"should be at lower height than children's ({forkpoint})") - with open(parent.path(), 'rb') as f: - f.seek((forkpoint - parent.forkpoint)*HEADER_SIZE) - parent_data = f.read(parent_branch_size*HEADER_SIZE) - self.write(parent_data, 0) - parent.write(my_data, (forkpoint - parent.forkpoint)*HEADER_SIZE) # swap parameters + self._forkpoint_hash, parent._forkpoint_hash = parent._forkpoint_hash, hash_raw_header(serialize_header(self.read_header(self.forkpoint))) self.parent, parent.parent = parent.parent, self # type: Optional[Blockchain], Optional[Blockchain] self.forkpoint, parent.forkpoint = parent.forkpoint, self.forkpoint - self._forkpoint_hash, parent._forkpoint_hash = parent._forkpoint_hash, hash_raw_header(bh2u(parent_data[:HEADER_SIZE])) + self.headerdb, parent.headerdb = parent.headerdb, self.headerdb self._prev_hash, parent._prev_hash = parent._prev_hash, self._prev_hash # parent's new name os.replace(child_old_name, parent.path()) - self.update_size() - parent.update_size() # update pointers blockchains.pop(child_old_id, None) blockchains.pop(parent_old_id, None) @@ -432,47 +543,44 @@ def assert_headers_file_available(self, path): @with_lock def write(self, data: bytes, offset: int, truncate: bool=True) -> None: - filename = self.path() - self.assert_headers_file_available(filename) - with open(filename, 'rb+') as f: - if truncate and offset != self._size * HEADER_SIZE: - f.seek(offset) - f.truncate() - f.seek(offset) - f.write(data) - f.flush() - os.fsync(f.fileno()) + pass + + @with_lock + def save_header(self, header: dict) -> None: + height = header.get('block_height') + # headers are only _appended_ to the end if header is not forkpoint header to saved of the chain: + if (height != self.forkpoint): + assert (height == (self._height + 1)), (height, self._height) + + self.headerdb.save_header(header) + self.logger.info(f'saved header into database at height: {height}') self.update_size() @with_lock - def save_header(self, header: dict) -> None: - delta = header.get('block_height') - self.forkpoint - data = bfh(serialize_header(header)) - # headers are only _appended_ to the end: - assert delta == self.size(), (delta, self.size()) - assert len(data) == HEADER_SIZE - self.write(data, delta*HEADER_SIZE) - self.swap_with_parent() + def save_header_without_update(self, header: dict) -> None: + height = header.get('block_height') + self.headerdb.save_header(header) + self.logger.info(f'saved header into database at height: {height}') @with_lock def read_header(self, height: int) -> Optional[dict]: if height < 0: return - if height < self.forkpoint: + if height < (self.forkpoint - constants.net.LWMA_AVERAGING_WINDOW): + if self.parent is None: + return return self.parent.read_header(height) if height > self.height(): return - delta = height - self.forkpoint - name = self.path() - self.assert_headers_file_available(name) - with open(name, 'rb') as f: - f.seek(delta * HEADER_SIZE) - h = f.read(HEADER_SIZE) - if len(h) < HEADER_SIZE: - raise Exception('Expected to read a full header. This was only {} bytes'.format(len(h))) - if h == bytes([0])*HEADER_SIZE: - return None - return deserialize_header(h, height) + + return self.headerdb.read_header(height) + + @with_lock + def header_exist(self, height: int) -> bool: + if self.headerdb.read_header(height) == None: + return False + else: + return True def header_at_tip(self) -> Optional[dict]: """Return latest header.""" @@ -513,91 +621,244 @@ def is_height_checkpoint(): raise MissingHeader(height) return hash_header(header) - def get_target(self, index: int) -> int: - # compute target from chunk x, used in chunk x+1 - if constants.net.TESTNET: - return 0 - if index == -1: - return MAX_TARGET - if index < len(self.checkpoints): - h, t = self.checkpoints[index] - return t - # new target - first = self.read_header(index * 2016) - last = self.read_header(index * 2016 + 2015) - if not first or not last: - raise MissingHeader() - bits = last.get('bits') - target = self.bits_to_target(bits) - nActualTimespan = last.get('timestamp') - first.get('timestamp') - nTargetTimespan = 14 * 24 * 60 * 60 - nActualTimespan = max(nActualTimespan, nTargetTimespan // 4) - nActualTimespan = min(nActualTimespan, nTargetTimespan * 4) - new_target = min(MAX_TARGET, (target * nActualTimespan) // nTargetTimespan) - # not any target can be represented in 32 bits: - new_target = self.bits_to_target(self.target_to_bits(new_target)) + def get_header(self, height, headers=None) -> Optional[dict]: + if headers is None: + headers = {} + + return headers[height] if height in headers else self.read_header(height) + + def get_target(self, height, headers=None): + if headers is None: + headers = {} + + # Check for genesis + if height == 0: + new_target = constants.net.POW_LIMIT_LEGACY + # Check for valid checkpoint + elif (height + 1) % difficulty_adjustment_interval() == 0 and 0 <= (((height + 1) // difficulty_adjustment_interval()) - 1) < len(self.checkpoints): + h, t = self.checkpoints[((height // difficulty_adjustment_interval()) - 1)] + new_target = t + # Check for prefork + elif height < constants.net.BTG_HEIGHT: + new_target = self.get_legacy_target(height, headers) + # Premine + elif height < constants.net.BTG_HEIGHT + constants.net.PREMINE_SIZE: + new_target = constants.net.POW_LIMIT + # Initial start of BTG Fork (reduced difficulty) + elif height < constants.net.BTG_HEIGHT + constants.net.PREMINE_SIZE + constants.net.DIGI_AVERAGING_WINDOW: + new_target = constants.net.POW_LIMIT_START + # Digishield + elif height < constants.net.LWMA_HEIGHT: + new_target = self.get_digishield_target(height, headers) + # Zawy LWMA (old) + elif height < constants.net.EQUIHASH_FORK_HEIGHT: + new_target = self.get_lwma_target(height, headers, constants.net.LWMA_ADJUST_WEIGHT_LEGACY, + constants.net.LWMA_MIN_DENOMINATOR_LEGACY) + # Initial start of BTG Equihash Fork (reduced difficulty) + elif height < constants.net.EQUIHASH_FORK_HEIGHT + constants.net.LWMA_AVERAGING_WINDOW: + last = self.get_header((height - 1), headers) + bits = last.get('bits') + new_target = self.bits_to_target(bits) + + if height == constants.net.EQUIHASH_FORK_HEIGHT: + # reduce diff + new_target *= 100 + + if new_target > constants.net.POW_LIMIT: + new_target = constants.net.POW_LIMIT + # Zawy LWMA (new) + else: + new_target = self.get_lwma_target(height, headers, constants.net.LWMA_ADJUST_WEIGHT, + constants.net.LWMA_MIN_DENOMINATOR) + return new_target + def get_legacy_target(self, height, headers): + last_height = (height - 1) + last = self.get_header(last_height, headers) + + if constants.net == constants.BitcoinGoldRegtest: + new_target = self.bits_to_target(last.get('bits')) + elif height % difficulty_adjustment_interval() != 0: + if constants.net == constants.BitcoinGoldTestnet: + cur = self.get_header(height, headers) + + # Special testnet handling + if cur.get('timestamp') > last.get('timestamp') + constants.net.POW_TARGET_SPACING * 2: + new_target = constants.net.POW_LIMIT_LEGACY + else: + # Return the last non-special-min-difficulty-rules-block + prev_height = last_height - 1 + prev = self.get_header(prev_height, headers) + + while prev is not None and last.get('block_height') % difficulty_adjustment_interval() != 0 \ + and last.get('bits') == constants.net.POW_LIMIT: + last = prev + prev_height -= 1 + prev = self.get_header(prev_height, headers) + + new_target = self.bits_to_target(last.get('bits')) + else: + new_target = self.bits_to_target(last.get('bits')) + else: + first = self.read_header(height - difficulty_adjustment_interval()) + target = self.bits_to_target(last.get('bits')) + + actual_timespan = last.get('timestamp') - first.get('timestamp') + target_timespan = constants.net.POW_TARGET_TIMESPAN_LEGACY + actual_timespan = max(actual_timespan, target_timespan // 4) + actual_timespan = min(actual_timespan, target_timespan * 4) + + new_target = min(constants.net.POW_LIMIT_LEGACY, (target * actual_timespan) // target_timespan) + + return new_target + + def get_lwma_target(self, height, headers, weight, denominator): + cur = self.get_header(height, headers) + last_height = (height - 1) + last = self.get_header(last_height, headers) + + # Special testnet handling + if constants.net == constants.BitcoinGoldRegtest: + new_target = self.bits_to_target(last.get('bits')) + elif constants.net == constants.BitcoinGoldTestnet and cur.get('timestamp') > last.get('timestamp') + constants.net.POW_TARGET_SPACING * 2: + new_target = constants.net.POW_LIMIT + else: + total = 0 + t = 0 + j = 0 + + assert (height - constants.net.LWMA_AVERAGING_WINDOW) > 0 + + ts = 6 * constants.net.POW_TARGET_SPACING + + # Loop through N most recent blocks. "< height", not "<=". + # height-1 = most recently solved block + for i in range(height - constants.net.LWMA_AVERAGING_WINDOW, height): + cur = self.get_header(i, headers) + prev_height = (i - 1) + prev = self.get_header(prev_height, headers) + + solvetime = cur.get('timestamp') - prev.get('timestamp') + + if constants.net.LWMA_SOLVETIME_LIMITATION and solvetime > ts: + solvetime = ts + + j += 1 + t += solvetime * j + total += self.bits_to_target(cur.get('bits')) // (weight * constants.net.LWMA_AVERAGING_WINDOW * constants.net.LWMA_AVERAGING_WINDOW) + + # Keep t reasonable in case strange solvetimes occurred. + if t < constants.net.LWMA_AVERAGING_WINDOW * weight // denominator: + t = constants.net.LWMA_AVERAGING_WINDOW * weight // denominator + + new_target = t * total + + if new_target > constants.net.POW_LIMIT: + new_target = constants.net.POW_LIMIT + + return new_target + + def get_digishield_target(self, height, headers): + pow_limit = constants.net.POW_LIMIT + height -= 1 + last = self.get_header(height, headers) + + if last is None: + new_target = pow_limit + elif constants.net == constants.BitcoinGoldRegtest: + new_target = self.bits_to_target(last.get('bits')) + else: + first = last + total = 0 + i = 0 + + while i < constants.net.DIGI_AVERAGING_WINDOW and first is not None: + total += self.bits_to_target(first.get('bits')) + prev_height = height - i - 1 + first = self.get_header(prev_height, headers) + i += 1 + + # This should never happen else we have a serious problem + assert first is not None + + avg = total // constants.net.DIGI_AVERAGING_WINDOW + actual_timespan = self.get_mediantime_past(headers, last.get('block_height')) \ + - self.get_mediantime_past(headers, first.get('block_height')) + + if actual_timespan < min_actual_timespan(): + actual_timespan = min_actual_timespan() + + if actual_timespan > max_actual_timespan(): + actual_timespan = max_actual_timespan() + + avg = avg // averaging_window_timespan() + avg *= actual_timespan + + if avg > pow_limit: + avg = pow_limit + + new_target = int(avg) + + return new_target + + def get_mediantime_past(self, headers, start_height): + header = self.get_header(start_height, headers) + + times = [] + i = 0 + + while i < 11 and header is not None: + times.append(header.get('timestamp')) + prev_height = start_height - i - 1 + header = self.get_header(prev_height, headers) + i += 1 + + times.sort() + return times[(len(times) // 2)] + @classmethod def bits_to_target(cls, bits: int) -> int: - bitsN = (bits >> 24) & 0xff - if not (0x03 <= bitsN <= 0x1d): - raise Exception("First part of bits should be in [0x03, 0x1d]") - bitsBase = bits & 0xffffff - if not (0x8000 <= bitsBase <= 0x7fffff): - raise Exception("Second part of bits should be in [0x8000, 0x7fffff]") - return bitsBase << (8 * (bitsN-3)) + size = bits >> 24 + word = bits & 0x007fffff + + if size <= 3: + word >>= 8 * (3 - size) + ret = word + else: + ret = word + ret <<= 8 * (size - 3) + + return ret @classmethod def target_to_bits(cls, target: int) -> int: - c = ("%064x" % target)[2:] - while c[:2] == '00' and len(c) > 6: - c = c[2:] - bitsN, bitsBase = len(c) // 2, int.from_bytes(bfh(c[:6]), byteorder='big') - if bitsBase >= 0x800000: - bitsN += 1 - bitsBase >>= 8 - return bitsN << 24 | bitsBase + assert target >= 0 + nsize = (target.bit_length() + 7) // 8 + if nsize <= 3: + c = target << (8 * (3 - nsize)) + else: + c = target >> (8 * (nsize - 3)) + if c & 0x00800000: + c >>= 8 + nsize += 1 + assert (c & ~0x007fffff) == 0 + assert nsize < 256 + c |= nsize << 24 + return c def chainwork_of_header_at_height(self, height: int) -> int: - """work done by single header at given height""" - chunk_idx = height // 2016 - 1 - target = self.get_target(chunk_idx) - work = ((2 ** 256 - target - 1) // (target + 1)) + 1 - return work + pass - @with_lock def get_chainwork(self, height=None) -> int: - if height is None: - height = max(0, self.height()) - if constants.net.TESTNET: - # On testnet/regtest, difficulty works somewhat different. - # It's out of scope to properly implement that. - return height - last_retarget = height // 2016 * 2016 - 1 - cached_height = last_retarget - while _CHAINWORK_CACHE.get(self.get_hash(cached_height)) is None: - if cached_height <= -1: - break - cached_height -= 2016 - assert cached_height >= -1, cached_height - running_total = _CHAINWORK_CACHE[self.get_hash(cached_height)] - while cached_height < last_retarget: - cached_height += 2016 - work_in_single_header = self.chainwork_of_header_at_height(cached_height) - work_in_chunk = 2016 * work_in_single_header - running_total += work_in_chunk - _CHAINWORK_CACHE[self.get_hash(cached_height)] = running_total - cached_height += 2016 - work_in_single_header = self.chainwork_of_header_at_height(cached_height) - work_in_last_partial_chunk = (height % 2016 + 1) * work_in_single_header - return running_total + work_in_last_partial_chunk - - def can_connect(self, header: dict, check_height: bool=True) -> bool: + pass + + def can_connect(self, header: dict, check_height: bool=True): if header is None: return False height = header['block_height'] if check_height and self.height() != height - 1: + self.logger.error(f'cannot connect at height {height}, because chain height != height - 1') return False if height == 0: return hash_header(header) == constants.net.GENESIS @@ -606,39 +867,35 @@ def can_connect(self, header: dict, check_height: bool=True) -> bool: except: return False if prev_hash != header.get('prev_block_hash'): + self.logger.error(f'cannot connect at height {height}, because pre_block_hash check failed') return False + + if constants.net == constants.BitcoinGoldRegtest or constants.net == constants.BitcoinGoldTestnet: + return True + + # do not check targt of headers before equihash fork + if height < constants.net.EQUIHASH_FORK_HEIGHT: + return True + + target = self.get_target(height, {height: header}) try: - target = self.get_target(height // 2016 - 1) - except MissingHeader: - return False - try: - self.verify_header(header, prev_hash, target) + self.verify_header(header, prev_hash, target, None) except BaseException as e: + self.logger.error(f'cannot connect at height {height}, because verify header failed: {e}') return False return True - def connect_chunk(self, idx: int, hexdata: str) -> bool: - assert idx >= 0, idx + def connect_chunk(self, height: int, hexdata: str) -> bool: try: data = bfh(hexdata) - self.verify_chunk(idx, data) - self.save_chunk(idx, data) + headerlist = self.verify_chunk(height, data) + self.logger.info(f'validated chunk, start height: {height} - verifed header size: {len(headerlist)}') + self.save_chunk(height, headerlist) return True except BaseException as e: - self.logger.info(f'verify_chunk idx {idx} failed: {repr(e)}') + self.logger.info(f'verify_chunk from height {height} failed: {repr(e)}') return False - def get_checkpoints(self): - # for each chunk, store the hash of the last block and the target after the chunk - cp = [] - n = self.height() // 2016 - for index in range(n): - h = self.get_hash((index+1) * 2016 -1) - target = self.get_target(index) - cp.append((h, target)) - return cp - - def check_header(header: dict) -> Optional[Blockchain]: """Returns any Blockchain that contains header, or None.""" if type(header) is not dict: @@ -668,3 +925,4 @@ def get_chains_that_contain_header(height: int, header_hash: str) -> Sequence[Bl if chain.check_hash(height=height, header_hash=header_hash)] chains = sorted(chains, key=lambda x: x.get_chainwork(), reverse=True) return chains + diff --git a/electrum/checkpoints.json b/electrum/checkpoints.json index 14d64b9b364d..b531d17b50e6 100644 --- a/electrum/checkpoints.json +++ b/electrum/checkpoints.json @@ -2,1309 +2,953 @@ [ "00000000693067b0e6b440bc51450b9f3850561b07f6d3c021c54fbd6abb9763", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "00000000f037ad09d0b05ee66b8c1da83030abaf909d2b1bf519c3c7d2cd3fdf", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "000000006ce8b5f16fcedde13acbc9641baa1c67734f177d770a4069c06c9de8", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "00000000563298de120522b5ae17da21aaae02eee2d7fcb5be65d9224dbd601c", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "000000009b0a4b2833b4a0aa61171ee75b8eb301ac45a18713795a72e461a946", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "00000000fa8a7363e8f6fdc88ec55edf264c9c7b31268c26e497a4587c750584", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "000000008ac55b5cd76a5c176f2457f0e9df5ff1c719d939f1022712b1ba2092", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "000000007f0c796631f00f542c0b402d638d3518bc208f8c9e5d29d2f169c084", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "00000000ffb062296c9d4eb5f87bbf905d30669d26eab6bced341bd3f1dba5fd", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "0000000074c108842c3ec2252bba62db4050bf0dddfee3ddaa5f847076b8822f", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "0000000067dc2f84a73fbf5d3c70678ce4a1496ef3a62c557bc79cbdd1d49f22", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "00000000dbf06f47c0624262ecb197bccf6bdaaabc2d973708ac401ac8955acc", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "000000009260fe30ec89ef367122f429dcc59f61735760f2b2288f2e854f04ac", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "00000000f9f1a700898c4e0671af6efd441eaf339ba075a5c5c7b0949473c80b", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "000000005107662c86452e7365f32f8ffdc70d8d87aa6f78630a79f7d77fbfe6", 26959535291011309493156476344723991336010898738574164086137773096960 - ], - [ + ],[ "00000000984f962134a7291e3693075ae03e521f0ee33378ec30a334d860034b", - 22791060871177364286867400663010583169263383106957897897309909286912 - ], - [ + 26959535291011309493156476344723991336010898738574164086137773096960 + ],[ "000000005e36047e39452a7beaaa6721048ac408a3e75bb60a8b0008713653ce", - 20657664212610420653213483117824978239553266057163961604478437687296 - ], - [ + 22791060871177364286867400663010583169263383106957897897309909286912 + ],[ "00000000128d789579ffbec00203a371cbb39cee27df35d951fd66e62ed59258", - 20055820920770189543295303139304627292355830414308479769458683936768 - ], - [ + 20657664212610420653213483117824978239553266057163961604478437687296 + ],[ "000000008dde642fb80481bb5e1671cb04c6716de5b7f783aa3388456d5c8a85", - 14823939180767414932263578623363531361763221729526512593941781544960 - ], - [ + 20055820920770189543295303139304627292355830414308479769458683936768 + ],[ "000000008135b689ad1557d4e148a8b9e58e2c4a67240fc87962abb69710231a", - 10665477591887247494381404907447500979192021944764506987270680608768 - ], - [ + 14823939180767414932263578623363531361763221729526512593941781544960 + ],[ "00000000308496ef3e4f9fa542a772df637b4aaf1dcce404424611feacfc09e7", - 7129927859545590787920041835044506526699926406309469412482969763840 - ], - [ + 10665477591887247494381404907447500979192021944764506987270680608768 + ],[ "000000001a2e0c63d7d012003c9173acfd04ccd6372027718979228c461b5ed5", - 5949911473257063494842414979623989957440207170696926280907451531264 - ], - [ + 7129927859545590787920041835044506526699926406309469412482969763840 + ],[ "000000002e0c0ac26ccde91b51ab018576b3a126b413e9f6f787b36637f1b174", - 5905492491837656485645884063467495540781288435542782321354050895872 - ], - [ + 5949911473257063494842414979623989957440207170696926280907451531264 + ],[ "00000000103226f85fe2b68795f087dcec345e523363f18017e60b5c94175355", - 4430143390146946405787502162943966061454423600514874825749833973760 - ], - [ + 5905492491837656485645884063467495540781288435542782321354050895872 + ],[ "000000001ae6f66fd4de47f8d6f357e798943bbfc4f39ebf14b0975fab059173", - 3447600406241317909690675945127070282093452846402311540118831235072 - ], - [ + 4430143390146946405787502162943966061454423600514874825749833973760 + ],[ "000000000a3f22690162744d3bc0b674c92e661a25afb3d2ac8b39b27ac14373", - 2351604382534916182160036119666703740669209516522695514729880748032 - ], - [ + 3447600406241317909690675945127070282093452846402311540118831235072 + ],[ "0000000006dc436c3c515a97446af858c1203a501c85d26c4a30afa380aba4a1", - 2098151686442211199940455690614286210348997571531298297574806519808 - ], - [ + 2351604382534916182160036119666703740669209516522695514729880748032 + ],[ "000000000943fe1680ffcc498ce50790ff8e842a8af2c157664e4fbc1cb7cb46", - 2275790652544821279950241890112140030244814501479017131553197129728 - ], - [ + 2098151686442211199940455690614286210348997571531298297574806519808 + ],[ "000000000847b2144376c1fb057ea1d5a027d5a6004277ed4c72422e93df04e9", - 1622203955679450683159610732218403647246163922223729367236739072000 - ], - [ + 2275790652544821279950241890112140030244814501479017131553197129728 + ],[ "00000000094505954deb1d31382b86d0510fd280a34143400b1856a4d52b4c93", - 1551048739079662593758612650769536967206480773659027300489594142720 - ], - [ + 1622203955679450683159610732218403647246163922223729367236739072000 + ],[ "000000000109272cecb3f7e98ac12cf149fa8a1b2aaab248e1b006b0dc595a3a", - 1389323280429349294447518501872137680563441219958739463959193059328 - ], - [ + 1551048739079662593758612650769536967206480773659027300489594142720 + ],[ "0000000009e6aa0fe39b790625ffeb18a2d6ff5060a5bd14e699e83c54109977", - 1147152896345386682952518188670047452875537662186691235300769792000 - ], - [ + 1389323280429349294447518501872137680563441219958739463959193059328 + ],[ "0000000000d14af55c4eae0121184919baba2deb8bf89c3af6b8e4c4f35c8e4e", - 594007861936424273334637371358095438347537381057796937154824241152 - ], - [ + 1147152896345386682952518188670047452875537662186691235300769792000 + ],[ "0000000003dfbfa2b33707e691ab2ab7cda7503be2c2cce43d1b21cd1cc757fb", - 148501965484106068333659342839523859586884345264449234288706060288 - ], - [ + 594007861936424273334637371358095438347537381057796937154824241152 + ],[ "0000000000c169d181d66d242901f70d006f3e088c1ae9cacb88b94b8266e9c3", - 110393429764504113949181711819653188468070301266890302199533928448 - ], - [ + 148501965484106068333659342839523859586884345264449234288706060288 + ],[ "000000000009f7d1439d6a2fc1a456db8e843674275bf0133fc7b43b5f45b96e", - 76554528428498296726819074079132986384157750623812250673757552640 - ], - [ + 110393429764504113949181711819653188468070301266890302199533928448 + ],[ "000000000011b8a8fad7973548b50f6d4b2ba1690f7487c374e43248c576354f", - 52678642966898219212816601311127992435882858542187514726849708032 - ], - [ + 76554528428498296726819074079132986384157750623812250673757552640 + ],[ "000000000077e856b6cc475d9cf784119811214c9cac8d7b674ec24faa7c2c0c", - 43246870766561725070861386869077695524372774526710079316876591104 - ], - [ + 52678642966898219212816601311127992435882858542187514726849708032 + ],[ "00000000004cbb474f2cbf3a65f690efa09804512af3351ba3a0888c806c6625", - 37817516728945957090904676150631917288430706594442690521085247488 - ], - [ + 43246870766561725070861386869077695524372774526710079316876591104 + ],[ "0000000000235b1ec6656d8e91f3dde3b6ab9ad7e75b332e4da9355ce60d860e", - 29373101246077110899697012205905070265841442578602225419818106880 - ], - [ + 37817516728945957090904676150631917288430706594442690521085247488 + ],[ "00000000002a153a2c95a8e5493db93086b0e3fe590b636a5871ace57523ef93", - 20444488966645742314409346972440253478913291170842138088329707520 - ], - [ + 29373101246077110899697012205905070265841442578602225419818106880 + ],[ "00000000000e9550e084908cf91a4e8b74f9f1315d1bc4020709f9e7f261bb18", - 19563849255781403323327768731100757126732627316116500830377476096 - ], - [ + 20444488966645742314409346972440253478913291170842138088329707520 + ],[ "00000000002c2cfef3bb85b463d3fcd39b73a6d3d5ae11c1e2a8113e3794f28d", - 12545026348036226200394850922278603223904369245268262607334146048 - ], - [ + 19563849255781403323327768731100757126732627316116500830377476096 + ],[ "00000000000fa92b757ee29674aa97e98a49ba3ad340d2baa94155d71648dfe1", - 8719867261221084516486306056196045840260667577454435863762042880 - ], - [ + 12545026348036226200394850922278603223904369245268262607334146048 + ],[ "0000000000030571601dbc8e13d00d45004eee6ea8b6ab3cdfb38d2546fee21c", - 5942996718418989293499865695368015163438891473576991811912597504 - ], - [ + 8719867261221084516486306056196045840260667577454435863762042880 + ],[ "00000000000bb6adef42e63082b20fd2b1dc1b324c51973512a4c31f29a9986e", - 3926013280397599483741094494745234959951218212740030386090803200 - ], - [ + 5942996718418989293499865695368015163438891473576991811912597504 + ],[ "000000000000765094788a98dbb8adac30d248b7129b59b1441ee2b7ef9e332f", - 3337321571246095014985518819479127172783474909736415373333364736 - ], - [ + 3926013280397599483741094494745234959951218212740030386090803200 + ],[ "00000000000431a0aa9625f82975709f3c6f4f64d04c559512af051599872084", - 2200419182034594781720344474937177839165432393990533906392154112 - ], - [ + 3337321571246095014985518819479127172783474909736415373333364736 + ],[ "00000000000292b850b8f8578e6b4d03cbb4a78ada44afbb4d2f80a16490e8f9", - 1861311314983800126815643622927230076368334845814253369901973504 - ], - [ + 2200419182034594781720344474937177839165432393990533906392154112 + ],[ "0000000000025afe84e27423011af25f777e5a94545dbd00fd04bebe9050f7dd", - 1653206561150525499452195696179626311675293455763937233695932416 - ], - [ + 1861311314983800126815643622927230076368334845814253369901973504 + ],[ "0000000000000e389cccae2a40437be574fd806909e24136711e7f8bce671d65", - 1462200632444444190489436459820840230299714881944341127503020032 - ], - [ + 1653206561150525499452195696179626311675293455763937233695932416 + ],[ "0000000000030510bf6bc1649726cf2e6e4010c64a2c8fd3fde5dc92535ca40e", - 1224744150896501443874292381730317417444978877835711165914677248 - ], - [ + 1462200632444444190489436459820840230299714881944341127503020032 + ],[ "00000000000082648057f14fc835779c6ce46a407bafb2e5c2ac1d20d9f4e822", - 1036989760889350435547200084292752907272941324136347429599444992 - ], - [ + 1224744150896501443874292381730317417444978877835711165914677248 + ],[ "000000000000f38accd6b22959010471a6d9f159d43bf2a9d4c53c220201254e", - 739430030225080220618328322475016688484025266646974337550123008 - ], - [ + 1036989760889350435547200084292752907272941324136347429599444992 + ],[ "0000000000004ed7a73133678b5eb883cd8882bf14dfb26c104ae0c3f94cf4ee", - 484975157177710342494716926626447514974484083994735770500857856 - ], - [ + 739430030225080220618328322475016688484025266646974337550123008 + ],[ "00000000000037bb3ff4cf649a1757d4028ecc10f893529b4a2214792c981f96", - 353833947722011807976659613996792948209273674048993161457434624 - ], - [ + 484975157177710342494716926626447514974484083994735770500857856 + ],[ "0000000000008008f46559fe7f181e9dc0648f213472a1e576e8bf506b88f22f", - 390843739553851677760235428436025349398613161749553108945469440 - ], - [ + 353833947722011807976659613996792948209273674048993161457434624 + ],[ "000000000000691d0c2444db713bf6c088844cc95a37cdc55cc269bb0a31d8c8", - 327394795212563108599383268946242257264650552916910648089116672 - ], - [ + 390843739553851677760235428436025349398613161749553108945469440 + ],[ "00000000000071153b0afcc64a425f8442c29749610797119e732dd4b723f675", - 291935447509363748964474894494542149680088347011133317125767168 - ], - [ + 327394795212563108599383268946242257264650552916910648089116672 + ],[ "000000000000a384acb522e4e5935ad2bc31366ecf1f16f1f11023e967ef033d", - 245823858161213192073337185391658632187400443916100519594033152 - ], - [ + 291935447509363748964474894494542149680088347011133317125767168 + ],[ "0000000000002e532093d43e901292121fb7c6583caf2d13b666fe7e194b4a97", - 171262555713783851185422181139260521316022447660158187451973632 - ], - [ + 245823858161213192073337185391658632187400443916100519594033152 + ],[ "00000000000033e435c4bbddc7eb255146aa7f18e61a832983af3a9ee5dd144d", - 110438984653392107399822606842181601255647711092336854093004800 - ], - [ + 171262555713783851185422181139260521316022447660158187451973632 + ],[ "00000000000028ff4b0bd45f0e3e713f91fa1821d28a276a1a1f32f786662f13", - 61993465896324436412959469550829248888675813063783317791309824 - ], - [ + 110438984653392107399822606842181601255647711092336854093004800 + ],[ "0000000000001ef9c75318e116a607af4de68fb4f67c788677ee6779fb5fa0d5", - 47525089675259291211422247200069659468817014361857087365971968 - ], - [ + 61993465896324436412959469550829248888675813063783317791309824 + ],[ "0000000000000e6e98694ccb8247aad63aaa1e2bec5a7be14329407e4cea6223", - 30742228348699538311994447367921718297595975288392383715082240 - ], - [ + 47525089675259291211422247200069659468817014361857087365971968 + ],[ "000000000000000a2153574b2523a6d1844c3cb82d085e2575846dd8c5d4ebb4", - 19547336162709893274575855467812492508787617050928192350584832 - ], - [ + 30742228348699538311994447367921718297595975288392383715082240 + ],[ "00000000000002a92c1b1ffb2a8388979cf30798e312335ae2a1b922927ee83d", - 17248274092338559882155796390905381469049315669915374897332224 - ], - [ + 19547336162709893274575855467812492508787617050928192350584832 + ],[ "00000000000004d54b1422ce733922e7672a4e2ecc86dcf96c0de06565cddaa6", - 15943936487596784557029840069157210316687734428242467413295104 - ], - [ + 17248274092338559882155796390905381469049315669915374897332224 + ],[ "00000000000009dd91ae96cbbf67af42340b0bc715b3606aa725f630b470262d", - 14273467308195657992975774342458504496649432985410431166185472 - ], - [ + 15943936487596784557029840069157210316687734428242467413295104 + ],[ "00000000000007d33d78522fa95bdcd4a25072aeac844cbe9b6bc5d0cc885d0a", - 14930233597189143322113827544414041000381079823613435714732032 - ], - [ + 14273467308195657992975774342458504496649432985410431166185472 + ],[ "00000000000003dd57f5dd1228f68390b586700063225d26bac972bd120546d2", - 15164766714763258952996988973449124317842091658872414191747072 - ], - [ + 14930233597189143322113827544414041000381079823613435714732032 + ],[ "000000000000076bdeca878b47c392f51fbda543b1e69612cf7d305deb537604", - 15357836632983707094928406965317628870031114888441593128288256 - ], - [ + 15164766714763258952996988973449124317842091658872414191747072 + ],[ "00000000000008eb1bb7e18d9dfe62210d761cbf114d59ca08e4f638b8563e30", - 15958672964717750944291813934170287689797412223641384931819520 - ], - [ + 15357836632983707094928406965317628870031114888441593128288256 + ],[ "00000000000001b0d8d885e4d77d7c51e8f1fdaba68f229ac04d191915845f09", - 18362361570655080300849714079315004638119732162003921272832000 - ], - [ + 15958672964717750944291813934170287689797412223641384931819520 + ],[ "000000000000081baa3a716d5f9ab072c9fc3b798900234c9be23ab02a287c30", - 22401652017447755518156310839596703571934659990690572544245760 - ], - [ + 18362361570655080300849714079315004638119732162003921272832000 + ],[ "00000000000005b88d0224b9b0d4b65d3de9a61d93609bb91c9297440f1c4657", - 22607619418140130980719672680045705126213018528712048676700160 - ], - [ + 22401652017447755518156310839596703571934659990690572544245760 + ],[ "000000000000027d6a6870403fa43a650b7d9a6e61243f375a79ea935ad9ef1f", - 24717289559589094364468373797949472355802981654048927838633984 - ], - [ + 22607619418140130980719672680045705126213018528712048676700160 + ],[ "0000000000000810a3490b86e4f302f6557f9621c5c8620c2b09ec8f0cf72794", - 23340814324747679919001773364939281849550099124416593832968192 - ], - [ + 24717289559589094364468373797949472355802981654048927838633984 + ],[ "000000000000073833bca8d0ea909fde717e251576b7b3ccaaa58ad5d39eed60", - 23242391331131109072962566885467580392541369223033474166816768 - ], - [ + 23340814324747679919001773364939281849550099124416593832968192 + ],[ "000000000000031b7fd2ed1f28ff74e969aa891297706c38bd2e1d3bc48183c4", - 21554562042243053719921017803645315870071034703425342074257408 - ], - [ + 23242391331131109072962566885467580392541369223033474166816768 + ],[ "0000000000000b0738bcba382983811d40b531f2e68cd57126092755f1be4ba6", - 20615546854515052444405957679617344022137222968655050411343872 - ], - [ + 21554562042243053719921017803645315870071034703425342074257408 + ],[ "000000000000000664cbfd5e3fa497c07614c33a0934b83e01fbe980634a9aa4", - 19540887421473929614259883543522244007742949396702043752628224 - ], - [ + 20615546854515052444405957679617344022137222968655050411343872 + ],[ "000000000000021eb520df39289a70e40c59822a8c47924dc4940e7d0c1455c4", - 19588382523276445241758125434587686389961661359576757951266816 - ], - [ + 19540887421473929614259883543522244007742949396702043752628224 + ],[ "0000000000000275e0c41b11bc250fe887c5e60c8ebaaa449f5c28c67133d496", - 18009299117968233362105684657812007807160912568078774269116416 - ], - [ + 19588382523276445241758125434587686389961661359576757951266816 + ],[ "000000000000097fb0fdbeee0cee7e8f4e1a4ef8fad49f3d549624b0d47abed0", - 17993483763986497389087426516491816616385967180337839494660096 - ], - [ + 18009299117968233362105684657812007807160912568078774269116416 + ],[ "000000000000053f199ae19d34365277e534f978ea2f6c69cd4757a4fc099af5", - 16574638092431222848464934504874974361824393751455373256032256 - ], - [ + 17993483763986497389087426516491816616385967180337839494660096 + ],[ "0000000000000217b2e7b4f61682d24b9357d62ad29f27ed45ea2a32dc1f32f6", - 17085559845791583266730740536950670241169412424878408752693248 - ], - [ + 16574638092431222848464934504874974361824393751455373256032256 + ],[ "000000000000039c1d77acd4702393f48ca61983c64fc0209ade141c694b2359", - 17870687961287995446644888885900316642120964851955511819501568 - ], - [ + 17085559845791583266730740536950670241169412424878408752693248 + ],[ "0000000000000ae53f0c78330f6c2fbece2752909bc3742823e4fab29c5fd2b0", - 15554707140145502641228553657813466188995512591033787398225920 - ], - [ + 17870687961287995446644888885900316642120964851955511819501568 + ],[ "00000000000004b4d72b8631a85ec7d226dc696f1913ba1bf735b7c8dec207b8", - 16944226977030767532657500340718760127019357828074148225613824 - ], - [ + 15554707140145502641228553657813466188995512591033787398225920 + ],[ "00000000000006e06735bffb7d2f215dcadd8311fc33f4a46661fdca3dc0560e", - 17028747171100603034973679895960153979114298528140818252824576 - ], - [ + 16944226977030767532657500340718760127019357828074148225613824 + ],[ "000000000000055fc0110d4a38ffb338eabc30c8b0aef355d4643d21b5b6a860", - 15614535766060906942258863525753414259523988166363835227176960 - ], - [ + 17028747171100603034973679895960153979114298528140818252824576 + ],[ "000000000000081b69cb4de006c14084c4861f0e4a140c37200117a738733fe8", - 15392654931672180089790308609774483894682932641297604569726976 - ], - [ + 15614535766060906942258863525753414259523988166363835227176960 + ],[ "00000000000009920770f2d40b5b6a8aba33d969b855c91b0f56e3db9c27e41a", - 14444739009842829731785903206212823051010663269705670545375232 - ], - [ + 15392654931672180089790308609774483894682932641297604569726976 + ],[ "0000000000000791dd1cb7a684a54c72ccde51f459fff0fc3e6e051641b1e941", - 13237058963854547748734324548161076199478283141947127217782784 - ], - [ + 14444739009842829731785903206212823051010663269705670545375232 + ],[ "000000000000019da474a1a598b5cf28534b7fd9b214eed0f36c67c203a9b449", - 12305424274651356593961118223415860240572779254789271782948864 - ], - [ + 13237058963854547748734324548161076199478283141947127217782784 + ],[ "000000000000074333e888bac730f9772b65e4cc9d07edb122c6e3c6606bc8ab", - 11046080738989403765716562970384822165842244193743674858799104 - ], - [ + 12305424274651356593961118223415860240572779254789271782948864 + ],[ "000000000000067080669115c445f378f3dec19787558d0e03263b9dec5d7720", - 10007073282210984973971337419529346944295676968729147521105920 - ], - [ + 11046080738989403765716562970384822165842244193743674858799104 + ],[ "0000000000000304760bf583f4ac241c5ffe77312fa213634eba252c720530f1", - 9412783771427520201810837309176674245361798887059324066070528 - ], - [ + 10007073282210984973971337419529346944295676968729147521105920 + ],[ "000000000000041fb61665c8a31b8b5c3ae8fe81903ea81530c979d5094e6f9d", - 8825801199382903987726989797449454220615414953524072026210304 - ], - [ + 9412783771427520201810837309176674245361798887059324066070528 + ],[ "000000000000022fc7f2a5c87b2bab742d71c4eb662d572df33f18193d6abf0e", - 8774971387283464186072960143252932765613148614319486309236736 - ], - [ + 8825801199382903987726989797449454220615414953524072026210304 + ],[ "000000000000013c6d43ba38bc5f24e699515b9d78602694112fefdc64606640", - 8158785580212107593904235970576336449063725988071903546310656 - ], - [ + 8774971387283464186072960143252932765613148614319486309236736 + ],[ "00000000000001665176b9a810fddf27cca60dfcfd80bf113289fcc8ffed0284", - 8002789794116287035234223109988652176644807295346590313611264 - ], - [ + 8158785580212107593904235970576336449063725988071903546310656 + ],[ "00000000000002dc6ef80f56a00f1091471d942ce9bfb656ebdab4ea0b77eb0b", - 7839560629067579481152758851432818444879208153964570478641152 - ], - [ + 8002789794116287035234223109988652176644807295346590313611264 + ],[ "00000000000002a1fa5546ec48ca88b9e5710e2c6d895bb3675004fdacd6ab13", - 7999430563890709006856701613305138698914315019190763857641472 - ], - [ + 7839560629067579481152758851432818444879208153964570478641152 + ],[ "00000000000000f517517c11e649b98feca7da84ae44fb643de5a86798fe3c31", - 9047927233058169382412882048952728634925849476849852060008448 - ], - [ + 7999430563890709006856701613305138698914315019190763857641472 + ],[ "0000000000000299cab92a923348acf9251f656bcbacdb641fd0a66d895a6e8f", - 8296391419817537486273948666838217011279219811331013552898048 - ], - [ + 9047927233058169382412882048952728634925849476849852060008448 + ],[ "000000000000027508b977f72c3a0f06f1f36e311ad079536630661880934501", - 9081029136740872581753422344739175313292014241889017867010048 - ], - [ + 8296391419817537486273948666838217011279219811331013552898048 + ],[ "00000000000001925959229452cc6fbfef0104ebed7ccd6f584f2439c5dd1f1b", - 8230751570811169734692743946971314968326461977249645504495616 - ], - [ + 9081029136740872581753422344739175313292014241889017867010048 + ],[ "00000000000003b34ca89509da5f558af468c194afaa8d458bbeb07c50cc7c74", - 7384127474250891166670391848516180960454656786677558849568768 - ], - [ + 8230751570811169734692743946971314968326461977249645504495616 + ],[ "0000000000000076559e314ab0c86cc552e34fd79488415d3d17f6ea3c01adb3", - 6172230000534146257480611019445716458048957888854766248787968 - ], - [ + 7384127474250891166670391848516180960454656786677558849568768 + ],[ "000000000000003a58043252cdc30ed2f37fb17e6ef1658324b1478f16c1463b", - 5561365017980676031428107027647386014985059524839404952616960 - ], - [ + 6172230000534146257480611019445716458048957888854766248787968 + ],[ "000000000000011babf767e60240658195b693711c217d7da0d9215ccab45333", - 4026319404534786334009451711043898716884778820756489262596096 - ], - [ + 5561365017980676031428107027647386014985059524839404952616960 + ],[ "000000000000027579d28fb480ccad8e2516d1219d4c1919e3fd4fc0c882955d", - 3513558656525386849113615662535622466519417660386833443323904 - ], - [ + 4026319404534786334009451711043898716884778820756489262596096 + ],[ "0000000000000074546fe07f80ba15fc81897ec56a5535de727df9fda9dab500", - 3004083578955603829930099910053556479043735076695139267117056 - ], - [ + 3513558656525386849113615662535622466519417660386833443323904 + ],[ "00000000000000b6c55833b80c07894f4c4d3bb686e5ddbc1b1d162e22752ca3", - 2675541054922611112919804040984964595022815308724929898217472 - ], - [ + 3004083578955603829930099910053556479043735076695139267117056 + ],[ "00000000000001326f2f970753122e35bfdf3358d046ddf5ea22e57f5d82b00d", - 2409843108029446766213067266805752590003732794677225687351296 - ], - [ + 2675541054922611112919804040984964595022815308724929898217472 + ],[ "00000000000000641084745613912464ff73c974bafd0bf6dd306295f019d306", - 2218268905456883731807407021635746739577921454491297946533888 - ], - [ + 2409843108029446766213067266805752590003732794677225687351296 + ],[ "000000000000011ae105ddb1a5bbac6931a6578d95c201525f3a945276a64559", - 1727551573307299192250197436766000536509732237655131060961280 - ], - [ + 2218268905456883731807407021635746739577921454491297946533888 + ],[ "00000000000000d9b66fee19af89eaaf3f3933d1acd2617924c107f0abbe0a41", - 1394031503757574068227953656553224448260418805016069352194048 - ], - [ + 1727551573307299192250197436766000536509732237655131060961280 + ],[ "0000000000000011956d42670c2f75eeb344ac0657a806775998e2c58fa4b157", - 1263610003247723462826224891154624535497729630761756072607744 - ], - [ + 1394031503757574068227953656553224448260418805016069352194048 + ],[ "00000000000000959b1ea990368fd16d494e68ee13bd7245ddd9cdfba3330100", - 1030450001678223668360152541055867895065240185756254103142400 - ], - [ + 1263610003247723462826224891154624535497729630761756072607744 + ],[ "0000000000000091f86b1e423e24fe358c72db181cfcc2738c85f2f51871a960", - 862513010327976103705811440432628413487564277790886242287616 - ], - [ + 1030450001678223668360152541055867895065240185756254103142400 + ],[ "0000000000000055e146e473b49fe656a1f2f4b8c33e72b80acc18f84d9fcc26", - 720982641204331278205950312227594303241470815982254303477760 - ], - [ + 862513010327976103705811440432628413487564277790886242287616 + ],[ "000000000000004f6a191a3261274735292bc30a1f79f23a143e4ee7dd2f64c1", - 530591525189316709998942710962548491505413142398652303540224 - ], - [ + 720982641204331278205950312227594303241470815982254303477760 + ],[ "000000000000005327c8e714272803c60277333362e74ec88b9ffab5410c2358", - 410030579894253754102159787320079652501746816512444002729984 - ], - [ + 530591525189316709998942710962548491505413142398652303540224 + ],[ "0000000000000002e2a62b8705564c38d6a746fc8e971a450a69989152b5ee97", - 310118479516817784682897231521434079438159381558537557639168 - ], - [ + 410030579894253754102159787320079652501746816512444002729984 + ],[ "00000000000000202bf3ff30109538bfd9b5075c6438ab5ef64ebe2cf9b61404", - 239366800071949252578530950352093786414793290792735831228416 - ], - [ + 310118479516817784682897231521434079438159381558537557639168 + ],[ "000000000000001c997105893f5991cb45765ff856b6e503f8466cb22cdd330a", - 181156297885756721946540202079438048595571151633323613224960 - ], - [ + 239366800071949252578530950352093786414793290792735831228416 + ],[ "0000000000000010c13ce182a3d8fc6748b75640447eb360d7739a5fe984ffc1", - 142431093377788751676361246670241704468765375727695350988800 - ], - [ + 181156297885756721946540202079438048595571151633323613224960 + ],[ "000000000000000bbb49db68b79ecc8393376d78272d237bb612288af64c1de8", - 100696259189502783924473792493100546893980348528488767029248 - ], - [ + 142431093377788751676361246670241704468765375727695350988800 + ],[ "0000000000000001bbfd0973c367d30eef2416d9e94bdddea53bccf541a4858f", - 68962778243821519216393853205209897734463141354237780295680 - ], - [ + 100696259189502783924473792493100546893980348528488767029248 + ],[ "0000000000000004ee5b6ace996ab746f1e6dd952cdbc74c0b4f8b9ac51c7335", - 52765641310467331636297188681879886184148735229489015947264 - ], - [ + 68962778243821519216393853205209897734463141354237780295680 + ],[ "0000000000000002f2f23b515085d0c9f37a2824304ccb7ca1546a48548d0dac", - 44233472386696495417387091608220539804351405166731810832384 - ], - [ + 52765641310467331636297188681879886184148735229489015947264 + ],[ "00000000000000045590c3fdeca1753d148a87614a70fa0897a17f90bb321654", - 38110290672195532365762668664552282566878756832852091863040 - ], - [ + 44233472386696495417387091608220539804351405166731810832384 + ],[ "0000000000000002b704edc0bf1435fe2116040b547adb1bc2d196eb81779834", - 29679649578007061283718812081441644170496168236939550392320 - ], - [ + 38110290672195532365762668664552282566878756832852091863040 + ],[ "00000000000000038cc59dc6dd68ae0fbe2ded8a3de65dbd9a2f9a36d26772df", - 22829202948393929850749706076701368331072452018388575715328 - ], - [ + 29679649578007061283718812081441644170496168236939550392320 + ],[ "0000000000000000a979bc50075e7cdf0da5274f7314910b2d798b1aeaf6543f", - 19005913916847449503306572434028937600915626422125897711616 - ], - [ + 22829202948393929850749706076701368331072452018388575715328 + ],[ "0000000000000001dd8e548c8cf5b77cde6e5631cd542e39f42c41952e5e7085", - 15065005852539512185984435657022720640916062598235628240896 - ], - [ + 19005913916847449503306572434028937600915626422125897711616 + ],[ "0000000000000002513542a461de351a5a94f96b4bcd3e324a48d2d71b403fe0", - 12288698618318346282960995223961541766142764336009759948800 - ], - [ + 15065005852539512185984435657022720640916062598235628240896 + ],[ "000000000000000150cc07163e78d599a7e56c0d1040641bffb382705ac17df0", - 10284386012808371892335572105827331142617405906583881252864 - ], - [ + 12288698618318346282960995223961541766142764336009759948800 + ],[ "00000000000000009051d83d276dad5c547612f67c2907acf6a143039bddb1bb", - 8614444778121073626993210829679478604092861119379437256704 - ], - [ + 10284386012808371892335572105827331142617405906583881252864 + ],[ "00000000000000000b83d3947d2790ab0bcbbb61eba1eb8d8f0f0eb3e9d461e0", - 7065379129219572345353864175298106702426244380437224882176 - ], - [ + 8614444778121073626993210829679478604092861119379437256704 + ],[ "00000000000000005a4fbbaeffee6d52fa329dd8c559f90c9b30264c46ad33fd", - 6343094824615218102798845742064326605321937397913065881600 - ], - [ + 7065379129219572345353864175298106702426244380437224882176 + ],[ "00000000000000006b6834bae83e895a78c5026a8c8141388040d90506cf3148", - 5384518863803604621895699676581808210968416076987222720512 - ], - [ + 6343094824615218102798845742064326605321937397913065881600 + ],[ "0000000000000000bf3c066c9acdb008e7fff3672f1391b35c8877b76b9e295e", - 4405349994161605759458363322921957536960017949107037405184 - ], - [ + 5384518863803604621895699676581808210968416076987222720512 + ],[ "00000000000000006bcf448b771c8f4db4e2ca653474e3b29504ec08422b3fba", - 3863038134637689339706803268689141874606936642244315185152 - ], - [ + 4405349994161605759458363322921957536960017949107037405184 + ],[ "000000000000000098686ab04cc22fec77e4fa2d76d5a3cc0eb8cbf4ed800cdc", - 3369574570478873127315415525946742317481702644901195284480 - ], - [ + 3863038134637689339706803268689141874606936642244315185152 + ],[ "000000000000000036cc637d80982595b1fa30f877efe8904965e6fd70aeae1a", - 3045099693687311168583241534842989903432036285033490677760 - ], - [ + 3369574570478873127315415525946742317481702644901195284480 + ],[ "00000000000000000ee9b585e0a707347d7c80f3a905f48fa32d448917335366", - 2578448441038522347123624842639328775756428679710156783616 - ], - [ + 3045099693687311168583241534842989903432036285033490677760 + ],[ "00000000000000000401800189014bad6a3ca1af029e19b362d6ef3c5425a8dc", - 2293149852232440455888971398133692017055281498246925516800 - ], - [ + 2578448441038522347123624842639328775756428679710156783616 + ],[ "00000000000000001b44d4645ac00773be676f3de8a8bff1a5fdd1fb04d2b3b2", - 2002553378451099534811946324256852041059202347552707969024 - ], - [ + 2293149852232440455888971398133692017055281498246925516800 + ],[ "00000000000000003ff2a53152ee98910d7383c0177459ad258c4b2d2c4d4610", - 1602972750958019380418919163663316163747908621623690788864 - ], - [ + 2002553378451099534811946324256852041059202347552707969024 + ],[ "00000000000000001bb242c9463b511b9e6a99a6d48bd783acb070ca27861c2b", - 1555090122338762644529309082074529684497336694348804259840 - ], - [ + 1602972750958019380418919163663316163747908621623690788864 + ],[ "000000000000000019d43247356b848a7ef8b1c786d8c833b76e382608cb59e9", - 1438882362326364789097016808333128944459434864174551793664 - ], - [ + 1555090122338762644529309082074529684497336694348804259840 + ],[ "00000000000000003711b624fbde8c77d4c7e25334cfa8bc176b7248ca67b24b", - 1366448002777625511026173062127977611952455397852592472064 - ], - [ + 1438882362326364789097016808333128944459434864174551793664 + ],[ "0000000000000000092c1f996e0b6d07fd0e73dfe6409a5c2adc1206e997c3a2", - 1130631509982695295834811811892052032638591596239280668672 - ], - [ + 1366448002777625511026173062127977611952455397852592472064 + ],[ "000000000000000020ce180d66df9d3c28aee9fcec7896071ec67091a9753283", - 982897592923314645728937741958820396011314229953349812224 - ], - [ + 1130631509982695295834811811892052032638591596239280668672 + ],[ "000000000000000018d37d53ae02e13634eefb8d9246253e99c1bdf65ac293ea", - 903780639904017349860452775965599807564731663176966340608 - ], - [ + 982897592923314645728937741958820396011314229953349812224 + ],[ "00000000000000001607d1a21507dea1c0e5f398daf94d35fb7e0a3238f96a0f", - 777796486219054632155478957346406689849105796561635377152 - ], - [ + 903780639904017349860452775965599807564731663176966340608 + ],[ "00000000000000001acae244523061f650ddab9c3271d13c0cd86071ae6e8a5f", - 770217816864616291160628694313702426464491250746461782016 - ], - [ + 777796486219054632155478957346406689849105796561635377152 + ],[ "0000000000000000104430189dba1219b0e3dd90824e8c2271609aca5b71250f", - 749174812297985386116525053725808178560617045558724395008 - ], - [ + 770217816864616291160628694313702426464491250746461782016 + ],[ "00000000000000001aa260733b6d8f8faa2092af35e55973278bb17f8eaeca6b", - 680733321990486529407107157001552378184394215934016880640 - ], - [ + 749174812297985386116525053725808178560617045558724395008 + ],[ "000000000000000009925ad5866a9cb3a1d83d9399137bccc7b5470b38b1db2b", - 668970595596618687654683311252875969389523722950049529856 - ], - [ + 680733321990486529407107157001552378184394215934016880640 + ],[ "00000000000000001133acacb92e43e24af63a487923361a4a98c87a5550dffe", - 673862533877092685902494685124943911912916060357898797056 - ], - [ + 668970595596618687654683311252875969389523722950049529856 + ],[ "000000000000000018c66b4a76ca69204e24ee069da9368c7a9883adb36c24af", - 683252062220249508849116041812776958610205092831121375232 - ], - [ + 673862533877092685902494685124943911912916060357898797056 + ],[ "000000000000000010b13aed220b96c35ccd5f07125b51308db976eefcd718f9", - 663358803453687177159928221638562617962497973903752691712 - ], - [ + 683252062220249508849116041812776958610205092831121375232 + ],[ "0000000000000000031b14ece1cfda0e23774e473cd2676834f73155e4f46a2b", - 613111582105360026820898034285227810088764320248934432768 - ], - [ + 663358803453687177159928221638562617962497973903752691712 + ],[ "000000000000000010bfa427c8d305d861ab5ee4776d87d6d911f5fb3045c754", - 653202279051259096361833571150520065936493508031976308736 - ], - [ + 613111582105360026820898034285227810088764320248934432768 + ],[ "000000000000000005d1e9e192a43a19e2fbd933ffb27df2623187ad5ce10adc", - 606439838822957553646521558653356639834299145437709336576 - ], - [ + 653202279051259096361833571150520065936493508031976308736 + ],[ "00000000000000000f9e30784bd647e91f6923263a674c9c5c18084fe79a41f8", - 577485176368838834686684127480472050622611986764206702592 - ], - [ + 606439838822957553646521558653356639834299145437709336576 + ],[ "00000000000000000036d3e1c36e4b959a3e4ad6376ce9ae65961e60350c86e8", - 568436119447114618883887501211268589217582000336195813376 - ], - [ + 577485176368838834686684127480472050622611986764206702592 + ],[ "00000000000000000b3ec9df7aebc319bb12491ba651337f9b3541e78446eca8", - 577075114085443079269506210404847846798089003835028668416 - ], - [ + 568436119447114618883887501211268589217582000336195813376 + ],[ "000000000000000012d24ce222e3c81d4c148f2bce88f752c0dba184c3bc6844", - 545227566982404669720599751103563308707559049533419683840 - ], - [ + 577075114085443079269506210404847846798089003835028668416 + ],[ "000000000000000000c4ccbdd98c267bd16bda12b63b648c47af3ac51c1cc574", - 566251116039239425785056264238964437451875594947144974336 - ], - [ + 545227566982404669720599751103563308707559049533419683840 + ],[ "00000000000000000056bfec1dca8e82710f411af64b1d3b04a2d2364a81993f", - 565860883410058976058672534759150528155363303710710038528 - ], - [ + 566251116039239425785056264238964437451875594947144974336 + ],[ "00000000000000001275d1cadce690546f74f77f6d4a6190e2137a8a819946f6", - 552364745922238091561919045022000637317595931246011088896 - ], - [ + 565860883410058976058672534759150528155363303710710038528 + ],[ "000000000000000003816ae80c6413b84cbee2f639ba497ab5872ec9711eb256", - 566500670366816952120145379831520408210047884740723212288 - ], - [ + 552364745922238091561919045022000637317595931246011088896 + ],[ "00000000000000000d92953224570f521b09553194da1ca3c4b31a09a238f4f6", - 542528489142608155505707877213460200687386787807972294656 - ], - [ + 566500670366816952120145379831520408210047884740723212288 + ],[ "000000000000000006721943f23cfacf20c17c2ad6ea4e902af36b01f92e3c06", - 545717322027080804612101478705745866012577831152301113344 - ], - [ + 542528489142608155505707877213460200687386787807972294656 + ],[ "0000000000000000031d9af2fe38cc02410361fb213181fdb667c74e210d54c4", + 545717322027080804612101478705745866012577831152301113344 + ],[ + "0000000000000000142e8a13ef6994961655c8e86aece3f0abebd2ee05473e75", 527827980769521817826567786138322798799309668948178370560 - ], - [ - "0000000000000000142e8a13ef6994961655c8e86aece3f0abebd2ee05473e75", - 515692606534173891771672037645739723025219384908133171200 - ], - [ + ],[ "00000000000000000c7a8db37a746d6637ef6a6eab28735608fd715ee2f394e7", - 511567664312971151375333957573881285830542480898837708800 - ], - [ + 515692606534173891771672037645739723025219384908133171200 + ],[ "000000000000000007854877c66c71a49af40d20f2d6f817becfe4d66d5e5a81", - 496889230460615059653870414954457230681194245244172894208 - ], - [ + 511567664312971151375333957573881285830542480898837708800 + ],[ "000000000000000005ce1d2d10aeb9def4d38233e859d98a4a168ea3fa36687a", - 473325989086544548323169648982069700877697035484407005184 - ], - [ + 496889230460615059653870414954457230681194245244172894208 + ],[ "000000000000000007c71decfe74855ad99dc2aa4a2e713165db5a8d6da5f32a", - 454358737757395076722955683517864397151243915416267915264 - ], - [ + 473325989086544548323169648982069700877697035484407005184 + ],[ "000000000000000008ce4f34161be6760569877c685e37ebebce3546ea42a767", - 443316987659242217350916733941384923365365929826941140992 - ], - [ + 454358737757395076722955683517864397151243915416267915264 + ],[ "0000000000000000086233f4843682eb47bacb58930a5577fbfd5c9ebd57ddf9", - 442802913227320896234856097023585967110900073490544590848 - ], - [ + 443316987659242217350916733941384923365365929826941140992 + ],[ "000000000000000010a904eee4fc763c6b88d378884f368fd652f63c1af71580", - 433057199397126884276233483897801969646324654385408245760 - ], - [ + 442802913227320896234856097023585967110900073490544590848 + ],[ "00000000000000000c114754749d622d4fa2f78c84d7147c345b2b99a8e83d2e", - 409419129139225030716120689261979366152221060879441985536 - ], - [ + 433057199397126884276233483897801969646324654385408245760 + ],[ "000000000000000000a5039e32cc9a89aeffbde1391e8bc9ae9724127904f01d", - 370716507988397359530778284103407727265240291588416995328 - ], - [ + 409419129139225030716120689261979366152221060879441985536 + ],[ "000000000000000003b0b73d9b3259c318cca48a6335b5d64545583f7f3773fa", - 340818253309165415058055171484606858815006633875327680512 - ], - [ + 370716507988397359530778284103407727265240291588416995328 + ],[ "00000000000000000198bcc5bd65fd0ccd1c7e3b49e0170ea80296cbfee05042", - 288495652867775987986282369150900282132304927019642126336 - ], - [ + 340818253309165415058055171484606858815006633875327680512 + ],[ "00000000000000000a60f379d3dc1413491f360809a97cbb02c81442c613dce7", - 259524902203633530447121351815377152077137395840706412544 - ], - [ + 288495652867775987986282369150900282132304927019642126336 + ],[ "0000000000000000038973a5f8ba8cdc7e371dcc8f4b24337ef695f24b962907", - 237834253647442358407456603145452341381064939329604812800 - ], - [ + 259524902203633530447121351815377152077137395840706412544 + ],[ "000000000000000004b8ec471974913d052a3af7dc2a8c6f01c2ac2f3d1f7b19", - 224600391397450328424792273873642383828872941895338164224 - ], - [ + 237834253647442358407456603145452341381064939329604812800 + ],[ "0000000000000000075d572eef1c4210adc7abf4e40986d7f0a80003853bfec4", - 187067719845325692996306936867878122094522982476155977728 - ], - [ + 224600391397450328424792273873642383828872941895338164224 + ],[ "0000000000000000074f9edbfc07648dc74392ba8248f0983ffea63431b3bc20", - 164898540577033087399552264895286015147022701908103004160 - ], - [ + 187067719845325692996306936867878122094522982476155977728 + ],[ "000000000000000003c4a4d9c62b3a7f4893afe14eef8a6a377229d23ad4b1ea", - 170169861298531990750482624090969781281789404909188153344 - ], - [ + 164898540577033087399552264895286015147022701908103004160 + ],[ "00000000000000000404b6939e6c35a5448386e5d58f318c82ce2fefb7d73e47", - 162900609378736249874251099581569547607832255884553093120 - ], - [ + 170169861298531990750482624090969781281789404909188153344 + ],[ "0000000000000000034656c96781091b5fbc799c881ea85b41cba0b88128eff7", - 161578008857017275969393492955354620126364423170461532160 - ], - [ + 162900609378736249874251099581569547607832255884553093120 + ],[ "0000000000000000045645e2acd740a88d2b3a09369e9f0f80d5376e4b6c5189", - 150883090635422687830679296233896712896447026244773478400 - ], - [ + 161578008857017275969393492955354620126364423170461532160 + ],[ "00000000000000000381e6a138308c6547d6fe3eb3437250ffefdebbf71eefd1", - 150899178845446426410002882396535253739927398750206558208 - ], - [ + 150883090635422687830679296233896712896447026244773478400 + ],[ "0000000000000000012100ddbb2102e65fb1ebbf104ead754a4110abffc4b8bc", - 138784382553152119468195441786396823230753870240366460928 - ], - [ + 150899178845446426410002882396535253739927398750206558208 + ],[ "0000000000000000046f56e59b9b1293b5e7c1587aa6d29c4f3f79b98cf22ee6", - 135262935280049154152065372885142255350817451144176992256 - ], - [ + 138784382553152119468195441786396823230753870240366460928 + ],[ "000000000000000001bd1c291e91f4476f93454d4542d2ed7e44fc86902c93bb", - 137505556928474480767543871928291413858290772017802117120 - ], - [ + 135262935280049154152065372885142255350817451144176992256 + ],[ "000000000000000001c37a483375ff6fd6ed7c5b79d80167b027a8fdb0721dcd", - 128713911367130082233924624261304605948946745676720504832 - ], - [ + 137505556928474480767543871928291413858290772017802117120 + ],[ "0000000000000000051804b4c2da5298c4573386bf1d4242bf0e26a49ec32e42", - 126333978716874242627475052620752087219210710628817698816 - ], - [ + 128713911367130082233924624261304605948946745676720504832 + ],[ "0000000000000000034bff7888f1f7294311f0199322f77c1457018c875bd9e1", - 126278605342839049377710151409810132688161986656629424128 - ], - [ + 126333978716874242627475052620752087219210710628817698816 + ],[ "00000000000000000506b43c9283ccbc40f583e0c734e4a8af2ce6a4262c6221", - 133533639774706835230353390473157702360903922769486413824 - ], - [ + 126278605342839049377710151409810132688161986656629424128 + ],[ "000000000000000003937068e19a0750a33978050f019d2b60f430e3da707db9", - 124022888639743237872084547350559836284832548627419234304 - ], - [ + 133533639774706835230353390473157702360903922769486413824 + ],[ "000000000000000002e2f6ec3c9eb965aa706c788da7dede201b6b4b8fae3971", - 122123731568103772089607259872577666017242529148853813248 - ], - [ + 124022888639743237872084547350559836284832548627419234304 + ],[ "000000000000000000b3076636b13562bb4315f895bcb324e0c962763c2196b1", - 119378259820331825692479928211144812308894309500762193920 - ], - [ + 122123731568103772089607259872577666017242529148853813248 + ],[ "00000000000000000025b8961d1d0cfba33b0205ec10b3ce541618e352b0bbd5", - 111759931157462873316041289986819959868258380300102402048 - ], - [ + 119378259820331825692479928211144812308894309500762193920 + ],[ "00000000000000000421d58b78b9f063a4b20e181d55c9c79082f9e4b8b30925", - 104283029085035157753191385936387396702868516379761311744 - ], - [ + 111759931157462873316041289986819959868258380300102402048 + ],[ "0000000000000000027fd968d41741f31c73c4a3b304472da0165245278e2ea3", - 106299667504289830835845558415962632664710558339861315584 - ], - [ + 104283029085035157753191385936387396702868516379761311744 + ],[ "00000000000000000364a23184b8a2c009d13172094421c22e4d9bc85dcf90a5", - 105881374043672627773432318187360570734220873198601240576 - ], - [ + 106299667504289830835845558415962632664710558339861315584 + ],[ "0000000000000000042a2ed4a504424060407825d774a54f2e148fa769ee72ff", - 95668727978371040303278646201741713440261619517174579200 - ], - [ + 105881374043672627773432318187360570734220873198601240576 + ],[ "0000000000000000025f769f13f2806fed19d9948b1a7ef19048177789afc5d3", - 94012390634764280055243391736606357298689315295029362688 - ], - [ + 95668727978371040303278646201741713440261619517174579200 + ],[ "000000000000000000b3ff31d54e9e83515ee18360c7dc59e30697d083c745ff", - 86923102180582917240747796162767475850640519180006195200 - ], - [ + 94012390634764280055243391736606357298689315295029362688 + ],[ "0000000000000000021ecdcb2368ce66c23efd8bd8ab6a88a8bb70571c6e67f0", - 84861566431029438820446406485131195674434646972185968640 - ], - [ + 86923102180582917240747796162767475850640519180006195200 + ],[ "000000000000000001972cb33b862b27c1dc3f3a723f7d1cfd69aebe0409126c", - 80022382513656536844370512820784980102919810105407963136 - ], - [ + 84861566431029438820446406485131195674434646972185968640 + ],[ "000000000000000000cb26d2b1018d80670ccc41d89c7da92175bd6b00f27a3e", - 68605739707508652902977299640495787127103841947617329152 - ], - [ + 80022382513656536844370512820784980102919810105407963136 + ],[ "00000000000000000276deb4022f66cacd929c690cd6b4f7e740836b614b21f4", - 63859343606086615291372321518809062931940920926127783936 - ], - [ + 68605739707508652902977299640495787127103841947617329152 + ],[ "000000000000000000587912ced677698c86eec8b1d70144dccb1c6b0bad0f17", - 61163258921643354765656928775243357859392914550528409600 - ], - [ + 63859343606086615291372321518809062931940920926127783936 + ],[ "0000000000000000009f989a246ac4221ebdced8ccebae9b8d5c83b69bb5e7c8", - 58509826700983959310706392369835644790490546910263246848 - ], - [ + 61163258921643354765656928775243357859392914550528409600 + ],[ "000000000000000000038bed8b89c4e82c13076dd64dc5f7a349c39d3921d607", - 56672777602924507578641088682504585686103825941044133888 - ], - [ + 58509826700983959310706392369835644790490546910263246848 + ],[ "00000000000000000122f47d580700a3a5b4b6cb46669a36e4fa974c720ab6cd", - 53958359841942568206719748916397287559357255547625668608 - ], - [ + 56672777602924507578641088682504585686103825941044133888 + ],[ "00000000000000000172ad9ea56a90bdfed0f364a902500e9ff4d74f000ced99", - 51764751112426770751506128647798102319231116027761786880 - ], - [ + 53958359841942568206719748916397287559357255547625668608 + ],[ "00000000000000000201d7429db233c7055e9699c5bfb57b167ca8d0c710dc71", - 51649140486907347007064544362790913467244253139882213376 - ], - [ + 51764751112426770751506128647798102319231116027761786880 + ],[ "000000000000000000c0549b2a8adbefbf6c909f61fdc4d6087c44a549cf8201", - 48144529712666433692552181910809237167694270386587828224 - ], - [ + 51649140486907347007064544362790913467244253139882213376 + ],[ "0000000000000000015b6789cdc5dc13766f58b38f16d5b35bf79ce4b040f7fd", - 45240046586752885057924289339576851866807485277820420096 - ], - [ + 48144529712666433692552181910809237167694270386587828224 + ],[ "0000000000000000013a31b29f845d97465bff53f901027f8ab4b1a2f59118a8", - 39718797393257298660757754408019939605415460564426031104 - ], - [ + 45240046586752885057924289339576851866807485277820420096 + ],[ "00000000000000000088cdeaa7389a7de9f09e3a28b3647630fea3bd1b107134", - 37880625861940376795251270290737354395669643839013912576 - ], - [ + 39718797393257298660757754408019939605415460564426031104 + ],[ "000000000000000001389446206ebcd378c32cd00b4920a8a1ba7b540ca7d699", - 38043004539854389433075372490391464304285496568268718080 - ], - [ + 37880625861940376795251270290737354395669643839013912576 + ],[ "000000000000000000f41e2b7f056b6edef47477d0d0f5833d5d4a047151f2dc", - 33509870757351677175294676059494700127350769223450230784 - ], - [ + 38043004539854389433075372490391464304285496568268718080 + ],[ "0000000000000000010e0373719b7538e713e47d8d7189826dce4264d85a79b8", - 31340207270661909233492904963194738468218672502370467840 - ], - [ + 33509870757351677175294676059494700127350769223450230784 + ],[ "00000000000000000053e2d10bd703ad5b7787614965711d6170b69b133aa366", - 29201223626342991605750065618903157022235193117232857088 - ], - [ + 31340207270661909233492904963194738468218672502370467840 + ],[ "000000000000000000cbeff0b533f8e1189cf09dfbebf57a8ebe349362811b80", - 30353962581764818649842367179120467226026534727449575424 - ], - [ + 29201223626342991605750065618903157022235193117232857088 + ],[ "000000000000000000d0ad638ad61e7c4c3113618b8b26b2044347c00c042278", - 29217311836366730185073651781541697865715565622665936896 - ], - [ + 30353962581764818649842367179120467226026534727449575424 + ],[ "000000000000000000a7bda943639876a2d7a8caf4cac45678fb237d59c28ba1", - 24433127148609864747615599184820261456796420809345204224 - ], - [ + 29217311836366730185073651781541697865715565622665936896 + ],[ "000000000000000000fb6c6a307c8363e923873499ba6299597769c10a438e61", - 23988269434232535193761088780698748366141469438183997440 - ], - [ + 24433127148609864747615599184820261456796420809345204224 + ],[ "0000000000000000006f408147ffbcaa0fb1dcf1f199c527ffdaf159d86e5cd9", - 22526487188587264742197108840494583820145762956159746048 - ], - [ - "000000000000000000e3be3cf7343d7792c0d47d3c39ddb9ceaf19961e9eeab4", - 18556440756915402760741928101946749165024073301499052032 - ], - [ - "000000000000000000b3fb09d6def197657e20f9c1d5e9680cfcac1e1f9aa269", - 19758940920085072387393228723348383373068660102939017216 - ], - [ - "000000000000000000bfe71f044145e1b42fdfb3a523ee2a215e80fa6afc2a98", - 20014481558369106100835306608979160026489460596213284864 - ], - [ - "000000000000000000cee3bff56ee49c0f96d1cbd17fa17dc6f84b3f48aed765", - 16946123176864917983795071264823963343174695083267063808 - ], - [ - "00000000000000000089ef13654974b8896b0b0909dd9ae8e350b8a8a7807ce3", - 14392961660539521116256653268419249019684881662910398464 - ], - [ - "0000000000000000003105a067417c318dab31e25ae1583fa2b27be226945fdd", - 13960450711994363030255127593764523087979983609872252928 - ], - [ - "000000000000000000720da39f66f29337b9a29223e1ce05fd5ee57bb72a9223", - 12101157559014734955774763823279522156034099347349045248 - ], - [ - "0000000000000000006a8957cbd52c2038861514f106f7f9f76392d5cb83fd4c", - 10356793971791534424976101420669664288187918308140384256 - ], - [ - "0000000000000000006b68e55432541794388c94fe9e805652038e7b3cac0681", - 9378292318569022964986206758839123913433917663832178688 - ], - [ - "00000000000000000001c9deea9f0302eadb1250df1ad53da802dfb40d47face", - 8964447668935855171055978546867850348456065181232922624 - ], - [ - "00000000000000000013aaa8778111530a626a3fe57e4e6f4a878c92669b04d1", - 8192878571041388924351625416816775770172128369752145920 - ], - [ - "0000000000000000002f67aa98789b98304a32e54bffbb34c8693eb0acac4c30", - 7786052052270684126234611299412205796254663675224260608 - ], - [ - "0000000000000000002e5f072398ee27b25b6cdcf69051bcdbbece417093c979", - 7678459224733657715202292429397298472913633233275453440 - ], - [ - "00000000000000000028d7447c20ade2053bbaf49e8a16eb5fb1bc74335d0d18", - 7021961458254440109762706424650140438182306270565892096 - ], - [ - "00000000000000000042d89446b9043387be2d4c09aa9e9524176c5754616510", - 6702918573828378664524678433037841287557455508299317248 - ], - [ - "00000000000000000018ec4d369bab2c13174834a02138decea7c85685d46bd6", - 6505870154073602347674948421782035713149324747260035072 - ], - [ - "0000000000000000000d4a6c2237c6c46b963b17f60d9c850c4915518deb6678", - 6259542822111302646229226565336702507884435252736688128 - ], - [ - "00000000000000000031adb986da21237ce06b57ae5390b7f0f890ab8e21b66a", - 5456617206587901877414813377199700077413780408546361344 - ], - [ - "000000000000000000031df41201cd3789559333cd9529f99834a805014c9b13", - 5309609141393698345581459330931267317315649121846034432 - ], - [ - "00000000000000000020c68bfc8de14bc9dd2d6cf45161a67e0c6455cf28cfd8", - 5026314587016750785722693470327208449351582469580652544 - ], - [ - "00000000000000000009dce52e227d46a6bdf38a8c1f2e88c6044893289c2bf0", - 5205879062684137510961952799929229129995569309608312832 - ], - [ - "0000000000000000002eca92f4e44dcf144115851689ace0ff4ce271792f16fe", - 4531442825108320403104334767545311437480985430866264064 - ], - [ - "00000000000000000000943de85f4495f053ff55f27d135edc61c27990c2eec5", - 4219470685603665866184576203153693664105230070242607104 - ], - [ - "0000000000000000001d9d48d93793aaa85b5f6d17c176d4ef905c7e7112b1cf", - 4007526641161212986792514236082843733160766044725313536 - ], - [ - "0000000000000000001877e616b546d1ba5cf9e8b8edd9eba480a4fbb9f02bce", - 3840827764407250199942201944063224491938810378873470976 - ], - [ - "00000000000000000025eb2c783f2f29d68ab4260f4b0248450c0038debc7ba4", - 3769176185135465353474348091454476000617158630021529600 - ], - [ - "0000000000000000000c61b8a7779dcc46e88ca343b9a3fcc6763917fe3b87e2", - 3616317728887026217259424694800679959591344645351669760 - ], - [ - "00000000000000000003dba9fedba6a0b92b640167eeda0d41485a3c85ac4ac6", - 3753318892370425056811838111019504329853891761930240000 - ], - [ - "0000000000000000001ac75bed7eb6169255893f99de28f24e3e0e57b6f7db7b", - 3752507758961706405692235065937346792777982719368888320 - ], - [ - "0000000000000000000e5796e9c5cdc8a8a2de84fd17287d7dfe89074de31766", - 4052052750044136275098507698196378011637603685579620352 - ], - [ - "00000000000000000015fe695e8d2e5ed3a7de81d3818ef43a444e1ee7b3ace2", - 4774638159061819979596346127394133648234752261950013440 - ], - [ - "00000000000000000015a08d0a60237487070fe0d956d5fb5fd9d21ad6d7b2d3", - 5279534360700703025330663904443631645337169341976674304 - ], - [ - "00000000000000000008f4f64baaa9b28d4476f2a000c459df492d5664320b12", - 4798269179035823348880781507454323228379569035237392384 - ], - [ - "00000000000000000028a69d9498c46b2b073752133e3e9e585965e7dab55065", - 4581847093576588582947343450056030606262879232408420352 - ], - [ - "00000000000000000014dbca1d9ea7256a3993253c033a50d8b3064a2cbd056b", - 4636475101776743072223960781733299832971578678999777280 - ], - [ - "00000000000000000019046cf62aa17f6e526636c71c09161c8e730b64d755ae", - 4447653474738502407900799312400854215681091162244907008 - ], - [ - "00000000000000000017e5c36734296b27065045f181e028c0d91cebb336d50c", - 4440088742263677654396177039706714734771352055402463232 - ], - [ - "0000000000000000002296c06935b34f3ed946d98781ff471a99101796e8611b", - 4442250303185290059812200289574302117357423179633524736 - ], - [ - "0000000000000000001ccf7aa37a7f07e4d709eef9c6c4abd0b808686b14c314", - 4226119056551884143559484765457720035561644907380604928 - ], - [ - "0000000000000000000de3e7a7711130dbac9fb0a14e5ad6ab72d080182f3321", - 4217024131862773934699503234743726606330326039165665280 - ], - [ - "0000000000000000000e6829c1245de98ce5a35c177a75f67e9c1678cb6e24aa", - 4243570847603252455305754966045185171099356397876281344 - ], - [ - "00000000000000000001b2505c11119fcf29be733ec379f686518bf1090a522a", - 4022508494445492072607020209303018350395259009223360512 - ], - [ - "0000000000000000000a4adf6c5192128535d4dcb56cfb5753755f8d392b26bf", - 4021030916290150529756716283937142188262386861422411776 - ], - [ - "0000000000000000000485ab94f5ea60203aacfc9740b3e42700d7e7012f76d7", - 3614033401827878015998272335407144409231622422786998272 - ], - [ - "0000000000000000000cbc6dfb3f2afbd6ed1427e30ed1f3167898ac4aa4c673", - 3638558860803927897868648370584956354584468626790678528 - ], - [ - "0000000000000000001d9865df58f5f300552699fefc09aa840ba25ac044a534", - 3397669776434136486181562425402160438435718857259745280 - ], - [ - "000000000000000000115eb6c10b7a98bf23a46002baec8fbbbb2cf0583439a6", - 2974300520630483197933400799376074857018768662277914624 - ], - [ - "000000000000000000113978c5b95531173923ba81ed4d1df3b09db37ae0f0cf", - 2990922178751847556822131306978557143801315583089180672 - ], - [ - "000000000000000000096b8d24db6471fb5871e9ae8bd1d7384fbee9c80a6052", - 2699909434228155498652331786772923585210445951064342528 - ], - [ - "00000000000000000016e0dd8fe86bf34feaa611b4c52180b6822b5ad31b68ff", - 2647377219375933524160418539145769508351933111739613184 - ], - [ - "00000000000000000011e20e47a868d12a2bf3de814ebd067e83514aa2725745", - 2502742632840755378666227277045667991877723059489079296 - ], - [ - "0000000000000000000c48f6bed594da7bb5e75731b4e78501670e834d426e87", - 2267299103571658911252368261549572946260211294613274624 - ], - [ - "0000000000000000000f7871dc40f51b1ecd6343a6d9fd614d0e2235a7d9e3fd", - 2112846149036891759953684644743283440459952687539027968 - ], - [ - "0000000000000000001558c0f33a360d105b52a749103eb2abd4a66a68d52664", - 2072520395859657486634608572838975759381606196813234176 - ], - [ - "0000000000000000000676463abf3771ea01e0f8c948d1c93658a1d82d95df5a", - 1969073848467738847181233556694484530967339635488849920 - ], - [ - "0000000000000000000e24396612da4ec125ee6c0b4507e854c5cfed1884cd30", - 2119459443945814095658556318611324621123895782295994368 - ], - [ - "00000000000000000002fb021eeb13e47021920faf6e5daa3c40bc552c4d248e", - 2078088717097888226752964612051624797686495299801972736 - ], - [ - "000000000000000000067b904af747b653ba448a79779f7846bf1ea5537b8a4d", - 2093644940525638357414324633411056914147713045789409280 - ], - [ - "000000000000000000080ae07ccf2f1b6d1d089f5dcbc1fac50a6b93d005f1e0", - 2082043540528505650049623783208955059537684253263265792 - ], - [ - "00000000000000000008f9ddf24dbec1459689fc399329e9738b2795860e4361", - 1953761695813422977307213550702116033770404430236090368 - ], - [ - "0000000000000000000aacba541ebb7b56b0831e4ae33faf20ff1e528bb9a657", - 1824503568004603261415443256727022530945994444270206976 - ], - [ - "00000000000000000010fe23dd08a4b6465c4850984bb538e9dfcb93995a23cc", - 1743137387349479903250289511035208906392689711805104128 - ], - [ - "0000000000000000001166c174a9d34b0743953e724162fe44388e38d078204c", - 1734095076719313606895363312975193263350078457161711616 - ], - [ - "00000000000000000006da92c61b6b63ea910be27cab5fd951137105314f2969", - 1740794600224838465872409004248364704712181251938713600 - ], - [ - "000000000000000000043f26353c41c2343a277ad72f115171fb49d3be52dbbc", - 1628687194130096895725758951785196783123433634364653568 - ], - [ - "0000000000000000000bc6800858a1b3be08fb26b55d4b989c95e06ad50a350c", - 1937788944419033539314165479165359776648584743473905664 - ], - [ - "0000000000000000000c799dc0e36302db7fbb471711f140dc308508ef19e343", - 1832085838499075985755083973639154607251969422303166464 - ], - [ - "0000000000000000000de98650125747f239134cf7e2b7362033e325a8003a14", - 1689336589076054705025375464973257095873115523033071616 - ], - [ - "0000000000000000001138f586983520b0de3645c0873164f4b214b90cf3aedc", - 1674005436900453533413418811078063286996924790657253376 - ], - [ - "0000000000000000000e87ecbff47d9ab75e78d92328d5951351f9702597dace", - 1780912820169571750977100152906426673601736600243404800 - ], - [ - "00000000000000000007c4dac98234149700771e9d1756956660b63cca88c36b", - 1963213226902041926479236780515292236058519345991516160 - ], - [ - "00000000000000000003030a3de58b57be352e2ca79016cefe19777e02ba0520", - 1707948812427463753688699391317898960128433823967870976 - ], - [ - "0000000000000000000cfd1300625612513c6cd1413245fcdaf1eeb766e33a93", - 1708005810991319658902509335026374895166200405337047040 - ], - [ - "0000000000000000000830b0a5ac4b78b5eb99209ebb4790be1fae1428c7f77c", - 1554226608711362053849117616927967595838003183165112320 - ], - [ - "0000000000000000000ed5cf2e86791b44abce69e178e58613e64ed47e1c02a3", - 1600203988720154928752887338080389143353359165034594304 - ], - [ - "0000000000000000000aac5c93f7945c60d82828990448cde97d3d7128830a6d", - 1590739304116800001454600275103718494518067345886281728 - ], - [ - "000000000000000000049a66ca322371799e1cb51d85c8937764ba6a2abb8ed9", - 1535456543183121267670627692621392373016562041515671552 - ], - [ - "0000000000000000000657c7aa925caa49d18e0c02cab9992be315012d8fab06", - 1554222224206450061140363005873469446988944215367483392 - ], - [ - "000000000000000000061250f1186194229157967d10a01a2b36ab19d4304da5", - 1395807138732878832030429199485686097922398375169228800 - ], - [ - "0000000000000000000d2e17e6d3179b4182518bd678f20bbda8b29e5e494d54", - 1397005570075490172423356221048513449998516239854469120 - ], - [ - "00000000000000000005e2dea23567cb4fe092a354e7d1b50b59571715de22f6", - 1348156339349342073285316259199804406349536350538039296 - ], - [ - "00000000000000000005e17383e25f65b531d50060b99ed66f673ea251949e4b", - 1605902383604108119230963505243149930846997646019657728 - ], - [ - "000000000000000000090386439b3e1c7dc56d2e450694e910b366895f05b9ef", - 1532070243889425565609149754863988745260019245813596160 - ], - [ - "000000000000000000046f183ba323cfceb2d11660376c59fb55e8521c4d32a5", - 1407282849589201081744164532792174352192736757496676352 + 23988269434232535193761088780698748366141469438183997440 + ],[ + "00023bd8af79aaa0bdb7b22706ac3174a78071dcd81a36a306d154a24ccb68ca", + 14134776517815698497336078495404605830980533548759267698564454644503805952 + ],[ + "0007ce71aeb9893fcbdb4555c6f0d0e5e42312ac4426f38c1cc012e2bb2e9ecd", + 14134776517815698497336078495404605830980533548759267698564454644503805952 + ],[ + "00039559118097e3e60a88ae228315b69c804035fff13a27b1e1bb1bbfcdb19b", + 14134776517815698497336078495404605830980533548759267698564454644503805952 + ],[ + "00043a9e7603bbc03c47d67f9f868f9d99b7d879a8a73b90efb35865b3134450", + 14134776517815698497336078495404605830980533548759267698564454644503805952 + ],[ + "0000000021d39d92a8c165889071dd3c169ae3a6420725ff824f937721513b3d", + 3669484396131597981737805513662878009197698812689065071816750479980 + ],[ + "00000000038a2ad1d5a7ac2916de2d5be831bf7f5d5852945444b23918faa245", + 1985558057908427916080709379924308808461714224796059348280218522676 + ],[ + "00000000058259396bc1fa09e309686b3e5ece347b9a001705002852acff18bd", + 3306164751546523262978918213385317234746997176049850908257051388400 + ],[ + "000000000c5ed5f31ddb7e2a61b7296c300907e8031cb5d032cf9b886beba7c5", + 3143946702108122812788759431428131688119780466243848894410917029600 + ],[ + "000000002c4ec521c2c8e0c2935cd0eb7b24c7e9949d833884310f823fa2e77c", + 6600952388167445051842960437324707407632787564992531618371340373440 + ],[ + "000000000b4b403fc5bfc0669e56ffec5c8cf912e56dd460e6e308184ca9fe22", + 5228546273429474065514617560071732412997035311700574187364889991902 + ],[ + "000000001b636e8eb0488db4612eed9f3a25192381b5527808d1281142510781", + 4689894807719485529226085522977581616192392234669814431112610339440 + ],[ + "0000000030132509dd049f6b7bded622e8b9b254f080b14d48c06e7c8e62ed05", + 6318769548885785903177137069912195591280650426849454679278965887360 + ],[ + "000000002b67af0fb648953baa2854ce55e6fb2b73fc6a0d84608ed43cc19b5d", + 5383446458693964367434994714682289983088745837975634686506808112400 + ],[ + "000000001a97698edd7a4d7efa98c2531093954f3068b01e9fc1324c4a930393", + 3909604766973972198797036734725468324956348828474735638950082060347 + ],[ + "000000001cc7209e390293c68d156c964e8e154bf3cc18b6a778d1e50b43e993", + 5021445174844590716534087972306407351343964001819953514901182034880 + ],[ + "000000000be5ad92c4b9b161a47924bd89a31b7e803bb9adb6d96a33c9dbe53f", + 5294141513231736509431899286017418438553965005388541512670896928640 + ],[ + "0000000015b9ad79ffcebc8509fe507a5233fc9a001d68c9a90c1eb55560f863", + 4622626581416194626222790382794637127548697992482713686298919195680 + ],[ + "000000002d15609f8e8eec5dbaabefc3f9645278493c6c53ef12a413d0f0c7bb", + 6108872223105790108758335779442053310992162122701383180299337947624 + ],[ + "000000000f5550c57893d3437af166510234dc6422d8788bbc0b0d7a09999c93", + 7996065154713553237801309299893902276886524870948389857375580525660 + ],[ + "00000000209bb9734fe4be5b29d5a2e829e4c88f7ce24c8ee61d419193cbe34a", + 8367971897041189024104720718825078746985893747480792866165034046320 + ],[ + "00000000431947d62e94ee6f5603e91ddcf647481fbe78f4e0ce83c11988630e", + 7480016471160565822236894014740622469415468162849588050688273025273 + ],[ + "000000001a39aefb3fe5097a4c9f9bd384e5fab7c79bef239b9d07e70b85eb66", + 7753218368760284370253835400384628094017422269235830862342064586310 + ],[ + "000000000edfb42424749a83de72b732335fcd3b4b08ad8bc0f6045026bd31cc", + 291457710056867152447551928352498356074946301343632673271876567435924 + ],[ + "0000000165d8f29e59dcef69ad3e280f29ab287b7bb98ea4186e8ce14075f74f", + 121737217619929675635164317105361438237375862706235602355398991534574 + ],[ + "000000028d6678882f3e79f2d485e00b46d2d1a77ef9892a034a32f6d0cdea30", + 93111568004779209352187506080847677422102840535482105469991357423185 + ],[ + "0000000498a36f86dc27050a4c5e6636f8f740a5a9850e125b48c4093bef5cc0", + 126209534794008450752061967481500424522877257493212435926599197008716 + ],[ + "00000002e90d7151ea2cb762f7222d537b65f534fd4cdf34d1a75f435a223fd5", + 81818540689583381635452287511672029490075473592194693441144845349598 + ],[ + "00000001b9f4bab5ab64a885c8983d2061d9789c9fb13d25d8daaa552f49810f", + 67228494965362042669945557309664026808811147413533328076334995443750 + ],[ + "00000000b06c9db4c34e920a7822ce096a417b8cd53f96e5e0ff188451787d92", + 67442337758959961709013976606979761010163750122564504011042294726642 + ],[ + "0000000187d6c4bcebfa0330d5e1e925fe8fc6d1244d4f73b2f292f10deec874", + 53990434335986604888288654823988444595253822525595165776866361794882 + ],[ + "000000016fd27b68a48abdde030609547d681380fdbf6ac1159b3ff3496c9645", + 72652566976951761361671924419015404429872382295456588368252078337856 + ],[ + "00000001cf8f2eab6554b05db63e1e03b2b9183688069a8e2f5ef1cfdece2dc1", + 51969828767166332618812237045265023176853238231905271669440120305990 + ],[ + "0000000073e8209f911be3a10829939752bf9c719a651c2d577526f16c37d644", + 51825840317093406590986398250502473293107617323142346640651804173196 + ],[ + "00000000e7e1bd6943b8646e04e123f9b602811c7313cb37c61d0c4f0c0a311b", + 63654637429717349695323945155072840928402527456037613663883830762860 + ],[ + "0000000139f0513f24e4cf823dd4f047e49e3c87dfadbb84f1315bf1726aede3", + 78821312130815604234668639934574096578010234514386107748055649965100 + ],[ + "00000000d1691eeb173bc5e164d73215d92acfd0c2b1a27036a0b006538d3e3e", + 50612315389094366733381364000612497359703594376198924475304077001306 + ],[ + "000000000035ae7ed26858d5d04009f00636d165b0ab3bfb14a67b7558df196e", + 65592739767795779529803281201844648704272728579789073763358385503970 + ],[ + "000000019104ad7bfca6a41b7b31dbebd9b4655f049ba6d87f8469d384eb5394", + 82108710287670752771297284508953343284824673382195615706700746511280 + ],[ + "00000000e72399a532b8736ca4c4ab9776b79988e692a40e02fd8b365c500c7a", + 95834966713990874774106613817257248437436032229113007303891315815280 + ],[ + "000000028902bec111380f226c88e58faf6314d03cb8ac87604e32071133727b", + 68811728242515631998526088157354565445775990664029607509735888431509 + ],[ + "00000000dbd064ebb0ff29e8cea73d0928ff378008f9d84ce5e854d99897626f", + 66928972015500390777586800637265424161602106557139925483007222613300 + ],[ + "00000001025a30f614fcb2f3d304bece68cdf0346aba4b8e340417ffa41d1a8f", + 79029664505499197699133084508465989874547400801371134240013495212236 + ],[ + "00000001a1596923e59c8bcd415a8d66c86a4f89a259c54abe24a62b67c35bd1", + 69562738661011059103711579574280237381880538417679967902953748112780 + ],[ + "00000001eb099fb95ef80c11f6c39dbca3fe49ebcb1806b76307281375eb05d7", + 80997216911856134337757185468917010480695444525477397414368329281645 + ],[ + "0000000077a4fb4daf5911d97f077a8023623df132b50cca62220a2035bf2061", + 50048297025461946019699252157181653729164232574281615479899247256296 + ],[ + "000000000fa0f1a3f9746681af77897fa42b91fac7103f929e78e83b325a0453", + 55669522172226548722039052713948906658215595387157685873364589228567 + ],[ + "0000000109301b7d62d2bbba5e845eb93de0e2d2da76863431a31032e2587de4", + 70306654946845926886044106369158228637959717918715513508290863563212 + ],[ + "0000000113994d03ef9dfb4b3644e14829350672acfbe987eaa0a02571afb6de", + 55488089310834219615679790341873452821399825232983772306406350223125 + ],[ + "00000001c57c159f48a0b15fe0e9674fc9c0d42a636577a0168b100029e2779b", + 54675048712548230989288105449748138096964672768535766979948131010002 + ],[ + "00000000e7007c335ff602d6fe11c252db1c37ccc8c3cd9901bc3e3d9eba93ee", + 47924987686627102274700249888992986353923926854681485661228934289448 + ],[ + "0000000074e03d757b827642c2300ffc4aea46014f66232613f96e98ee0e3641", + 73661290428418502887341869004719096000854665128681191790051993799024 + ],[ + "0000000072720d195785c0c3ea83aab9943c895ada94979abb9f8c4897caeb1d", + 63440985214819345885915255078145391578332855659567080782702827663242 + ],[ + "000000019701d6203d5addee2c9d910157fa2e554e3b61b2d56321fd7cb637e9", + 68244490697603430925597821511703535742990526860447083460242637435115 + ],[ + "000000020486d58eb5d6bb7800ce5c97bf9a2b82fd9acb74939574299e67b629", + 78922912297228963249876544992555495455376974217567977750094411105668 + ],[ + "00000001bb44352ec0230212b7d00cf569d703390c1f55a0e1d116cc699ffe15", + 83560466589271425950495901618623954902569007254628960452110696898362 + ],[ + "00000001d36ccab59882cd54c5d87de36b1635c627a1c0e10861f844cd89435c", + 69777194913651148909317010977008391643710468045601734328462763033760 + ],[ + "000000020d1dc544be13db770803c2011ad01331170683671506aaad5258e143", + 92258392663666543018589729508711592690304251887251273650976684373895 + ],[ + "000000001270348a58861f8bcdf886fe49e1b8d997f9d78201611195be667a37", + 101597039631184455422114706940026744075634823075073973083854621622582 + ],[ + "00000002512533f4b71185c51035ef3393191cddf0e12c696088e3e1d4e2221b", + 89335996926111294310211363404263137567533681045848646063024834988250 + ],[ + "000000018dc38ea9734ed95660d264093b53c67ed3b9edfff927472c05eca260", + 104612163754758361633410498300375467570951534941672362696867756729456 + ],[ + "00000002cd208ce50d14883750ea589bcfee933bfcb22aa392dd940f00501d1a", + 131728085468056614095323464697142032259601293127281539516168803444684 + ],[ + "0000000152dce16d9654b2a9910b102c4d696209ede8902e9e34a8784be75db9", + 106816940389064917221560944514691304180425830654550105169186876235936 + ],[ + "00000000003157e287f6ac664d174c92ff990865a5964e9fa40c14953f363398", + 67900592009944247774311099109114849151497184861179708633839889994150 + ],[ + "0000000247eba261dc3ccc4c9803c25d03bc33f7607309cba9590eb70fbad932", + 72927027826995744314207324806313412929352065441120164026244670671062 + ],[ + "00000000953e714917ca8afc1ae6457f30782528107772af5d78b3f27387d5fd", + 78344129647569936346465148666931424473159387180061417121527127617496 + ],[ + "000000002d61bae4a8b51b5ad3c466671c1bebb571139355231de5aaa4e12613", + 84851412858470707283932339178174717888069044936886335412175585121200 + ],[ + "000000003eb44e9a8785d7d37ee388b2dd2a045349241c1e8980da481edc0217", + 74926253331746245736958888458906663000938178754093139636765945110810 + ],[ + "000000005d93a632b3e98e0f90740b6e9a62eb34678cb7681e104ddac3116d4e", + 73403446282838525969691586782931661674209218966519255221251669343839 + ],[ + "00000001f199b47963a76639eb93d54fd02ffbf0440b1e6aadc7b37d578bd64c", + 59256954889529828839517682041642985553786739817886426353160069918960 + ],[ + "0000000296733f91dce47384b17d6e73edb0bf4734e07e1d636d44b3c32b5142", + 120923660762046458848994277452498227740235164767127100987822155719178 + ],[ + "00000003b7e1aa001bf27aeddb6db14e77d6f78e328d3776f0d0865f3612929f", + 212484374952948996472101808691497105349469738946937983120901055594762 + ],[ + "00000000ab5ea01c470257688fba915f0906bf87e87698654a1358f4be561a19", + 178577365802799031639642660707943356907782418407836913693838090559614 + ],[ + "00000004ece07d55bb0881566bda28f6a00591b10b9b0f952cfa8ec90a9bc448", + 226264816780657888306990708967345767790019237974454959121517710653120 + ],[ + "0000000417acc0e985cbd8595af18721125099e366659859942c6c3cee9fca24", + 144484383031703302004364897027648429524629369964624500302017543428054 ] ] \ No newline at end of file diff --git a/electrum/checkpoints_testnet.json b/electrum/checkpoints_testnet.json index 3461d67c50b0..64566cd12722 100644 --- a/electrum/checkpoints_testnet.json +++ b/electrum/checkpoints_testnet.json @@ -1,3762 +1,158 @@ [ [ - "00000000864b744c5025331036aa4a16e9ed1cbb362908c625272150fa059b29", + "00006764419c86ef7a81c11576bbee1e2c17c425d7871faca1c8b1b59d5df88d", 0 ], [ - "000000002e9ccffc999166ccf8d72129e1b2e9c754f6c90ad2f77cab0d9fb4c7", + "0000080a471063c3dff14c2f05a7543ae30883d231dfe3d57914033cd743530f", 0 ], [ - "0000000009b9f0436a9c733e2c9a9d9c8fe3475d383bdc1beb7bfa995f90be70", + "00019d599421235ead813a8093c031e4f68452396b3f4588a6a9ac375b281868", 0 ], [ - "000000000a9c9c79f246042b9e2819822287f2be7cd6487aecf7afab6a88bed5", + "00012afe43761541c20a7b5a14939589ae57f5fb869229ee4b0b79d17f54e6da", 0 ], [ - "000000003a7002e1247b0008cba36cd46f57cd7ce56ac9d9dc5644265064df09", + "00002d21637f012fd42fdabea5952ccbb7e627a30e021e80e9b164b10ec50ddd", 0 ], [ - "00000000061e01e82afff6e7aaea4eb841b78cc0eed3af11f6706b14471fa9c8", + "000493f11fd1cc378704158d077b0b5bcf7ebc43d0f38dfe04b0d61b2e548dba", 0 ], [ - "000000003911e011ae2459e44d4581ac69ba703fb26e1421529bd326c538f12d", + "00074c9c854b7263da6a54ef807860e32d23057801ecd95583427b8eb189e16e", 0 ], [ - "000000000a5984d6c73396fe40de392935f5fc2a8e48eedf38034ce0a3178a60", + "00002eb4395973a80777e2817e67a269b713004a34ea8bca5511c4b5102078e7", 0 ], [ - "000000000786bdc642fa54c0a791d58b732ed5676516fffaeca04492be97c243", + "00044e5ecbbc8d349c02a3c8b972e5d1f7dddd33897ef9088c2b10faa3970cbc", 0 ], [ - "000000001359c49f9618f3ee69afbd1b3196f1832acc47557d42256fcc6b7f48", + "0007944348416eacf2c8448e228c4b114962398b076253a2d41c279a1f668a40", 0 ], [ - "00000000270dde98d582af35dff5aed02087dad8529dc5c808c67573d6dabaf4", + "0006e2bc9ce4c8fd3f49fdfc04fc18e48c81264723f90ca79544efd7832f27a6", 0 ], [ - "00000000425c160908c215c4adf998771a2d1c472051bc58320696f3a5eb0644", + "00073e0df4f470243c25ad4007d42763e81e78a519fb85503c4f942166f9b3e9", 0 ], [ - "0000000006a5976471986377805d4a148d8822bb7f458138c83f167d197817c9", + "00014caffac68cfd037a5d55ae53ddb78cc8edfec9f454d3fd6efcfb8491c015", 0 ], [ - "000000000318394ea17038ef369f3cccc79b3d7dfda957af6c8cd4a471ffa814", + "0000d501b3750dfb9752e9ab00d81e8ab6870b507fff868cb4aec1aaa8c862e6", 0 ], [ - "000000000ad4f9d0b8e86871478cc849f7bc42fb108ebec50e4a795afc284926", + "0000d991605428dde607d6fe587a47e9e7c9276e739b95165cc7c5301082476f", 0 ], [ - "000000000207e63e68f2a7a4c067135883d726fd65e3620142fb9bdf50cce1f6", + "000550f4d15dc929f23693cf655c7d195236d0868fd908ae8510849067290486", 0 ], [ - "00000000003b426d2c12ee66b2eedb4dcc05d5e158685b222240d31e43687762", + "0001d7f22f69e38abbd622f39191154c5002b73029d42901bca782c6d957e5c0", 0 ], [ - "00000000017cf6ee86e3d483f9a978ded72be1fa5af37d287a71c5dfb87cdd83", + "00009a5033d1334a423c33b15cdf5d18ce5d66d2feef1ec5362200f2fabc68a0", 0 ], [ - "00000000004b1d9fe16fc0c72cfa0395c98a3e460cd2affb8640e28bca295a4a", + "00003080e3334d624121571476d74b43c721b5de60e76cf883b482e318ecbed7", 0 ], [ - "0000000046d191b09f7726e4f8bfaffed6c30734afbf1f95e6bddbe0b07d9e88", + "000160ad6054866c168122f97825eea46a89e5c4758d8fec6737f7b80f5d6eba", 0 ], [ - "0000000082cec8200e9ea055c2991bf74560eb7e7140691ea53e7828dbdc9553", + "000022440bedcab93798e16c5f829abea01480586a246e9b1a34e4c901da9b19", 0 ], [ - "000000003775b96d6b362d4804afe2d9c3cf3cbb46a45c3ccc377c94e83edd23", + "0001036dbd9d58c0cc322c64b44b050a12e8c0df27893bce06675f229fb11175", 0 ], [ - "00000000037835a92404acb2f18768a49d4f93685ead30aad6bb3b073f411e02", + "0004b26771d0422a4eb6c30c5eb364ff5cc1f6a3d90fc9b1c228e4540c20a23c", 0 ], [ - "0000000006cf75d17706d1f62e6b08e6ba5facfde38a8920b7d808a6b6781ff2", + "0001aafac9788b8ff884edf55a45aadedeb76c96957fe7558b1c9cf53944a74f", 0 ], [ - "0000000003dff257cdae43703fcd0ca91fda0970f5fc04258b4608fb1942a6f6", + "0000564d208c67543c42ee1994d0e6c0520c6713dd270686d390374de2fa8498", 0 ], [ - "0000000000532d97d18867658e08c789f627535652382147e33bf8626d4131bc", + "00046e928981c58157df4ce3452c73368ec1f427755db4f9b5348f8422d564e0", 0 ], [ - "000000000266dfb79bb11dedd0ae748505863ab3ab731269cd71a2c2fbd159b3", + "00021e88748a616a054c6aa92d8ec37e11500b84dc0feb23aef24c2fde78349b", 0 ], [ - "00000000349ff0119d5c0dd8ffad8bf41cd6126a88416148b81fa4dcaebc42e1", + "0000ed4e90a8783935dbdf5236e108cf2c56587fa6e41498ad9b51fa69531a2d", 0 ], [ - "000000003c61939b4799eeea4335218d30de9b1071605126d719dce0f0d14810", + "00042bc59b2f25e347370a660170da81eed36df60fd2a4c36c67aefc89ee24f9", 0 ], [ - "000000003d9284570ed648d2b12ad24046ac8b9abcf05c4e9813ea110490cf73", + "0001c79e5fa520514edddc8152327b1996fbfe674fd5748d4a2e3ac734066d26", 0 ], [ - "0000000001360b66e6dc0ccfbd75356034e721ae55c3d5c71a58be5d281c252b", + "0002c1a4e816b3c4875ea0db8ef61b7b497863cb9d28e7bfdd69883284bd10fe", 0 ], [ - "000000000c114f42504916bfb2ee26ed8307b3f7f74226c1cfe1f5302ec23d26", + "0003643f9ec9480c474c142c59e5986e0403ac4dfe952fda75976dc3c36e3a8b", 0 ], [ - "0000000007acac3fcf97b4ca81821263b704364adaa2736fce0a0722bfed4f8d", + "00036f212e2f5dcc8fe56b0f07367494f6580d8662cf7a367d57770204c1a6e4", 0 ], [ - "00000000059768ef7731d27f9c2be48c6e16d7cb56680625f08ff25ead504280", + "0001dce94948cf2ebb242856a789f33472ec1f83098337781f31514e669870bb", 0 ], [ - "000000000351c8908f1f52518ce4bd251b896ca3fbccb69a2607db6624bafcfc", + "0004dd94fb1cf44a02171295adb566388561cb46eeb08694eaa63eef3752224a", 0 ], [ - "0000000068d7ccae048e212e9e2ecb4d944f583b4490df4fbf654b4915597052", + "000105263971918984342660a08e6736d536db27c746ffbe974bcc115565aab9", 0 ], [ - "000000000e2aaa36417187233ff55325473bd5b7a164b358da60c96d1920fd77", + "00003b23dc19da26b2f319e09f778d6d16947ad33dd0359df2d2aef86f4d6e78", 0 ], [ - "000000001eb11ef6dbe0647bc87a8d218f6e59c2b9690f17edcf0dbd39cd0308", + "0000d92fad78f2e7069485283b3fc7c8de46391cd5faec1d40cba8c28cfa0943", 0 ], [ - "00000000022e7855e24cc3fff67ce093242434a8ffa45882333a0f08a40aad9c", - 0 - ], - [ - "000000000210130ff4e3186258c09a8463c1e196f5c5432b4c7b6954e907bf63", - 0 - ], - [ - "0000000000e01372ede322bf88ee5ed8a46dd4fd8df832eca16180263fc8b1ef", - 0 - ], - [ - "00000000a0701896e26d5d884834b267512e0af52c92edc4bccf1c5c803d3c4f", - 0 - ], - [ - "00000000869fc8d9ac1588f3e5bdfd60253e9824083800b7794010e0e9c6b6fe", - 0 - ], - [ - "000000001d43b3165ec30736f28f0761600b092686f861db23ec38f2d92b0ec6", - 0 - ], - [ - "000000000ef4092da8c2056e5933de0e1530194c3ad941a9b393fbb26f98862e", - 0 - ], - [ - "0000000001e3fed39f70023909f962bea146b03bc8e94e5d19d7da93123f4f64", - 0 - ], - [ - "0000000000b4b8c877bbe3cde97649845290bb78999ecff4621b9bf2ab16aa2e", - 0 - ], - [ - "00000000006095ba3b4742883a0ec427a3fd685ffb65b987ea77ebfedea7da82", - 0 - ], - [ - "000000000168f0a76a6068a34fc042553aff4aa63b906028f28c2a4c327328e1", - 0 - ], - [ - "0000000000af10f3079b4989ac4ff0baaecab38220510cdae9672d6922e93919", - 0 - ], - [ - "0000000000312791ada0f6a4c5eaf2a1cd57cd06f5970a8ab49923817b862c35", - 0 - ], - [ - "000000000055f3d4f45c4d199d9c230cb2cfeb68c8e934cfd061bd616358655a", - 0 - ], - [ - "000000000036b6129bb5a786bfdd75cb4b932f7dcae9da469d3ba35096f1e821", - 0 - ], - [ - "00000000002fbccf271c13e486673251ecd7951ecc12ee73c4390e0ff09e9b59", - 0 - ], - [ - "0000000000314e297a81bf002fc40eb391d8883ea45ee4e782385aa0fdba6452", - 0 - ], - [ - "00000000d3c473819ec3b3c268f7b555df22772e407bc8f246a47cfc579ec61f", - 0 - ], - [ - "0000000075a438fda6bdb391263d0a2a6e8e68edd9dd8f70fe5734eab9351eb8", - 0 - ], - [ - "0000000017ebae0a2bec50008b4a4ea8839798cbd9ff228e76aba087d0ff1736", - 0 - ], - [ - "000000000800466ba31c0bbc12b125f16d05ed27788de045e25d6f093817d29c", - 0 - ], - [ - "00000000002163c41f2264f202e611aeb9ba6c0a3ee95cd8e5e7e571edc64edf", - 0 - ], - [ - "0000000000de9882d417786fce8c755cfaad17f40cda744d4badedfe5e414e31", - 0 - ], - [ - "00000000002af352cf41f60a5ebf033bf7e4967c0597cee706ba877b795aefb4", - 0 - ], - [ - "0000000000009ca0030f1dd0b09cc628f2d4d278c87b20781a1b136dc395debf", - 0 - ], - [ - "00000000ffd27370a76d06a0da0e3805f47e35e2cf584d73d2c5ecaa2e525642", - 0 - ], - [ - "00000000720da6910aa75099baa020cb8db37e1dc19cdff66152225b7609c23a", - 0 - ], - [ - "000000000a5c2cc704bce5e8527ce91bac7430c659624ecd86e6a1bb9b697962", - 0 - ], - [ - "00000000084273545134e9a06483c8fab00c2b0628056bb1967f310c74a971bc", - 0 - ], - [ - "0000000002f66f4da52804647b1c3e1f89d17bdb05e9cd4ebbd922007c773f21", - 0 - ], - [ - "00000000c46146c9d0a67a354b3f82947e52670a3bded6d8513ab34a68ae18bd", - 0 - ], - [ - "000000002f61c429d7dbe7bde75796086efe574998766806138710a2d6001eba", - 0 - ], - [ - "0000000001daf3e3e78a57df2c2d2ddd14093d10515925e75c818bec3bbd30c2", - 0 - ], - [ - "0000000002e133a7427a9aac6ceca969b27507c14111a45512cdf8f52a436de0", - 0 - ], - [ - "0000000000f7c4374d458666740de1d0e8c55229a209ced7c38e38708781487c", - 0 - ], - [ - "000000000035bb9ea329ba30b83eeb4ea6f57c2fe703b97f9b879f21e22643e0", - 0 - ], - [ - "00000000001220503e0aaee266bca85de09ce97b0091f24972d1ad1c8afe8609", - 0 - ], - [ - "000000000010a614c60457f8d2ae2bb826d037f52113252888fadda8ed773c9c", - 0 - ], - [ - "00000000585a8b882ecff8aa8434feeac4ef199ca669bd81ed473e37f0bb4528", - 0 - ], - [ - "000000009504ffdb5fe82ad88218fb5e75a8bc185247e30e22d23b9fd9b7f282", - 0 - ], - [ - "000000000ddec7d73bcd653168d82e34cf5746e006bccda8a9c031c3289b9568", - 0 - ], - [ - "000000000cb6620ee4e8cb8b6b4d51251e5961f7ae2e83538ab3a4fef3bcc773", - 0 - ], - [ - "000000000239224a0841738513c1eda712b73266ea958aa75f44a3985ebfab82", - 0 - ], - [ - "00000000002630c7c3586fcc19079300403c54dc293bcfdf8a9981f85a5c31bc", - 0 - ], - [ - "000000000028d8c34f44e51fd71f5401094a983f6566e6d08ce86ec5d1bd639c", - 0 - ], - [ - "00000000000dca95f1828adc3c37b4625f60aeb35a6614a4358322b7a6bc2f7d", - 0 - ], - [ - "00000000d72ec84fda18959ddc474d1a31a3a13b1d94695136c4810af8c01a0b", - 0 - ], - [ - "00000000327c29604996eb7f0a208160969ee4408a1cad277a956334f94e0f35", - 0 - ], - [ - "000000000e1bd41d009c1910fcfee7bf1cc1adb04b0b7a632ac36c1092f01bb7", - 0 - ], - [ - "000000000201a5afed48b9d095b949229e9882ef8bc96767be3097c87264dfb6", - 0 - ], - [ - "00000000003f28e8f3f9c80b1269bb0aa3b57501c12458550ef04fd43aca6a33", - 0 - ], - [ - "000000000029e09fc14e38a6a0103c8c67383f41af7d76998055682525f4ca89", - 0 - ], - [ - "00000000285ce297602995582ba5d32d583d618a6a92643566e25dd36cf2b7ab", - 0 - ], - [ - "00000000657045fa54fac52b8480dc84bd4c418940ba63679f4bd6add6a39962", - 0 - ], - [ - "0000000017b7bb58be05a47ff7c4ead27db750813d6bcf3f99cbcc35324cf445", - 0 - ], - [ - "00000000003a310e39b6df17f17450496b4f5c1593399bfa1ab8b4d39bac9b25", - 0 - ], - [ - "00000000000bfbc5294f003548a9636ebbcea3ba42577821266317676fbc363c", - 0 - ], - [ - "000000002329351dd70c24da2eea5ac19f65b6053c4611aa4eb93bcc2783c57e", - 0 - ], - [ - "000000004ce02f1005aa6fa4d158c6e4fce95ab053d88ae74881dd080c24e057", - 0 - ], - [ - "0000000000fdaaa54cdaade8cfb75245de0747c60c0307ad11be9fe154535565", - 0 - ], - [ - "0000000003dc49f7472f960eedb4fb2d1ccc8b0530ca6c75ed2bba9718b6f297", - 0 - ], - [ - "00000000014ca604d769d4b99fff03ae3ac84d1e8eb991c5dac7c3cd4d9e68ee", - 0 - ], - [ - "0000000000190ab8ecef3a3d5583563851672d81a4d4d952b8cf3bd503c655e5", - 0 - ], - [ - "00000000001204d263b607987fab11e1c19c94b7e3e674cc73cc2fb7b05fbf07", - 0 - ], - [ - "0000000000141e8d7f7ac359a8ae58e35ce6010c25ddd6f1881f41c0b939332e", - 0 - ], - [ - "00000000946344dd06ef5ddd13fb74f20c475daf911ff4e3f1dcdf64c330e274", - 0 - ], - [ - "00000000ec77a7892e48b85bcbaf404d16d7fc93747d7e9e3ba6195a9b6f1525", - 0 - ], - [ - "0000000018a305c04dea8e93e423ce9569872e0ec5af49d23a0e3872b0ad6297", - 0 - ], - [ - "00000000055e32c5f8a86c9a712eeb6440bbf9810ae6da12d0cea2493138a885", - 0 - ], - [ - "0000000001913fcbe67badbce4234e86e35a1ea867ecd69814b5f5ab039b7d4b", - 0 - ], - [ - "00000000002c71fe4403aee704720ceafd21f9f8c9c97a8bfbd25bb46223aa40", - 0 - ], - [ - "0000000000343a42da0c811836d0785c272591facd816f0e7fdcfb1109d8f9a8", - 0 - ], - [ - "00000000000309b182608b3eea7fafd0d72e3c79a0a3a9cda03cde3947e332e1", - 0 - ], - [ - "00000000000204cc04e421c3958a64d7bc024a474ce792d42ab5b48a5a6f3927", - 0 - ], - [ - "000000005eaa010e7255bd37e0b00780575074a74d889e17c4dbc578f917348d", - 0 - ], - [ - "00000000a0d425f62d9196c069286dc6635ded9d027de40070d397e45bd63e0e", - 0 - ], - [ - "000000003355fd37068ce2d5d2a94ef964eeb9b687f21f4a00850a3e6cc4a71f", - 0 - ], - [ - "000000000ca9148dabe9424cd8c96860c90d836ab25970a3e91856764e2e640c", - 0 - ], - [ - "0000000000bde23f829dde8edef35436be4b8978da21fd2c3a8100ef5334e3cc", - 0 - ], - [ - "000000000028bb26f1427fbfabeae65d55a9e59e18230713e40f0f7c9c2dee12", - 0 - ], - [ - "00000000002ac05422d254e597ee6b5e0f8be9b3e2f887486442d720c7766919", - 0 - ], - [ - "00000000000e36d0b6f187dd9601b1d1dcd987c3e0f6a081ffd039c7c5e32462", - 0 - ], - [ - "0000000000048d7b1f2a2a11fda34a5cfeea067ab03e482931e5a0f463f438ba", - 0 - ], - [ - "00000000f780ab88c8a4f4247573a749fbb087a4e3fb6a7d29926de8a9ab3462", - 0 - ], - [ - "000000000313bbe6a940e6a8c40ba091aa1ebbaad135bbbff3ed8ae07cf574d2", - 0 - ], - [ - "000000001d4ab29721aa2722482562670a0d71dc1eb73231c5dafb64756b04e8", - 0 - ], - [ - "0000000006588bcbdec38d19962b96cf0352cbf1b90f3379cc6787d018cdb96d", - 0 - ], - [ - "000000000022e79539a21ac24f9daa2cbddf2bb4a3125f88a5efc20d13ea856b", - 0 - ], - [ - "0000000000dd284b7fee584cc578a10fbe57e8efe6bf6ebacb23c0ac5d46cdf7", - 0 - ], - [ - "00000000001451143787f411c93d5506065c3fb597966f2fd7a4a5c078ee6aa2", - 0 - ], - [ - "00000000000ca977394af1e414dc1f9d83efa007f7226e11d3a00f59a1fdfad1", - 0 - ], - [ - "0000000000011f8caa80580e7a796bbce5b84e60731bf48e03c6ff5c6bba868e", - 0 - ], - [ - "000000000001705beb1376af1af08b437acef6befbe7d3b60c5fbaf6bb7f38c9", - 0 - ], - [ - "000000000000c838f1f45422d93ca9b5838368a37423efa8439ee24b2bf247a2", - 0 - ], - [ - "00000000000111ad857d31d07fdc8b32d17af2522c18bdaccfef449b29d17362", - 0 - ], - [ - "000000000000312a7718fc616b0ecfdbf6066f71ec1a4a8c43f50f02f61cc398", - 0 - ], - [ - "0000000000007d232b217a59b804ef67091c5720a5460c2c16bf97b97a24801e", - 0 - ], - [ - "000000000000177235c33695aced585685b4c500eb76e72caad02e17503900eb", - 0 - ], - [ - "00000000000037f5c5890da7a8e2acd2b0669ad7db648ac43140c637a1c81637", - 0 - ], - [ - "0000000000002123904063f223bc35135c426a4f9a0b74c1907e837b810f0321", - 0 - ], - [ - "0000000000000961db809da357d91a9341170fafef9f24896d8730bd05cf3f96", - 0 - ], - [ - "000000000d2e8fcd05eb874e98cfc3a6e239f6974950e6f50b0487513ecab760", - 0 - ], - [ - "00000000017e362508c8db23fae0431eaed708d9db13e48fd5d318066bf6733f", - 0 - ], - [ - "000000000011b2bc4fe36f90b7ba5a62f974db250bfdc285b70c71148023c7e3", - 0 - ], - [ - "000000000001be28570b378dd5dd2eb3aa495c229913b6757fe8900dfa3cce99", - 0 - ], - [ - "0000000000242bd0bb16d0a5324e0b4b5a83697dabb3b4a059084557478e50b9", - 0 - ], - [ - "0000000000d8ce69d18da32ed52e503d6b5ad48d970b90545f956b2d2af2edf6", - 0 - ], - [ - "0000000000366655bf0cb3dd0cd7801e0adbd26b5b441b77a9e3642597effb00", - 0 - ], - [ - "00000000000dc7aa00d4607ca8374d40d1187f1c084b620edb45fc39bc8d2db8", - 0 - ], - [ - "000000000003baf60d9c6e70a765cf517f66a124509191188e9547ad09edf68b", - 0 - ], - [ - "000000000000e0f476893b8fb4d37e855353075fde73dbc1fe181cc956349f19", - 0 - ], - [ - "00000000000032ed16b7de758abadf4a4fb2df7a101ff275c51f29e1555a89a5", - 0 - ], - [ - "0000000000000a564d03f0f2fe20f6fb5f038d931f732d817641cd7fff3b0acd", - 0 - ], - [ - "000000000000011aa4d0fdcea8d4ca85cd5d548e322e2b6abd17f8444be855c5", - 0 - ], - [ - "0000000000000610588540267a0eb544531047d4c8af0f21fca7cd3d96205cfc", - 0 - ], - [ - "00000000000002770dab5e14843149df8f76b8dc8458ed3ed2ed8a14a6e2e564", - 0 - ], - [ - "00000000000006b70ebc9f75bd32f466602cbd4b86c3c2d2379059542bb8bec6", - 0 - ], - [ - "00000000000000ef579af389fa7674f98a2371063fa8b218c5ca0ad94e21b896", - 0 - ], - [ - "000000000000021b6108dc988f9153383f9501ab9001109aa87902ddd4c8a4d1", - 0 - ], - [ - "000000000000022c02ff22bc0af5201f0e1a14a75879c494731e4fbf999218c8", - 0 - ], - [ - "000000000000032651c988edc1ccd08e82b888cbb8135e24a958ac0c0b640d5d", - 0 - ], - [ - "000000000000015aefdfa0790bed326c38c358c07aac0674f5b2e771258b8df3", - 0 - ], - [ - "00000000000000822e1534c86afef911b67d3fa20cf2b12d93d20d64005f54d7", - 0 - ], - [ - "00000000000000338b871276768c923b1c603fd6150bd054c2287e532e61de7f", - 0 - ], - [ - "00000000000002d0af52c0cae894bf836b61137ace2bd7500abd13a584c02741", - 0 - ], - [ - "000000006f8443a458f38d8731821c07a2fda0ecdbb1cf797f541844d468ce0c", - 0 - ], - [ - "0000000000b6fbd8b4e227f5514979a61d8b0b918d2adc154e585ca926386704", - 0 - ], - [ - "000000000f4f5e49b10278e27d9dee15b92f9d4a257138a206831e0c00188767", - 0 - ], - [ - "0000000002c7e9769bd8ae9906fc5682e937b5c31ab5b5b86e4d70af2c15a95c", - 0 - ], - [ - "0000000000f68a1db8cd387e0a2f93f45149fe1ee4a230bb386313bdd42058e8", - 0 - ], - [ - "0000000000f0f65c360c8f0f9853ad1142f16675dc1175d61afdbef977776b25", - 0 - ], - [ - "000000000004f734e634156511cbef7dfefebdf317e7488aa6c2562572d7ecb7", - 0 - ], - [ - "0000000000002a46a7a16787e8317dc567ae26816324c2035be0186ba54d5cb8", - 0 - ], - [ - "000000000001a593e6f01875b77e270163538d88452779bb557df7c2607c28e0", - 0 - ], - [ - "0000000000004f24cfafa10bd50a452535f64be577a6161e51c7c71542f654c4", - 0 - ], - [ - "00000000597cce73e84b63f08cfcb9b01f5e7621752d8c8e08fabbd6ab5c0dd5", - 0 - ], - [ - "000000007cad379df01247771fff471bc99faea1b86218602f45ab13efc5e9f6", - 0 - ], - [ - "000000000d6085aab25892be49c49d6c0a3949befdc3ddce2faa46b104e1e804", - 0 - ], - [ - "0000000002be5996786b42d6a229093896aea9966b1854ea261e01e84da1f420", - 0 - ], - [ - "00000000002684b72056e270b115d80b12b2f68eac7412355287226aecd9b5e0", - 0 - ], - [ - "0000000079ea27efb24366c87856a9e371c56fcbd59d09d3164a5c2fc15fcbca", - 0 - ], - [ - "000000001694120525dba4548ca54087544da1fbefa51c38f0208d683418825d", - 0 - ], - [ - "000000000693e80d372938f3553151ab9d0a9a6922182591c701df739dc9a502", - 0 - ], - [ - "0000000002950d9cb23c8511937811910b712f73d448e6fdc2e39e029b86848b", - 0 - ], - [ - "000000000091c40056c6a48f33db17764af89c01f62ae653aa5e494146164cee", - 0 - ], - [ - "00000000001f373c47e1a39af4e1ebcd8c88411ec49d6bd520c2781564070971", - 0 - ], - [ - "00000000000809ca4b2170c57958709b867095b1972d80a2ee55359fbd0940fe", - 0 - ], - [ - "0000000000038e7bd66fc3308447b1370dbdd0661c427c512bdbc641ff360fb2", - 0 - ], - [ - "000000009a3325df76e2de1fc1970cc2f241fa8a41da9ad745a0d9666d9ff51d", - 0 - ], - [ - "000000003176e92ff837bf43a48a995c1a321b166475f586ffb4b962e0254a4a", - 0 - ], - [ - "0000000001ae3292e81ca3859b75bccd5bff825cd9f496efd085160c716ed05e", - 0 - ], - [ - "00000000033bdac4f0d36bb912fba28bb5caa54d1b611759a10f79ff3c969cf2", - 0 - ], - [ - "00000000004c6db7fa0e2c9f08693abfeb128c5827b511a5c46c623a103b416b", - 0 - ], - [ - "00000000003d87f48bb95e9431760d0c5f4f93c77d02fce9dd1673e9f5b01029", - 0 - ], - [ - "00000000000e214fc3d8b97571eb75d248ca29f8e25a584c33de8488ceee72b0", - 0 - ], - [ - "00000000000133269b7159b828700d02de770a8cbd91f3d166e6bbc95d8e0dfc", - 0 - ], - [ - "000000000000cc92e2dd933a08f7fd87f84451627982fb66583587858217c059", - 0 - ], - [ - "00000000000030708136c20c4c8216314005b3cb5c551ded33b26cf64d2ff47d", - 0 - ], - [ - "00000000c472a1341d479ed02f31b699e448c035049a7092670b38f4ec6121f0", - 0 - ], - [ - "000000000a358834d6eed41b9b7161a338aba53828111414cdea7552ed15548a", - 0 - ], - [ - "000000000e13e77372daea775c8358916e57ed11835899c14e5140ed9be11089", - 0 - ], - [ - "00000000008252cd0931f94b2465bd4f93e4bfeec6697962c5b034cf3d12cf7c", - 0 - ], - [ - "00000000019812cd6cde3a43831234be71e68118be24a80161349b8b327acb5b", - 0 - ], - [ - "00000000005865499f301adfb59f8380743e4c3b3ab220ca4eb97dc6628df626", - 0 - ], - [ - "000000000015f77e1e61329560a4378eb401fa5bf0ef90b0a014a4d7857ca7a8", - 0 - ], - [ - "00000000e9cbcbb625e8a463ba8e7f14be46ba9538ffe93338784ccad3d992e8", - 0 - ], - [ - "000000000fb27169efcc2873cfaac223ebb91cc5e1e5ad7e9a312d42bedf7c42", - 0 - ], - [ - "000000000c9c96d62ebfbf3fa4003f1d46d175140ab084dee17e8125fa40f24a", - 0 - ], - [ - "000000000311e3a766b1ab2064b68a344a561eb496d595126808ffb166c71cc1", - 0 - ], - [ - "00000000677568c82262ac3a4ca3f909bdfb0b35145ad490fa3fbdc719d06b91", - 0 - ], - [ - "000000000ee77ba9ab657e51fd9140f5c9b46731d9341e98188f929c97d04746", - 0 - ], - [ - "0000000008a67eb9c91a6d74168f3f385270fa942ea00bdd31924d1b6ea11148", - 0 - ], - [ - "00000000017f93c9e0026e90d579e18c83b4a8557f0c00e9b85ab164cf4466c5", - 0 - ], - [ - "0000000000994efa379235c03711a8e6b29895d928b5fde96cb01c02374c0602", - 0 - ], - [ - "00000000b3be9f23c943d71d7c7dbdf6dd672d77a712f6c83e9796a85e4379f2", - 0 - ], - [ - "000000000713e1089b0b2bdcba462b740c9396f822f1c73e090713978a7f1314", - 0 - ], - [ - "0000000002fc44d358401a7ac9ce4ddcb17f3cbac08e40242e755e60ab2292ed", - 0 - ], - [ - "00000000021ef2c04fd30be7049f73b9a8353ac96a467dd5f0b9c1457be1bc5e", - 0 - ], - [ - "000000000023b95b440ccbbdcb914172cf675cd15d6111bd7f5a436a4925d36e", - 0 - ], - [ - "00000000001983521dbffd1b742a6d4b5dfda3f46579fbbdd83a2ebf9a039bec", - 0 - ], - [ - "0000000000044d53dbea312432e68fa90dc2148946f613216dbdeec86f6a67c1", - 0 - ], - [ - "00000000000107667692f12d21a55a72ff1dce828f96872e36c35bfbae475a8d", - 0 - ], - [ - "000000000000252d1d0c01744ec25af801ef7c57e2581c95295070b6a8a85bd5", - 0 - ], - [ - "000000001c1da54e16dc06158677024d9e74bff39bfaec83434ac33673fcc251", - 0 - ], - [ - "00000000b4d0c6ae86bfdf7ba4c205fc3e6b3b6d63836b85e30e9d8bac922301", - 0 - ], - [ - "000000002b16179cb022bf678bd847dd6fc1908d0df04abf0c7874981eb33ee7", - 0 - ], - [ - "000000000e6783554aae41856424d184dc4fa061f40676efd107e6f933a25641", - 0 - ], - [ - "00000000005ae4acbab519895b4b523d97a09e381c9e4b044e642f73b8c0f1b0", - 0 - ], - [ - "000000000010372b59c9595d947064804b75ab21868dd075a3842ab7d2df6181", - 0 - ], - [ - "00000000002f9f587ea304093be049d3142ac0c92f9c68928a4f82d12b929b69", - 0 - ], - [ - "000000000005d4cae51b3c76dc3c61bed0c265c4f228c0c4d1d3d147146c34eb", - 0 - ], - [ - "000000000001a5b6c0e0a0b485a490cb52ccdf9b22596656039b51545bb07be5", - 0 - ], - [ - "000000000000d723d0976338edf55d08edab995dd6283cbb688855f0dca6e8f5", - 0 - ], - [ - "00000000bfebfae90208a82c7fa06c0f61674dbf1e4f9162e370656c38d611bb", - 0 - ], - [ - "000000000c91cd144b2a92ab5024c87f70cc1d76a4a7f26a82a98c5aaad62850", - 0 - ], - [ - "00000000077c8114eb5cfb69c3924c699d0c70334360dd1daa95db0db4816953", - 0 - ], - [ - "000000000348a6443e091db8f68e88a10afad7c6e3e5392247902c4b4feade43", - 0 - ], - [ - "0000000000d63b70351e05829ad8a56336521b361b0d50eb7ea1f5b46c25b00a", - 0 - ], - [ - "00000000004658603163f0ede572120a1bbfce8d313aa282ae54d2ffd9fe9079", - 0 - ], - [ - "0000000000048063b410c793db34856f23acfb19a0ce72f5997fa572773378c8", - 0 - ], - [ - "00000000000228fb6e587fa593ff8b4764064bba8bfc2f43ba5b1f12af33d04a", - 0 - ], - [ - "00000000000082e3ddb75c0ea2a98922b1556ce10346f9bb0cedd97ccb3fdf62", - 0 - ], - [ - "00000000000005571b54d4886b44b81c21dfbefa554cd7c23430e5aeff6b5ae2", - 0 - ], - [ - "00000000306a603ca1a0d961e08e103a9f13f3615163c3373d1bd2a67cadc2a7", - 0 - ], - [ - "00000000195d93ba7ae19832b622de86ebdadf3c78f1751ef2b2e9b0e3a530d8", - 0 - ], - [ - "0000000000476d0d00cbc68bb20b4893f0e608b02a1e029b8c6c73e169c49e69", - 0 - ], - [ - "000000000051348044bc10fc05960c244c3ccd3b3b6c145ffd9958a1c8bc0215", - 0 - ], - [ - "0000000001e4df369203badca9aedc28c240d592b12d284ce0b0463fc7537c09", - 0 - ], - [ - "000000000091cc1ccd448b0ec9185618a84dea96f52477cfb9b9ca2b60cebe83", - 0 - ], - [ - "000000000024a50299c0ef0c6dec9c64336b6cf5c1a1b0013e22fd4fcee1d7d1", - 0 - ], - [ - "00000000000349248c1df06c3783d1270cd97ce7f605b9036fca0fdc2f0fbb96", - 0 - ], - [ - "000000000001afe6793e7427a3d780876d26eb7f2ded92563f991bf7302aea69", - 0 - ], - [ - "0000000000007148006e139e24d9fccc307661c9a0cbcd1af983487c2f0780c9", - 0 - ], - [ - "0000000000002734722a341984738177a3f6f264291424e4984f2128d921bf29", - 0 - ], - [ - "000000000109b02caaa95e49a477757a41a42daed40e92f54fa09e63f5538cd2", - 0 - ], - [ - "000000009a11c7ff8b8fa7fbff5a04c25906f701ab5bd67195736f9ccc839ab9", - 0 - ], - [ - "000000002b1d77f8e0cd60af1c62ef6d381e8905665b15a7fbc546d0c1a45e18", - 0 - ], - [ - "0000000002588cb017de9e2f23cea7edc5082f1b3faec890f9252d556efeac40", - 0 - ], - [ - "00000000008b07f177adc24a4b1a64d2dbcfbcc903ba861d493e11d6b33af7dc", - 0 - ], - [ - "0000000000bab8db5020aa8e052165275e8eb3e7c843533246bf6e4c8374757e", - 0 - ], - [ - "0000000000138488fdca8bfc327e6dbd6c72c5f1dc5868d9c0ea886665b9b56b", - 0 - ], - [ - "0000000000094021fc954efbf08be667fef1b817e8715d4093a561fc30264aa7", - 0 - ], - [ - "000000000000e8183e64072db79adfc6c09b650c4178001be3fade4050b06005", - 0 - ], - [ - "0000000000004c93e8661c75974cd191c68dd66999da4f70d039c0ba4a12b970", - 0 - ], - [ - "00000000000021c675b3ec404bb996f5e68f9eeceeac6946e5a6822987824d33", - 0 - ], - [ - "0000000000000ad85684d30f25d1ec34638f099df2f33b418a07307c68fe3c2d", - 0 - ], - [ - "000000000009c6add76ac42a1942c4ce74d25d1b8975d4e3ac8932185e785a44", - 0 - ], - [ - "000000001e7d828d354716881683eb6fb5caec5d91afce298e4e3bcee9574924", - 0 - ], - [ - "000000000a0e438ab203d8fd3e56100f2f14759f704bff6c699df0bb4e9aad64", - 0 - ], - [ - "000000000b7d5c2895df8bc1fdf5d31e0f663564cb5cff3b18642c44a71b6248", - 0 - ], - [ - "000000000193209ecd92fce00a75975446423d94a325ed525c15d5ab921da273", - 0 - ], - [ - "000000000020835bdc30ac67efdbc785d15186914bc14e86387f97450df46418", - 0 - ], - [ - "00000000000c9078321f0030214c75e170b01ec664d39bab1b1e48460a54eb63", - 0 - ], - [ - "00000000000ac68b63d486ade190dc9108eb3730d25e7537649fe21c30e0121f", - 0 - ], - [ - "000000000002a94dfc5f4b677b251a7a7647dbb99c0803df8658222227fe3e3f", - 0 - ], - [ - "000000000000b076bbef0e50593b1595ffb3d571e7ad95dbdf06dca8824ef7f3", - 0 - ], - [ - "000000000000167075c8bcd24233d25cd268271c0e8fcb6f301ee1b6f6ff0341", - 0 - ], - [ - "00000000013107aa587bcf12ac445330ff0325d73c5253f7e6a49ed8c50257bb", - 0 - ], - [ - "00000000090ff53d49c9ffd51511af8d5cba2038a8e25e3b17186b1bc941f43d", - 0 - ], - [ - "000000000d9e704d5607f77f8983cc56069571a3761d5bd5da55f05ec5d8e844", - 0 - ], - [ - "0000000002b2b4c0950fb6390f0ae860840e84eb0a82e5e8a9bc37c14bbf43b0", - 0 - ], - [ - "0000000000be10137a2434dce1d97850b768ce878c1c80ec905f6e9f21e65fa7", - 0 - ], - [ - "00000000005cd966f80183d4c048e63a5c14f649298dfd261d989d9e3c026bf4", - 0 - ], - [ - "00000000000e8f30e55006a4082380c4b1a372b7ad919d3a9b0a52fe5ee881d3", - 0 - ], - [ - "0000000000018c70a4c27bdba237ad19ebae5d3ca23f1394ccc746d73669a1c4", - 0 - ], - [ - "0000000000022acc8432c883953227786f7a6560aeaf0176d232c8affa5b25b4", - 0 - ], - [ - "0000000000001854e95b28b4efcb2cfeb08c76d8cf1fb03f2055b3fb758f3a1c", - 0 - ], - [ - "000000000000187080c2c39f5a3ea8be72ac4d3ec0d16b21cd34f1541bef23be", - 0 - ], - [ - "0000000000001593766a3c63b524f658ec7690df467cc7bbcebbdb56385500d4", - 0 - ], - [ - "00000000000012d6966dc51a41f2c617192169ec8418405e164ba83b9f7ecdfe", - 0 - ], - [ - "0000000000001d0c7d0a2605e127b00448b71e756ad96625116ab8ca18f74900", - 0 - ], - [ - "000000000009cb439ea49282d257595ad1f7602856c16cc26fff423f7783c792", - 0 - ], - [ - "0000000000889282b98336c994d7420a639221e0484b511227fd616d78dbd028", - 0 - ], - [ - "000000000071a4a2ad6767864bd21239c74c9912a40ca9fd3b209e21b66460d9", - 0 - ], - [ - "0000000000f3ed2c3c9a7c3a7291e859cecba8cf9243d23a4892e6be8ea9b70f", - 0 - ], - [ - "00000000006a4258ffdff8b7f6f4f685ce18c6eb1d7a1cf501ca9e02fcb7620a", - 0 - ], - [ - "00000000004af78f1a109d1267a9c24d69c6a4b30fea49f0efa6c8834cf394f9", - 0 - ], - [ - "0000000000193bf3efbb145747198470a81b2cd33c991057676742d5c22a64b2", - 0 - ], - [ - "000000000006b436798c7e4a8c3bdbf054a66707feee5a18ce9ca57eb95bb48a", - 0 - ], - [ - "0000000000001db50c7caa3a02ea4f173343f958f334a8bf3f8638add9e69b34", - 0 - ], - [ - "0000000000003c621629cc0bcec5968d61d2e42c6673de4d46555118ad5001d8", - 0 - ], - [ - "0000000000001262bef2918265f6dd4534013a4650444054fb4f5e490c5ed57b", - 0 - ], - [ - "0000000000000120ceee972d70cc84430006645997c7337976c673bd75cbef2b", - 0 - ], - [ - "00000000ba16134dc0c418a116b97ad5deccd6bf6e3daa028a8a6a80d7823faf", - 0 - ], - [ - "00000000a1a00d6d6fe0660e63402a5a7c7248589211594d37fd800456ce84b6", - 0 - ], - [ - "00000000394766cec78f962c29aaa715b66e3ad34e1f2323dba45e087cb3b395", - 0 - ], - [ - "0000000008b15a3020676f5e084210ecc05f646885eca1cf6a10e9ae9e3995cc", - 0 - ], - [ - "0000000002cf7eb98abe784f6e516670a88b9028a6faabfd099a364c2dc5c42b", - 0 - ], - [ - "000000000054015fec337a9ee43eea501d2292f031f5bc1f09758d20f5cd3135", - 0 - ], - [ - "0000000000068d24d31a9f1192d848155a2f90939627bc456c9a337135a923fa", - 0 - ], - [ - "000000000006262bd09358258edcc455f9ba46b7f9d6e69d0f6b9da89488a4a5", - 0 - ], - [ - "000000000002327bf77ae67961463ea98a78dab06c24ac7d58b1727c5f856626", - 0 - ], - [ - "0000000000006672235c1606fbacd7861b16b267d203b4d687708eeb1fc25e6d", - 0 - ], - [ - "000000000000ac0c9a39a47313a8715f125c46d6ea8be8741b99b1db4a8aae47", - 0 - ], - [ - "0000000000007e93f6578e7856aae0ecf6341e1312664d9e1d812ff254c37ae6", - 0 - ], - [ - "0000000000002a980acdb1443926875e7d4a57859b2b45ce3fa92c7716319f62", - 0 - ], - [ - "0000000000683bfd82c63514bc58a80daf699a6bcd040bb2a499540baf52463d", - 0 - ], - [ - "00000000373e6262928d7a6cac965b294aef35f90b72c85100ef91501775e06a", - 0 - ], - [ - "0000000000f7bc44061b65c62d4d7747138df127dd2a30f583c3ebb66a25c7a4", - 0 - ], - [ - "000000000212a71c38d0e13ab7c5646c949d4b7ca23afedbe351a43b7607043b", - 0 - ], - [ - "0000000000a836e88f76ee5dcca1e884572f32f4460a3b024280738d76e98ced", - 0 - ], - [ - "0000000000413f6c1b1c9841961636bb3290f2410ba0731f3522c4ff3faa2e0e", - 0 - ], - [ - "0000000000082336107412226110ab2a53016d4faad4deec048828507a300248", - 0 - ], - [ - "000000000000a91e7a3f35a23f01621dd051e314da617714991467131808d3bf", - 0 - ], - [ - "000000000000cd6576950f6f238227c3ba7f62405ed1bf3af4878c6dc1b04635", - 0 - ], - [ - "0000000000674099e9741e44da03e9531402a2607a19a65660b57470340828db", - 0 - ], - [ - "0000000030c4744001ae85f9e6b46ed0664449927b86b8fbf25b22b851d23671", - 0 - ], - [ - "00000000002f5095ad1a12eb9eedf88ce1e7268368461b6b4e10051148f436cb", - 0 - ], - [ - "000000000057d3e2a77eadb8b9613cb839ab02a96094dd5d0a6d1f09026c3936", - 0 - ], - [ - "00000000004e0a28be887d6ed037cd9102cbbda7d6c9e584ba51f2c2dce96232", - 0 - ], - [ - "0000000000211346d8099f7ecea72481c4cd45591f5e0d7e347725ac2162f142", - 0 - ], - [ - "0000000000199ae9fc06c5acee766db6033b86f76c266cadefe1461c611c2198", - 0 - ], - [ - "00000000004c9e5748558d4f5a75bc824171e3b958152dfd6844330f1e907f8c", - 0 - ], - [ - "0000000000137addf1521361dad1ee007eb9e6dd4eb8441492ebfaa3c240d556", - 0 - ], - [ - "000000000054d4c77bb7964e5327c35760d87b890ea336aec5ecdeb783350738", - 0 - ], - [ - "00000000006b7b06d04818e97a4df66164b471912f88d9cd02de4af6c8bbe74f", - 0 - ], - [ - "0000000000380fa9858e3e90335c061a3776a26bee1e8b6851de33ec63670782", - 0 - ], - [ - "00000000000842598b03fb79ce7386e9f9181a02dcf1effc8f70d3ff7368ccd5", - 0 - ], - [ - "000000000003d3475edecd733fc7b82432882d9c9f1350a98ef8921b87db4dec", - 0 - ], - [ - "00000000000000e330a8d57a38dbcc0b0a5dc7a4210f231b8082b9be5f9e4bce", - 0 - ], - [ - "000000000000218ff87fd50cfba2fd04203a78d2600cb2c4dcb039d803426e19", - 0 - ], - [ - "00000000007c96e6e3ed3146260348ac79ea7dc2ec2ae6bf8dc203400a37721d", - 0 - ], - [ - "000000005abaa10bf7260470c28ba32f1755b4cfd3734aad580681e39a9605a5", - 0 - ], - [ - "00000000005e77c226e6fffccafa56055e68f0ea0a30101e6a243ab9b3e07db0", - 0 - ], - [ - "0000000000e989fe27f85b89c1e852d7bc94b09033cc6c8b32fbbbd9383a9ae1", - 0 - ], - [ - "000000000091a1e962438583146293ef34156962445ffc5e81e4d0fe327d37ac", - 0 - ], - [ - "0000000000477978a6903217e2817d10e99bdfedb4f8bc396b96fd5b0b93b522", - 0 - ], - [ - "00000000000bfd9e5f13a9c03c48e8b58a937cf1ae2849160f1ca11f8fcced3c", - 0 - ], - [ - "00000000000158dd3c31b6379887b4353ef2898c03b7ce55458fcd57cb6f0639", - 0 - ], - [ - "00000000000029d7009eb56b9d38366005576b82a9b59fc845522a34ad36a38a", - 0 - ], - [ - "0000000000e6e207a82b8ad7136352204bb8e9ccfcd25885a715d3c65cbee997", - 0 - ], - [ - "0000000000fadc4429f50fc534ccac4db5e51a313df25034d6c5c25f7e83448c", - 0 - ], - [ - "000000000019c58defcfdab6c6ab9497685e61118effda4c2613bf44be19fcbd", - 0 - ], - [ - "000000000006cf444d846093c5045d42ddc0986ca805f261476d0fd2eb474c39", - 0 - ], - [ - "0000000000d0856a3d6a1e5b1ac7e388cc029bd8410b3b1489598974fe470568", - 0 - ], - [ - "00000000003d9aae63ed532b78082ca5386211e22410fd24ebd5318d1a4cd1da", - 0 - ], - [ - "00000000000345003879f86021a6d5e3fe93813246818c145947b7e225691177", - 0 - ], - [ - "00000000000175393730cde3e49de7af2b81ae736eee005a9f9c4a1e878c52ec", - 0 - ], - [ - "00000000000087a8c621c879aec2a897258632d6aa631b9a38ba4d564e08682a", - 0 - ], - [ - "0000000000002ea641b2975935bd9caf337b51ac9f9bb90a54f6ea6ee5d3112b", - 0 - ], - [ - "0000000000000c544f9b6a8cbab6d25caf949875622bf75139234850b10affe1", - 0 - ], - [ - "0000000000000f66fc4e37232a29f3389c493863a980d58a1d570eddd5268999", - 0 - ], - [ - "00000000001213fe2bbb8aacb1fc14983586e09db964151cb507956a81b35f25", - 0 - ], - [ - "0000000000ba82c2160602ddc1913bc4c133ad0af8848e014367c84110d00e05", - 0 - ], - [ - "0000000000b7a98b364b1cf9521275a915c7a1b3a0f0c052c7d8efb620ec0870", - 0 - ], - [ - "000000000047dc62db23540ab4aee43e54812aedb623a2a158aa3244fc784722", - 0 - ], - [ - "00000000005291002da10e53c3855882251a6e5a425b5e639ef9be3bd05767ca", - 0 - ], - [ - "00000000005ffbcbc0d9b380584bdc78050a6f0c3582b4c9c5103a150cbc71f5", - 0 - ], - [ - "00000000000a7a69cc06b0a68b27a8fa5d29727ec3b6db8d32d61cf7489b5ff3", - 0 - ], - [ - "000000000007212eb8c49758d98cefaa6098da2b877a6055be341f5f7c0ad301", - 0 - ], - [ - "000000000068d1099d8cf3f43f6d164f2925b1d52ede75640cc65ca020e1de1c", - 0 - ], - [ - "0000000008d5ddef4468a4414bd08184c2eba0ec536b85a743b1091828a6a884", - 0 - ], - [ - "000000000acae40db93b589783b0cde70b98552955cb3c12f08de1b417d9008d", - 0 - ], - [ - "000000000066a51eaa3a54036f338719da3d5779180c0bc3787b533410de90e5", - 0 - ], - [ - "00000000008b521677a6e897950aac69640e52efb01b7af10bba3820ecd09a89", - 0 - ], - [ - "00000000001823f0e399311cab0fcf57403e094feebf99b22030bafd2004da87", - 0 - ], - [ - "00000000000bf821c2abf5bcd00ca96439ddf5b0b593be5601145fda5338efdc", - 0 - ], - [ - "000000000003f4fd19b2af0141289177014ecc6dce6ea8fb50bab93d4a291095", - 0 - ], - [ - "00000000000011842d892a02e55ca594caddc9f3cea1979ddffefc070eda8498", - 0 - ], - [ - "000000000000208aa0259d20f51c0e7b8895e18a93aea79af9b3832e710ef134", - 0 - ], - [ - "00000000000007218f849e72dee1f7fb6fcf36f3b6745c6468187ed2ed13287f", - 0 - ], - [ - "00000000000f79f656cae641c2b74554c6ecd673c0c7550671c4c2af940661b3", - 0 - ], - [ - "0000000000199b4d178c05fd1c3154c9a4632eadc7bfc734c4522176c977ce8a", - 0 - ], - [ - "00000000085d0682d481635cb2e6de2e4d9884589455a86194f0b222f9acb3c6", - 0 - ], - [ - "00000000015972a5a6786a14b009bf582c4bbf7b9854591dd8d26f82b43ddaef", - 0 - ], - [ - "000000000064bf72b7bdbfcbe96dbbd0efcaf7aa94c0f92cb4e6662819468fe4", - 0 - ], - [ - "00000000003df36b7962bb4ad62266c462382eddc93f4bfeac464b95f7a89ee9", - 0 - ], - [ - "000000000006516d3a9f424eb61db5dfb85aeee29708b78c65d24827bd926263", - 0 - ], - [ - "000000000001c1709fe1b294712638db356e89155650f6fbecde79ec47a92af7", - 0 - ], - [ - "000000000000dfc23251344b593c16c28cd195abcb337519d7bc82175721a033", - 0 - ], - [ - "0000000000000aae2dd2bf0b8581d137fcfa3d9c4cadbe3ef3834d7cae4268c0", - 0 - ], - [ - "000000000000092a5baff3d9a5ae87689b2afe668e71bac3b342c7d383f0060f", - 0 - ], - [ - "00000000000fa906eeff7d2e126698d88b8cda01d32ea2c039c26984daaa17a3", - 0 - ], - [ - "00000000002d4315e5bdc2bcfdb245b914130764a50943a2b2e02ea3acf5c47b", - 0 - ], - [ - "0000000000fc2bc9bb83e04cbe922d64719295bfef6320027725402306bcf1a0", - 0 - ], - [ - "000000000142690e7c334b97612746d6db208e6153bdfa8479d86d1b575feacd", - 0 - ], - [ - "0000000000629a7820e8cdbbed18dcfe16c992152badc745ca73b9b34e53fb0d", - 0 - ], - [ - "000000000023c2e9dbf3fe03248e40f4ec3fb2dc81ac573d5a6a4f490c701877", - 0 - ], - [ - "000000000013658a43b6d1c4be95fa36e32d3edf80716de3a8f7e98858016adb", - 0 - ], - [ - "000000000007c847295d8c4b6da9d8a64b57c3a2307e64387bf8882b9d35d6de", - 0 - ], - [ - "0000000000032bf90b823332af80bd2ea18f411f081c7dca8f2fe79d9215526b", - 0 - ], - [ - "000000000000001bc0655da6f24c6952e811006897a0c6dd8b6bd94f178636c8", - 0 - ], - [ - "0000000000001e1d09b15393190cf686e25488db7fcbc2f1ebacc8165fe6e3a0", - 0 - ], - [ - "00000000000cc79ae066badb4157def4067057cefd705bf87f1d832845a7ab36", - 0 - ], - [ - "000000000014408398244b94b4eff6b54875802ede6df2d1d21915333a195719", - 0 - ], - [ - "0000000000114135a1bc757110c05162fa649b694db9569be117e34832c87257", - 0 - ], - [ - "00000000009b15fb2bcee1af904989ba0761e4cddc6b3ee214c0bb07dac6211f", - 0 - ], - [ - "000000000012be506dde2c54adf355bdb41a457b0abec436202a3be73f0b052c", - 0 - ], - [ - "00000000000963760ceb5fc65570650d494805e05c9d753f3ea6d44247ad3d08", - 0 - ], - [ - "00000000000bfec54977673f68b6fe5f088398e697d778fa7987f8bab6a70825", - 0 - ], - [ - "000000000000e7f428bb413c17032c0031af0d26133ba93f744a5a0c16cf7e1a", - 0 - ], - [ - "00000000000036bc80378323c6eaff8ab350b6d89955f602960cb7c93d2feb4c", - 0 - ], - [ - "00000000000f0d5edcaeba823db17f366be49a80d91d15b77747c2e017b8c20a", - 0 - ], - [ - "00000000001ff8fd57798082ab5a7452ada211e1c3be38745155505601498829", - 0 - ], - [ - "000000000020f960b535eac585e5810ad64f158c1142f0eecd925c8058172933", - 0 - ], - [ - "0000000000067bd89409368d221507a160e5c45972eeb01efe210054fe8e7d85", - 0 - ], - [ - "00000000003521f2d5ea3232d4835ca6c6bae083ba90458f67d4cd765ce93b09", - 0 - ], - [ - "000000000005ab3ff3a0c484eff7b571fb78ce27d93f77a480074232e5ce0c1d", - 0 - ], - [ - "00000000001048c9eca7cc1cbb86946c04498052071f7e7c775bba565ada337c", - 0 - ], - [ - "00000000000154caacde41be616f924d7d478812148242fba85605eefec9ac61", - 0 - ], - [ - "000000000000c34f75bd6f338c0206a31a8d5021cc2ded51e88a6ef4fe686d10", - 0 - ], - [ - "0000000000001e0581d86c49a6ca14ba88639ef908abb09210b57989e06b1a1f", - 0 - ], - [ - "0000000000d0e6dc0bf830b50bde3e400e16ec4f772f92a55390e62d4aa73af3", - 0 - ], - [ - "00000000069c2501a2f32cc69af72a602ff674438ae04dd05516f72a71b9ab26", - 0 - ], - [ - "0000000000c926b38954550c9b8d363ff058c2eb135eebdb3e640cfa67df803d", - 0 - ], - [ - "000000000011e9ad9c18e9e2095c3662af5be1e918dff653758583aa45dc8197", - 0 - ], - [ - "0000000000f311624ff4dcdf07400d0d2fec8b16b14c1c16babc377a2d85ad21", - 0 - ], - [ - "00000000002e455cabfdc2a8955e8ddfe717b12efe5b80937b0c0ad6ac977fc5", - 0 - ], - [ - "00000000000fed8889a22339b340f599ac7908e790bfc3cfca9b78078a52d228", - 0 - ], - [ - "0000000000012ca4492956b3f859b00e5db14b54d422cd95c68c7150743db365", - 0 - ], - [ - "0000000000004c58e8f7bac59eb4a036764a4d8e0da51c0290858ab14fb72481", - 0 - ], - [ - "0000000000002f60bc99563ff5b4b800c176fe8bde95e8f968fd6b53d74c9cef", - 0 - ], - [ - "0000000000000bffd10a3fb0b5b86d8b2561f39d07f8a4c41dfa08e3e49b7db5", - 0 - ], - [ - "00000000000006a296be9cd8fd4e3145c146863adbe08b71831abb8a869d032c", - 0 - ], - [ - "0000000000000c557f496e82891039ff22e277bd604be6e2e8b95e519bee91f9", - 0 - ], - [ - "0000000000399b30d2111c4bf3051c1f7f2f35bba7ff290d92393341ae47df55", - 0 - ], - [ - "000000001f88733439e4e8d3c474504aed62037faa16f3845b4c671f69732e26", - 0 - ], - [ - "0000000018aa2f93d2ab76a7e2f1bf5b565b4a1b0ececb6ee46490984f6c0d4b", - 0 - ], - [ - "0000000005e22674fcf65ce7be896a0557205ab26d1f76d73a717f5f14a6d6ad", - 0 - ], - [ - "0000000000223d866b324c097973210f8fc715c9535908359d61d8e1ab2f0100", - 0 - ], - [ - "00000000002b321fd6452ab43849bd7a781953ec4485554e0fdc579f2a52c90a", - 0 - ], - [ - "0000000000173132748c51b5754b0341232325bd118455bf3c8d25164d3eb92a", - 0 - ], - [ - "00000000000143158cdea5fbb9453bbe1a7a900e6feba1e2193e4f5c106d9fba", - 0 - ], - [ - "0000000000014677751456af5630025b3d9921a4eafb4d36a06498f0c6a84c56", - 0 - ], - [ - "000000000000243976cf2d30ecd3cb1fd0b805fba4da92d2758f78e1c6f8ae92", - 0 - ], - [ - "0000000000001323db1ab3f247bcb1e92592004b43e4bed0966ed09f675cf269", - 0 - ], - [ - "000000000000017a410c22c4b6caf710f5ccf005d644caf276ea8626a538798d", - 0 - ], - [ - "0000000000170b2b1374e3a0dfdce2fbc5e302e1e0e9fb419dc057c9959902d1", - 0 - ], - [ - "000000000015b4fad4d929630487680cda2d3aada138c58cc08241ef6dd4ab09", - 0 - ], - [ - "00000000000abebab869f1620843d413a3d9e06dc7d9f5201a414d547ace1f99", - 0 - ], - [ - "00000000000b0bdaf05c2fe8b12ebd2372f49d8eabcfbccdadd68b5e5b7c9565", - 0 - ], - [ - "00000000000ca1af42ee1be2c8895d94f39dab5fcdbe0b4b4065f4be534e7294", - 0 - ], - [ - "000000000069d0cc8c0452bf86cff87db05232f801a162acab2d080d6e4e9ea9", - 0 - ], - [ - "000000000019c7f7685f5bdc3afbb5e978cb3f4f70fea7b2b410139741303b53", - 0 - ], - [ - "00000000000d3874ce21db78f4d1883ad9ae8b26c1d7c13f3d723ff85629d595", - 0 - ], - [ - "0000000000033f87c25275ff72b58630d8da90221f2c84bcbd77c8e615709f8b", - 0 - ], - [ - "000000000000dc72adaaae6483eb6737de7d21b3a24b2426330e80b078ceaed1", - 0 - ], - [ - "00000000000002fb1337228db02ac464565271f22f045c1b6ee5e449f057a829", - 0 - ], - [ - "00000000000001902376ff640d3088899af0819dbd15f602156a13ac2fc8e94e", - 0 - ], - [ - "000000000000007ee49761a1c8284a3b8acefa39e37e455be4773d648e2db794", - 0 - ], - [ - "00000000000005b4d495a77f57018dbc72bf47993d494349329a3c653f04ab93", - 0 - ], - [ - "000000000000009dcb3ae6d68828e2f5ccfd58780abb260354e74484106f81ce", - 0 - ], - [ - "00000000a3ceb118021fb42d39be52db951c6f852bb9a241046e972706f7329a", - 0 - ], - [ - "00000000574e8e1c27fa54c77b4e7cd1b79de070f0d3ad5b383206ab9777d983", - 0 - ], - [ - "0000000039d562f640c1743421d53e7e04c3e8ba222c339fff6f3d25b1d4a7fe", - 0 - ], - [ - "000000000001cb1559d55c697871e18d5c26800f77fb11587241bfbec3b15e26", - 0 - ], - [ - "000000000006e01a93090319756c7ca826ef655feb0cc2ef9abcc59d67de5e5b", - 0 - ], - [ - "000000000000a81aaf5a4c013032638a077af6aad8bc449d74daef8ad3a74419", - 0 - ], - [ - "00000000000087d0574963c1582f2161298e2de5e48f74566291ef9afc2be24a", - 0 - ], - [ - "0000000000033251e71c347cd663945fb68efe82a8c6666c0b41e93f1c46658d", - 0 - ], - [ - "000000000000f592857e6f0e4711b5b93fdf95f2b21a5963bde15be750a07908", - 0 - ], - [ - "0000000000004353c8426e18b942a5012934ddac8322b86d6ab98ed7c0ee86ed", - 0 - ], - [ - "00000000004f027845b699f42e7d0d30c530e99524c5f97186ce6a250a5fac42", - 0 - ], - [ - "000000002fc6407edc060df90785082834867331e6746a43ed34a26fbdc5df64", - 0 - ], - [ - "0000000000048733007c91ea3665bd4e1653b10799e3f43abee0fe830ffbb3ad", - 0 - ], - [ - "0000000000025a9b1c5afceba0c78c4b0320797acdc1ad50b4e040f148fbff7f", - 0 - ], - [ - "00000000007ca6d026d27387edc1c5570de41c61bacbcb1dad2c0f300b49e637", - 0 - ], - [ - "00000000000258f683a77ad509da82a4fab24188fdb4b4690e212c50794a9abb", - 0 - ], - [ - "0000000000015111bce7b6ac13c930484e14e31e13e43355cb4d63c8f1782440", - 0 - ], - [ - "000000000001ca074fdecac7749d95f28f10c83a7e13787fd865bfbe505382bc", - 0 - ], - [ - "0000000000001c11a6505dd44ab405fdc07ddfc015f3c1166a5d9352ab58b52c", - 0 - ], - [ - "0000000000000c83f7f8e1cab4efa08d6c68c4555fb6ab542e01b87edd8f56ac", - 0 - ], - [ - "00000000000009561d0ceba15388573d2a994aff24512ec3ed7d7881aa0997dd", - 0 - ], - [ - "00000000007dc7cfbbb94db1fbc076a70a1252fd595686b4d75b2ea77ed6ee9e", - 0 - ], - [ - "00000000000251feb68a8c90852f73aeb29ebda191038737b7edd37c9475f4ac", - 0 - ], - [ - "0000000000013f9a97045ea9047654e514951288911b2c3986787c27bab49106", - 0 - ], - [ - "0000000006e8c37735c61f22bec69f4cb7eba03172349e7012b7704652f3e83a", - 0 - ], - [ - "0000000001f341add5657043d8e50e53ba079fe24966a2668f904be5579c84b9", - 0 - ], - [ - "000000000029a6275cd477d77939424bd183c2f1308a9912f45aa7cc9ed13b56", - 0 - ], - [ - "00000000000a0336239e5e1faedf5bd2eedf38c9a5ba34a832356aea70aeb102", - 0 - ], - [ - "000000000003c1a2b25093a64eb624055f6a3a26e18b8e7ea2d9382ec7a3609a", - 0 - ], - [ - "000000000001bd89bf7e8740ce22adfa6e8793bd1716a647e558ed1742ee8329", - 0 - ], - [ - "0000000000001320421f1bb2c94000e11a621f581fc277c0e2911c3b89f680bd", - 0 - ], - [ - "000000000054ce90a949f5ae2d43c4ace599668c6ccbc50620f6d5705922ea7c", - 0 - ], - [ - "00000000200d16fea4857e6b73169cc593421a57971acdbcaf87a31d7d8d72c8", - 0 - ], - [ - "0000000000e75602181c88f713b91c49de291ed878be305d25b75c0ec5fbe942", - 0 - ], - [ - "000000000081f8169c3c3665f20351dc0fe499612ae232ec0b55858a8e5dc6e9", - 0 - ], - [ - "0000000000d7ad232e7593fb435d125343b8113bbdb3705ab58ac0e18c26cc79", - 0 - ], - [ - "0000000000076df615d887e33193ca2dc0f2fc0e70744512c95da6242e9b1a81", - 0 - ], - [ - "0000000000084a62093d1929843e74456686429b698a7ea9b1901c1565779f58", - 0 - ], - [ - "00000000000251d1da01e9de9fcaf3ca3a64bff78a5faf51a8e697dfab6b5e4b", - 0 - ], - [ - "000000000000609a8798996b1f1fe0b66060a628eadc380d0d369a2318c2d0ec", - 0 - ], - [ - "00000000000014770aeab044a022e86d888a6ede75b6474022c71aead3a1db74", - 0 - ], - [ - "00000000000004101d04ebc90ade5d4b911aa13c038ecf25e9887d877203ddb8", - 0 - ], - [ - "000000007c700410b61eb7ff1aaccbfc3a79e4e4484ad7a2b0eda4d91dc4b613", - 0 - ], - [ - "00000000055ff438a031413ee042fd3c0a2b69be98690542806ff123b7988024", - 0 - ], - [ - "000000002eca5f9f2c3b656d2550662fdee4c95da133eade51a5cae653bc69fe", - 0 - ], - [ - "000000000c679b76ccf0c5b943095fdee8fa466311edbea2c4a05f9430ffef3f", - 0 - ], - [ - "00000000007c6f494e32d5d9de58fa008a770fdc0a7b4a141be5b7c2de3ab970", - 0 - ], - [ - "0000000000d5dcd5a26c8ad29c1293e70401e2f90d8288469df3816b8cc6d4aa", - 0 - ], - [ - "00000000000d754d94f36cacbfb620710672afb1558499cabe17ca62c54a7d3a", - 0 - ], - [ - "000000000004096bb78fba714b130f7f1f929e2803c75a7a85619f7a2b86567f", - 0 - ], - [ - "0000000000020e686c38d44c35896df35f9f1b7723a82a826a5e2393c25ef68c", - 0 - ], - [ - "000000000000504f9af6885c0cb6484109ea205a956c8efae9557a1f5b9233da", - 0 - ], - [ - "0000000000000e8746e52e4320ec17e66434a3936a3825f7046fe874e92275fb", - 0 - ], - [ - "0000000000000f48d818a9a026270c9f733f629959bea25192596d59874b1ce2", - 0 - ], - [ - "00000000eaa9214cb05b241828a1cfb0c4209fb7ea64429815d61f7c1d98939e", - 0 - ], - [ - "000000001f7f915a6002cce4edd5cba392307f3a199a520ee8937327a9135162", - 0 - ], - [ - "0000000009674ee0c606d687bdcddf8e023462927e2902b3381bc4bb862a7397", - 0 - ], - [ - "0000000001f3f3528c083a4b11eb2f04d8bbeca92b57f05d8282909bde78bc77", - 0 - ], - [ - "000000000131917ac459aefb91774dbb42caeca497afc0cfd1766e0338cc7f88", - 0 - ], - [ - "000000000027634444081e1289354cb50034a506bb306a2ac1d8280683771c5c", - 0 - ], - [ - "000000000017a852acff78fbee573329d45bb8b121e9f6fc1e4f687bb3778ada", - 0 - ], - [ - "000000000006789e1a00eca982fb2827f680b254c4a0ecb005af4464f3585a02", - 0 - ], - [ - "0000000000015d2e9f54b1e9419d6b32ce68ae626cdd7f2a1954f22ca39ae0fa", - 0 - ], - [ - "0000000000002f7893bc169165ed9fefb434b6201103f23cc84a747a68ff8797", - 0 - ], - [ - "00000000000008471ccf356a18dd48aa12506ef0b6162cb8f98a8d8bb0465902", - 0 - ], - [ - "0000000000000596f00b9db53c4111bcde16f3781471c5307af1a996e34ec20a", - 0 - ], - [ - "000000000000007b5d2406f64f5f5833c063a6906552e815e603140c00bca951", - 0 - ], - [ - "0000000093ca5d935740a1b25f10ce092fd777c2bb521f3156619389ae78931e", - 0 - ], - [ - "00000000292f3a48559527341f72400a0f8a783aebcaae5bfa0e390dfaa5286b", - 0 - ], - [ - "000000001e852ed7ddf0108d1fce0f4f686f43c8c1b85bcb12c43e564dc7630e", - 0 - ], - [ - "000000000c4bea8fb1e7f3a1f3e6c6b3f71388c0ec7eef3de381853767e89f87", - 0 - ], - [ - "00000000029ef31a21711b55c4300efa38ace0b706091e373f48285286f2c578", - 0 - ], - [ - "0000000000979060786bb008f193d3917e28667bb1b28329f3adadc172e4cce7", - 0 - ], - [ - "000000000019030ceb98013b1627517b45b04ee055ef445813bbebaa25fa1ed3", - 0 - ], - [ - "00000000000adf202247bb794fc9a3c82cd8767143f1e6ed5f60940ee18b09a8", - 0 - ], - [ - "000000000000b19061e2481d8be6183b3d881b0d58601072d2a32729435f6af3", - 0 - ], - [ - "0000000000007a6d34f59b29e8d4da53e51e3414acd18527466d064945fe19fc", - 0 - ], - [ - "0000000000002e66ca213a2c3e9eb5fa62de29feb83880a0bd29f90fca8ad199", - 0 - ], - [ - "0000000000000b4ca10aa100728d0928f37db5296303db1b74ffe29e4a17b6cd", - 0 - ], - [ - "0000000000000143309f6b19567955743775f61f8dc6932c0b46cf5fb11c6c72", - 0 - ], - [ - "00000000000000b04d5409b3ac60cc18c0b9a3d58b303594635a8f75a9d2abd5", - 0 - ], - [ - "000000000000040a2699f62a552703a278608248c2ce823f4cd8845376e9a371", - 0 - ], - [ - "00000000000005cfcb850db7e83d4963994f958bae9b1de1483f5aeb3d449925", - 0 - ], - [ - "00000000000190f80220e70c1481153671a7c90fd856988c183ab0e3d9313df8", - 0 - ], - [ - "000000009374563a06178641d06776f66554c2a094b5319f0801fe35cef72ccf", - 0 - ], - [ - "00000000003e4e6e5e8e4a89e7de50eed104d4a49d2992ff101b6740beec7cb5", - 0 - ], - [ - "0000000000618cd377d14aaa441cbdb92527894f98da316eca81664f8ab5488d", - 0 - ], - [ - "00000000000d977ab2897885fee712f58612fce8c10ffbe9400326fe3429b77b", - 0 - ], - [ - "00000000000c3575b487dd0f938c5bc744fa65ca4ca3a9c981b8bda903ec110b", - 0 - ], - [ - "0000000000247ac689595ed8d62678bfe53e5af13c0f5455e558f5e6bb375c16", - 0 - ], - [ - "0000000000093d175376aa621176511f335a48f824b66d998e8082f85134a48b", - 0 - ], - [ - "000000000000c0c0448fe922f2c737946297d35f2c25ad7cc223e11bbe58e1f8", - 0 - ], - [ - "00000000000016abe4e7c10ddb658bb089b2ef3b1de3f3329097cf679eedf2b5", - 0 - ], - [ - "000000000000242757cea5b68c52b83dd8c2eb9257492074fc69dfa30bd4cbf4", - 0 - ], - [ - "00000000000006813f3dd7726a509fbe3101835db155dfd35d44aeae6aedb316", - 0 - ], - [ - "000000000000053cc4f39cff1c8cee1aff7e289a85dee84164d2d981afc8f17a", - 0 - ], - [ - "00000000000000789724805cf1d37ef689acf52c47a460507f540d5e5ca79bfa", - 0 - ], - [ - "00000000000003d71618bb8952887f65540270a5e54d6246b9419e08831b5e4e", - 0 - ], - [ - "0000000000000251a513a33eadfad67c015f6e3b291dfd0ae1cc4bb3a43006dc", - 0 - ], - [ - "00000000968009e3f8d6e6071e7def68298307717a9af6c2d44986deaae297d5", - 0 - ], - [ - "0000000062bcacb734df83bbfa3e1b9a8dfa570ecffb6c29eaaf8e9498cccd30", - 0 - ], - [ - "000000001d4618c0931bd3c25ee592c35341f30ff3b549a671f637b3c26ef414", - 0 - ], - [ - "000000000418b329df96a004f1b652ad06a7ca295f9f2e711c412d00493f5a86", - 0 - ], - [ - "000000000302bfb88e9027237d023c4b969e106c9a7a23a84103776de7880836", - 0 - ], - [ - "000000000069b9f7d9134fd93c8b7e3af8b26bbcbb5553af02fb6ed644d7fca5", - 0 - ], - [ - "00000000000411ec444240ee91e2777ad18b80dee854e3e838e32209e84774fa", - 0 - ], - [ - "0000000000007c73f322eba4dee5463305227c7e1a8139f1b7b296444f265052", - 0 - ], - [ - "00000000000129adf0f9c0242aedbb9d87935d67ee4ddea758c00344d4b6a29e", - 0 - ], - [ - "000000000000343594e671158b6e1b4b6499f6ad66e2aeabf1f6d295d3dba850", - 0 - ], - [ - "000000000000320f0d5c22ba22b588b97a0e02273034bcd53669b1c8c4eeda1b", - 0 - ], - [ - "0000000000001e8cdb2d98471a5c60bdbddbe644b9ad08e17a97b3a7dce1e332", - 0 - ], - [ - "0000000000000026c9994ccdd027e86f51a2e36812f754bd855a7f9b1ca56511", - 0 - ], - [ - "00000000000002746a820a2c08b35b8d0493c4b5d468fcc971b9c88003e84849", - 0 - ], - [ - "000000000002949f844e92645df73ce9c093e5aac0d962a0fa13eb076eec835c", - 0 - ], - [ - "00000000000156fbda67468ae2863993b98a41227c420246e4bc4e68c84df0e8", - 0 - ], - [ - "000000000003b43c6c807122c8dd10e2a0cffbf72946f41c97c1ab82d416f74d", - 0 - ], - [ - "000000000004e0635c2438b1b649007e5d424b3de846299a8db53049ebf4da0c", - 0 - ], - [ - "00000000000258e4b79e3cca2ab7d12b35ba77fc491572f2e794f0a10f5236d9", - 0 - ], - [ - "0000000000f5816875d9fece105e499b0467b8fb23ea973c48d828a235acdebd", - 0 - ], - [ - "000000000001353bbaec810af7a4c74b4964ae072361c0889ed6d59cf16db6fd", - 0 - ], - [ - "00000000000b354d8c389473670ca6bed7e3dffa069f270d35ec9dad810af141", - 0 - ], - [ - "000000000002fa1f39e7cd8730fa08085ba2b532146ad1ef3b400a13e835ca36", - 0 - ], - [ - "000000000000d2c7943eee59652a9783bff27e474a92ec206c5c6e3cdd58d0d7", - 0 - ], - [ - "00000000000036034181b4d9a84a97490b49fbee4262b9cfb25a7bfc9c0eec9f", - 0 - ], - [ - "00000000000007deb59381cce692f152fc902732d96a7e7d463bc83915b37c0a", - 0 - ], - [ - "00000000ea7d32833462c0f72ade0cae4766e6065caa4e510331929c56d16632", - 0 - ], - [ - "000000000068fce0ddd370d4c8f9129a7bc7843e75fc57666202d3b90239e269", - 0 - ], - [ - "0000000026b4a2212c9c9493f8bd9d5331cab6d8eda8ee017410e58a783ca069", - 0 - ], - [ - "0000000009535ea2dc7e83c31cd17f1db1bb78b0a678fc0610844273de143bf5", - 0 - ], - [ - "00000000008607cbd5baca91d5b8b82ee965aace335744a3e21578af22bee8ba", - 0 - ], - [ - "000000000030dcedae0f5e98c4e176f9569ce76c4d4135bb028fc3144ef381d9", - 0 - ], - [ - "0000000000297c3f0e3fa85731222ba934a955bf513247a72a33c74c498cadbe", - 0 - ], - [ - "0000000000020a0d4a1e8120cbdb486e758b58919c9df12e0edc8ca1f2795e94", - 0 - ], - [ - "000000000000078773afc9023182bfb6534a60158672e6bc6e8aa5052854da80", - 0 - ], - [ - "00000000000102ecdd67800807d9e137357805b9bbf8a439ed86bde5b19fbeb7", - 0 - ], - [ - "0000000000005c3d2e3c7ee737c67ab465533acb233e0df902c1525fc11c3a55", - 0 - ], - [ - "0000000000001a77771650cdbbceff87caa4461391ba6a4ddc9815b5b0ab47b0", - 0 - ], - [ - "000000000000071ec390bbd28fa2a84e52ab5b32901d0723d22646b04ae01dc3", - 0 - ], - [ - "00000000000005c3ec3194f710c6f26ee736d59cc935ddfa574440f39846433a", - 0 - ], - [ - "00000000000001cc3df6924591939269d61ead563b9eb68402a2ca01d7ff99e2", - 0 - ], - [ - "000000008c778b3554ceaf3a13a856acbfe46b5750fb86fd92ba30651c2852f4", - 0 - ], - [ - "00000000107ca31f75f8ea76073dda3c33330b2706c1ec20c3ec240e853b65c5", - 0 - ], - [ - "0000000006ba99b08e7f2869ce113e2ad7464891de7b4cfa96f330d706a2da46", - 0 - ], - [ - "000000000f31036bd51b2818f6dfb90ada9be5019abf55fb15694b181e269865", - 0 - ], - [ - "00000000004fcc101bc47eb7a379b9f608d5c00ac04d2d0ea165ae2937070796", - 0 - ], - [ - "000000000044d5ca3eda838edef0df7e69e1934047f8482822ce58ff7a18466d", - 0 - ], - [ - "000000000029bdfb157be6d400c4dd3370d98afdd8cd3db6f1ada8c19bbf4650", - 0 - ], - [ - "000000000005e9699ad8035caa4f73af781ac2040c87b8aa77459b3607209aa8", - 0 - ], - [ - "000000000001c0ba033f7d85beeaa167c9bde0e192240653a7ff6d9b81679842", - 0 - ], - [ - "0000000000000e0176111f29e800b49c7b8c7226dbbf4df715f1a4f06bcaaa49", - 0 - ], - [ - "00000000ac3bb2cf42192e9053f5384355228a2b3d70b4ece4d45773a5d5ddd2", - 0 - ], - [ - "000000000f29f7b60842b1044b2db7998e9bcbd92f8ec6fe8d159c6d582f1f1a", - 0 - ], - [ - "00000000352f86bc5f9760961a25de009940508bb2cd0b37f378fbc87dc97eef", - 0 - ], - [ - "000000000e9b3086008679ed57f59857f64c3954368ba1088117dbf88d5839cd", - 0 - ], - [ - "000000000015324bd8fed0e61b62bd1d6c663b862cb98ea03c494a92e4a8d0af", - 0 - ], - [ - "000000000020475a181b7a084b341860a72fc0c1fdfcc13a85adeb0471444b0f", - 0 - ], - [ - "0000000000031905c508a975707b74f24e733880382775ee0e6250666473e1d8", - 0 - ], - [ - "000000000000ca38b15d2ea33a6eef505a9c661540a18882f79ba9a3c575a9bd", - 0 - ], - [ - "000000000002739979a7a89fa279303b6606885e750b19e91ed637d7f222b392", - 0 - ], - [ - "00000000000091e935fc266facc2c92759d5468a39aee5be6b76b519a9bc7567", - 0 - ], - [ - "00000000000006e339938254208203b67c3c400f703fc29535fc646699e36e58", - 0 - ], - [ - "00000000000008f6f1d1150d77f93a7f1baa24b65ceb471b1825b2e92ca6997c", - 0 - ], - [ - "000000000000004894e1edcc5421dbcec77d47c5c50bf27b2cff3f1c242c9eb3", - 0 - ], - [ - "000000000000054e97fb5e1a8bd7900f7c329385895761aaa40d11b3c75b0c8e", - 0 - ], - [ - "0000000000000600f4bcc5a89527eede43d1d3342dc12eee1371ab534b0102dc", - 0 - ], - [ - "00000000d1ad5c3ef8c3bb4610b34c264e4ca1ea51c4c8bac18b215e7dc96948", - 0 - ], - [ - "0000000062f6a07ae11f9724b8ba9dc2b7348ffd02b59edd3cd2bf387fab9723", - 0 - ], - [ - "000000000014e4c97c9b09ff20203213f3336b0927fd19d214cef1f544756e39", - 0 - ], - [ - "0000000000d004681880e127aed3fa73255a2e75c2e5c8580cd555526614b294", - 0 - ], - [ - "000000000008093189bba28d40662d6964afc1c0fc9b5c1681bbe32e8bee6c0b", - 0 - ], - [ - "00000000002df10cf8165b2204ef4db6721c8c2119d60463b040fbc81c266bbf", - 0 - ], - [ - "00000000000c28c789e7cd9800b98c1dd32e2dda54048116ff47ed856a14acfb", - 0 - ], - [ - "000000000003e8e7755d9b8299b28c71d9f0e18909f25bc9f3eeec3464ece1dd", - 0 - ], - [ - "0000000000004b95a0103abe2cb97806caca76f6922d9c5df003cf4a467df822", - 0 - ], - [ - "0000000000005f12d2ab72bfa715860444c281265ef77e09dc2d041ce89506c0", - 0 - ], - [ - "00000000000016eeedb3f367daaee93334188db877fb01cd0282b990f60812b3", - 0 - ], - [ - "00000000000001daf3bd8306b6f6899af8aa656d87ac2aa37d493fdcb0cb3000", - 0 - ], - [ - "0000000000000390b86892ad0bed9b520783056961cad7362ace8049aa00471c", - 0 - ], - [ - "00000000000002105d01b4de7d3e3ada9c757a239151d50b5dd193e3951a23cc", - 0 - ], - [ - "00000000000002362fa802df308201a4b1fff2fd8a91892915a46f5d54098ff4", - 0 - ], - [ - "00000000000004fb8aa6c6aecb64b9d8d7e691a6cd56fad69fc5278b9e8d98cb", - 0 - ], - [ - "00000000000000ce3bd9752b2508ddae1ee71332e905163a3c0d7e10b8c472f7", - 0 - ], - [ - "00000000000002d0d8520982f15a45d4a405334c61886b6d13d95843386af647", - 0 - ], - [ - "00000000cafd25502ad67d5d409edfc98f5bbd3173e86e085c69658d58da5f70", - 0 - ], - [ - "00000000b01e0675317a29a07731ea092fa029016a40ed8bb4fc17cde50eda05", - 0 - ], - [ - "000000002676805396ed2883ccc8ad401aa0a974627559fbae2416ba5c54999c", - 0 - ], - [ - "0000000000030ab759158f3d425824228dc5c91f32db91d404bee29ee3a41878", - 0 - ], - [ - "00000000000da1c8040ec08e7490fb201ca1fb3571f29c0efd3351ae197d3017", - 0 - ], - [ - "000000000004e3cba890c16ffc7d1c019d4ab88afa39315164e1b08b8e6a9330", - 0 - ], - [ - "00000000000bdcfb630b43977be44529e54daa02d199014a0967deac669bd060", - 0 - ], - [ - "000000000007254038f9c621d6df0d9fbd90b5697e4170cd6090daaf579f3790", - 0 - ], - [ - "000000000002263e27ea1cec943632bf469a28b067f0bfde3b9a6b48540981b4", - 0 - ], - [ - "000000000000f194a8d17e683d17f222d23a9032f034d4dc4497263fd785dfa0", - 0 - ], - [ - "00000000000036e359b7b07044e3cd5b132a3c72501a0f3f9ccde167f5316bba", - 0 - ], - [ - "0000000000000b10e98a90e0fd1ffbf7d5fc5a76e8e6e960c6fb158711af6f48", - 0 - ], - [ - "0000000000000104e1e4303b8dae78389bb4e6c38f3eb3fe42aec6464bd5c397", - 0 - ], - [ - "00000000000000bde368a635921f5ad25aeb4b784651de24d624cf20c27691c7", - 0 - ], - [ - "0000000081a626a33cff134e7e56dc0f0a67b1735c96256774885d5d095807c0", - 0 - ], - [ - "0000000055d357cdf39130eb767f416101e79025515906bea528f43cb6446920", - 0 - ], - [ - "0000000012558b30f9c1a156fd80b02451e8dfcc7fe0350fb4adeeb84951a0a6", - 0 - ], - [ - "000000000001a4868924fc7cca0334ffc4dd49c07fb841c1da059a7c219bdf95", - 0 - ], - [ - "00000000000010086bd2bba88c71b08cfc7e24183d610a2803e6d382049d52c0", - 0 - ], - [ - "0000000000018c83992fe05d820b097228de93787e3f59e65cb89ad4c385e364", - 0 - ], - [ - "00000000000023ab80324770ff4c6802d09e5e1e7de78d2a8e64783904d47f19", - 0 - ], - [ - "000000000000287fa294ea557835d8c98bfe94c4d8b18d5b10f1b62d68957113", - 0 - ], - [ - "000000000001d842f5a0dff13820ba1e151fd8c886e28e648a0be41f3a3f1cb3", - 0 - ], - [ - "000000000000906854973b2ec51409f0b78b25b074eef3f0dbb31e1060c07c3d", - 0 - ], - [ - "00000000000009e694e22b97a4757bffef74f0ccd832398b3e815171636e3a85", - 0 - ], - [ - "0000000000000594b95678610bd47671b1142eb575d1c1d4a0073f69a71a3c65", - 0 - ], - [ - "00000000000002ac6d5c058c9932f350aeef84f6e334f4e01b40be4db537f8c2", - 0 - ], - [ - "00000000000000c9a91d8277c58eab3bfda59d3068142dd54216129e5597ccbd", - 0 - ], - [ - "0000000000000051bff2f64c9078fb346d6a2a209ba5c3ffa0048c6b7027e47f", - 0 - ], - [ - "000000000000df3c366a105ce9ed82a4917c9e19f0736493894feaba2542c7cd", - 0 - ], - [ - "0000000000007c8006959f91675b2dbf6264a1172279c826ae7f561b70e88b12", - 0 - ], - [ - "0000000000015ab3720de7669e8731c84c392aae3509d937b8d883c304e0ca86", - 0 - ], - [ - "0000000000016d7156ee43da389020fb5d30f05e11498c54f7e324561d6a6039", - 0 - ], - [ - "0000000000009c9592f83d63fe39839080ced253e1d71c52bce576f823b7722a", - 0 - ], - [ - "00000000003dee6b438ddf51b831fbedb9d2ee91644aaf5866e3a85c740b3a99", - 0 - ], - [ - "00000000000155f5594d8a3ade605d1504ee9a6f6389f1c4516e974698ebb9e4", - 0 - ], - [ - "000000000001e21adfc306bf4aa2ad90e3c2aa4a43263d1bbdc70bf9f1593416", - 0 - ], - [ - "0000000000008218e84ba7d9850a5c12b77ec5d1348e7cbdfdcb86f8fe929682", - 0 - ], - [ - "00000000000054fb41b42b30fff1738104c3edca6dab47c75e4d3565bc4b9e34", - 0 - ], - [ - "0000000000002763b825c315ba35959dcc1bd8114627949ede769ac2eece8248", - 0 - ], - [ - "00000000000007437044da0baed38a28e2991c6a527f495e91739a8d9c35acbb", - 0 - ], - [ - "000000000000032d74ad8eb0a0be6b39b8e095bd9ca8537da93aae15087aafaf", - 0 - ], - [ - "000000000000006d4025181f5b54cca6d730cc26313817c6529ba9ed62cc83b3", - 0 - ], - [ - "000000001c3ad81ffea0b74d356b6886fd3381506b7c568f96c88a78815ede09", - 0 - ], - [ - "000000000140739d224af1254712d8c4e9fb9082b381baf22c628e459157ce49", - 0 - ], - [ - "000000000306491c835f1a03c8d1e17645435296d3593dacba8ab1a7d9341d38", - 0 - ], - [ - "000000000002b383618b228eb8e4cfcf269ba647b91ac6d60ddd070295709ad1", - 0 - ], - [ - "000000000000c90fc724a76407b4405032474fc8d1649817f7ad238b96856c6a", - 0 - ], - [ - "0000000000002d5a62b323a5f213152dd84e2f415a3c6c28043c0ccaaddb3229", - 0 - ], - [ - "0000000000008c086a21457ba523b682356c760538000a480650cd667a29647a", - 0 - ], - [ - "00000000000007c586d36266aa83d8cc702aa29f31e3cc01c6eeac5a0f5f9887", - 0 - ], - [ - "0000000000013bf175e35603f24758bf8d40b1f5c266e707e3ba4de6fae43a7f", - 0 - ], - [ - "00000000000096841c486983a4333afb2525549abe57e7263723b9782e9cfef1", - 0 - ], - [ - "00000000000012dfd7c4e1f40a1dd4833da2d010a33fc65c053871884146c941", - 0 - ], - [ - "0000000000000b47eb6bc8c6562b5a30cefcf81623a37f6f61cc7497a530eb33", - 0 - ], - [ - "0000000000000021ca4558aeb796f900e581c029d751f89e1a69ae9ba9f6ebb3", - 0 - ], - [ - "00000000000000a5bf9029aebb1956200304ffee31bc09f1323ae412d81fa2b2", - 0 - ], - [ - "0000000000000046f38ada53de3346d8191f69c8f3c0ba9e1950f5bf291989c4", - 0 - ], - [ - "00000000658b5a572ea407ac49a1dccf85d67d0adfc5f613b17fa3fff1d99d51", - 0 - ], - [ - "000000005d6be9ae758c520b0061feee99cd0a231f982cc074e4d0ced1f96952", - 0 - ], - [ - "0000000001aa4671747707d329a94c398c04aaf2268e551ac5d6a7f29ffd4acd", - 0 - ], - [ - "0000000004b441b97963463faca7a933469fabfa3e7b243621159e445e5c192a", - 0 - ], - [ - "0000000002ce8842113bc875330fa77f3b984a90806a5ec0bb73321fef3c76c6", - 0 - ], - [ - "0000000000019761bf9a1c6f679b880e9fb45b3f6dc1accdbdcfce01368c9377", - 0 - ], - [ - "0000000000008a069efd1a7923557be3d9584d307b2555dc0a56d66e74e083e1", - 0 - ], - [ - "000000000001c14cec52030659ef7d45318ca574f1633ef69e9c8c9bd7e45289", - 0 - ], - [ - "0000000000009cfccb8a27f66f1d9ff40c9d47449f78d82fee2465daca582ab7", - 0 - ], - [ - "0000000000007f30cfae7fbb8ff965f70d500b98be202b1dd57ea418500c922d", - 0 - ], - [ - "0000000000002cbd2dbab4352fe4979e0d5afc47f21ef575ae0e3bb620a5478a", - 0 - ], - [ - "000000000000017a872a5c7a15b3cb6e1ecf9e009759848b85c19ca6e7bd16d2", - 0 - ], - [ - "00000000000001ade79216032b49854c966a1061fd3f8c6c56a0d38d0024629e", - 0 - ], - [ - "0000000000000090b8dfe4dde9f9f8d675642db97b3649bd147f60d1fc64cd76", - 0 - ], - [ - "0000000000000109ed5f0d6fc387ad1bc45db1e522f76adce131067fc64440ec", - 0 - ], - [ - "000000000000003105650f0b8e7b4cb466cd32ff5608f59906879aff5cad64a7", - 0 - ], - [ - "0000000000000113d4262419a8aa3a4fe928c0ea81893a2d2ffee5258b2085d8", - 0 - ], - [ - "00000000000000f15b8a196b1c3568d14b5a7856da2fef7a7f5548266582ff28", - 0 - ], - [ - "0000000000000034fb9e91c8b5f7147bd1a4f089d19a266d183df6f8497d1dff", - 0 - ], - [ - "000000000000005e51ad800c9e8ab11abb4b945f5ea86b120fa140c8af6301e0", - 0 - ], - [ - "00000000000000e903f2002fd08a732fd5380ea1f2dac26bb84d57e247af8ac2", - 0 - ], - [ - "000000000015115dac432884296259f508dae6b6f5f15cef17939840f5a295c3", - 0 - ], - [ - "000000000029913c80e5f49d413603d91f5fd67b76a7e187f76c077973be6f8a", - 0 - ], - [ - "00000000002e864e470ccec1fec0ca5f2053c9a9b8978a40f3482b4d30f683a9", - 0 - ], - [ - "00000000001ccf523df85df9abdb7c5bbad5c5fcbd12a4a8eb4700de7291f03b", - 0 - ], - [ - "00000000002aa81027df021e3ccde48dff6e7f01a4aba27727308f2ce17f2f1a", - 0 - ], - [ - "000000000015a577d71d65bde7e8f5359458336218dc024584f7510b38dc1259", - 0 - ], - [ - "00000000003aef1877bcc6817cac497aeb95af3336ba2908e8194f96a2c9fc29", - 0 - ], - [ - "00000000000ccd42d542ddca68300ec2a9db2564327108234641535fd51aa7f3", - 0 - ], - [ - "000000000000a2652b2e523866f3c4d5c07dc1c204d439b627f2ab2848bfa139", - 0 - ], - [ - "0000000000002c065179a394d8da754c2e2db5fed21def076c16c24a902b448d", - 0 - ], - [ - "000000000000175a878558186e53b559e494ce7e9f687bf0462d63169bfcce03", - 0 - ], - [ - "00000000000007524a71cc81cadbd1ddf9d38848fa8081ad2a72eade4b70d1c1", - 0 - ], - [ - "0000000000000159321405d24d99131df6bf69ffeca30c4a949926807c4175ad", - 0 - ], - [ - "000000000000016c271ae44c8dca3567b332ec178a243be2a7dfa7a0aef270c3", - 0 - ], - [ - "00000000000000a7d62de601cdf73e25c49c1c99717c94ffd574fc657fd42fa8", - 0 - ], - [ - "0000000000000052d492170de491c1355d640bae48f4d954009e963f6f9a18c3", - 0 - ], - [ - "000000006f5707f2f707b9ddcce2739723e911210b131da4ca1efdff581212ad", - 0 - ], - [ - "00000000021be68dc9c33db0c2222e97cd2c06fc43834e8f5292133c45c2abb4", - 0 - ], - [ - "00000000019ca3eaf7c39f70a7a1a736f74021abf885bebc5d91aa946496bac5", - 0 - ], - [ - "00000000006e4752fbe2627ebb2d0118f7437908a8219f973324727195335209", - 0 - ], - [ - "00000000038471612a0955307f367071888985707ec0e42c82f9145caed8fea1", - 0 - ], - [ - "000000000004604d2d7d921b21d86f2ade82ded3af33877ec59d47072023d763", - 0 - ], - [ - "000000000034a3e45665a8dcbb94e7a218375a5199b3f3ca2cc7b5fe151bb198", - 0 - ], - [ - "0000000000043fb2c2ff5db60c6d2d35a633746e8585e04a096a9b55a4787fe6", - 0 - ], - [ - "0000000000020d4d8735b66134c1fcdd1d3f3d135b9ff3f70968ef96c227fb75", - 0 - ], - [ - "0000000000004f3f4dc1fa11a6ad9bd320413b042eb599c4599a14d341f6825f", - 0 - ], - [ - "0000000000001e0a495d23acf46a44f8b569ada39ac70730da5e9109871b77e9", - 0 - ], - [ - "00000000000002257a08acca858f239fabb258a7cc1665fc464f6e18e9372d32", - 0 - ], - [ - "00000000000002845d416fbfa05a5d40ba5ba5418a64f06443042a53cf1fd608", - 0 - ], - [ - "00000000000000fee91a2ae8b8d1bb9a687c9b28b0185723c8ff6ffdac2e9ce4", - 0 - ], - [ - "00000000000001d6874b4d88e387098c0b7100ff674d99781fc7045a78216a15", - 0 - ], - [ - "00000000000144a03e701c199673d72fc63766bcf0cdaf565f4c941c7ef72971", - 0 - ], - [ - "000000009b6cc4d8aee22cca6880e4d7bb30bff2851034ad437d63d3a7278de7", - 0 - ], - [ - "0000000023e998d64618475e31b4aee9d83d2bc32cb6d062aa97c0b4651fed08", - 0 - ], - [ - "0000000000036f4bf6b42a7776a97872fa24362064c5bc4bc946acb70ab6fbf4", - 0 - ], - [ - "0000000001e2252455ffd0cf0b4109ace996a0d2a03999f5cc5c5e08fb6130ac", - 0 - ], - [ - "0000000000002713db42d53f0c2d86c904f4e0338652acc1cbda953c530a15bb", - 0 - ], - [ - "000000000001b075f9ccc604a50326732f5d42373c4a831978be0e2d830cac75", - 0 - ], - [ - "0000000000000bfa7d93c6b36298b933b1a652c95ee9f0de4151e007f3180391", - 0 - ], - [ - "000000000002c60a0af1cfeb9c26c60970b354897fd0a94c8e5c414d0767b06b", - 0 - ], - [ - "0000000000001f2d9462507a9408859fb0b5f97013d6b4577337b0382340c5aa", - 0 - ], - [ - "0000000000000b7428e0d3c6c7fd2df623a74125db4989b1c61c78eeed1bcde5", - 0 - ], - [ - "00000000000002e8b4f1fa041a37515c1b76d59994792f1c772c9a4993c194dc", - 0 - ], - [ - "0000000000094e70c0cf5185b480542a1faa8392a3f2f7f583d91e033856d7ce", - 0 - ], - [ - "000000005b036d8c18ed5d1219e4137bd71438c9b1ba7ff4d10a626e9a7bcc98", - 0 - ], - [ - "0000000008745d4a943e958f5cb5084646c0fe1cae57eeab666c3ad0d4ff1dec", - 0 - ], - [ - "00000000000f8c5b3455e540d074b5c71709e37f8950975953798d27bdc701fa", - 0 - ], - [ - "0000000000050885884f7ac233bb174cf7b33c037f81907f7766afe9d0ad9091", - 0 - ], - [ - "000000000002d7cd1043ccd0581a47d6fdf82a7cf1646b61495f917a48ebeb5c", - 0 - ], - [ - "000000000003a2b3e3d7ef47829db1672bfd79e49f32ef3a04ec7c4df355392b", - 0 - ], - [ - "0000000000032a6c7e5bc3878c1815bc6759594a4736638fdacaa5642be3e649", - 0 - ], - [ - "000000000001386a3904f0ba4f25dc7ace09b67a6fe8977e7aecc55813fa9ac5", - 0 - ], - [ - "0000000000003fe030a2231da87076679c1d38d323bf56b45ceb49a5128fb4b1", - 0 - ], - [ - "000000000000147cd3b6195c6a727cd4fe6b3a879d7934e52bf29020ed9c6fcc", - 0 - ], - [ - "00000000000003ed5a0a7176f3f1b3ed26510045af2860e5b6313b358774fbad", - 0 - ], - [ - "00000000000000c2952ac8a580895ac13799a9c29badb6599bc4a86c1fc83b6e", - 0 - ], - [ - "0000000000000056f49d6f7b8243eecf6597946158efe044b07fd091398e380d", - 0 - ], - [ - "000000000000006b039683c36b18ec712346521edce4dc5b81cdaf6475d89bd7", - 0 - ], - [ - "00000000000000525de83fba2439549ef0ed78d6d08516a0513abb972b0fca95", - 0 - ], - [ - "000000000000006c5403ae9c42acf37362885c75c1a71a6b7fe20f9cfc5304a7", - 0 - ], - [ - "000000000000006f881a62bc5ec9d4c4da83ddc6619a7eee82617e26e2c7ef3c", - 0 - ], - [ - "000000000000012941300197c5b6627a66f9cf48ae9c6791b36c63c0218a1be9", - 0 - ], - [ - "00000000000002cd7ec2e00992a4dc6c5e0a56cfbc19b5afa9730bd94f174b5b", - 0 - ], - [ - "000000000022e09ee2ee7b3fd223cb9ccfe11058cca5ad0c705fe5a0c26b28dc", - 0 - ], - [ - "0000000007d35ebaf81412d40d1224bdc5792bfbc70827c09f05dc5fb168e67f", - 0 - ], - [ - "00000000328e1b1aecf68947ad53fb11c58a383704ddbb8b29704669e22225bd", - 0 - ], - [ - "000000000003d3b3f171fd10fda1be9d4464b1438bb9443081c2c224a047cc4e", - 0 - ], - [ - "000000000001e3c5dcea0586d3c8f69c0f35658fae283d29f64df9b5301bc721", - 0 - ], - [ - "00000000000ce5f3757a0cab09a8cb131b3f2c63303375ad1c84fe423866d33f", - 0 - ], - [ - "00000000000ca01b96070fb643bcebbc862cff4da78dcd52de1418c940d4f466", - 0 - ], - [ - "0000000000006eb74e5036cf42888759c4ebf91a5eb128463e60ae9ab02876a3", - 0 - ], - [ - "000000000003aae0765dfee956b322477d786a2cde617ff073e0bc4eeaf7c252", - 0 - ], - [ - "00000000000033421d804b4bc0f7dc61715d2fc0cc2a98904ff5e1f9ef909010", - 0 - ], - [ - "0000000000002a24b916b5f03bd47250276ad32f08a1684334c7f181b0b7a055", - 0 - ], - [ - "00000000000002a7399ec806255c4ae63d7583001bbde70e2038e9b90fb824f4", - 0 - ], - [ - "00000000000000ec89aaa13c7222b3ec787a487cdc7a17c1ee87ce313e6ed4d3", - 0 - ], - [ - "00000000000001564cf9db3397bd0983a68f450d5b7e59824339fe1d46ba1c75", - 0 - ], - [ - "00000000000e932953388774b6b3492d8756f936d74fda1d33eace33538fb0bb", - 0 - ], - [ - "0000000084c2d56f703e72f6ad637105409552792ee482bbc14376cfb29c30d9", - 0 - ], - [ - "00000000392f30ba333fac2e4937e162105ba2b20fe953848b1a4c004f460223", - 0 - ], - [ - "00000000000842b42c56e4dc573efd9b6b6864dba81730c4f95b837d52078ad5", - 0 - ], - [ - "0000000003e4cca12f6109687fcccfc5c3827bf3bca2487096fec0293b4b351e", - 0 - ], - [ - "00000000007b7eece3ebbf77ed583a711c8427284ea9b556ec67efd14e7f5d90", - 0 - ], - [ - "000000000002c0e026657401be7998fce1618869ec073a49ac935a15d16c5741", - 0 - ], - [ - "00000000000cf19ef67151f6d06b426371dfa63d9d2bbd6024cca520cf4d96b4", - 0 - ], - [ - "0000000000019a6ef183423833a4347d77e8687b4fc83a85f4c98c579631acbe", - 0 - ], - [ - "000000000000a292b9ff43becd4770243d2750e2b3c4e81a6ed79b8abd2f5052", - 0 - ], - [ - "000000000000280db4a9a31097024bc81f0358ba624f1f8dd83a2362a156a817", - 0 - ], - [ - "00000000000009b17b295d898cda8899ce547183fd63fa901b9f502aed00c45d", - 0 - ], - [ - "0000000000000013f5c40f6b0e7e8fe854045135564a4df6ff4ca736861d7ea8", - 0 - ], - [ - "000000000000c39ffca7d1daad0d4f8af9ee108443bb1b4352cd740fd8297aef", - 0 - ], - [ - "000000000002f42ee90d7d459393eb90e2ea5a3ed292394ce1dc5f7a42d66ce0", - 0 - ], - [ - "0000000000010d6bd31805e0a9b8629192c0ad704641d2b08c28865052bbf469", - 0 - ], - [ - "0000000001015f5067612dc0d681d71b33d278c50ca88d7756322ab90f753290", - 0 - ], - [ - "000000000003dadd324301ee6157c29e7aa9f120edefaf05369d849510e6d60c", - 0 - ], - [ - "000000000000a62107ea11c5db9929d819181d8903624e9088b8700d1dc66ea7", - 0 - ], - [ - "00000000000022b91e1b652f626cd3a81bfb2ff70717ace53c488dd45c75fcbb", - 0 - ], - [ - "0000000000002845027a6a08c436c6e99aa8af0f7c744a722fd598ba0f66f4cb", - 0 - ], - [ - "000000000000ae5347baecbcb3cd01265f0e52c8819f830dcfc6dafa1ec4327a", - 0 - ], - [ - "0000000000008dd3169522647ae90ca0a3acc405f0e8c2b53dab013433708921", - 0 - ], - [ - "00000000000023abea5dd709951fb1fa5c34a75670ddc7eea46d2d23c6033669", - 0 - ], - [ - "00000000000006fe20edd4be3beabc4432fbe410ab53466660105ced53056190", - 0 - ], - [ - "000000000000003f6d6889d2917ba88f6e286c156028baebf05be409e1b97ef8", - 0 - ], - [ - "000000000000005d871f102aaa25e60855c96c1aa8404f004db1c8bbfab341e9", - 0 - ], - [ - "0000000000000197fac06dd6c7f80c838b6a21f1ce72f10aa6ba0aff40c3cb92", - 0 - ], - [ - "0000000000000289a999cf132efbee896d8c22e2f9d1036381b00d72c41660e3", - 0 - ], - [ - "00000000e9f6bd4700dea0c0841272461e4e9d125b8fe2c35a2ca39f77269321", - 0 - ], - [ - "00000000f91f03ac1d08214a3646c2bef1878961a8c40d867254d733fd9cb2a3", - 0 - ], - [ - "000000003d42ef351c6a1fb5e2d43d1a28ca095052be35ad9bb901b097c667c8", - 0 - ], - [ - "000000000014b426a9844698b6369c0e2befe4e369f1dd01c157dbdd472c9136", - 0 - ], - [ - "000000000016dfa525db05b9db92a080e0da65a4a0b15e538649eb4c0c670cf4", - 0 - ], - [ - "0000000000027a82eb5b1ab46a276a9aa19e3a1e52e2328c07a50db314664148", - 0 - ], - [ - "000000000026945c53ba1f9b0c34f9e502f3aa64c9979ce583b93daf347d2292", - 0 - ], - [ - "00000000000f64a42d38e16119aa724e6d859d8b7ed2964bd0929a226e57c838", - 0 - ], - [ - "0000000000011bee42dca16315be14fd0be451e4385c787a66c7dc6c0a498ce2", - 0 - ], - [ - "0000000000007fcace99545546c5ee4df862e21840543865ad0944ca7b82baf7", - 0 - ], - [ - "0000000000003b3a9be8e418e11db77aa16dbf9f04a9b43b34466e7b41520fa2", - 0 - ], - [ - "00000000000004ae741f8cd7f6f20231f8be6b89946e50339f0089a2e5c6d4d6", - 0 - ], - [ - "0000000000000379b21385de297e65a62e4d15ee27fbf1e3b4fa7a46b4a274ba", - 0 - ], - [ - "000000000001fd6b7db603c305be360c602800e5d9068bd65bae111b4561d5ab", - 0 - ], - [ - "000000003925c7eb3144eb77e7891a607152b662b161cd4a052e2a5689c4b694", - 0 - ], - [ - "000000000000a8476194924cd6612277821149e22f7326a054c09c7d55b8a9d5", - 0 - ], - [ - "0000000009ddc12332eb5903b89ddfd116bfd9b300c4d70821e749a302fa438b", - 0 - ], - [ - "0000000000028fe3bfc47a9ad8a71c90fa3edea0c1d04f823c5a9d8674b9d1c5", - 0 - ], - [ - "000000000000075849c07342e632fa3f2b4e137de35703e91c62cb568a8583ea", - 0 - ], - [ - "0000000000001100406d8447ce19989346956134e2dabb87f93ff1b32208dc21", - 0 - ], - [ - "0000000000006a8a2fd9d16a22f28523940811b3c4f179f888249b6f5f19c708", - 0 - ], - [ - "000000000001af7c8a48d294945d937c3f1ab297617bab1a0eb1d9a40e543139", - 0 - ], - [ - "00000000000040eafb8f54cb988a19d0370379be0b2917787e640720677ba6de", - 0 - ], - [ - "000000000000025f7bc6cb5759f267fd649620c69f6518213729bb6aeb4d98d3", - 0 - ], - [ - "0000000000000217a8588f1af88d2f73a96a658f0aea62de5c53b5b348346456", - 0 - ], - [ - "00000000000001b8aa8353bbafb6f47125f67a711c0a2a7a00bfebff5a8df093", - 0 - ], - [ - "000000004ca77c8921259d7da52f341526df3f34edb62e3e2888b7ce42b8c29f", - 0 - ], - [ - "000000005c8253a86af2492291e888d78d0a69a7a657a221e59b23eb6291fcff", - 0 - ], - [ - "0000000000fba14ebb3757a9348a05b07ec207b25aaffeac4118237e665fc566", - 0 - ], - [ - "0000000008f01a3c024cb6d1814e54659c72b17e34e2b60fd35af2184b6bd3ea", - 0 - ], - [ - "0000000003da1325f0d607889753f3a7214c3e559b9834c6f0e37bd52e14eaec", - 0 - ], - [ - "0000000000d303f0b50fc25ea141ad3c26d0dfe61fa4cfcc6875edbcef902163", - 0 - ], - [ - "00000000002131de3bcff721c93c169e34450054c18fc02cd5a8e08c7c3fd567", - 0 - ], - [ - "00000000000c69cdb751a4ef5f527ae244909ddfda10a4caed4d6f8dd44e51fe", - 0 - ], - [ - "0000000000024819bfbc99fd2032441181dcb2456ada1d047c4b6b7829be62a0", - 0 - ], - [ - "00000000000077021c5164bc1014b24abd321f160bb914a1257a86645f923385", - 0 - ], - [ - "00000000000038e149b42e964bdeb10f01fbbfd38ce57ec25eb3fdfb712cf9b0", - 0 - ], - [ - "000000000000047dd3d1ce9862add6979aa622a7cb2141b4c6ec569b172dd776", - 0 - ], - [ - "0000000090c401521295d1040e0f9b6cb65da914085bb9346e60477837dab234", - 0 - ], - [ - "00000000f36784781eaf4b0d3ef92525b6cf55e910c782bd4f355b71ee40dc36", - 0 - ], - [ - "000000001d3848f040d48696a9e258798bea34969e810ad01e8092183f201dfd", - 0 - ], - [ - "0000000007658642f1e8ac45feec2766358f425030b14ad824f3a6df30b9eb15", - 0 - ], - [ - "00000000028e5b819d9e197b1d3f1246a2a6990d8e2360371dbf258c2c5861fb", - 0 - ], - [ - "00000000002a8dbd19a807d955c7d01962fea32f5ae027345121176ac10c20f4", - 0 - ], - [ - "0000000000144908febd5cbacd1d9b828817f0350211be3248a1ec2d3ac3e251", - 0 - ], - [ - "00000000000a302f19d696c7be172c6ac92ec2adf956417bba482d3e5285e5d7", - 0 - ], - [ - "000000000000a289eb62cae8c41644d7c9de31148f711744aa5409164b90d6e3", - 0 - ], - [ - "000000000000036a6f6002c633b6be318745d2f2ff1520daa6a49db7649bca67", - 0 - ], - [ - "0000000000000293db488f4a3c7289489664e6e7e1ec917dc58c83ec828a4730", - 0 - ], - [ - "0000000000000e24d4ce3b9247d6316791438ab82ea755e788112bb9729730cf", - 0 - ], - [ - "00000000000003a18b92493908ebe4ccecf24bfeda95bf3b8a026e3c01af116a", - 0 - ], - [ - "0000000000000007a2b7ba9dd58c20651b477daf83df5a7ac24b856b22f1fb25", - 0 - ], - [ - "000000000000000ce321e0271dd532a6ce58737151baa84a77a585df614c2ab6", - 0 - ], - [ - "000000000000004ebec3379d6a8569295a2d0a0c0e0c815d2b01803315032185", - 0 - ], - [ - "000000000000001bb9ed28d9b0a70fee0b6d42f91f3db53f2086eef4daabce30", - 0 - ], - [ - "000000007c5711c573d147a6fae21faf529c039220c97dfe2ba96e732d88fa89", - 0 - ], - [ - "000000008e5a5e820d1a10dbeecf6f6df3bf7ab56e46eec275d8ca1a52e86b68", - 0 - ], - [ - "000000003fa06ace5db33de18cf03b0c56d4e62cdaf8ab533919953c22bffaf1", - 0 - ], - [ - "000000000000e6442b0c74fa811319edf2edd5f8d9b2e3ee831b4bdee644fbd0", - 0 - ], - [ - "00000000011d0c3f98e9c3db6b51468be632bdef0c47f5e45871b771e5b0bc57", - 0 - ], - [ - "000000000000e3c0978d872ed3b3a43f6f319995459105159b5f4e92143d40d2", - 0 - ], - [ - "000000000000cdf25c3e15601dcb798c6cf8d2dd89002a4e046b746be6b87fa0", - 0 - ], - [ - "000000000000521507052d13f4fac6c01c0099466720bea95c2e9349aef7fa5f", - 0 - ], - [ - "00000000000064823750f1a6b7cd1748dfcc73376086cfdba987d2a36fcddb71", - 0 - ], - [ - "0000000000000b4a41be0612f47a58efb899dc1cc0965c1c1fac89e1ea69f587", - 0 - ], - [ - "00000000000010aab857bf7d475d9a594dca8b1144597a9e69c70f20fdd20b4f", - 0 - ], - [ - "0000000000000c264f193e8d5099f2c20c08fdf9e5ca9006fb53778c0d8eb869", - 0 - ], - [ - "00000000000002adcce72a5cce517f1afc33c765927b77ccbce5cdc6f5f68e45", - 0 - ], - [ - "00000000b179a6096a58938311b3b8cc4479ccdf3909667a58598acc4ebd0192", - 0 - ], - [ - "000000004e86c06d23b8a4c20e6cb5a4c51cad24fca30e41695f8ad00852a88e", - 0 - ], - [ - "000000000bafa134d62d9df490ffdbc1f2b86b4373b86c079c5b730034aad214", - 0 - ], - [ - "00000000033e9b623ca1d89418114f63af55e042dafbfe97952e7a5fe7a3ebf4", - 0 - ], - [ - "000000000119025b6c9bbc3390708b1a77e85eda69fcb79666418ac2cb874a17", - 0 - ], - [ - "000000000000feafbf3a525a1dd7950fa53f7df1b0210e79337ce588d35a8b9a", - 0 - ], - [ - "0000000000007044088a1cc9ddc0c3779c0e156dee10fa15a760897ed4249f8f", - 0 - ], - [ - "000000000001a10e8b1ad577278f946252298b49b74ac9db70ea80c0a9c12db3", - 0 - ], - [ - "000000000001281354a7d86b3c750681283276c0bdde2b18c38d8354138ca4e1", - 0 - ], - [ - "0000000000000398b17fcd5d4d59ccb31d642f7b60c2a4d4d2aa7239ebc0efa9", - 0 - ], - [ - "00000000000021a571a2c475115fe723b593633efb85bf0ec0f7d67b780e70c3", - 0 - ], - [ - "00000000000002d1506c82becd7b480c85402d27f23a1248cfa128b7a8c009a6", - 0 - ], - [ - "00000000000001978f804f5cf8e4a0dc0c454fce0f0e2614510b8eae6e504b2e", - 0 - ], - [ - "00000000000001c4558889a43ac35208f502bccd9d38c741571723e9d79bcc26", - 0 - ], - [ - "000000000000005c782bbbc75358216e1ffc37973cd43a474b87dfbac4c61fab", - 0 - ], - [ - "0000000053bffe3e3db3672c5f050fa54239f93833ec5c38af92e83dec71a9fc", - 0 - ], - [ - "000000000001362fd5182f1cbfc1981937cd67ba54bc7b6d7f0a68f94e369f0a", - 0 - ], - [ - "000000000386ae84caa25e9dfa7816594b7c30a079e340bfcd951be2b5c092b2", - 0 - ], - [ - "0000000003cc09a351d647c0e12063d45b20e6f99c27c18ea62342b9d246581d", - 0 - ], - [ - "0000000002527c4756350bafee88786cd7ea27bc802f482c4e50cafc547ff9f7", - 0 - ], - [ - "00000000003d7288f44aa0b725af7816d2d333e118de12c390423d641139d5d5", - 0 - ], - [ - "000000000008c0a0fadcfbe27a880ce9c387425d3a2c6b06c1a599e4ce51ec92", - 0 - ], - [ - "00000000000158ab2486a8f1251c5c94502763ced9eb85847bb9d2eb476b515a", - 0 - ], - [ - "000000000000c817e5775378accf08412657e2557d2895df0fbb8475b5e190ba", - 0 - ], - [ - "00000000000078d59d08215b3aecdf0e0665d3a16ae1716e408df790a3566e72", - 0 - ], - [ - "0000000000002208404b39b95cc20845de19b47e05e8146146056d3d9bb382ae", - 0 - ], - [ - "0000000000000543e9315ca8b3b72bd3590f24535e4ddc6ccb1050b607777530", - 0 - ], - [ - "00000000000000abb8d3ffd3cc347cee5c092dde5355a7dc5d288036a28760fb", - 0 - ], - [ - "000000000000008bfbcce7d768df6f4610205dcb40173e8c4c417a2325487f34", - 0 - ], - [ - "00000000209e49391ad09577f87d1e0ffda27d2e749fd305c51692112627c99d", - 0 - ], - [ - "000000000005561eb4b2e0cb8107c81617284e7bcd7d390d16a3cd5925cf42a9", - 0 - ], - [ - "00000000006b24215c790a371bc18c53c83ff35e2c82d459bb6240cd9615dde5", - 0 - ], - [ - "0000000000af315d6fbde8488d68dbd055a56d79555ed32c3ad4d70286b4df2a", - 0 - ], - [ - "00000000019e49bc89fcabc4050521fb8835f926a62cc10b68e9618ffc117162", - 0 - ], - [ - "00000000009c0dcde4e694463245e8e5e45d2897e7fa67772ce0ef37094f3afd", - 0 - ], - [ - "000000000005efbda8c010f29a5b81606d186459047ce4b7eacde8d9659dce97", - 0 - ], - [ - "0000000000051c1655579a441a7f4d543c323d482405cf1d1250c3ccb665d426", - 0 - ], - [ - "0000000000007f13adadd1fc6462fbc5231425b81826af4e5f0cbb0de54a5b3a", - 0 - ], - [ - "00000000000011e00df09353fcb53766447279b96228da0525d769f33026bebb", - 0 - ], - [ - "0000000000002b91e6bb56015e0e60dc650a63666aa3943058e9641d4d679fa3", - 0 - ], - [ - "00000000000008e4d5fbcf207583267efff33e6c8d0a5fbdaa5704aeb674fe29", - 0 - ], - [ - "000000000000018aeeabcb422b5b0a46cf3a5f2458125c043c5781ffafeffbf9", - 0 - ], - [ - "000000000000004ca501cc9138ef5fef4b7b235682b81ab9719b3cf215e94f73", - 0 - ], - [ - "000000000000002b5bb1c4c43059575556a0ed10099ce5095f805d3d9ae10cab", + "0007907962e5c00316a7e73aa10ff4d6115d6c3a053f3838d881d422a82eb503", 0 ] ] \ No newline at end of file diff --git a/electrum/constants.py b/electrum/constants.py index 6e5f7435e923..7e0f00bca910 100644 --- a/electrum/constants.py +++ b/electrum/constants.py @@ -29,6 +29,8 @@ from .util import inv_dict from . import bitcoin +from .equihash_params import EquihashParams + def read_json(filename, default): path = os.path.join(os.path.dirname(__file__), filename) @@ -39,9 +41,8 @@ def read_json(filename, default): r = default return r - -GIT_REPO_URL = "https://github.com/spesmilo/electrum" -GIT_REPO_ISSUES_URL = "https://github.com/spesmilo/electrum/issues" +GIT_REPO_URL = "https://github.com/BTCGPU/electrum" +GIT_REPO_ISSUES_URL = GIT_REPO_URL + "/issues" BIP39_WALLET_FORMATS = read_json('bip39_wallet_formats.json', []) @@ -49,45 +50,91 @@ class AbstractNet: BLOCK_HEIGHT_FIRST_LIGHTNING_CHANNELS = 0 + POW_TARGET_SPACING = 10 * 60 + POW_TARGET_TIMESPAN_LEGACY = 14 * 24 * 60 * 60 + + DIGI_AVERAGING_WINDOW = 30 + DIGI_MAX_ADJUST_DOWN = 32 + DIGI_MAX_ADJUST_UP = 16 + + LWMA_AVERAGING_WINDOW = 45 + LWMA_ADJUST_WEIGHT_LEGACY = 13772 + LWMA_ADJUST_WEIGHT = 13772 + LWMA_MIN_DENOMINATOR_LEGACY = 10 + LWMA_MIN_DENOMINATOR = 10 + LWMA_SOLVETIME_LIMITATION = True + + EQUIHASH_PARAMS = EquihashParams(n=200, k=9, personalization=b'ZcashPoW') + EQUIHASH_PARAMS_FORK = EquihashParams(n=144, k=5, personalization=b'BgoldPoW') + + HEADER_SIZE_ORIGIN = 80 + HEADER_SIZE_LEGACY = 141 + + CHUNK_SIZE = 252 + + SIGHASH_FORK_BTG = 0x4f40 + @classmethod def max_checkpoint(cls) -> int: return max(0, len(cls.CHECKPOINTS) * 2016 - 1) @classmethod - def rev_genesis_bytes(cls) -> bytes: - return bytes.fromhex(bitcoin.rev_hex(cls.GENESIS)) + def get_checkpoint_hash(cls, height) -> str: + def is_height_checkpoint(): + within_cp_range = height <= cls.max_checkpoint() + at_chunk_boundary = (height+1) % 2016 == 0 + return within_cp_range and at_chunk_boundary + if is_height_checkpoint(): + index = height // 2016 + h, t = cls.CHECKPOINTS[index] + return h -class BitcoinMainnet(AbstractNet): + @classmethod + def rev_genesis_bytes(cls) -> bytes: + return bytes.fromhex(bitcoin.rev_hex(cls.GENESIS)) +class BitcoinGoldMainnet(AbstractNet): TESTNET = False WIF_PREFIX = 0x80 - ADDRTYPE_P2PKH = 0 - ADDRTYPE_P2SH = 5 - SEGWIT_HRP = "bc" + ADDRTYPE_P2PKH = 38 + ADDRTYPE_P2SH = 23 + SEGWIT_HRP = "btg" + HEADERS_URL = "https://headers.bitcoingold.org/blockchain_headers.gz" GENESIS = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" DEFAULT_PORTS = {'t': '50001', 's': '50002'} DEFAULT_SERVERS = read_json('servers.json', {}) CHECKPOINTS = read_json('checkpoints.json', []) - BLOCK_HEIGHT_FIRST_LIGHTNING_CHANNELS = 497000 + + PREMINE_SIZE = 8000 + BTG_HEIGHT = 491407 + + LWMA_HEIGHT = 536200 + + EQUIHASH_FORK_HEIGHT = 536200 + + POW_LIMIT = 0x0007ffffffff0000000000000000000000000000000000000000000000000000 + POW_LIMIT_START = 0x0000000fffff0000000000000000000000000000000000000000000000000000 + POW_LIMIT_LEGACY = 0x00000000ffff0000000000000000000000000000000000000000000000000000 XPRV_HEADERS = { - 'standard': 0x0488ade4, # xprv - 'p2wpkh-p2sh': 0x049d7878, # yprv - 'p2wsh-p2sh': 0x0295b005, # Yprv - 'p2wpkh': 0x04b2430c, # zprv - 'p2wsh': 0x02aa7a99, # Zprv + 'standard': 0x0488ade4, # xprv + 'p2wpkh-p2sh': 0x049d7878, # yprv + 'p2wsh-p2sh': 0x0295b005, # Yprv + 'p2wpkh': 0x04b2430c, # zprv + 'p2wsh': 0x02aa7a99, # Zprv } XPRV_HEADERS_INV = inv_dict(XPRV_HEADERS) + XPUB_HEADERS = { - 'standard': 0x0488b21e, # xpub - 'p2wpkh-p2sh': 0x049d7cb2, # ypub - 'p2wsh-p2sh': 0x0295b43f, # Ypub - 'p2wpkh': 0x04b24746, # zpub - 'p2wsh': 0x02aa7ed3, # Zpub + 'standard': 0x0488b21e, # xpub + 'p2wpkh-p2sh': 0x049d7cb2, # ypub + 'p2wsh-p2sh': 0x0295b43f, # Ypub + 'p2wpkh': 0x04b24746, # zpub + 'p2wsh': 0x02aa7ed3, # Zpub } XPUB_HEADERS_INV = inv_dict(XPUB_HEADERS) - BIP44_COIN_TYPE = 0 + BIP44_COIN_TYPE = 156 LN_REALM_BYTE = 0 LN_DNS_SEEDS = [ 'nodes.lightning.directory.', @@ -95,35 +142,63 @@ class BitcoinMainnet(AbstractNet): 'lseed.darosior.ninja', ] + MAX_CHECKPOINT_HEADER = { + 'version': 536870912, + 'prev_block_hash': '000000013db74be10e3bbc9ae80672992862f7029f599ba81e7da7bb0a17b3d9', + 'merkle_root': '2d52f4ca32e7521fdb5ed9c4bb383ccf954e75d354103ca5830fe5f4bafadcbd', + 'block_height': 639071, + 'reserved': '00000000000000000000000000000000000000000000000000000000', + 'timestamp': 1592690053, + 'bits': 0x1d055bf6, + 'nonce': '0000027100000000000000001800000000000000000000008ebc540100000000', + 'solution':'0682d8163dec57623a0f544ba27f344cbc894cc884c2ee8c1011cdb9f7d06157fd2fd8e3fb2305874ee9a0321ef6e7589e310e07fdb230ac1224c33d1d9e942a46b619d5fd952d8d6ef729239844300f2c523f315635c06457297b6d61659ef8e3d62bae' + } -class BitcoinTestnet(AbstractNet): - +class BitcoinGoldTestnet(AbstractNet): TESTNET = True WIF_PREFIX = 0xef ADDRTYPE_P2PKH = 111 ADDRTYPE_P2SH = 196 - SEGWIT_HRP = "tb" - GENESIS = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" + SEGWIT_HRP = "tbtg" + GENESIS = "00000000e0781ebe24b91eedc293adfea2f557b53ec379e78959de3853e6f9f6" DEFAULT_PORTS = {'t': '51001', 's': '51002'} DEFAULT_SERVERS = read_json('servers_testnet.json', {}) CHECKPOINTS = read_json('checkpoints_testnet.json', []) + PREMINE_SIZE = 50 + BTG_HEIGHT = 1 + + LWMA_HEIGHT = -1 + LWMA_ADJUST_WEIGHT_LEGACY = 13632 + LWMA_ADJUST_WEIGHT = 13772 + LWMA_MIN_DENOMINATOR_LEGACY = 3 + LWMA_MIN_DENOMINATOR = 10 + LWMA_SOLVETIME_LIMITATION = False + + EQUIHASH_FORK_HEIGHT = 14300 + + POW_LIMIT = 0x0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + POW_LIMIT_START = 0x0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + POW_LIMIT_LEGACY = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff + XPRV_HEADERS = { - 'standard': 0x04358394, # tprv + 'standard': 0x04358394, # tprv 'p2wpkh-p2sh': 0x044a4e28, # uprv - 'p2wsh-p2sh': 0x024285b5, # Uprv - 'p2wpkh': 0x045f18bc, # vprv - 'p2wsh': 0x02575048, # Vprv + 'p2wsh-p2sh': 0x024285b5, # Uprv + 'p2wpkh': 0x045f18bc, # vprv + 'p2wsh': 0x02575048, # Vprv } XPRV_HEADERS_INV = inv_dict(XPRV_HEADERS) + XPUB_HEADERS = { - 'standard': 0x043587cf, # tpub + 'standard': 0x043587cf, # tpub 'p2wpkh-p2sh': 0x044a5262, # upub - 'p2wsh-p2sh': 0x024289ef, # Upub - 'p2wpkh': 0x045f1cf6, # vpub - 'p2wsh': 0x02575483, # Vpub + 'p2wsh-p2sh': 0x024289ef, # Upub + 'p2wpkh': 0x045f1cf6, # vpub + 'p2wsh': 0x02575483, # Vpub } XPUB_HEADERS_INV = inv_dict(XPUB_HEADERS) + BIP44_COIN_TYPE = 1 LN_REALM_BYTE = 1 LN_DNS_SEEDS = [ # TODO investigate this again @@ -131,44 +206,76 @@ class BitcoinTestnet(AbstractNet): #'lseed.bitcoinstats.com.', # ignores REALM byte and returns mainnet peers... ] + MAX_CHECKPOINT_HEADER = { + 'version': 536870912, + 'prev_block_hash': '00078c55b0972a70d6920cab734c9043d7916fd82dfe7e832455662ff3334c7a', + 'merkle_root': '8a45ebd0c4895c35b98cae7a6ed950c99301e3995283e36fb1f9a8d8f4cce51a', + 'block_height': 78623, + 'reserved': '00000000000000000000000000000000000000000000000000000000', + 'timestamp': 1591897081, + 'bits': 0x1f07ffff, + 'nonce': '0000052d0000000000000000000000000000000000000000000000000004198f', + 'solution':'0d628f363b74106f99d1d867840980ab9b54f6f0ed53f8a1c35d5a2c36ed4f3924137fd914e8d21ed7d64656f3cb1dd553f715af4ac5a883466c1f4e62fce7ca33d744d8539e48f3d2dfdb2d290e4254260edcc7c843ac433354b1d14ce9687683225dac' + } -class BitcoinRegtest(BitcoinTestnet): +class BitcoinGoldRegtest(AbstractNet): + REGTEST = True + + WIF_PREFIX = 0xef + ADDRTYPE_P2PKH = 111 + ADDRTYPE_P2SH = 196 + SEGWIT_HRP = "tbtg" - SEGWIT_HRP = "bcrt" GENESIS = "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206" + DEFAULT_SERVERS = read_json('servers_regtest.json', {}) - CHECKPOINTS = [] - LN_DNS_SEEDS = [] + PREMINE_SIZE = 10 + BTG_HEIGHT = 2000 -class BitcoinSimnet(BitcoinTestnet): + LWMA_HEIGHT = -1 - WIF_PREFIX = 0x64 - ADDRTYPE_P2PKH = 0x3f - ADDRTYPE_P2SH = 0x7b - SEGWIT_HRP = "sb" - GENESIS = "683e86bd5c6d110d91b94b97137ba6bfe02dbbdb8e3dff722a669b5d69d77af6" - DEFAULT_SERVERS = read_json('servers_regtest.json', {}) - CHECKPOINTS = [] - LN_DNS_SEEDS = [] + EQUIHASH_FORK_HEIGHT = 2001 + EQUIHASH_PARAMS = EquihashParams(n=48, k=5, personalization=b'ZcashPoW') + EQUIHASH_PARAMS_FORK = EquihashParams(n=96, k=5, personalization=b'BgoldPoW') + POW_LIMIT = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + POW_LIMIT_START = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + POW_LIMIT_LEGACY = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + + XPRV_HEADERS = { + 'standard': 0x04358394, # tprv + 'p2wpkh-p2sh': 0x044a4e28, # uprv + 'p2wsh-p2sh': 0x024285b5, # Uprv + 'p2wpkh': 0x045f18bc, # vprv + 'p2wsh': 0x02575048, # Vprv + } + + XPUB_HEADERS = { + 'standard': 0x043587cf, # tpub + 'p2wpkh-p2sh': 0x044a5262, # upub + 'p2wsh-p2sh': 0x024289ef, # Upub + 'p2wpkh': 0x045f1cf6, # vpub + 'p2wsh': 0x02575483, # Vpub + } + + MAX_CHECKPOINT_HEADER = None # don't import net directly, import the module instead (so that net is singleton) -net = BitcoinMainnet +net = BitcoinGoldMainnet def set_simnet(): global net - net = BitcoinSimnet + net = BitcoinGoldTestnet # TODO: Add BitcoinGold simnet def set_mainnet(): global net - net = BitcoinMainnet + net = BitcoinGoldMainnet def set_testnet(): global net - net = BitcoinTestnet - + net = BitcoinGoldTestnet def set_regtest(): global net - net = BitcoinRegtest + net = BitcoinGoldRegtest diff --git a/electrum/currencies.json b/electrum/currencies.json index 342708d713a2..0de940e79bc5 100644 --- a/electrum/currencies.json +++ b/electrum/currencies.json @@ -1,904 +1,9 @@ { - "BitFlyer": [ - "JPY" - ], - "BitPay": [ - "AED", - "AFN", - "ALL", - "AMD", - "ANG", - "AOA", - "ARS", - "AUD", - "AWG", - "AZN", - "BAM", - "BBD", - "BCH", - "BDT", - "BGN", - "BHD", - "BIF", - "BMD", - "BND", - "BOB", - "BRL", - "BSD", + "Bitfinex": [ "BTC", - "BTN", - "BWP", - "BZD", - "CAD", - "CDF", - "CHF", - "CLF", - "CLP", - "CNY", - "COP", - "CRC", - "CUP", - "CVE", - "CZK", - "DJF", - "DKK", - "DOP", - "DZD", - "EGP", - "ETB", - "EUR", - "FJD", - "FKP", - "GBP", - "GEL", - "GHS", - "GIP", - "GMD", - "GNF", - "GTQ", - "GYD", - "HKD", - "HNL", - "HRK", - "HTG", - "HUF", - "IDR", - "ILS", - "INR", - "IQD", - "IRR", - "ISK", - "JEP", - "JMD", - "JOD", - "JPY", - "KES", - "KGS", - "KHR", - "KMF", - "KPW", - "KRW", - "KWD", - "KYD", - "KZT", - "LAK", - "LBP", - "LKR", - "LRD", - "LSL", - "LYD", - "MAD", - "MDL", - "MGA", - "MKD", - "MMK", - "MNT", - "MOP", - "MRU", - "MUR", - "MVR", - "MWK", - "MXN", - "MYR", - "MZN", - "NAD", - "NGN", - "NIO", - "NOK", - "NPR", - "NZD", - "OMR", - "PAB", - "PAX", - "PEN", - "PGK", - "PHP", - "PKR", - "PLN", - "PYG", - "QAR", - "RON", - "RSD", - "RUB", - "RWF", - "SAR", - "SBD", - "SCR", - "SDG", - "SEK", - "SGD", - "SHP", - "SLL", - "SOS", - "SRD", - "STN", - "SVC", - "SYP", - "SZL", - "THB", - "TJS", - "TMT", - "TND", - "TOP", - "TRY", - "TTD", - "TWD", - "TZS", - "UAH", - "UGX", - "USD", - "UYU", - "UZS", - "VEF", - "VES", - "VND", - "VUV", - "WST", - "XAF", - "XAG", - "XAU", - "XCD", - "XOF", - "XPF", - "YER", - "ZAR", - "ZMW", - "ZWL" - ], - "BitStamp": [ - "USD", - "EUR" - ], - "Bitbank": [ - "JPY" - ], - "BitcoinAverage": [ - "AED", - "AFN", - "ALL", - "AMD", - "ANG", - "AOA", - "ARS", - "AUD", - "AWG", - "AZN", - "BAM", - "BBD", - "BDT", - "BGN", - "BHD", - "BIF", - "BMD", - "BND", - "BOB", - "BRL", - "BSD", - "BTN", - "BWP", - "BYN", - "BZD", - "CAD", - "CDF", - "CHF", - "CLF", - "CLP", - "CNH", - "CNY", - "COP", - "CRC", - "CUC", - "CUP", - "CVE", - "CZK", - "DJF", - "DKK", - "DOP", - "DZD", - "EGP", - "ERN", - "ETB", - "EUR", - "FJD", - "FKP", - "GBP", - "GEL", - "GGP", - "GHS", - "GIP", - "GMD", - "GNF", - "GTQ", - "GYD", - "HKD", - "HNL", - "HRK", - "HTG", - "HUF", - "IDR", - "ILS", - "IMP", - "INR", - "IQD", - "IRR", - "ISK", - "JEP", - "JMD", - "JOD", - "JPY", - "KES", - "KGS", - "KHR", - "KMF", - "KPW", - "KRW", - "KWD", - "KYD", - "KZT", - "LAK", - "LBP", - "LKR", - "LRD", - "LSL", - "LYD", - "MAD", - "MDL", - "MGA", - "MKD", - "MMK", - "MNT", - "MOP", - "MRO", - "MUR", - "MVR", - "MWK", - "MXN", - "MYR", - "MZN", - "NAD", - "NGN", - "NIO", - "NOK", - "NPR", - "NZD", - "OMR", - "PAB", - "PEN", - "PGK", - "PHP", - "PKR", - "PLN", - "PYG", - "QAR", - "RON", - "RSD", - "RUB", - "RWF", - "SAR", - "SBD", - "SCR", - "SDG", - "SEK", - "SGD", - "SHP", - "SLL", - "SOS", - "SRD", - "SSP", - "STD", - "SVC", - "SYP", - "SZL", - "THB", - "TJS", - "TMT", - "TND", - "TOP", - "TRY", - "TTD", - "TWD", - "TZS", - "UAH", - "UGX", - "USD", - "UYU", - "UZS", - "VES", - "VND", - "VUV", - "WST", - "XAF", - "XAG", - "XAU", - "XCD", - "XDR", - "XOF", - "XPD", - "XPF", - "XPT", - "YER", - "ZAR", - "ZMW", - "ZWL" - ], - "BitcoinVenezuela": [ - "ARS", - "ETH", - "EUR", - "LTC", - "USD", - "VEF", - "XMR" - ], - "Bitcointoyou": [ - "BRL" - ], - "Bitso": [ - "MXN" - ], - "Bitvalor": [ - "BRL" - ], - "BlockchainInfo": [ - "AUD", - "BRL", - "CAD", - "CHF", - "CLP", - "CNY", - "DKK", - "EUR", - "GBP", - "HKD", - "INR", - "ISK", - "JPY", - "KRW", - "NZD", - "PLN", - "RUB", - "SEK", - "SGD", - "THB", - "TWD", "USD" ], - "Bylls": [ - "CAD" - ], - "CoinCap": [ - "USD" - ], - "CoinDesk": [ - "AED", - "AFN", - "ALL", - "AMD", - "ANG", - "AOA", - "ARS", - "AUD", - "AWG", - "AZN", - "BAM", - "BBD", - "BDT", - "BGN", - "BHD", - "BIF", - "BMD", - "BND", - "BOB", - "BRL", - "BSD", - "BTC", - "BTN", - "BWP", - "BYR", - "BZD", - "CAD", - "CDF", - "CHF", - "CLF", - "CLP", - "CNY", - "COP", - "CRC", - "CUP", - "CVE", - "CZK", - "DJF", - "DKK", - "DOP", - "DZD", - "EEK", - "EGP", - "ERN", - "ETB", - "EUR", - "FJD", - "FKP", - "GBP", - "GEL", - "GHS", - "GIP", - "GMD", - "GNF", - "GTQ", - "GYD", - "HKD", - "HNL", - "HRK", - "HTG", - "HUF", - "IDR", - "ILS", - "INR", - "IQD", - "IRR", - "ISK", - "JEP", - "JMD", - "JOD", - "JPY", - "KES", - "KGS", - "KHR", - "KMF", - "KPW", - "KRW", - "KWD", - "KYD", - "KZT", - "LAK", - "LBP", - "LKR", - "LRD", - "LSL", - "LTL", - "LVL", - "LYD", - "MAD", - "MDL", - "MGA", - "MKD", - "MMK", - "MNT", - "MOP", - "MRO", - "MTL", - "MUR", - "MVR", - "MWK", - "MXN", - "MYR", - "MZN", - "NAD", - "NGN", - "NIO", - "NOK", - "NPR", - "NZD", - "OMR", - "PAB", - "PEN", - "PGK", - "PHP", - "PKR", - "PLN", - "PYG", - "QAR", - "RON", - "RSD", - "RUB", - "RWF", - "SAR", - "SBD", - "SCR", - "SDG", - "SEK", - "SGD", - "SHP", - "SLL", - "SOS", - "SRD", - "STD", - "SVC", - "SYP", - "SZL", - "THB", - "TJS", - "TMT", - "TND", - "TOP", - "TRY", - "TTD", - "TWD", - "TZS", - "UAH", - "UGX", - "USD", - "UYU", - "UZS", - "VEF", - "VND", - "VUV", - "WST", - "XAF", - "XAG", - "XAU", - "XBT", - "XCD", - "XDR", - "XOF", - "XPF", - "YER", - "ZAR", - "ZMK", - "ZMW", - "ZWL" - ], - "CoinGecko": [ - "AED", - "ARS", - "AUD", - "BCH", - "BDT", - "BHD", - "BMD", - "BNB", - "BRL", - "BTC", - "CAD", - "CHF", - "CLP", - "CNY", - "CZK", - "DKK", - "EOS", - "ETH", - "EUR", - "GBP", - "HKD", - "HUF", - "IDR", - "ILS", - "INR", - "JPY", - "KRW", - "KWD", - "LKR", - "LTC", - "MMK", - "MXN", - "MYR", - "NOK", - "NZD", - "PHP", - "PKR", - "PLN", - "RUB", - "SAR", - "SEK", - "SGD", - "THB", - "TRY", - "TWD", - "USD", - "VEF", - "VND", - "XAG", - "XAU", - "XDR", - "XLM", - "XRP", - "ZAR" - ], - "Coinbase": [ - "AED", - "AFN", - "ALL", - "AMD", - "ANG", - "AOA", - "ARS", - "AUD", - "AWG", - "AZN", - "BAM", - "BAT", - "BBD", - "BCH", - "BDT", - "BGN", - "BHD", - "BIF", - "BMD", - "BND", - "BOB", - "BRL", - "BSD", - "BSV", - "BTC", - "BTN", - "BWP", - "BYN", - "BYR", - "BZD", - "CAD", - "CDF", - "CHF", - "CLF", - "CLP", - "CNH", - "CNY", - "COP", - "CRC", - "CUC", - "CVE", - "CZK", - "DJF", - "DKK", - "DOP", - "DZD", - "EEK", - "EGP", - "ERN", - "ETB", - "ETC", - "ETH", - "EUR", - "FJD", - "FKP", - "GBP", - "GEL", - "GGP", - "GHS", - "GIP", - "GMD", - "GNF", - "GTQ", - "GYD", - "HKD", - "HNL", - "HRK", - "HTG", - "HUF", - "IDR", - "ILS", - "IMP", - "INR", - "IQD", - "ISK", - "JEP", - "JMD", - "JOD", - "JPY", - "KES", - "KGS", - "KHR", - "KMF", - "KRW", - "KWD", - "KYD", - "KZT", - "LAK", - "LBP", - "LKR", - "LRD", - "LSL", - "LTC", - "LTL", - "LVL", - "LYD", - "MAD", - "MDL", - "MGA", - "MKD", - "MMK", - "MNT", - "MOP", - "MRO", - "MTL", - "MUR", - "MVR", - "MWK", - "MXN", - "MYR", - "MZN", - "NAD", - "NGN", - "NIO", - "NOK", - "NPR", - "NZD", - "OMR", - "PAB", - "PEN", - "PGK", - "PHP", - "PKR", - "PLN", - "PYG", - "QAR", - "RON", - "RSD", - "RUB", - "RWF", - "SAR", - "SBD", - "SCR", - "SEK", - "SGD", - "SHP", - "SLL", - "SOS", - "SRD", - "SSP", - "STD", - "SVC", - "SZL", - "THB", - "TJS", - "TMT", - "TND", - "TOP", - "TRY", - "TTD", - "TWD", - "TZS", - "UAH", - "UGX", - "USD", - "UYU", - "UZS", - "VEF", - "VND", - "VUV", - "WST", - "XAF", - "XAG", - "XAU", - "XCD", - "XDR", - "XOF", - "XPD", - "XPF", - "XPT", - "YER", - "ZAR", - "ZEC", - "ZMK", - "ZMW", - "ZRX", - "ZWL" - ], - "CointraderMonitor": [ - "BRL" - ], - "Kraken": [ - "CAD", - "EUR", - "GBP", - "JPY", - "USD" - ], - "LocalBitcoins": [ - "AED", - "ARS", - "AUD", - "BAM", - "BDT", - "BGN", - "BOB", - "BRL", - "BWP", - "BYN", - "CAD", - "CHF", - "CLP", - "CNY", - "COP", - "CRC", - "CZK", - "DKK", - "DOP", - "EGP", - "ETH", - "EUR", - "GBP", - "GEL", - "GHS", - "GTQ", - "HKD", - "HNL", - "HRK", - "HUF", - "IDR", - "ILS", - "INR", - "IRR", - "JOD", - "JPY", - "KES", - "KRW", - "KZT", - "LKR", - "LTC", - "MAD", - "MXN", - "MYR", - "NGN", - "NOK", - "NZD", - "OMR", - "PAB", - "PEN", - "PHP", - "PKR", - "PLN", - "QAR", - "RON", - "RSD", - "RUB", - "RWF", - "SAR", - "SEK", - "SGD", - "SZL", - "THB", - "TRY", - "TTD", - "TWD", - "TZS", - "UAH", - "UGX", - "USD", - "UYU", - "VES", - "VND", - "XAF", - "XMR", - "XRP", - "ZAR" - ], - "MercadoBitcoin": [ - "BRL" - ], - "TheRockTrading": [ - "EUR" - ], - "Zaif": [ - "JPY" - ], - "itBit": [], - "Bitragem": [ - "BRL" - ], - "Biscoint": [ - "BRL" - ], - "Walltime": [ - "BRL" + "Bitmarket": [ + "PLN" ] } diff --git a/electrum/equihash.py b/electrum/equihash.py new file mode 100644 index 000000000000..43e190ba6522 --- /dev/null +++ b/electrum/equihash.py @@ -0,0 +1,318 @@ +# ZCASH implementation: https://github.com/zcash/zcash/blob/master/qa/rpc-tests/test_framework/equihash.py +from hashlib import blake2b +from operator import itemgetter +import struct +from functools import reduce + +DEBUG = False +VERBOSE = False + + +word_size = 32 +word_mask = (1<= 8 and word_size >= 7+bit_len + + out_width = (bit_len+7)//8 + byte_pad + assert out_len == 8*out_width*len(inp)//bit_len + out = bytearray(out_len) + + bit_len_mask = (1 << bit_len) - 1 + + # The acc_bits least-significant bits of acc_value represent a bit sequence + # in big-endian order. + acc_bits = 0 + acc_value = 0 + + j = 0 + for i in range(len(inp)): + acc_value = ((acc_value << 8) & word_mask) | inp[i] + acc_bits += 8 + + # When we have bit_len or more bits in the accumulator, write the next + # output element. + if acc_bits >= bit_len: + acc_bits -= bit_len + for x in range(byte_pad, out_width): + out[j+x] = ( + # Big-endian + acc_value >> (acc_bits+(8*(out_width-x-1))) + ) & ( + # Apply bit_len_mask across byte boundaries + (bit_len_mask >> (8*(out_width-x-1))) & 0xFF + ) + j += out_width + + return out + + +def compress_array(inp, out_len, bit_len, byte_pad=0): + assert bit_len >= 8 and word_size >= 7+bit_len + + in_width = (bit_len+7)//8 + byte_pad + assert out_len == bit_len*len(inp)//(8*in_width) + out = bytearray(out_len) + + bit_len_mask = (1 << bit_len) - 1 + + # The acc_bits least-significant bits of acc_value represent a bit sequence + # in big-endian order. + acc_bits = 0 + acc_value = 0 + + j = 0 + for i in range(out_len): + # When we have fewer than 8 bits left in the accumulator, read the next + # input element. + if acc_bits < 8: + acc_value = ((acc_value << bit_len) & word_mask) | inp[j] + for x in range(byte_pad, in_width): + acc_value = acc_value | ( + ( + # Apply bit_len_mask across byte boundaries + inp[j+x] & ((bit_len_mask >> (8*(in_width-x-1))) & 0xFF) + ) << (8*(in_width-x-1))) # Big-endian + j += in_width + acc_bits += bit_len + + acc_bits -= 8 + out[i] = (acc_value >> acc_bits) & 0xFF + + return out + + +def get_indices_from_minimal(minimal, bit_len): + eh_index_size = 4 + assert (bit_len+7)//8 <= eh_index_size + len_indices = 8*eh_index_size*len(minimal)//bit_len + byte_pad = eh_index_size - (bit_len+7)//8 + expanded = expand_array(minimal, len_indices, bit_len, byte_pad) + return [struct.unpack('>I', expanded[i:i+4])[0] for i in range(0, len_indices, eh_index_size)] + + +def get_minimal_from_indices(indices, bit_len): + eh_index_size = 4 + assert (bit_len+7)//8 <= eh_index_size + len_indices = len(indices)*eh_index_size + min_len = bit_len*len_indices//(8*eh_index_size) + byte_pad = eh_index_size - (bit_len+7)//8 + byte_indices = bytearray(b''.join([struct.pack('>I', i) for i in indices])) + return compress_array(byte_indices, min_len, bit_len, byte_pad) + + +def hash_nonce(digest, nonce): + for i in range(8): + digest.update(struct.pack('> (32*i) & 0xffffffff)) + +def hash_xi(digest, xi): + digest.update(struct.pack(' 0: + # 2b) Find next set of unordered pairs with collisions on first n/(k+1) bits + j = 1 + while j < len(X): + if not has_collision(X[-1][0], X[-1-j][0], i, collision_length): + break + j += 1 + + # 2c) Store tuples (X_i ^ X_j, (i, j)) on the table + for l in range(0, j-1): + for m in range(l+1, j): + # Check that there are no duplicate indices in tuples i and j + if distinct_indices(X[-1-l][1], X[-1-m][1]): + if X[-1-l][1][0] < X[-1-m][1][0]: + concat = X[-1-l][1] + X[-1-m][1] + else: + concat = X[-1-m][1] + X[-1-l][1] + Xc.append((xor(X[-1-l][0], X[-1-m][0]), concat)) + + # 2d) Drop this set + while j > 0: + X.pop(-1) + j -= 1 + # 2e) Replace previous list with new list + X = Xc + + # k+1) Find a collision on last 2n(k+1) bits + if DEBUG: + print('Final round:') + print('- Sorting list') + X.sort(key=itemgetter(0)) + if DEBUG and VERBOSE: + for Xi in X[-32:]: + print('%s %s' % (print_hash(Xi[0]), Xi[1])) + if DEBUG: print('- Finding collisions') + solns = [] + while len(X) > 0: + j = 1 + while j < len(X): + if not (has_collision(X[-1][0], X[-1-j][0], k, collision_length) and + has_collision(X[-1][0], X[-1-j][0], k+1, collision_length)): + break + j += 1 + + for l in range(0, j-1): + for m in range(l+1, j): + res = xor(X[-1-l][0], X[-1-m][0]) + if count_zeroes(res) == 8*hash_length and distinct_indices(X[-1-l][1], X[-1-m][1]): + if DEBUG and VERBOSE: + print('Found solution:') + print('- %s %s' % (print_hash(X[-1-l][0]), X[-1-l][1])) + print('- %s %s' % (print_hash(X[-1-m][0]), X[-1-m][1])) + if X[-1-l][1][0] < X[-1-m][1][0]: + solns.append(list(X[-1-l][1] + X[-1-m][1])) + else: + solns.append(list(X[-1-m][1] + X[-1-l][1])) + + # 2d) Drop this set + while j > 0: + X.pop(-1) + j -= 1 + return [get_minimal_from_indices(soln, collision_length+1) for soln in solns] + + +def gbp_validate(digest, minimal, n, k): + validate_params(n, k) + collision_length = n//(k+1) + hash_length = (k+1)*((collision_length+7)//8) + indices_per_hash_output = 512//n + solution_width = (1 << k)*(collision_length+1)//8 + + if len(minimal) != solution_width: + print('Invalid solution length: %d (expected %d)' % (len(minimal), solution_width)) + return False + + X = [] + for i in get_indices_from_minimal(minimal, collision_length+1): + r = i % indices_per_hash_output + # X_i = H(I||V||x_i) + curr_digest = digest.copy() + hash_xi(curr_digest, i//indices_per_hash_output) + tmp_hash = curr_digest.digest() + X.append(( + expand_array(bytearray(tmp_hash[r*n//8:(r+1)*n//8]), + hash_length, collision_length), + (i,) + )) + + for r in range(1, k+1): + Xc = [] + for i in range(0, len(X), 2): + if not has_collision(X[i][0], X[i+1][0], r, collision_length): + print('Invalid solution: invalid collision length between StepRows') + return False + if X[i+1][1][0] < X[i][1][0]: + print('Invalid solution: Index tree incorrectly ordered') + return False + if not distinct_indices(X[i][1], X[i+1][1]): + print('Invalid solution: duplicate indices') + return False + Xc.append((xor(X[i][0], X[i+1][0]), X[i][1] + X[i+1][1])) + X = Xc + + if len(X) != 1: + print('Invalid solution: incorrect length after end of rounds: %d' % len(X)) + return False + + if count_zeroes(X[0][0]) != 8*hash_length: + print('Invalid solution: incorrect number of zeroes: %d' % count_zeroes(X[0][0])) + return False + + return True + + +def zcash_person(n, k, personalization): + return personalization + struct.pack('= n): + raise ValueError('n must be larger than k') + if (((n/(k+1))+1) >= 32): + raise ValueError('Parameters must satisfy n/(k+1)+1 < 32') + + +# a bit different from https://github.com/zcash/zcash/blob/master/qa/rpc-tests/test_framework/mininode.py#L747 +# since electrum is a SPV oriented and not a node +def is_gbp_valid(header, nonce, solution, equihash_params): + # H(I||... + digest = blake2b(digest_size=(512//equihash_params.n)*equihash_params.n//8, + person=zcash_person(equihash_params.n, equihash_params.k, equihash_params.personalization)) + digest.update(header[:108]) + hash_nonce(digest, nonce) + return gbp_validate(digest, solution, equihash_params.n, equihash_params.k) diff --git a/electrum/equihash_params.py b/electrum/equihash_params.py new file mode 100644 index 000000000000..f398ad80c921 --- /dev/null +++ b/electrum/equihash_params.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# +# Electrum - lightweight Bitcoin Gold client +# Copyright (C) 2018 The Bitcoin Gold developers +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +class EquihashParams(object): + def __init__(self, n, k, personalization): + self.n = n + self.k = k + self.personalization = personalization + + def get_solution_size(self): + return int((1 << self.k) * (self.n // (self.k + 1) + 1) // 8) diff --git a/electrum/exchange_rate.py b/electrum/exchange_rate.py index 7ae230623545..1b3bcc0569a1 100644 --- a/electrum/exchange_rate.py +++ b/electrum/exchange_rate.py @@ -24,8 +24,8 @@ DEFAULT_ENABLED = False -DEFAULT_CURRENCY = "EUR" -DEFAULT_EXCHANGE = "CoinGecko" # default exchange should ideally provide historical rates +DEFAULT_CURRENCY = "USD" +DEFAULT_EXCHANGE = "Bitfinex" # default exchange should ideally provide historical rates # See https://en.wikipedia.org/wiki/ISO_4217 @@ -153,156 +153,6 @@ async def get_currencies(self): return sorted([str(a) for (a, b) in rates.items() if b is not None and len(a)==3]) -class BitcoinAverage(ExchangeBase): - # note: historical rates used to be freely available - # but this is no longer the case. see #5188 - - async def get_rates(self, ccy): - json = await self.get_json('apiv2.bitcoinaverage.com', '/indices/global/ticker/short') - return dict([(r.replace("BTC", ""), Decimal(json[r]['last'])) - for r in json if r != 'timestamp']) - - -class Bitcointoyou(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('bitcointoyou.com', "/API/ticker.aspx") - return {'BRL': Decimal(json['ticker']['last'])} - - -class BitcoinVenezuela(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('api.bitcoinvenezuela.com', '/') - rates = [(r, json['BTC'][r]) for r in json['BTC'] - if json['BTC'][r] is not None] # Giving NULL for LTC - return dict(rates) - - def history_ccys(self): - return ['ARS', 'EUR', 'USD', 'VEF'] - - async def request_history(self, ccy): - json = await self.get_json('api.bitcoinvenezuela.com', - "/historical/index.php?coin=BTC") - return json[ccy +'_BTC'] - - -class Bitbank(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('public.bitbank.cc', '/btc_jpy/ticker') - return {'JPY': Decimal(json['data']['last'])} - - -class BitFlyer(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('bitflyer.jp', '/api/echo/price') - return {'JPY': Decimal(json['mid'])} - - -class BitPay(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('bitpay.com', '/api/rates') - return dict([(r['code'], Decimal(r['rate'])) for r in json]) - - -class Bitso(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('api.bitso.com', '/v2/ticker') - return {'MXN': Decimal(json['last'])} - - -class BitStamp(ExchangeBase): - - async def get_currencies(self): - return ['USD', 'EUR'] - - async def get_rates(self, ccy): - if ccy in CURRENCIES[self.name()]: - json = await self.get_json('www.bitstamp.net', f'/api/v2/ticker/btc{ccy.lower()}/') - return {ccy: Decimal(json['last'])} - return {} - - -class Bitvalor(ExchangeBase): - - async def get_rates(self,ccy): - json = await self.get_json('api.bitvalor.com', '/v1/ticker.json') - return {'BRL': Decimal(json['ticker_1h']['total']['last'])} - - -class BlockchainInfo(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('blockchain.info', '/ticker') - return dict([(r, Decimal(json[r]['15m'])) for r in json]) - - -class Bylls(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('bylls.com', '/api/price?from_currency=BTC&to_currency=CAD') - return {'CAD': Decimal(json['public_price']['to_price'])} - - -class Coinbase(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('api.coinbase.com', - '/v2/exchange-rates?currency=BTC') - return {ccy: Decimal(rate) for (ccy, rate) in json["data"]["rates"].items()} - - -class CoinCap(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('api.coincap.io', '/v2/rates/bitcoin/') - return {'USD': Decimal(json['data']['rateUsd'])} - - def history_ccys(self): - return ['USD'] - - async def request_history(self, ccy): - # Currently 2000 days is the maximum in 1 API call - # (and history starts on 2017-03-23) - history = await self.get_json('api.coincap.io', - '/v2/assets/bitcoin/history?interval=d1&limit=2000') - return dict([(datetime.utcfromtimestamp(h['time']/1000).strftime('%Y-%m-%d'), h['priceUsd']) - for h in history['data']]) - - -class CoinDesk(ExchangeBase): - - async def get_currencies(self): - dicts = await self.get_json('api.coindesk.com', - '/v1/bpi/supported-currencies.json') - return [d['currency'] for d in dicts] - - async def get_rates(self, ccy): - json = await self.get_json('api.coindesk.com', - '/v1/bpi/currentprice/%s.json' % ccy) - result = {ccy: Decimal(json['bpi'][ccy]['rate_float'])} - return result - - def history_starts(self): - return {'USD': '2012-11-30', 'EUR': '2013-09-01'} - - def history_ccys(self): - return self.history_starts().keys() - - async def request_history(self, ccy): - start = self.history_starts()[ccy] - end = datetime.today().strftime('%Y-%m-%d') - # Note ?currency and ?index don't work as documented. Sigh. - query = ('/v1/bpi/historical/close.json?start=%s&end=%s' - % (start, end)) - json = await self.get_json('api.coindesk.com', query) - return json['bpi'] - - class CoinGecko(ExchangeBase): async def get_rates(self, ccy): @@ -316,107 +166,23 @@ def history_ccys(self): async def request_history(self, ccy): history = await self.get_json('api.coingecko.com', - '/api/v3/coins/bitcoin/market_chart?vs_currency=%s&days=max' % ccy) + '/api/v3/coins/bitcoin-gold/market_chart?vs_currency=%s&days=max' % ccy) return dict([(datetime.utcfromtimestamp(h[0]/1000).strftime('%Y-%m-%d'), h[1]) for h in history['prices']]) -class CointraderMonitor(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('cointradermonitor.com', '/api/pbb/v1/ticker') - return {'BRL': Decimal(json['last'])} - - -class itBit(ExchangeBase): - - async def get_rates(self, ccy): - ccys = ['USD', 'EUR', 'SGD'] - json = await self.get_json('api.itbit.com', '/v1/markets/XBT%s/ticker' % ccy) - result = dict.fromkeys(ccys) - if ccy in ccys: - result[ccy] = Decimal(json['lastPrice']) - return result - - -class Kraken(ExchangeBase): - - async def get_rates(self, ccy): - ccys = ['EUR', 'USD', 'CAD', 'GBP', 'JPY'] - pairs = ['XBT%s' % c for c in ccys] - json = await self.get_json('api.kraken.com', - '/0/public/Ticker?pair=%s' % ','.join(pairs)) - return dict((k[-3:], Decimal(float(v['c'][0]))) - for k, v in json['result'].items()) - - -class LocalBitcoins(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('localbitcoins.com', - '/bitcoinaverage/ticker-all-currencies/') - return dict([(r, Decimal(json[r]['rates']['last'])) for r in json]) - - -class MercadoBitcoin(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('api.bitvalor.com', '/v1/ticker.json') - return {'BRL': Decimal(json['ticker_1h']['exchanges']['MBT']['last'])} - - -class TheRockTrading(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('api.therocktrading.com', - '/v1/funds/BTCEUR/ticker') - return {'EUR': Decimal(json['last'])} - - -class Winkdex(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('winkdex.com', '/api/v0/price') - return {'USD': Decimal(json['price'] / 100.0)} - - def history_ccys(self): - return ['USD'] - - async def request_history(self, ccy): - json = await self.get_json('winkdex.com', - "/api/v0/series?start_time=1342915200") - history = json['series'][0]['results'] - return dict([(h['timestamp'][:10], h['price'] / 100.0) - for h in history]) - - -class Zaif(ExchangeBase): - async def get_rates(self, ccy): - json = await self.get_json('api.zaif.jp', '/api/1/last_price/btc_jpy') - return {'JPY': Decimal(json['last_price'])} +class Bitfinex(ExchangeBase): + def get_rates(self, ccy): + json = self.get_json('api.bitfinex.com', "/v1/ticker/btg%s" % ccy) + return {ccy: Decimal(json['last_price'])} -class Bitragem(ExchangeBase): +class Bitmarket(ExchangeBase): - async def get_rates(self,ccy): - json = await self.get_json('api.bitragem.com', '/v1/index?asset=BTC&market=BRL') - return {'BRL': Decimal(json['response']['index'])} - - -class Biscoint(ExchangeBase): - - async def get_rates(self,ccy): - json = await self.get_json('api.biscoint.io', '/v1/ticker?base=BTC"e=BRL') - return {'BRL': Decimal(json['data']['last'])} - - -class Walltime(ExchangeBase): - - async def get_rates(self, ccy): - json = await self.get_json('s3.amazonaws.com', - '/data-production-walltime-info/production/dynamic/walltime-info.json') - return {'BRL': Decimal(json['BRL_XBT']['last_inexact'])} + def get_rates(self, ccy): + json = self.get_json('www.bitmarket.pl', '/json/BTGPLN/ticker.json') + return {'PLN': Decimal(json['last'])} def dictinvert(d): diff --git a/electrum/gui/icons/electrum.icns b/electrum/gui/icons/electrum.icns deleted file mode 100644 index 977b124d0d26..000000000000 Binary files a/electrum/gui/icons/electrum.icns and /dev/null differ diff --git a/electrum/gui/icons/electrum.ico b/electrum/gui/icons/electrum.ico deleted file mode 100644 index 3baebbce3c64..000000000000 Binary files a/electrum/gui/icons/electrum.ico and /dev/null differ diff --git a/electrum/gui/icons/electrum.png b/electrum/gui/icons/electrum.png deleted file mode 100644 index 2ab3260e042b..000000000000 Binary files a/electrum/gui/icons/electrum.png and /dev/null differ diff --git a/electrum/gui/icons/electrum_dark_icon.png b/electrum/gui/icons/electrum_dark_icon.png deleted file mode 100644 index 6fee7de9f74c..000000000000 Binary files a/electrum/gui/icons/electrum_dark_icon.png and /dev/null differ diff --git a/electrum/gui/icons/electrum_launcher.png b/electrum/gui/icons/electrum_launcher.png deleted file mode 100644 index 37af81ca9f9b..000000000000 Binary files a/electrum/gui/icons/electrum_launcher.png and /dev/null differ diff --git a/electrum/gui/icons/electrum_light_icon.png b/electrum/gui/icons/electrum_light_icon.png deleted file mode 100644 index da52cb3c17b0..000000000000 Binary files a/electrum/gui/icons/electrum_light_icon.png and /dev/null differ diff --git a/electrum/gui/icons/electrum_presplash.png b/electrum/gui/icons/electrum_presplash.png deleted file mode 100644 index 8d7b414db8b0..000000000000 Binary files a/electrum/gui/icons/electrum_presplash.png and /dev/null differ diff --git a/electrum/gui/icons/electrumg.icns b/electrum/gui/icons/electrumg.icns new file mode 100644 index 000000000000..8075e1ce86cc Binary files /dev/null and b/electrum/gui/icons/electrumg.icns differ diff --git a/electrum/gui/icons/electrumg.ico b/electrum/gui/icons/electrumg.ico new file mode 100644 index 000000000000..942c2c8ffbd0 Binary files /dev/null and b/electrum/gui/icons/electrumg.ico differ diff --git a/electrum/gui/icons/electrumg.png b/electrum/gui/icons/electrumg.png new file mode 100644 index 000000000000..67f472461b47 Binary files /dev/null and b/electrum/gui/icons/electrumg.png differ diff --git a/electrum/gui/icons/electrumg_dark_icon.png b/electrum/gui/icons/electrumg_dark_icon.png new file mode 100644 index 000000000000..d80c49bafd75 Binary files /dev/null and b/electrum/gui/icons/electrumg_dark_icon.png differ diff --git a/electrum/gui/icons/electrumg_launcher.png b/electrum/gui/icons/electrumg_launcher.png new file mode 100644 index 000000000000..1f9440fb2b1f Binary files /dev/null and b/electrum/gui/icons/electrumg_launcher.png differ diff --git a/electrum/gui/icons/electrumg_light_icon.png b/electrum/gui/icons/electrumg_light_icon.png new file mode 100644 index 000000000000..bd0c2f1ae06c Binary files /dev/null and b/electrum/gui/icons/electrumg_light_icon.png differ diff --git a/electrum/gui/icons/electrumg_presplash.png b/electrum/gui/icons/electrumg_presplash.png new file mode 100644 index 000000000000..a95b95931144 Binary files /dev/null and b/electrum/gui/icons/electrumg_presplash.png differ diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py index 8c828a24373e..62e7b37e4076 100644 --- a/electrum/gui/kivy/main_window.py +++ b/electrum/gui/kivy/main_window.py @@ -821,7 +821,7 @@ def init_ui(self): self.history_screen = None self.send_screen = None self.receive_screen = None - self.icon = os.path.dirname(KIVY_GUI_PATH) + "/icons/electrum.png" + self.icon = "electrum/gui/icons/electrumg.png" self.tabs = self.root.ids['tabs'] def update_interfaces(self, dt): diff --git a/electrum/gui/qt/__init__.py b/electrum/gui/qt/__init__.py index af4c3ae53f97..14b44930c30a 100644 --- a/electrum/gui/qt/__init__.py +++ b/electrum/gui/qt/__init__.py @@ -114,7 +114,7 @@ def __init__(self, config: 'SimpleConfig', daemon: 'Daemon', plugins: 'Plugins') self.efilter = OpenFileEventFilter(self.windows) self.app = QElectrumApplication(sys.argv) self.app.installEventFilter(self.efilter) - self.app.setWindowIcon(read_QIcon("electrum.png")) + self.app.setWindowIcon(read_QIcon("electrumg.png")) self._cleaned_up = False # timer self.timer = QTimer(self.app) @@ -184,9 +184,9 @@ def build_tray_menu(self): def tray_icon(self): if self.dark_icon: - return read_QIcon('electrum_dark_icon.png') + return read_QIcon('electrumg_dark_icon.png') else: - return read_QIcon('electrum_light_icon.png') + return read_QIcon('electrumg_light_icon.png') def toggle_tray_icon(self): if not self.tray: diff --git a/electrum/gui/qt/exception_window.py b/electrum/gui/qt/exception_window.py index 103bf63c3c7a..1b52da41b7c4 100644 --- a/electrum/gui/qt/exception_window.py +++ b/electrum/gui/qt/exception_window.py @@ -52,7 +52,7 @@ def __init__(self, config: 'SimpleConfig', exctype, value, tb): self.config = config QWidget.__init__(self) - self.setWindowTitle('Electrum - ' + _('An Error Occurred')) + self.setWindowTitle('ElectrumG - ' + _('An Error Occurred')) self.setMinimumSize(600, 300) Logger.__init__(self) diff --git a/electrum/gui/qt/installwizard.py b/electrum/gui/qt/installwizard.py index 98f81bdd6ef8..8dca17f358db 100644 --- a/electrum/gui/qt/installwizard.py +++ b/electrum/gui/qt/installwizard.py @@ -152,7 +152,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): def __init__(self, config: 'SimpleConfig', app: QApplication, plugins: 'Plugins', *, gui_object: 'ElectrumGui'): QDialog.__init__(self, None) BaseWizard.__init__(self, config, plugins) - self.setWindowTitle('Electrum - ' + _('Install Wizard')) + self.setWindowTitle('ElectrumG - ' + _('Install Wizard')) self.app = app self.config = config self.gui_thread = gui_object.gui_thread @@ -195,7 +195,7 @@ def __init__(self, config: 'SimpleConfig', app: QApplication, plugins: 'Plugins' hbox.setStretchFactor(scroll, 1) outer_vbox.addLayout(hbox) outer_vbox.addLayout(Buttons(self.back_button, self.next_button)) - self.set_icon('electrum.png') + self.set_icon('electrumg.png') self.show() self.raise_() self.refresh_gui() # Need for QT on MacOSX. Lame. diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index c45c21004a26..c593475ff1af 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -251,7 +251,7 @@ def add_optional_tab(tabs, tab, icon, description, name): if self.config.get("is_maximized"): self.showMaximized() - self.setWindowIcon(read_QIcon("electrum.png")) + self.setWindowIcon(read_QIcon("electrumg.png")) self.init_menubar() wrtabs = weakref.proxy(tabs) @@ -296,9 +296,9 @@ def add_optional_tab(tabs, tab, icon, description, name): # If the option hasn't been set yet if config.get('check_updates') is None: - choice = self.question(title="Electrum - " + _("Enable update check"), - msg=_("For security reasons we advise that you always use the latest version of Electrum.") + " " + - _("Would you like to be notified when there is a newer version of Electrum available?")) + choice = self.question(title="ElectrumG - " + _("Enable update check"), + msg=_("For security reasons we advise that you always use the latest version of ElectrumG.") + " " + + _("Would you like to be notified when there is a newer version of ElectrumG available?")) config.set_key('check_updates', bool(choice), save=True) self._update_check_thread = None @@ -307,7 +307,7 @@ def add_optional_tab(tabs, tab, icon, description, name): # to prevent GC from getting in our way. def on_version_received(v): if UpdateCheck.is_newer(v): - self.update_check_button.setText(_("Update to Electrum {} is available").format(v)) + self.update_check_button.setText(_("Update to ElectrumG {} is available").format(v)) self.update_check_button.clicked.connect(lambda: self.show_update_check(v)) self.update_check_button.show() self._update_check_thread = UpdateCheckThread() @@ -541,7 +541,7 @@ def init_geometry(self): self.setGeometry(100, 100, 840, 400) def watching_only_changed(self): - name = "Electrum Testnet" if constants.net.TESTNET else "Electrum" + name = "ElectrumG Testnet" if constants.net.TESTNET else "ElectrumG" title = '%s %s - %s' % (name, ELECTRUM_VERSION, self.wallet.basename()) extra = [self.wallet.db.get('wallet_type', '?')] @@ -558,8 +558,8 @@ def warn_if_watching_only(self): if self.wallet.is_watching_only(): msg = ' '.join([ _("This wallet is watching-only."), - _("This means you will not be able to spend Bitcoins with it."), - _("Make sure you own the seed phrase or the private keys, before you request Bitcoins to be sent to this wallet.") + _("This means you will not be able to spend BTGs with it."), + _("Make sure you own the seed phrase or the private keys, before you request BTGs to be sent to this wallet.") ]) self.show_warning(msg, title=_('Watch-only wallet')) @@ -576,7 +576,7 @@ def warn_if_testnet(self): msg = ''.join([ _("You are in testnet mode."), ' ', _("Testnet coins are worthless."), '\n', - _("Testnet is separate from the main Bitcoin network. It is used for testing.") + _("Testnet is separate from the main BitcoinGold network. It is used for testing.") ]) cb = QCheckBox(_("Don't show this again.")) cb_checked = False @@ -636,7 +636,7 @@ def backup_wallet(self): try: new_path = self.wallet.save_backup(backup_dir) except BaseException as reason: - self.show_critical(_("Electrum was unable to copy your wallet file to the specified location.") + "\n" + str(reason), title=_("Unable to create backup")) + self.show_critical(_("ElectrumG was unable to copy your wallet file to the specified location.") + "\n" + str(reason), title=_("Unable to create backup")) return msg = _("A copy of your wallet file was created in")+" '%s'" % str(new_path) self.show_message(msg, title=_("Wallet backup created")) @@ -744,7 +744,7 @@ def add_toggle_action(view_menu, tab): # Hence, this menu item will be at a "uniform location re macOS processes" preferences_action.setMenuRole(QAction.PreferencesRole) # make sure OS recognizes it as preferences # Add another preferences item, to also have a "uniform location for Electrum between different OSes" - tools_menu.addAction(_("Electrum preferences"), self.settings_dialog) + tools_menu.addAction(_("ElectrumG preferences"), self.settings_dialog) tools_menu.addAction(_("&Network"), self.gui_object.show_network_dialog).setEnabled(bool(self.network)) if self.network and self.network.local_watchtower: @@ -768,7 +768,7 @@ def add_toggle_action(view_menu, tab): help_menu = menubar.addMenu(_("&Help")) help_menu.addAction(_("&About"), self.show_about) help_menu.addAction(_("&Check for updates"), self.show_update_check) - help_menu.addAction(_("&Official website"), lambda: webopen("https://electrum.org")) + help_menu.addAction(_("&Official website"), lambda: webopen("https://bitcoingold.org/electrumg/")) help_menu.addSeparator() help_menu.addAction(_("&Documentation"), lambda: webopen("http://docs.electrum.org/")).setShortcut(QKeySequence.HelpContents) if not constants.net.TESTNET: @@ -783,18 +783,18 @@ def donate_to_server(self): d = self.network.get_donation_address() if d: host = self.network.get_parameters().server.host - self.pay_to_URI('bitcoin:%s?message=donation for %s'%(d, host)) + self.pay_to_URI('bitcoingold:%s?message=donation for %s'%(d, host)) else: self.show_error(_('No donation address for this server')) def show_about(self): - QMessageBox.about(self, "Electrum", + QMessageBox.about(self, "ElectrumG", (_("Version")+" %s" % ELECTRUM_VERSION + "\n\n" + - _("Electrum's focus is speed, with low resource usage and simplifying Bitcoin.") + " " + + _("ElectrumG's focus is speed, with low resource usage and simplifying BitcoinGold.") + " " + _("You do not need to perform regular backups, because your wallet can be " "recovered from a secret phrase that you can memorize or write on paper.") + " " + _("Startup times are instant because it operates in conjunction with high-performance " - "servers that handle the most complicated parts of the Bitcoin system.") + "\n\n" + + "servers that handle the most complicated parts of the BitcoinGold system.") + "\n\n" + _("Uses icons from the Icons8 icon pack (icons8.com)."))) def show_bitcoin_paper(self): @@ -816,10 +816,10 @@ def show_report_bug(self): msg = ' '.join([ _("Please report any bugs as issues on github:
"), f'''{constants.GIT_REPO_ISSUES_URL}

''', - _("Before reporting a bug, upgrade to the most recent version of Electrum (latest release or git HEAD), and include the version number in your report."), + _("Before reporting a bug, upgrade to the most recent version of ElectrumG (latest release or git HEAD), and include the version number in your report."), _("Try to explain not only what the bug is, but how it occurs.") ]) - self.show_message(msg, title="Electrum - " + _("Reporting Bugs"), rich_text=True) + self.show_message(msg, title="ElectrumG - " + _("Reporting Bugs"), rich_text=True) def notify_transactions(self): if self.tx_notification_queue.qsize() == 0: @@ -859,9 +859,9 @@ def notify(self, message): if self.tray: try: # this requires Qt 5.9 - self.tray.showMessage("Electrum", message, read_QIcon("electrum_dark_icon"), 20000) + self.tray.showMessage("ElectrumG", message, read_QIcon("electrum_dark_icon"), 20000) except TypeError: - self.tray.showMessage("Electrum", message, QSystemTrayIcon.Information, 20000) + self.tray.showMessage("ElectrumG", message, QSystemTrayIcon.Information, 20000) def timer_actions(self): self.request_list.refresh_status() @@ -884,7 +884,7 @@ def format_amount(self, amount_sat, is_diff=False, whitespaces=False) -> str: return self.config.format_amount(amount_sat, is_diff=is_diff, whitespaces=whitespaces) def format_amount_and_units(self, amount_sat, *, timestamp: int = None) -> str: - """Returns string with both bitcoin and fiat amounts, in desired units. + """Returns string with both BTGs and fiat amounts, in desired units. E.g. 500_000 -> '0.005 BTC (191.42 EUR)' """ text = self.config.format_amount_and_units(amount_sat) @@ -1097,8 +1097,8 @@ def on_expiry(i): _('This information is seen by the recipient if you send them a signed payment request.'), '\n\n', _('For on-chain requests, the address gets reserved until expiration. After that, it might get reused.'), ' ', - _('The bitcoin address never expires and will always be part of this electrum wallet.'), ' ', - _('You can reuse a bitcoin address any number of times but it is not good for your privacy.'), + _('The btg address never expires and will always be part of this electrumG wallet.'), ' ', + _('You can reuse a btg address any number of times but it is not good for your privacy.'), '\n\n', _('For Lightning requests, payments will not be accepted after the expiration.'), ]) diff --git a/electrum/gui/qt/qrwindow.py b/electrum/gui/qt/qrwindow.py index eca450eb3bd6..459bafcce298 100644 --- a/electrum/gui/qt/qrwindow.py +++ b/electrum/gui/qt/qrwindow.py @@ -36,7 +36,7 @@ class QR_Window(QWidget): def __init__(self, win): QWidget.__init__(self) self.win = win - self.setWindowTitle('Electrum - '+_('Payment Request')) + self.setWindowTitle('ElectrumG - '+_('Payment Request')) self.setMinimumSize(800, 800) self.setFocusPolicy(Qt.NoFocus) main_box = QHBoxLayout() diff --git a/electrum/gui/qt/update_checker.py b/electrum/gui/qt/update_checker.py index de27742cd8a5..01c1893c8a9b 100644 --- a/electrum/gui/qt/update_checker.py +++ b/electrum/gui/qt/update_checker.py @@ -30,7 +30,7 @@ class UpdateCheck(QDialog, Logger): def __init__(self, *, latest_version=None): QDialog.__init__(self) - self.setWindowTitle('Electrum - ' + _('Update Check')) + self.setWindowTitle('ElectrumG - ' + _('Update Check')) self.content = QVBoxLayout() self.content.setContentsMargins(*[10]*4) @@ -124,7 +124,7 @@ async def get_update_info(self): sig = base64.b64decode(sig) msg = version_num.encode('utf-8') if ecc.verify_message_with_address(address=address, sig65=sig, message=msg, - net=constants.BitcoinMainnet): + net=constants.BitcoinGoldMainnet): self.logger.info(f"valid sig for version announcement '{version_num}' from address '{address}'") break else: diff --git a/electrum/header_storage.py b/electrum/header_storage.py new file mode 100644 index 000000000000..3e5835b59d56 --- /dev/null +++ b/electrum/header_storage.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python +# +# Electrum - lightweight Bitcoin client +# Copyright (C) 2020 The Bitcoin Gold developers +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os +from enum import IntEnum +from typing import Optional +import diskcache + +from .logging import Logger +from . import blockchain +from .util import profiler, to_bytes, to_string, bfh, standardize_path +from .bitcoin import int_to_hex, rev_hex + +def Singleton(cls): + _instance = {} + + def _singleton(*args, **kargs): + if cls not in _instance: + _instance[cls] = cls(*args, **kargs) + return _instance[cls] + + return _singleton + +class HeaderStorageNotContinuousError(Exception): pass + + +# use shelve to save header +# key: bytes of header height string +# value: bytes of serialized header hex string +# @Singleton +class HeaderStorage(Logger): + + def __init__(self, path): + Logger.__init__(self) + self.path = standardize_path(path) + self._file_exists = bool(self.path and os.path.exists(self.path)) + self.logger.info(f"header path {self.path}") + self.db = diskcache.Cache(self.path) + + def _header_exist(self, height: int) -> bool: + try: + headerstr = self.db.get(str(height)) + + if headerstr is None: + return False + return True + except KeyError: + return False + + def save_header(self, header: dict) -> None: + if self._header_exist(header['block_height']): + self.logger.warning(f"block at height {header['block_height']} already exist, will be ignored") + return + + self.db[str(header['block_height'])] = blockchain.serialize_header(header) + + if header['block_height'] > self.get_latest(): + self.set_latest(header['block_height']) + self.logger.info(f"latest height of header storage update to {header['block_height']}") + + def read_header(self, height: int) -> Optional[dict]: + try: + headerstr = self.db.get(str(height)) + if headerstr is None: + return None + return blockchain.deserialize_header(bfh(headerstr), height) + except KeyError: + self.logger.warning(f"block at height {height} doesn't exist") + return None + + def delete_header(self, height: int) -> None: + del self.db[str(height)] + + # header mast be continuous + def save_header_chunk(self, headerlist: list) -> None: + if len(headerlist) == 0: + return None + + last_height = headerlist[0]['block_height'] + for header in headerlist[1:]: + if(header['block_height'] - last_height == 1): + last_height = header['block_height'] + else: + raise HeaderStorageNotContinuousError('header is not continuous during save chunk header') + + for header in headerlist: + self.db[str(header['block_height'])] = blockchain.serialize_header(header) + + self.logger.info(f"{len(headerlist)} blocks saved into header storage") + + if headerlist[-1]['block_height'] > self.get_latest(): + self.set_latest(headerlist[-1]['block_height']) + self.logger.info(f"latest height of header storage update to {headerlist[-1]['block_height']}") + + # height mast be continuous + def read_header_chunk(self, heightlist: list) -> Optional[list]: + if len(heightlist) == 0: + return None + + last_height = heightlist[0] + for height in heightlist[1:]: + if(height - last_height == 1): + last_height = height + else: + raise HeaderStorageNotContinuousError('height is not continuous during read chunk header') + + headerlist = [] + for height in heightlist: + try: + headerstr = self.db.get(str(height)) + if headerstr is None: + return None + headerlist.append(blockchain.deserialize_header(bfh(headerstr), height)) + except KeyError: + self.logger.warning(f"block at height {height} doesn't exist") + return None + + return headerlist + + # height mast be continuous + def delete_header_chunk(self, heightlist: list) -> None: + if len(heightlist) == 0: + return None + + last_height = heightlist[0] + for height in heightlist[1:]: + if(height - last_height == 1): + last_height = height + else: + raise HeaderStorageNotContinuousError('height is not continuous during read chunk header') + + for height in heightlist: + del self.db[str(height)] + + def set_latest(self, height: int): + self.db['latest'] = str(height) + + def get_latest(self) -> int: + try: + heightstr = self.db.get('latest') + if heightstr is None: + return 0 + return int(heightstr) + except KeyError: + return 0 + + diff --git a/electrum/interface.py b/electrum/interface.py index 34cbff1f772a..dd030d0f5dd9 100644 --- a/electrum/interface.py +++ b/electrum/interface.py @@ -591,35 +591,21 @@ async def get_block_header(self, height, assert_mode): return blockchain.deserialize_header(bytes.fromhex(res), height) async def request_chunk(self, height: int, tip=None, *, can_return_early=False): - if not is_non_negative_integer(height): - raise Exception(f"{repr(height)} is not a block height") - index = height // 2016 + # the concept of index here is different with legacy electrum + index = (height - constants.net.max_checkpoint()) // constants.net.CHUNK_SIZE if can_return_early and index in self._requested_chunks: return - self.logger.info(f"requesting chunk from height {height}") - size = 2016 + size = constants.net.CHUNK_SIZE if tip is not None: - size = min(size, tip - index * 2016 + 1) + size = min(size, tip - (constants.net.max_checkpoint() + index * constants.net.CHUNK_SIZE) + 1) size = max(size, 0) try: + self.logger.info(f"requesting chunk from height {height} to height {height + size - 1}") self._requested_chunks.add(index) - res = await self.session.send_request('blockchain.block.headers', [index * 2016, size]) + res = await self.session.send_request('blockchain.block.headers', [height, size]) finally: self._requested_chunks.discard(index) - assert_dict_contains_field(res, field_name='count') - assert_dict_contains_field(res, field_name='hex') - assert_dict_contains_field(res, field_name='max') - assert_non_negative_integer(res['count']) - assert_non_negative_integer(res['max']) - assert_hex_str(res['hex']) - if len(res['hex']) != HEADER_SIZE * 2 * res['count']: - raise RequestCorrupted('inconsistent chunk hex and count') - # we never request more than 2016 headers, but we enforce those fit in a single response - if res['max'] < 2016: - raise RequestCorrupted(f"server uses too low 'max' count for block.headers: {res['max']} < 2016") - if res['count'] != size: - raise RequestCorrupted(f"expected {size} headers but only got {res['count']}") - conn = self.blockchain.connect_chunk(index, res['hex']) + conn = self.blockchain.connect_chunk(height, res['hex']) if not conn: return conn, 0 return conn, res['count'] @@ -702,6 +688,9 @@ async def close(self, *, force_after: int = None): # monitor_connection will cancel tasks async def run_fetch_blocks(self): + + self.logger.info(f"start to subscribe latest block from server...") + header_queue = asyncio.Queue() await self.session.subscribe('blockchain.headers.subscribe', [], header_queue) while True: @@ -709,11 +698,21 @@ async def run_fetch_blocks(self): raw_header = item[0] height = raw_header['height'] header = blockchain.deserialize_header(bfh(raw_header['hex']), height) + self.logger.info(f"blockchain.headers.subscribe return new block at {height}") self.tip_header = header self.tip = height if self.tip < constants.net.max_checkpoint(): raise GracefulDisconnect('server tip below max checkpoint') self._mark_ready() + + # before preocess blocks after max checkpoint, we need to fetch number of + # constants.net.LWMA_AVERAGING_WINDOW blocks before max checkpoints to make + # target check success + for i in range(constants.net.max_checkpoint() - constants.net.LWMA_AVERAGING_WINDOW, constants.net.max_checkpoint()): + if not self.blockchain.header_exist(i): + header = await self.get_block_header(i, 'backward') + self.blockchain.save_header_without_update(header) + await self._process_header_at_tip() # header processing done util.trigger_callback('blockchain_updated') @@ -728,14 +727,18 @@ async def _process_header_at_tip(self): # another interface amended the blockchain self.logger.info(f"skipping header {height}") return - _, height = await self.step(height, header) - # in the simple case, height == self.tip+1 - if height <= self.tip: - await self.sync_until(height) + + # sync blocks after max checkpoint + await self.sync_until(self.blockchain.height() + 1) + + util.trigger_callback('blockchain_updated') async def sync_until(self, height, next_height=None): if next_height is None: next_height = self.tip + + self.logger.info(f"start to sync blocks from height {height} to height {next_height}") + last = None while last is None or height <= next_height: prev_last, prev_height = last, height @@ -747,7 +750,7 @@ async def sync_until(self, height, next_height=None): last, height = await self.step(height) continue util.trigger_callback('network_updated') - height = (height // 2016 * 2016) + num_headers + height = height + num_headers assert height <= next_height+1, (height, self.tip) last = 'catchup' else: diff --git a/electrum/lnaddr.py b/electrum/lnaddr.py index cd6954ee8586..65da421944ca 100644 --- a/electrum/lnaddr.py +++ b/electrum/lnaddr.py @@ -86,7 +86,7 @@ def bitarray_to_u5(barr): def encode_fallback(fallback: str, currency): """ Encode all supported fallback addresses. """ - if currency in [constants.BitcoinMainnet.SEGWIT_HRP, constants.BitcoinTestnet.SEGWIT_HRP]: + if currency in [constants.BitcoinGoldMainnet.SEGWIT_HRP, constants.BitcoinGoldTestnet.SEGWIT_HRP]: wver, wprog_ints = segwit_addr.decode_segwit_address(currency, fallback) if wver is not None: wprog = bytes(wprog_ints) @@ -105,7 +105,7 @@ def encode_fallback(fallback: str, currency): def parse_fallback(fallback, currency): - if currency in [constants.BitcoinMainnet.SEGWIT_HRP, constants.BitcoinTestnet.SEGWIT_HRP]: + if currency in [constants.BitcoinGoldMainnet.SEGWIT_HRP, constants.BitcoinGoldTestnet.SEGWIT_HRP]: wver = fallback[0:5].uint if wver == 17: addr=hash160_to_b58_address(fallback[5:].tobytes(), base58_prefix_map[currency][0]) @@ -125,8 +125,8 @@ def parse_fallback(fallback, currency): # Map of classical and witness address prefixes base58_prefix_map = { - constants.BitcoinMainnet.SEGWIT_HRP : (constants.BitcoinMainnet.ADDRTYPE_P2PKH, constants.BitcoinMainnet.ADDRTYPE_P2SH), - constants.BitcoinTestnet.SEGWIT_HRP : (constants.BitcoinTestnet.ADDRTYPE_P2PKH, constants.BitcoinTestnet.ADDRTYPE_P2SH) + constants.BitcoinGoldMainnet.SEGWIT_HRP : (constants.BitcoinGoldMainnet.ADDRTYPE_P2PKH, constants.BitcoinGoldMainnet.ADDRTYPE_P2SH), + constants.BitcoinGoldTestnet.SEGWIT_HRP : (constants.BitcoinGoldTestnet.ADDRTYPE_P2PKH, constants.BitcoinGoldTestnet.ADDRTYPE_P2SH) } def is_p2pkh(currency, prefix): diff --git a/electrum/lnworker.py b/electrum/lnworker.py index e96bb5da1726..f0b36a9efdd8 100644 --- a/electrum/lnworker.py +++ b/electrum/lnworker.py @@ -407,7 +407,7 @@ async def _get_next_peers_to_try(self) -> Sequence[LNPeerAddr]: # getting desperate... let's try hardcoded fallback list of peers if constants.net in (constants.BitcoinTestnet,): fallback_list = FALLBACK_NODE_LIST_TESTNET - elif constants.net in (constants.BitcoinMainnet,): + elif constants.net in (constants.BitcoinGoldMainnet,): fallback_list = FALLBACK_NODE_LIST_MAINNET else: return [] # regtest?? @@ -1526,7 +1526,7 @@ def create_routes_for_payment( # for trampoline mpp payments we have to restrict ourselves to pay # to a single node due to some incompatibility in Eclair, see: # https://github.com/ACINQ/eclair/issues/1723 - use_singe_node = not self.channel_db and constants.net is constants.BitcoinMainnet + use_singe_node = not self.channel_db and constants.net is constants.BitcoinGoldMainnet split_configurations = suggest_splits(amount_msat, channels_with_funds, single_node=use_singe_node) self.logger.info(f'suggest_split {amount_msat} returned {len(split_configurations)} configurations') diff --git a/electrum/plugins/bitbox02/bitbox02.py b/electrum/plugins/bitbox02/bitbox02.py index 97750bb30e95..5a0397ae0394 100644 --- a/electrum/plugins/bitbox02/bitbox02.py +++ b/electrum/plugins/bitbox02/bitbox02.py @@ -203,7 +203,7 @@ def get_password_for_storage_encryption(self) -> str: derivation = get_derivation_used_for_hw_device_encryption() derivation_list = bip32.convert_bip32_path_to_list_of_uint32(derivation) xpub = self.bitbox02_device.electrum_encryption_key(derivation_list) - node = bip32.BIP32Node.from_xkey(xpub, net = constants.BitcoinMainnet()).subkey_at_public_derivation(()) + node = bip32.BIP32Node.from_xkey(xpub, net = constants.BitcoinGoldMainnet()).subkey_at_public_derivation(()) return node.eckey.get_public_key_bytes(compressed=True).hex() @runs_in_hwd_thread diff --git a/electrum/plugins/digitalbitbox/digitalbitbox.py b/electrum/plugins/digitalbitbox/digitalbitbox.py index f9c03e311495..f75b1ec66870 100644 --- a/electrum/plugins/digitalbitbox/digitalbitbox.py +++ b/electrum/plugins/digitalbitbox/digitalbitbox.py @@ -116,7 +116,7 @@ def get_xpub(self, bip32_path, xtype): # only ever returns the mainnet standard type, but it is agnostic # to the type when signing. if xtype != 'standard' or constants.net.TESTNET: - node = BIP32Node.from_xkey(xpub, net=constants.BitcoinMainnet) + node = BIP32Node.from_xkey(xpub, net=constants.BitcoinGoldMainnet) xpub = node._replace(xtype=xtype).to_xpub() return xpub else: diff --git a/electrum/plugins/keepkey/keepkey.py b/electrum/plugins/keepkey/keepkey.py index 8296ff58a947..4c372500ba90 100644 --- a/electrum/plugins/keepkey/keepkey.py +++ b/electrum/plugins/keepkey/keepkey.py @@ -199,7 +199,7 @@ def get_client(self, keystore, force_pair=True, *, return client def get_coin_name(self): - return "Testnet" if constants.net.TESTNET else "Bitcoin" + return "Testnet" if constants.net.TESTNET else "Bgold" def initialize_device(self, device_id, wizard, handler): # Initialization method diff --git a/electrum/plugins/ledger/auth2fa.py b/electrum/plugins/ledger/auth2fa.py index 638285e2d094..4498b1283780 100644 --- a/electrum/plugins/ledger/auth2fa.py +++ b/electrum/plugins/ledger/auth2fa.py @@ -116,7 +116,7 @@ def pin_changed(s): text = addr[:i] + '' + addr[i:i+1] + '' + addr[i+1:] else: # pin needs to be created from mainnet address - addr_mainnet = bitcoin.script_to_address(bitcoin.address_to_script(addr), net=constants.BitcoinMainnet) + addr_mainnet = bitcoin.script_to_address(bitcoin.address_to_script(addr), net=constants.BitcoinGoldMainnet) addr_mainnet = addr_mainnet[:i] + '' + addr_mainnet[i:i+1] + '' + addr_mainnet[i+1:] text = str(addr) + '\n' + str(addr_mainnet) self.addrtext.setHtml(str(text)) diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py index be9d7b859872..feb72c4efd60 100644 --- a/electrum/plugins/trezor/trezor.py +++ b/electrum/plugins/trezor/trezor.py @@ -206,7 +206,7 @@ def get_client(self, keystore, force_pair=True, *, return client def get_coin_name(self): - return "Testnet" if constants.net.TESTNET else "Bitcoin" + return "Testnet" if constants.net.TESTNET else "Bgold" def initialize_device(self, device_id, wizard, handler): # Initialization method diff --git a/electrum/scripts/get-checkpoint-arry.py b/electrum/scripts/get-checkpoint-arry.py new file mode 100644 index 000000000000..616b499a6971 --- /dev/null +++ b/electrum/scripts/get-checkpoint-arry.py @@ -0,0 +1,398 @@ +#!/usr/bin/env python + +from json import loads, dumps +from sys import exit, argv +import base64 +import urllib.request, urllib.error, urllib.parse +from urllib.error import HTTPError + +from electrum import constants +from struct import unpack_from, unpack +from electrum.equihash import is_gbp_valid + +if len(argv) < 2: + print('Arguments: ') + sys.exit(1) + +def averaging_window_timespan(): + return constants.net.DIGI_AVERAGING_WINDOW * constants.net.POW_TARGET_SPACING + +def min_actual_timespan(): + return (averaging_window_timespan() * (100 - constants.net.DIGI_MAX_ADJUST_UP)) // 100 + +def max_actual_timespan(): + return (averaging_window_timespan() * (100 + constants.net.DIGI_MAX_ADJUST_DOWN)) // 100 + +def is_post_btg_fork(height): + return height >= constants.net.BTG_HEIGHT + +def is_post_equihash_fork(height): + return height >= constants.net.EQUIHASH_FORK_HEIGHT + +def needs_retarget(height): + return is_post_btg_fork(height) or (height % difficulty_adjustment_interval() == 0) + + +def difficulty_adjustment_interval(): + return constants.net.POW_TARGET_TIMESPAN_LEGACY // constants.net.POW_TARGET_SPACING + +def get_header_size(height): + size = constants.net.HEADER_SIZE_LEGACY + + if is_post_btg_fork(height): + solution_size = get_equihash_params(height).get_solution_size() + solution_size_compact = len(var_int(solution_size)) // 2 - 1 + size += solution_size_compact + solution_size + + return size + +def get_equihash_params(height): + return constants.net.EQUIHASH_PARAMS if height < constants.net.EQUIHASH_FORK_HEIGHT \ + else constants.net.EQUIHASH_PARAMS_FORK + +def var_int(i): + # https://en.bitcoin.it/wiki/Protocol_specification#Variable_length_integer + if i < 0xfd: + return int_to_hex(i) + elif i <= 0xffff: + return "fd"+int_to_hex(i, 2) + elif i <= 0xffffffff: + return "fe"+int_to_hex(i, 4) + else: + return "ff"+int_to_hex(i, 8) + + +def var_int_read(value, start): + size = value[start] + start += 1 + + if size == 253: + (size,) = unpack_from(' constants.net.POW_LIMIT: + new_target = constants.net.POW_LIMIT + # Zawy LWMA (new) + else: + new_target = get_lwma_target(height, headers, constants.net.LWMA_ADJUST_WEIGHT, + constants.net.LWMA_MIN_DENOMINATOR) + + return new_target + +def get_legacy_target(height, headers): + last_height = (height - 1) + last = get_header(last_height, headers) + + if constants.net == constants.BitcoinGoldRegtest: + new_target = bits_to_target(last.get('bits')) + elif height % difficulty_adjustment_interval() != 0: + if constants.net == constants.BitcoinGoldTestnet: + cur = get_header(height, headers) + + # Special testnet handling + if cur.get('timestamp') > last.get('timestamp') + constants.net.POW_TARGET_SPACING * 2: + new_target = constants.net.POW_LIMIT_LEGACY + else: + # Return the last non-special-min-difficulty-rules-block + prev_height = last_height - 1 + prev = get_header(prev_height, headers) + + while prev is not None and last.get('block_height') % difficulty_adjustment_interval() != 0 \ + and last.get('bits') == constants.net.POW_LIMIT: + last = prev + prev_height -= 1 + prev = get_header(prev_height, headers) + + new_target = bits_to_target(last.get('bits')) + else: + new_target = bits_to_target(last.get('bits')) + else: + first = read_header(height - difficulty_adjustment_interval()) + target = bits_to_target(last.get('bits')) + + actual_timespan = last.get('timestamp') - first.get('timestamp') + target_timespan = constants.net.POW_TARGET_TIMESPAN_LEGACY + actual_timespan = max(actual_timespan, target_timespan // 4) + actual_timespan = min(actual_timespan, target_timespan * 4) + + new_target = min(constants.net.POW_LIMIT_LEGACY, (target * actual_timespan) // target_timespan) + + return new_target + +def get_lwma_target(height, headers, weight, denominator): + cur = get_header(height, headers) + last_height = (height - 1) + last = get_header(last_height, headers) + + # Special testnet handling + if constants.net == constants.BitcoinGoldRegtest: + new_target = bits_to_target(last.get('bits')) + elif constants.net == constants.BitcoinGoldTestnet and cur.get('timestamp') > last.get('timestamp') + constants.net.POW_TARGET_SPACING * 2: + new_target = constants.net.POW_LIMIT + else: + total = 0 + t = 0 + j = 0 + + assert (height - constants.net.LWMA_AVERAGING_WINDOW) > 0 + + ts = 6 * constants.net.POW_TARGET_SPACING + + # Loop through N most recent blocks. "< height", not "<=". + # height-1 = most recently solved block + for i in range(height - constants.net.LWMA_AVERAGING_WINDOW, height): + cur = get_header(i, headers) + prev_height = (i - 1) + prev = get_header(prev_height, headers) + + solvetime = cur.get('timestamp') - prev.get('timestamp') + + if constants.net.LWMA_SOLVETIME_LIMITATION and solvetime > ts: + solvetime = ts + + j += 1 + t += solvetime * j + total += bits_to_target(cur.get('bits')) // (weight * constants.net.LWMA_AVERAGING_WINDOW * constants.net.LWMA_AVERAGING_WINDOW) + + # Keep t reasonable in case strange solvetimes occurred. + if t < constants.net.LWMA_AVERAGING_WINDOW * weight // denominator: + t = constants.net.LWMA_AVERAGING_WINDOW * weight // denominator + + new_target = t * total + + if new_target > constants.net.POW_LIMIT: + new_target = constants.net.POW_LIMIT + + return new_target + +def get_digishield_target(height, headers): + pow_limit = constants.net.POW_LIMIT + height -= 1 + last = get_header(height, headers) + + if last is None: + new_target = pow_limit + elif constants.net == constants.BitcoinGoldRegtest: + new_target = bits_to_target(last.get('bits')) + else: + first = last + total = 0 + i = 0 + + while i < constants.net.DIGI_AVERAGING_WINDOW and first is not None: + total += bits_to_target(first.get('bits')) + prev_height = height - i - 1 + first = get_header(prev_height, headers) + i += 1 + + # This should never happen else we have a serious problem + assert first is not None + + avg = total // constants.net.DIGI_AVERAGING_WINDOW + actual_timespan = get_mediantime_past(headers, last.get('block_height')) \ + - get_mediantime_past(headers, first.get('block_height')) + + if actual_timespan < min_actual_timespan(): + actual_timespan = min_actual_timespan() + + if actual_timespan > max_actual_timespan(): + actual_timespan = max_actual_timespan() + + avg = avg // averaging_window_timespan() + avg *= actual_timespan + + if avg > pow_limit: + avg = pow_limit + + new_target = int(avg) + + return new_target + +def get_mediantime_past(headers, start_height): + header = get_header(start_height, headers) + + times = [] + i = 0 + + while i < 11 and header is not None: + times.append(header.get('timestamp')) + prev_height = start_height - i - 1 + header = get_header(prev_height, headers) + i += 1 + + times.sort() + return times[(len(times) // 2)] + +def bits_to_target(bits: int) -> int: + size = bits >> 24 + word = bits & 0x007fffff + + if size <= 3: + word >>= 8 * (3 - size) + ret = word + else: + ret = word + ret <<= 8 * (size - 3) + + return ret + +def target_to_bits(target: int) -> int: + assert target >= 0 + nsize = (target.bit_length() + 7) // 8 + if nsize <= 3: + c = target << (8 * (3 - nsize)) + else: + c = target >> (8 * (nsize - 3)) + if c & 0x00800000: + c >>= 8 + nsize += 1 + assert (c & ~0x007fffff) == 0 + assert nsize < 256 + c |= nsize << 24 + return c + +def rpc(method, params): + data = { + "jsonrpc": "1.0", + "id":"1", + "method": method, + "params": params + } + + data_json = dumps(data) + username = + password = + port = + + url = "http://:{}/".format(port) + req = urllib.request.Request(url, data_json.encode("utf-8"), {'content-type': 'application/json'}) + + base64string = base64.encodestring(('%s:%s' % (username, password)).encode()).decode().replace('\n', '') + req.add_header("Authorization", "Basic %s" % base64string) + + try: + response_stream = urllib.request.urlopen(req) + except HTTPError as e: + content = e.read() + print('error content: ', content) + return None + + json_response = response_stream.read() + + return loads(json_response) + +def checkpoints(): + return constants.net.CHECKPOINTS + +def get_header_from_block(block): + + header = { + 'version': block['version'], + 'prev_block_hash': block['previousblockhash'], + 'merkle_root': block['merkleroot'], + 'block_height': block['height'], + 'reserved': '00000000000000000000000000000000000000000000000000000000', + 'timestamp': block['time'], + 'bits': int(block['bits'], 16), + 'nonce': block['nonce'], + 'solution':block['solution'] + } + + return header + +def read_header(height: int) -> None: + print('read header of block ', height) + h = rpc('getblockhash', [height])['result'] + block = rpc('getblock', [h])['result'] + + return get_header_from_block(block) + +def get_header(height : int, headers=None) -> None: + return read_header(height) + +def get_block(height: int) -> None: + print('read block at height: ', height) + h = rpc('getblockhash', [height])['result'] + block = rpc('getblock', [h])['result'] + + return block + +i = int(argv[1]) +INTERVAL = 2016 # Electrum checkpoints are blocks 2015, 2015 + 2016, 2015 + 2016*2, ... + +block_count = int(rpc('getblockcount', [])['result']) +print(('Network latest block: {}'.format(block_count))) +while True: + try: + block = get_block(i) + cp = [ + block['hash'], + get_target(i, get_header_from_block(block)) + ] + + with open('checkpoints_output.json', 'a+') as f: + f.write(dumps(cp, indent=4, separators=(',', ':')) + ',') + + i += INTERVAL + if i > block_count: + print('Done.') + break + except: + print('error occured during handle block ', i, 'please restart with this block') + break + diff --git a/electrum/scripts/get-testnet-checkpoints.sh b/electrum/scripts/get-testnet-checkpoints.sh new file mode 100644 index 000000000000..d76e666930aa --- /dev/null +++ b/electrum/scripts/get-testnet-checkpoints.sh @@ -0,0 +1,17 @@ +#!/bin/bash + + +echo "begin to find checkpoints hash..." + +checkpoints="[" + +for((i=2015; i<78152; i+=2016)) +do + hash=`bgold-cli -testnet -rpcuser=tolak -rpcpassword=123 -rpcport=18332 getblockhash $i` + echo "get block hash: $i - $hash" + checkpoints=${checkpoints}"\n[\n \"$hash\",\n 0\n]," +done +checkpoints=${checkpoints}"\n]" + +echo "checkpoints of testnet is: " +echo -e $checkpoints diff --git a/electrum/servers.json b/electrum/servers.json index 5bf0a3058cc2..f48d4d42f766 100644 --- a/electrum/servers.json +++ b/electrum/servers.json @@ -1,411 +1,8 @@ { - "3smoooajg7qqac2y.onion": { + "test-electrum.bitcoingold.dev": { "pruning": "-", "s": "50002", "t": "50001", - "version": "1.4" - }, - "81-7-10-251.blue.kundencontroller.de": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "E-X.not.fyi": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "VPS.hsmiths.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "b.ooze.cc": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "bitcoin.corgi.party": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "bitcoin3nqy3db7c.onion": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "bitcoins.sk": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "btc.cihar.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "btc.xskyx.net": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum.jochen-hoenicke.de": { - "pruning": "-", - "s": "50005", - "t": "50003", - "version": "1.4" - }, - "dragon085.startdedicated.de": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "e-1.claudioboxx.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "e.keff.org": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum-server.ninja": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum-unlimited.criptolayer.net": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "electrum.eff.ro": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum.festivaldelhumor.org": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum.hsmiths.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum.leblancnet.us": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum.mindspot.org": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "electrum.qtornado.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum.taborsky.cz": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "electrum.villocq.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum2.eff.ro": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum2.villocq.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrumx.bot.nu": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrumx.ddns.net": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrumx.ftp.sh": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "electrumx.soon.it": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrumxhqdsmlu.onion": { - "pruning": "-", - "t": "50001", - "version": "1.4" - }, - "elx01.knas.systems": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "fedaykin.goip.de": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "fn.48.org": { - "pruning": "-", - "s": "50002", - "t": "50003", - "version": "1.4" - }, - "hsmiths4fyqlw5xw.onion": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "hsmiths5mjk6uijs.onion": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum.emzy.de": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "ndnd.selfhost.eu": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "ndndword5lpb7eex.onion": { - "pruning": "-", - "t": "50001", - "version": "1.4" - }, - "orannis.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "ozahtqwp25chjdjd.onion": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "qtornadoklbgdyww.onion": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "rbx.curalle.ovh": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "s7clinmo4cazmhul.onion": { - "pruning": "-", - "t": "50001", - "version": "1.4" - }, - "tardis.bauerj.eu": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "technetium.network": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "tomscryptos.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "ulrichard.ch": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "vmd27610.contaboserver.net": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "vmd30612.contaboserver.net": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "wsw6tua3xl24gsmi264zaep6seppjyrkyucpsmuxnjzyt3f3j6swshad.onion": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "xray587.startdedicated.de": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "yuio.top": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "bitcoin.dragon.zone": { - "pruning": "-", - "s": "50004", - "t": "50003", - "version": "1.4" - }, - "ecdsa.net" : { - "pruning": "-", - "s": "110", - "t": "50001", - "version": "1.4" - }, - "btc.usebsv.com": { - "pruning": "-", - "s": "50006", - "version": "1.4" - }, - "e2.keff.org": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrum.hodlister.co": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "electrum3.hodlister.co": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "electrum5.hodlister.co": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "electrumx.electricnewyear.net": { - "pruning": "-", - "s": "50002", - "version": "1.4" - }, - "fortress.qtornado.com": { - "pruning": "-", - "s": "443", - "t": "50001", - "version": "1.4" - }, - "green-gold.westeurope.cloudapp.azure.com": { - "pruning": "-", - "s": "56002", - "t": "56001", - "version": "1.4" - }, - "electrumx.erbium.eu": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "electrumx-core.1209k.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4.2" - }, - "bitcoin.aranguren.org": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4.2" - }, - "bitcoin.lukechilds.co": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4.2" - }, - "electrum.aantonop.com": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4.2" - }, - "electrum.bitkoins.nl": { - "pruning": "-", - "s": "50512", - "t": "50001", - "version": "1.4.2" - }, - "electrum.blockstream.info": { - "pruning": "-", - "s": "50002", - "t": "50001", - "version": "1.4" - }, - "blockstream.info": { - "pruning": "-", - "s": "700", - "t": "110", - "version": "1.4" + "version": "1.9.2" } -} +} \ No newline at end of file diff --git a/electrum/servers_testnet.json b/electrum/servers_testnet.json index 85a516040fc8..65e9be3ecffe 100644 --- a/electrum/servers_testnet.json +++ b/electrum/servers_testnet.json @@ -1,66 +1,9 @@ { - "hsmithsxurybd7uh.onion": { - "pruning": "-", - "s": "53012", - "t": "53011", - "version": "1.4" - }, - "testnet.hsmiths.com": { - "pruning": "-", - "s": "53012", - "t": "53011", - "version": "1.4" - }, - "testnet.qtornado.com": { - "pruning": "-", - "s": "51002", - "t": "51001", - "version": "1.4.2" - }, - "testnet1.bauerj.eu": { + "test-electrum.bitcoingold.dev": { "pruning": "-", "s": "50002", - "version": "1.4.2" - }, - "tn.not.fyi": { - "pruning": "-", - "s": "55002", - "t": "55001", - "version": "1.4" - }, - "bitcoin.cluelessperson.com": { - "pruning": "-", - "s": "51002", - "t": "51001", - "version": "1.4" - }, - "electrum.blockstream.info": { - "pruning": "-", - "s": "60002", - "t": "60001", - "version": "1.4" - }, - "explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion": { - "pruning": "-", - "t": "143", - "version": "1.4" - }, - "testnet.aranguren.org": { - "pruning": "-", - "s": "51002", - "t": "51001", - "version": "1.4.2" - }, - "wgzwu3vg3i54wayx.onion": { - "pruning": "-", - "s": "51002", - "t": "51001", - "version": "1.4.2" - }, - "blockstream.info": { - "pruning": "-", - "s": "993", - "t": "143", - "version": "1.4" + "t": "50001", + "version": "1.9.2" } } + diff --git a/electrum/simple_config.py b/electrum/simple_config.py index 3ab248da71ff..3521fac51c87 100644 --- a/electrum/simple_config.py +++ b/electrum/simple_config.py @@ -560,7 +560,7 @@ def fee_per_kb(self, dyn: bool=None, mempool: bool=None, fee_level: float=None) fee_level: float between 0.0 and 1.0, representing fee slider position """ - if constants.net is constants.BitcoinRegtest: + if constants.net is constants.BitcoinGoldRegtest: return FEERATE_REGTEST_HARDCODED if dyn is None: dyn = self.is_dynfee() diff --git a/electrum/submarine_swaps.py b/electrum/submarine_swaps.py index e5ad617d2b6b..704d49c60661 100644 --- a/electrum/submarine_swaps.py +++ b/electrum/submarine_swaps.py @@ -144,7 +144,7 @@ def __init__(self, *, wallet: 'Abstract_Wallet', lnworker: 'LNWallet'): if swap.is_reverse and swap.prepay_hash is not None: self.prepayments[swap.prepay_hash] = bytes.fromhex(k) # api url - if constants.net == constants.BitcoinMainnet: + if constants.net == constants.BitcoinGoldMainnet: self.api_url = API_URL_MAINNET elif constants.net == constants.BitcoinTestnet: self.api_url = API_URL_TESTNET diff --git a/electrum/tests/scripts/header-handle.py b/electrum/tests/scripts/header-handle.py new file mode 100644 index 000000000000..22f727000538 --- /dev/null +++ b/electrum/tests/scripts/header-handle.py @@ -0,0 +1,152 @@ + +bfh = bytes.fromhex + + +def bh2u(x: bytes) -> str: + """ + str with hex representation of a bytes-like object + + >>> x = bytes((1, 2, 10)) + >>> bh2u(x) + '01020A' + """ + return x.hex() + +def rev_hex(s: str) -> str: + return bh2u(bfh(s)[::-1]) + + +def int_to_hex(i: int, length: int=1) -> str: + """Converts int to little-endian hex string. + `length` is the number of bytes available + """ + if not isinstance(i, int): + raise TypeError('{} instead of int'.format(i)) + range_size = pow(256, length) + if i < -(range_size//2) or i >= range_size: + raise OverflowError('cannot convert int {} to hex ({} bytes)'.format(i, length)) + if i < 0: + # two's complement + i = range_size + i + s = hex(i)[2:].rstrip('L') + s = "0"*(2*length - len(s)) + s + return rev_hex(s) + +def hash_encode(x: bytes) -> str: + return bh2u(x[::-1]) + +def serialize_header(header_dict: dict) -> str: + s = int_to_hex(header_dict['version'], 4) \ + + rev_hex(header_dict['prev_block_hash']) \ + + rev_hex(header_dict['merkle_root']) + + # not legacy block + if header_dict.get('block_height') >= 1: + s += int_to_hex(header_dict.get('block_height'), 4) \ + + rev_hex(header_dict.get('reserved')) + + s += int_to_hex(header_dict.get('timestamp'), 4) \ + + int_to_hex(header_dict.get('bits'), 4) + + # legacy block + if header_dict.get('block_height') < 1: + s += rev_hex(header_dict.get('nonce'))[:8] + else: + s += rev_hex(header_dict.get('nonce')) \ + + rev_hex(header_dict.get('solution')) + + return s + +def deserialize_header(s: bytes, height: int) -> dict: + if not s: + return + + # original blok + if height < 1: + if len(s) != 80: + return None + else: + if len(s) < 140: + return None + + hex_to_int = lambda s: int.from_bytes(s, byteorder='little') + h = {} + h['block_height'] = height + h['version'] = hex_to_int(s[0:4]) + h['prev_block_hash'] = hash_encode(s[4:36]) + h['merkle_root'] = hash_encode(s[36:68]) + + # original block + if height < 1: + h['timestamp'] = hex_to_int(s[68:72]) + h['bits'] = hex_to_int(s[72:76]) + h['nonce'] = hex_to_int(s[76:80]) + else: + h['reserved'] = hash_encode(s[72:100]) + h['timestamp'] = hex_to_int(s[100:104]) + h['bits'] = hex_to_int(s[104:108]) + h['nonce'] = hex_to_int(s[108:140]) + h['solution'] = hash_encode(s[140:]) + + return h + +# All block header data below are from Bitcoin Gold testnet +def dump_78190() -> str: + header = { + 'version': 536870912, + 'prev_block_hash': '0006670b8b876c13f847b5b190097bec8f225b948b8a4dc4a52246324c225815', + 'merkle_root': 'bfb0f27df25d67a12c8088db1470cb644603e21d8c9fb22b3277fca75f8fd076', + 'block_height': 78190, + 'reserved': '00000000000000000000000000000000000000000000000000000000', + 'timestamp': 1591182462, + 'bits': 0x1f07ffff, + 'nonce': '0000052f0000000000000000000000000000000000000000000000000003168f', + 'solution':'141ad6110bc7cd252f7f15ea33f4da474d2cb935c136bf8e9946515cb577d2d5e6252efb6b06b56a54e9d92a81152f76bff21a9c723855f35d7c05dccea532407a1eb796e0e9a3c9d4f9a647a9e1d5090059fc213f3b6997ec110f0d1462919411bd5434' + } + + return serialize_header(header) + + +def dump_78191() -> str: + header = { + 'version': 536870912, + 'prev_block_hash': '0001e3b67be015ee30ad46ef53fd273807af43847e399d25b5aee784ad36ae28', + 'merkle_root': '4aed2ab8d5da31cbf4007c22d004a59bf6b82048481d8dfd235f34ecb5addc1e', + 'block_height': 78191, + 'reserved': '00000000000000000000000000000000000000000000000000000000', + 'timestamp': 1591185960, + 'bits': 0x1f07ffff, + 'nonce': '000000480000000000000000000000000000000000000000000000000007168f', + 'solution':'075c778555fc06bbc73fca0dd1e26a8b4e8bfccf14592cd83954ef6131c1ceddd6d298496a86cc2b86c9a68a9b5c7b7a63233584f6e6a998b2a5f3bf1634239762bca16365db2eff7019d6684383ff50711a3ec791174ad7fc70f60e394a232c6971a55e' + } + + return serialize_header(header) + + +def dump_78192() -> str: + header = { + 'version': 536870912, + 'prev_block_hash': '0002542468c9827fc1b310cd92df8f3b02704fec256834baec4cc2de36b6ada2', + 'merkle_root': 'e1500a34006a7cec807f52b487a564fe447a1dcd7388be1a00e0bfc62c6192eb', + 'block_height': 78192, + 'reserved': '00000000000000000000000000000000000000000000000000000000', + 'timestamp': 1591188771, + 'bits': 0x1f07ffff, + 'nonce': '000005bf000000000000000000000000000000000000000000000000000a168f', + 'solution':'0ec1397e1de32303551857579402acbbe0a0beafdaff7e7959204dc5a7bb471d77c8da095353b2338647e0c69423fbfabe0610cea64fcca6c587f67797148a7a3e3717f8ef2cb395d48d7c55966a3b3e7f6646acfb7fc9a5a04f577829c706f9f9cdd963' + } + + return serialize_header(header) + + +if __name__ == '__main__': + print('============ 78190 =============') + print(dump_78190()) + print(deserialize_header(bfh(dump_78190()), 78190)['block_height'] == 78190) + print('============ 78191 =============') + print(dump_78191()) + print(deserialize_header(bfh(dump_78191()), 78191)['block_height'] == 78191) + print('============ 78192 =============') + print(dump_78192()) + print(deserialize_header(bfh(dump_78192()), 78192)['block_height'] == 78192) + diff --git a/electrum/tests/test_equihash.py b/electrum/tests/test_equihash.py new file mode 100644 index 000000000000..98595dcf1ed4 --- /dev/null +++ b/electrum/tests/test_equihash.py @@ -0,0 +1,37 @@ +import unittest + +from ..blockchain import serialize_header, rev_hex, uint256_from_bytes, var_int_read, bfh +from ..equihash import validate_params, is_gbp_valid + + +class TestEquihash(unittest.TestCase): + def test_params(self): + self.assertRaises(ValueError, validate_params, 0, 1) + self.assertRaises(ValueError, validate_params, 32, 0) + + validate_params(200, 9) + validate_params(48, 5) + + def test_validate_solution(self): + header = { + 'merkle_root': 'a0c38df01cd66ccd636c2917472002b90f40c69f177585793167c7c96cc00aea', + 'bits': '207fffff', + 'block_height': 24156, + 'version': 536870912, + 'timestamp': 1520027553, + 'reserved': '00000000000000000000000000000000000000000000000000000000', + 'solution': '269125e395b85db52eafd3b401615665ab0407b725253552073a1b6eefe092c20d02250024', + 'nonce': '0000b0e08b5b13938bcda848f480619e320ceeee9175aef1630e2a6a78f30005', + 'prev_block_hash': '42e56ff42ad233fa1444b4fbb23ea69e85a196ad4e4017292563ecef6561d59b' + } + + n = 48 + k = 5 + + header_bytes = bytes.fromhex(serialize_header(header, False)) + nonce = uint256_from_bytes(bfh(header.get('nonce'))[::-1]) + solution = bfh(header.get('solution'))[::-1] + offset, length = var_int_read(solution, 0) + solution = solution[offset:] + + self.assertTrue(is_gbp_valid(header_bytes, nonce, solution, n, k)) diff --git a/electrum/tests/test_header_storage.py b/electrum/tests/test_header_storage.py new file mode 100644 index 000000000000..d4950bb9a5ee --- /dev/null +++ b/electrum/tests/test_header_storage.py @@ -0,0 +1,148 @@ +import os, shutil +import unittest +from typing import NamedTuple + +from electrum.util import to_bytes, bh2u +from electrum.header_storage import HeaderStorage, HeaderStorageNotContinuousError + + +class HeaderCase(NamedTuple): + height: int + hex: str + data: dict + +# Check python code ./scripts/header-handle.py to see how test case data generated +HEADER_TEST_CASES = [ + HeaderCase( + height=78190, + hex='000000201558224c324622a5c44d8a8b945b228fec7b0990b1b547f8136c878b0b67060076d08f5fa7fc77322bb29f8c1de2034664cb7014db88802ca1675df27df2b0bf6e310100000000000000000000000000000000000000000000000000000000007e84d75effff071f8f1603000000000000000000000000000000000000000000000000002f0500003454bd11949162140d0f11ec97693b3f21fc590009d5e1a947a6f9d4c9a3e9e096b71e7a4032a5cedc057c5df35538729c1af2bf762f15812ad9e9546ab5066bfb2e25e6d5d277b55c5146998ebf36c135b92c4d47daf433ea157f2f25cdc70b11d61a14', + data={ + 'version': 536870912, + 'prev_block_hash': '0006670b8b876c13f847b5b190097bec8f225b948b8a4dc4a52246324c225815', + 'merkle_root': 'bfb0f27df25d67a12c8088db1470cb644603e21d8c9fb22b3277fca75f8fd076', + 'block_height': 78190, + 'reserved': '00000000000000000000000000000000000000000000000000000000', + 'timestamp': 1591182462, + 'bits': 0x1f07ffff, + 'nonce': '0000052f0000000000000000000000000000000000000000000000000003168f', + 'solution':'141ad6110bc7cd252f7f15ea33f4da474d2cb935c136bf8e9946515cb577d2d5e6252efb6b06b56a54e9d92a81152f76bff21a9c723855f35d7c05dccea532407a1eb796e0e9a3c9d4f9a647a9e1d5090059fc213f3b6997ec110f0d1462919411bd5434' + } + ), + HeaderCase( + height=78191, + hex='0000002028ae36ad84e7aeb5259d397e8443af073827fd53ef46ad30ee15e07bb6e301001edcadb5ec345f23fd8d1d484820b8f69ba504d0227c00f4cb31dad5b82aed4a6f310100000000000000000000000000000000000000000000000000000000002892d75effff071f8f160700000000000000000000000000000000000000000000000000480000005ea571692c234a390ef670fcd74a1791c73e1a7150ff834368d61970ff2edb6563a1bc6297233416bff3a5b298a9e6f6843523637a7b5c9b8aa6c9862bcc866a4998d2d6ddcec13161ef5439d82c5914cffc8b4e8b6ae2d10dca3fc7bb06fc5585775c07', + data={ + 'version': 536870912, + 'prev_block_hash': '0001e3b67be015ee30ad46ef53fd273807af43847e399d25b5aee784ad36ae28', + 'merkle_root': '4aed2ab8d5da31cbf4007c22d004a59bf6b82048481d8dfd235f34ecb5addc1e', + 'block_height': 78191, + 'reserved': '00000000000000000000000000000000000000000000000000000000', + 'timestamp': 1591185960, + 'bits': 0x1f07ffff, + 'nonce': '000000480000000000000000000000000000000000000000000000000007168f', + 'solution':'075c778555fc06bbc73fca0dd1e26a8b4e8bfccf14592cd83954ef6131c1ceddd6d298496a86cc2b86c9a68a9b5c7b7a63233584f6e6a998b2a5f3bf1634239762bca16365db2eff7019d6684383ff50711a3ec791174ad7fc70f60e394a232c6971a55e' + } + ), + HeaderCase( + height=78192, + hex='00000020a2adb636dec24cecba346825ec4f70023b8fdf92cd10b3c17f82c96824540200eb92612cc6bfe0001abe8873cd1d7a44fe64a587b4527f80ec7c6a00340a50e17031010000000000000000000000000000000000000000000000000000000000239dd75effff071f8f160a00000000000000000000000000000000000000000000000000bf05000063d9cdf9f906c72978574fa0a5c97ffbac46667f3e3b6a96557c8dd495b32ceff817373e7a8a149777f687c5a6cc4fa6ce1006befafb2394c6e0478633b2535309dac8771d47bba7c54d2059797effdaafbea0e0bbac0294575718550323e31d7e39c10e', + data={ + 'version': 536870912, + 'prev_block_hash': '0002542468c9827fc1b310cd92df8f3b02704fec256834baec4cc2de36b6ada2', + 'merkle_root': 'e1500a34006a7cec807f52b487a564fe447a1dcd7388be1a00e0bfc62c6192eb', + 'block_height': 78192, + 'reserved': '00000000000000000000000000000000000000000000000000000000', + 'timestamp': 1591188771, + 'bits': 0x1f07ffff, + 'nonce': '000005bf000000000000000000000000000000000000000000000000000a168f', + 'solution':'0ec1397e1de32303551857579402acbbe0a0beafdaff7e7959204dc5a7bb471d77c8da095353b2338647e0c69423fbfabe0610cea64fcca6c587f67797148a7a3e3717f8ef2cb395d48d7c55966a3b3e7f6646acfb7fc9a5a04f577829c706f9f9cdd963' + } + ) +] + + +class Test_HeaderStorage(unittest.TestCase): + + def test_create_header_storage(self): + db = HeaderStorage('./test1.db') + self.assertTrue(os.path.exists('./test1.db')) + shutil.rmtree('./test1.db') + + def test_save_header(self): + db = HeaderStorage('./test2.db') + + db.save_header(HEADER_TEST_CASES[0].data) + self.assertEqual(HEADER_TEST_CASES[0].height, db.read_header(HEADER_TEST_CASES[0].height)['block_height']) + + db.save_header(HEADER_TEST_CASES[1].data) + self.assertEqual(HEADER_TEST_CASES[1].height, db.read_header(HEADER_TEST_CASES[1].height)['block_height']) + + db.save_header(HEADER_TEST_CASES[2].data) + self.assertEqual(HEADER_TEST_CASES[2].height, db.read_header(HEADER_TEST_CASES[2].height)['block_height']) + + shutil.rmtree('./test2.db') + + def test_read_header(self): + db = HeaderStorage('./test3.db') + + db.save_header(HEADER_TEST_CASES[0].data) + self.assertEqual(db.read_header(HEADER_TEST_CASES[0].height)['block_height'], HEADER_TEST_CASES[0].height) + + shutil.rmtree('./test3.db') + + def test_save_header_chunk(self): + db = HeaderStorage('./test4.db') + + db.save_header_chunk([HEADER_TEST_CASES[0].data, HEADER_TEST_CASES[1].data, HEADER_TEST_CASES[2].data]) + self.assertEqual(HEADER_TEST_CASES[0].height, db.read_header(HEADER_TEST_CASES[0].height)['block_height']) + self.assertEqual(HEADER_TEST_CASES[1].height, db.read_header(HEADER_TEST_CASES[1].height)['block_height']) + self.assertEqual(HEADER_TEST_CASES[2].height, db.read_header(HEADER_TEST_CASES[2].height)['block_height']) + + with self.assertRaises(HeaderStorageNotContinuousError): + db.save_header_chunk([HEADER_TEST_CASES[0].data, HEADER_TEST_CASES[2].data]) + + + shutil.rmtree('./test4.db') + + def test_read_header_chunk(self): + db = HeaderStorage('./test5.db') + + db.save_header_chunk([HEADER_TEST_CASES[0].data, HEADER_TEST_CASES[1].data, HEADER_TEST_CASES[2].data]) + headerlist = db.read_header_chunk([HEADER_TEST_CASES[0].height, HEADER_TEST_CASES[1].height, HEADER_TEST_CASES[2].height]) + + self.assertEqual(headerlist[0]['block_height'], HEADER_TEST_CASES[0].height) + self.assertEqual(headerlist[1]['block_height'], HEADER_TEST_CASES[1].height) + self.assertEqual(headerlist[2]['block_height'], HEADER_TEST_CASES[2].height) + + with self.assertRaises(HeaderStorageNotContinuousError): + headerlist = db.read_header_chunk([HEADER_TEST_CASES[0].height, HEADER_TEST_CASES[2].height]) + + shutil.rmtree('./test5.db') + + def test_delete_header(self): + db = HeaderStorage('./test6.db') + + db.save_header_chunk([HEADER_TEST_CASES[0].data, HEADER_TEST_CASES[1].data, HEADER_TEST_CASES[2].data]) + db.delete_header(HEADER_TEST_CASES[0].height) + + self.assertEqual(HEADER_TEST_CASES[1].height, db.read_header(HEADER_TEST_CASES[1].height)['block_height']) + self.assertEqual(HEADER_TEST_CASES[2].height, db.read_header(HEADER_TEST_CASES[2].height)['block_height']) + + self.assertEqual(db.read_header(HEADER_TEST_CASES[0].height), None) + + shutil.rmtree('./test6.db') + + def test_delete_header_chunk(self): + db = HeaderStorage('./test7.db') + + db.save_header_chunk([HEADER_TEST_CASES[0].data, HEADER_TEST_CASES[1].data, HEADER_TEST_CASES[2].data]) + db.delete_header_chunk([HEADER_TEST_CASES[0].height, HEADER_TEST_CASES[1].height, HEADER_TEST_CASES[2].height]) + + self.assertEqual(db.read_header(HEADER_TEST_CASES[0].height), None) + self.assertEqual(db.read_header(HEADER_TEST_CASES[1].height), None) + self.assertEqual(db.read_header(HEADER_TEST_CASES[2].height), None) + + shutil.rmtree('./test7.db') + +if __name__ == '__main__': + unittest.main() diff --git a/electrum/trampoline.py b/electrum/trampoline.py index 07eed3ce88f1..bacef5833e46 100644 --- a/electrum/trampoline.py +++ b/electrum/trampoline.py @@ -64,7 +64,7 @@ } def hardcoded_trampoline_nodes(): - if constants.net in (constants.BitcoinMainnet,): + if constants.net in (constants.BitcoinGoldMainnet,): return TRAMPOLINE_NODES_MAINNET if constants.net in (constants.BitcoinTestnet,): return TRAMPOLINE_NODES_TESTNET diff --git a/electrum/transaction.py b/electrum/transaction.py index b38a553c8d3a..d13864f0cbc4 100644 --- a/electrum/transaction.py +++ b/electrum/transaction.py @@ -1851,12 +1851,16 @@ def serialize_preimage(self, txin_index: int, *, inputs = self.inputs() outputs = self.outputs() txin = inputs[txin_index] - sighash = txin.sighash if txin.sighash is not None else SIGHASH_ALL - if sighash != SIGHASH_ALL: + sighash = txin.sighash if txin.sighash is not None else SIGHASH_ALL | constants.net.SIGHASH_FORK_BTG + if sighash != SIGHASH_ALL | constants.net.SIGHASH_FORK_BTG: raise Exception("only SIGHASH_ALL signing is supported!") nHashType = int_to_hex(sighash, 4) preimage_script = self.get_preimage_script(txin) - if txin.is_segwit(): + + def is_bip143_input(txin) -> bool: + return True + + if is_bip143_input(txin): if bip143_shared_txdigest_fields is None: bip143_shared_txdigest_fields = self._calc_bip143_shared_txdigest_fields() hashPrevouts = bip143_shared_txdigest_fields.hashPrevouts @@ -1899,7 +1903,7 @@ def sign_txin(self, txin_index, privkey_bytes, *, bip143_shared_txdigest_fields= bip143_shared_txdigest_fields=bip143_shared_txdigest_fields))) privkey = ecc.ECPrivkey(privkey_bytes) sig = privkey.sign_transaction(pre_hash) - sig = bh2u(sig) + '01' # SIGHASH_ALL + sig = bh2u(sig) + '41' # SIGHASH_ALL | SIGHASH_FORK_BTG return sig def is_complete(self) -> bool: diff --git a/electrum/util.py b/electrum/util.py index 8f88b2b8d2c8..aa34b987405a 100644 --- a/electrum/util.py +++ b/electrum/util.py @@ -75,18 +75,18 @@ def inv_dict(d): ca_path = certifi.where() -base_units = {'BTC':8, 'mBTC':5, 'bits':2, 'sat':0} +base_units = {'BTG':8, 'mBTG':5, 'bits':2, 'sat':0} base_units_inverse = inv_dict(base_units) -base_units_list = ['BTC', 'mBTC', 'bits', 'sat'] # list(dict) does not guarantee order +base_units_list = ['BTG', 'mBTG', 'bits', 'sat'] # list(dict) does not guarantee order -DECIMAL_POINT_DEFAULT = 5 # mBTC +DECIMAL_POINT_DEFAULT = 5 # mBTG class UnknownBaseUnit(Exception): pass def decimal_point_to_base_unit_name(dp: int) -> str: - # e.g. 8 -> "BTC" + # e.g. 8 -> "BTG" try: return base_units_inverse[dp] except KeyError: @@ -94,7 +94,7 @@ def decimal_point_to_base_unit_name(dp: int) -> str: def base_unit_name_to_decimal_point(unit_name: str) -> int: - # e.g. "BTC" -> 8 + # e.g. "BTG" -> 8 try: return base_units[unit_name] except KeyError: @@ -550,11 +550,11 @@ def user_dir(): elif 'ANDROID_DATA' in os.environ: return android_data_dir() elif os.name == 'posix': - return os.path.join(os.environ["HOME"], ".electrum") + return os.path.join(os.environ["HOME"], ".electrumg") elif "APPDATA" in os.environ: - return os.path.join(os.environ["APPDATA"], "Electrum") + return os.path.join(os.environ["APPDATA"], "ElectrumG") elif "LOCALAPPDATA" in os.environ: - return os.path.join(os.environ["LOCALAPPDATA"], "Electrum") + return os.path.join(os.environ["LOCALAPPDATA"], "ElectrumG") else: #raise Exception("No home directory found in environment variables.") return @@ -747,41 +747,11 @@ def time_difference(distance_in_time, include_seconds): return "over %d years" % (round(distance_in_minutes / 525600)) mainnet_block_explorers = { - 'Bitupper Explorer': ('https://bitupper.com/en/explorer/bitcoin/', - {'tx': 'transactions/', 'addr': 'addresses/'}), - 'Bitflyer.jp': ('https://chainflyer.bitflyer.jp/', - {'tx': 'Transaction/', 'addr': 'Address/'}), - 'Blockchain.info': ('https://blockchain.com/btc/', + 'BitcoinGold Explorer': ('https://explorer.bitcoingold.org/insight/', {'tx': 'tx/', 'addr': 'address/'}), - 'blockchainbdgpzk.onion': ('https://blockchainbdgpzk.onion/', + 'Trezor Explorer': ('https://btg1.trezor.io/', {'tx': 'tx/', 'addr': 'address/'}), - 'Blockstream.info': ('https://blockstream.info/', - {'tx': 'tx/', 'addr': 'address/'}), - 'Bitaps.com': ('https://btc.bitaps.com/', - {'tx': '', 'addr': ''}), - 'BTC.com': ('https://btc.com/', - {'tx': '', 'addr': ''}), - 'Chain.so': ('https://www.chain.so/', - {'tx': 'tx/BTC/', 'addr': 'address/BTC/'}), - 'Insight.is': ('https://insight.bitpay.com/', - {'tx': 'tx/', 'addr': 'address/'}), - 'TradeBlock.com': ('https://tradeblock.com/blockchain/', - {'tx': 'tx/', 'addr': 'address/'}), - 'BlockCypher.com': ('https://live.blockcypher.com/btc/', - {'tx': 'tx/', 'addr': 'address/'}), - 'Blockchair.com': ('https://blockchair.com/bitcoin/', - {'tx': 'transaction/', 'addr': 'address/'}), - 'blockonomics.co': ('https://www.blockonomics.co/', - {'tx': 'api/tx?txid=', 'addr': '#/search?q='}), - 'mempool.space': ('https://mempool.space/', - {'tx': 'tx/', 'addr': 'address/'}), - 'mempool.emzy.de': ('https://mempool.emzy.de/', - {'tx': 'tx/', 'addr': 'address/'}), - 'OXT.me': ('https://oxt.me/', - {'tx': 'transaction/', 'addr': 'address/'}), - 'smartbit.com.au': ('https://www.smartbit.com.au/', - {'tx': 'tx/', 'addr': 'address/'}), - 'mynode.local': ('http://mynode.local:3002/', + 'BTG Explorer': ('https://btgexplorer.com/', {'tx': 'tx/', 'addr': 'address/'}), 'system default': ('blockchain:/', {'tx': 'tx/', 'addr': 'address/'}), @@ -818,7 +788,7 @@ def block_explorer(config: 'SimpleConfig') -> Optional[str]: """ if config.get('block_explorer_custom') is not None: return None - default_ = 'Blockstream.info' + default_ = 'BitcoinGold Explorer' be_key = config.get('block_explorer', default_) be_tuple = block_explorer_info().get(be_key) if be_tuple is None: @@ -861,8 +831,8 @@ def block_explorer_URL(config: 'SimpleConfig', kind: str, item: str) -> Optional # note: when checking against these, use .lower() to support case-insensitivity -BITCOIN_BIP21_URI_SCHEME = 'bitcoin' -LIGHTNING_URI_SCHEME = 'lightning' +BITCOIN_BIP21_URI_SCHEME = 'bitcoingold' +LIGHTNING_URI_SCHEME = 'lightningbtg' class InvalidBitcoinURI(Exception): pass diff --git a/setup.py b/setup.py index efcd5dd0f203..e4bac8e43d80 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ usr_share = os.path.expanduser('~/.local/share') data_files += [ (os.path.join(usr_share, 'applications/'), ['electrum.desktop']), - (os.path.join(usr_share, icons_dirname), ['electrum/gui/icons/electrum.png']), + (os.path.join(usr_share, icons_dirname), ['electrum/gui/icons/electrumg.png']), ] extras_require = { @@ -65,7 +65,7 @@ setup( - name="Electrum", + name="ElectrumG", version=version.ELECTRUM_VERSION, python_requires='>={}'.format(MIN_PYTHON_VERSION), install_requires=requirements, @@ -85,10 +85,10 @@ include_package_data=True, scripts=['electrum/electrum'], data_files=data_files, - description="Lightweight Bitcoin Wallet", + description="Lightweight Bitcoin Gold Wallet", author="Thomas Voegtlin", author_email="thomasv@electrum.org", license="MIT Licence", - url="https://electrum.org", - long_description="""Lightweight Bitcoin Wallet""", + url="https://bitcoingold.org", + long_description="""Lightweight Bitcoin Gold Wallet""", )