What changed, and why it matters
This commit is a routine cleanup titled 'Fix: linter errors'. It removes trailing whitespace, fixes typos in comments and strings, corrects indentation, removes unused include directives, and deletes a large number of stale test files under test/bitcoin_functional/functional. There is no functional code change that affects how the software behaves or processes untrusted data.
No security action required. Treat as normal maintenance/cleanup commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff is almost entirely cosmetic and build-hygiene changes: whitespace trimming, spelling corrections (‘determinstic’→’deterministic’, ‘parallellism’→’parallelism’, ‘explicity’→’explicitly’), indentation fixes in shell scripts, removal of duplicate/unnecessary #include directives, addition of IWYU pragma includes for bitcoin-build-config.h, and deletion of legacy bitcoin_functional test files and data. No consensus, validation, networking, wallet, or RPC logic is modified. The only non-cosmetic changes are include cleanups, which are compile-time only and do not alter runtime behavior.
Changed components
ci/test/03_test_script.shcontrib/devtools/deterministic-fuzz-coverage/src/main.rscontrib/merge-prs.shsrc/bench/mempool_eviction.cppsrc/chainparams.cppsrc/chainparamsbase.cppsrc/chainparamsbase.hsrc/common/args.cppsrc/confidential_validation.cppsrc/init.cppsrc/kernel/chainparams.cppsrc/kernel/chainparams.hsrc/policy/policy.cppsrc/qt/guiconstants.hsrc/qt/guiutil.cppsrc/qt/networkstyle.cppsrc/rpc/mining.cppsrc/rpc/request.cppsrc/test/argsman_tests.cppsrc/test/fuzz/bloom_filter.cppsrc/test/fuzz/deserialize.cppsrc/test/fuzz/psbt.cppsrc/test/fuzz/rbf.cppsrc/txmempool.cppsrc/util/chaintype.cppsrc/util/chaintype.hsrc/validation.cppsrc/validation.hsrc/wallet/wallet.cpptest/bitcoin_functional/functional/*test/functional/*test/lint/*Inspect captured patch +84 / −30883
diff --git a/ci/test/03_test_script.sh b/ci/test/03_test_script.sh
index 1e8b829..fd19889 100755
--- a/ci/test/03_test_script.sh
+++ b/ci/test/03_test_script.sh
@@ -124,11 +124,11 @@ fi
# === CMake build (modern path used by the fork) ===
if [ -n "$NO_DEPENDS" ]; then
echo "Building with CMake (NO_DEPENDS=1)..."
- cmake -B build -S . ${CMAKE_GENERATOR:+-G "$CMAKE_GENERATOR"} $BITCOIN_CONFIG_ALL
+ cmake -B build -S . ${CMAKE_GENERATOR:+-G "$CMAKE_GENERATOR"} "$BITCOIN_CONFIG_ALL"
else
# depends path (still uses configure in some jobs)
./autogen.sh
- ./configure $BITCOIN_CONFIG_ALL
+ ./configure "$BITCOIN_CONFIG_ALL"
fi
cmake --build build --config Release --parallel "$MAKEJOBS"
@@ -159,12 +159,12 @@ cd "${BASE_BUILD_DIR}/elements-$HOST"
bash -c "./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG" || ( (cat config.log) && false)
-# ELEMENTS FIXME: fix fix in order to correctly run it #30454
+# ELEMENTS FIXME: fix fix in order to correctly run it #30454
# # Folder where the build is done.
# BASE_BUILD_DIR=${BASE_BUILD_DIR:-$BASE_SCRATCH_DIR/build-$HOST}
# mkdir -p "${BASE_BUILD_DIR}"
# cd "${BASE_BUILD_DIR}"
-#
+#
# BITCOIN_CONFIG_ALL="$BITCOIN_CONFIG_ALL -DENABLE_EXTERNAL_SIGNER=ON -DCMAKE_INSTALL_PREFIX=$BASE_OUTDIR"
diff --git a/contrib/devtools/deterministic-fuzz-coverage/src/main.rs b/contrib/devtools/deterministic-fuzz-coverage/src/main.rs
index adf6333..3ebcb75 100644
--- a/contrib/devtools/deterministic-fuzz-coverage/src/main.rs
+++ b/contrib/devtools/deterministic-fuzz-coverage/src/main.rs
@@ -165,7 +165,7 @@ fn deterministic_coverage(
.success();
if !same {
eprintln!();
- eprintln!("The coverage was not determinstic between runs.");
+ eprintln!("The coverage was not deterministic between runs.");
eprintln!("{}", err);
eprintln!("Exiting.");
exit(1);
diff --git a/contrib/merge-prs.sh b/contrib/merge-prs.sh
index 1c1c9e9..ccc425d 100755
--- a/contrib/merge-prs.sh
+++ b/contrib/merge-prs.sh
@@ -23,7 +23,7 @@ PR_PREFIX="bitcoin/bitcoin"
# Set your git worktree location here. This is where the merges will be done, and where you should checkout the merged-master branch.
WORKTREE="/home/byron/code/elements-worktree"
-# Set your parallellism during build/test. You probably want as many cores as possible.
+# Set your parallelism during build/test. You probably want as many cores as possible.
# Parallel functional tests can somewhat exceed your core count, depends on the build machine CPU/RAM.
PARALLEL_BUILD=23 # passed to make -j
PARALLEL_TEST=46 # passed to test_runner.py --jobs
@@ -142,7 +142,7 @@ echo start > merge.log
quietly () {
if [[ "$VERBOSE" == "1" ]]; then
- date | tee --append merge.log
+ date | tee --append merge.log
time "$@" 2>&1 | tee --append merge.log
else
chronic "$@"
@@ -158,7 +158,7 @@ notify () {
echo "$MESSAGE"
fi
if [[ "$2" == "1" ]]; then
- exit 1
+ exit 1
fi
}
@@ -170,7 +170,7 @@ do
CHAIN=$(echo "$line" | cut -d ' ' -f 4)
PR_ID=$(echo "$line" | grep -o -P "#\d+")
- GIT_HEAD=$(git rev-parse HEAD)
+ GIT_HEAD=$(git rev-parse HEAD)
## Do it
if [[ "$1" == "list-only" ]]; then
@@ -207,13 +207,13 @@ do
)
for STOPPER in "${STOPPERS[@]}"
do
- if [[ "$PR_ID" == *"$STOPPER"* ]]; then
- echo "Found $STOPPER in $PR_ID! Exiting."
- notify "hit stopper, exiting"
- exit 1
- else
- echo "Didn't find $STOPPER in $PR_ID. Continuing."
- fi
+ if [[ "$PR_ID" == *"$STOPPER"* ]]; then
+ echo "Found $STOPPER in $PR_ID! Exiting."
+ notify "hit stopper, exiting"
+ exit 1
+ else
+ echo "Didn't find $STOPPER in $PR_ID. Continuing."
+ fi
done
if [[ "$SKIP_MERGE" == "1" ]]; then
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
index de07afa..7e191fa 100644
--- a/src/bench/mempool_eviction.cpp
+++ b/src/bench/mempool_eviction.cpp
@@ -18,8 +18,6 @@
#include <memory>
#include <vector>
-#include <primitives/transaction.h>
-
static void AddTx(const CTransactionRef& tx, const CAmount& nFee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
{
int64_t nTime = 0;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index f81711e..e0484a3 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -22,13 +22,13 @@
#include <util/moneystr.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <crypto/sha256.h>
#include <cassert>
#include <cstdint>
#include <limits>
#include <stdexcept>
#include <vector>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
using util::SplitString;
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 79c0311..aaa7f65 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -14,6 +14,7 @@
#include <util/chaintype.h>
#include <assert.h>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
void SetupChainParamsBaseOptions(ArgsManager& argsman)
{
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index 54a3524..f52092e 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -8,7 +8,6 @@
#include <cstdint>
#include <util/chaintype.h>
-#include <cstdint>
#include <memory>
#include <string>
diff --git a/src/common/args.cpp b/src/common/args.cpp
index 80e353e..0fb2369 100644
--- a/src/common/args.cpp
+++ b/src/common/args.cpp
@@ -39,6 +39,7 @@
#include <string>
#include <utility>
#include <variant>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
#ifdef LIQUID
const char * const BITCOIN_CONF_FILENAME = "liquid.conf";
diff --git a/src/confidential_validation.cpp b/src/confidential_validation.cpp
index 359b93e..915bbb4 100644
--- a/src/confidential_validation.cpp
+++ b/src/confidential_validation.cpp
@@ -86,7 +86,7 @@ std::optional<std::pair<ScriptError, std::string>> CSurjectionCheck::operator()(
error = SCRIPT_ERR_SURJECTION;
return std::make_pair(error, std::move(debug_str));
}
-
+
return std::nullopt;
}
diff --git a/src/init.cpp b/src/init.cpp
index 9717960..c54ff39 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -983,7 +983,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
if (chain.chain_type == ChainType::TESTNET) {
LogInfo("Warning: Support for testnet3 is deprecated and will be removed in an upcoming release. Consider switching to testnet4.\n");
}
-
+
if (!fs::is_directory(args.GetBlocksDirPath())) {
return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), args.GetArg("-blocksdir", "")));
}
@@ -1146,7 +1146,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
} catch (const std::exception& e) {
return InitError(Untranslated(strprintf("Error in -assetdir: %s\n", e.what())));
}
-
+
const std::vector<std::string> test_options = args.GetArgs("-test");
if (!test_options.empty()) {
if (chainparams.GetChainTypeMeta().chain_type != ChainType::REGTEST && chainparams.GetChainTypeMeta().chain_type != ChainType::CUSTOM) {
@@ -1515,7 +1515,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
node.scheduler = std::make_unique<CScheduler>();
assert(!node.reverification_scheduler);
node.reverification_scheduler = std::make_unique<CScheduler>();
-
+
auto& scheduler = *node.scheduler;
// Start the lightweight task scheduler thread
@@ -1572,7 +1572,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ELEMENTS:
policyAsset = CAsset(uint256S(gArgs.GetArg("-feeasset", chainparams.GetConsensus().pegged_asset.GetHex())));
-
+
// Check port numbers
if (!CheckHostPortOptions(args)) return false;
diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp
index c677917..f71c023 100644
--- a/src/kernel/chainparams.cpp
+++ b/src/kernel/chainparams.cpp
@@ -34,6 +34,7 @@
#include <type_traits>
#include <assert.h>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
using util::SplitString;
using namespace util::hex_literals;
@@ -538,7 +539,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_SIMPLICITY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
consensus.vDeployments[Consensus::DEPLOYMENT_SIMPLICITY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_SIMPLICITY].min_activation_height = 0; // No activation delay
-
+
consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000000000001d6dce8651b6094e4c1"};
consensus.defaultAssumeValid = uint256{"0000000000003ed4f08dbdf6f7d6b271a6bcffce25675cb40aa9fa43179a89f3"}; // 72600
diff --git a/src/kernel/chainparams.h b/src/kernel/chainparams.h
index 7e68421..4b58481 100644
--- a/src/kernel/chainparams.h
+++ b/src/kernel/chainparams.h
@@ -28,6 +28,7 @@
#include <unordered_map>
#include <utility>
#include <vector>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
typedef std::map<int, uint256> MapCheckpoints;
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 2289da4..d32dc2d 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -83,7 +83,7 @@ std::vector<uint32_t> GetDust(const CTransaction& tx, CFeeRate dust_relay_rate)
{
std::vector<uint32_t> dust_outputs;
for (uint32_t i{0}; i < tx.vout.size(); ++i) {
- // ELEMENTS: check explicity
+ // ELEMENTS: check explicitly
const auto& output = tx.vout[i];
if (output.nAsset.IsExplicit() && output.nAsset.GetAsset() != ::policyAsset) continue;
if (IsDust(output, dust_relay_rate)) dust_outputs.push_back(i);
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index 35fd7e7..778d1db 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -11,6 +11,7 @@
#include <chrono>
#include <cstdint>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
using namespace std::chrono_literals;
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index a0bc7a6..745dd8d 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -78,6 +78,7 @@
#include <optional>
#include <string>
#include <vector>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
#if defined(Q_OS_MACOS)
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index 78ab4c1..92c302f 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -14,6 +14,7 @@
#include <util/chaintype.h>
#include <QApplication>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
static const struct {
const ChainType networkId;
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index d620a28..7d96607 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -1259,7 +1259,7 @@ static RPCHelpMan getnewblockhex()
options.min_tx_age = std::chrono::seconds(required_wait);
options.proposed_entry = proposed;
options.commit_scripts = data_commitments;
-
+
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(chainman.ActiveChainstate(), node.mempool.get(), options).CreateNewBlock());
if (!pblocktemplate.get()) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty");
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index adb4fd7..f58ea0e 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -21,6 +21,7 @@
#include <stdexcept>
#include <string>
#include <vector>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
/**
* JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
diff --git a/src/test/argsman_tests.cpp b/src/test/argsman_tests.cpp
index 16b5d25..2d494cf 100644
--- a/src/test/argsman_tests.cpp
+++ b/src/test/argsman_tests.cpp
@@ -23,6 +23,7 @@
#include <vector>
#include <boost/test/unit_test.hpp>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
using util::ToString;
diff --git a/src/test/fuzz/bloom_filter.cpp b/src/test/fuzz/bloom_filter.cpp
index 19cfe61..11bd283 100644
--- a/src/test/fuzz/bloom_filter.cpp
+++ b/src/test/fuzz/bloom_filter.cpp
@@ -18,6 +18,7 @@
#include <limits>
#include <optional>
#include <vector>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
FUZZ_TARGET(bloom_filter)
{
diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp
index ad7824e..38ca659 100644
--- a/src/test/fuzz/deserialize.cpp
+++ b/src/test/fuzz/deserialize.cpp
@@ -37,6 +37,7 @@
#include <optional>
#include <stdexcept>
#include <stdint.h>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
using node::SnapshotMetadata;
diff --git a/src/test/fuzz/psbt.cpp b/src/test/fuzz/psbt.cpp
index b099bda..13832c7 100644
--- a/src/test/fuzz/psbt.cpp
+++ b/src/test/fuzz/psbt.cpp
@@ -20,6 +20,7 @@
#include <optional>
#include <string>
#include <vector>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
using node::AnalyzePSBT;
using node::PSBTAnalysis;
diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp
index f399318..09a69c0 100644
--- a/src/test/fuzz/rbf.cpp
+++ b/src/test/fuzz/rbf.cpp
@@ -24,6 +24,7 @@
#include <optional>
#include <string>
#include <vector>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
namespace {
const BasicTestingSetup* g_setup;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 4cf0d1a..cd8a4cc 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -744,7 +744,7 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
}
}
}
-
+
if (m_opts.signals) {
m_opts.signals->MempoolTransactionsRemovedForBlock(txs_removed_for_block, nBlockHeight);
}
diff --git a/src/util/chaintype.cpp b/src/util/chaintype.cpp
index ac6eef6..e0954c8 100644
--- a/src/util/chaintype.cpp
+++ b/src/util/chaintype.cpp
@@ -11,6 +11,7 @@
#include <cassert>
#include <optional>
#include <string>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
std::string ChainTypeToString(ChainType chain)
{
diff --git a/src/util/chaintype.h b/src/util/chaintype.h
index aa54e96..50edad3 100644
--- a/src/util/chaintype.h
+++ b/src/util/chaintype.h
@@ -11,6 +11,7 @@
#include <optional>
#include <string>
+#include <bitcoin-build-config.h> // IWYU pragma: keep
enum class ChainType {
MAIN,
diff --git a/src/validation.cpp b/src/validation.cpp
index d32faa9..269ed71 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -864,7 +864,7 @@ private:
// or the peg-in paid enough subsidy
return true;
}
-
+
ValidationCache& GetValidationCache()
{
return m_active_chainstate.m_chainman.m_validation_cache;
@@ -3095,7 +3095,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
Ticks<SecondsDouble>(m_chainman.time_connect),
Ticks<MillisecondsDouble>(m_chainman.time_connect) / m_chainman.num_blocks_total);
- // todo:
+ // todo:
// CAmountMap block_reward = fee_map;
// block_reward[consensusParams.subsidy_asset] += GetBlockSubsidy(pindex->nHeight, consensusParams);
// if (!MoneyRange(block_reward)) {
@@ -3105,7 +3105,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
// if (!VerifyCoinbaseAmount(*(block.vtx[0]), block_reward)) {
// LogPrintf("ERROR: ConnectBlock(): coinbase pays too much\n");
// return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-amount");
-
+
CAmountMap block_reward = fee_map;
block_reward[consensusParams.subsidy_asset] += GetBlockSubsidy(pindex->nHeight, consensusParams);
if (!MoneyRange(block_reward) && state.IsValid()) {
@@ -4832,7 +4832,7 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
LogPrintf("ERROR: %s: block height in header is incorrect (got %d, expected %d)\n", __func__, block.block_height, nHeight);
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "bad-header-height");
}
-
+
// Testnet4 and regtest only: Check timestamp against prev for difficulty-adjustment
// blocks to prevent timewarp attacks (see https://github.com/bitcoin/bitcoin/pull/15482).
if (consensusParams.enforce_BIP94) {
diff --git a/src/validation.h b/src/validation.h
index 8e2b274..b62d800 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -15,7 +15,6 @@
#include <consensus/amount.h>
#include <cuckoocache.h>
#include <deploymentstatus.h>
-#include <kernel/chain.h>
#include <kernel/chainparams.h>
#include <kernel/chainstatemanager_opts.h>
#include <kernel/cs_main.h> // IWYU pragma: export
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index c9371f5..f17231a 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2628,15 +2628,15 @@ std::optional<PSBTError> CWallet::SignPSBT(PartiallySignedTransaction& psbtx, bo
std::optional<common::PSBTError> CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, bool imbalance_ok, size_t* n_signed, bool include_explicit, bool finalize) const
{
complete = false;
-
+
std::optional<common::PSBTError> error;
error = FillPSBTData(psbtx, bip32derivs, include_explicit);
if (error) {
return error;
}
-
+
// For backwards compatibility, do not check if amounts balance before signing in this case.
-
+
error = SignPSBT(psbtx, complete, sighash_type, sign, imbalance_ok, bip32derivs, n_signed, finalize);
if (error) {
return error;
diff --git a/test/bitcoin_functional/functional/.gitignore b/test/bitcoin_functional/functional/.gitignore
deleted file mode 100644
index cb41d94..0000000
--- a/test/bitcoin_functional/functional/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*.pyc
-cache
diff --git a/test/bitcoin_functional/functional/README.md b/test/bitcoin_functional/functional/README.md
deleted file mode 100644
index 82568f3..0000000
--- a/test/bitcoin_functional/functional/README.md
+++ /dev/null
@@ -1,158 +0,0 @@
-# Functional tests
-
-### Writing Functional Tests
-
-#### Example test
-
-The [example_test.py](example_test.py) is a heavily commented example of a test case that uses both
-the RPC and P2P interfaces. If you are writing your first test, copy that file
-and modify to fit your needs.
-
-#### Coverage
-
-Running `test_runner.py` with the `--coverage` argument tracks which RPCs are
-called by the tests and prints a report of uncovered RPCs in the summary. This
-can be used (along with the `--extended` argument) to find out which RPCs we
-don't have test cases for.
-
-#### Style guidelines
-
-- Where possible, try to adhere to [PEP-8 guidelines](https://www.python.org/dev/peps/pep-0008/)
-- Use a python linter like flake8 before submitting PRs to catch common style
- nits (eg trailing whitespace, unused imports, etc)
-- The oldest supported Python version is specified in [doc/dependencies.md](/doc/dependencies.md).
- Consider using [pyenv](https://github.com/pyenv/pyenv), which checks [.python-version](/.python-version),
- to prevent accidentally introducing modern syntax from an unsupported Python version.
- The Travis linter also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126).
-- See [the python lint script](/test/lint/lint-python.sh) that checks for violations that
- could lead to bugs and issues in the test code.
-- Avoid wildcard imports
-- Use a module-level docstring to describe what the test is testing, and how it
- is testing it.
-- When subclassing the BitcoinTestFramework, place overrides for the
- `set_test_params()`, `add_options()` and `setup_xxxx()` methods at the top of
- the subclass, then locally-defined helper methods, then the `run_test()` method.
-- Use `'{}'.format(x)` for string formatting, not `'%s' % x`.
-
-#### Naming guidelines
-
-- Name the test `<area>_test.py`, where area can be one of the following:
- - `feature` for tests for full features that aren't wallet/mining/mempool, eg `feature_rbf.py`
- - `interface` for tests for other interfaces (REST, ZMQ, etc), eg `interface_rest.py`
- - `mempool` for tests for mempool behaviour, eg `mempool_reorg.py`
- - `mining` for tests for mining features, eg `mining_prioritisetransaction.py`
- - `p2p` for tests that explicitly test the p2p interface, eg `p2p_disconnect_ban.py`
- - `rpc` for tests for individual RPC methods or features, eg `rpc_listtransactions.py`
- - `tool` for tests for tools, eg `tool_wallet.py`
- - `wallet` for tests for wallet features, eg `wallet_keypool.py`
-- use an underscore to separate words
- - exception: for tests for specific RPCs or command line options which don't include underscores, name the test after the exact RPC or argument name, eg `rpc_decodescript.py`, not `rpc_decode_script.py`
-- Don't use the redundant word `test` in the name, eg `interface_zmq.py`, not `interface_zmq_test.py`
-
-#### General test-writing advice
-
-- Set `self.num_nodes` to the minimum number of nodes necessary for the test.
- Having additional unrequired nodes adds to the execution time of the test as
- well as memory/CPU/disk requirements (which is important when running tests in
- parallel or on Travis).
-- Avoid stop-starting the nodes multiple times during the test if possible. A
- stop-start takes several seconds, so doing it several times blows up the
- runtime of the test.
-- Set the `self.setup_clean_chain` variable in `set_test_params()` to control whether
- or not to use the cached data directories. The cached data directories
- contain a 200-block pre-mined blockchain and wallets for four nodes. Each node
- has 25 mature blocks (25x50=1250 BTC) in its wallet.
-- When calling RPCs with lots of arguments, consider using named keyword
- arguments instead of positional arguments to make the intent of the call
- clear to readers.
-- Many of the core test framework classes such as `CBlock` and `CTransaction`
- don't allow new attributes to be added to their objects at runtime like
- typical Python objects allow. This helps prevent unpredictable side effects
- from typographical errors or usage of the objects outside of their intended
- purpose.
-
-#### RPC and P2P definitions
-
-Test writers may find it helpful to refer to the definitions for the RPC and
-P2P messages. These can be found in the following source files:
-
-- `/src/rpc/*` for RPCs
-- `/src/wallet/rpc*` for wallet RPCs
-- `ProcessMessage()` in `/src/net_processing.cpp` for parsing P2P messages
-
-#### Using the P2P interface
-
-- `messages.py` contains all the definitions for objects that pass
-over the network (`CBlock`, `CTransaction`, etc, along with the network-level
-wrappers for them, `msg_block`, `msg_tx`, etc).
-
-- P2P tests have two threads. One thread handles all network communication
-with the bitcoind(s) being tested in a callback-based event loop; the other
-implements the test logic.
-
-- `P2PConnection` is the class used to connect to a bitcoind. `P2PInterface`
-contains the higher level logic for processing P2P payloads and connecting to
-the Bitcoin Core node application logic. For custom behaviour, subclass the
-P2PInterface object and override the callback methods.
-
-- Can be used to write tests where specific P2P protocol behavior is tested.
-Examples tests are `p2p_unrequested_blocks.py`, `p2p_compactblocks.py`.
-
-### test-framework modules
-
-#### [test_framework/authproxy.py](test_framework/authproxy.py)
-Taken from the [python-bitcoinrpc repository](https://github.com/jgarzik/python-bitcoinrpc).
-
-#### [test_framework/test_framework.py](test_framework/test_framework.py)
-Base class for functional tests.
-
-#### [test_framework/util.py](test_framework/util.py)
-Generally useful functions.
-
-#### [test_framework/mininode.py](test_framework/mininode.py)
-Basic code to support P2P connectivity to a bitcoind.
-
-#### [test_framework/script.py](test_framework/script.py)
-Utilities for manipulating transaction scripts (originally from python-bitcoinlib)
-
-#### [test_framework/key.py](test_framework/key.py)
-Wrapper around OpenSSL EC_Key (originally from python-bitcoinlib)
-
-#### [test_framework/bignum.py](test_framework/bignum.py)
-Helpers for script.py
-
-#### [test_framework/blocktools.py](test_framework/blocktools.py)
-Helper functions for creating blocks and transactions.
-
-### Benchmarking with perf
-
-An easy way to profile node performance during functional tests is provided
-for Linux platforms using `perf`.
-
-Perf will sample the running node and will generate profile data in the node's
-datadir. The profile data can then be presented using `perf report` or a graphical
-tool like [hotspot](https://github.com/KDAB/hotspot).
-
-There are two ways of invoking perf: one is to use the `--perf` flag when
-running tests, which will profile each node during the entire test run: perf
-begins to profile when the node starts and ends when it shuts down. The other
-way is the use the `profile_with_perf` context manager, e.g.
-
-```python
-with node.profile_with_perf("send-big-msgs"):
- # Perform activity on the node you're interested in profiling, e.g.:
- for _ in range(10000):
- node.p2p.send_message(some_large_message)
-```
-
-To see useful textual output, run
-
-```sh
-perf report -i /path/to/datadir/send-big-msgs.perf.data.xxxx --stdio | c++filt | less
-```
-
-#### See also:
-
-- [Installing perf](https://askubuntu.com/q/50145)
-- [Perf examples](http://www.brendangregg.com/perf.html)
-- [Hotspot](https://github.com/KDAB/hotspot): a GUI for perf output analysis
diff --git a/test/bitcoin_functional/functional/combine_logs.py b/test/bitcoin_functional/functional/combine_logs.py
deleted file mode 100755
index 5bb3b5c..0000000
--- a/test/bitcoin_functional/functional/combine_logs.py
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/env python3
-"""Combine logs from multiple bitcoin nodes as well as the test_framework log.
-
-This streams the combined log output to stdout. Use combine_logs.py > outputfile
-to write to an outputfile.
-
-If no argument is provided, the most recent test directory will be used."""
-
-import argparse
-from collections import defaultdict, namedtuple
-import heapq
-import itertools
-import os
-import re
-import sys
-import tempfile
-
-# N.B.: don't import any local modules here - this script must remain executable
-# without the parent module installed.
-
-# Should match same symbol in `test_framework.test_framework`.
-TMPDIR_PREFIX = "bitcoin_func_test_"
-
-# Matches on the date format at the start of the log event
-TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{6})?Z")
-
-LogEvent = namedtuple('LogEvent', ['timestamp', 'source', 'event'])
-
-def main():
- """Main function. Parses args, reads the log files and renders them as text or html."""
- parser = argparse.ArgumentParser(
- description=__doc__, formatter_class=argparse.RawTextHelpFormatter)
- parser.add_argument(
- 'testdir', nargs='?', default='',
- help=('temporary test directory to combine logs from. '
- 'Defaults to the most recent'))
- parser.add_argument('-c', '--color', dest='color', action='store_true', help='outputs the combined log with events colored by source (requires posix terminal colors. Use less -r for viewing)')
- parser.add_argument('--html', dest='html', action='store_true', help='outputs the combined log as html. Requires jinja2. pip install jinja2')
- args = parser.parse_args()
-
- if args.html and args.color:
- print("Only one out of --color or --html should be specified")
- sys.exit(1)
-
- testdir = args.testdir or find_latest_test_dir()
-
- if not testdir:
- print("No test directories found")
- sys.exit(1)
-
- if not args.testdir:
- print("Opening latest test directory: {}".format(testdir), file=sys.stderr)
-
- log_events = read_logs(testdir)
-
- print_logs(log_events, color=args.color, html=args.html)
-
-def read_logs(tmp_dir):
- """Reads log files.
-
- Delegates to generator function get_log_events() to provide individual log events
- for each of the input log files."""
-
- files = [("test", "%s/test_framework.log" % tmp_dir)]
- for i in itertools.count():
- logfile = "{}/node{}/regtest/debug.log".format(tmp_dir, i)
- if not os.path.isfile(logfile):
- break
- files.append(("node%d" % i, logfile))
-
- return heapq.merge(*[get_log_events(source, f) for source, f in files])
-
-
-def find_latest_test_dir():
- """Returns the latest tmpfile test directory prefix."""
- tmpdir = tempfile.gettempdir()
-
- def join_tmp(basename):
- return os.path.join(tmpdir, basename)
-
- def is_valid_test_tmpdir(basename):
- fullpath = join_tmp(basename)
- return (
- os.path.isdir(fullpath)
- and basename.startswith(TMPDIR_PREFIX)
- and os.access(fullpath, os.R_OK)
- )
-
- testdir_paths = [
- join_tmp(name) for name in os.listdir(tmpdir) if is_valid_test_tmpdir(name)
- ]
-
- return max(testdir_paths, key=os.path.getmtime) if testdir_paths else None
-
-
-def get_log_events(source, logfile):
- """Generator function that returns individual log events.
-
- Log events may be split over multiple lines. We use the timestamp
- regex match as the marker for a new log event."""
- try:
- with open(logfile, 'r', encoding='utf-8') as infile:
- event = ''
- timestamp = ''
- for line in infile:
- # skip blank lines
- if line == '\n':
- continue
- # if this line has a timestamp, it's the start of a new log event.
- time_match = TIMESTAMP_PATTERN.match(line)
- if time_match:
- if event:
- yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())
- timestamp = time_match.group()
- if time_match.group(1) is None:
- # timestamp does not have microseconds. Add zeroes.
- timestamp_micro = timestamp.replace("Z", ".000000Z")
- line = line.replace(timestamp, timestamp_micro)
- timestamp = timestamp_micro
- event = line
- # if it doesn't have a timestamp, it's a continuation line of the previous log.
- else:
- # Add the line. Prefix with space equivalent to the source + timestamp so log lines are aligned
- event += " " + line
- # Flush the final event
- yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())
- except FileNotFoundError:
- print("File %s could not be opened. Continuing without it." % logfile, file=sys.stderr)
-
-def print_logs(log_events, color=False, html=False):
- """Renders the iterator of log events into text or html."""
- if not html:
- colors = defaultdict(lambda: '')
- if color:
- colors["test"] = "\033[0;36m" # CYAN
- colors["node0"] = "\033[0;34m" # BLUE
- colors["node1"] = "\033[0;32m" # GREEN
- colors["node2"] = "\033[0;31m" # RED
- colors["node3"] = "\033[0;33m" # YELLOW
- colors["reset"] = "\033[0m" # Reset font color
-
- for event in log_events:
- lines = event.event.splitlines()
- print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, lines[0], colors["reset"]))
- if len(lines) > 1:
- for line in lines[1:]:
- print("{0}{1}{2}".format(colors[event.source.rstrip()], line, colors["reset"]))
-
- else:
- try:
- import jinja2
- except ImportError:
- print("jinja2 not found. Try `pip install jinja2`")
- sys.exit(1)
- print(jinja2.Environment(loader=jinja2.FileSystemLoader('./'))
- .get_template('combined_log_template.html')
- .render(title="Combined Logs from testcase", log_events=[event._asdict() for event in log_events]))
-
-if __name__ == '__main__':
- main()
diff --git a/test/bitcoin_functional/functional/combined_log_template.html b/test/bitcoin_functional/functional/combined_log_template.html
deleted file mode 100644
index c0b854b..0000000
--- a/test/bitcoin_functional/functional/combined_log_template.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<html lang="en">
-<head>
- <title> {{ title }} </title>
- <style>
- ul {
- list-style-type: none;
- font-family: monospace;
- }
- li {
- border: 1px solid slategray;
- margin-bottom: 1px;
- }
- li:hover {
- filter: brightness(85%);
- }
- li.log-test {
- background-color: cyan;
- }
- li.log-node0 {
- background-color: lightblue;
- }
- li.log-node1 {
- background-color: lightgreen;
- }
- li.log-node2 {
- background-color: lightsalmon;
- }
- li.log-node3 {
- background-color: lightyellow;
- }
- </style>
-</head>
-<body>
-<ul>
-{% for event in log_events %}
-<li class="log-{{ event.source }}"> {{ event.source }} {{ event.timestamp }} {{event.event}}</li>
-{% endfor %}
-</ul>
-</body>
-</html>
diff --git a/test/bitcoin_functional/functional/create_cache.py b/test/bitcoin_functional/functional/create_cache.py
deleted file mode 100755
index edf16fa..0000000
--- a/test/bitcoin_functional/functional/create_cache.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Create a blockchain cache.
-
-Creating a cache of the blockchain speeds up test execution when running
-multiple functional tests. This helper script is executed by test_runner when multiple
-tests are being run in parallel.
-"""
-
-from test_framework.test_framework import BitcoinTestFramework
-
-class CreateCache(BitcoinTestFramework):
- # Test network and test nodes are not required:
-
- def set_test_params(self):
- self.num_nodes = 0
- self.supports_cli = True
-
- def setup_network(self):
- pass
-
- def run_test(self):
- pass
-
-if __name__ == '__main__':
- CreateCache().main()
diff --git a/test/bitcoin_functional/functional/data/invalid_txs.py b/test/bitcoin_functional/functional/data/invalid_txs.py
deleted file mode 100644
index 02deae9..0000000
--- a/test/bitcoin_functional/functional/data/invalid_txs.py
+++ /dev/null
@@ -1,180 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""
-Templates for constructing various sorts of invalid transactions.
-
-These templates (or an iterator over all of them) can be reused in different
-contexts to test using a number of invalid transaction types.
-
-Hopefully this makes it easier to get coverage of a full variety of tx
-validation checks through different interfaces (AcceptBlock, AcceptToMemPool,
-etc.) without repeating ourselves.
-
-Invalid tx cases not covered here can be found by running:
-
- $ diff \
- <(grep -IREho "bad-txns[a-zA-Z-]+" src | sort -u) \
- <(grep -IEho "bad-txns[a-zA-Z-]+" test/functional/data/invalid_txs.py | sort -u)
-
-"""
-import abc
-
-from test_framework.messages import CTransaction, CTxIn, CTxOut, COutPoint
-from test_framework import script as sc
-from test_framework.blocktools import create_tx_with_script, MAX_BLOCK_SIGOPS
-
-basic_p2sh = sc.CScript([sc.OP_HASH160, sc.hash160(sc.CScript([sc.OP_0])), sc.OP_EQUAL])
-
-
-class BadTxTemplate:
- """Allows simple construction of a certain kind of invalid tx. Base class to be subclassed."""
- __metaclass__ = abc.ABCMeta
-
- # The expected error code given by bitcoind upon submission of the tx.
- reject_reason = ""
-
- # Only specified if it differs from mempool acceptance error.
- block_reject_reason = ""
-
- # Do we expect to be disconnected after submitting this tx?
- expect_disconnect = False
-
- # Is this tx considered valid when included in a block, but not for acceptance into
- # the mempool (i.e. does it violate policy but not consensus)?
- valid_in_block = False
-
- def __init__(self, *, spend_tx=None, spend_block=None):
- self.spend_tx = spend_block.vtx[0] if spend_block else spend_tx
- self.spend_avail = sum(o.nValue for o in self.spend_tx.vout)
- self.valid_txin = CTxIn(COutPoint(self.spend_tx.sha256, 0), b"", 0xffffffff)
-
- @abc.abstractmethod
- def get_tx(self, *args, **kwargs):
- """Return a CTransaction that is invalid per the subclass."""
- pass
-
-
-class OutputMissing(BadTxTemplate):
- reject_reason = "bad-txns-vout-empty"
- expect_disconnect = False
-
- def get_tx(self):
- tx = CTransaction()
- tx.vin.append(self.valid_txin)
- tx.calc_sha256()
- return tx
-
-
-class InputMissing(BadTxTemplate):
- reject_reason = "bad-txns-vin-empty"
- expect_disconnect = False
-
- def get_tx(self):
- tx = CTransaction()
- tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE] * 100)))
- tx.calc_sha256()
- return tx
-
-
-class SizeTooSmall(BadTxTemplate):
- reject_reason = "tx-size-small"
- expect_disconnect = False
- valid_in_block = True
-
- def get_tx(self):
- tx = CTransaction()
- tx.vin.append(self.valid_txin)
- tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE])))
- tx.calc_sha256()
- return tx
-
-
-class BadInputOutpointIndex(BadTxTemplate):
- # Won't be rejected - nonexistent outpoint index is treated as an orphan since the coins
- # database can't distinguish between spent outpoints and outpoints which never existed.
- reject_reason = None
- expect_disconnect = False
-
- def get_tx(self):
- num_indices = len(self.spend_tx.vin)
- bad_idx = num_indices + 100
-
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256, bad_idx), b"", 0xffffffff))
- tx.vout.append(CTxOut(0, basic_p2sh))
- tx.calc_sha256()
- return tx
-
-
-class DuplicateInput(BadTxTemplate):
- reject_reason = 'bad-txns-inputs-duplicate'
- expect_disconnect = True
-
- def get_tx(self):
- tx = CTransaction()
- tx.vin.append(self.valid_txin)
- tx.vin.append(self.valid_txin)
- tx.vout.append(CTxOut(1, basic_p2sh))
- tx.calc_sha256()
- return tx
-
-
-class NonexistentInput(BadTxTemplate):
- reject_reason = None # Added as an orphan tx.
- expect_disconnect = False
-
- def get_tx(self):
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(self.spend_tx.sha256 + 1, 0), b"", 0xffffffff))
- tx.vin.append(self.valid_txin)
- tx.vout.append(CTxOut(1, basic_p2sh))
- tx.calc_sha256()
- return tx
-
-
-class SpendTooMuch(BadTxTemplate):
- reject_reason = 'bad-txns-in-belowout'
- expect_disconnect = True
-
- def get_tx(self):
- return create_tx_with_script(
- self.spend_tx, 0, script_pub_key=basic_p2sh, amount=(self.spend_avail + 1))
-
-
-class SpendNegative(BadTxTemplate):
- reject_reason = 'bad-txns-vout-negative'
- expect_disconnect = True
-
- def get_tx(self):
- return create_tx_with_script(self.spend_tx, 0, amount=-1)
-
-
-class InvalidOPIFConstruction(BadTxTemplate):
- reject_reason = "mandatory-script-verify-flag-failed (Invalid OP_IF construction)"
- expect_disconnect = True
- valid_in_block = True
-
- def get_tx(self):
- return create_tx_with_script(
- self.spend_tx, 0, script_sig=b'\x64' * 35,
- amount=(self.spend_avail // 2))
-
-
-class TooManySigops(BadTxTemplate):
- reject_reason = "bad-txns-too-many-sigops"
- block_reject_reason = "bad-blk-sigops, out-of-bounds SigOpCount"
- expect_disconnect = False
-
- def get_tx(self):
- lotsa_checksigs = sc.CScript([sc.OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))
- return create_tx_with_script(
- self.spend_tx, 0,
- script_pub_key=lotsa_checksigs,
- amount=1)
-
-
-def iter_all_templates():
- """Iterate through all bad transaction template types."""
- return BadTxTemplate.__subclasses__()
diff --git a/test/bitcoin_functional/functional/data/rpc_getblockstats.json b/test/bitcoin_functional/functional/data/rpc_getblockstats.json
deleted file mode 100644
index b8cabe1..0000000
--- a/test/bitcoin_functional/functional/data/rpc_getblockstats.json
+++ /dev/null
@@ -1,222 +0,0 @@
-{
- "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"
- ],
- "mocktime": 1525107225,
- "stats": [
- {
- "avgfee": 0,
- "avgfeerate": 0,
- "avgtxsize": 0,
- "blockhash": "1d7fe80f19d28b8e712af0399ac84006db753441f3033111b3a8d610afab364f",
- "feerate_percentiles": [
- 0,
- 0,
- 0,
- 0,
- 0
- ],
- "height": 101,
- "ins": 0,
- "maxfee": 0,
- "maxfeerate": 0,
- "maxtxsize": 0,
- "medianfee": 0,
- "mediantime": 1525107242,
- "mediantxsize": 0,
- "minfee": 0,
- "minfeerate": 0,
- "mintxsize": 0,
- "outs": 2,
- "subsidy": 5000000000,
- "swtotal_size": 0,
- "swtotal_weight": 0,
- "swtxs": 0,
- "time": 1525107243,
- "total_out": 0,
- "total_size": 0,
- "total_weight": 0,
- "totalfee": 0,
- "txs": 1,
- "utxo_increase": 2,
- "utxo_size_inc": 173
- },
- {
- "avgfee": 3760,
- "avgfeerate": 20,
- "avgtxsize": 187,
- "blockhash": "4e21a43675d7a41cb6b944e068c5bcd0a677baf658d9ebe021ae2d2f99397ccc",
- "height": 102,
- "feerate_percentiles": [
- 20,
- 20,
- 20,
- 20,
- 20
- ],
- "ins": 1,
- "maxfee": 3760,
- "maxfeerate": 20,
- "maxtxsize": 187,
- "medianfee": 3760,
- "mediantime": 1525107242,
- "mediantxsize": 187,
- "minfee": 3760,
- "minfeerate": 20,
- "mintxsize": 187,
- "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,
- "txs": 2,
- "utxo_increase": 3,
- "utxo_size_inc": 234
- },
- {
- "avgfee": 18960,
- "avgfeerate": 109,
- "avgtxsize": 228,
- "blockhash": "22d9b8b9c2a37c81515f3fc84f7241f6c07dbcea85ef16b00bcc33ae400a030f",
- "feerate_percentiles": [
- 20,
- 20,
- 20,
- 300,
- 300
- ],
- "height": 103,
- "ins": 3,
- "maxfee": 49800,
- "maxfeerate": 300,
- "maxtxsize": 248,
- "medianfee": 3760,
- "mediantime": 1525107243,
- "mediantxsize": 248,
- "minfee": 3320,
- "minfeerate": 20,
- "mintxsize": 188,
- "outs": 8,
- "subsidy": 5000000000,
- "swtotal_size": 496,
- "swtotal_weight": 1324,
- "swtxs": 2,
- "time": 1525107243,
- "total_out": 9999939360,
- "total_size": 684,
- "total_weight": 2076,
- "totalfee": 56880,
- "txs": 4,
- "utxo_increase": 5,
- "utxo_size_inc": 380
- }
- ]
-}
\ No newline at end of file
diff --git a/test/bitcoin_functional/functional/data/rpc_psbt.json b/test/bitcoin_functional/functional/data/rpc_psbt.json
deleted file mode 100644
index 57f2608..0000000
--- a/test/bitcoin_functional/functional/data/rpc_psbt.json
+++ /dev/null
@@ -1,131 +0,0 @@
-{
- "invalid" : [
- "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"
- ],
- "valid" : [
- "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"
- ],
- "creator" : [
- {
- "inputs" : [
- {
- "txid":"75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858",
- "vout":0
- },
- {
- "txid":"1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83",
- "vout":1
- }
- ],
- "outputs" : [
- {
- "bcrt1qmpwzkuwsqc9snjvgdt4czhjsnywa5yjdqpxskv":1.49990000
- },
- {
- "bcrt1qqzh2ngh97ru8dfvgma25d6r595wcwqy0cee4cc": 1
- }
- ],
- "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAAAAAA="
- }
- ],
- "signer" : [
- {
- "privkeys" : [
- "cP53pDbR5WtAD8dYAW9hhTjuvvTVaEiQBdrz9XPrgLBeRFiyCbQr",
- "cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4iSgw6d"
- ],
- "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
- "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
- },
- {
- "privkeys" : [
- "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
- "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
- ],
- "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
- "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210cwRAIgYxqYn+c4qSrQGYYCMxLBkhT+KAKznly8GsNniAbGksMCIDnbbDh70mdxbf2z1NjaULjoXSEzJrp8faqkwM5B65IjAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgICOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
- },
- {
- "privkeys" : [
- "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
- ],
- "psbt" : "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEBItPf9QUAAAAAGXapFNSO0xELlAFMsRS9Mtb00GbcdCVriKwAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=",
- "result" : "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEBItPf9QUAAAAAGXapFNSO0xELlAFMsRS9Mtb00GbcdCVriKwAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
- },
- {
- "privkeys" : [
- "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
- "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
- ],
- "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq8iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
- "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq8iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
- },
- {
- "privkeys" : [
- "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
- "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
- ],
- "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQABBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
- "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQABBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
- },
- {
- "privkeys" : [
- "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
- "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
- ],
- "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSrSIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
- "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSrSIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
- }
- ],
- "combiner" : [
- {
- "combine" : [
- "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"
- ],
- "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXRzBEAiBjGpif5zipKtAZhgIzEsGSFP4oArOeXLwaw2eIBsaSwwIgOdtsOHvSZ3Ft/bPU2NpQuOhdITMmunx9qqTAzkHrkiMBAQMEAQAAAAEER1IhApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/IQLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU211KuIgYClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8Q2QxqTwAAAIAAAACAAAAAgCIGAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXENkMak8AAACAAAAAgAEAAIAAAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IciAgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3EcwRAIgYut6VWEHp8c/RaxKtaHd329wdfsSdZaafzg+//eEvLICIAwF27dHDb8vCFV901bHMlwe0wkT6ZbNOECUXbEiKNpfASICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
- },
- {
- "combine" : [
- "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcICQ8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgJDwECAwQFBgcICQoLDA0ODwA=",
- "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcIEA8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCBAPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgQDwECAwQFBgcICQoLDA0ODwA="
- ],
- "result" : "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcICQ8BAgMEBQYHCAkKCwwNDg8KDwECAwQFBgcIEA8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PCg8BAgMEBQYHCBAPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgJDwECAwQFBgcICQoLDA0ODwoPAQIDBAUGBwgQDwECAwQFBgcICQoLDA0ODwA="
- }
- ],
- "finalizer" : [
- {
- "finalize" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEiAgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc0cwRAIgZfRbpZmLWaJ//hp77QFq8fH5DVSzqo90UKpfVqJRA70CIH9yRwOtHtuWaAsoS1bU/8uI9/t1nqu+CKow8puFE4PSAQEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
- "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
- }
- ],
- "extractor" : [
- {
- "extract" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==",
- "result" : "0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000"
- }
- ]
-}
\ No newline at end of file
diff --git a/test/bitcoin_functional/functional/example_test.py b/test/bitcoin_functional/functional/example_test.py
deleted file mode 100755
index f367e4f..0000000
--- a/test/bitcoin_functional/functional/example_test.py
+++ /dev/null
@@ -1,214 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2017-2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""An example functional test
-
-The module-level docstring should include a high-level description of
-what the test is doing. It's the first thing people see when they open
-the file and should give the reader information about *what* the test
-is testing and *how* it's being tested
-"""
-# Imports should be in PEP8 ordering (std library first, then third party
-# libraries then local imports).
-from collections import defaultdict
-
-# Avoid wildcard * imports
-from test_framework.blocktools import (create_block, create_coinbase)
-from test_framework.messages import CInv
-from test_framework.mininode import (
- P2PInterface,
- mininode_lock,
- msg_block,
- msg_getdata,
-)
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (
- assert_equal,
- connect_nodes,
- wait_until,
-)
-
-# P2PInterface is a class containing callbacks to be executed when a P2P
-# message is received from the node-under-test. Subclass P2PInterface and
-# override the on_*() methods if you need custom behaviour.
-class BaseNode(P2PInterface):
- def __init__(self):
- """Initialize the P2PInterface
-
- Used to initialize custom properties for the Node that aren't
- included by default in the base class. Be aware that the P2PInterface
- base class already stores a counter for each P2P message type and the
- last received message of each type, which should be sufficient for the
- needs of most tests.
-
- Call super().__init__() first for standard initialization and then
- initialize custom properties."""
- super().__init__()
- # Stores a dictionary of all blocks received
- self.block_receive_map = defaultdict(int)
-
- def on_block(self, message):
- """Override the standard on_block callback
-
- Store the hash of a received block in the dictionary."""
- message.block.calc_sha256()
- self.block_receive_map[message.block.sha256] += 1
-
- def on_inv(self, message):
- """Override the standard on_inv callback"""
- pass
-
-def custom_function():
- """Do some custom behaviour
-
- If this function is more generally useful for other tests, consider
- moving it to a module in test_framework."""
- # self.log.info("running custom_function") # Oops! Can't run self.log outside the BitcoinTestFramework
- pass
-
-
-class ExampleTest(BitcoinTestFramework):
- # Each functional test is a subclass of the BitcoinTestFramework class.
-
- # Override the set_test_params(), skip_test_if_missing_module(), add_options(), setup_chain(), setup_network()
- # and setup_nodes() methods to customize the test setup as required.
-
- def set_test_params(self):
- """Override test parameters for your individual test.
-
- This method must be overridden and num_nodes must be explicitly set."""
- self.setup_clean_chain = True
- self.num_nodes = 3
- # Use self.extra_args to change command-line arguments for the nodes
- self.extra_args = [[], ["-logips"], []]
-
- # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test()
-
- # Use skip_test_if_missing_module() to skip the test if your test requires certain modules to be present.
- # This test uses generate which requires wallet to be compiled
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
- # Use add_options() to add specific command-line options for your test.
- # In practice this is not used very much, since the tests are mostly written
- # to be run in automated environments without command-line options.
- # def add_options()
- # pass
-
- # Use setup_chain() to customize the node data directories. In practice
- # this is not used very much since the default behaviour is almost always
- # fine
- # def setup_chain():
- # pass
-
- def setup_network(self):
- """Setup the test network topology
-
- Often you won't need to override this, since the standard network topology
- (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests.
-
- If you do override this method, remember to start the nodes, assign
- them to self.nodes, connect them and then sync."""
-
- self.setup_nodes()
-
- # In this test, we're not connecting node2 to node0 or node1. Calls to
- # sync_all() should not include node2, since we're not expecting it to
- # sync.
- connect_nodes(self.nodes[0], 1)
- self.sync_all([self.nodes[0:2]])
-
- # Use setup_nodes() to customize the node start behaviour (for example if
- # you don't want to start all nodes at the start of the test).
- # def setup_nodes():
- # pass
-
- def custom_method(self):
- """Do some custom behaviour for this test
-
- Define it in a method here because you're going to use it repeatedly.
- If you think it's useful in general, consider moving it to the base
- BitcoinTestFramework class so other tests can use it."""
-
- self.log.info("Running custom_method")
-
- def run_test(self):
- """Main test logic"""
-
- # Create P2P connections will wait for a verack to make sure the connection is fully up
- self.nodes[0].add_p2p_connection(BaseNode())
-
- # Generating a block on one of the nodes will get us out of IBD
- blocks = [int(self.nodes[0].generate(nblocks=1)[0], 16)]
- self.sync_all([self.nodes[0:2]])
-
- # Notice above how we called an RPC by calling a method with the same
- # name on the node object. Notice also how we used a keyword argument
- # to specify a named RPC argument. Neither of those are defined on the
- # node object. Instead there's some __getattr__() magic going on under
- # the covers to dispatch unrecognised attribute calls to the RPC
- # interface.
-
- # Logs are nice. Do plenty of them. They can be used in place of comments for
- # breaking the test into sub-sections.
- self.log.info("Starting test!")
-
- self.log.info("Calling a custom function")
- custom_function()
-
- self.log.info("Calling a custom method")
- self.custom_method()
-
- self.log.info("Create some blocks")
- self.tip = int(self.nodes[0].getbestblockhash(), 16)
- self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
-
- height = self.nodes[0].getblockcount()
-
- for i in range(10):
- # Use the mininode and blocktools functionality to manually build a block
- # Calling the generate() rpc is easier, but this allows us to exactly
- # control the blocks and transactions.
- block = create_block(self.tip, create_coinbase(height+1), self.block_time)
- block.solve()
- block_message = msg_block(block)
- # Send message is used to send a P2P message to the node over our P2PInterface
- self.nodes[0].p2p.send_message(block_message)
- self.tip = block.sha256
- blocks.append(self.tip)
- self.block_time += 1
- height += 1
-
- self.log.info("Wait for node1 to reach current tip (height 11) using RPC")
- self.nodes[1].waitforblockheight(11)
-
- self.log.info("Connect node2 and node1")
- connect_nodes(self.nodes[1], 2)
-
- self.log.info("Add P2P connection to node2")
- self.nodes[0].disconnect_p2ps()
-
- self.nodes[2].add_p2p_connection(BaseNode())
-
- self.log.info("Wait for node2 reach current tip. Test that it has propagated all the blocks to us")
-
- getdata_request = msg_getdata()
- for block in blocks:
- getdata_request.inv.append(CInv(2, block))
- self.nodes[2].p2p.send_message(getdata_request)
-
- # wait_until() will loop until a predicate condition is met. Use it to test properties of the
- # P2PInterface objects.
- wait_until(lambda: sorted(blocks) == sorted(list(self.nodes[2].p2p.block_receive_map.keys())), timeout=5, lock=mininode_lock)
-
- self.log.info("Check that each block was received only once")
- # The network thread uses a global lock on data access to the P2PConnection objects when sending and receiving
- # messages. The test thread should acquire the global lock before accessing any P2PConnection data to avoid locking
- # and synchronization issues. Note wait_until() acquires this global lock when testing the predicate.
- with mininode_lock:
- for block in self.nodes[2].p2p.block_receive_map.values():
- assert_equal(block, 1)
-
-if __name__ == '__main__':
- ExampleTest().main()
diff --git a/test/bitcoin_functional/functional/feature_assumevalid.py b/test/bitcoin_functional/functional/feature_assumevalid.py
deleted file mode 100755
index 12a4ce9..0000000
--- a/test/bitcoin_functional/functional/feature_assumevalid.py
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Test logic for skipping signature validation on old blocks.
-
-Test logic for skipping signature validation on blocks which we've assumed
-valid (https://github.com/bitcoin/bitcoin/pull/9484)
-
-We build a chain that includes and invalid signature for one of the
-transactions:
-
- 0: genesis block
- 1: block 1 with coinbase transaction output.
- 2-101: bury that block with 100 blocks so the coinbase transaction
- output can be spent
- 102: a block containing a transaction spending the coinbase
- transaction output. The transaction has an invalid signature.
- 103-2202: bury the bad block with just over two weeks' worth of blocks
- (2100 blocks)
-
-Start three nodes:
-
- - node0 has no -assumevalid parameter. Try to sync to block 2202. It will
- reject block 102 and only sync as far as block 101
- - node1 has -assumevalid set to the hash of block 102. Try to sync to
- block 2202. node1 will sync all the way to block 2202.
- - node2 has -assumevalid set to the hash of block 102. Try to sync to
- block 200. node2 will reject block 102 since it's assumed valid, but it
- isn't buried by at least two weeks' work.
-"""
-import time
-
-from test_framework.blocktools import (create_block, create_coinbase)
-from test_framework.key import CECKey
-from test_framework.messages import (
- CBlockHeader,
- COutPoint,
- CTransaction,
- CTxIn,
- CTxOut,
- msg_block,
- msg_headers
-)
-from test_framework.mininode import P2PInterface
-from test_framework.script import (CScript, OP_TRUE)
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
-
-class BaseNode(P2PInterface):
- def send_header_for_blocks(self, new_blocks):
- headers_message = msg_headers()
- headers_message.headers = [CBlockHeader(b) for b in new_blocks]
- self.send_message(headers_message)
-
-class AssumeValidTest(BitcoinTestFramework):
- def set_test_params(self):
- self.setup_clean_chain = True
- self.num_nodes = 3
-
- def setup_network(self):
- self.add_nodes(3)
- # Start node0. We don't start the other nodes yet since
- # we need to pre-mine a block with an invalid transaction
- # signature so we can pass in the block hash as assumevalid.
- self.start_node(0)
-
- def send_blocks_until_disconnected(self, p2p_conn):
- """Keep sending blocks to the node until we're disconnected."""
- for i in range(len(self.blocks)):
- if not p2p_conn.is_connected:
- break
- try:
- p2p_conn.send_message(msg_block(self.blocks[i]))
- except IOError as e:
- assert not p2p_conn.is_connected
- break
-
- def assert_blockchain_height(self, node, height):
- """Wait until the blockchain is no longer advancing and verify it's reached the expected height."""
- last_height = node.getblock(node.getbestblockhash())['height']
- timeout = 10
- while True:
- time.sleep(0.25)
- current_height = node.getblock(node.getbestblockhash())['height']
- if current_height != last_height:
- last_height = current_height
- if timeout < 0:
- assert False, "blockchain too short after timeout: %d" % current_height
- timeout - 0.25
- continue
- elif current_height > height:
- assert False, "blockchain too long: %d" % current_height
- elif current_height == height:
- break
-
- def run_test(self):
- p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
-
- # Build the blockchain
- self.tip = int(self.nodes[0].getbestblockhash(), 16)
- self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
-
- self.blocks = []
-
- # Get a pubkey for the coinbase TXO
- coinbase_key = CECKey()
- coinbase_key.set_secretbytes(b"horsebattery")
- coinbase_pubkey = coinbase_key.get_pubkey()
-
- # Create the first block with a coinbase output to our key
- height = 1
- block = create_block(self.tip, create_coinbase(height, coinbase_pubkey), self.block_time)
- self.blocks.append(block)
- self.block_time += 1
- block.solve()
- # Save the coinbase for later
- self.block1 = block
- self.tip = block.sha256
- height += 1
-
- # Bury the block 100 deep so the coinbase output is spendable
- for i in range(100):
- block = create_block(self.tip, create_coinbase(height), self.block_time)
- block.solve()
- self.blocks.append(block)
- self.tip = block.sha256
- self.block_time += 1
- height += 1
-
- # Create a transaction spending the coinbase output with an invalid (null) signature
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(self.block1.vtx[0].sha256, 0), scriptSig=b""))
- tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE])))
- tx.calc_sha256()
-
- block102 = create_block(self.tip, create_coinbase(height), self.block_time)
- self.block_time += 1
- block102.vtx.extend([tx])
- block102.hashMerkleRoot = block102.calc_merkle_root()
- block102.rehash()
- block102.solve()
- self.blocks.append(block102)
- self.tip = block102.sha256
- self.block_time += 1
- height += 1
-
- # Bury the assumed valid block 2100 deep
- for i in range(2100):
- block = create_block(self.tip, create_coinbase(height), self.block_time)
- block.nVersion = 4
- block.solve()
- self.blocks.append(block)
- self.tip = block.sha256
- self.block_time += 1
- height += 1
-
- self.nodes[0].disconnect_p2ps()
-
- # Start node1 and node2 with assumevalid so they accept a block with a bad signature.
- self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)])
- self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)])
-
- p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
- p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
- p2p2 = self.nodes[2].add_p2p_connection(BaseNode())
-
- # send header lists to all three nodes
- p2p0.send_header_for_blocks(self.blocks[0:2000])
- p2p0.send_header_for_blocks(self.blocks[2000:])
- p2p1.send_header_for_blocks(self.blocks[0:2000])
- p2p1.send_header_for_blocks(self.blocks[2000:])
- p2p2.send_header_for_blocks(self.blocks[0:200])
-
- # Send blocks to node0. Block 102 will be rejected.
- self.send_blocks_until_disconnected(p2p0)
- self.assert_blockchain_height(self.nodes[0], 101)
-
- # Send all blocks to node1. All blocks will be accepted.
- for i in range(2202):
- p2p1.send_message(msg_block(self.blocks[i]))
- # Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.
- p2p1.sync_with_ping(150)
- assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)
-
- # Send blocks to node2. Block 102 will be rejected.
- self.send_blocks_until_disconnected(p2p2)
- self.assert_blockchain_height(self.nodes[2], 101)
-
-if __name__ == '__main__':
- AssumeValidTest().main()
diff --git a/test/bitcoin_functional/functional/feature_bip68_sequence.py b/test/bitcoin_functional/functional/feature_bip68_sequence.py
deleted file mode 100755
index 8466f85..0000000
--- a/test/bitcoin_functional/functional/feature_bip68_sequence.py
+++ /dev/null
@@ -1,402 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Test BIP68 implementation."""
-
-import time
-
-from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
-from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, ToHex
-from test_framework.script import CScript
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, bytes_to_hex_str, get_bip9_status, satoshi_round, sync_blocks
-
-SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)
-SEQUENCE_LOCKTIME_TYPE_FLAG = (1<<22) # this means use time (0 means height)
-SEQUENCE_LOCKTIME_GRANULARITY = 9 # this is a bit-shift
-SEQUENCE_LOCKTIME_MASK = 0x0000ffff
-
-# RPC error for non-BIP68 final transactions
-NOT_FINAL_ERROR = "non-BIP68-final (code 64)"
-
-class BIP68Test(BitcoinTestFramework):
- def set_test_params(self):
- self.num_nodes = 2
- self.extra_args = [[], ["-acceptnonstdtxn=0"]]
-
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
- def run_test(self):
- self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
-
- # Generate some coins
- self.nodes[0].generate(110)
-
- self.log.info("Running test disable flag")
- self.test_disable_flag()
-
- self.log.info("Running test sequence-lock-confirmed-inputs")
- self.test_sequence_lock_confirmed_inputs()
-
- self.log.info("Running test sequence-lock-unconfirmed-inputs")
- self.test_sequence_lock_unconfirmed_inputs()
-
- self.log.info("Running test BIP68 not consensus before versionbits activation")
- self.test_bip68_not_consensus()
-
- self.log.info("Activating BIP68 (and 112/113)")
- self.activateCSV()
-
- self.log.info("Verifying nVersion=2 transactions are standard.")
- self.log.info("Note that nVersion=2 transactions are always standard (independent of BIP68 activation status).")
- self.test_version2_relay()
-
- self.log.info("Passed")
-
- # Test that BIP68 is not in effect if tx version is 1, or if
- # the first sequence bit is set.
- def test_disable_flag(self):
- # Create some unconfirmed inputs
- new_addr = self.nodes[0].getnewaddress()
- self.nodes[0].sendtoaddress(new_addr, 2) # send 2 BTC
-
- utxos = self.nodes[0].listunspent(0, 0)
- assert(len(utxos) > 0)
-
- utxo = utxos[0]
-
- tx1 = CTransaction()
- value = int(satoshi_round(utxo["amount"] - self.relayfee)*COIN)
-
- # Check that the disable flag disables relative locktime.
- # If sequence locks were used, this would require 1 block for the
- # input to mature.
- sequence_value = SEQUENCE_LOCKTIME_DISABLE_FLAG | 1
- tx1.vin = [CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), nSequence=sequence_value)]
- tx1.vout = [CTxOut(value, CScript([b'a']))]
-
- tx1_signed = self.nodes[0].signrawtransactionwithwallet(ToHex(tx1))["hex"]
- tx1_id = self.nodes[0].sendrawtransaction(tx1_signed)
- tx1_id = int(tx1_id, 16)
-
- # This transaction will enable sequence-locks, so this transaction should
- # fail
- tx2 = CTransaction()
- tx2.nVersion = 2
- sequence_value = sequence_value & 0x7fffffff
- tx2.vin = [CTxIn(COutPoint(tx1_id, 0), nSequence=sequence_value)]
- tx2.vout = [CTxOut(int(value - self.relayfee * COIN), CScript([b'a' * 35]))]
- tx2.rehash()
-
- assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx2))
-
- # Setting the version back down to 1 should disable the sequence lock,
- # so this should be accepted.
- tx2.nVersion = 1
-
- self.nodes[0].sendrawtransaction(ToHex(tx2))
-
- # Calculate the median time past of a prior block ("confirmations" before
- # the current tip).
- def get_median_time_past(self, confirmations):
- block_hash = self.nodes[0].getblockhash(self.nodes[0].getblockcount()-confirmations)
- return self.nodes[0].getblockheader(block_hash)["mediantime"]
-
- # Test that sequence locks are respected for transactions spending confirmed inputs.
- def test_sequence_lock_confirmed_inputs(self):
- # Create lots of confirmed utxos, and use them to generate lots of random
- # transactions.
- max_outputs = 50
- addresses = []
- while len(addresses) < max_outputs:
- addresses.append(self.nodes[0].getnewaddress())
- while len(self.nodes[0].listunspent()) < 200:
- import random
- random.shuffle(addresses)
- num_outputs = random.randint(1, max_outputs)
- outputs = {}
- for i in range(num_outputs):
- outputs[addresses[i]] = random.randint(1, 20)*0.01
- self.nodes[0].sendmany("", outputs)
- self.nodes[0].generate(1)
-
- utxos = self.nodes[0].listunspent()
-
- # Try creating a lot of random transactions.
- # Each time, choose a random number of inputs, and randomly set
- # some of those inputs to be sequence locked (and randomly choose
- # between height/time locking). Small random chance of making the locks
- # all pass.
- for i in range(400):
- # Randomly choose up to 10 inputs
- num_inputs = random.randint(1, 10)
- random.shuffle(utxos)
-
- # Track whether any sequence locks used should fail
- should_pass = True
-
- # Track whether this transaction was built with sequence locks
- using_sequence_locks = False
-
- tx = CTransaction()
- tx.nVersion = 2
- value = 0
- for j in range(num_inputs):
- sequence_value = 0xfffffffe # this disables sequence locks
-
- # 50% chance we enable sequence locks
- if random.randint(0,1):
- using_sequence_locks = True
-
- # 10% of the time, make the input sequence value pass
- input_will_pass = (random.randint(1,10) == 1)
- sequence_value = utxos[j]["confirmations"]
- if not input_will_pass:
- sequence_value += 1
- should_pass = False
-
- # Figure out what the median-time-past was for the confirmed input
- # Note that if an input has N confirmations, we're going back N blocks
- # from the tip so that we're looking up MTP of the block
- # PRIOR to the one the input appears in, as per the BIP68 spec.
- orig_time = self.get_median_time_past(utxos[j]["confirmations"])
- cur_time = self.get_median_time_past(0) # MTP of the tip
-
- # can only timelock this input if it's not too old -- otherwise use height
- can_time_lock = True
- if ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY) >= SEQUENCE_LOCKTIME_MASK:
- can_time_lock = False
-
- # if time-lockable, then 50% chance we make this a time lock
- if random.randint(0,1) and can_time_lock:
- # Find first time-lock value that fails, or latest one that succeeds
- time_delta = sequence_value << SEQUENCE_LOCKTIME_GRANULARITY
- if input_will_pass and time_delta > cur_time - orig_time:
- sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY)
- elif (not input_will_pass and time_delta <= cur_time - orig_time):
- sequence_value = ((cur_time - orig_time) >> SEQUENCE_LOCKTIME_GRANULARITY)+1
- sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG
- tx.vin.append(CTxIn(COutPoint(int(utxos[j]["txid"], 16), utxos[j]["vout"]), nSequence=sequence_value))
- value += utxos[j]["amount"]*COIN
- # Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output
- tx_size = len(ToHex(tx))//2 + 120*num_inputs + 50
- tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), CScript([b'a'])))
- rawtx = self.nodes[0].signrawtransactionwithwallet(ToHex(tx))["hex"]
-
- if (using_sequence_locks and not should_pass):
- # This transaction should be rejected
- assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, rawtx)
- else:
- # This raw transaction should be accepted
- self.nodes[0].sendrawtransaction(rawtx)
- utxos = self.nodes[0].listunspent()
-
- # Test that sequence locks on unconfirmed inputs must have nSequence
- # height or time of 0 to be accepted.
- # Then test that BIP68-invalid transactions are removed from the mempool
- # after a reorg.
- def test_sequence_lock_unconfirmed_inputs(self):
- # Store height so we can easily reset the chain at the end of the test
- cur_height = self.nodes[0].getblockcount()
-
- # Create a mempool tx.
- txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)
- tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid))
- tx1.rehash()
-
- # Anyone-can-spend mempool tx.
- # Sequence lock of 0 should pass.
- tx2 = CTransaction()
- tx2.nVersion = 2
- tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]
- tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))]
- tx2_raw = self.nodes[0].signrawtransactionwithwallet(ToHex(tx2))["hex"]
- tx2 = FromHex(tx2, tx2_raw)
- tx2.rehash()
-
- self.nodes[0].sendrawtransaction(tx2_raw)
-
- # Create a spend of the 0th output of orig_tx with a sequence lock
- # of 1, and test what happens when submitting.
- # orig_tx.vout[0] must be an anyone-can-spend output
- def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock):
- sequence_value = 1
- if not use_height_lock:
- sequence_value |= SEQUENCE_LOCKTIME_TYPE_FLAG
-
- tx = CTransaction()
- tx.nVersion = 2
- tx.vin = [CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)]
- tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN), CScript([b'a' * 35]))]
- tx.rehash()
-
- if (orig_tx.hash in node.getrawmempool()):
- # sendrawtransaction should fail if the tx is in the mempool
- assert_raises_rpc_error(-26, NOT_FINAL_ERROR, node.sendrawtransaction, ToHex(tx))
- else:
- # sendrawtransaction should succeed if the tx is not in the mempool
- node.sendrawtransaction(ToHex(tx))
-
- return tx
-
- test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True)
- test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)
-
- # Now mine some blocks, but make sure tx2 doesn't get mined.
- # Use prioritisetransaction to lower the effective feerate to 0
- self.nodes[0].prioritisetransaction(txid=tx2.hash, fee_delta=int(-self.relayfee*COIN))
- cur_time = int(time.time())
- for i in range(10):
- self.nodes[0].setmocktime(cur_time + 600)
- self.nodes[0].generate(1)
- cur_time += 600
-
- assert(tx2.hash in self.nodes[0].getrawmempool())
-
- test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True)
- test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)
-
- # Mine tx2, and then try again
- self.nodes[0].prioritisetransaction(txid=tx2.hash, fee_delta=int(self.relayfee*COIN))
-
- # Advance the time on the node so that we can test timelocks
- self.nodes[0].setmocktime(cur_time+600)
- self.nodes[0].generate(1)
- assert(tx2.hash not in self.nodes[0].getrawmempool())
-
- # Now that tx2 is not in the mempool, a sequence locked spend should
- # succeed
- tx3 = test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)
- assert(tx3.hash in self.nodes[0].getrawmempool())
-
- self.nodes[0].generate(1)
- assert(tx3.hash not in self.nodes[0].getrawmempool())
-
- # One more test, this time using height locks
- tx4 = test_nonzero_locks(tx3, self.nodes[0], self.relayfee, use_height_lock=True)
- assert(tx4.hash in self.nodes[0].getrawmempool())
-
- # Now try combining confirmed and unconfirmed inputs
- tx5 = test_nonzero_locks(tx4, self.nodes[0], self.relayfee, use_height_lock=True)
- assert(tx5.hash not in self.nodes[0].getrawmempool())
-
- utxos = self.nodes[0].listunspent()
- tx5.vin.append(CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]), nSequence=1))
- tx5.vout[0].nValue += int(utxos[0]["amount"]*COIN)
- raw_tx5 = self.nodes[0].signrawtransactionwithwallet(ToHex(tx5))["hex"]
-
- assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, raw_tx5)
-
- # Test mempool-BIP68 consistency after reorg
- #
- # State of the transactions in the last blocks:
- # ... -> [ tx2 ] -> [ tx3 ]
- # tip-1 tip
- # And currently tx4 is in the mempool.
- #
- # If we invalidate the tip, tx3 should get added to the mempool, causing
- # tx4 to be removed (fails sequence-lock).
- self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
- assert(tx4.hash not in self.nodes[0].getrawmempool())
- assert(tx3.hash in self.nodes[0].getrawmempool())
-
- # Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in
- # diagram above).
- # This would cause tx2 to be added back to the mempool, which in turn causes
- # tx3 to be removed.
- tip = int(self.nodes[0].getblockhash(self.nodes[0].getblockcount()-1), 16)
- height = self.nodes[0].getblockcount()
- for i in range(2):
- block = create_block(tip, create_coinbase(height), cur_time)
- block.nVersion = 3
- block.rehash()
- block.solve()
- tip = block.sha256
- height += 1
- self.nodes[0].submitblock(ToHex(block))
- cur_time += 1
-
- mempool = self.nodes[0].getrawmempool()
- assert(tx3.hash not in mempool)
- assert(tx2.hash in mempool)
-
- # Reset the chain and get rid of the mocktimed-blocks
- self.nodes[0].setmocktime(0)
- self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1))
- self.nodes[0].generate(10)
-
- # Make sure that BIP68 isn't being used to validate blocks, prior to
- # versionbits activation. If more blocks are mined prior to this test
- # being run, then it's possible the test has activated the soft fork, and
- # this test should be moved to run earlier, or deleted.
- def test_bip68_not_consensus(self):
- assert(get_bip9_status(self.nodes[0], 'csv')['status'] != 'active')
- txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)
-
- tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid))
- tx1.rehash()
-
- # Make an anyone-can-spend transaction
- tx2 = CTransaction()
- tx2.nVersion = 1
- tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]
- tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))]
-
- # sign tx2
- tx2_raw = self.nodes[0].signrawtransactionwithwallet(ToHex(tx2))["hex"]
- tx2 = FromHex(tx2, tx2_raw)
- tx2.rehash()
-
- self.nodes[0].sendrawtransaction(ToHex(tx2))
-
- # Now make an invalid spend of tx2 according to BIP68
- sequence_value = 100 # 100 block relative locktime
-
- tx3 = CTransaction()
- tx3.nVersion = 2
- tx3.vin = [CTxIn(COutPoint(tx2.sha256, 0), nSequence=sequence_value)]
- tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), CScript([b'a' * 35]))]
- tx3.rehash()
-
- assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx3))
-
- # make a block that violates bip68; ensure that the tip updates
- tip = int(self.nodes[0].getbestblockhash(), 16)
- block = create_block(tip, create_coinbase(self.nodes[0].getblockcount()+1))
- block.nVersion = 3
- block.vtx.extend([tx1, tx2, tx3])
- block.hashMerkleRoot = block.calc_merkle_root()
- block.rehash()
- add_witness_commitment(block)
- block.solve()
-
- self.nodes[0].submitblock(bytes_to_hex_str(block.serialize(True)))
- assert_equal(self.nodes[0].getbestblockhash(), block.hash)
-
- def activateCSV(self):
- # activation should happen at block height 432 (3 periods)
- # getblockchaininfo will show CSV as active at block 431 (144 * 3 -1) since it's returning whether CSV is active for the next block.
- min_activation_height = 432
- height = self.nodes[0].getblockcount()
- assert_greater_than(min_activation_height - height, 2)
- self.nodes[0].generate(min_activation_height - height - 2)
- assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "locked_in")
- self.nodes[0].generate(1)
- assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "active")
- sync_blocks(self.nodes)
-
- # Use self.nodes[1] to test that version 2 transactions are standard.
- def test_version2_relay(self):
- inputs = [ ]
- outputs = { self.nodes[1].getnewaddress() : 1.0 }
- rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
- rawtxfund = self.nodes[1].fundrawtransaction(rawtx)['hex']
- tx = FromHex(CTransaction(), rawtxfund)
- tx.nVersion = 2
- tx_signed = self.nodes[1].signrawtransactionwithwallet(ToHex(tx))["hex"]
- self.nodes[1].sendrawtransaction(tx_signed)
-
-if __name__ == '__main__':
- BIP68Test().main()
diff --git a/test/bitcoin_functional/functional/feature_block.py b/test/bitcoin_functional/functional/feature_block.py
deleted file mode 100755
index 5253ff7..0000000
--- a/test/bitcoin_functional/functional/feature_block.py
+++ /dev/null
@@ -1,1386 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2015-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.
-"""Test block processing."""
-import copy
-import struct
-import time
-
-from test_framework.blocktools import (
- create_block,
- create_coinbase,
- create_tx_with_script,
- get_legacy_sigopcount_block,
- MAX_BLOCK_SIGOPS,
-)
-from test_framework.key import CECKey
-from test_framework.messages import (
- CBlock,
- COIN,
- COutPoint,
- CTransaction,
- CTxIn,
- CTxOut,
- MAX_BLOCK_BASE_SIZE,
- uint256_from_compact,
- uint256_from_str,
-)
-from test_framework.mininode import P2PDataStore
-from test_framework.script import (
- CScript,
- MAX_SCRIPT_ELEMENT_SIZE,
- OP_2DUP,
- OP_CHECKMULTISIG,
- OP_CHECKMULTISIGVERIFY,
- OP_CHECKSIG,
- OP_CHECKSIGVERIFY,
- OP_ELSE,
- OP_ENDIF,
- OP_EQUAL,
- OP_DROP,
- OP_FALSE,
- OP_HASH160,
- OP_IF,
- OP_INVALIDOPCODE,
- OP_RETURN,
- OP_TRUE,
- SIGHASH_ALL,
- SignatureHash,
- hash160,
-)
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
-from data import invalid_txs
-
-# Use this class for tests that require behavior other than normal "mininode" behavior.
-# For now, it is used to serialize a bloated varint (b64).
-class CBrokenBlock(CBlock):
- def initialize(self, base_block):
- self.vtx = copy.deepcopy(base_block.vtx)
- self.hashMerkleRoot = self.calc_merkle_root()
-
- def serialize(self, with_witness=False):
- r = b""
- r += super(CBlock, self).serialize()
- r += struct.pack("<BQ", 255, len(self.vtx))
- for tx in self.vtx:
- if with_witness:
- r += tx.serialize_with_witness()
- else:
- r += tx.serialize_without_witness()
- return r
-
- def normal_serialize(self):
- return super().serialize()
-
-class FullBlockTest(BitcoinTestFramework):
- def set_test_params(self):
- self.num_nodes = 1
- self.setup_clean_chain = True
- self.extra_args = [[]]
-
- def run_test(self):
- node = self.nodes[0] # convenience reference to the node
-
- self.bootstrap_p2p() # Add one p2p connection to the node
-
- self.block_heights = {}
- self.coinbase_key = CECKey()
- self.coinbase_key.set_secretbytes(b"horsebattery")
- self.coinbase_pubkey = self.coinbase_key.get_pubkey()
- self.tip = None
- self.blocks = {}
- self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
- self.block_heights[self.genesis_hash] = 0
- self.spendable_outputs = []
-
- # Create a new block
- b0 = self.next_block(0)
- self.save_spendable_output()
- self.sync_blocks([b0])
-
- # These constants chosen specifically to trigger an immature coinbase spend
- # at a certain time below.
- NUM_BUFFER_BLOCKS_TO_GENERATE = 99
- NUM_OUTPUTS_TO_COLLECT = 33
-
- # Allow the block to mature
- blocks = []
- for i in range(NUM_BUFFER_BLOCKS_TO_GENERATE):
- blocks.append(self.next_block("maturitybuffer.{}".format(i)))
- self.save_spendable_output()
- self.sync_blocks(blocks)
-
- # collect spendable outputs now to avoid cluttering the code later on
- out = []
- for i in range(NUM_OUTPUTS_TO_COLLECT):
- out.append(self.get_spendable_output())
-
- # Start by building a couple of blocks on top (which output is spent is
- # in parentheses):
- # genesis -> b1 (0) -> b2 (1)
- b1 = self.next_block(1, spend=out[0])
- self.save_spendable_output()
-
- b2 = self.next_block(2, spend=out[1])
- self.save_spendable_output()
-
- self.sync_blocks([b1, b2], timeout=4)
-
- # Select a txn with an output eligible for spending. This won't actually be spent,
- # since we're testing submission of a series of blocks with invalid txns.
- attempt_spend_tx = out[2]
-
- # Submit blocks for rejection, each of which contains a single transaction
- # (aside from coinbase) which should be considered invalid.
- for TxTemplate in invalid_txs.iter_all_templates():
- template = TxTemplate(spend_tx=attempt_spend_tx)
-
- if template.valid_in_block:
- continue
-
- self.log.info("Reject block with invalid tx: %s", TxTemplate.__name__)
- blockname = "for_invalid.%s" % TxTemplate.__name__
- badblock = self.next_block(blockname)
- badtx = template.get_tx()
- if TxTemplate != invalid_txs.InputMissing:
- self.sign_tx(badtx, attempt_spend_tx)
- else:
- # Segwit is active in regtest at this point, so to deserialize a
- # transaction without any inputs correctly, we set the outputs
- # to an empty list. This is a hack, as the serialization of an
- # empty list of outputs is deserialized as flags==0 and thus
- # deserialization of the outputs is skipped.
- # A policy check requires "loose" txs to be of a minimum size,
- # so vtx is not set to be empty in the TxTemplate class and we
- # only apply the workaround where txs are not "loose", i.e. in
- # blocks.
- #
- # The workaround has the purpose that both sides calculate
- # the same tx hash in the merkle tree
- badtx.vout = []
- badtx.rehash()
- badblock = self.update_block(blockname, [badtx])
- self.sync_blocks(
- [badblock], success=False,
- reject_reason=(template.block_reject_reason or template.reject_reason),
- reconnect=True, timeout=2)
-
- self.move_tip(2)
-
- # Fork like this:
- #
- # genesis -> b1 (0) -> b2 (1)
- # \-> b3 (1)
- #
- # Nothing should happen at this point. We saw b2 first so it takes priority.
- self.log.info("Don't reorg to a chain of the same length")
- self.move_tip(1)
- b3 = self.next_block(3, spend=out[1])
- txout_b3 = b3.vtx[1]
- self.sync_blocks([b3], False)
-
- # Now we add another block to make the alternative chain longer.
- #
- # genesis -> b1 (0) -> b2 (1)
- # \-> b3 (1) -> b4 (2)
- self.log.info("Reorg to a longer chain")
- b4 = self.next_block(4, spend=out[2])
- self.sync_blocks([b4])
-
- # ... and back to the first chain.
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b3 (1) -> b4 (2)
- self.move_tip(2)
- b5 = self.next_block(5, spend=out[2])
- self.save_spendable_output()
- self.sync_blocks([b5], False)
-
- self.log.info("Reorg back to the original chain")
- b6 = self.next_block(6, spend=out[3])
- self.sync_blocks([b6], True)
-
- # Try to create a fork that double-spends
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b7 (2) -> b8 (4)
- # \-> b3 (1) -> b4 (2)
- self.log.info("Reject a chain with a double spend, even if it is longer")
- self.move_tip(5)
- b7 = self.next_block(7, spend=out[2])
- self.sync_blocks([b7], False)
-
- b8 = self.next_block(8, spend=out[4])
- self.sync_blocks([b8], False, reconnect=True)
-
- # Try to create a block that has too much fee
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b9 (4)
- # \-> b3 (1) -> b4 (2)
- self.log.info("Reject a block where the miner creates too much coinbase reward")
- self.move_tip(6)
- b9 = self.next_block(9, spend=out[4], additional_coinbase_value=1)
- self.sync_blocks([b9], success=False, reject_reason='bad-cb-amount', reconnect=True)
-
- # Create a fork that ends in a block with too much fee (the one that causes the reorg)
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b10 (3) -> b11 (4)
- # \-> b3 (1) -> b4 (2)
- self.log.info("Reject a chain where the miner creates too much coinbase reward, even if the chain is longer")
- self.move_tip(5)
- b10 = self.next_block(10, spend=out[3])
- self.sync_blocks([b10], False)
-
- b11 = self.next_block(11, spend=out[4], additional_coinbase_value=1)
- self.sync_blocks([b11], success=False, reject_reason='bad-cb-amount', reconnect=True)
-
- # Try again, but with a valid fork first
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b12 (3) -> b13 (4) -> b14 (5)
- # \-> b3 (1) -> b4 (2)
- self.log.info("Reject a chain where the miner creates too much coinbase reward, even if the chain is longer (on a forked chain)")
- self.move_tip(5)
- b12 = self.next_block(12, spend=out[3])
- self.save_spendable_output()
- b13 = self.next_block(13, spend=out[4])
- self.save_spendable_output()
- b14 = self.next_block(14, spend=out[5], additional_coinbase_value=1)
- self.sync_blocks([b12, b13, b14], success=False, reject_reason='bad-cb-amount', reconnect=True)
-
- # New tip should be b13.
- assert_equal(node.getbestblockhash(), b13.hash)
-
- # Add a block with MAX_BLOCK_SIGOPS and one with one more sigop
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b12 (3) -> b13 (4) -> b15 (5) -> b16 (6)
- # \-> b3 (1) -> b4 (2)
- self.log.info("Accept a block with lots of checksigs")
- lots_of_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS - 1))
- self.move_tip(13)
- b15 = self.next_block(15, spend=out[5], script=lots_of_checksigs)
- self.save_spendable_output()
- self.sync_blocks([b15], True)
-
- self.log.info("Reject a block with too many checksigs")
- too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))
- b16 = self.next_block(16, spend=out[6], script=too_many_checksigs)
- self.sync_blocks([b16], success=False, reject_reason='bad-blk-sigops', reconnect=True)
-
- # Attempt to spend a transaction created on a different fork
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (b3.vtx[1])
- # \-> b3 (1) -> b4 (2)
- self.log.info("Reject a block with a spend from a re-org'ed out tx")
- self.move_tip(15)
- b17 = self.next_block(17, spend=txout_b3)
- self.sync_blocks([b17], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
-
- # Attempt to spend a transaction created on a different fork (on a fork this time)
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b12 (3) -> b13 (4) -> b15 (5)
- # \-> b18 (b3.vtx[1]) -> b19 (6)
- # \-> b3 (1) -> b4 (2)
- self.log.info("Reject a block with a spend from a re-org'ed out tx (on a forked chain)")
- self.move_tip(13)
- b18 = self.next_block(18, spend=txout_b3)
- self.sync_blocks([b18], False)
-
- b19 = self.next_block(19, spend=out[6])
- self.sync_blocks([b19], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
-
- # Attempt to spend a coinbase at depth too low
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b12 (3) -> b13 (4) -> b15 (5) -> b20 (7)
- # \-> b3 (1) -> b4 (2)
- self.log.info("Reject a block spending an immature coinbase.")
- self.move_tip(15)
- b20 = self.next_block(20, spend=out[7])
- self.sync_blocks([b20], success=False, reject_reason='bad-txns-premature-spend-of-coinbase')
-
- # Attempt to spend a coinbase at depth too low (on a fork this time)
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b12 (3) -> b13 (4) -> b15 (5)
- # \-> b21 (6) -> b22 (5)
- # \-> b3 (1) -> b4 (2)
- self.log.info("Reject a block spending an immature coinbase (on a forked chain)")
- self.move_tip(13)
- b21 = self.next_block(21, spend=out[6])
- self.sync_blocks([b21], False)
-
- b22 = self.next_block(22, spend=out[5])
- self.sync_blocks([b22], success=False, reject_reason='bad-txns-premature-spend-of-coinbase')
-
- # Create a block on either side of MAX_BLOCK_BASE_SIZE and make sure its accepted/rejected
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6)
- # \-> b24 (6) -> b25 (7)
- # \-> b3 (1) -> b4 (2)
- self.log.info("Accept a block of size MAX_BLOCK_BASE_SIZE")
- self.move_tip(15)
- b23 = self.next_block(23, spend=out[6])
- tx = CTransaction()
- script_length = MAX_BLOCK_BASE_SIZE - len(b23.serialize()) - 69
- script_output = CScript([b'\x00' * script_length])
- tx.vout.append(CTxOut(0, script_output))
- tx.vin.append(CTxIn(COutPoint(b23.vtx[1].sha256, 0)))
- b23 = self.update_block(23, [tx])
- # Make sure the math above worked out to produce a max-sized block
- assert_equal(len(b23.serialize()), MAX_BLOCK_BASE_SIZE)
- self.sync_blocks([b23], True)
- self.save_spendable_output()
-
- self.log.info("Reject a block of size MAX_BLOCK_BASE_SIZE + 1")
- self.move_tip(15)
- b24 = self.next_block(24, spend=out[6])
- script_length = MAX_BLOCK_BASE_SIZE - len(b24.serialize()) - 69
- script_output = CScript([b'\x00' * (script_length + 1)])
- tx.vout = [CTxOut(0, script_output)]
- b24 = self.update_block(24, [tx])
- assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE + 1)
- self.sync_blocks([b24], success=False, reject_reason='bad-blk-length', reconnect=True)
-
- b25 = self.next_block(25, spend=out[7])
- self.sync_blocks([b25], False)
-
- # Create blocks with a coinbase input script size out of range
- # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
- # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7)
- # \-> ... (6) -> ... (7)
- # \-> b3 (1) -> b4 (2)
- self.log.info("Reject a block with coinbase input script size out of range")
- self.move_tip(15)
- b26 = self.next_block(26, spend=out[6])
- b26.vtx[0].vin[0].scriptSig = b'\x00'
- b26.vtx[0].rehash()
- # update_block causes the merkle root to get updated, even with no new
- # transactions, and updates the required state.
- b26 = self.update_block(26, [])
- self.sync_blocks([b26], success=False, reject_reason='bad-cb-length', reconnect=True)
-
- # Extend the b26 chain to make sure bitcoind isn't accepting b26
- b27 = self.next_block(27, spend=out[7])
- self.sync_blocks([b27], False)
-
- # Now try a too-large-coinbase script
- self.move_tip(15)
- b28 = self.next_block(28, spend=out[6])
- b28.vtx[0].vin[0].scriptSig = b'\x00' * 101
- b28.vtx[0].rehash()
- b28 = self.update_block(28, [])
- self.sync_blocks([b28], success=False, reject_reason='bad-cb-length', reconnect=True)
-
- # Extend the b28 chain to make sure bitcoind isn't accepting b28
- b29 = self.next_block(29, spend=out[7])
- self.sync_blocks([b29], False)
-
- # b30 has a max-sized coinbase scriptSig.
- self.move_tip(23)
- b30 = self.next_block(30)
- b30.vtx[0].vin[0].scriptSig = b'\x00' * 100
- b30.vtx[0].rehash()
- b30 = self.update_block(30, [])
- self.sync_blocks([b30], True)
- self.save_spendable_output()
-
- # b31 - b35 - check sigops of OP_CHECKMULTISIG / OP_CHECKMULTISIGVERIFY / OP_CHECKSIGVERIFY
- #
- # genesis -> ... -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10)
- # \-> b36 (11)
- # \-> b34 (10)
- # \-> b32 (9)
- #
-
- # MULTISIG: each op code counts as 20 sigops. To create the edge case, pack another 19 sigops at the end.
- self.log.info("Accept a block with the max number of OP_CHECKMULTISIG sigops")
- lots_of_multisigs = CScript([OP_CHECKMULTISIG] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19)
- b31 = self.next_block(31, spend=out[8], script=lots_of_multisigs)
- assert_equal(get_legacy_sigopcount_block(b31), MAX_BLOCK_SIGOPS)
- self.sync_blocks([b31], True)
- self.save_spendable_output()
-
- # this goes over the limit because the coinbase has one sigop
- self.log.info("Reject a block with too many OP_CHECKMULTISIG sigops")
- too_many_multisigs = CScript([OP_CHECKMULTISIG] * (MAX_BLOCK_SIGOPS // 20))
- b32 = self.next_block(32, spend=out[9], script=too_many_multisigs)
- assert_equal(get_legacy_sigopcount_block(b32), MAX_BLOCK_SIGOPS + 1)
- self.sync_blocks([b32], success=False, reject_reason='bad-blk-sigops', reconnect=True)
-
- # CHECKMULTISIGVERIFY
- self.log.info("Accept a block with the max number of OP_CHECKMULTISIGVERIFY sigops")
- self.move_tip(31)
- lots_of_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19)
- b33 = self.next_block(33, spend=out[9], script=lots_of_multisigs)
- self.sync_blocks([b33], True)
- self.save_spendable_output()
-
- self.log.info("Reject a block with too many OP_CHECKMULTISIGVERIFY sigops")
- too_many_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * (MAX_BLOCK_SIGOPS // 20))
- b34 = self.next_block(34, spend=out[10], script=too_many_multisigs)
- self.sync_blocks([b34], success=False, reject_reason='bad-blk-sigops', reconnect=True)
-
- # CHECKSIGVERIFY
- self.log.info("Accept a block with the max number of OP_CHECKSIGVERIFY sigops")
- self.move_tip(33)
- lots_of_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS - 1))
- b35 = self.next_block(35, spend=out[10], script=lots_of_checksigs)
- self.sync_blocks([b35], True)
- self.save_spendable_output()
-
- self.log.info("Reject a block with too many OP_CHECKSIGVERIFY sigops")
- too_many_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS))
- b36 = self.next_block(36, spend=out[11], script=too_many_checksigs)
- self.sync_blocks([b36], success=False, reject_reason='bad-blk-sigops', reconnect=True)
-
- # Check spending of a transaction in a block which failed to connect
- #
- # b6 (3)
- # b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10)
- # \-> b37 (11)
- # \-> b38 (11/37)
- #
-
- # save 37's spendable output, but then double-spend out11 to invalidate the block
- self.log.info("Reject a block spending transaction from a block which failed to connect")
- self.move_tip(35)
- b37 = self.next_block(37, spend=out[11])
- txout_b37 = b37.vtx[1]
- tx = self.create_and_sign_transaction(out[11], 0)
- b37 = self.update_block(37, [tx])
- self.sync_blocks([b37], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
-
- # attempt to spend b37's first non-coinbase tx, at which point b37 was still considered valid
- self.move_tip(35)
- b38 = self.next_block(38, spend=txout_b37)
- self.sync_blocks([b38], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
-
- # Check P2SH SigOp counting
- #
- #
- # 13 (4) -> b15 (5) -> b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b41 (12)
- # \-> b40 (12)
- #
- # b39 - create some P2SH outputs that will require 6 sigops to spend:
- #
- # redeem_script = COINBASE_PUBKEY, (OP_2DUP+OP_CHECKSIGVERIFY) * 5, OP_CHECKSIG
- # p2sh_script = OP_HASH160, ripemd160(sha256(script)), OP_EQUAL
- #
- self.log.info("Check P2SH SIGOPS are correctly counted")
- self.move_tip(35)
- b39 = self.next_block(39)
- b39_outputs = 0
- b39_sigops_per_output = 6
-
- # Build the redeem script, hash it, use hash to create the p2sh script
- redeem_script = CScript([self.coinbase_pubkey] + [OP_2DUP, OP_CHECKSIGVERIFY] * 5 + [OP_CHECKSIG])
- redeem_script_hash = hash160(redeem_script)
- p2sh_script = CScript([OP_HASH160, redeem_script_hash, OP_EQUAL])
-
- # Create a transaction that spends one satoshi to the p2sh_script, the rest to OP_TRUE
- # This must be signed because it is spending a coinbase
- spend = out[11]
- tx = self.create_tx(spend, 0, 1, p2sh_script)
- tx.vout.append(CTxOut(spend.vout[0].nValue - 1, CScript([OP_TRUE])))
- self.sign_tx(tx, spend)
- tx.rehash()
- b39 = self.update_block(39, [tx])
- b39_outputs += 1
-
- # Until block is full, add tx's with 1 satoshi to p2sh_script, the rest to OP_TRUE
- tx_new = None
- tx_last = tx
- total_size = len(b39.serialize())
- while(total_size < MAX_BLOCK_BASE_SIZE):
- tx_new = self.create_tx(tx_last, 1, 1, p2sh_script)
- tx_new.vout.append(CTxOut(tx_last.vout[1].nValue - 1, CScript([OP_TRUE])))
- tx_new.rehash()
- total_size += len(tx_new.serialize())
- if total_size >= MAX_BLOCK_BASE_SIZE:
- break
- b39.vtx.append(tx_new) # add tx to block
- tx_last = tx_new
- b39_outputs += 1
-
- b39 = self.update_block(39, [])
- self.sync_blocks([b39], True)
- self.save_spendable_output()
-
- # Test sigops in P2SH redeem scripts
- #
- # b40 creates 3333 tx's spending the 6-sigop P2SH outputs from b39 for a total of 19998 sigops.
- # The first tx has one sigop and then at the end we add 2 more to put us just over the max.
- #
- # b41 does the same, less one, so it has the maximum sigops permitted.
- #
- self.log.info("Reject a block with too many P2SH sigops")
- self.move_tip(39)
- b40 = self.next_block(40, spend=out[12])
- sigops = get_legacy_sigopcount_block(b40)
- numTxes = (MAX_BLOCK_SIGOPS - sigops) // b39_sigops_per_output
- assert_equal(numTxes <= b39_outputs, True)
-
- lastOutpoint = COutPoint(b40.vtx[1].sha256, 0)
- new_txs = []
- for i in range(1, numTxes + 1):
- tx = CTransaction()
- tx.vout.append(CTxOut(1, CScript([OP_TRUE])))
- tx.vin.append(CTxIn(lastOutpoint, b''))
- # second input is corresponding P2SH output from b39
- tx.vin.append(CTxIn(COutPoint(b39.vtx[i].sha256, 0), b''))
- # Note: must pass the redeem_script (not p2sh_script) to the signature hash function
- (sighash, err) = SignatureHash(redeem_script, tx, 1, SIGHASH_ALL)
- sig = self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))
- scriptSig = CScript([sig, redeem_script])
-
- tx.vin[1].scriptSig = scriptSig
- tx.rehash()
- new_txs.append(tx)
- lastOutpoint = COutPoint(tx.sha256, 0)
-
- b40_sigops_to_fill = MAX_BLOCK_SIGOPS - (numTxes * b39_sigops_per_output + sigops) + 1
- tx = CTransaction()
- tx.vin.append(CTxIn(lastOutpoint, b''))
- tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b40_sigops_to_fill)))
- tx.rehash()
- new_txs.append(tx)
- self.update_block(40, new_txs)
- self.sync_blocks([b40], success=False, reject_reason='bad-blk-sigops', reconnect=True)
-
- # same as b40, but one less sigop
- self.log.info("Accept a block with the max number of P2SH sigops")
- self.move_tip(39)
- b41 = self.next_block(41, spend=None)
- self.update_block(41, b40.vtx[1:-1])
- b41_sigops_to_fill = b40_sigops_to_fill - 1
- tx = CTransaction()
- tx.vin.append(CTxIn(lastOutpoint, b''))
- tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b41_sigops_to_fill)))
- tx.rehash()
- self.update_block(41, [tx])
- self.sync_blocks([b41], True)
-
- # Fork off of b39 to create a constant base again
- #
- # b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13)
- # \-> b41 (12)
- #
- self.move_tip(39)
- b42 = self.next_block(42, spend=out[12])
- self.save_spendable_output()
-
- b43 = self.next_block(43, spend=out[13])
- self.save_spendable_output()
- self.sync_blocks([b42, b43], True)
-
- # Test a number of really invalid scenarios
- #
- # -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b44 (14)
- # \-> ??? (15)
-
- # The next few blocks are going to be created "by hand" since they'll do funky things, such as having
- # the first transaction be non-coinbase, etc. The purpose of b44 is to make sure this works.
- self.log.info("Build block 44 manually")
- height = self.block_heights[self.tip.sha256] + 1
- coinbase = create_coinbase(height, self.coinbase_pubkey)
- b44 = CBlock()
- b44.nTime = self.tip.nTime + 1
- b44.hashPrevBlock = self.tip.sha256
- b44.nBits = 0x207fffff
- b44.vtx.append(coinbase)
- b44.hashMerkleRoot = b44.calc_merkle_root()
- b44.solve()
- self.tip = b44
- self.block_heights[b44.sha256] = height
- self.blocks[44] = b44
- self.sync_blocks([b44], True)
-
- self.log.info("Reject a block with a non-coinbase as the first tx")
- non_coinbase = self.create_tx(out[15], 0, 1)
- b45 = CBlock()
- b45.nTime = self.tip.nTime + 1
- b45.hashPrevBlock = self.tip.sha256
- b45.nBits = 0x207fffff
- b45.vtx.append(non_coinbase)
- b45.hashMerkleRoot = b45.calc_merkle_root()
- b45.calc_sha256()
- b45.solve()
- self.block_heights[b45.sha256] = self.block_heights[self.tip.sha256] + 1
- self.tip = b45
- self.blocks[45] = b45
- self.sync_blocks([b45], success=False, reject_reason='bad-cb-missing', reconnect=True)
-
- self.log.info("Reject a block with no transactions")
- self.move_tip(44)
- b46 = CBlock()
- b46.nTime = b44.nTime + 1
- b46.hashPrevBlock = b44.sha256
- b46.nBits = 0x207fffff
- b46.vtx = []
- b46.hashMerkleRoot = 0
- b46.solve()
- self.block_heights[b46.sha256] = self.block_heights[b44.sha256] + 1
- self.tip = b46
- assert 46 not in self.blocks
- self.blocks[46] = b46
- self.sync_blocks([b46], success=False, reject_reason='bad-blk-length', reconnect=True)
-
- self.log.info("Reject a block with invalid work")
- self.move_tip(44)
- b47 = self.next_block(47, solve=False)
- target = uint256_from_compact(b47.nBits)
- while b47.sha256 < target:
- b47.nNonce += 1
- b47.rehash()
- self.sync_blocks([b47], False, force_send=True, reject_reason='high-hash')
-
- self.log.info("Reject a block with a timestamp >2 hours in the future")
- self.move_tip(44)
- b48 = self.next_block(48, solve=False)
- b48.nTime = int(time.time()) + 60 * 60 * 3
- b48.solve()
- self.sync_blocks([b48], False, force_send=True, reject_reason='time-too-new')
-
- self.log.info("Reject a block with invalid merkle hash")
- self.move_tip(44)
- b49 = self.next_block(49)
- b49.hashMerkleRoot += 1
- b49.solve()
- self.sync_blocks([b49], success=False, reject_reason='bad-txnmrklroot', reconnect=True)
-
- self.log.info("Reject a block with incorrect POW limit")
- self.move_tip(44)
- b50 = self.next_block(50)
- b50.nBits = b50.nBits - 1
- b50.solve()
- self.sync_blocks([b50], False, force_send=True, reject_reason='bad-diffbits', reconnect=True)
-
- self.log.info("Reject a block with two coinbase transactions")
- self.move_tip(44)
- b51 = self.next_block(51)
- cb2 = create_coinbase(51, self.coinbase_pubkey)
- b51 = self.update_block(51, [cb2])
- self.sync_blocks([b51], success=False, reject_reason='bad-cb-multiple', reconnect=True)
-
- self.log.info("Reject a block with duplicate transactions")
- # Note: txns have to be in the right position in the merkle tree to trigger this error
- self.move_tip(44)
- b52 = self.next_block(52, spend=out[15])
- tx = self.create_tx(b52.vtx[1], 0, 1)
- b52 = self.update_block(52, [tx, tx])
- self.sync_blocks([b52], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
-
- # Test block timestamps
- # -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15)
- # \-> b54 (15)
- #
- self.move_tip(43)
- b53 = self.next_block(53, spend=out[14])
- self.sync_blocks([b53], False)
- self.save_spendable_output()
-
- self.log.info("Reject a block with timestamp before MedianTimePast")
- b54 = self.next_block(54, spend=out[15])
- b54.nTime = b35.nTime - 1
- b54.solve()
- self.sync_blocks([b54], False, force_send=True, reject_reason='time-too-old')
-
- # valid timestamp
- self.move_tip(53)
- b55 = self.next_block(55, spend=out[15])
- b55.nTime = b35.nTime
- self.update_block(55, [])
- self.sync_blocks([b55], True)
- self.save_spendable_output()
-
- # Test Merkle tree malleability
- #
- # -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57p2 (16)
- # \-> b57 (16)
- # \-> b56p2 (16)
- # \-> b56 (16)
- #
- # Merkle tree malleability (CVE-2012-2459): repeating sequences of transactions in a block without
- # affecting the merkle root of a block, while still invalidating it.
- # See: src/consensus/merkle.h
- #
- # b57 has three txns: coinbase, tx, tx1. The merkle root computation will duplicate tx.
- # Result: OK
- #
- # b56 copies b57 but duplicates tx1 and does not recalculate the block hash. So it has a valid merkle
- # root but duplicate transactions.
- # Result: Fails
- #
- # b57p2 has six transactions in its merkle tree:
- # - coinbase, tx, tx1, tx2, tx3, tx4
- # Merkle root calculation will duplicate as necessary.
- # Result: OK.
- #
- # b56p2 copies b57p2 but adds both tx3 and tx4. The purpose of the test is to make sure the code catches
- # duplicate txns that are not next to one another with the "bad-txns-duplicate" error (which indicates
- # that the error was caught early, avoiding a DOS vulnerability.)
-
- # b57 - a good block with 2 txs, don't submit until end
- self.move_tip(55)
- b57 = self.next_block(57)
- tx = self.create_and_sign_transaction(out[16], 1)
- tx1 = self.create_tx(tx, 0, 1)
- b57 = self.update_block(57, [tx, tx1])
-
- # b56 - copy b57, add a duplicate tx
- self.log.info("Reject a block with a duplicate transaction in the Merkle Tree (but with a valid Merkle Root)")
- self.move_tip(55)
- b56 = copy.deepcopy(b57)
- self.blocks[56] = b56
- assert_equal(len(b56.vtx), 3)
- b56 = self.update_block(56, [tx1])
- assert_equal(b56.hash, b57.hash)
- self.sync_blocks([b56], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
-
- # b57p2 - a good block with 6 tx'es, don't submit until end
- self.move_tip(55)
- b57p2 = self.next_block("57p2")
- tx = self.create_and_sign_transaction(out[16], 1)
- tx1 = self.create_tx(tx, 0, 1)
- tx2 = self.create_tx(tx1, 0, 1)
- tx3 = self.create_tx(tx2, 0, 1)
- tx4 = self.create_tx(tx3, 0, 1)
- b57p2 = self.update_block("57p2", [tx, tx1, tx2, tx3, tx4])
-
- # b56p2 - copy b57p2, duplicate two non-consecutive tx's
- self.log.info("Reject a block with two duplicate transactions in the Merkle Tree (but with a valid Merkle Root)")
- self.move_tip(55)
- b56p2 = copy.deepcopy(b57p2)
- self.blocks["b56p2"] = b56p2
- assert_equal(b56p2.hash, b57p2.hash)
- assert_equal(len(b56p2.vtx), 6)
- b56p2 = self.update_block("b56p2", [tx3, tx4])
- self.sync_blocks([b56p2], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
-
- self.move_tip("57p2")
- self.sync_blocks([b57p2], True)
-
- self.move_tip(57)
- self.sync_blocks([b57], False) # The tip is not updated because 57p2 seen first
- self.save_spendable_output()
-
- # Test a few invalid tx types
- #
- # -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)
- # \-> ??? (17)
- #
-
- # tx with prevout.n out of range
- self.log.info("Reject a block with a transaction with prevout.n out of range")
- self.move_tip(57)
- b58 = self.next_block(58, spend=out[17])
- tx = CTransaction()
- assert(len(out[17].vout) < 42)
- tx.vin.append(CTxIn(COutPoint(out[17].sha256, 42), CScript([OP_TRUE]), 0xffffffff))
- tx.vout.append(CTxOut(0, b""))
- tx.calc_sha256()
- b58 = self.update_block(58, [tx])
- self.sync_blocks([b58], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
-
- # tx with output value > input value
- self.log.info("Reject a block with a transaction with outputs > inputs")
- self.move_tip(57)
- b59 = self.next_block(59)
- tx = self.create_and_sign_transaction(out[17], 51 * COIN)
- b59 = self.update_block(59, [tx])
- self.sync_blocks([b59], success=False, reject_reason='bad-txns-in-belowout', reconnect=True)
-
- # reset to good chain
- self.move_tip(57)
- b60 = self.next_block(60, spend=out[17])
- self.sync_blocks([b60], True)
- self.save_spendable_output()
-
- # Test BIP30
- #
- # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)
- # \-> b61 (18)
- #
- # Blocks are not allowed to contain a transaction whose id matches that of an earlier,
- # not-fully-spent transaction in the same chain. To test, make identical coinbases;
- # the second one should be rejected.
- #
- self.log.info("Reject a block with a transaction with a duplicate hash of a previous transaction (BIP30)")
- self.move_tip(60)
- b61 = self.next_block(61, spend=out[18])
- b61.vtx[0].vin[0].scriptSig = b60.vtx[0].vin[0].scriptSig # Equalize the coinbases
- b61.vtx[0].rehash()
- b61 = self.update_block(61, [])
- assert_equal(b60.vtx[0].serialize(), b61.vtx[0].serialize())
- self.sync_blocks([b61], success=False, reject_reason='bad-txns-BIP30', reconnect=True)
-
- # Test tx.isFinal is properly rejected (not an exhaustive tx.isFinal test, that should be in data-driven transaction tests)
- #
- # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)
- # \-> b62 (18)
- #
- self.log.info("Reject a block with a transaction with a nonfinal locktime")
- self.move_tip(60)
- b62 = self.next_block(62)
- tx = CTransaction()
- tx.nLockTime = 0xffffffff # this locktime is non-final
- tx.vin.append(CTxIn(COutPoint(out[18].sha256, 0))) # don't set nSequence
- tx.vout.append(CTxOut(0, CScript([OP_TRUE])))
- assert(tx.vin[0].nSequence < 0xffffffff)
- tx.calc_sha256()
- b62 = self.update_block(62, [tx])
- self.sync_blocks([b62], success=False, reject_reason='bad-txns-nonfinal')
-
- # Test a non-final coinbase is also rejected
- #
- # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17)
- # \-> b63 (-)
- #
- self.log.info("Reject a block with a coinbase transaction with a nonfinal locktime")
- self.move_tip(60)
- b63 = self.next_block(63)
- b63.vtx[0].nLockTime = 0xffffffff
- b63.vtx[0].vin[0].nSequence = 0xDEADBEEF
- b63.vtx[0].rehash()
- b63 = self.update_block(63, [])
- self.sync_blocks([b63], success=False, reject_reason='bad-txns-nonfinal')
-
- # This checks that a block with a bloated VARINT between the block_header and the array of tx such that
- # the block is > MAX_BLOCK_BASE_SIZE with the bloated varint, but <= MAX_BLOCK_BASE_SIZE without the bloated varint,
- # does not cause a subsequent, identical block with canonical encoding to be rejected. The test does not
- # care whether the bloated block is accepted or rejected; it only cares that the second block is accepted.
- #
- # What matters is that the receiving node should not reject the bloated block, and then reject the canonical
- # block on the basis that it's the same as an already-rejected block (which would be a consensus failure.)
- #
- # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18)
- # \
- # b64a (18)
- # b64a is a bloated block (non-canonical varint)
- # b64 is a good block (same as b64 but w/ canonical varint)
- #
- self.log.info("Accept a valid block even if a bloated version of the block has previously been sent")
- self.move_tip(60)
- regular_block = self.next_block("64a", spend=out[18])
-
- # make it a "broken_block," with non-canonical serialization
- b64a = CBrokenBlock(regular_block)
- b64a.initialize(regular_block)
- self.blocks["64a"] = b64a
- self.tip = b64a
- tx = CTransaction()
-
- # use canonical serialization to calculate size
- script_length = MAX_BLOCK_BASE_SIZE - len(b64a.normal_serialize()) - 69
- script_output = CScript([b'\x00' * script_length])
- tx.vout.append(CTxOut(0, script_output))
- tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0)))
- b64a = self.update_block("64a", [tx])
- assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8)
- self.sync_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize()')
-
- # bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently
- # resend the header message, it won't send us the getdata message again. Just
- # disconnect and reconnect and then call sync_blocks.
- # TODO: improve this test to be less dependent on P2P DOS behaviour.
- node.disconnect_p2ps()
- self.reconnect_p2p()
-
- self.move_tip(60)
- b64 = CBlock(b64a)
- b64.vtx = copy.deepcopy(b64a.vtx)
- assert_equal(b64.hash, b64a.hash)
- assert_equal(len(b64.serialize()), MAX_BLOCK_BASE_SIZE)
- self.blocks[64] = b64
- b64 = self.update_block(64, [])
- self.sync_blocks([b64], True)
- self.save_spendable_output()
-
- # Spend an output created in the block itself
- #
- # -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19)
- #
- self.log.info("Accept a block with a transaction spending an output created in the same block")
- self.move_tip(64)
- b65 = self.next_block(65)
- tx1 = self.create_and_sign_transaction(out[19], out[19].vout[0].nValue)
- tx2 = self.create_and_sign_transaction(tx1, 0)
- b65 = self.update_block(65, [tx1, tx2])
- self.sync_blocks([b65], True)
- self.save_spendable_output()
-
- # Attempt to spend an output created later in the same block
- #
- # -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19)
- # \-> b66 (20)
- self.log.info("Reject a block with a transaction spending an output created later in the same block")
- self.move_tip(65)
- b66 = self.next_block(66)
- tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)
- tx2 = self.create_and_sign_transaction(tx1, 1)
- b66 = self.update_block(66, [tx2, tx1])
- self.sync_blocks([b66], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
-
- # Attempt to double-spend a transaction created in a block
- #
- # -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19)
- # \-> b67 (20)
- #
- #
- self.log.info("Reject a block with a transaction double spending a transaction created in the same block")
- self.move_tip(65)
- b67 = self.next_block(67)
- tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)
- tx2 = self.create_and_sign_transaction(tx1, 1)
- tx3 = self.create_and_sign_transaction(tx1, 2)
- b67 = self.update_block(67, [tx1, tx2, tx3])
- self.sync_blocks([b67], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
-
- # More tests of block subsidy
- #
- # -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20)
- # \-> b68 (20)
- #
- # b68 - coinbase with an extra 10 satoshis,
- # creates a tx that has 9 satoshis from out[20] go to fees
- # this fails because the coinbase is trying to claim 1 satoshi too much in fees
- #
- # b69 - coinbase with extra 10 satoshis, and a tx that gives a 10 satoshi fee
- # this succeeds
- #
- self.log.info("Reject a block trying to claim too much subsidy in the coinbase transaction")
- self.move_tip(65)
- b68 = self.next_block(68, additional_coinbase_value=10)
- tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 9)
- b68 = self.update_block(68, [tx])
- self.sync_blocks([b68], success=False, reject_reason='bad-cb-amount', reconnect=True)
-
- self.log.info("Accept a block claiming the correct subsidy in the coinbase transaction")
- self.move_tip(65)
- b69 = self.next_block(69, additional_coinbase_value=10)
- tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 10)
- self.update_block(69, [tx])
- self.sync_blocks([b69], True)
- self.save_spendable_output()
-
- # Test spending the outpoint of a non-existent transaction
- #
- # -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20)
- # \-> b70 (21)
- #
- self.log.info("Reject a block containing a transaction spending from a non-existent input")
- self.move_tip(69)
- b70 = self.next_block(70, spend=out[21])
- bogus_tx = CTransaction()
- bogus_tx.sha256 = uint256_from_str(b"23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c")
- tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", 0xffffffff))
- tx.vout.append(CTxOut(1, b""))
- b70 = self.update_block(70, [tx])
- self.sync_blocks([b70], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
-
- # Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks)
- #
- # -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) -> b72 (21)
- # \-> b71 (21)
- #
- # b72 is a good block.
- # b71 is a copy of 72, but re-adds one of its transactions. However, it has the same hash as b72.
- self.log.info("Reject a block containing a duplicate transaction but with the same Merkle root (Merkle tree malleability")
- self.move_tip(69)
- b72 = self.next_block(72)
- tx1 = self.create_and_sign_transaction(out[21], 2)
- tx2 = self.create_and_sign_transaction(tx1, 1)
- b72 = self.update_block(72, [tx1, tx2]) # now tip is 72
- b71 = copy.deepcopy(b72)
- b71.vtx.append(tx2) # add duplicate tx2
- self.block_heights[b71.sha256] = self.block_heights[b69.sha256] + 1 # b71 builds off b69
- self.blocks[71] = b71
-
- assert_equal(len(b71.vtx), 4)
- assert_equal(len(b72.vtx), 3)
- assert_equal(b72.sha256, b71.sha256)
-
- self.move_tip(71)
- self.sync_blocks([b71], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
-
- self.move_tip(72)
- self.sync_blocks([b72], True)
- self.save_spendable_output()
-
- # Test some invalid scripts and MAX_BLOCK_SIGOPS
- #
- # -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) -> b72 (21)
- # \-> b** (22)
- #
-
- # b73 - tx with excessive sigops that are placed after an excessively large script element.
- # The purpose of the test is to make sure those sigops are counted.
- #
- # script is a bytearray of size 20,526
- #
- # bytearray[0-19,998] : OP_CHECKSIG
- # bytearray[19,999] : OP_PUSHDATA4
- # bytearray[20,000-20,003]: 521 (max_script_element_size+1, in little-endian format)
- # bytearray[20,004-20,525]: unread data (script_element)
- # bytearray[20,526] : OP_CHECKSIG (this puts us over the limit)
- self.log.info("Reject a block containing too many sigops after a large script element")
- self.move_tip(72)
- b73 = self.next_block(73)
- size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5 + 1
- a = bytearray([OP_CHECKSIG] * size)
- a[MAX_BLOCK_SIGOPS - 1] = int("4e", 16) # OP_PUSHDATA4
-
- element_size = MAX_SCRIPT_ELEMENT_SIZE + 1
- a[MAX_BLOCK_SIGOPS] = element_size % 256
- a[MAX_BLOCK_SIGOPS + 1] = element_size // 256
- a[MAX_BLOCK_SIGOPS + 2] = 0
- a[MAX_BLOCK_SIGOPS + 3] = 0
-
- tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
- b73 = self.update_block(73, [tx])
- assert_equal(get_legacy_sigopcount_block(b73), MAX_BLOCK_SIGOPS + 1)
- self.sync_blocks([b73], success=False, reject_reason='bad-blk-sigops', reconnect=True)
-
- # b74/75 - if we push an invalid script element, all previous sigops are counted,
- # but sigops after the element are not counted.
- #
- # The invalid script element is that the push_data indicates that
- # there will be a large amount of data (0xffffff bytes), but we only
- # provide a much smaller number. These bytes are CHECKSIGS so they would
- # cause b75 to fail for excessive sigops, if those bytes were counted.
- #
- # b74 fails because we put MAX_BLOCK_SIGOPS+1 before the element
- # b75 succeeds because we put MAX_BLOCK_SIGOPS before the element
- self.log.info("Check sigops are counted correctly after an invalid script element")
- self.move_tip(72)
- b74 = self.next_block(74)
- size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42 # total = 20,561
- a = bytearray([OP_CHECKSIG] * size)
- a[MAX_BLOCK_SIGOPS] = 0x4e
- a[MAX_BLOCK_SIGOPS + 1] = 0xfe
- a[MAX_BLOCK_SIGOPS + 2] = 0xff
- a[MAX_BLOCK_SIGOPS + 3] = 0xff
- a[MAX_BLOCK_SIGOPS + 4] = 0xff
- tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
- b74 = self.update_block(74, [tx])
- self.sync_blocks([b74], success=False, reject_reason='bad-blk-sigops', reconnect=True)
-
- self.move_tip(72)
- b75 = self.next_block(75)
- size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42
- a = bytearray([OP_CHECKSIG] * size)
- a[MAX_BLOCK_SIGOPS - 1] = 0x4e
- a[MAX_BLOCK_SIGOPS] = 0xff
- a[MAX_BLOCK_SIGOPS + 1] = 0xff
- a[MAX_BLOCK_SIGOPS + 2] = 0xff
- a[MAX_BLOCK_SIGOPS + 3] = 0xff
- tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
- b75 = self.update_block(75, [tx])
- self.sync_blocks([b75], True)
- self.save_spendable_output()
-
- # Check that if we push an element filled with CHECKSIGs, they are not counted
- self.move_tip(75)
- b76 = self.next_block(76)
- size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5
- a = bytearray([OP_CHECKSIG] * size)
- a[MAX_BLOCK_SIGOPS - 1] = 0x4e # PUSHDATA4, but leave the following bytes as just checksigs
- tx = self.create_and_sign_transaction(out[23], 1, CScript(a))
- b76 = self.update_block(76, [tx])
- self.sync_blocks([b76], True)
- self.save_spendable_output()
-
- # Test transaction resurrection
- #
- # -> b77 (24) -> b78 (25) -> b79 (26)
- # \-> b80 (25) -> b81 (26) -> b82 (27)
- #
- # b78 creates a tx, which is spent in b79. After b82, both should be in mempool
- #
- # The tx'es must be unsigned and pass the node's mempool policy. It is unsigned for the
- # rather obscure reason that the Python signature code does not distinguish between
- # Low-S and High-S values (whereas the bitcoin code has custom code which does so);
- # as a result of which, the odds are 50% that the python code will use the right
- # value and the transaction will be accepted into the mempool. Until we modify the
- # test framework to support low-S signing, we are out of luck.
- #
- # To get around this issue, we construct transactions which are not signed and which
- # spend to OP_TRUE. If the standard-ness rules change, this test would need to be
- # updated. (Perhaps to spend to a P2SH OP_TRUE script)
- self.log.info("Test transaction resurrection during a re-org")
- self.move_tip(76)
- b77 = self.next_block(77)
- tx77 = self.create_and_sign_transaction(out[24], 10 * COIN)
- b77 = self.update_block(77, [tx77])
- self.sync_blocks([b77], True)
- self.save_spendable_output()
-
- b78 = self.next_block(78)
- tx78 = self.create_tx(tx77, 0, 9 * COIN)
- b78 = self.update_block(78, [tx78])
- self.sync_blocks([b78], True)
-
- b79 = self.next_block(79)
- tx79 = self.create_tx(tx78, 0, 8 * COIN)
- b79 = self.update_block(79, [tx79])
- self.sync_blocks([b79], True)
-
- # mempool should be empty
- assert_equal(len(self.nodes[0].getrawmempool()), 0)
-
- self.move_tip(77)
- b80 = self.next_block(80, spend=out[25])
- self.sync_blocks([b80], False, force_send=True)
- self.save_spendable_output()
-
- b81 = self.next_block(81, spend=out[26])
- self.sync_blocks([b81], False, force_send=True) # other chain is same length
- self.save_spendable_output()
-
- b82 = self.next_block(82, spend=out[27])
- self.sync_blocks([b82], True) # now this chain is longer, triggers re-org
- self.save_spendable_output()
-
- # now check that tx78 and tx79 have been put back into the peer's mempool
- mempool = self.nodes[0].getrawmempool()
- assert_equal(len(mempool), 2)
- assert(tx78.hash in mempool)
- assert(tx79.hash in mempool)
-
- # Test invalid opcodes in dead execution paths.
- #
- # -> b81 (26) -> b82 (27) -> b83 (28)
- #
- self.log.info("Accept a block with invalid opcodes in dead execution paths")
- b83 = self.next_block(83)
- op_codes = [OP_IF, OP_INVALIDOPCODE, OP_ELSE, OP_TRUE, OP_ENDIF]
- script = CScript(op_codes)
- tx1 = self.create_and_sign_transaction(out[28], out[28].vout[0].nValue, script)
-
- tx2 = self.create_and_sign_transaction(tx1, 0, CScript([OP_TRUE]))
- tx2.vin[0].scriptSig = CScript([OP_FALSE])
- tx2.rehash()
-
- b83 = self.update_block(83, [tx1, tx2])
- self.sync_blocks([b83], True)
- self.save_spendable_output()
-
- # Reorg on/off blocks that have OP_RETURN in them (and try to spend them)
- #
- # -> b81 (26) -> b82 (27) -> b83 (28) -> b84 (29) -> b87 (30) -> b88 (31)
- # \-> b85 (29) -> b86 (30) \-> b89a (32)
- #
- self.log.info("Test re-orging blocks with OP_RETURN in them")
- b84 = self.next_block(84)
- tx1 = self.create_tx(out[29], 0, 0, CScript([OP_RETURN]))
- tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
- tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
- tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
- tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
- tx1.calc_sha256()
- self.sign_tx(tx1, out[29])
- tx1.rehash()
- tx2 = self.create_tx(tx1, 1, 0, CScript([OP_RETURN]))
- tx2.vout.append(CTxOut(0, CScript([OP_RETURN])))
- tx3 = self.create_tx(tx1, 2, 0, CScript([OP_RETURN]))
- tx3.vout.append(CTxOut(0, CScript([OP_TRUE])))
- tx4 = self.create_tx(tx1, 3, 0, CScript([OP_TRUE]))
- tx4.vout.append(CTxOut(0, CScript([OP_RETURN])))
- tx5 = self.create_tx(tx1, 4, 0, CScript([OP_RETURN]))
-
- b84 = self.update_block(84, [tx1, tx2, tx3, tx4, tx5])
- self.sync_blocks([b84], True)
- self.save_spendable_output()
-
- self.move_tip(83)
- b85 = self.next_block(85, spend=out[29])
- self.sync_blocks([b85], False) # other chain is same length
-
- b86 = self.next_block(86, spend=out[30])
- self.sync_blocks([b86], True)
-
- self.move_tip(84)
- b87 = self.next_block(87, spend=out[30])
- self.sync_blocks([b87], False) # other chain is same length
- self.save_spendable_output()
-
- b88 = self.next_block(88, spend=out[31])
- self.sync_blocks([b88], True)
- self.save_spendable_output()
-
- # trying to spend the OP_RETURN output is rejected
- b89a = self.next_block("89a", spend=out[32])
- tx = self.create_tx(tx1, 0, 0, CScript([OP_TRUE]))
- b89a = self.update_block("89a", [tx])
- self.sync_blocks([b89a], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
-
- self.log.info("Test a re-org of one week's worth of blocks (1088 blocks)")
-
- self.move_tip(88)
- LARGE_REORG_SIZE = 1088
- blocks = []
- spend = out[32]
- for i in range(89, LARGE_REORG_SIZE + 89):
- b = self.next_block(i, spend, version=4)
- tx = CTransaction()
- script_length = MAX_BLOCK_BASE_SIZE - len(b.serialize()) - 69
- script_output = CScript([b'\x00' * script_length])
- tx.vout.append(CTxOut(0, script_output))
- tx.vin.append(CTxIn(COutPoint(b.vtx[1].sha256, 0)))
- b = self.update_block(i, [tx])
- assert_equal(len(b.serialize()), MAX_BLOCK_BASE_SIZE)
- blocks.append(b)
- self.save_spendable_output()
- spend = self.get_spendable_output()
-
- self.sync_blocks(blocks, True, timeout=480)
- chain1_tip = i
-
- # now create alt chain of same length
- self.move_tip(88)
- blocks2 = []
- for i in range(89, LARGE_REORG_SIZE + 89):
- blocks2.append(self.next_block("alt" + str(i), version=4))
- self.sync_blocks(blocks2, False, force_send=True)
-
- # extend alt chain to trigger re-org
- block = self.next_block("alt" + str(chain1_tip + 1), version=4)
- self.sync_blocks([block], True, timeout=480)
-
- # ... and re-org back to the first chain
- self.move_tip(chain1_tip)
- block = self.next_block(chain1_tip + 1, version=4)
- self.sync_blocks([block], False, force_send=True)
- block = self.next_block(chain1_tip + 2, version=4)
- self.sync_blocks([block], True, timeout=480)
-
- self.log.info("Reject a block with an invalid block header version")
- b_v1 = self.next_block('b_v1', version=1)
- self.sync_blocks([b_v1], success=False, force_send=True, reject_reason='bad-version(0x00000001)')
-
- self.move_tip(chain1_tip + 2)
- b_cb34 = self.next_block('b_cb34', version=4)
- b_cb34.vtx[0].vin[0].scriptSig = b_cb34.vtx[0].vin[0].scriptSig[:-1]
- b_cb34.vtx[0].rehash()
- b_cb34.hashMerkleRoot = b_cb34.calc_merkle_root()
- b_cb34.solve()
- self.sync_blocks([b_cb34], success=False, reject_reason='bad-cb-height', reconnect=True)
-
- # Helper methods
- ################
-
- def add_transactions_to_block(self, block, tx_list):
- [tx.rehash() for tx in tx_list]
- block.vtx.extend(tx_list)
-
- # this is a little handier to use than the version in blocktools.py
- def create_tx(self, spend_tx, n, value, script=CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])):
- return create_tx_with_script(spend_tx, n, amount=value, script_pub_key=script)
-
- # sign a transaction, using the key we know about
- # this signs input 0 in tx, which is assumed to be spending output n in spend_tx
- def sign_tx(self, tx, spend_tx):
- scriptPubKey = bytearray(spend_tx.vout[0].scriptPubKey)
- if (scriptPubKey[0] == OP_TRUE): # an anyone-can-spend
- tx.vin[0].scriptSig = CScript()
- return
- (sighash, err) = SignatureHash(spend_tx.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL)
- tx.vin[0].scriptSig = CScript([self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))])
-
- def create_and_sign_transaction(self, spend_tx, value, script=CScript([OP_TRUE])):
- tx = self.create_tx(spend_tx, 0, value, script)
- self.sign_tx(tx, spend_tx)
- tx.rehash()
- return tx
-
- def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True, *, version=1):
- if self.tip is None:
- base_block_hash = self.genesis_hash
- block_time = int(time.time()) + 1
- else:
- base_block_hash = self.tip.sha256
- block_time = self.tip.nTime + 1
- # First create the coinbase
- height = self.block_heights[base_block_hash] + 1
- coinbase = create_coinbase(height, self.coinbase_pubkey)
- coinbase.vout[0].nValue += additional_coinbase_value
- coinbase.rehash()
- if spend is None:
- block = create_block(base_block_hash, coinbase, block_time, version=version)
- else:
- coinbase.vout[0].nValue += spend.vout[0].nValue - 1 # all but one satoshi to fees
- coinbase.rehash()
- block = create_block(base_block_hash, coinbase, block_time, version=version)
- tx = self.create_tx(spend, 0, 1, script) # spend 1 satoshi
- self.sign_tx(tx, spend)
- self.add_transactions_to_block(block, [tx])
- block.hashMerkleRoot = block.calc_merkle_root()
- if solve:
- block.solve()
- self.tip = block
- self.block_heights[block.sha256] = height
- assert number not in self.blocks
- self.blocks[number] = block
- return block
-
- # save the current tip so it can be spent by a later block
- def save_spendable_output(self):
- self.log.debug("saving spendable output %s" % self.tip.vtx[0])
- self.spendable_outputs.append(self.tip)
-
- # get an output that we previously marked as spendable
- def get_spendable_output(self):
- self.log.debug("getting spendable output %s" % self.spendable_outputs[0].vtx[0])
- return self.spendable_outputs.pop(0).vtx[0]
-
- # move the tip back to a previous block
- def move_tip(self, number):
- self.tip = self.blocks[number]
-
- # adds transactions to the block and updates state
- def update_block(self, block_number, new_transactions):
- block = self.blocks[block_number]
- self.add_transactions_to_block(block, new_transactions)
- old_sha256 = block.sha256
- block.hashMerkleRoot = block.calc_merkle_root()
- block.solve()
- # Update the internal state just like in next_block
- self.tip = block
- if block.sha256 != old_sha256:
- self.block_heights[block.sha256] = self.block_heights[old_sha256]
- del self.block_heights[old_sha256]
- self.blocks[block_number] = block
- return block
-
- def bootstrap_p2p(self, timeout=10):
- """Add a P2P connection to the node.
-
- Helper to connect and wait for version handshake."""
- self.nodes[0].add_p2p_connection(P2PDataStore())
- # We need to wait for the initial getheaders from the peer before we
- # start populating our blockstore. If we don't, then we may run ahead
- # to the next subtest before we receive the getheaders. We'd then send
- # an INV for the next block and receive two getheaders - one for the
- # IBD and one for the INV. We'd respond to bothWhy this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.