diff options
104 files changed, 1229 insertions, 651 deletions
diff --git a/.travis.yml b/.travis.yml index 21d1062c26..c281d3ed70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -98,16 +98,6 @@ jobs: BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi" - stage: test - name: 'Win32 [GOAL: deploy] [no gui or functional tests]' - env: >- - HOST=i686-w64-mingw32 - DPKG_ADD_ARCH="i386" - PACKAGES="python3 nsis g++-mingw-w64-i686 wine-binfmt wine32" - RUN_FUNCTIONAL_TESTS=false - GOAL="deploy" - BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests" - - - stage: test name: 'Win64 [GOAL: deploy] [no gui or functional tests]' env: >- HOST=x86_64-w64-mingw32 @@ -131,6 +121,7 @@ jobs: HOST=x86_64-unknown-linux-gnu PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1" + TEST_RUNNER_EXTRA="--coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash GOAL="install" BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\"" diff --git a/.travis/test_04_install.sh b/.travis/test_04_install.sh index 8055bbdd19..b589ee7a16 100755 --- a/.travis/test_04_install.sh +++ b/.travis/test_04_install.sh @@ -29,10 +29,6 @@ DOCKER_EXEC () { docker exec $DOCKER_ID bash -c "cd $PWD && $*" } -if [ -n "$DPKG_ADD_ARCH" ]; then - DOCKER_EXEC dpkg --add-architecture "$DPKG_ADD_ARCH" -fi - travis_retry DOCKER_EXEC apt-get update travis_retry DOCKER_EXEC apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES $DOCKER_PACKAGES diff --git a/.travis/test_06_script_b.sh b/.travis/test_06_script_b.sh index e13abfd52f..0420acb993 100755 --- a/.travis/test_06_script_b.sh +++ b/.travis/test_06_script_b.sh @@ -16,7 +16,7 @@ fi if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then BEGIN_FOLD functional-tests - DOCKER_EXEC test/functional/test_runner.py --ci --combinedlogslen=4000 --coverage --quiet --failfast + DOCKER_EXEC test/functional/test_runner.py --ci --combinedlogslen=4000 ${TEST_RUNNER_EXTRA} --quiet --failfast END_FOLD fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 007ebd7ccf..5df99adba8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -220,6 +220,7 @@ In general, all pull requests must: - Not break the existing test suite; - Where bugs are fixed, where possible, there should be unit tests demonstrating the bug and also proving the fix. This helps prevent regression. + - Change relevant comments and documentation when behaviour of code changes. Patches that change Bitcoin consensus rules are considerably more involved than normal because they affect the entire ecosystem and so must be preceded by diff --git a/configure.ac b/configure.ac index 854d6b1d49..d57e3b9196 100644 --- a/configure.ac +++ b/configure.ac @@ -734,6 +734,10 @@ if test x$TARGET_OS != xwindows; then AX_CHECK_COMPILE_FLAG([-fPIC],[PIC_FLAGS="-fPIC"]) fi +# All versions of gcc that we commonly use for building are subject to bug +# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90348. To work around that, set +# -fstack-reuse=none for all gcc builds. (Only gcc understands this flag) +AX_CHECK_COMPILE_FLAG([-fstack-reuse=none],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-reuse=none"]) if test x$use_hardening != xno; then use_hardening=yes AX_CHECK_COMPILE_FLAG([-Wstack-protector],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -Wstack-protector"]) diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index fd374f6328..bb864bfc0c 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -43,18 +43,6 @@ class TestSecurityChecks(unittest.TestCase): self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE']), (0, '')) - def test_32bit_PE(self): - source = 'test1.c' - executable = 'test1.exe' - cc = 'i686-w64-mingw32-gcc' - write_testcode(source) - - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--no-nxcompat','-Wl,--no-dynamicbase']), - (1, executable+': failed DYNAMIC_BASE NX')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--no-dynamicbase']), - (1, executable+': failed DYNAMIC_BASE')) - self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']), - (0, '')) def test_64bit_PE(self): source = 'test1.c' executable = 'test1.exe' diff --git a/contrib/gitian-build.py b/contrib/gitian-build.py index fc7fbb764d..e51481e0bf 100755 --- a/contrib/gitian-build.py +++ b/contrib/gitian-build.py @@ -68,14 +68,14 @@ def build(): subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-win.yml']) subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-unsigned', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-win.yml']) subprocess.check_call('mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/', shell=True) - subprocess.check_call('mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../bitcoin-binaries/'+args.version, shell=True) + subprocess.check_call('mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/'+args.version, shell=True) if args.macos: print('\nCompiling ' + args.version + ' MacOS') subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml']) subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-unsigned', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml']) subprocess.check_call('mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/', shell=True) - subprocess.check_call('mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../bitcoin-binaries/'+args.version, shell=True) + subprocess.check_call('mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/'+args.version, shell=True) os.chdir(workdir) @@ -95,15 +95,14 @@ def sign(): if args.windows: print('\nSigning ' + args.version + ' Windows') subprocess.check_call('cp inputs/bitcoin-' + args.version + '-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz', shell=True) - subprocess.check_call(['bin/gbuild', '-i', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml']) + subprocess.check_call(['bin/gbuild', '--skip-image', '--upgrade', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml']) subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-signed', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml']) subprocess.check_call('mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/'+args.version, shell=True) - subprocess.check_call('mv build/out/bitcoin-*win32-setup.exe ../bitcoin-binaries/'+args.version, shell=True) if args.macos: print('\nSigning ' + args.version + ' MacOS') subprocess.check_call('cp inputs/bitcoin-' + args.version + '-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz', shell=True) - subprocess.check_call(['bin/gbuild', '-i', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml']) + subprocess.check_call(['bin/gbuild', '--skip-image', '--upgrade', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml']) subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-signed', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml']) subprocess.check_call('mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/'+args.version+'/bitcoin-'+args.version+'-osx.dmg', shell=True) diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index eca32a5dc5..c055109715 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -31,7 +31,7 @@ script: | set -e -o pipefail WRAP_DIR=$HOME/wrapped - HOSTS="i686-w64-mingw32 x86_64-w64-mingw32" + HOSTS="x86_64-w64-mingw32" CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests" FAKETIME_HOST_PROGS="ar ranlib nm windres strip objcopy" FAKETIME_PROGS="date makensis zip" @@ -179,6 +179,4 @@ script: | cp $OUTDIR/bitcoin-*setup-unsigned.exe unsigned/ find . | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.zip ${OUTDIR}/${DISTNAME}-win64-debug.zip - mv ${OUTDIR}/${DISTNAME}-i686-*-debug.zip ${OUTDIR}/${DISTNAME}-win32-debug.zip mv ${OUTDIR}/${DISTNAME}-x86_64-*.zip ${OUTDIR}/${DISTNAME}-win64.zip - mv ${OUTDIR}/${DISTNAME}-i686-*.zip ${OUTDIR}/${DISTNAME}-win32.zip diff --git a/depends/README.md b/depends/README.md index 68a83a2aea..11ef9d2b67 100644 --- a/depends/README.md +++ b/depends/README.md @@ -20,7 +20,6 @@ created. To use it for Bitcoin: Common `host-platform-triplets` for cross compilation are: -- `i686-w64-mingw32` for Win32 - `x86_64-w64-mingw32` for Win64 - `x86_64-apple-darwin14` for macOS - `arm-linux-gnueabihf` for Linux ARM 32 bit diff --git a/doc/build-windows.md b/doc/build-windows.md index 036c585b44..5ca9f98475 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -102,30 +102,6 @@ Build using: CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site ./configure --prefix=/ make -## Building for 32-bit Windows - -To build executables for Windows 32-bit, install the following dependencies: - - sudo apt install g++-mingw-w64-i686 mingw-w64-i686-dev - -For Ubuntu Bionic 18.04 and Windows Subsystem for Linux <sup>[1](#footnote1)</sup>: - - sudo update-alternatives --config i686-w64-mingw32-g++ # Set the default mingw32 g++ compiler option to posix. - -Note that for WSL the Bitcoin Core source path MUST be somewhere in the default mount file system, for -example /usr/src/bitcoin, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts will fail. -This means you cannot use a directory that located directly on the host Windows file system to perform the build. - -Build using: - - PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var - cd depends - make HOST=i686-w64-mingw32 - cd .. - ./autogen.sh # not required when building from tarball - CONFIG_SITE=$PWD/depends/i686-w64-mingw32/share/config.site ./configure --prefix=/ - make - ## Depends system For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory. diff --git a/doc/release-notes-14802.md b/doc/release-notes-14802.md new file mode 100644 index 0000000000..1fcc38866a --- /dev/null +++ b/doc/release-notes-14802.md @@ -0,0 +1,3 @@ +RPC changes +----------- +The `getblockstats` RPC is faster for fee calculation by using BlockUndo data. Also, `-txindex` is no longer required and `getblockstats` works for all non-pruned blocks. diff --git a/doc/release-notes-15006.md b/doc/release-notes-15006.md new file mode 100644 index 0000000000..76ed3247a6 --- /dev/null +++ b/doc/release-notes-15006.md @@ -0,0 +1,4 @@ +Miscellaneous RPC changes +------------ + +- `createwallet` can now create encrypted wallets if a non-empty passphrase is specified. diff --git a/doc/release-notes.md b/doc/release-notes.md index 834c9b36dc..4a86469ccf 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,5 +1,19 @@ -(note: this is a temporary file, to be added-to by anybody, and moved to -release-notes at release time) +*After branching off for a major version release of Bitcoin Core, use this +template to create the initial release notes draft.* + +*The release notes draft is a temporary file that can be added to by anyone. See +[/doc/developer-notes.md#release-notes](/doc/developer-notes.md#release-notes) +for the process.* + +*Create the draft, named* "*version* Release Notes Draft" +*(e.g. "0.20.0 Release Notes Draft"), as a collaborative wiki in:* + +https://github.com/bitcoin-core/bitcoin-devwiki/wiki/ + +*Before the final release, move the notes back to this git repository.* + +*version* Release Notes Draft +=============================== Bitcoin Core version *version* is now available from: @@ -97,6 +111,16 @@ Configuration the selected network. This change takes only effect if the selected network is not mainnet. +Wallet +------ + +- When in pruned mode, a rescan that was triggered by an `importwallet`, + `importpubkey`, `importaddress`, or `importprivkey` RPC will only fail when + blocks have been pruned. Previously it would fail when `-prune` has been set. + This change allows to set `-prune` to a high value (e.g. the disk size) and + the calls to any of the import RPCs would fail when the first block is + pruned. + Credits ======= diff --git a/doc/release-process.md b/doc/release-process.md index 7522310ce2..9b796fa816 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -1,17 +1,19 @@ Release Process ==================== -Before every release candidate: +## Branch updates + +### Before every release candidate * Update translations (ping wumpus on IRC) see [translation_process.md](https://github.com/bitcoin/bitcoin/blob/master/doc/translation_process.md#synchronising-translations). * Update manpages, see [gen-manpages.sh](https://github.com/bitcoin/bitcoin/blob/master/contrib/devtools/README.md#gen-manpagessh). * Update release candidate version in `configure.ac` (`CLIENT_VERSION_RC`). -Before every minor and major release: +### Before every major and minor release * Update [bips.md](bips.md) to account for changes since the last release. * Update version in `configure.ac` (don't forget to set `CLIENT_VERSION_RC` to `0`). -* Write release notes (see below). +* Write release notes (see "Write the release notes" below). * Update `src/chainparams.cpp` nMinimumChainWork with information from the getblockchaininfo rpc. * Update `src/chainparams.cpp` defaultAssumeValid with information from the getblockhash rpc. - The selected value must not be orphaned so it may be useful to set the value two blocks back from the tip. @@ -19,13 +21,12 @@ Before every minor and major release: - This update should be reviewed with a reindex-chainstate with assumevalid=0 to catch any defect that causes rejection of blocks in the past history. -Before every major release: +### Before every major release * Update hardcoded [seeds](/contrib/seeds/README.md), see [this pull request](https://github.com/bitcoin/bitcoin/pull/7415) for an example. * Update [`src/chainparams.cpp`](/src/chainparams.cpp) m_assumed_blockchain_size and m_assumed_chain_state_size with the current size plus some overhead. * Update `src/chainparams.cpp` chainTxData with statistics about the transaction count and rate. Use the output of the RPC `getchaintxstats`, see [this pull request](https://github.com/bitcoin/bitcoin/pull/12270) for an example. Reviewers can verify the results by running `getchaintxstats <window_block_count> <window_last_block_hash>` with the `window_block_count` and `window_last_block_hash` from your output. -* Update version of `contrib/gitian-descriptors/*.yml`: usually one'd want to do this on master after branching off the release - but be sure to at least do it before a new major release. * In `configure.ac` and `build_msvc/bitcoin_config.h` on _the master branch_: - update `CLIENT_VERSION_MINOR` version * In `configure.ac` and `build_msvc/bitcoin_config.h` on _a new release branch_ (see [this commit](https://github.com/bitcoin/bitcoin/commit/742f7dd972fca3dd4a33cfff90bf901b71a687e7)): @@ -33,6 +34,26 @@ Before every major release: - set `CLIENT_VERSION_REVISION` to `0` - set `CLIENT_VERSION_IS_RELEASE` to `true` +#### Before branch-off + +- Clear the release notes and move them to the wiki (see "Write the release notes" below). + +#### After branch-off (on master) + +- Update the version of `contrib/gitian-descriptors/*.yml`. + +#### After branch-off (on the major release branch) + +- Update the versions and the link to the release notes draft in `doc/release-notes.md`. + +#### Before final release + +- Merge the release notes from the wiki into the branch. +- Ensure the "Needs release note" label is removed from all relevant pull requests and issues. + + +## Building + ### First time / New builders If you're using the automated script (found in [contrib/gitian-build.py](/contrib/gitian-build.py)), then at this point you should run it with the "--setup" command. Otherwise ignore this. @@ -45,22 +66,26 @@ Check out the source code in the following directory hierarchy. git clone https://github.com/devrandom/gitian-builder.git git clone https://github.com/bitcoin/bitcoin.git -### Bitcoin maintainers/release engineers, suggestion for writing release notes +### Write the release notes -Write release notes. git shortlog helps a lot, for example: +Open a draft of the release notes for collaborative editing at https://github.com/bitcoin-core/bitcoin-devwiki/wiki. - git shortlog --no-merges v(current version, e.g. 0.7.2)..v(new version, e.g. 0.8.0) +For the period during which the notes are being edited on the wiki, the version on the branch should be wiped and replaced with a link to the wiki which should be used for all announcements until `-final`. + +Write the release notes. `git shortlog` helps a lot, for example: + + git shortlog --no-merges v(current version, e.g. 0.19.2)..v(new version, e.g. 0.20.0) (or ping @wumpus on IRC, he has specific tooling to generate the list of merged pulls -and sort them into categories based on labels) +and sort them into categories based on labels). Generate list of authors: - git log --format='- %aN' v(current version, e.g. 0.16.0)..v(new version, e.g. 0.16.1) | sort -fiu + git log --format='- %aN' v(current version, e.g. 0.20.0)..v(new version, e.g. 0.20.1) | sort -fiu -Tag version (or release candidate) in git +Tag the version (or release candidate) in git: - git tag -s v(new version, e.g. 0.8.0) + git tag -s v(new version, e.g. 0.20.0) ### Setup and perform Gitian builds @@ -70,7 +95,7 @@ Setup Gitian descriptors: pushd ./bitcoin export SIGNER="(your Gitian key, ie bluematt, sipa, etc)" - export VERSION=(new version, e.g. 0.8.0) + export VERSION=(new version, e.g. 0.20.0) git fetch git checkout v${VERSION} popd @@ -221,7 +246,6 @@ Create (and optionally verify) the signed Windows binaries: ./bin/gsign --signer "$SIGNER" --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-signed ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml mv build/out/bitcoin-*win64-setup.exe ../bitcoin-${VERSION}-win64-setup.exe - mv build/out/bitcoin-*win32-setup.exe ../bitcoin-${VERSION}-win32-setup.exe popd Commit your signature for the signed macOS/Windows binaries: @@ -229,7 +253,7 @@ Commit your signature for the signed macOS/Windows binaries: pushd gitian.sigs git add ${VERSION}-osx-signed/"${SIGNER}" git add ${VERSION}-win-signed/"${SIGNER}" - git commit -a + git commit -m "Add ${SIGNER} ${VERSION} signed binaries signatures" git push # Assuming you can push to the gitian.sigs tree popd @@ -250,8 +274,6 @@ bitcoin-${VERSION}-x86_64-linux-gnu.tar.gz bitcoin-${VERSION}-osx64.tar.gz bitcoin-${VERSION}-osx.dmg bitcoin-${VERSION}.tar.gz -bitcoin-${VERSION}-win32-setup.exe -bitcoin-${VERSION}-win32.zip bitcoin-${VERSION}-win64-setup.exe bitcoin-${VERSION}-win64.zip ``` @@ -326,9 +348,11 @@ bitcoin.org (see below for bitcoin.org update instructions). - This repo - - Archive release notes for the new version to `doc/release-notes/` (branch `master` and branch of the release) + - Archive the release notes for the new version to `doc/release-notes/` (branch `master` and branch of the release) + + - Create a [new GitHub release](https://github.com/bitcoin/bitcoin/releases/new) with a link to the archived release notes - - Create a [new GitHub release](https://github.com/bitcoin/bitcoin/releases/new) with a link to the archived release notes. + - Create a pinned meta-issue for testing the release candidate (see [this issue](https://github.com/bitcoin/bitcoin/issues/15555) for an example) and provide a link to it in the release announcements where useful - Announce the release: diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index ae7eb19ceb..ef8a207841 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -21,6 +21,7 @@ bench_bench_bitcoin_SOURCES = \ bench/duplicate_inputs.cpp \ bench/examples.cpp \ bench/rollingbloom.cpp \ + bench/chacha20.cpp \ bench/crypto_hash.cpp \ bench/ccoins_caching.cpp \ bench/gcs_filter.cpp \ diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index d0e0109546..f2b520e893 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -114,6 +114,7 @@ void benchmark::BenchRunner::RunAll(Printer& printer, uint64_t num_evals, double for (const auto& p : benchmarks()) { TestingSetup test{CBaseChainParams::REGTEST}; { + LOCK(cs_main); assert(::ChainActive().Height() == 0); const bool witness_enabled{IsWitnessEnabled(::ChainActive().Tip(), Params().GetConsensus())}; assert(witness_enabled); diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp index 9cfd5d23ef..1041a22303 100644 --- a/src/bench/ccoins_caching.cpp +++ b/src/bench/ccoins_caching.cpp @@ -39,9 +39,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet) dummyTransactions[1].vout.resize(2); dummyTransactions[1].vout[0].nValue = 21 * COIN; - dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID()); + dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[2].GetPubKey())); dummyTransactions[1].vout[1].nValue = 22 * COIN; - dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID()); + dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(PKHash(key[3].GetPubKey())); AddCoins(coinsRet, CTransaction(dummyTransactions[1]), 0); return dummyTransactions; diff --git a/src/bench/chacha20.cpp b/src/bench/chacha20.cpp new file mode 100644 index 0000000000..69d8c96ec0 --- /dev/null +++ b/src/bench/chacha20.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <iostream> + +#include <bench/bench.h> +#include <hash.h> +#include <crypto/chacha20.h> + +/* Number of bytes to process per iteration */ +static const uint64_t BUFFER_SIZE_TINY = 64; +static const uint64_t BUFFER_SIZE_SMALL = 256; +static const uint64_t BUFFER_SIZE_LARGE = 1024*1024; + +static void CHACHA20(benchmark::State& state, size_t buffersize) +{ + std::vector<uint8_t> key(32,0); + ChaCha20 ctx(key.data(), key.size()); + ctx.SetIV(0); + ctx.Seek(0); + std::vector<uint8_t> in(buffersize,0); + std::vector<uint8_t> out(buffersize,0); + while (state.KeepRunning()) { + ctx.Crypt(in.data(), out.data(), in.size()); + } +} + +static void CHACHA20_64BYTES(benchmark::State& state) +{ + CHACHA20(state, BUFFER_SIZE_TINY); +} + +static void CHACHA20_256BYTES(benchmark::State& state) +{ + CHACHA20(state, BUFFER_SIZE_SMALL); +} + +static void CHACHA20_1MB(benchmark::State& state) +{ + CHACHA20(state, BUFFER_SIZE_LARGE); +} + +BENCHMARK(CHACHA20_64BYTES, 500000); +BENCHMARK(CHACHA20_256BYTES, 250000); +BENCHMARK(CHACHA20_1MB, 340); diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp index aa3f219b18..80ff13612c 100644 --- a/src/bench/duplicate_inputs.cpp +++ b/src/bench/duplicate_inputs.cpp @@ -29,6 +29,7 @@ static void DuplicateInputs(benchmark::State& state) CMutableTransaction coinbaseTx{}; CMutableTransaction naughtyTx{}; + LOCK(cs_main); CBlockIndex* pindexPrev = ::ChainActive().Tip(); assert(pindexPrev != nullptr); block.nBits = GetNextWorkRequired(pindexPrev, &block, chainparams.GetConsensus()); diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 7f41ea7aed..ac1d62a8f4 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -323,7 +323,7 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str } if (bScriptHash) { // Get the ID for the script, and then construct a P2SH destination for it. - scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); + scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); } // construct TxOut, append to transaction output list @@ -397,7 +397,7 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); } // Get the ID for the script, and then construct a P2SH destination for it. - scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); + scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); } // construct TxOut, append to transaction output list @@ -469,7 +469,7 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str throw std::runtime_error(strprintf( "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); } - scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); + scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); } // construct TxOut, append to transaction output list diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp index ac4470f04f..42a17f02ff 100644 --- a/src/crypto/chacha20.cpp +++ b/src/crypto/chacha20.cpp @@ -71,7 +71,7 @@ void ChaCha20::Seek(uint64_t pos) input[13] = pos >> 32; } -void ChaCha20::Output(unsigned char* c, size_t bytes) +void ChaCha20::Keystream(unsigned char* c, size_t bytes) { uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; @@ -178,3 +178,133 @@ void ChaCha20::Output(unsigned char* c, size_t bytes) c += 64; } } + +void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes) +{ + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + unsigned char *ctarget = nullptr; + unsigned char tmp[64]; + unsigned int i; + + if (!bytes) return; + + j0 = input[0]; + j1 = input[1]; + j2 = input[2]; + j3 = input[3]; + j4 = input[4]; + j5 = input[5]; + j6 = input[6]; + j7 = input[7]; + j8 = input[8]; + j9 = input[9]; + j10 = input[10]; + j11 = input[11]; + j12 = input[12]; + j13 = input[13]; + j14 = input[14]; + j15 = input[15]; + + for (;;) { + if (bytes < 64) { + // if m has fewer than 64 bytes available, copy m to tmp and + // read from tmp instead + for (i = 0;i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 += j0; + x1 += j1; + x2 += j2; + x3 += j3; + x4 += j4; + x5 += j5; + x6 += j6; + x7 += j7; + x8 += j8; + x9 += j9; + x10 += j10; + x11 += j11; + x12 += j12; + x13 += j13; + x14 += j14; + x15 += j15; + + x0 ^= ReadLE32(m + 0); + x1 ^= ReadLE32(m + 4); + x2 ^= ReadLE32(m + 8); + x3 ^= ReadLE32(m + 12); + x4 ^= ReadLE32(m + 16); + x5 ^= ReadLE32(m + 20); + x6 ^= ReadLE32(m + 24); + x7 ^= ReadLE32(m + 28); + x8 ^= ReadLE32(m + 32); + x9 ^= ReadLE32(m + 36); + x10 ^= ReadLE32(m + 40); + x11 ^= ReadLE32(m + 44); + x12 ^= ReadLE32(m + 48); + x13 ^= ReadLE32(m + 52); + x14 ^= ReadLE32(m + 56); + x15 ^= ReadLE32(m + 60); + + ++j12; + if (!j12) ++j13; + + WriteLE32(c + 0, x0); + WriteLE32(c + 4, x1); + WriteLE32(c + 8, x2); + WriteLE32(c + 12, x3); + WriteLE32(c + 16, x4); + WriteLE32(c + 20, x5); + WriteLE32(c + 24, x6); + WriteLE32(c + 28, x7); + WriteLE32(c + 32, x8); + WriteLE32(c + 36, x9); + WriteLE32(c + 40, x10); + WriteLE32(c + 44, x11); + WriteLE32(c + 48, x12); + WriteLE32(c + 52, x13); + WriteLE32(c + 56, x14); + WriteLE32(c + 60, x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + input[12] = j12; + input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} diff --git a/src/crypto/chacha20.h b/src/crypto/chacha20.h index a305977bcd..5a4674f4a8 100644 --- a/src/crypto/chacha20.h +++ b/src/crypto/chacha20.h @@ -8,7 +8,8 @@ #include <stdint.h> #include <stdlib.h> -/** A PRNG class for ChaCha20. */ +/** A class for ChaCha20 256-bit stream cipher developed by Daniel J. Bernstein + https://cr.yp.to/chacha/chacha-20080128.pdf */ class ChaCha20 { private: @@ -17,10 +18,17 @@ private: public: ChaCha20(); ChaCha20(const unsigned char* key, size_t keylen); - void SetKey(const unsigned char* key, size_t keylen); - void SetIV(uint64_t iv); - void Seek(uint64_t pos); - void Output(unsigned char* output, size_t bytes); + void SetKey(const unsigned char* key, size_t keylen); //!< set key with flexible keylength; 256bit recommended */ + void SetIV(uint64_t iv); // set the 64bit nonce + void Seek(uint64_t pos); // set the 64bit block counter + + /** outputs the keystream of size <bytes> into <c> */ + void Keystream(unsigned char* c, size_t bytes); + + /** enciphers the message <input> of length <bytes> and write the enciphered representation into <output> + * Used for encryption and decryption (XOR) + */ + void Crypt(const unsigned char* input, unsigned char* output, size_t bytes); }; #endif // BITCOIN_CRYPTO_CHACHA20_H diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp index a00331dcb7..edee06cc34 100644 --- a/src/crypto/ripemd160.cpp +++ b/src/crypto/ripemd160.cpp @@ -256,7 +256,7 @@ CRIPEMD160& CRIPEMD160::Write(const unsigned char* data, size_t len) ripemd160::Transform(s, buf); bufsize = 0; } - while (end >= data + 64) { + while (end - data >= 64) { // Process full chunks directly from the source. ripemd160::Transform(s, data); bytes += 64; diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp index 5c601c54a6..3dcdcb186e 100644 --- a/src/crypto/sha1.cpp +++ b/src/crypto/sha1.cpp @@ -163,7 +163,7 @@ CSHA1& CSHA1::Write(const unsigned char* data, size_t len) sha1::Transform(s, buf); bufsize = 0; } - while (end >= data + 64) { + while (end - data >= 64) { // Process full chunks directly from the source. sha1::Transform(s, data); bytes += 64; diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp index bc64135cae..4e6aa363f7 100644 --- a/src/crypto/sha512.cpp +++ b/src/crypto/sha512.cpp @@ -168,7 +168,7 @@ CSHA512& CSHA512::Write(const unsigned char* data, size_t len) sha512::Transform(s, buf); bufsize = 0; } - while (end >= data + 128) { + while (end - data >= 128) { // Process full chunks directly from the source. sha512::Transform(s, data); data += 128; diff --git a/src/init.cpp b/src/init.cpp index 3d825a29b6..944200e24d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -380,7 +380,7 @@ void SetupServerArgs() gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS); gArgs.AddArg("-alertnotify=<cmd>", "Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-assumevalid=<hex>", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()), false, OptionsCategory::OPTIONS); - gArgs.AddArg("-blocksdir=<dir>", "Specify blocks directory (default: <datadir>/blocks)", false, OptionsCategory::OPTIONS); + gArgs.AddArg("-blocksdir=<dir>", "Specify directory to hold blocks subdirectory for *.dat files (default: <datadir>)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-blocknotify=<cmd>", "Execute command when the best block changes (%s in cmd is replaced by block hash)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-blockreconstructionextratxn=<n>", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), false, OptionsCategory::OPTIONS); gArgs.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Transactions from the wallet or RPC are not affected. (default: %u)", DEFAULT_BLOCKSONLY), false, OptionsCategory::OPTIONS); @@ -457,7 +457,7 @@ void SetupServerArgs() #endif gArgs.AddArg("-whitebind=<addr>", "Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6", false, OptionsCategory::CONNECTION); gArgs.AddArg("-whitelist=<IP address or network>", "Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times." - " Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway", false, OptionsCategory::CONNECTION); + " Whitelisted peers cannot be DoS banned", false, OptionsCategory::CONNECTION); g_wallet_init_interface.AddWalletOptions(); @@ -528,7 +528,7 @@ void SetupServerArgs() gArgs.AddArg("-mempoolreplacement", strprintf("Enable transaction replacement in the memory pool (default: %u)", DEFAULT_ENABLE_REPLACEMENT), false, OptionsCategory::NODE_RELAY); gArgs.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), false, OptionsCategory::NODE_RELAY); - gArgs.AddArg("-whitelistforcerelay", strprintf("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)", DEFAULT_WHITELISTFORCERELAY), false, OptionsCategory::NODE_RELAY); + gArgs.AddArg("-whitelistforcerelay", strprintf("Force relay of transactions from whitelisted peers even if the transactions were already in the mempool or violate local relay policy (default: %d)", DEFAULT_WHITELISTFORCERELAY), false, OptionsCategory::NODE_RELAY); gArgs.AddArg("-whitelistrelay", strprintf("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), false, OptionsCategory::NODE_RELAY); diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index fcbc442d12..d2a915ec02 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -41,6 +41,7 @@ class LockImpl : public Chain::Lock { Optional<int> getHeight() override { + LockAnnotation lock(::cs_main); int height = ::ChainActive().Height(); if (height >= 0) { return height; @@ -49,6 +50,7 @@ class LockImpl : public Chain::Lock } Optional<int> getBlockHeight(const uint256& hash) override { + LockAnnotation lock(::cs_main); CBlockIndex* block = LookupBlockIndex(hash); if (block && ::ChainActive().Contains(block)) { return block->nHeight; @@ -63,29 +65,34 @@ class LockImpl : public Chain::Lock } uint256 getBlockHash(int height) override { + LockAnnotation lock(::cs_main); CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetBlockHash(); } int64_t getBlockTime(int height) override { + LockAnnotation lock(::cs_main); CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetBlockTime(); } int64_t getBlockMedianTimePast(int height) override { + LockAnnotation lock(::cs_main); CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetMedianTimePast(); } bool haveBlockOnDisk(int height) override { + LockAnnotation lock(::cs_main); CBlockIndex* block = ::ChainActive()[height]; return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0; } Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override { + LockAnnotation lock(::cs_main); CBlockIndex* block = ::ChainActive().FindEarliestAtLeast(time, height); if (block) { if (hash) *hash = block->GetBlockHash(); @@ -95,6 +102,7 @@ class LockImpl : public Chain::Lock } Optional<int> findPruned(int start_height, Optional<int> stop_height) override { + LockAnnotation lock(::cs_main); if (::fPruneMode) { CBlockIndex* block = stop_height ? ::ChainActive()[*stop_height] : ::ChainActive().Tip(); while (block && block->nHeight >= start_height) { @@ -108,6 +116,7 @@ class LockImpl : public Chain::Lock } Optional<int> findFork(const uint256& hash, Optional<int>* height) override { + LockAnnotation lock(::cs_main); const CBlockIndex* block = LookupBlockIndex(hash); const CBlockIndex* fork = block ? ::ChainActive().FindFork(block) : nullptr; if (height) { @@ -122,7 +131,11 @@ class LockImpl : public Chain::Lock } return nullopt; } - CBlockLocator getTipLocator() override { return ::ChainActive().GetLocator(); } + CBlockLocator getTipLocator() override + { + LockAnnotation lock(::cs_main); + return ::ChainActive().GetLocator(); + } Optional<int> findLocatorFork(const CBlockLocator& locator) override { LockAnnotation lock(::cs_main); @@ -319,7 +332,11 @@ public: CFeeRate relayMinFee() override { return ::minRelayTxFee; } CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; } CFeeRate relayDustFee() override { return ::dustRelayFee; } - bool getPruneMode() override { return ::fPruneMode; } + bool havePruned() override + { + LOCK(cs_main); + return ::fHavePruned; + } bool p2pEnabled() override { return g_connman != nullptr; } bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !IsInitialBlockDownload(); } bool isInitialBlockDownload() override { return IsInitialBlockDownload(); } diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 0b7249a5ab..1d604bd823 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -196,8 +196,8 @@ public: //! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's economical to spend. virtual CFeeRate relayDustFee() = 0; - //! Check if pruning is enabled. - virtual bool getPruneMode() = 0; + //! Check if any block has been pruned. + virtual bool havePruned() = 0; //! Check if p2p enabled. virtual bool p2pEnabled() = 0; diff --git a/src/key_io.cpp b/src/key_io.cpp index 1d53a5e074..cd41a93549 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -26,14 +26,14 @@ private: public: explicit DestinationEncoder(const CChainParams& params) : m_params(params) {} - std::string operator()(const CKeyID& id) const + std::string operator()(const PKHash& id) const { std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); data.insert(data.end(), id.begin(), id.end()); return EncodeBase58Check(data); } - std::string operator()(const CScriptID& id) const + std::string operator()(const ScriptHash& id) const { std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); data.insert(data.end(), id.begin(), id.end()); @@ -81,14 +81,14 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) { std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin()); - return CKeyID(hash); + return PKHash(hash); } // Script-hash-addresses have version 5 (or 196 testnet). // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) { std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin()); - return CScriptID(hash); + return ScriptHash(hash); } } data.clear(); diff --git a/src/keystore.cpp b/src/keystore.cpp index 148979cf35..f6d19416ce 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -178,16 +178,17 @@ CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest) { // Only supports destinations which map to single public keys, i.e. P2PKH, // P2WPKH, and P2SH-P2WPKH. - if (auto id = boost::get<CKeyID>(&dest)) { - return *id; + if (auto id = boost::get<PKHash>(&dest)) { + return CKeyID(*id); } if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) { return CKeyID(*witness_id); } - if (auto script_id = boost::get<CScriptID>(&dest)) { + if (auto script_hash = boost::get<ScriptHash>(&dest)) { CScript script; + CScriptID script_id(*script_hash); CTxDestination inner_dest; - if (store.GetCScript(*script_id, script) && ExtractDestination(script, inner_dest)) { + if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) { if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) { return CKeyID(*inner_witness_id); } diff --git a/src/outputtype.cpp b/src/outputtype.cpp index 7e5690dfc5..73ffb801f2 100644 --- a/src/outputtype.cpp +++ b/src/outputtype.cpp @@ -45,14 +45,14 @@ const std::string& FormatOutputType(OutputType type) CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type) { switch (type) { - case OutputType::LEGACY: return key.GetID(); + case OutputType::LEGACY: return PKHash(key); case OutputType::P2SH_SEGWIT: case OutputType::BECH32: { - if (!key.IsCompressed()) return key.GetID(); - CTxDestination witdest = WitnessV0KeyHash(key.GetID()); + if (!key.IsCompressed()) return PKHash(key); + CTxDestination witdest = WitnessV0KeyHash(PKHash(key)); CScript witprog = GetScriptForDestination(witdest); if (type == OutputType::P2SH_SEGWIT) { - return CScriptID(witprog); + return ScriptHash(witprog); } else { return witdest; } @@ -63,10 +63,10 @@ CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type) std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key) { - CKeyID keyid = key.GetID(); + PKHash keyid(key); if (key.IsCompressed()) { CTxDestination segwit = WitnessV0KeyHash(keyid); - CTxDestination p2sh = CScriptID(GetScriptForDestination(segwit)); + CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit)); return std::vector<CTxDestination>{std::move(keyid), std::move(p2sh), std::move(segwit)}; } else { return std::vector<CTxDestination>{std::move(keyid)}; @@ -80,19 +80,19 @@ CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript& // Note that scripts over 520 bytes are not yet supported. switch (type) { case OutputType::LEGACY: - return CScriptID(script); + return ScriptHash(script); case OutputType::P2SH_SEGWIT: case OutputType::BECH32: { CTxDestination witdest = WitnessV0ScriptHash(script); CScript witprog = GetScriptForDestination(witdest); // Check if the resulting program is solvable (i.e. doesn't use an uncompressed key) - if (!IsSolvable(keystore, witprog)) return CScriptID(script); + if (!IsSolvable(keystore, witprog)) return ScriptHash(script); // Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours. keystore.AddCScript(witprog); if (type == OutputType::BECH32) { return witdest; } else { - return CScriptID(witprog); + return ScriptHash(witprog); } } default: assert(false); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 0d9f1adcd2..6c9bae7673 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -471,8 +471,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) else if(ExtractDestination(out.txout.scriptPubKey, address)) { CPubKey pubkey; - CKeyID *keyid = boost::get<CKeyID>(&address); - if (keyid && model->wallet().getPubKey(*keyid, pubkey)) + PKHash *pkhash = boost::get<PKHash>(&address); + if (pkhash && model->wallet().getPubKey(CKeyID(*pkhash), pubkey)) { nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); } diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 64cc85d623..71f5f2ae75 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -120,8 +120,8 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return; } - const CKeyID* keyID = boost::get<CKeyID>(&destination); - if (!keyID) { + const PKHash* pkhash = boost::get<PKHash>(&destination); + if (!pkhash) { ui->addressIn_SM->setValid(false); ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); @@ -137,7 +137,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() } CKey key; - if (!model->wallet().getPrivKey(*keyID, key)) + if (!model->wallet().getPrivKey(CKeyID(*pkhash), key)) { ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_SM->setText(tr("Private key for the entered address is not available.")); @@ -198,7 +198,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return; } - if (!boost::get<CKeyID>(&destination)) { + if (!boost::get<PKHash>(&destination)) { ui->addressIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); @@ -229,7 +229,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() return; } - if (!(CTxDestination(pubkey.GetID()) == destination)) { + if (!(CTxDestination(PKHash(pubkey)) == destination)) { ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>")); return; diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index e1e14e99c0..21209d4994 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -145,6 +145,8 @@ void TestGUI() } { auto locked_chain = wallet->chain().lock(); + LockAnnotation lock(::cs_main); + WalletRescanReserver reserver(wallet.get()); reserver.reserve(); CWallet::ScanResult result = wallet->ScanForWalletTransactions(locked_chain->getBlockHash(0), {} /* stop_block */, reserver, true /* fUpdate */); @@ -169,8 +171,8 @@ void TestGUI() // Send two transactions, and verify they are added to transaction list. TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel(); QCOMPARE(transactionTableModel->rowCount({}), 105); - uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, CKeyID(), 5 * COIN, false /* rbf */); - uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, CKeyID(), 10 * COIN, true /* rbf */); + uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, false /* rbf */); + uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, true /* rbf */); QCOMPARE(transactionTableModel->rowCount({}), 107); QVERIFY(FindTx(*transactionTableModel, txid1).isValid()); QVERIFY(FindTx(*transactionTableModel, txid2).isValid()); diff --git a/src/random.cpp b/src/random.cpp index 1aa78a9034..b08de60fbe 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -652,7 +652,7 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len) if (requires_seed) RandomSeed(); std::vector<unsigned char> ret(len); if (len > 0) { - rng.Output(&ret[0], len); + rng.Keystream(&ret[0], len); } return ret; } diff --git a/src/random.h b/src/random.h index 1c035f87ba..2f9c0f5a36 100644 --- a/src/random.h +++ b/src/random.h @@ -111,7 +111,7 @@ private: if (requires_seed) { RandomSeed(); } - rng.Output(bytebuf, sizeof(bytebuf)); + rng.Keystream(bytebuf, sizeof(bytebuf)); bytebuf_size = sizeof(bytebuf); } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 3d0fa8eb2b..56018caf24 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -28,6 +28,7 @@ #include <sync.h> #include <txdb.h> #include <txmempool.h> +#include <undo.h> #include <util/strencodings.h> #include <util/system.h> #include <util/validation.h> @@ -485,7 +486,10 @@ UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose) const uint256& hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); entryToJSON(pool, info, e); - o.pushKV(hash.ToString(), info); + // Mempool has unique entries so there is no advantage in using + // UniValue::pushKV, which checks if the key already exists in O(N). + // UniValue::__pushKV is used instead which currently is O(1). + o.__pushKV(hash.ToString(), info); } return o; } else { @@ -828,6 +832,20 @@ static CBlock GetBlockChecked(const CBlockIndex* pblockindex) return block; } +static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) +{ + CBlockUndo blockUndo; + if (IsBlockPruned(pblockindex)) { + throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)"); + } + + if (!UndoReadFromDisk(blockUndo, pblockindex)) { + throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk"); + } + + return blockUndo; +} + static UniValue getblock(const JSONRPCRequest& request) { const RPCHelpMan help{"getblock", @@ -1799,8 +1817,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) { const RPCHelpMan help{"getblockstats", "\nCompute per block statistics for a given window. All amounts are in satoshis.\n" - "It won't work for some heights with pruning.\n" - "It won't work without -txindex for utxo_size_inc, *fee or *feerate stats.\n", + "It won't work for some heights with pruning.\n", { {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", "", {"", "string or numeric"}}, {"stats", RPCArg::Type::ARR, /* default */ "all values", "Values to plot (see result below)", @@ -1895,6 +1912,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) } const CBlock block = GetBlockChecked(pindex); + const CBlockUndo blockUndo = GetUndoChecked(pindex); const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default) const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0; @@ -1908,10 +1926,6 @@ static UniValue getblockstats(const JSONRPCRequest& request) const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate"); const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight"); - if (loop_inputs && !g_txindex) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more of the selected stats requires -txindex enabled"); - } - CAmount maxfee = 0; CAmount maxfeerate = 0; CAmount minfee = MAX_MONEY; @@ -1932,7 +1946,8 @@ static UniValue getblockstats(const JSONRPCRequest& request) std::vector<std::pair<CAmount, int64_t>> feerate_array; std::vector<int64_t> txsize_array; - for (const auto& tx : block.vtx) { + for (size_t i = 0; i < block.vtx.size(); ++i) { + const auto& tx = block.vtx.at(i); outputs += tx->vout.size(); CAmount tx_total_out = 0; @@ -1976,14 +1991,9 @@ static UniValue getblockstats(const JSONRPCRequest& request) if (loop_inputs) { CAmount tx_total_in = 0; - for (const CTxIn& in : tx->vin) { - CTransactionRef tx_in; - uint256 hashBlock; - if (!GetTransaction(in.prevout.hash, tx_in, Params().GetConsensus(), hashBlock)) { - throw JSONRPCError(RPC_INTERNAL_ERROR, std::string("Unexpected internal error (tx index seems corrupt)")); - } - - CTxOut prevoutput = tx_in->vout[in.prevout.n]; + const auto& txundo = blockUndo.vtxundo.at(i - 1); + for (const Coin& coin: txundo.vprevout) { + const CTxOut& prevoutput = coin.out; tx_total_in += prevoutput.nValue; utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; @@ -2244,8 +2254,7 @@ UniValue scantxoutset(const JSONRPCRequest& request) desc_str = desc_uni.get_str(); UniValue range_uni = find_value(scanobject, "range"); if (!range_uni.isNull()) { - range = ParseRange(range_uni); - if (range.first < 0 || (range.second >> 31) != 0 || range.second >= range.first + 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range"); + range = ParseDescriptorRange(range_uni); } } else { throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object"); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index bfb559f0db..7008a83143 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -24,6 +24,7 @@ #include <warnings.h> #include <stdint.h> +#include <tuple> #ifdef HAVE_MALLOC_INFO #include <malloc.h> #endif @@ -215,18 +216,7 @@ UniValue deriveaddresses(const JSONRPCRequest& request) int64_t range_end = 0; if (request.params.size() >= 2 && !request.params[1].isNull()) { - auto range = ParseRange(request.params[1]); - if (range.first < 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0"); - } - if ((range.second >> 31) != 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high"); - } - if (range.second >= range.first + 1000000) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large"); - } - range_begin = range.first; - range_end = range.second; + std::tie(range_begin, range_end) = ParseDescriptorRange(request.params[1]); } FlatSigningProvider key_provider; @@ -307,8 +297,8 @@ static UniValue verifymessage(const JSONRPCRequest& request) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); } - const CKeyID *keyID = boost::get<CKeyID>(&destination); - if (!keyID) { + const PKHash *pkhash = boost::get<PKHash>(&destination); + if (!pkhash) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); } @@ -326,7 +316,7 @@ static UniValue verifymessage(const JSONRPCRequest& request) if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) return false; - return (pubkey.GetID() == *keyID); + return (pubkey.GetID() == *pkhash); } static UniValue signmessagewithprivkey(const JSONRPCRequest& request) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 0a820af114..b3926786db 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -572,7 +572,7 @@ static UniValue decodescript(const JSONRPCRequest& request) if (type.isStr() && type.get_str() != "scripthash") { // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH, // don't return the address for a P2SH of the P2SH. - r.pushKV("p2sh", EncodeDestination(CScriptID(script))); + r.pushKV("p2sh", EncodeDestination(ScriptHash(script))); // P2SH and witness programs cannot be wrapped in P2WSH, if this script // is a witness program, don't return addresses for a segwit programs. if (type.get_str() == "pubkey" || type.get_str() == "pubkeyhash" || type.get_str() == "multisig" || type.get_str() == "nonstandard") { @@ -599,7 +599,7 @@ static UniValue decodescript(const JSONRPCRequest& request) segwitScr = GetScriptForDestination(WitnessV0ScriptHash(script)); } ScriptPubKeyToUniv(segwitScr, sr, /* fIncludeHex */ true); - sr.pushKV("p2sh-segwit", EncodeDestination(CScriptID(segwitScr))); + sr.pushKV("p2sh-segwit", EncodeDestination(ScriptHash(segwitScr))); r.pushKV("segwit", sr); } } diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 1a87c9f935..9cdb22001f 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -8,6 +8,8 @@ #include <tinyformat.h> #include <util/strencodings.h> +#include <tuple> + InitInterfaces* g_rpc_interfaces = nullptr; void RPCTypeCheck(const UniValue& params, @@ -181,7 +183,7 @@ public: return UniValue(UniValue::VOBJ); } - UniValue operator()(const CKeyID& keyID) const + UniValue operator()(const PKHash& keyID) const { UniValue obj(UniValue::VOBJ); obj.pushKV("isscript", false); @@ -189,7 +191,7 @@ public: return obj; } - UniValue operator()(const CScriptID& scriptID) const + UniValue operator()(const ScriptHash& scriptID) const { UniValue obj(UniValue::VOBJ); obj.pushKV("isscript", true); @@ -654,7 +656,7 @@ std::string RPCArg::ToString(const bool oneline) const assert(false); } -std::pair<int64_t, int64_t> ParseRange(const UniValue& value) +static std::pair<int64_t, int64_t> ParseRange(const UniValue& value) { if (value.isNum()) { return {0, value.get_int64()}; @@ -667,3 +669,19 @@ std::pair<int64_t, int64_t> ParseRange(const UniValue& value) } throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified as end or as [begin,end]"); } + +std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value) +{ + int64_t low, high; + std::tie(low, high) = ParseRange(value); + if (low < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0"); + } + if ((high >> 31) != 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high"); + } + if (high >= low + 1000000) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large"); + } + return {low, high}; +} diff --git a/src/rpc/util.h b/src/rpc/util.h index b5b5789253..e4fa8fc3d7 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -81,7 +81,7 @@ RPCErrorCode RPCErrorFromTransactionError(TransactionError terr); UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string = ""); //! Parse a JSON range specified as int64, or [int64, int64] -std::pair<int64_t, int64_t> ParseRange(const UniValue& value); +std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value); struct RPCArg { enum class Type { diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index a333d4d4ac..9be87fabb0 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -514,7 +514,7 @@ protected: { CKeyID id = keys[0].GetID(); out.pubkeys.emplace(id, keys[0]); - return Singleton(GetScriptForDestination(id)); + return Singleton(GetScriptForDestination(PKHash(id))); } public: PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {} @@ -544,12 +544,12 @@ protected: CKeyID id = keys[0].GetID(); out.pubkeys.emplace(id, keys[0]); ret.emplace_back(GetScriptForRawPubKey(keys[0])); // P2PK - ret.emplace_back(GetScriptForDestination(id)); // P2PKH + ret.emplace_back(GetScriptForDestination(PKHash(id))); // P2PKH if (keys[0].IsCompressed()) { CScript p2wpkh = GetScriptForDestination(WitnessV0KeyHash(id)); out.scripts.emplace(CScriptID(p2wpkh), p2wpkh); ret.emplace_back(p2wpkh); - ret.emplace_back(GetScriptForDestination(CScriptID(p2wpkh))); // P2SH-P2WPKH + ret.emplace_back(GetScriptForDestination(ScriptHash(p2wpkh))); // P2SH-P2WPKH } return ret; } @@ -572,7 +572,7 @@ public: class SHDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(CScriptID(*script))); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(ScriptHash(*script))); } public: SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {} }; diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 51bd2d6e9f..75fc2e84f1 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -90,7 +90,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, // This also applies to the P2WSH case. break; } - ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0)); + ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0)); break; } case TX_PUBKEYHASH: diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 31bfd04b0f..91a301bcdf 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -19,6 +19,10 @@ unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY; CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} +ScriptHash::ScriptHash(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} + +PKHash::PKHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {} + WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in) { CSHA256().Write(in.data(), in.size()).Finalize(begin()); @@ -162,17 +166,17 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) if (!pubKey.IsValid()) return false; - addressRet = pubKey.GetID(); + addressRet = PKHash(pubKey); return true; } else if (whichType == TX_PUBKEYHASH) { - addressRet = CKeyID(uint160(vSolutions[0])); + addressRet = PKHash(uint160(vSolutions[0])); return true; } else if (whichType == TX_SCRIPTHASH) { - addressRet = CScriptID(uint160(vSolutions[0])); + addressRet = ScriptHash(uint160(vSolutions[0])); return true; } else if (whichType == TX_WITNESS_V0_KEYHASH) { WitnessV0KeyHash hash; @@ -217,7 +221,7 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std:: if (!pubKey.IsValid()) continue; - CTxDestination address = pubKey.GetID(); + CTxDestination address = PKHash(pubKey); addressRet.push_back(address); } @@ -250,13 +254,13 @@ public: return false; } - bool operator()(const CKeyID &keyID) const { + bool operator()(const PKHash &keyID) const { script->clear(); *script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; return true; } - bool operator()(const CScriptID &scriptID) const { + bool operator()(const ScriptHash &scriptID) const { script->clear(); *script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL; return true; diff --git a/src/script/standard.h b/src/script/standard.h index f16068c413..e45e2d92cc 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -73,6 +73,22 @@ public: friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; } }; +struct PKHash : public uint160 +{ + PKHash() : uint160() {} + explicit PKHash(const uint160& hash) : uint160(hash) {} + explicit PKHash(const CPubKey& pubkey); + using uint160::uint160; +}; + +struct ScriptHash : public uint160 +{ + ScriptHash() : uint160() {} + explicit ScriptHash(const uint160& hash) : uint160(hash) {} + explicit ScriptHash(const CScript& script); + using uint160::uint160; +}; + struct WitnessV0ScriptHash : public uint256 { WitnessV0ScriptHash() : uint256() {} @@ -113,14 +129,14 @@ struct WitnessUnknown /** * A txout script template with a specific destination. It is either: * * CNoDestination: no destination set - * * CKeyID: TX_PUBKEYHASH destination (P2PKH) - * * CScriptID: TX_SCRIPTHASH destination (P2SH) + * * PKHash: TX_PUBKEYHASH destination (P2PKH) + * * ScriptHash: TX_SCRIPTHASH destination (P2SH) * * WitnessV0ScriptHash: TX_WITNESS_V0_SCRIPTHASH destination (P2WSH) * * WitnessV0KeyHash: TX_WITNESS_V0_KEYHASH destination (P2WPKH) * * WitnessUnknown: TX_WITNESS_UNKNOWN destination (P2W???) * A CTxDestination is the internal data type encoded in a bitcoin address */ -typedef boost::variant<CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination; +typedef boost::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination; /** Check whether a CTxDestination is a CNoDestination. */ bool IsValidDestination(const CTxDestination& dest); diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index a720d07e1c..7ba483173c 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -166,7 +166,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup) LOCK(cs_main); tip = ::ChainActive().Tip(); } - CScript coinbase_script_pub_key = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); + CScript coinbase_script_pub_key = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey())); std::vector<std::shared_ptr<CBlock>> chainA, chainB; BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainA)); BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainB)); diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 232c077c68..665975ca67 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -485,7 +485,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization) BOOST_CHECK_EQUAL(cc1.fCoinBase, false); BOOST_CHECK_EQUAL(cc1.nHeight, 203998U); BOOST_CHECK_EQUAL(cc1.out.nValue, CAmount{60000000000}); - BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35")))))); + BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35")))))); // Good example CDataStream ss2(ParseHex("8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"), SER_DISK, CLIENT_VERSION); @@ -494,7 +494,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization) BOOST_CHECK_EQUAL(cc2.fCoinBase, true); BOOST_CHECK_EQUAL(cc2.nHeight, 120891U); BOOST_CHECK_EQUAL(cc2.out.nValue, 110397); - BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4")))))); + BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4")))))); // Smallest possible example CDataStream ss3(ParseHex("000006"), SER_DISK, CLIENT_VERSION); diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 0d05b6514f..64458cd7d4 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -125,17 +125,36 @@ static void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, b } } -static void TestChaCha20(const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout) +static void TestChaCha20(const std::string &hex_message, const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout) { std::vector<unsigned char> key = ParseHex(hexkey); + std::vector<unsigned char> m = ParseHex(hex_message); ChaCha20 rng(key.data(), key.size()); rng.SetIV(nonce); rng.Seek(seek); std::vector<unsigned char> out = ParseHex(hexout); std::vector<unsigned char> outres; outres.resize(out.size()); - rng.Output(outres.data(), outres.size()); + assert(hex_message.empty() || m.size() == out.size()); + + // perform the ChaCha20 round(s), if message is provided it will output the encrypted ciphertext otherwise the keystream + if (!hex_message.empty()) { + rng.Crypt(m.data(), outres.data(), outres.size()); + } else { + rng.Keystream(outres.data(), outres.size()); + } BOOST_CHECK(out == outres); + if (!hex_message.empty()) { + // Manually XOR with the keystream and compare the output + rng.SetIV(nonce); + rng.Seek(seek); + std::vector<unsigned char> only_keystream(outres.size()); + rng.Keystream(only_keystream.data(), only_keystream.size()); + for (size_t i = 0; i != m.size(); i++) { + outres[i] = m[i] ^ only_keystream[i]; + } + BOOST_CHECK(out == outres); + } } static void TestPoly1305(const std::string &hexmessage, const std::string &hexkey, const std::string& hextag) @@ -420,25 +439,37 @@ BOOST_AUTO_TEST_CASE(aes_cbc_testvectors) { BOOST_AUTO_TEST_CASE(chacha20_testvector) { // Test vector from RFC 7539 - TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1, + + // test encryption + TestChaCha20("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756" + "c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e" + "20776f756c642062652069742e", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1, + "6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d" + "624e65152ab8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74" + "a35be6b40b8eedf2785e42874d" + ); + + // test keystream output + TestChaCha20("", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1, "224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fcaec9ef3cf788a3b0aa372600a92b57974cded2b9334794cb" "a40c63e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a" "832c89c167eacd901d7e2bf363"); // Test vectors from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7 - TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0, 0, + TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 0, 0, "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b" "8f41518a11cc387b669b2ee6586"); - TestChaCha20("0000000000000000000000000000000000000000000000000000000000000001", 0, 0, + TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000001", 0, 0, "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d79" "2b1c43fea817e9ad275ae546963"); - TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0x0100000000000000ULL, 0, + TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 0x0100000000000000ULL, 0, "de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b52770" "62eb7a0433e445f41e3"); - TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 1, 0, + TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 1, 0, "ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc4" "97a0b466e7d6bbdb0041b2f586b"); - TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x0706050403020100ULL, 0, + TestChaCha20("", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x0706050403020100ULL, 0, "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3b" "e59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc1" "18be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5" diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index c5d3611dfa..d47f395c15 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -381,7 +381,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vin[0].scriptSig << OP_1; tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); AddOrphanTx(MakeTransactionRef(tx), i); } @@ -397,7 +397,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vin[0].prevout.hash = txPrev->GetHash(); tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL)); AddOrphanTx(MakeTransactionRef(tx), i); @@ -411,7 +411,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) CMutableTransaction tx; tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); tx.vin.resize(2777); for (unsigned int j = 0; j < tx.vin.size(); j++) { diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index e816546e62..ceed73b14d 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -68,10 +68,10 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(!key2C.VerifyPubKey(pubkey2)); BOOST_CHECK(key2C.VerifyPubKey(pubkey2C)); - BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(pubkey1.GetID())); - BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(pubkey2.GetID())); - BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID())); - BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID())); + BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(PKHash(pubkey1))); + BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(PKHash(pubkey2))); + BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(PKHash(pubkey1C))); + BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(PKHash(pubkey2C))); for (int n=0; n<16; n++) { diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 9ab1c348fa..4321d7d16e 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -8,15 +8,15 @@ #include <consensus/merkle.h> #include <consensus/tx_verify.h> #include <consensus/validation.h> -#include <validation.h> #include <miner.h> #include <policy/policy.h> #include <pubkey.h> #include <script/standard.h> #include <txmempool.h> #include <uint256.h> -#include <util/system.h> #include <util/strencodings.h> +#include <util/system.h> +#include <validation.h> #include <test/setup_common.h> @@ -82,7 +82,7 @@ struct { {2, 0xbbbeb305}, {2, 0xfe1c810a}, }; -static CBlockIndex CreateBlockIndex(int nHeight) +static CBlockIndex CreateBlockIndex(int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { CBlockIndex index; index.nHeight = nHeight; @@ -399,7 +399,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].scriptSig = CScript() << OP_1; tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE; script = CScript() << OP_0; - tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); + tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script)); hash = tx.GetHash(); mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index 0ce5f09e42..9c4606f1b3 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -69,14 +69,14 @@ BOOST_AUTO_TEST_CASE(sign) // different keys, straight/P2SH, pubkey/pubkeyhash CScript standardScripts[4]; standardScripts[0] << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; - standardScripts[1] = GetScriptForDestination(key[1].GetPubKey().GetID()); + standardScripts[1] = GetScriptForDestination(PKHash(key[1].GetPubKey())); standardScripts[2] << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; - standardScripts[3] = GetScriptForDestination(key[2].GetPubKey().GetID()); + standardScripts[3] = GetScriptForDestination(PKHash(key[2].GetPubKey())); CScript evalScripts[4]; for (int i = 0; i < 4; i++) { BOOST_CHECK(keystore.AddCScript(standardScripts[i])); - evalScripts[i] = GetScriptForDestination(CScriptID(standardScripts[i])); + evalScripts[i] = GetScriptForDestination(ScriptHash(standardScripts[i])); } CMutableTransaction txFrom; // Funding transaction: @@ -131,7 +131,7 @@ BOOST_AUTO_TEST_CASE(norecurse) CScript invalidAsScript; invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE; - CScript p2sh = GetScriptForDestination(CScriptID(invalidAsScript)); + CScript p2sh = GetScriptForDestination(ScriptHash(invalidAsScript)); CScript scriptSig; scriptSig << Serialize(invalidAsScript); @@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE(norecurse) // Try to recur, and verification should succeed because // the inner HASH160 <> EQUAL should only check the hash: - CScript p2sh2 = GetScriptForDestination(CScriptID(p2sh)); + CScript p2sh2 = GetScriptForDestination(ScriptHash(p2sh)); CScript scriptSig2; scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh); @@ -165,7 +165,7 @@ BOOST_AUTO_TEST_CASE(set) } CScript inner[4]; - inner[0] = GetScriptForDestination(key[0].GetPubKey().GetID()); + inner[0] = GetScriptForDestination(PKHash(key[0].GetPubKey())); inner[1] = GetScriptForMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+2)); inner[2] = GetScriptForMultisig(1, std::vector<CPubKey>(keys.begin(), keys.begin()+2)); inner[3] = GetScriptForMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+3)); @@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(set) CScript outer[4]; for (int i = 0; i < 4; i++) { - outer[i] = GetScriptForDestination(CScriptID(inner[i])); + outer[i] = GetScriptForDestination(ScriptHash(inner[i])); BOOST_CHECK(keystore.AddCScript(inner[i])); } @@ -253,7 +253,7 @@ BOOST_AUTO_TEST_CASE(switchover) CScript scriptSig; scriptSig << Serialize(notValid); - CScript fund = GetScriptForDestination(CScriptID(notValid)); + CScript fund = GetScriptForDestination(ScriptHash(notValid)); // Validation should succeed under old rules (hash is correct): @@ -284,11 +284,11 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txFrom.vout.resize(7); // First three are standard: - CScript pay1 = GetScriptForDestination(key[0].GetPubKey().GetID()); + CScript pay1 = GetScriptForDestination(PKHash(key[0].GetPubKey())); BOOST_CHECK(keystore.AddCScript(pay1)); CScript pay1of3 = GetScriptForMultisig(1, keys); - txFrom.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(pay1)); // P2SH (OP_CHECKSIG) + txFrom.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(pay1)); // P2SH (OP_CHECKSIG) txFrom.vout[0].nValue = 1000; txFrom.vout[1].scriptPubKey = pay1; // ordinary OP_CHECKSIG txFrom.vout[1].nValue = 2000; @@ -303,7 +303,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) oneAndTwo << OP_2 << ToByteVector(key[3].GetPubKey()) << ToByteVector(key[4].GetPubKey()) << ToByteVector(key[5].GetPubKey()); oneAndTwo << OP_3 << OP_CHECKMULTISIG; BOOST_CHECK(keystore.AddCScript(oneAndTwo)); - txFrom.vout[3].scriptPubKey = GetScriptForDestination(CScriptID(oneAndTwo)); + txFrom.vout[3].scriptPubKey = GetScriptForDestination(ScriptHash(oneAndTwo)); txFrom.vout[3].nValue = 4000; // vout[4] is max sigops: @@ -312,24 +312,24 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) fifteenSigops << ToByteVector(key[i%3].GetPubKey()); fifteenSigops << OP_15 << OP_CHECKMULTISIG; BOOST_CHECK(keystore.AddCScript(fifteenSigops)); - txFrom.vout[4].scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops)); + txFrom.vout[4].scriptPubKey = GetScriptForDestination(ScriptHash(fifteenSigops)); txFrom.vout[4].nValue = 5000; // vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS CScript sixteenSigops; sixteenSigops << OP_16 << OP_CHECKMULTISIG; BOOST_CHECK(keystore.AddCScript(sixteenSigops)); - txFrom.vout[5].scriptPubKey = GetScriptForDestination(CScriptID(sixteenSigops)); + txFrom.vout[5].scriptPubKey = GetScriptForDestination(ScriptHash(sixteenSigops)); txFrom.vout[5].nValue = 5000; CScript twentySigops; twentySigops << OP_CHECKMULTISIG; BOOST_CHECK(keystore.AddCScript(twentySigops)); - txFrom.vout[6].scriptPubKey = GetScriptForDestination(CScriptID(twentySigops)); + txFrom.vout[6].scriptPubKey = GetScriptForDestination(ScriptHash(twentySigops)); txFrom.vout[6].nValue = 6000; AddCoins(coins, CTransaction(txFrom), 0); CMutableTransaction txTo; txTo.vout.resize(1); - txTo.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); + txTo.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[1].GetPubKey())); txTo.vin.resize(5); for (int i = 0; i < 5; i++) @@ -352,7 +352,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) CMutableTransaction txToNonStd1; txToNonStd1.vout.resize(1); - txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); + txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[1].GetPubKey())); txToNonStd1.vout[0].nValue = 1000; txToNonStd1.vin.resize(1); txToNonStd1.vin[0].prevout.n = 5; @@ -364,7 +364,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) CMutableTransaction txToNonStd2; txToNonStd2.vout.resize(1); - txToNonStd2.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); + txToNonStd2.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[1].GetPubKey())); txToNonStd2.vout[0].nValue = 1000; txToNonStd2.vin.resize(1); txToNonStd2.vin[0].prevout.n = 6; diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 36a2b1bee5..9f50083335 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -179,23 +179,23 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) s.clear(); s << ToByteVector(pubkey) << OP_CHECKSIG; BOOST_CHECK(ExtractDestination(s, address)); - BOOST_CHECK(boost::get<CKeyID>(&address) && - *boost::get<CKeyID>(&address) == pubkey.GetID()); + BOOST_CHECK(boost::get<PKHash>(&address) && + *boost::get<PKHash>(&address) == PKHash(pubkey)); // TX_PUBKEYHASH s.clear(); s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; BOOST_CHECK(ExtractDestination(s, address)); - BOOST_CHECK(boost::get<CKeyID>(&address) && - *boost::get<CKeyID>(&address) == pubkey.GetID()); + BOOST_CHECK(boost::get<PKHash>(&address) && + *boost::get<PKHash>(&address) == PKHash(pubkey)); // TX_SCRIPTHASH CScript redeemScript(s); // initialize with leftover P2PKH script s.clear(); s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; BOOST_CHECK(ExtractDestination(s, address)); - BOOST_CHECK(boost::get<CScriptID>(&address) && - *boost::get<CScriptID>(&address) == CScriptID(redeemScript)); + BOOST_CHECK(boost::get<ScriptHash>(&address) && + *boost::get<ScriptHash>(&address) == ScriptHash(redeemScript)); // TX_MULTISIG s.clear(); @@ -255,8 +255,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TX_PUBKEY); BOOST_CHECK_EQUAL(addresses.size(), 1U); BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) && - *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID()); + BOOST_CHECK(boost::get<PKHash>(&addresses[0]) && + *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); // TX_PUBKEYHASH s.clear(); @@ -265,8 +265,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH); BOOST_CHECK_EQUAL(addresses.size(), 1U); BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) && - *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID()); + BOOST_CHECK(boost::get<PKHash>(&addresses[0]) && + *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); // TX_SCRIPTHASH CScript redeemScript(s); // initialize with leftover P2PKH script @@ -276,8 +276,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH); BOOST_CHECK_EQUAL(addresses.size(), 1U); BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(boost::get<CScriptID>(&addresses[0]) && - *boost::get<CScriptID>(&addresses[0]) == CScriptID(redeemScript)); + BOOST_CHECK(boost::get<ScriptHash>(&addresses[0]) && + *boost::get<ScriptHash>(&addresses[0]) == ScriptHash(redeemScript)); // TX_MULTISIG s.clear(); @@ -289,10 +289,10 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); BOOST_CHECK_EQUAL(addresses.size(), 2U); BOOST_CHECK_EQUAL(nRequired, 2); - BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) && - *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID()); - BOOST_CHECK(boost::get<CKeyID>(&addresses[1]) && - *boost::get<CKeyID>(&addresses[1]) == pubkeys[1].GetID()); + BOOST_CHECK(boost::get<PKHash>(&addresses[0]) && + *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); + BOOST_CHECK(boost::get<PKHash>(&addresses[1]) && + *boost::get<PKHash>(&addresses[1]) == PKHash(pubkeys[1])); // TX_NULL_DATA s.clear(); @@ -311,17 +311,17 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) CScript expected, result; - // CKeyID + // PKHash expected.clear(); expected << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; - result = GetScriptForDestination(pubkeys[0].GetID()); + result = GetScriptForDestination(PKHash(pubkeys[0])); BOOST_CHECK(result == expected); // CScriptID CScript redeemScript(result); expected.clear(); expected << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; - result = GetScriptForDestination(CScriptID(redeemScript)); + result = GetScriptForDestination(ScriptHash(redeemScript)); BOOST_CHECK(result == expected); // CNoDestination @@ -421,7 +421,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) // P2PKH compressed { CBasicKeyStore keystore; - scriptPubKey = GetScriptForDestination(pubkeys[0].GetID()); + scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0])); // Keystore does not have key result = IsMine(keystore, scriptPubKey); @@ -436,7 +436,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) // P2PKH uncompressed { CBasicKeyStore keystore; - scriptPubKey = GetScriptForDestination(uncompressedPubkey.GetID()); + scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey)); // Keystore does not have key result = IsMine(keystore, scriptPubKey); @@ -452,8 +452,8 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) { CBasicKeyStore keystore; - CScript redeemScript = GetScriptForDestination(pubkeys[0].GetID()); - scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); + CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0])); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); // Keystore does not have redeemScript or key result = IsMine(keystore, scriptPubKey); @@ -474,9 +474,9 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) { CBasicKeyStore keystore; - CScript redeemscript_inner = GetScriptForDestination(pubkeys[0].GetID()); - CScript redeemscript = GetScriptForDestination(CScriptID(redeemscript_inner)); - scriptPubKey = GetScriptForDestination(CScriptID(redeemscript)); + CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0])); + CScript redeemscript = GetScriptForDestination(ScriptHash(redeemscript_inner)); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemscript)); BOOST_CHECK(keystore.AddCScript(redeemscript)); BOOST_CHECK(keystore.AddCScript(redeemscript_inner)); @@ -490,8 +490,8 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) { CBasicKeyStore keystore; - CScript redeemscript = GetScriptForDestination(pubkeys[0].GetID()); - CScript witnessscript = GetScriptForDestination(CScriptID(redeemscript)); + CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0])); + CScript witnessscript = GetScriptForDestination(ScriptHash(redeemscript)); scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript)); BOOST_CHECK(keystore.AddCScript(witnessscript)); @@ -506,7 +506,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) { CBasicKeyStore keystore; - CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0].GetID())); + CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0]))); scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript)); BOOST_CHECK(keystore.AddCScript(witnessscript)); @@ -520,7 +520,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) { CBasicKeyStore keystore; - CScript witnessscript_inner = GetScriptForDestination(pubkeys[0].GetID()); + CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0])); CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner)); scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript)); @@ -537,7 +537,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) CBasicKeyStore keystore; BOOST_CHECK(keystore.AddKey(keys[0])); - scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0].GetID())); + scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0]))); // Keystore implicitly has key and P2SH redeemScript BOOST_CHECK(keystore.AddCScript(scriptPubKey)); @@ -550,7 +550,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) CBasicKeyStore keystore; BOOST_CHECK(keystore.AddKey(uncompressedKey)); - scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(uncompressedPubkey.GetID())); + scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(uncompressedPubkey))); // Keystore has key, but no P2SH redeemScript result = IsMine(keystore, scriptPubKey); @@ -598,7 +598,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) BOOST_CHECK(keystore.AddKey(keys[1])); CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]}); - scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); // Keystore has no redeemScript result = IsMine(keystore, scriptPubKey); @@ -664,7 +664,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]}); CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript)); - scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); // Keystore has no witnessScript, P2SH redeemScript, or keys result = IsMine(keystore, scriptPubKey); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 588ae55a69..4798909e2f 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1211,7 +1211,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) BOOST_CHECK(keystore.AddKey(key)); } - CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID())); + CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(PKHash(keys[0].GetPubKey()))); CMutableTransaction txTo = BuildSpendingTransaction(CScript(), CScriptWitness(), CTransaction(txFrom)); CScript& scriptPubKey = txFrom.vout[0].scriptPubKey; SignatureData scriptSig; @@ -1237,7 +1237,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) // P2SH, single-signature case: CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; BOOST_CHECK(keystore.AddCScript(pkSingle)); - scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); + scriptPubKey = GetScriptForDestination(ScriptHash(pkSingle)); BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL)); scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]); combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty); diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 4efa023fbb..5c12ec13d2 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount) BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3U); BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21U); - CScript p2sh = GetScriptForDestination(CScriptID(s1)); + CScript p2sh = GetScriptForDestination(ScriptHash(s1)); CScript scriptSig; scriptSig << OP_0 << Serialize(s1); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount) BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3U); BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20U); - p2sh = GetScriptForDestination(CScriptID(s2)); + p2sh = GetScriptForDestination(ScriptHash(s2)); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0U); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0U); CScript scriptSig2; @@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) // Multisig nested in P2SH { CScript redeemScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY; - CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); + CScript scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); CScript scriptSig = CScript() << OP_0 << OP_0 << ToByteVector(redeemScript); BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CScriptWitness()); @@ -185,7 +185,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) { CScript p2pk = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; CScript scriptSig = GetScriptForWitness(p2pk); - CScript scriptPubKey = GetScriptForDestination(CScriptID(scriptSig)); + CScript scriptPubKey = GetScriptForDestination(ScriptHash(scriptSig)); scriptSig = CScript() << ToByteVector(scriptSig); CScriptWitness scriptWitness; scriptWitness.stack.push_back(std::vector<unsigned char>(0)); @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) { CScript witnessScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY; CScript redeemScript = GetScriptForWitness(witnessScript); - CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); + CScript scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); CScript scriptSig = CScript() << ToByteVector(redeemScript); CScriptWitness scriptWitness; scriptWitness.stack.push_back(std::vector<unsigned char>(0)); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 6242fdabd1..f5ff18c055 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -311,9 +311,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet) dummyTransactions[1].vout.resize(2); dummyTransactions[1].vout[0].nValue = 21*CENT; - dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID()); + dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[2].GetPubKey())); dummyTransactions[1].vout[1].nValue = 22*CENT; - dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID()); + dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(PKHash(key[3].GetPubKey())); AddCoins(coinsRet, CTransaction(dummyTransactions[1]), 0); return dummyTransactions; @@ -562,8 +562,8 @@ BOOST_AUTO_TEST_CASE(test_witness) CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); // P2SH pay-to-compressed-pubkey. - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey1)), output1, input1); - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey2)), output2, input2); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey1)), output1, input1); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey2)), output2, input2); ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1); CheckWithFlag(output1, input1, 0, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); @@ -587,8 +587,8 @@ BOOST_AUTO_TEST_CASE(test_witness) CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); // P2SH witness pay-to-compressed-pubkey (v0). - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1))), output1, input1); - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2))), output2, input2); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey1))), output1, input1); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey2))), output2, input2); ReplaceRedeemScript(input2.vin[0].scriptSig, GetScriptForWitness(scriptPubkey1)); CheckWithFlag(output1, input1, 0, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); @@ -612,8 +612,8 @@ BOOST_AUTO_TEST_CASE(test_witness) CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); // P2SH pay-to-uncompressed-pubkey. - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey1L)), output1, input1); - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey2L)), output2, input2); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey1L)), output1, input1); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey2L)), output2, input2); ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1L); CheckWithFlag(output1, input1, 0, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); @@ -629,8 +629,8 @@ BOOST_AUTO_TEST_CASE(test_witness) CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2, false); // Signing disabled for P2SH witness pay-to-uncompressed-pubkey (v1). - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1, false); - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2, false); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey1L))), output1, input1, false); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey2L))), output2, input2, false); // Normal 2-of-2 multisig CreateCreditAndSpend(keystore, scriptMulti, output1, input1, false); @@ -642,10 +642,10 @@ BOOST_AUTO_TEST_CASE(test_witness) CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); // P2SH 2-of-2 multisig - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptMulti)), output1, input1, false); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptMulti)), output1, input1, false); CheckWithFlag(output1, input1, 0, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, false); - CreateCreditAndSpend(keystore2, GetScriptForDestination(CScriptID(scriptMulti)), output2, input2, false); + CreateCreditAndSpend(keystore2, GetScriptForDestination(ScriptHash(scriptMulti)), output2, input2, false); CheckWithFlag(output2, input2, 0, true); CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, false); BOOST_CHECK(*output1 == *output2); @@ -666,10 +666,10 @@ BOOST_AUTO_TEST_CASE(test_witness) CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); // P2SH witness 2-of-2 multisig - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptMulti))), output1, input1, false); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptMulti))), output1, input1, false); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false); - CreateCreditAndSpend(keystore2, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptMulti))), output2, input2, false); + CreateCreditAndSpend(keystore2, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptMulti))), output2, input2, false); CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false); BOOST_CHECK(*output1 == *output2); @@ -695,7 +695,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) t.vout[0].nValue = 90*CENT; CKey key; key.MakeNewKey(true); - t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + t.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); std::string reason; BOOST_CHECK(IsStandardTx(CTransaction(t), reason)); diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp index 9d62b471c1..19561d4f67 100644 --- a/src/test/txindex_tests.cpp +++ b/src/test/txindex_tests.cpp @@ -56,7 +56,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup) // Check that new transactions in new blocks make it into the index. for (int i = 0; i < 10; i++) { - CScript coinbase_script_pub_key = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); + CScript coinbase_script_pub_key = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey())); std::vector<CMutableTransaction> no_txns; const CBlock& block = CreateAndProcessBlock(no_txns, coinbase_script_pub_key); const CTransaction& txn = *block.vtx[0]; diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 1077a3eaa5..fe30d5f3a7 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -66,18 +66,27 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) // Test 1: block with both of those transactions should be rejected. block = CreateAndProcessBlock(spends, scriptPubKey); - BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + } // Test 2: ... and should be rejected if spend1 is in the memory pool BOOST_CHECK(ToMemPool(spends[0])); block = CreateAndProcessBlock(spends, scriptPubKey); - BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + } mempool.clear(); // Test 3: ... and should be rejected if spend2 is in the memory pool BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(spends, scriptPubKey); - BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + } mempool.clear(); // Final sanity test: first spend in mempool, second in block, that's OK: @@ -85,7 +94,10 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) oneSpend.push_back(spends[0]); BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(oneSpend, scriptPubKey); - BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash()); + } // spends[1] should have been removed from the mempool when the // block with spends[0] is accepted: BOOST_CHECK_EQUAL(mempool.size(), 0U); @@ -151,8 +163,8 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) } CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; - CScript p2sh_scriptPubKey = GetScriptForDestination(CScriptID(p2pk_scriptPubKey)); - CScript p2pkh_scriptPubKey = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); + CScript p2sh_scriptPubKey = GetScriptForDestination(ScriptHash(p2pk_scriptPubKey)); + CScript p2pkh_scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey())); CScript p2wpkh_scriptPubKey = GetScriptForWitness(p2pkh_scriptPubKey); CBasicKeyStore keystore; diff --git a/src/test/util.cpp b/src/test/util.cpp index 2afa88bd2c..64ecc6623a 100644 --- a/src/test/util.cpp +++ b/src/test/util.cpp @@ -84,6 +84,7 @@ std::shared_ptr<CBlock> PrepareBlock(const CScript& coinbase_scriptPubKey) .CreateNewBlock(coinbase_scriptPubKey) ->block); + LOCK(cs_main); block->nTime = ::ChainActive().Tip()->GetMedianTimePast() + 1; block->hashMerkleRoot = BlockMerkleRoot(*block); diff --git a/src/test/util.h b/src/test/util.h index 8ba647ec3f..f90cb0d623 100644 --- a/src/test/util.h +++ b/src/test/util.h @@ -34,5 +34,37 @@ std::string getnewaddress(CWallet& w); /** Returns the generated coin */ CTxIn generatetoaddress(const std::string& address); +/** + * Increment a string. Useful to enumerate all fixed length strings with + * characters in [min_char, max_char]. + */ +template <typename CharType, size_t StringLength> +bool NextString(CharType (&string)[StringLength], CharType min_char, CharType max_char) +{ + for (CharType& elem : string) { + bool has_next = elem != max_char; + elem = elem < min_char || elem >= max_char ? min_char : CharType(elem + 1); + if (has_next) return true; + } + return false; +} + +/** + * Iterate over string values and call function for each string without + * successive duplicate characters. + */ +template <typename CharType, size_t StringLength, typename Fn> +void ForEachNoDup(CharType (&string)[StringLength], CharType min_char, CharType max_char, Fn&& fn) { + for (bool has_next = true; has_next; has_next = NextString(string, min_char, max_char)) { + int prev = -1; + bool skip_string = false; + for (CharType c : string) { + if (c == prev) skip_string = true; + if (skip_string || c < min_char || c > max_char) break; + prev = c; + } + if (!skip_string) fn(); + } +} #endif // BITCOIN_TEST_UTIL_H diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 0f1834240d..51dd25ed1c 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -7,6 +7,7 @@ #include <clientversion.h> #include <primitives/transaction.h> #include <sync.h> +#include <test/util.h> #include <util/strencodings.h> #include <util/moneystr.h> #include <test/setup_common.h> @@ -580,7 +581,7 @@ BOOST_AUTO_TEST_CASE(util_GetChainName) // Test different ways settings can be merged, and verify results. This test can // be used to confirm that updates to settings code don't change behavior -// unintentially. +// unintentionally. // // The test covers: // @@ -600,20 +601,22 @@ BOOST_AUTO_TEST_CASE(util_GetChainName) // outside a network section, and non-network specific settings like "-server" // that aren't sensitive to the network. // -struct SettingsMergeTestingSetup : public BasicTestingSetup { +struct ArgsMergeTestingSetup : public BasicTestingSetup { //! Max number of actions to sequence together. Can decrease this when //! debugging to make test results easier to understand. static constexpr int MAX_ACTIONS = 3; - enum Action { SET = 0, NEGATE, SECTION_SET, SECTION_NEGATE, END }; + enum Action { NONE, SET, NEGATE, SECTION_SET, SECTION_NEGATE }; using ActionList = Action[MAX_ACTIONS]; //! Enumerate all possible test configurations. template <typename Fn> void ForEachMergeSetup(Fn&& fn) { - ForEachActionList([&](const ActionList& arg_actions) { - ForEachActionList([&](const ActionList& conf_actions) { + ActionList arg_actions = {}; + ForEachNoDup(arg_actions, SET, SECTION_NEGATE, [&] { + ActionList conf_actions = {}; + ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] { for (bool soft_set : {false, true}) { for (bool force_set : {false, true}) { for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) { @@ -629,36 +632,6 @@ struct SettingsMergeTestingSetup : public BasicTestingSetup { }); } - //! Enumerate interesting combinations of actions. - template <typename Fn> - void ForEachActionList(Fn&& fn) - { - ActionList actions = {SET}; - for (bool done = false; !done;) { - int prev_action = -1; - bool skip_actions = false; - for (Action action : actions) { - if ((prev_action == END && action != END) || (prev_action != END && action == prev_action)) { - // To cut down list of enumerated settings, skip enumerating - // settings with ignored actions after an END, and settings that - // repeat the same action twice in a row. - skip_actions = true; - break; - } - prev_action = action; - } - if (!skip_actions) fn(actions); - done = true; - for (Action& action : actions) { - action = Action(action < END ? action + 1 : 0); - if (action) { - done = false; - break; - } - } - } - } - //! Translate actions into a list of <key>=<value> setting strings. std::vector<std::string> GetValues(const ActionList& actions, const std::string& section, @@ -668,7 +641,7 @@ struct SettingsMergeTestingSetup : public BasicTestingSetup { std::vector<std::string> values; int suffix = 0; for (Action action : actions) { - if (action == END) break; + if (action == NONE) break; std::string prefix; if (action == SECTION_SET || action == SECTION_NEGATE) prefix = section + "."; if (action == SET || action == SECTION_SET) { @@ -687,12 +660,12 @@ struct SettingsMergeTestingSetup : public BasicTestingSetup { // Regression test covering different ways config settings can be merged. The // test parses and merges settings, representing the results as strings that get // compared against an expected hash. To debug, the result strings can be dumped -// to a file (see below). -BOOST_FIXTURE_TEST_CASE(util_SettingsMerge, SettingsMergeTestingSetup) +// to a file (see comments below). +BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup) { CHash256 out_sha; FILE* out_file = nullptr; - if (const char* out_path = getenv("SETTINGS_MERGE_TEST_OUT")) { + if (const char* out_path = getenv("ARGS_MERGE_TEST_OUT")) { out_file = fsbridge::fopen(out_path, "w"); if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed"); } @@ -706,7 +679,7 @@ BOOST_FIXTURE_TEST_CASE(util_SettingsMerge, SettingsMergeTestingSetup) desc += network; parser.m_network = network; - const std::string& name = net_specific ? "server" : "wallet"; + const std::string& name = net_specific ? "wallet" : "server"; const std::string key = "-" + name; parser.AddArg(key, name, false, OptionsCategory::OPTIONS); if (net_specific) parser.SetNetworkOnlyArg(key); @@ -794,14 +767,116 @@ BOOST_FIXTURE_TEST_CASE(util_SettingsMerge, SettingsMergeTestingSetup) // If check below fails, should manually dump the results with: // - // SETTINGS_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_SettingsMerge + // ARGS_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ArgsMerge // // And verify diff against previous results to make sure the changes are expected. // // Results file is formatted like: // // <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output> - BOOST_CHECK_EQUAL(out_sha_hex, "80964e17fbd3c5569d3c824d032e28e2d319ef57494735b0e76eb7aad9957f2c"); + BOOST_CHECK_EQUAL(out_sha_hex, "b835eef5977d69114eb039a976201f8c7121f34fe2b7ea2b73cafb516e5c9dc8"); +} + +// Similar test as above, but for ArgsManager::GetChainName function. +struct ChainMergeTestingSetup : public BasicTestingSetup { + static constexpr int MAX_ACTIONS = 2; + + enum Action { NONE, ENABLE_TEST, DISABLE_TEST, NEGATE_TEST, ENABLE_REG, DISABLE_REG, NEGATE_REG }; + using ActionList = Action[MAX_ACTIONS]; + + //! Enumerate all possible test configurations. + template <typename Fn> + void ForEachMergeSetup(Fn&& fn) + { + ActionList arg_actions = {}; + ForEachNoDup(arg_actions, ENABLE_TEST, NEGATE_REG, [&] { + ActionList conf_actions = {}; + ForEachNoDup(conf_actions, ENABLE_TEST, NEGATE_REG, [&] { fn(arg_actions, conf_actions); }); + }); + } +}; + +BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup) +{ + CHash256 out_sha; + FILE* out_file = nullptr; + if (const char* out_path = getenv("CHAIN_MERGE_TEST_OUT")) { + out_file = fsbridge::fopen(out_path, "w"); + if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed"); + } + + ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions) { + TestArgsManager parser; + LOCK(parser.cs_args); + parser.AddArg("-regtest", "regtest", false, OptionsCategory::OPTIONS); + parser.AddArg("-testnet", "testnet", false, OptionsCategory::OPTIONS); + + auto arg = [](Action action) { return action == ENABLE_TEST ? "-testnet=1" : + action == DISABLE_TEST ? "-testnet=0" : + action == NEGATE_TEST ? "-notestnet=1" : + action == ENABLE_REG ? "-regtest=1" : + action == DISABLE_REG ? "-regtest=0" : + action == NEGATE_REG ? "-noregtest=1" : nullptr; }; + + std::string desc; + std::vector<const char*> argv = {"ignored"}; + for (Action action : arg_actions) { + const char* argstr = arg(action); + if (!argstr) break; + argv.push_back(argstr); + desc += " "; + desc += argv.back(); + } + std::string error; + BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error)); + BOOST_CHECK_EQUAL(error, ""); + + std::string conf; + for (Action action : conf_actions) { + const char* argstr = arg(action); + if (!argstr) break; + desc += " "; + desc += argstr + 1; + conf += argstr + 1; + } + std::istringstream conf_stream(conf); + BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error)); + BOOST_CHECK_EQUAL(error, ""); + + desc += " || "; + try { + desc += parser.GetChainName(); + } catch (const std::runtime_error& e) { + desc += "error: "; + desc += e.what(); + } + desc += "\n"; + + out_sha.Write((const unsigned char*)desc.data(), desc.size()); + if (out_file) { + BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size()); + } + }); + + if (out_file) { + if (fclose(out_file)) throw std::system_error(errno, std::generic_category(), "fclose failed"); + out_file = nullptr; + } + + unsigned char out_sha_bytes[CSHA256::OUTPUT_SIZE]; + out_sha.Finalize(out_sha_bytes); + std::string out_sha_hex = HexStr(std::begin(out_sha_bytes), std::end(out_sha_bytes)); + + // If check below fails, should manually dump the results with: + // + // CHAIN_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ChainMerge + // + // And verify diff against previous results to make sure the changes are expected. + // + // Results file is formatted like: + // + // <input> || <output> + BOOST_CHECK_EQUAL(out_sha_hex, "b284f4b4a15dd6bf8c06213a69a004b1960388e1d9917173927db52ac220927f"); } BOOST_AUTO_TEST_CASE(util_FormatMoney) diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 7c8d4ea49d..5dee034b20 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -181,6 +181,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering) UnregisterValidationInterface(&sub); + LOCK(cs_main); BOOST_CHECK_EQUAL(sub.m_expected_tip, ::ChainActive().Tip()->GetBlockHash()); } diff --git a/src/util/threadnames.cpp b/src/util/threadnames.cpp index 7b0d744aec..b221b0c975 100644 --- a/src/util/threadnames.cpp +++ b/src/util/threadnames.cpp @@ -9,6 +9,11 @@ #include <atomic> #include <thread> +#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) +#include <pthread.h> +#include <pthread_np.h> +#endif + #include <util/threadnames.h> #ifdef HAVE_SYS_PRCTL_H diff --git a/src/validation.cpp b/src/validation.cpp index b71e8daf97..dcd2350fd8 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3224,7 +3224,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc } //! Returns last CBlockIndex* that is a checkpoint -static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) +static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { const MapCheckpoints& checkpoints = data.mapCheckpoints; @@ -3248,7 +3248,7 @@ static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) * in ConnectBlock(). * Note that -reindex-chainstate skips the validation that happens here! */ -static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) +static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { assert(pindexPrev != nullptr); const int nHeight = pindexPrev->nHeight + 1; diff --git a/src/validation.h b/src/validation.h index 3cd64bc391..ad978f0e05 100644 --- a/src/validation.h +++ b/src/validation.h @@ -412,7 +412,7 @@ public: /** Replay blocks that aren't fully applied to the database. */ bool ReplayBlocks(const CChainParams& params, CCoinsView* view); -inline CBlockIndex* LookupBlockIndex(const uint256& hash) +inline CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); BlockMap::const_iterator it = mapBlockIndex.find(hash); diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h index 9257b272bc..12ba032dff 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index a255177e36..dd56ea10ab 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index fb3bb12a7a..546e3d54eb 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/db.h b/src/wallet/db.h index 762fb83a2f..b3856fbaf9 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp index 78db4df5e5..15ddd5cb97 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h index f9cbfc5f68..0c4e1cb7dd 100644 --- a/src/wallet/feebumper.h +++ b/src/wallet/feebumper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp index d9ae18ed60..59d05a771a 100644 --- a/src/wallet/fees.cpp +++ b/src/wallet/fees.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 47ef01bfd1..0b8afd5a5d 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 79c5f439df..54aa12dba8 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/load.h b/src/wallet/load.h index 9bb6f2166e..81f078fd10 100644 --- a/src/wallet/load.h +++ b/src/wallet/load.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/psbtwallet.cpp b/src/wallet/psbtwallet.cpp index 1b17b09763..ce4788dee1 100644 --- a/src/wallet/psbtwallet.cpp +++ b/src/wallet/psbtwallet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index c339e111ba..3861b5524f 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -22,6 +22,7 @@ #include <wallet/rpcwallet.h> #include <stdint.h> +#include <tuple> #include <boost/algorithm/string.hpp> #include <boost/date_time/posix_time/posix_time.hpp> @@ -157,8 +158,11 @@ UniValue importprivkey(const JSONRPCRequest& request) if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); - if (fRescan && pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode"); + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned"); } if (fRescan && !reserver.reserve()) { @@ -252,7 +256,7 @@ static void ImportScript(CWallet* const pwallet, const CScript& script, const st if (!pwallet->HaveCScript(id) && !pwallet->AddCScript(script)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet"); } - ImportAddress(pwallet, id, strLabel); + ImportAddress(pwallet, ScriptHash(id), strLabel); } else { CTxDestination destination; if (ExtractDestination(script, destination)) { @@ -314,8 +318,11 @@ UniValue importaddress(const JSONRPCRequest& request) if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); - if (fRescan && pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode"); + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); @@ -507,8 +514,11 @@ UniValue importpubkey(const JSONRPCRequest& request) if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); - if (fRescan && pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode"); + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); @@ -573,8 +583,11 @@ UniValue importwallet(const JSONRPCRequest& request) }, }.ToString()); - if (pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode"); + if (pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); @@ -661,17 +674,17 @@ UniValue importwallet(const JSONRPCRequest& request) assert(key.VerifyPubKey(pubkey)); CKeyID keyid = pubkey.GetID(); if (pwallet->HaveKey(keyid)) { - pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid)); + pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(PKHash(keyid))); continue; } - pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid)); + pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(PKHash(keyid))); if (!pwallet->AddKeyPubKey(key, pubkey)) { fGood = false; continue; } pwallet->mapKeyMetadata[keyid].nCreateTime = time; if (has_label) - pwallet->SetAddressBook(keyid, label, "receive"); + pwallet->SetAddressBook(PKHash(keyid), label, "receive"); nTimeBegin = std::min(nTimeBegin, time); progress++; } @@ -807,19 +820,16 @@ UniValue dumpwallet(const JSONRPCRequest& request) if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); - std::map<CTxDestination, int64_t> mapKeyBirth; + std::map<CKeyID, int64_t> mapKeyBirth; const std::map<CKeyID, int64_t>& mapKeyPool = pwallet->GetAllReserveKeys(); pwallet->GetKeyBirthTimes(*locked_chain, mapKeyBirth); std::set<CScriptID> scripts = pwallet->GetCScripts(); - // TODO: include scripts in GetKeyBirthTimes() output instead of separate // sort time/key pairs std::vector<std::pair<int64_t, CKeyID> > vKeyBirth; for (const auto& entry : mapKeyBirth) { - if (const CKeyID* keyID = boost::get<CKeyID>(&entry.first)) { // set and test - vKeyBirth.push_back(std::make_pair(entry.second, *keyID)); - } + vKeyBirth.push_back(std::make_pair(entry.second, entry.first)); } mapKeyBirth.clear(); std::sort(vKeyBirth.begin(), vKeyBirth.end()); @@ -870,7 +880,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) for (const CScriptID &scriptid : scripts) { CScript script; std::string create_time = "0"; - std::string address = EncodeDestination(scriptid); + std::string address = EncodeDestination(ScriptHash(scriptid)); // get birth times for scripts with metadata auto it = pwallet->m_script_metadata.find(scriptid); if (it != pwallet->m_script_metadata.end()) { @@ -1144,12 +1154,7 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID if (!data.exists("range")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the range"); } - auto range = ParseRange(data["range"]); - range_start = range.first; - range_end = range.second; - if (range_start < 0 || (range_end >> 31) != 0 || range_end - range_start >= 1000000) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid descriptor range specified"); - } + std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]); } const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 626cdccfee..96a74a338a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -550,13 +550,14 @@ static UniValue signmessage(const JSONRPCRequest& request) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); } - const CKeyID *keyID = boost::get<CKeyID>(&dest); - if (!keyID) { + const PKHash *pkhash = boost::get<PKHash>(&dest); + if (!pkhash) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); } CKey key; - if (!pwallet->GetKey(*keyID, key)) { + CKeyID keyID(*pkhash); + if (!pwallet->GetKey(keyID, key)) { throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available"); } @@ -2640,26 +2641,29 @@ static UniValue loadwallet(const JSONRPCRequest& request) static UniValue createwallet(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) { - throw std::runtime_error( - RPCHelpMan{"createwallet", - "\nCreates and loads a new wallet.\n", - { - {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."}, - {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."}, - {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."}, - }, - RPCResult{ + const RPCHelpMan help{ + "createwallet", + "\nCreates and loads a new wallet.\n", + { + {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."}, + {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."}, + {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."}, + {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."}, + }, + RPCResult{ "{\n" " \"name\" : <wallet_name>, (string) The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path.\n" " \"warning\" : <warning>, (string) Warning message if wallet was not loaded cleanly.\n" "}\n" - }, - RPCExamples{ - HelpExampleCli("createwallet", "\"testwallet\"") + }, + RPCExamples{ + HelpExampleCli("createwallet", "\"testwallet\"") + HelpExampleRpc("createwallet", "\"testwallet\"") - }, - }.ToString()); + }, + }; + + if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { + throw std::runtime_error(help.ToString()); } std::string error; std::string warning; @@ -2669,7 +2673,20 @@ static UniValue createwallet(const JSONRPCRequest& request) flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; } + bool create_blank = false; // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted if (!request.params[2].isNull() && request.params[2].get_bool()) { + create_blank = true; + flags |= WALLET_FLAG_BLANK_WALLET; + } + SecureString passphrase; + passphrase.reserve(100); + if (!request.params[3].isNull()) { + passphrase = request.params[3].get_str().c_str(); + if (passphrase.empty()) { + // Empty string is invalid + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Cannot encrypt a wallet with a blank password"); + } + // Born encrypted wallets need to be blank first so that wallet creation doesn't make any unencrypted keys flags |= WALLET_FLAG_BLANK_WALLET; } @@ -2687,6 +2704,29 @@ static UniValue createwallet(const JSONRPCRequest& request) if (!wallet) { throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed."); } + + // Encrypt the wallet if there's a passphrase + if (!passphrase.empty() && !(flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + if (!wallet->EncryptWallet(passphrase)) { + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet created but failed to encrypt."); + } + + if (!create_blank) { + // Unlock the wallet + if (!wallet->Unlock(passphrase)) { + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet was encrypted but could not be unlocked"); + } + + // Set a seed for the wallet + CPubKey master_pub_key = wallet->GenerateNewSeed(); + wallet->SetHDSeed(master_pub_key); + wallet->NewKeyPool(); + + // Relock the wallet + wallet->Lock(); + } + } + AddWallet(wallet); wallet->postInitProcess(); @@ -2897,7 +2937,7 @@ static UniValue listunspent(const JSONRPCRequest& request) } if (scriptPubKey.IsPayToScriptHash()) { - const CScriptID& hash = boost::get<CScriptID>(address); + const CScriptID& hash = CScriptID(boost::get<ScriptHash>(address)); CScript redeemScript; if (pwallet->GetCScript(hash, redeemScript)) { entry.pushKV("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())); @@ -3537,8 +3577,9 @@ public: UniValue operator()(const CNoDestination& dest) const { return UniValue(UniValue::VOBJ); } - UniValue operator()(const CKeyID& keyID) const + UniValue operator()(const PKHash& pkhash) const { + CKeyID keyID(pkhash); UniValue obj(UniValue::VOBJ); CPubKey vchPubKey; if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) { @@ -3548,8 +3589,9 @@ public: return obj; } - UniValue operator()(const CScriptID& scriptID) const + UniValue operator()(const ScriptHash& scripthash) const { + CScriptID scriptID(scripthash); UniValue obj(UniValue::VOBJ); CScript subscript; if (pwallet && pwallet->GetCScript(scriptID, subscript)) { @@ -4137,7 +4179,7 @@ static const CRPCCommand commands[] = { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} }, { "wallet", "backupwallet", &backupwallet, {"destination"} }, { "wallet", "bumpfee", &bumpfee, {"txid", "options"} }, - { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank"} }, + { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase"} }, { "wallet", "dumpprivkey", &dumpprivkey, {"address"} }, { "wallet", "dumpwallet", &dumpwallet, {"filename"} }, { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} }, diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h index 90617472cc..1c0523c90b 100644 --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index 34b9770e8b..9e7f0ed773 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp index d9b07af329..e4950af4e5 100644 --- a/src/wallet/test/db_tests.cpp +++ b/src/wallet/test/db_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h index 0f2d9fbd3d..e2b7075085 100644 --- a/src/wallet/test/init_test_fixture.h +++ b/src/wallet/test/init_test_fixture.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp index e1c53c83e2..9e5208b453 100644 --- a/src/wallet/test/init_tests.cpp +++ b/src/wallet/test/init_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp index f774cb4ad1..4753c7f313 100644 --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp index acc61c984f..2f41813234 100644 --- a/src/wallet/test/wallet_crypto_tests.cpp +++ b/src/wallet/test/wallet_crypto_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index 6526e69eea..e352c81519 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h index 1017e61700..c1dbecdf8c 100644 --- a/src/wallet/test/wallet_test_fixture.h +++ b/src/wallet/test/wallet_test_fixture.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 8857a78dee..69a78f1fc0 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -12,12 +12,12 @@ #include <consensus/validation.h> #include <interfaces/chain.h> +#include <policy/policy.h> #include <rpc/server.h> #include <test/setup_common.h> #include <validation.h> #include <wallet/coincontrol.h> #include <wallet/test/wallet_test_fixture.h> -#include <policy/policy.h> #include <boost/test/unit_test.hpp> #include <univalue.h> @@ -36,16 +36,15 @@ static void AddKey(CWallet& wallet, const CKey& key) BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) { - auto chain = interfaces::MakeChain(); - // Cap last block file size, and mine new block in a new block file. CBlockIndex* oldTip = ::ChainActive().Tip(); GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE; CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CBlockIndex* newTip = ::ChainActive().Tip(); - LockAnnotation lock(::cs_main); + auto chain = interfaces::MakeChain(); auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); // Verify ScanForWalletTransactions accommodates a null start block. { @@ -116,16 +115,15 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) { - auto chain = interfaces::MakeChain(); - // Cap last block file size, and mine new block in a new block file. CBlockIndex* oldTip = ::ChainActive().Tip(); GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE; CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CBlockIndex* newTip = ::ChainActive().Tip(); - LockAnnotation lock(::cs_main); + auto chain = interfaces::MakeChain(); auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); // Prune the older block file. PruneOneBlockFile(oldTip->GetBlockPos().nFile); @@ -177,8 +175,6 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) // than or equal to key birthday. BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) { - auto chain = interfaces::MakeChain(); - // Create two blocks with same timestamp to verify that importwallet rescan // will pick up both blocks, not just the first. const int64_t BLOCK_TIME = ::ChainActive().Tip()->GetBlockTimeMax() + 5; @@ -192,7 +188,9 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) SetMockTime(KEY_TIME); m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); + auto chain = interfaces::MakeChain(); auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); std::string backup_file = (SetDataDir("importwallet_rescan") / "wallet.backup").string(); @@ -245,10 +243,14 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup) { auto chain = interfaces::MakeChain(); + CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWalletTx wtx(&wallet, m_coinbase_txns.back()); + auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); LOCK(wallet.cs_wallet); + wtx.hashBlock = ::ChainActive().Tip()->GetBlockHash(); wtx.nIndex = 0; @@ -322,7 +324,7 @@ BOOST_AUTO_TEST_CASE(ComputeTimeSmart) BOOST_AUTO_TEST_CASE(LoadReceiveRequests) { - CTxDestination dest = CKeyID(); + CTxDestination dest = PKHash(); LOCK(m_wallet.cs_wallet); m_wallet.AddDestData(dest, "misc", "val_misc"); m_wallet.AddDestData(dest, "rr0", "val_rr0"); @@ -375,6 +377,8 @@ public: blocktx = CMutableTransaction(*wallet->mapWallet.at(tx->GetHash()).tx); } CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); + + LOCK(cs_main); LOCK(wallet->cs_wallet); auto it = wallet->mapWallet.find(tx->GetHash()); BOOST_CHECK(it != wallet->mapWallet.end()); @@ -399,7 +403,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) list = wallet->ListCoins(*m_locked_chain); } BOOST_CHECK_EQUAL(list.size(), 1U); - BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress); + BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U); // Check initial balance from one mature coinbase transaction. @@ -415,7 +419,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) list = wallet->ListCoins(*m_locked_chain); } BOOST_CHECK_EQUAL(list.size(), 1U); - BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress); + BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U); // Lock both coins. Confirm number of available coins drops to 0. @@ -444,7 +448,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) list = wallet->ListCoins(*m_locked_chain); } BOOST_CHECK_EQUAL(list.size(), 1U); - BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress); + BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index ac33d07ec0..7038eff4bb 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -306,7 +306,7 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& secret, const C // check if we need to remove from watch-only CScript script; - script = GetScriptForDestination(pubkey.GetID()); + script = GetScriptForDestination(PKHash(pubkey)); if (HaveWatchOnly(script)) { RemoveWatchOnly(script); } @@ -449,7 +449,7 @@ bool CWallet::LoadCScript(const CScript& redeemScript) * these. Do not add them to the wallet and warn. */ if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) { - std::string strAddr = EncodeDestination(CScriptID(redeemScript)); + std::string strAddr = EncodeDestination(ScriptHash(redeemScript)); WalletLogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr); return true; } @@ -3711,7 +3711,7 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const /** @} */ // end of Actions -void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CTxDestination, int64_t>& mapKeyBirth) const { +void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CKeyID, int64_t>& mapKeyBirth) const { AssertLockHeld(cs_wallet); mapKeyBirth.clear(); @@ -4209,10 +4209,13 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, if (tip_height && *tip_height != rescan_height) { - //We can't rescan beyond non-pruned blocks, stop and throw an error - //this might happen if a user uses an old wallet within a pruned node - // or if he ran -disablewallet for a longer time, then decided to re-enable - if (chain.getPruneMode()) { + // We can't rescan beyond non-pruned blocks, stop and throw an error. + // This might happen if a user uses an old wallet within a pruned node + // or if they ran -disablewallet for a longer time, then decided to re-enable + if (chain.havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will load the wallet, + // but fail the rescan with a generic error. int block_height = *tip_height; while (block_height > 0 && locked_chain->haveBlockOnDisk(block_height - 1) && rescan_height != block_height) { --block_height; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 30ea51c8a2..5e3bbe2f37 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -141,14 +141,61 @@ enum WalletFlags : uint64_t { static constexpr uint64_t g_known_wallet_flags = WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET | WALLET_FLAG_KEY_ORIGIN_METADATA; -/** A key pool entry */ +/** A key from a CWallet's keypool + * + * The wallet holds one (for pre HD-split wallets) or several keypools. These + * are sets of keys that have not yet been used to provide addresses or receive + * change. + * + * The Bitcoin Core wallet was originally a collection of unrelated private + * keys with their associated addresses. If a non-HD wallet generated a + * key/address, gave that address out and then restored a backup from before + * that key's generation, then any funds sent to that address would be + * lost definitively. + * + * The keypool was implemented to avoid this scenario (commit: 10384941). The + * wallet would generate a set of keys (100 by default). When a new public key + * was required, either to give out as an address or to use in a change output, + * it would be drawn from the keypool. The keypool would then be topped up to + * maintain 100 keys. This ensured that as long as the wallet hadn't used more + * than 100 keys since the previous backup, all funds would be safe, since a + * restored wallet would be able to scan for all owned addresses. + * + * A keypool also allowed encrypted wallets to give out addresses without + * having to be decrypted to generate a new private key. + * + * With the introduction of HD wallets (commit: f1902510), the keypool + * essentially became an address look-ahead pool. Restoring old backups can no + * longer definitively lose funds as long as the addresses used were from the + * wallet's HD seed (since all private keys can be rederived from the seed). + * However, if many addresses were used since the backup, then the wallet may + * not know how far ahead in the HD chain to look for its addresses. The + * keypool is used to implement a 'gap limit'. The keypool maintains a set of + * keys (by default 1000) ahead of the last used key and scans for the + * addresses of those keys. This avoids the risk of not seeing transactions + * involving the wallet's addresses, or of re-using the same address. + * + * The HD-split wallet feature added a second keypool (commit: 02592f4c). There + * is an external keypool (for addresses to hand out) and an internal keypool + * (for change addresses). + * + * Keypool keys are stored in the wallet/keystore's keymap. The keypool data is + * stored as sets of indexes in the wallet (setInternalKeyPool, + * setExternalKeyPool and set_pre_split_keypool), and a map from the key to the + * index (m_pool_key_to_index). The CKeyPool object is used to + * serialize/deserialize the pool data to/from the database. + */ class CKeyPool { public: + //! The time at which the key was generated. Set in AddKeypoolPubKeyWithDB int64_t nTime; + //! The public key CPubKey vchPubKey; - bool fInternal; // for change outputs - bool m_pre_split; // For keys generated before keypool split upgrade + //! Whether this keypool entry is in the internal keypool (for change outputs) + bool fInternal; + //! Whether this key was generated for a keypool before the wallet was upgraded to HD-split + bool m_pre_split; CKeyPool(); CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn); @@ -187,6 +234,57 @@ public: } }; +/** A wrapper to reserve a key from a wallet keypool + * + * CReserveKey is used to reserve a key from the keypool. It is passed around + * during the CreateTransaction/CommitTransaction procedure. + * + * Instantiating a CReserveKey does not reserve a keypool key. To do so, + * GetReservedKey() needs to be called on the object. Once a key has been + * reserved, call KeepKey() on the CReserveKey object to make sure it is not + * returned to the keypool. Call ReturnKey() to return the key to the keypool + * so it can be re-used (for example, if the key was used in a new transaction + * and that transaction was not completed and needed to be aborted). + * + * If a key is reserved and KeepKey() is not called, then the key will be + * returned to the keypool when the CReserveObject goes out of scope. + */ +class CReserveKey +{ +protected: + //! The wallet to reserve the keypool key from + CWallet* pwallet; + //! The index of the key in the keypool + int64_t nIndex{-1}; + //! The public key + CPubKey vchPubKey; + //! Whether this is from the internal (change output) keypool + bool fInternal{false}; + +public: + //! Construct a CReserveKey object. This does NOT reserve a key from the keypool yet + explicit CReserveKey(CWallet* pwalletIn) + { + pwallet = pwalletIn; + } + + CReserveKey(const CReserveKey&) = delete; + CReserveKey& operator=(const CReserveKey&) = delete; + + //! Destructor. If a key has been reserved and not KeepKey'ed, it will be returned to the keypool + ~CReserveKey() + { + ReturnKey(); + } + + //! Reserve a key from the keypool + bool GetReservedKey(CPubKey &pubkey, bool internal = false); + //! Return a key to the keypool + void ReturnKey(); + //! Keep the key. Do not return it to the keypool when this object goes out of scope + void KeepKey(); +}; + /** Address book data */ class CAddressBookData { @@ -875,7 +973,7 @@ public: bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); - void GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CTxDestination, int64_t> &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + void GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CKeyID, int64_t> &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); unsigned int ComputeTimeSmart(const CWalletTx& wtx) const; /** @@ -1201,34 +1299,6 @@ public: */ void MaybeResendWalletTxs(); -/** A key allocated from the key pool. */ -class CReserveKey -{ -protected: - CWallet* pwallet; - int64_t nIndex{-1}; - CPubKey vchPubKey; - bool fInternal{false}; - -public: - explicit CReserveKey(CWallet* pwalletIn) - { - pwallet = pwalletIn; - } - - CReserveKey(const CReserveKey&) = delete; - CReserveKey& operator=(const CReserveKey&) = delete; - - ~CReserveKey() - { - ReturnKey(); - } - - void ReturnKey(); - bool GetReservedKey(CPubKey &pubkey, bool internal = false); - void KeepKey(); -}; - /** RAII object to check and reserve a wallet rescan */ class WalletRescanReserver { diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 3122cd6fa4..ece97e2a75 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index 1ff1e8b840..5c1b086703 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h index 5b06fd1792..da848a747b 100644 --- a/src/wallet/wallettool.h +++ b/src/wallet/wallettool.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index b227a15556..04c2407a89 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/test/functional/data/rpc_getblockstats.json b/test/functional/data/rpc_getblockstats.json index b8cabe1e5e..16dbc5fe60 100644 --- a/test/functional/data/rpc_getblockstats.json +++ b/test/functional/data/rpc_getblockstats.json @@ -1,109 +1,109 @@ { "blocks": [ "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000", - "0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f1cd16b94f20a8a3dda91027c888025f2ec1a07ddcb2786bdff5916e66c00406f194ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002014341131c18d3b3aa30056a0f7a97c9ac852d3fd0ec9c76f7a25e83c01e7f821bf83574fb606f25c59200c844443201faf923ef5284fd4401f3104a323c601491a4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03520101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002078616da95299bd42cd8f813c8043816ec5741de466be3162e16bfff471808461f671e694afaf534d37df484f1990fc19a65fc26964b38141b7f8ecf61b8a50241a4ae75affff7f200500000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03530101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020a08613f37d305835a3a1553e77a479eba0f34c06c52e429ece54f5973cd77a7086a1efcaf75f1cd5be2c9deb6a7850225757a2cfc3031a91cc1330b3af4acc891b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03540101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000203b304fa1ce0505c2366982939ac148d9124c5ac747cc9aea133cea9916484966305de0e8d049f2be65c68d64d2c45746def5a9b4fcb8e298692b53b83b4690241b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03550101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020fbdf49978ec4f0b23704b6772a614336872587e29c463f375836ffd775248837fed9f3fdfc33f076c6663ae78070fad7263c1e24161f3ee1a4857b8931815e2c1b4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03560101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020c37548b9ca256b9ff17187d4d4309cf3143845b0a5811d3ca5427b2fddf000731a10985dfd473561c070c3527c3fe3941834cf51b3dfbacb501b44c69c9745ce1b4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03570101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020383dd3766c0675440f26370ad62d687e335ea3a650dec9b02fe544107cc1823a13b98696d41562945457d655f4c6921f736068f7a72afd1ad6b335f2857d16631c4ae75affff7f200400000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03580101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000207476dd96d81f53e63934ce28c9e89022e0f24d040ec3c838443e925fc3a2f230a94d0cbcefb4a151191dd7664153944d9eee3b7b46d4ba997f397ed2b72c3afe1c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03590101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000209e425c73eea16cce98c0d47d6070aca29f0524eab4b97af84c386aa5322dd43055002f097e929bc6ad88ce869968e1b049aab7f6e45a5b869cf4349afd5d43e01c4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000202090e16a514fad40386413a100bbaa4fc14086a8d3501ac64c91fdef922e834a369e409444d0ec496eb0dd9a47f1fe81a7ab974bab28c50a912b994acf13b5f91c4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020777b767e42624c52775b331f19e81ba03be2f51a0608166cd5388c1a47d5e776473570bb9bba553a7db4a9a3083533027c54af1fea3ef6ef67757ef2255d64631c4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002076bb2bf3251a51ec367a42f8584043171a5d53157394cd776ebd017e2982127653d953aca3e2217f56533c043c07b9a926a30672ebce2562f1d06a6dc5044e7b1c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020e6d7f02292655b73fc1f1958b09633ba07265d71d2a2784060b354cbbf1900202e9c9b02b63170002a94a0c9d8d787e2faa4c074a1ebdeb2855555347321dd101d4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020d61f077b0ed326e17f0a3d5af3fa876b72b434a252c9c3248d20130ed744287fcb10da470222dd29c7a07e2da7eb25d6499ed3919676df89cc630bd1b23fbb411d4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000205efa9741cf51533ed6e07a97c71768372f53ca9c6df83894d64fe94c718eee23a207441e79ecdcf99ef3326385f5f675e2dea84c85ab8973219c63f92847ed5b1d4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03600101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020368386b0a0f46b2a2c4648eb9cb5dd1380c4f22e437e0bd49420670993361e5b9026632c2ddbb4b31b3c3118c51e43ea4d78e05c0aca0956278ead26a263d1521d4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401110101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020dd0a1594bbff6345a3e34f326e5ee605c855f5e0a5c363fc39615a8b1539b736200b51297dbee4aadf9b536cd2afe7617651e0a1d0f0610f436518a2a4dc54621d4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401120101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020f302a1092709dc27a32d7229d391b90824a75828692c4bb2ca8f0ca5c88b3613c2e18797ffe8b367336338f90b2cf8c3f66277eb1e1ddbe18c052977294f10691d4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401130101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000203dcc77aac703a8cd0e799384b74383c1d5f236426f77d516694607fc88fe85581276a20ceb98d02e6355c9dba4312e2fdc9832f4302cc307e1263f2df0aadd6a1e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401140101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020dfe109704a0b2801aee4232c31fb744145a7c80dd91a7727e16d4057719d5c3730f8296243521d82d96ed75c5af800a722fc9dde2e02af95c8c9822190ba07b21e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401150101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000201ef9ef2699bc36fd646bb9ba8629644bc98396122f6753710caf0315d7539f751382d3d85f17eb8b42cf17e54baa327886dcf6fa63207e097df8f9b84cc5422f1e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401160101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020834c91f23cd91b727be08b892f1c1a2f33c1e66d66f35607925fa1be4bca2c25b4145a73b1c71b945f5bb9ede3d8d95c9a3b12a0a81b7b14f440ec5146dd4ec71e4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401170101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000205743202bf1e543a9be2a59b62be6a5a494511fab96968007b8d7199ea60a524697227ba473ceaf48d4f48ee17f8ee6cd2f1f5ddff03a641642ece240e7872f8f1e4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401180101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000207469f5c1841bf57275d82db23e5a8f0e8512af1eb10119c238519cdd6cdced34fd96dc659a874b3f5d30fbe6ea421a6b9791dfce8450f8851e4b90d80f0f794e1e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401190101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020b6338f55fcc473b744d53d675b4a83dcd80ddec9d02ad3323cf1ff50ac0412239d986ec20885d772fdc67803273aaec43871426ac93d3815846a8cd13dea5af11f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020a19d9edf2d22415cf226b4e1416c8a3097e0af222efac2bfeab15fa1f07b3f24c18580c4004de6d6244a30ce431c4be3ca44731509fc6b11710c792efed5e9191f4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000208f9f29a27424ec01ce77485617088506ca8faeef69300f0a474ad63ca5d32972d6049609fa3588d6ffab4d9d89a90636ac94c0ca1995f7768163abeb25dbf2bc1f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020fbd87d530a9ec3835ab579337fd16e512cec6c4779ab4d84e7256b3333dece28de1065c8c3d3d166e057139ac59af6f4f2c0d241b6269bbea6f61c5eff3dba431f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020dc6ef4f436baab2d6880f242a2588313a2739ac694e30319344045ee318c9524d0ec7fbcaca30ce85392cb03b64015ece769afb50fd07db05c15ec49abf7d71c1f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020386bf4cbb3708ae6345b9f2459bdd99d07422b05f9b005d2d4d1d3bf87d47359ebb22b3a15c8e94ddd8129527873b9bebfa10c54d11196961376efbcaad3c4681f4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020600e892f12ad82a23ce12684d3ffa0887eab5e3e97804fa651050b23366cc55ef2468e65c3d3cf49650657eb47d0b0b7949c71dcc0922eb824523157b7eff478204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401200101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002068e4aec52a3f4e44279e3a65cd476237bdfcc2328390bb31b8a903f89ddfa70e8d669f61b469acb31b1d4ecdc238e6616a83a30644a5d06fc2ca1aad6449d09b204ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401210101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020cf2428ae9a5014b910275807f54a8bbbeec47d462f9d284ada60329b4955ff10cf83c44ddde39a709aef54fb302c7f1cb36db8fe7c3befce20dcc3729767518c204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401220101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000205801eef8cca082407ce4798648c4d3ba0fc4dd2d4459eccfe5300c7960760d16cb3dd78a2f22fb88717a175e45c53d34f970b94ef9f7cd1b6c279294d427d163204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401230101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002088320983a4bcb95b9f342994c6943c227f3102d3b16282f048ceb8e15748662a52d1207591a0a364bc9245a76e36530f147ec4d1b4e1917676b4071f542c3b19204ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401240101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020acd85b6d8087d3b6bd2a208a2e39b75da459c0e0eb14088075a23a2e043e8a4ed5a1754491f8180d293b42e6c04ec3f82e29c1f2600dc8607616f69a4a464e6e204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401250101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000204873bcb379f78da4497ce1e22f6bfb63537b89c8c522257a7b7bef74e515ed1b6b235faab048fa73a76c68fdbdde6a4ee7ebe0a3b7b23df24ce75dbd2cf49c33214ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401260101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020a87f6d13bae8e2e07996c3316e8e0da6aec7d1aee6b80aa5883018e4d136db3e9a498ff7d322ad93863e0a5318af7e7d0ed683fd2e4ecf523f2b7369106dbe4a214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401270101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020d9b0618450a51c08f43187c479e20d351f0466464409bb3071dc0af7c51d65498a198cef23dddd2c4b93d9d3288ae922584e221a9ef1ded3dba5a2ad494d9237214ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401280101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020167dff31847b8dcad472bb6bb7d0af53b245f0f1d4c9f83d4ce14a0f05d42d7f0f2638ffc0e6896230f28df1865ef133dccb1f027545c6a1177dffd1fecf8a01214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401290101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000208236c04424573692504e777e179b9247e54622b118239311413812f13cefbf6e39a639143f599dc76208b2014de12a364716df2918af9186453e3676dca743d7214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020fab7b55aeb59f63315dbc10784c55e55635a7600cc4f3b94a00003007e7fc90b4af016248e9908882f8a7f0bd8743c8da82da119446e8b02e4d3b8d1d938a3aa214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020794b4160d8fd4ebe7611d0fc9d3e04f3038a485669f74075aa153852ed181121c577f4c0b7151f6d78a16e3c21ab291b53ced8a5c4f05a22caf24a25ed029d56224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000204a8acdb549d2ed922360ae0e81de6c913c3fd84b0de51abacbf97162a99f7c26c656b252d3259c33ffc7e5d403843accc6ace9b7e60e911e2347a6a0b0abd122224ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020dee6d00c7058b3422e4273c98c16181e04ea93116496a8442de546c2ee9fd86b550013f39e004b3829dc3717b17fcfedc87de9450315fcca540963119cb264c1224ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000202ebca471f5fb2226a790233c3d0bc323f73d935872f3e15b66bd5fdcb822101d7b68788ed61d3fb8cb746f627e09db2fc09d8a07672747709d92ae400e053e78224ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020ee500470fc1c71a82f2cbb9f8d5723bcdf57b8051fc458a8dbd8d0dbf60d0e40d1a0be0e50f3312d4830e3900186e5a6760d44006c164b4f0758218ef2b2de8e224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401300101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000205057e8d8a7451d79325851dc8e0f4dfdb1dfaaab637509d9e61f0e064af5ee5c185221c53c0cf43261b3c238c0e8117da5d6ac60085615f7a3d8027726cb2143224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401310101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000200907f01d9c5c872296796ca77feb62eb414cc080e13a93e59e181528bc19c336eaabacb1ebcbd20b26f6bacdc712ffe17d4c8131e7f99b9cac309c0683737c04234ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401320101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000209bd6a4ec962d9e6199c0a2f39481a7ecc322fedbd2320cbe7dc984c6ab958421fe7a5c7f2513a3c3de9ddf7b211f5bfe85675b31183c4bb98ae79ab28cd055ac234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401330101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000202b8a6381b7c9476fd77be379a929863db6b7edd9858d6eca0f68a430dc87cc3a9c6c8b34bfadfdacbe95cb1d4ae5ce4e4f4ccf0300171d7a91cdc97f620c7b37234ae75affff7f200400000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401340101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000203d3e9a0b4decf12b4402a2178b60599311c8a9c7d50ece365a61ca29530da7056754ddf7d77a11cc8ce680a74fae01d851bda024fc9c51712c55b4a190caef24234ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401350101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002067fa05082d4f7a29a3985f30798940cd854c76a2b20e9560b2047f7753193f71ac61b8df17a8a63f099c8f55869301fc2a0aa37355a4a2f89078135ee72a1362234ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401360101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020249684272865fec3ad62ecb73dfd930500e32e475306c9e5d4b6d545e3687b0a48deaeebfafa213f0a560994b3f4000d5e2b93951d7e5be40073503877292dc7234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401370101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000204671db1df91098669bb03c3e8504d432da99853601366c7de7585bb8f23a6e1e2996a16c11a0f9ae87d937f566c8bbd919040528c1bf8dae4e22a8f0ac5f935a244ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401380101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000203046500cabfee552ed114c505279cd75c28faa811adcb5010c53c14df5de3216d265321a4168c70fff1c85fd83bd976cc03c8c1fb6567398cc24053e343ad137244ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401390101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020591533cf8dd1fa1872c7e6d62ef714b28886f38f7921ee614e13b748eaf923282a96287277f18b1113a9c3ac384fd7b43bccd0e45114908ca5396a76cbd736fd244ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000205286b5747d0244a55e1dce435fdbb9f300d7138fff3b16767bc09196eb00256c6795e3f372a2d5d137244a4fd72fd799e8de913f868f22269eaa628d7d2970a1244ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000209649b55f6a5ff0d5db73aeb7089fcce605fb9dd23971e577b73747ffab586f4edf84581240223e2d8912a6eca049e06aa46ddbf271af08e9ac9605505311418b244ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020fe7ff82c11ad3a3db3dc11a03a67e0b86b727d232c80f37209b028bc2689296c0da76fb756e1c9833f38b198cfe843ab820fbc0c38e30f8f858f6ffdbd64e834244ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020c02e6109b6aaf6643cac109ad5b5be7f7ec47c7993335bdceea6e0e490ae9067eb1fcee49ecc40a61477f934e3b9821f2cc7ada429fcca2cd645866742854c40254ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020956c46fce0adfc8a30d91c7b7f328f17c2a90771083884c4fdb7f24640598f6fa69c4e5971bd3b6cdc7e3ee98e03a969b28c3220fdc685cc2eb77293763ca4ba254ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000203eec7d0ea9c539f47e684eec9dba900e27c805b8200f237924c7df8065957726c83caf659fa341bf45f733a92cf76daf2cfb6bccbf969a2753f5f7d9cda4bd1e254ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401400101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000203c022b42283bf651ee4d536fe71b7e5382e9783d4a85f8bc159f00b97f16d82d312ac4f89f1b1496de576811f2ff17de44b512db0beddae59e030e2ce3eba4df254ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401410101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000205da9709dea4bea4f3229d0eed439a4820a0e817f9fbbcd8bb355cd8052702973403358080a2881b823a740f58b6b0c922b42189e06326478cc33390f2c704743254ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401420101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020447c49f664916cc13a839e27f7cbe0b09dea990dec71dd479b537ecfb771c7159ae6241727c2645ce00817909ba97d43447fe2e146bce55b7dccd5bcd27d2e3d254ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401430101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020ae3b214b1495953eea3b99af7ade4b8d22d615d598dd6c790c6576d6453ef35d37fbd3446f8431f00052f278c3e0359beba54a2f5064bc6be4990478fcf4e086264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401440101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000204cc68f9f571f59145e1f7505550d56da13a797fbc7e5a178dd7f6f9241d91f007f2400f7aa1b32b30bf869e4da86f75eaf2baae182efc45c42c6245f06aba675264ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401450101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002096d55714a83c3d030cc72141eac3577b8a394b8366b2c93354fcecdafeab025022f5e26de7e4eba3f8e4a09f243b55ea6f08bfd013e2051cf1d5df20dcb3331b264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401460101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000202ccf49665bd46e4915dcc9221f5fc72124bb73fb11fed8869dc5862a47950c0d654693a1d86098212d68fa9a27f9df0faafea4aecebd8b203f2ab8f3f0b86196264ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401470101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000205d0be5aea546eab7734cbee757ea5f4983ab3a3f202323c1c88590bdbc8b561974cb0de6549bfdec92322ad53d8a4192433edab0e33a10e7561d2e27c7759f8a264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401480101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020fc3d70d4f690d7d7da90b1c832a51c2a92940cdd9fccda6a909c7256ad567160550e1089b48fe75f0f1e6f712cc2a1d4aad384a4ceacf1c71576420fe8e7de46264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401490101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020995ab1f2293e3aa1e7bef418919bdce60032e89e60223b8c12b17488c50af83b3a360b4f89551aa0ced646a6210b0c3d3f7d0464faa248b9d252c89615babc9f274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020e02dd5e1201ebe7ef453e77df3021cffde1b5447b9eced017963489e005ac247e1f2b80e91180cd9744c3e126eb8a0fb34ced45587da6b0fa9fd1c6946f049bf274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002081b265800d61feb37525c58aacc7e6d32cfc6b6579784f9952dca51c3addeb37da900ae4ec1b2075056001a361c0fc8f9ac1ca018bde2a2bd8fc587424dfe18f274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000207daba0dc6fccc067a19dec46770d1443fc715b50540242ff26073a6748bcd9583804c315b783d4f9aac4dc8f109fa60bcbf1c3cf98a7e1e593fcb969e88aafae274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000204a35ab2d9c4656c4992d2445ee566e4f5cd0468358292c94839de2b270ba0628de9148db03da59ca2eb727a4f7a03f2b9ee1e4045f37bdaa4b75a89de56b63ee274ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020215ed7b31d118a45a06407133e41f3f9d25c913ff98f3e798144f981d9145305266efc9274f7c836aa0f8b831732aec2c1d85c5bb9176af4c889a707cca380fc274ae75affff7f200400000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020425321a1f12ed4613b63b3cc5b4c7674242c3de67ea86984f2d9bb2766f6220a5c460ce6840832b7ef05f206c5d255bc2d8ea83753a7f5ef5c0bf3dbcbc7c74a284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401500101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000204e088cfd312091bf589f0fc24131dba20ed83f716530a7b033356e9ec803be23a73c4af5b64fc631d20aa1f646c7c61c4cc5d4be6e2fa29570030d72219726a0284ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401510101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000204287a2bf40300e39b45d6667d6e17abba37d98c41efc7023fd21b643fb2f6b76d915d10e1f9e224d3bfdf5203da57173f0b8d8eedc92ed9ff23372927e86073b284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401520101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002083137929ca902f409a1f35385b4d31e0f5163d488d71b00ade724d7831986a280a187c13fe0db45aed5fa4f5089d544a617da9f4f80fe6ce1d0711b228f3a6bd284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401530101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020b38c074d78cbcc8bbbf20c48e30639c2dcf444488efee59f5aa01c48322a30418009c11df7e14de6a6d0d72cc22f20ff5fdba3a7dbe409409ff92b1302340fb8284ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401540101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020a6865148220c7f5ac3259f57fa381676d6be5fdab56eed8e060808fcce4118492476fe6d5ecc681e7a18c20a04239143de1c2cddefbb08f15153b8e9b0c22f62284ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401550101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020ae146263f4087106b8c51ffb5cdddb03a4e593ea1a22a8f6580eaa374185126db2187dbe694a1b17b7c5664115307965407274c25bf6ae02049817685f923256294ae75affff7f200600000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401560101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020718abe22705f33134812b56d04c129d453da890e27caf6e77d2bfb3f9be460083634f35fc8ea4a29b0f30d6c6b4926455a31de62d2f763bc95c8cd1a7a425599294ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401570101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002084537c50520f4e6b0173926320c3193f6b4259c9a724fe202337d3d5cf7da70b1104e1d6f25c411165a856a0bfdd5ddbe168238425c05271962aa6e5ebb676fb294ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401580101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000204bae65b948c9790468cfc8fbf78a81e7aec5407dbab18c18ef1ab37a13f0c257792cd1246dac5ce265a8439e539db1aebe4776535d422315bac8e57a51605aa6294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401590101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000201e68985b2a15920524c3c2da77354c0ccfb202c3ab4005128eb2743aa33f0a5b0527a624a6d1f808c896d8cd1552c251a4ae5310e6c62493977b0965d17f580d294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020ab1d90854505caa1ee748c1987f4cb6674844b84d17224bc3983fdd6e44a930b2edf3e5a90be7a9080ad15014ce796b38b6c19ddd3754443243fc277bcd2368a294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002062242f316efa083c17e2173d9f9831afc1465f3fe84431d8e52fec71ae358b243e29246e0db770708987f2cff380920321636926d9c66c2c808d2d5f0ed27d672a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020258c1a9b0ca17819d8d7fea5178e9c72c2e7c6769696f70098e0d5d2a9dc0e5cf039f5f686d727c6158ef5405ee8794ec2f89c641093a1dff0f5240263a441bc2a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020434ce26cddae99571a1d663419d715f88e6ff0e413c45f21c44b1991d041fd2745534db221054e2233052aaffe7d7232a91b3f0918c14eac74b2f704b37bfb8e2a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020ec94475f112ea37dddd84f066e61446b431d28d2d9b6fbb336d16295e7eece52f1dc01abb3b27e71d8a25c3ed2d6fbbc5900bf954738ed63d57689ba5e68f6532a4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000206188cca18a2be3b7f0b500a724f1b73312873488f04c5082abd81ca0b2250a75ec0efb2fa994ad23e1f39416e69976e66fc4ef9f101bd4f60fcee1f8c45a2b802a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401600101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000202384b91bd0bfb1385ef42bda9b2fa43930aa8889214bb14f63c61a74f380dc7f9d547f2925ad39b9161fa55b9cd258463fd058234778a7c7b3061113d64179812a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401610101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000204c266a3008c3bd95ae4bc8228bf878595cabf76cc2ef3fed32936777fe37833a1a13ea016868b2352a8d6d1eb35d0aee784cef06ed50655b8d84c089324351df2b4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401620101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "00000020ab2c78d1249de8482cf26bfb1616ac04f7b8404eafcae3e0654f398943fd41571b4d7549862be0b06ed1408ddc3e7c01b07af24c203a18fe9744e214b14d2d652b4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401630101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "0000002031aa0fc5e0242a9c9d91024b6b7e67544da72c4773537f881ee5caacd45a3c38c650ff5fa0ffd080b3e5f9752527b718e8c6b731467028e14b0b009d4e7406ee2b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401640101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000200418c57609fc6ea3f24f569dc3afe163538a6aab940fe8c3d73c72cd781221380482c6f8ef2c19429da2f7a842bb811496aa86247c55f7ecb3337718b694d9472b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401650101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", - "000000204f36abaf10d6a8b3113103f3413475db0640c89a39f02a718e8bd2190fe87f1d6ffaf2b9fdbed67ebae4b36c97f9582814c99c90d0b5123f14da4861bf3e4f742b4ae75affff7f200100000002020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401660101ffffffff02b000062a01000000232102f6869601b2b9980b07fc047e309c1fc1433e08c5bf0498115c5c0e117ef59bfdac0000000000000000266a24aa21a9ed5896cd6a40cd126b09e317cbd179f39e2bcef2f9d423751d980258396416e671012000000000000000000000000000000000000000000000000000000000000000000000000002000000011cd16b94f20a8a3dda91027c888025f2ec1a07ddcb2786bdff5916e66c00406f0000000048473044022046d00465c4508cfd02fcb878b19d120e28be28e40658b1f15458828891ed1541022036aac054f36a42666dfb7b42a20506315a0b72232ce7704406e23c7a9515178701feffffff0200286bee0000000017a91481ddd4a9708ba8088cdcfeab9583ede8d83a298c8750bb9a3b0000000017a91484e16967722289584257803688aae36cd64480688765000000", - "00000020cc7c39992f2dae21e0ebd958f6ba77a6d0bcc568e044b9b61ca4d77536a4214e7b4ade79dd733ea72d97993aaac27f2263b91b1500467350ff35ea40c2850d392b4ae75affff7f200100000004020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401670101ffffffff0230d0062a01000000232102f58ba54b2d51c4e2a6096f9d266261b45f1026a86ba88c29ed8070dfe3f5ec6bac0000000000000000266a24aa21a9edb824d92cb231c2366f0726aedf8bfc2705239a40ae6b10a106534e8b5395a09d01200000000000000000000000000000000000000000000000000000000000000000000000000200000000010196bac2a0f6212b8e5710f8c7214dd32c393d38d20b7703cf0b7b25276bb6ab8001000000171600144f8a6c8d4c6c309b1e2b725b7496859e172ea367feffffff02781ef5050000000017a9149f00bafb542049fe32d532b0ea7494ebb7ae41398750daa4350000000017a9147794e6dc43de332ca7a095e582478c331446686d8702483045022100bd85ed3954f1151c2fde32c4021a32c96d7defa4a57c14b1a056be9b361a8e49022054947bf6fdb535c46cbee62efc1262cc0389a6eaa19afbcfa98fb1fb30c3ef230121031b2371df07fb88dddf590b246dc74defc265fdbfe258e4b168250859b806f5ce660000000200000001bf83574fb606f25c59200c844443201faf923ef5284fd4401f3104a323c601490000000049483045022100d1c4b09b488f6375ee4540a531a13b5549e88e2459bd88c84867e293c54862740220222e8af70c8d8b1139c2a7b616d9132bde94244edca7eee3c7a783b12839dadc01feffffff0250196bee0000000017a91490e5e33cfedf18d5cf911d6f853770c62e1f5d028700ca9a3b0000000017a91422311ee58518edf3a2289012461dc66bc8739d2687660000000200000000010196bac2a0f6212b8e5710f8c7214dd32c393d38d20b7703cf0b7b25276bb6ab800000000017160014b81faaafa52f7723f539f8d595147b1a112b38ecfeffffff0208bd9a3b0000000017a9146b2e611708a94d9c674dd08c7c4c1fbb97bcdba987005ed0b20000000017a914933a20f07bab1d8f341f391819466a271f0cfd648702483045022100dfa8b0052c7825e6abcea05d10fc82550a8d6538681ffc8188d48ba789e4d9b40220697371cdf527a6ecd1887f87da3c87dca3419e4a1aa2683e5c4e035199084d100121021cc37c2ec090f30ea0b49508ae8a7d65d9759903932666da56671c1faa445d5d53000000" + "0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f28394022bf44bff30d7399cb5a16e3b94fed67dc174c2e1d77df91bad5a51cb3194ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020e959d05cac787d7f82d1348326a4ca25ead09589befcd4b4513163e5acb5af6612d2f07672102dc6f099c4be308f598e4c4da1a7e0cb462ae14f0444525a13321a4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03520101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000204401ebd07d42f8f18e80ede81795f728a9eb2a63073274ad92ccb9eda593ff3c5f17ca91704a014c6f68ca623ace6c542950f2e1d2d02ece08fbd440e33af53a1a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03530101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020eab1809c3e750647f588c027df5c9d5735bb8cb2a1a5f182d7b35524b0b8595f9d59f165de689fd9a4b6954b4394d40d7899eef078e6ddb9f7eb036b7b15af2b1b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03540101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020bbe445e86bf69865a0c816690c0e470338bf9d692d388f8186613830afe2f54c07ae38ccc6fd49e7098d6e3149e459a234f30970c6c9a9894df992e3caf97ce31b4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03550101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020f5b84b4e3b7e84720a83dae76aad6657c06ec6bbf85d9158c575de09c34631035b263b763b955c4c6d1a97b23e6b4bc5e6ee96d75910845557aaca233fe777fe1b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03560101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002028d52759ccb342b81f2e8d574d8cf116178949f8a595d577098bae70e6969326119c83444b75d63bbe98d8b3a937f0de3a459bda5fdc0fd66c7acd752d19496d1b4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03570101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020f461e9c8981911f5180e9a8e28be1d34146460ae4e7583935949f43f6252bb3cb287270caf2d4e735caf0d9888f998b8d7c79443e97933976930919e6dbc0b471c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03580101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020d3328d99edb99583b478969aea57e378c2840bfc1df0341963fde16f75636e34a6c85df88c2800c54565eb2e6579b729def99fa9b8ca347ec649b8d4f8db78de1c4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03590101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000206b88980f5b713605233c1c8806639717f753c4aad93617d5e37872a43188af6c8dabd724a42288139a21186c855f23c4fe1d12337ec7b97f87c48389983239651c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002030fd29b0e0e54a5eec463f93dac2fd9d73f383b7467d146a882bee4700f79832a343b1b1867b07ba30134ae555db5816ccd971232b78a9d596e2711d02251c521c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000201845eacaca9b23798f32c22414015655035d4918be70e26f56b56e730e195e220bf32e9a8af59ce9264884b0690bb26709616ccf4bfb85812faf87144b2fb8131c4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020353ff17bd0d66a6ee1e784bfbb2497691f49e27c3822aced5125fda6ff09892fe72239d73e75b82916e8eef04a4963e6b500de80a7fdcd89952e23c6d249c5931c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020c6c359d1b891b0a6afa7e0fb685b9c21afe41c8dddd80cd6331ecd856650af3803953a9bf6fc675eb2856718bac5362a12168e7b1baa7dc6b46a4eacd2e8baf61d4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020291a8a183e7ebb538030bc791b0f995a2ac0a766add84d83d3fa9f6fad50075a0857e76b64648e82fd4341931116efccaf147f0bc6e8c107cee68f400530c17d1d4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002081f804c3afb976efbaf9f62d50ca43402fd5a09571cfd93ddaf77d78952ebb3e3db790f598f68da5e0514b03902de787ff0d2457c05a59bfb22547d8ee6f7ed91d4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03600101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000204d559298cc1db4c70f422519822a850603ec250f4ab705f51423d67bb2d4a03abfdfd932c91a77b0065183cf1a575e73b9d1322804f869cc640747e7fa36c0531d4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401110101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020b49a26625c5d5210a3dbd1aeba62718b828a29dab035b6e028073c3679053c02ee7b702c74ece9d04af3aca5f745aad5d4142d6a15ae12d16157c1449b62b1b31d4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401120101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020655a431b076a153aa7d9d3731b42b4213995f92299a56e6270860be4005d584d33b5d4b94367acd8ef20e10678a75de3c02e143a3f9bb0b0f0c31ed0396454c31d4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401130101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020a96f9ad3e058c097d63488627158e074f759a73ae3292b8d8e3e979edcb4e33f0ccd7e3208e9cf08375f36a34f3d71da039e6a33cb8621a67bb484cedc5fb4f31e4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401140101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000202ec3fddee36cdcfa564d29eafe073ba79120ecdf8740f62600293b0aad6039419047bdc522883061665549cacc029b05713ad4ae24281eeaf0a041cec3c7d0d31e4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401150101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020d2985cee6e78b525c61ad111b0e9a6ad8c222ca793eff2121c23cf06462fd930bfe97d3f071f45d95467db4f5d31d8b7966c26789be3d5c1a5d53c903230abe61e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401160101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020e799bf0166a1e3e7b94d6709fa0edd5feeadac19ddb271ce8e8a6144fd52c23b1699dad3820cb2ba528c13e37550cd32a900ca14f307db9b735daddb523b1d511e4ae75affff7f200a00000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401170101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020a6e38cccd5f39851e6f1aaab690b3591ce59ed225bc4815b66ed59f9e604da4beadf823c049567a4628d7b06090ac7f51f1a854c46817a8b6fb8f069a098f8941e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401180101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002067dc38dccecab584fccbd21e1fdcaa8ce69155053eaffe082d51fedff22c26299e57f12478cab2077ac63eecad4a342082c9976addd08ea58896ab334ddf5e6d1e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401190101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000200b71cba7f1d43034d1584c309e04bff61a7814896b3fd170f69d8757a81b114b4769be83a7993e5214c7cbb5053a142840cc180e23366cc1d52cd2ace2347a1b1f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002044d38910c5362c279ee6e183c56bb2379f0d053bceea9f2c00f99adaf1a70067de8615ddd58387b2847d215fde3633242c278ef9b18ab9c70963c9060b4a3f101f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020b063fc1b09b6f9cd8207b0f9ca9f1549ce2b1de07b7f937275d96461ecacb26a3abf0a5d24c68c0b3df1a58b6128039eca6452810a374a306ac0cb96bd462df61f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002023334826cbee5a6679259a50f8e112332db9663c97a1d08d54e64319dabac73331dbae7789d23e1da14d1ee39a9dea43581ddd9c09a199253ec0bd6c819514911f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020911e28670d744a0cb23495711db6ac20576273eec7ee442b0377ea2d7564402fcc7db46bd4aa8fdf1209e649b3866f5cb79fe3f2cfaf8aadd39a3d43eb084ce21f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002038d6d41fddd3c9278884c9141096360c538d2491ffb078be006222a88a10c854366b75e0a133e1d3f4db26e1b0e9b9820db50dbfb11988e8bb8739420ce1799c1f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000204e501ddc49c462c4ca52283614e99e6379b9c6570c947a822b832804e39aee00b037b85318c2f997bd9edda927e85dc2c83f8aa1952dc67556565d141a246186204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401200101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002040cb0b50f15716374c2dc627d1fa6e3eaae67b1b4f1c90a30914e3c89a74de794a98fd86cc22c32f447477016e297c61a4e48135e658e5b5be84638f3a836ee3204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401210101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020f51dd27d82fbb9296330e7f105a69ea307303799ca986abe900f00836f181e59a34210d60eb84f3fe493845aadfe404fb4096e599a26f63453c8120257cfc8c2204ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401220101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020b696bc517ca5d36092ca1106fd8d31047552e9453a9de51d92cf9226259a491618e806cd5aa13974beb89d41c5040a48242c24bffa8e65e9fdf3bc35e2a7c1b4204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401230101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020358daeb9eef51c07f280abf17c5321023d8cf8bae26254abf25b9268d89a424fb67a604005cd713a7df2c45fbf5f761da51b9c6f21e86a3d8eb40827bbe2764b204ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401240101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000200170975c14ec6544367490c04b06294aa57fe978a1da6e5939ee6051d7602928e3676a94ad350f04f371edfe21281df51430055242082d9704030cf5317d0b81204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401250101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002008d02d23a387a7263f5f3475bcd56b380fde9b742bbe83790dd9751701a7923038bfe35d91a9e4e5f8cc714713acfe2d1e96646e61b29b3dc072e5b182fdb45e214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401260101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000206bd75eab3dabdee5a35c0a64de2aa90fb54f2d12b4f37ee60aa28541b51b493f0e5915bc2be5d87850016a330fc36b62f6e40ad7a6d38e0ed6a4f62056ba22a9214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401270101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020a42645a785e5dd28047022b724c1af64d507d372b83f3f23899c82b317168262371693330fe6d94f33a962de50891b2f5811a066830c331a240996310b5c6280214ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401280101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020a6626233cfb7d9dd7c97f6db305ca20b6a7fc32d5e8ce9b07e35aeaaa7c0af3975cbe08a458c6fc4cd748a39427e29c2b29180293359623e30e2b5639d2d0417214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401290101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000203a5a408e1a076fdc7bfa08460932fa40aedb0471fe808e268ee5768ce173520af5dc75a6bde31efc2ba81a4ea94fe91d3b1ab1ed99975fc5b1cc725f7f20817b214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000204cc70837ef7c3804c04419260a2d65ce21515317991751117fb81596ef32c3161154931edf6dd92bb8a13231190f7c0b21bc527e188384770faa53b54aba04f8214ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002070b6275e92ff0b54df08933d70b7d933c3b534b779026630dfb2f96efb860436581cf56e07b7d7e2a377ba0e698f592e464d1ed84bf464b0dd67cb85cbf69f7a224ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020a330af8e1dc93fd74b7479c626b1a77c21dec2d240fe7b7d90249da127aaea50773fe8f12bdce2a65c375082dc3db0414e68aacea57f41504cf901a7858b8cf3224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002052841b806090d1d40d221788025ba6ae3a9bb32f352cb12ce4b165be58846a12ee2ad08be6b3e693e3d53a90abe88a8426b342f19f3b271818e66eed4ed1892f224ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002095b86217b1ebf86fa345f2c605f4251b24d5a647710758cbe08340448250ef015f65e5752628c0a0131fc31fac03ed3a2ab0d2c1407414d4dfdc1680037a3b38224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020757dfdbb6f52e389a0ed997dff15de8682d55f9e241d3b53b254f19fd96b926860d0c537aaa527616248c9e50fd776e801eb5dc5d9ef034251b846359da84bc1224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401300101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000204c5ff56d6188016b722ba01c7d3b74bc530820b7dff447efbb8c5e756def2d25bdb8e2a27ead1a99e184a87195f06f858b810add552f6bf0127c0a36ec101a60224ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401310101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002064c6f9651c489cb014e8d5271e1f711b71d20d865ab7561b26bea5c85fe6957b6326b1ba78a33db0f148a07e1d49437ca70ae9d73544c183d2cfdf814fd7ff37234ae75affff7f200700000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401320101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020bc955dccd950bcd6051723e18c87ba5114103eb66c136d4bde1070b99678c12f6192856637c104e86194dc91e1550447d83b7124a230871020c37454f2ec82bf234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401330101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000200f4e7a95470e9056dda68e82b62a61cae778e88b6e35a4714bdfa3bff8b6e846c45be9fa19a24d90a3180a562bdd8b8a5b71d4c2e0a9f84b6c55c439ebf2f22a234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401340101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002044388dd29a4f16901222a7beeb49315884c0583a2c31a2f8865536931ff8ec4442553d33ba0273b54c52e589523cde509eb117046f5e63bd5e8a5a96f467c5f1234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401350101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020438366e968619730e26031d71e8208d31ab6cb7c242acb65f3d1769157cb971210b6afd88e0ce95bb14554c6dad04012fa8ce0c88a5932ad71da4d04a15d44c3234ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401360101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020c38296d021842f437d04f8515079f943f0a1c8437d8f2c329499c32c0448ae1d961fb68ada366165b25199757ce8a527f11d0744bbcbaad402815e09623dae04234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401370101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020101cd76ca645831e3a55898707454b2405151a06f8c8cee7822d148ca1251d12fd945975eb3855e5f0cd2afafd20b169a7763bdc73b64d1c2f096425d9c902eb244ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401380101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020f7735468f9b54bae6399754a1ba4b5ee620af1dc6a46261f4d8ab4d872818f35507916cc69e748edc3a9feadf7b79d1d19f16140e8f3260d7fbe9d1620e55f26244ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401390101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000200bc5d881eeab42717526d45d8475fefb1940bbf03c5726174e64379e5a23bf5cbc75b97dfb5771d55e7bd108bb109705ba34952511ab96646cd2db4539fc3b2b244ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002094a466199740a3c77035005e1fe5ae603df04ab18c429abfcc385b93681b75390e0d6b356161c1ccbe486a26b777ff01b1247cd6b4b9d4d5b0f958d2e887caab244ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020b5e8aad67d17f4f047da10404862703a89feab21624801f785cfe77af4a71d6b87994452ce4bfdc92a07f49ed16903e68d8d48191e31d9558dad4805718311d5244ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020b0ed4309ee1541c2dc5480b14092940b88870b9d4ca32ca448e7eaffc1d74978b9c5b6e8c1739811c932cdbecd192ae0bead4068782ca2e98805b8174d40f213244ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000205caa7f7a1817fcf6b454b156301f44edbb71cd19de098d9261305aa5731cf073faa4b4bcef4b3ed44ddf9b2b708397114484aa262a538c81b04103a02d8c033a254ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020c7ec1d68a2b4309b255ebc418cc4c8c1a57892bb3c6360a07d22b526ffba6a38436088fcdbf94cabbacefee23bb69b5ac30e3627f94500746630163249cc5029254ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002014c877261aa37fc58f703b64278f1d611b6faddd582e33cc7f1e7e63ad75df6cbd9d279982bfe391b013160a66675ed11debd83c32a9efa02351eee65ac96d09254ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401400101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000202b5cbee48cac714ff220fafa0cd4304f452e5c5b63dc5cd4f27072cc4ba7e9376f1f5aac2480c10e93e13f3be00b38523dc036eb6ae49b93f815140ee2b08a27254ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401410101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020aebd16a2c6cf18789e213338ee08bcca42d89e7c9f9220cf80e803cf9b67205eb58e2687eae141c7bc9656b434bc95900a6935f00db43dc23ac155e380af8e9e254ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401420101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020984d2d236668762da13fcb8f811401c1928a1df9a9896a4cc382912669b0b13642ad8e61dd8e6c702869587acb0d09b3355a1be27cb20ea909f51287f9e1b010254ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401430101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020d8ca9b5782f98937be5967d0c34aabdcdddc0201e17b70e4071e320bbb2c06418d020f678641ba278d49d70430385ede2f830c46aa49ff7a3febe99d2a9896a9264ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401440101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002017dad2d355421342e973abef035c18398d83dceccd6372269f6bbe6e844fcd52d9c4bce498d350184aae9af97f0aef0f366356d50b926c59bc1605ff6f41f144264ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401450101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020ab1775daac96add2d038b5046be91c90b597b8ed11038b2b9da32f47537d106556d820e14b52e6f4fd113554754f3a8d65b80e7dfab2c84c5e7bb41a30c39977264ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401460101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000204dd398d0716e12f3397c9de79cc644ae3d63c6b90c579f5872d76820dd79260fc5808f07c0d1a3e6a23c9e8dc84d58c12758cd61a2f0e8ec3694a1ac08a89bda264ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401470101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020ed9c915c725956194c078ed08ad2508ec34a6b868c21226d14213904bb3c4c50f385dbbdfd18fa6f8355a89c58370c50a71f59f44e2d2e505fb861960d155705264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401480101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020b2f8525fa7a276f4a078bdad600074c49df4c237aae27cadb60ecf91eb7b8d42c21e035455f17270ff5e2a53c57c8c663f31cdb7a3a929de1499e3117358108f264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401490101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020897b6cc09bd1b7cb5d42c648498199aba4008875614e021898b121e8e751f34cf0b8a1a4c993ffd133335d84b9aba6159bb8129384a253131d1998f28c3d371b274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000206a9836bb25994ab592060389b119cb8f7a19a64acd27f9665eab93b235803170ec6385bd31ab432ed3a13f7a6cdf0a6c87fe50c614372a58a5a3716c34456e83274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000208202cd4938b8eef65707e3b6cbd025780f7220fdfea8bc897e802da008026d29043cd5b1662309701440c7941d61cfb95d0c98e22ff8ff8b5994149e988ab179274ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002074eed60562b3fabf1cfbd4efd86acd62a470dc264b81b98c784dce4a57f56614d713809d3b1678f325563577d3b6dd9ae4f1e5b05b70c3b16abd67d7161d9002274ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002072677aab7f4bb3af82841c6a7100df3ac5e8b643d9e88bb271b2da39c575222aadfd5417618dde8d0ee9191c4b110d0c76dcb65eb8adfd3f8a32a35ccceee445274ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020508ed0a8978dd8a6a4e55bb5bc27dd8edae3838d4ddba461332da10f0fb901080c5a78ea3fb056e326e873cea75009c29c401fb77a415ee64ae4eca44bd617dd274ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000202004607f94d91d8eca99a860ed208c53a4fd53f38889c77dc35b31a676eef1625ee8e5c95cb2105d0b8268ed13eaac6236eb3405df3099fc52d62169d218fcdf284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401500101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000204374d19a51a307de1344af36d893991965f58779adbc4b1c1045d5d8e14d6d0b034e10cf7e5158f62fe2674c89e8fc4ee94d2da62d81c0ffc8a237e8dfcb3e21284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401510101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002037320af6c9cc617be33ba517458ae4607b1c0e3e007268669cf5c799e93ebe67f182660cef31f84c0c6b384f084b243a77e2c271be610ac958124076306d9170284ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401520101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000201ea13062078bd8f70060208d6973bd55789cbf2f221e8690f1a78254a597a1434a16aa13a90a872e0dd3046458114dc745e37d2928bd9ff306ce7adb2567efb3284ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401530101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002052fe4aa74774077ea9a1c27fea59dfa12b75f7ad46746f8458eb67acaeb9803921a47de6874e6c2359af86d72abdee12b27bcebe0f1ce48751055005813d3f42284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401540101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000208ee41caa2f3076233035157fde7c5c2795a81b85d5e27ce7898e301679e91c4d2d38f595981a444c7d868166ae50e371d83b5f59802bebfed056b93aad1b971e284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401550101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000201a0eea032f4abd74aa1bf1151e2966433175ecdf2d68b750b509305bc5663e3641f55e2175bc1d50b4d8a83f167091059a2a6e7d1a24d8223f50ca41313eef1b294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401560101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000207403c2bca2c06351f16746d3360a1a7dceb5194d57879caee03a8316ec774a608a5d44cb75516291cdf62cd51a1a9c71fd3d4879737d88216c6c4c6bffb0784a294ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401570101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020f2be7a9ba2c914d5ee97c819cb096aa9d2c715d2f74e9dcf8a12cc83ac48475e4e332a45285f3fff16e8c5cf79107ee110dc2a2f84456205f43d8f4e237a10da294ae75affff7f200400000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401580101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000205fc71ff65dd07485e26129b765937f514315487b27f0e431c5da7de97b397a4f1d984f86e81bd2c9db53c3515b6e3d6a28187b50adffb87df25608b738190bcf294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401590101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020d7befb40f244eb69f02a3253bcc9b14f5c2697261e158288e7d0b48eab34f12eeac43d0751178d2574aa20506d1b91af13af688a8dfcdf1a48806f63e53b3245294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000204a0082f8508319d99c86cc074cfedcf26fb98f2e6d0c27d602a9d6ed6d04db042163e10278a5cc75003c52739df112f1ea4fe0ed250ace8e544ecde713f47bfe294ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000203de23751fef24f5d30565808862dd364e209fc0f7bf83874ebcc8f155e65574acda81243c6a438daeb547e1b36c9a5441e6556bf16bb9bfb839628c39a3785162a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002045addce76c20d564ac3ff6b955e8ecf2185a5aa355a0d3ac7fd29448dcfb9c1ed184bdf283ba671c76c99173e4ec87e45dd97331c9000070edc81093bc4c7c872a4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020a7e8079eccbca3b4a4a0136ef27478b45352270f2f8947ab83eea09b06cc826ab29d7b37989b6570510e368a20f4fee2ca0142044f96a027830abdf438ddf7592a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000201f28203982fc7c2fc155361d00ef7e69ac9fa9c35ff3d10e8fd1a0004e9b10528488982a149b5ac96bef6be131e0b2f0ad9269ba66c9b4216901c0b81523123e2a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020435d68020c01c6088e4013cb4f349009e65c28ffa0630baf5dde1676df55481513a48742e06190847a40cabbda6d48f715802bdb3cbab7ad7a2e5c345d557b082a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401600101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020e525dd596c4b9ca78d964ef7997063d35af98665f62e9da62ed9c7fb38c9f57f5abfb8140edec21a383e1e3e31288ee0130a86564e5c3da9764594d8365134652a4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401610101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000203d4144c4bd71aa7f71af930a98087d3786e697335fc1eb11177bedcdae72a61549aa4519391183deb58058f99a6abb7638fe81f079b31c4e090d486c49e047ac2b4ae75affff7f200500000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401620101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "00000020f44e7a48b9f221af95f3295c8dcefc5358934a68dc79e2933dc0794b350cad0a90fad2cd50b41d4ef45e76c2a456b98c180632bb4b44e0cd18ce90679fe54e552b4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401630101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "0000002087454276cce83f4d19e0120f6e9728ac5905f7adaf6b27e3f5bbe43ab823f85db7d1f44666531483df3d67c15f2c231718ad93b63b851dce5ff4c4a67f524ffa2b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401640101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000202cdc3e99f07a80252dd6097faa0eddf3f2dde5ae390610e0bca94ecc25931551d31fceb8fe0a682f6017ca3dbb582f3a2f06e5d99ec99c42c8a744dd4c9216b82b4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401650101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000", + "000000209b3ace9bd510918d20e87518c0cf5976cab3e28cc7af41259a89c6dd7668a32922808b8a082be71bcd6152cb8fd223650b5579a41344ba749e4d17b9bf211a9e2b4ae75affff7f200000000002020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401660101ffffffff026c03062a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9edb85d8f3c122c43a72f1e0dd122c8f7af040aa0b0a46001621110fb37818021510120000000000000000000000000000000000000000000000000000000000000000000000000020000000128394022bf44bff30d7399cb5a16e3b94fed67dc174c2e1d77df91bad5a51cb3000000006a47304402201c16d06a5c4353168b3881071aea7d1eb4d88eedfea53a9d6af9abb56da9060002205abf3ae535f1f1b5cfe8ba955535c2b20ac003e7d7720c5b7d2640ac2a04d19001210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff0294b89a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac00286bee0000000017a91452bab4f229415d0dc5c6d30b162f93a1a0cac5958765000000", + "000000200fa168b50a79ad24378a6b0f96e4c9f4ccb657a2663320d5fc1efd8ee7caa10ab42a31c444f2153387530a0979d4dc3dcc134b394c821227b8abff930c03c8412b4ae75affff7f200200000004020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401670101ffffffff02e015072a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ed20376d4bc90f9c689850eec3603cda658ba6295241730473ceb0e970b8d594150120000000000000000000000000000000000000000000000000000000000000000000000000020000000191e549a6cc852bbf1d3f11144b1a34079f64305e6971d2e685d2b40cd386e8a6000000006a47304402200bf62021c0a9a47ced8eba1e0998f5c71b2950763198d83ad284bd791241dbb00220446a05b7c35e7458924de88a8dcccab1ec6a106aa005345e55b482d8eb66337301210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff02acdbf405000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac94d7a4350000000017a914dfa6f0b17d2c64962c94203e744a9d4179ed22c18766000000020000000112d2f07672102dc6f099c4be308f598e4c4da1a7e0cb462ae14f0444525a1332000000006a47304402200a6a2f544f3f9d299608a7c745e2326de176fb1cac03ae3e74943f4250b8896e02205023a5b4faff99865bf91f1263605a502c723628be9240c0b7bec81d2ed106f101210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff0200ca9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac94166bee0000000017a914152cc82f7944f5c416de7dbffb052f7081765d7987660000000200000000010191e549a6cc852bbf1d3f11144b1a34079f64305e6971d2e685d2b40cd386e8a601000000171600147cc872ad7350c37fecab9c4c6d9f08aceb53bdb8feffffff02005ed0b20000000017a914aab1c8c53fe62e283a53efa28097709f4f2ed37b87e0bc9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0247304402201b4476f238ed5d515bfcd6927d0d008a4993770763eca73e3ee66f69971831d902200f5215a6dfd90391dd63462cfdf69804fe31224c309ec9c38d33a04dce71c0ee0121028c9d2955a95301b699db62e97d54bf0a91feb44e5cd94bbf5b62f1df57fb643966000000" ], "mocktime": 1525107225, "stats": [ @@ -111,7 +111,7 @@ "avgfee": 0, "avgfeerate": 0, "avgtxsize": 0, - "blockhash": "1d7fe80f19d28b8e712af0399ac84006db753441f3033111b3a8d610afab364f", + "blockhash": "29a36876ddc6899a2541afc78ce2b3ca7659cfc01875e8208d9110d59bce3a9b", "feerate_percentiles": [ 0, 0, @@ -142,14 +142,13 @@ "totalfee": 0, "txs": 1, "utxo_increase": 2, - "utxo_size_inc": 173 + "utxo_size_inc": 163 }, { - "avgfee": 3760, + "avgfee": 4460, "avgfeerate": 20, - "avgtxsize": 187, - "blockhash": "4e21a43675d7a41cb6b944e068c5bcd0a677baf658d9ebe021ae2d2f99397ccc", - "height": 102, + "avgtxsize": 223, + "blockhash": "0aa1cae78efd1efcd5203366a257b6ccf4c9e4960f6b8a3724ad790ab568a10f", "feerate_percentiles": [ 20, 20, @@ -157,35 +156,36 @@ 20, 20 ], + "height": 102, "ins": 1, - "maxfee": 3760, + "maxfee": 4460, "maxfeerate": 20, - "maxtxsize": 187, - "medianfee": 3760, + "maxtxsize": 223, + "medianfee": 4460, "mediantime": 1525107242, - "mediantxsize": 187, - "minfee": 3760, + "mediantxsize": 223, + "minfee": 4460, "minfeerate": 20, - "mintxsize": 187, + "mintxsize": 223, "outs": 4, "subsidy": 5000000000, "swtotal_size": 0, "swtotal_weight": 0, "swtxs": 0, "time": 1525107243, - "total_out": 4999996240, - "total_size": 187, - "total_weight": 748, - "totalfee": 3760, + "total_out": 4999995540, + "total_size": 223, + "total_weight": 892, + "totalfee": 4460, "txs": 2, "utxo_increase": 3, - "utxo_size_inc": 234 + "utxo_size_inc": 236 }, { - "avgfee": 18960, - "avgfeerate": 109, - "avgtxsize": 228, - "blockhash": "22d9b8b9c2a37c81515f3fc84f7241f6c07dbcea85ef16b00bcc33ae400a030f", + "avgfee": 24906, + "avgfeerate": 121, + "avgtxsize": 231, + "blockhash": "53e416e2538bc783c42a7aea566e884321afed893e9e58cf356d6429759dfa46", "feerate_percentiles": [ 20, 20, @@ -195,28 +195,28 @@ ], "height": 103, "ins": 3, - "maxfee": 49800, + "maxfee": 66900, "maxfeerate": 300, - "maxtxsize": 248, - "medianfee": 3760, + "maxtxsize": 249, + "medianfee": 4460, "mediantime": 1525107243, - "mediantxsize": 248, - "minfee": 3320, + "mediantxsize": 223, + "minfee": 3360, "minfeerate": 20, - "mintxsize": 188, + "mintxsize": 223, "outs": 8, "subsidy": 5000000000, - "swtotal_size": 496, - "swtotal_weight": 1324, - "swtxs": 2, + "swtotal_size": 249, + "swtotal_weight": 669, + "swtxs": 1, "time": 1525107243, - "total_out": 9999939360, - "total_size": 684, - "total_weight": 2076, - "totalfee": 56880, + "total_out": 9999920820, + "total_size": 695, + "total_weight": 2453, + "totalfee": 74720, "txs": 4, "utxo_increase": 5, - "utxo_size_inc": 380 + "utxo_size_inc": 384 } ] }
\ No newline at end of file diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py index e17a8f6421..efab69ac26 100755 --- a/test/functional/rpc_getblockstats.py +++ b/test/functional/rpc_getblockstats.py @@ -13,7 +13,6 @@ from test_framework.util import ( ) import json import os -import time TESTSDIR = os.path.dirname(os.path.realpath(__file__)) @@ -21,18 +20,6 @@ class GetblockstatsTest(BitcoinTestFramework): start_height = 101 max_stat_pos = 2 - STATS_NEED_TXINDEX = [ - 'avgfee', - 'avgfeerate', - 'maxfee', - 'maxfeerate', - 'medianfee', - 'feerate_percentiles', - 'minfee', - 'minfeerate', - 'totalfee', - 'utxo_size_inc', - ] def add_options(self, parser): parser.add_argument('--gen-test-data', dest='gen_test_data', @@ -44,24 +31,26 @@ class GetblockstatsTest(BitcoinTestFramework): help='Test data file') def set_test_params(self): - self.num_nodes = 2 - self.extra_args = [['-txindex'], ['-paytxfee=0.003']] + self.num_nodes = 1 self.setup_clean_chain = True def get_stats(self): return [self.nodes[0].getblockstats(hash_or_height=self.start_height + i) for i in range(self.max_stat_pos+1)] def generate_test_data(self, filename): - mocktime = time.time() + mocktime = 1525107225 + self.nodes[0].setmocktime(mocktime) self.nodes[0].generate(101) - self.nodes[0].sendtoaddress(address=self.nodes[1].getnewaddress(), amount=10, subtractfeefromamount=True) + address = self.nodes[0].get_deterministic_priv_key().address + self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=True) self.nodes[0].generate(1) self.sync_all() - self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=10, subtractfeefromamount=True) - self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=10, subtractfeefromamount=False) - self.nodes[1].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=1, subtractfeefromamount=True) + self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=True) + self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=False) + self.nodes[0].settxfee(amount=0.003) + self.nodes[0].sendtoaddress(address=address, amount=1, subtractfeefromamount=True) self.sync_all() self.nodes[0].generate(1) @@ -93,11 +82,12 @@ class GetblockstatsTest(BitcoinTestFramework): # Set the timestamps from the file so that the nodes can get out of Initial Block Download self.nodes[0].setmocktime(mocktime) - self.nodes[1].setmocktime(mocktime) + self.sync_all() for b in blocks: self.nodes[0].submitblock(b) + def run_test(self): test_data = os.path.join(TESTSDIR, self.options.test_data) if self.options.gen_test_data: @@ -107,9 +97,6 @@ class GetblockstatsTest(BitcoinTestFramework): self.sync_all() stats = self.get_stats() - expected_stats_noindex = [] - for stat_row in stats: - expected_stats_noindex.append({k: v for k, v in stat_row.items() if k not in self.STATS_NEED_TXINDEX}) # Make sure all valid statistics are included but nothing else is expected_keys = self.expected_stats[0].keys() @@ -127,10 +114,6 @@ class GetblockstatsTest(BitcoinTestFramework): stats_by_hash = self.nodes[0].getblockstats(hash_or_height=blockhash) assert_equal(stats_by_hash, self.expected_stats[i]) - # Check with the node that has no txindex - stats_no_txindex = self.nodes[1].getblockstats(hash_or_height=blockhash, stats=list(expected_stats_noindex[i].keys())) - assert_equal(stats_no_txindex, expected_stats_noindex[i]) - # Make sure each stat can be queried on its own for stat in expected_keys: for i in range(self.max_stat_pos+1): @@ -168,12 +151,6 @@ class GetblockstatsTest(BitcoinTestFramework): # Make sure we aren't always returning inv_sel_stat as the culprit stat assert_raises_rpc_error(-8, 'Invalid selected statistic aaa%s' % inv_sel_stat, self.nodes[0].getblockstats, hash_or_height=1, stats=['minfee' , 'aaa%s' % inv_sel_stat]) - - assert_raises_rpc_error(-8, 'One or more of the selected stats requires -txindex enabled', - self.nodes[1].getblockstats, hash_or_height=1) - assert_raises_rpc_error(-8, 'One or more of the selected stats requires -txindex enabled', - self.nodes[1].getblockstats, hash_or_height=self.start_height + self.max_stat_pos) - # Mainchain's genesis block shouldn't be found on regtest assert_raises_rpc_error(-5, 'Block not found', self.nodes[0].getblockstats, hash_or_height='000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f') diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py index 7bf8e68176..8a3f8c6f06 100755 --- a/test/functional/rpc_misc.py +++ b/test/functional/rpc_misc.py @@ -46,5 +46,13 @@ class RpcMiscTest(BitcoinTestFramework): assert_raises_rpc_error(-8, "unknown mode foobar", node.getmemoryinfo, mode="foobar") + self.log.info("test logging") + assert_equal(node.logging()['qt'], True) + node.logging(exclude=['qt']) + assert_equal(node.logging()['qt'], False) + node.logging(include=['qt']) + assert_equal(node.logging()['qt'], True) + + if __name__ == '__main__': RpcMiscTest().main() diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py index 6346477922..a1cd33ad54 100755 --- a/test/functional/rpc_scantxoutset.py +++ b/test/functional/rpc_scantxoutset.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the scantxoutset rpc call.""" from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal +from test_framework.util import assert_equal, assert_raises_rpc_error from decimal import Decimal import shutil @@ -67,6 +67,13 @@ class ScantxoutsetTest(BitcoinTestFramework): assert_equal(self.nodes[0].scantxoutset("start", [ "addr(" + addr_P2SH_SEGWIT + ")", "addr(" + addr_LEGACY + ")", "addr(" + addr_BECH32 + ")"])['total_amount'], Decimal("0.007")) assert_equal(self.nodes[0].scantxoutset("start", [ "addr(" + addr_P2SH_SEGWIT + ")", "addr(" + addr_LEGACY + ")", "combo(" + pubk3 + ")"])['total_amount'], Decimal("0.007")) + self.log.info("Test range validation.") + assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": -1}]) + assert_raises_rpc_error(-8, "Range should be greater or equal than 0", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [-1, 10]}]) + assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]}]) + assert_raises_rpc_error(-8, "Range specified as [begin,end] must not have begin after end", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [2, 1]}]) + assert_raises_rpc_error(-8, "Range is too large", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [0, 1000001]}]) + self.log.info("Test extended key derivation.") # Run various scans, and verify that the sum of the amounts of the matches corresponds to the expected subset. # Note that all amounts in the UTXO set are powers of 2 multiplied by 0.001 BTC, so each amounts uniquely identifies a subset. diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 555d55d97f..2187bf5f5f 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -10,6 +10,7 @@ import logging import argparse import os import pdb +import random import shutil import sys import tempfile @@ -129,6 +130,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): help="use bitcoin-cli instead of RPC for all commands") parser.add_argument("--perf", dest="perf", default=False, action="store_true", help="profile running nodes with perf for the duration of the test") + parser.add_argument("--randomseed", type=int, + help="set a random seed for deterministically reproducing a previous test run") self.add_options(parser) self.options = parser.parse_args() @@ -158,6 +161,22 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.options.tmpdir = tempfile.mkdtemp(prefix=TMPDIR_PREFIX) self._start_logging() + # Seed the PRNG. Note that test runs are reproducible if and only if + # a single thread accesses the PRNG. For more information, see + # https://docs.python.org/3/library/random.html#notes-on-reproducibility. + # The network thread shouldn't access random. If we need to change the + # network thread to access randomness, it should instantiate its own + # random.Random object. + seed = self.options.randomseed + + if seed is None: + seed = random.randrange(sys.maxsize) + else: + self.log.debug("User supplied random seed {}".format(seed)) + + random.seed(seed) + self.log.debug("PRNG seed is: {}".format(seed)) + self.log.debug('Setting up network thread') self.network_thread = NetworkThread() self.network_thread.start() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index eff6128588..80dced733e 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -402,16 +402,18 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage= print_results(test_results, max_len_name, (int(time.time() - start_time))) if coverage: - coverage.report_rpc_coverage() + coverage_passed = coverage.report_rpc_coverage() logging.debug("Cleaning up coverage data") coverage.cleanup() + else: + coverage_passed = True # Clear up the temp directory if all subdirectories are gone if not os.listdir(tmpdir): os.rmdir(tmpdir) - all_passed = all(map(lambda test_result: test_result.was_successful, test_results)) + all_passed = all(map(lambda test_result: test_result.was_successful, test_results)) and coverage_passed # This will be a no-op unless failfast is True in which case there may be dangling # processes which need to be killed. @@ -613,8 +615,10 @@ class RPCCoverage(): if uncovered: print("Uncovered RPC commands:") print("".join((" - %s\n" % command) for command in sorted(uncovered))) + return False else: print("All RPC commands covered.") + return True def cleanup(self): return shutil.rmtree(self.dir) diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py index 8ec4b98b6e..fc7969ad19 100755 --- a/test/functional/wallet_createwallet.py +++ b/test/functional/wallet_createwallet.py @@ -96,5 +96,28 @@ class CreateWalletTest(BitcoinTestFramework): assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getnewaddress) assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getrawchangeaddress) + self.log.info('New blank and encrypted wallets can be created') + self.nodes[0].createwallet(wallet_name='wblank', disable_private_keys=False, blank=True, passphrase='thisisapassphrase') + wblank = node.get_wallet_rpc('wblank') + assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", wblank.signmessage, "needanargument", "test") + wblank.walletpassphrase('thisisapassphrase', 10) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getnewaddress) + assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getrawchangeaddress) + + self.log.info('Test creating a new encrypted wallet.') + # Born encrypted wallet is created (has keys) + self.nodes[0].createwallet(wallet_name='w6', disable_private_keys=False, blank=False, passphrase='thisisapassphrase') + w6 = node.get_wallet_rpc('w6') + assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", w6.signmessage, "needanargument", "test") + w6.walletpassphrase('thisisapassphrase', 10) + w6.signmessage(w6.getnewaddress('', 'legacy'), "test") + w6.keypoolrefill(1) + # There should only be 1 key + walletinfo = w6.getwalletinfo() + assert_equal(walletinfo['keypoolsize'], 1) + assert_equal(walletinfo['keypoolsize_hd_internal'], 1) + # Empty passphrase, error + assert_raises_rpc_error(-16, 'Cannot encrypt a wallet with a blank password', self.nodes[0].createwallet, 'w7', False, False, '') + if __name__ == '__main__': CreateWalletTest().main() diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py index 9de30d0374..47c97f62bf 100755 --- a/test/functional/wallet_import_rescan.py +++ b/test/functional/wallet_import_rescan.py @@ -21,7 +21,6 @@ happened previously. from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( - assert_raises_rpc_error, connect_nodes, assert_equal, set_node_times, @@ -39,23 +38,17 @@ Rescan = enum.Enum("Rescan", "no yes late_timestamp") class Variant(collections.namedtuple("Variant", "call data rescan prune")): """Helper for importing one key and verifying scanned transactions.""" - def try_rpc(self, func, *args, **kwargs): - if self.expect_disabled: - assert_raises_rpc_error(-4, "Rescan is disabled in pruned mode", func, *args, **kwargs) - else: - return func(*args, **kwargs) - def do_import(self, timestamp): """Call one key import RPC.""" rescan = self.rescan == Rescan.yes if self.call == Call.single: if self.data == Data.address: - response = self.try_rpc(self.node.importaddress, address=self.address["address"], label=self.label, rescan=rescan) + response = self.node.importaddress(address=self.address["address"], label=self.label, rescan=rescan) elif self.data == Data.pub: - response = self.try_rpc(self.node.importpubkey, pubkey=self.address["pubkey"], label=self.label, rescan=rescan) + response = self.node.importpubkey(pubkey=self.address["pubkey"], label=self.label, rescan=rescan) elif self.data == Data.priv: - response = self.try_rpc(self.node.importprivkey, privkey=self.key, label=self.label, rescan=rescan) + response = self.node.importprivkey(privkey=self.key, label=self.label, rescan=rescan) assert_equal(response, None) elif self.call in (Call.multiaddress, Call.multiscript): @@ -172,8 +165,7 @@ class ImportRescanTest(BitcoinTestFramework): # check the results from getbalance and listtransactions. for variant in IMPORT_VARIANTS: self.log.info('Run import for variant {}'.format(variant)) - variant.expect_disabled = variant.rescan == Rescan.yes and variant.prune and variant.call == Call.single - expect_rescan = variant.rescan == Rescan.yes and not variant.expect_disabled + expect_rescan = variant.rescan == Rescan.yes variant.node = self.nodes[2 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan))] variant.do_import(timestamp) if expect_rescan: @@ -198,12 +190,9 @@ class ImportRescanTest(BitcoinTestFramework): # Check the latest results from getbalance and listtransactions. for variant in IMPORT_VARIANTS: self.log.info('Run check for variant {}'.format(variant)) - if not variant.expect_disabled: - variant.expected_balance += variant.sent_amount - variant.expected_txs += 1 - variant.check(variant.sent_txid, variant.sent_amount, 1) - else: - variant.check() + variant.expected_balance += variant.sent_amount + variant.expected_txs += 1 + variant.check(variant.sent_txid, variant.sent_amount, 1) if __name__ == "__main__": ImportRescanTest().main() diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index 81c650f4c1..7d652a7825 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -591,6 +591,21 @@ class ImportMultiTest(BitcoinTestFramework): key.p2sh_p2wpkh_addr, solvable=True) + self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": -1}, + success=False, error_code=-8, error_message='End of range is too high') + + self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [-1, 10]}, + success=False, error_code=-8, error_message='Range should be greater or equal than 0') + + self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]}, + success=False, error_code=-8, error_message='End of range is too high') + + self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [2, 1]}, + success=False, error_code=-8, error_message='Range specified as [begin,end] must not have begin after end') + + self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]}, + success=False, error_code=-8, error_message='Range is too large') + # Test importing of a P2PKH address via descriptor key = get_key(self.nodes[0]) self.log.info("Should import a p2pkh address from descriptor") diff --git a/test/lint/lint-all.sh b/test/lint/lint-all.sh index 7c4f96cb3b..fabc24c91b 100755 --- a/test/lint/lint-all.sh +++ b/test/lint/lint-all.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2017 The Bitcoin Core developers +# Copyright (c) 2017-2019 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. # @@ -16,11 +16,15 @@ set -u SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}") LINTALL=$(basename "${BASH_SOURCE[0]}") +EXIT_CODE=0 + for f in "${SCRIPTDIR}"/lint-*.sh; do if [ "$(basename "$f")" != "$LINTALL" ]; then if ! "$f"; then echo "^---- failure generated from $f" - exit 1 + EXIT_CODE=1 fi fi done + +exit ${EXIT_CODE} |