aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml39
-rwxr-xr-xci/test/00_setup_env_native_asan.sh6
-rwxr-xr-xci/test/00_setup_env_native_fuzz.sh1
-rwxr-xr-xci/test/04_install.sh3
-rw-r--r--src/init.cpp6
-rw-r--r--src/serialize.h187
-rw-r--r--src/test/fuzz/addrman.cpp33
-rwxr-xr-xtest/functional/mempool_datacarrier.py30
8 files changed, 131 insertions, 174 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 542bbb6ee6..4a6e73ac85 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -14,8 +14,24 @@ cirrus_ephemeral_worker_template_env: &CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
persistent_worker_template_env: &PERSISTENT_WORKER_TEMPLATE_ENV
RESTART_CI_DOCKER_BEFORE_RUN: "1"
+# https://cirrus-ci.org/guide/persistent-workers/
+#
+# It is possible to select a specific persistent worker by label. Refer to the
+# Cirrus CI docs for more details.
+#
+# Generally, a persistent worker must run Ubuntu 23.04+ or Debian 12+.
+# Specifically,
+# - apt-get is required due to PACKAGE_MANAGER_INSTALL
+# - podman-docker-4.1+ is required due to the use of `podman` when
+# RESTART_CI_DOCKER_BEFORE_RUN is set and 4.1+ due to the bugfix in 4.1
+# (https://github.com/bitcoin/bitcoin/pull/21652)
+# - The ./ci/ depedencies should be installed:
+# apt update && apt install screen python3 bash podman-docker curl -y
+#
+# The following specific types should exist, with the following requirements:
+# - lunar: For a machine running the Linux kernel shipped with Ubuntu Lunar 23.04. The machine is recommended to have 4 CPUs and 16 GB of memory.
persistent_worker_template: &PERSISTENT_WORKER_TEMPLATE
- persistent_worker: {} # https://cirrus-ci.org/guide/persistent-workers/
+ persistent_worker: {} # Only use this if the task does not care about the type at all
# https://cirrus-ci.org/guide/tips-and-tricks/#sharing-configuration-between-tasks
filter_template: &FILTER_TEMPLATE
@@ -257,22 +273,17 @@ task:
task:
name: '[ASan + LSan + UBSan + integer, no depends, USDT] [lunar]'
+ enable_bpfcc_script:
+ # In the image build step, no external environment variables are available,
+ # so any settings will need to be written to the settings env file:
+ - sed -i "s|\${CIRRUS_CI}|true|g" ./ci/test/00_setup_env_native_asan.sh
<< : *GLOBAL_TASK_TEMPLATE
- # We can't use a 'container' for the USDT interface tests as the CirrusCI
- # containers don't have privileges to hook into bitcoind. CirrusCI uses
- # Google Compute Engine instances: https://cirrus-ci.org/guide/custom-vms/
- # Images can be found here: https://cloud.google.com/compute/docs/images/os-details
- compute_engine_instance:
- image_project: ubuntu-os-cloud
- image: family/ubuntu-2304-amd64 # https://cirrus-ci.org/guide/custom-vms/#custom-compute-engine-vms
- cpu: 4
- disk: 100
- memory: 12G
+ persistent_worker:
+ labels:
+ type: lunar # Must use the lunar-specific worker (needed for USDT functional tests)
env:
- << : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
- HOME: /root/ # Only needed for compute_engine_instance
+ << : *PERSISTENT_WORKER_TEMPLATE_ENV
FILE_ENV: "./ci/test/00_setup_env_native_asan.sh"
- MAKEJOBS: "-j4" # Avoid excessive memory use
task:
name: '[fuzzer,address,undefined,integer, no depends] [lunar]'
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index a5c80c2afc..dff86b1ffe 100755
--- a/ci/test/00_setup_env_native_asan.sh
+++ b/ci/test/00_setup_env_native_asan.sh
@@ -8,9 +8,11 @@ export LC_ALL=C.UTF-8
# Only install BCC tracing packages in Cirrus CI.
if [[ "${CIRRUS_CI}" == "true" ]]; then
- export BPFCC_PACKAGE="bpfcc-tools"
+ BPFCC_PACKAGE="bpfcc-tools linux-headers-$(uname --kernel-release)"
+ export CI_CONTAINER_CAP="--privileged -v /sys/kernel:/sys/kernel:rw"
else
- export BPFCC_PACKAGE=""
+ BPFCC_PACKAGE=""
+ export CI_CONTAINER_CAP="--cap-add SYS_PTRACE" # If run with (ASan + LSan), the container needs access to ptrace (https://github.com/google/sanitizers/issues/764)
fi
export CONTAINER_NAME=ci_native_asan
diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh
index 15785d1613..bfd51be6d0 100755
--- a/ci/test/00_setup_env_native_fuzz.sh
+++ b/ci/test/00_setup_env_native_fuzz.sh
@@ -14,6 +14,7 @@ export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export RUN_FUZZ_TESTS=true
export GOAL="install"
+export CI_CONTAINER_CAP="--cap-add SYS_PTRACE" # If run with (ASan + LSan), the container needs access to ptrace (https://github.com/google/sanitizers/issues/764)
export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined,float-divide-by-zero,integer \
CC='clang-16 -ftrivial-auto-var-init=pattern' CXX='clang++-16 -ftrivial-auto-var-init=pattern'"
export CCACHE_MAXSIZE=200M
diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh
index ff43698994..205c79328a 100755
--- a/ci/test/04_install.sh
+++ b/ci/test/04_install.sh
@@ -18,9 +18,6 @@ export ASAN_OPTIONS="detect_stack_use_after_return=1:check_initialization_order=
export LSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/lsan"
export TSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/tsan:halt_on_error=1:log_path=${BASE_SCRATCH_DIR}/sanitizer-output/tsan"
export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1"
-if [[ $BITCOIN_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764)
- CI_CONTAINER_CAP="--cap-add SYS_PTRACE"
-fi
if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
# Export all env vars to avoid missing some.
diff --git a/src/init.cpp b/src/init.cpp
index c11f100139..4d526bd0de 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -590,7 +590,11 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-acceptstalefeeestimates", strprintf("Read fee estimates even if they are stale (%sdefault: %u) fee estimates are considered stale if they are %s hours old", "regtest only; ", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES, Ticks<std::chrono::hours>(MAX_FILE_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
- argsman.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
+ argsman.AddArg("-datacarriersize",
+ strprintf("Relay and mine transactions whose data-carrying raw scriptPubKey "
+ "is of this size or less (default: %u)",
+ MAX_OP_RETURN_RELAY),
+ ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-mempoolfullrbf", strprintf("Accept transaction replace-by-fee without requiring replaceability signaling (default: %u)", DEFAULT_MEMPOOL_FULL_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY,
OptionsCategory::NODE_RELAY);
diff --git a/src/serialize.h b/src/serialize.h
index 0cda0ac7d5..39f2c0f3ae 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -642,23 +642,14 @@ template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_st
* prevector
* prevectors of unsigned char are a special case and are intended to be serialized as a single opaque blob.
*/
-template<typename Stream, unsigned int N, typename T> void Serialize_impl(Stream& os, const prevector<N, T>& v, const unsigned char&);
-template<typename Stream, unsigned int N, typename T, typename V> void Serialize_impl(Stream& os, const prevector<N, T>& v, const V&);
template<typename Stream, unsigned int N, typename T> inline void Serialize(Stream& os, const prevector<N, T>& v);
-template<typename Stream, unsigned int N, typename T> void Unserialize_impl(Stream& is, prevector<N, T>& v, const unsigned char&);
-template<typename Stream, unsigned int N, typename T, typename V> void Unserialize_impl(Stream& is, prevector<N, T>& v, const V&);
template<typename Stream, unsigned int N, typename T> inline void Unserialize(Stream& is, prevector<N, T>& v);
/**
* vector
* vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob.
*/
-template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, const unsigned char&);
-template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, const bool&);
-template<typename Stream, typename T, typename A, typename V> void Serialize_impl(Stream& os, const std::vector<T, A>& v, const V&);
template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v);
-template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, const unsigned char&);
-template<typename Stream, typename T, typename A, typename V> void Unserialize_impl(Stream& is, std::vector<T, A>& v, const V&);
template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v);
/**
@@ -751,122 +742,82 @@ void Unserialize(Stream& is, std::basic_string<C>& str)
/**
* prevector
*/
-template<typename Stream, unsigned int N, typename T>
-void Serialize_impl(Stream& os, const prevector<N, T>& v, const unsigned char&)
-{
- WriteCompactSize(os, v.size());
- if (!v.empty())
- os.write(MakeByteSpan(v));
-}
-
-template<typename Stream, unsigned int N, typename T, typename V>
-void Serialize_impl(Stream& os, const prevector<N, T>& v, const V&)
-{
- Serialize(os, Using<VectorFormatter<DefaultFormatter>>(v));
-}
-
-template<typename Stream, unsigned int N, typename T>
-inline void Serialize(Stream& os, const prevector<N, T>& v)
-{
- Serialize_impl(os, v, T());
-}
-
-
-template<typename Stream, unsigned int N, typename T>
-void Unserialize_impl(Stream& is, prevector<N, T>& v, const unsigned char&)
-{
- // Limit size per read so bogus size value won't cause out of memory
- v.clear();
- unsigned int nSize = ReadCompactSize(is);
- unsigned int i = 0;
- while (i < nSize)
- {
- unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));
- v.resize_uninitialized(i + blk);
- is.read(AsWritableBytes(Span{&v[i], blk}));
- i += blk;
+template <typename Stream, unsigned int N, typename T>
+void Serialize(Stream& os, const prevector<N, T>& v)
+{
+ if constexpr (std::is_same_v<T, unsigned char>) {
+ WriteCompactSize(os, v.size());
+ if (!v.empty())
+ os.write(MakeByteSpan(v));
+ } else {
+ Serialize(os, Using<VectorFormatter<DefaultFormatter>>(v));
}
}
-template<typename Stream, unsigned int N, typename T, typename V>
-void Unserialize_impl(Stream& is, prevector<N, T>& v, const V&)
-{
- Unserialize(is, Using<VectorFormatter<DefaultFormatter>>(v));
-}
-template<typename Stream, unsigned int N, typename T>
-inline void Unserialize(Stream& is, prevector<N, T>& v)
+template <typename Stream, unsigned int N, typename T>
+void Unserialize(Stream& is, prevector<N, T>& v)
{
- Unserialize_impl(is, v, T());
+ if constexpr (std::is_same_v<T, unsigned char>) {
+ // Limit size per read so bogus size value won't cause out of memory
+ v.clear();
+ unsigned int nSize = ReadCompactSize(is);
+ unsigned int i = 0;
+ while (i < nSize) {
+ unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));
+ v.resize_uninitialized(i + blk);
+ is.read(AsWritableBytes(Span{&v[i], blk}));
+ i += blk;
+ }
+ } else {
+ Unserialize(is, Using<VectorFormatter<DefaultFormatter>>(v));
+ }
}
-
/**
* vector
*/
-template<typename Stream, typename T, typename A>
-void Serialize_impl(Stream& os, const std::vector<T, A>& v, const unsigned char&)
-{
- WriteCompactSize(os, v.size());
- if (!v.empty())
- os.write(MakeByteSpan(v));
-}
-
-template<typename Stream, typename T, typename A>
-void Serialize_impl(Stream& os, const std::vector<T, A>& v, const bool&)
-{
- // A special case for std::vector<bool>, as dereferencing
- // std::vector<bool>::const_iterator does not result in a const bool&
- // due to std::vector's special casing for bool arguments.
- WriteCompactSize(os, v.size());
- for (bool elem : v) {
- ::Serialize(os, elem);
+template <typename Stream, typename T, typename A>
+void Serialize(Stream& os, const std::vector<T, A>& v)
+{
+ if constexpr (std::is_same_v<T, unsigned char>) {
+ WriteCompactSize(os, v.size());
+ if (!v.empty())
+ os.write(MakeByteSpan(v));
+ } else if constexpr (std::is_same_v<T, bool>) {
+ // A special case for std::vector<bool>, as dereferencing
+ // std::vector<bool>::const_iterator does not result in a const bool&
+ // due to std::vector's special casing for bool arguments.
+ WriteCompactSize(os, v.size());
+ for (bool elem : v) {
+ ::Serialize(os, elem);
+ }
+ } else {
+ Serialize(os, Using<VectorFormatter<DefaultFormatter>>(v));
}
}
-template<typename Stream, typename T, typename A, typename V>
-void Serialize_impl(Stream& os, const std::vector<T, A>& v, const V&)
-{
- Serialize(os, Using<VectorFormatter<DefaultFormatter>>(v));
-}
-template<typename Stream, typename T, typename A>
-inline void Serialize(Stream& os, const std::vector<T, A>& v)
+template <typename Stream, typename T, typename A>
+void Unserialize(Stream& is, std::vector<T, A>& v)
{
- Serialize_impl(os, v, T());
-}
-
-
-template<typename Stream, typename T, typename A>
-void Unserialize_impl(Stream& is, std::vector<T, A>& v, const unsigned char&)
-{
- // Limit size per read so bogus size value won't cause out of memory
- v.clear();
- unsigned int nSize = ReadCompactSize(is);
- unsigned int i = 0;
- while (i < nSize)
- {
- unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));
- v.resize(i + blk);
- is.read(AsWritableBytes(Span{&v[i], blk}));
- i += blk;
+ if constexpr (std::is_same_v<T, unsigned char>) {
+ // Limit size per read so bogus size value won't cause out of memory
+ v.clear();
+ unsigned int nSize = ReadCompactSize(is);
+ unsigned int i = 0;
+ while (i < nSize) {
+ unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));
+ v.resize(i + blk);
+ is.read(AsWritableBytes(Span{&v[i], blk}));
+ i += blk;
+ }
+ } else {
+ Unserialize(is, Using<VectorFormatter<DefaultFormatter>>(v));
}
}
-template<typename Stream, typename T, typename A, typename V>
-void Unserialize_impl(Stream& is, std::vector<T, A>& v, const V&)
-{
- Unserialize(is, Using<VectorFormatter<DefaultFormatter>>(v));
-}
-
-template<typename Stream, typename T, typename A>
-inline void Unserialize(Stream& is, std::vector<T, A>& v)
-{
- Unserialize_impl(is, v, T());
-}
-
-
/**
* pair
@@ -1039,28 +990,16 @@ public:
int GetVersion() const { return nVersion; }
};
-template<typename Stream>
-void SerializeMany(Stream& s)
-{
-}
-
-template<typename Stream, typename Arg, typename... Args>
-void SerializeMany(Stream& s, const Arg& arg, const Args&... args)
-{
- ::Serialize(s, arg);
- ::SerializeMany(s, args...);
-}
-
-template<typename Stream>
-inline void UnserializeMany(Stream& s)
+template <typename Stream, typename... Args>
+void SerializeMany(Stream& s, const Args&... args)
{
+ (::Serialize(s, args), ...);
}
-template<typename Stream, typename Arg, typename... Args>
-inline void UnserializeMany(Stream& s, Arg&& arg, Args&&... args)
+template <typename Stream, typename... Args>
+inline void UnserializeMany(Stream& s, Args&&... args)
{
- ::Unserialize(s, arg);
- ::UnserializeMany(s, args...);
+ (::Unserialize(s, args), ...);
}
template<typename Stream, typename... Args>
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index 8ac1330dcb..02df4590de 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -263,40 +263,21 @@ FUZZ_TARGET(addrman, .init = initialize_addrman)
[&] {
std::vector<CAddress> addresses;
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
- const std::optional<CAddress> opt_address = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- if (!opt_address) {
- break;
- }
- addresses.push_back(*opt_address);
- }
- const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
- if (opt_net_addr) {
- addr_man.Add(addresses, *opt_net_addr, std::chrono::seconds{ConsumeTime(fuzzed_data_provider, 0, 100000000)});
+ addresses.push_back(ConsumeAddress(fuzzed_data_provider));
}
+ addr_man.Add(addresses, ConsumeNetAddr(fuzzed_data_provider), std::chrono::seconds{ConsumeTime(fuzzed_data_provider, 0, 100000000)});
},
[&] {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.Good(*opt_service, NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
- }
+ addr_man.Good(ConsumeService(fuzzed_data_provider), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
},
[&] {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
- }
+ addr_man.Attempt(ConsumeService(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool(), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
},
[&] {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.Connected(*opt_service, NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
- }
+ addr_man.Connected(ConsumeService(fuzzed_data_provider), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
},
[&] {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.SetServices(*opt_service, ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS));
- }
+ addr_man.SetServices(ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS));
});
}
const AddrMan& const_addr_man{addr_man};
@@ -334,4 +315,4 @@ FUZZ_TARGET(addrman_serdeser, .init = initialize_addrman)
data_stream << addr_man1;
data_stream >> addr_man2;
assert(addr_man1 == addr_man2);
-}
+} \ No newline at end of file
diff --git a/test/functional/mempool_datacarrier.py b/test/functional/mempool_datacarrier.py
index c370d8fa91..951bf37ae8 100755
--- a/test/functional/mempool_datacarrier.py
+++ b/test/functional/mempool_datacarrier.py
@@ -22,16 +22,18 @@ from test_framework.wallet import MiniWallet
class DataCarrierTest(BitcoinTestFramework):
def set_test_params(self):
- self.num_nodes = 3
+ self.num_nodes = 4
self.extra_args = [
[],
["-datacarrier=0"],
- ["-datacarrier=1", f"-datacarriersize={MAX_OP_RETURN_RELAY - 1}"]
+ ["-datacarrier=1", f"-datacarriersize={MAX_OP_RETURN_RELAY - 1}"],
+ ["-datacarrier=1", f"-datacarriersize=2"],
]
- def test_null_data_transaction(self, node: TestNode, data: bytes, success: bool) -> None:
+ def test_null_data_transaction(self, node: TestNode, data, success: bool) -> None:
tx = self.wallet.create_self_transfer(fee_rate=0)["tx"]
- tx.vout.append(CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN, data])))
+ data = [] if data is None else [data]
+ tx.vout.append(CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN] + data)))
tx.vout[0].nValue -= tx.get_vsize() # simply pay 1sat/vbyte fee
tx_hex = tx.serialize().hex()
@@ -49,6 +51,8 @@ class DataCarrierTest(BitcoinTestFramework):
default_size_data = random_bytes(MAX_OP_RETURN_RELAY - 3)
too_long_data = random_bytes(MAX_OP_RETURN_RELAY - 2)
small_data = random_bytes(MAX_OP_RETURN_RELAY - 4)
+ one_byte = random_bytes(1)
+ zero_bytes = random_bytes(0)
self.log.info("Testing null data transaction with default -datacarrier and -datacarriersize values.")
self.test_null_data_transaction(node=self.nodes[0], data=default_size_data, success=True)
@@ -65,6 +69,24 @@ class DataCarrierTest(BitcoinTestFramework):
self.log.info("Testing a null data transaction with a size smaller than accepted by -datacarriersize.")
self.test_null_data_transaction(node=self.nodes[2], data=small_data, success=True)
+ self.log.info("Testing a null data transaction with no data.")
+ self.test_null_data_transaction(node=self.nodes[0], data=None, success=True)
+ self.test_null_data_transaction(node=self.nodes[1], data=None, success=False)
+ self.test_null_data_transaction(node=self.nodes[2], data=None, success=True)
+ self.test_null_data_transaction(node=self.nodes[3], data=None, success=True)
+
+ self.log.info("Testing a null data transaction with zero bytes of data.")
+ self.test_null_data_transaction(node=self.nodes[0], data=zero_bytes, success=True)
+ self.test_null_data_transaction(node=self.nodes[1], data=zero_bytes, success=False)
+ self.test_null_data_transaction(node=self.nodes[2], data=zero_bytes, success=True)
+ self.test_null_data_transaction(node=self.nodes[3], data=zero_bytes, success=True)
+
+ self.log.info("Testing a null data transaction with one byte of data.")
+ self.test_null_data_transaction(node=self.nodes[0], data=one_byte, success=True)
+ self.test_null_data_transaction(node=self.nodes[1], data=one_byte, success=False)
+ self.test_null_data_transaction(node=self.nodes[2], data=one_byte, success=True)
+ self.test_null_data_transaction(node=self.nodes[3], data=one_byte, success=False)
+
if __name__ == '__main__':
DataCarrierTest().main()