diff --git a/builds/gnu/Makefile.am b/builds/gnu/Makefile.am
index 659e6cd2..716b796f 100644
--- a/builds/gnu/Makefile.am
+++ b/builds/gnu/Makefile.am
@@ -48,21 +48,24 @@ src_libbitcoin_server_la_LIBADD = \
src_libbitcoin_server_la_SOURCES = \
${srcdir}/../../src/configuration.cpp \
- ${srcdir}/../../src/error.cpp \
${srcdir}/../../src/parser.cpp \
${srcdir}/../../src/server_node.cpp \
${srcdir}/../../src/settings.cpp \
+ ${srcdir}/../../src/error/bitcoind_error_t.cpp \
+ ${srcdir}/../../src/error/btcd_error_t.cpp \
+ ${srcdir}/../../src/error/electrum_error_t.cpp \
+ ${srcdir}/../../src/error/error_t.cpp \
${srcdir}/../../src/parsers/admin_query.cpp \
${srcdir}/../../src/parsers/admin_target.cpp \
+ ${srcdir}/../../src/parsers/bitcoind_block_stats.cpp \
+ ${srcdir}/../../src/parsers/bitcoind_descriptor.cpp \
+ ${srcdir}/../../src/parsers/bitcoind_merkle.cpp \
${srcdir}/../../src/parsers/bitcoind_script.cpp \
${srcdir}/../../src/parsers/bitcoind_target.cpp \
- ${srcdir}/../../src/parsers/block_stats.cpp \
${srcdir}/../../src/parsers/btcd_filter.cpp \
- ${srcdir}/../../src/parsers/descriptor.cpp \
${srcdir}/../../src/parsers/electrum_version.cpp \
${srcdir}/../../src/parsers/native_query.cpp \
${srcdir}/../../src/parsers/native_target.cpp \
- ${srcdir}/../../src/parsers/partial_merkle.cpp \
${srcdir}/../../src/protocols/protocol_html.cpp \
${srcdir}/../../src/protocols/protocol_http.cpp \
${srcdir}/../../src/protocols/admin/protocol_admin.cpp \
@@ -115,7 +118,6 @@ include_bitcoin_serverdir = \
include_bitcoin_server_HEADERS = \
${srcdir}/../../include/bitcoin/server/configuration.hpp \
${srcdir}/../../include/bitcoin/server/define.hpp \
- ${srcdir}/../../include/bitcoin/server/error.hpp \
${srcdir}/../../include/bitcoin/server/parser.hpp \
${srcdir}/../../include/bitcoin/server/server_node.hpp \
${srcdir}/../../include/bitcoin/server/settings.hpp \
@@ -132,6 +134,16 @@ include_bitcoin_server_channels_HEADERS = \
${srcdir}/../../include/bitcoin/server/channels/channel_stratum_v2.hpp \
${srcdir}/../../include/bitcoin/server/channels/channels.hpp
+include_bitcoin_server_errordir = \
+ ${includedir}/bitcoin/server/error
+
+include_bitcoin_server_error_HEADERS = \
+ ${srcdir}/../../include/bitcoin/server/error/bitcoind_error_t.hpp \
+ ${srcdir}/../../include/bitcoin/server/error/btcd_error_t.hpp \
+ ${srcdir}/../../include/bitcoin/server/error/electrum_error_t.hpp \
+ ${srcdir}/../../include/bitcoin/server/error/error.hpp \
+ ${srcdir}/../../include/bitcoin/server/error/error_t.hpp
+
include_bitcoin_server_impl_protocolsdir = \
${includedir}/bitcoin/server/impl/protocols
@@ -167,16 +179,16 @@ include_bitcoin_server_parsersdir = \
include_bitcoin_server_parsers_HEADERS = \
${srcdir}/../../include/bitcoin/server/parsers/admin_query.hpp \
${srcdir}/../../include/bitcoin/server/parsers/admin_target.hpp \
+ ${srcdir}/../../include/bitcoin/server/parsers/bitcoind_block_stats.hpp \
+ ${srcdir}/../../include/bitcoin/server/parsers/bitcoind_descriptor.hpp \
+ ${srcdir}/../../include/bitcoin/server/parsers/bitcoind_merkle.hpp \
${srcdir}/../../include/bitcoin/server/parsers/bitcoind_script.hpp \
${srcdir}/../../include/bitcoin/server/parsers/bitcoind_target.hpp \
- ${srcdir}/../../include/bitcoin/server/parsers/block_stats.hpp \
${srcdir}/../../include/bitcoin/server/parsers/btcd_filter.hpp \
- ${srcdir}/../../include/bitcoin/server/parsers/descriptor.hpp \
${srcdir}/../../include/bitcoin/server/parsers/electrum_version.hpp \
${srcdir}/../../include/bitcoin/server/parsers/native_query.hpp \
${srcdir}/../../include/bitcoin/server/parsers/native_target.hpp \
- ${srcdir}/../../include/bitcoin/server/parsers/parsers.hpp \
- ${srcdir}/../../include/bitcoin/server/parsers/partial_merkle.hpp
+ ${srcdir}/../../include/bitcoin/server/parsers/parsers.hpp
include_bitcoin_server_protocolsdir = \
${includedir}/bitcoin/server/protocols
@@ -251,13 +263,13 @@ test_libbitcoin_server_test_SOURCES = \
${srcdir}/../../test/mocks/blocks.cpp \
${srcdir}/../../test/parsers/admin_query.cpp \
${srcdir}/../../test/parsers/admin_target.cpp \
+ ${srcdir}/../../test/parsers/bitcoind_block_stats.cpp \
+ ${srcdir}/../../test/parsers/bitcoind_descriptor.cpp \
+ ${srcdir}/../../test/parsers/bitcoind_merkle.cpp \
${srcdir}/../../test/parsers/bitcoind_target.cpp \
- ${srcdir}/../../test/parsers/block_stats.cpp \
- ${srcdir}/../../test/parsers/descriptor.cpp \
${srcdir}/../../test/parsers/electrum_version.cpp \
${srcdir}/../../test/parsers/native_query.cpp \
${srcdir}/../../test/parsers/native_target.cpp \
- ${srcdir}/../../test/parsers/partial_merkle.cpp \
${srcdir}/../../test/protocols/admin/admin_diagnostics.cpp \
${srcdir}/../../test/protocols/admin/admin_setup_fixture.cpp \
${srcdir}/../../test/protocols/bitcoind/bitcoind_json.cpp \
diff --git a/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj b/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj
index 121a64e6..827b5562 100644
--- a/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj
@@ -126,15 +126,15 @@
+
+
+
-
-
$(IntDir)test_parsers_electrum_version.obj
-
diff --git a/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters
index d8c24b2d..ca0576ff 100644
--- a/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters
@@ -63,13 +63,16 @@
src\parsers
-
+
+ src\parsers
+
+
src\parsers
-
+
src\parsers
-
+
src\parsers
@@ -81,9 +84,6 @@
src\parsers
-
- src\parsers
-
src\protocols\admin
diff --git a/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj b/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj
index db05e8f9..0bb09d0d 100644
--- a/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj
@@ -122,19 +122,22 @@
-
+
+
+
+
+
+
+
-
-
-
@@ -188,7 +191,11 @@
-
+
+
+
+
+
@@ -210,16 +217,16 @@
+
+
+
-
-
-
diff --git a/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj.filters
index 7eab2f40..6c9dae31 100644
--- a/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-server/libbitcoin-server.vcxproj.filters
@@ -19,61 +19,76 @@
{73CE0AC2-ECB2-4E8D-0000-000000000003}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000004}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000005}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000006}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000007}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000008}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000009}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000A}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000B}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000C}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000D}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000E}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000F}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000001}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000002}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000003}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000004}
+
+ {73CE0AC2-ECB2-4E8D-0000-000000000005}
+
+
+ {73CE0AC2-ECB2-4E8D-0000-000000000006}
+
src
-
- src
+
+ src\error
+
+
+ src\error
+
+
+ src\error
+
+
+ src\error
src
@@ -84,19 +99,22 @@
src\parsers
-
+
src\parsers
-
+
src\parsers
-
+
src\parsers
-
+
+ src\parsers
+
+
src\parsers
-
+
src\parsers
@@ -108,9 +126,6 @@
src\parsers
-
- src\parsers
-
src\protocols\admin
@@ -266,8 +281,20 @@
include\bitcoin\server
-
- include\bitcoin\server
+
+ include\bitcoin\server\error
+
+
+ include\bitcoin\server\error
+
+
+ include\bitcoin\server\error
+
+
+ include\bitcoin\server\error
+
+
+ include\bitcoin\server\error
include\bitcoin\server\interfaces
@@ -332,19 +359,22 @@
include\bitcoin\server\parsers
-
+
include\bitcoin\server\parsers
-
+
include\bitcoin\server\parsers
-
+
include\bitcoin\server\parsers
-
+
+ include\bitcoin\server\parsers
+
+
include\bitcoin\server\parsers
-
+
include\bitcoin\server\parsers
@@ -359,9 +389,6 @@
include\bitcoin\server\parsers
-
- include\bitcoin\server\parsers
-
include\bitcoin\server\protocols
diff --git a/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj b/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj
index 010a810a..2083eddb 100644
--- a/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj
+++ b/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj
@@ -126,15 +126,15 @@
+
+
+
-
-
$(IntDir)test_parsers_electrum_version.obj
-
diff --git a/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters
index d8c24b2d..ca0576ff 100644
--- a/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters
+++ b/builds/msvc/vs2026/libbitcoin-server-test/libbitcoin-server-test.vcxproj.filters
@@ -63,13 +63,16 @@
src\parsers
-
+
+ src\parsers
+
+
src\parsers
-
+
src\parsers
-
+
src\parsers
@@ -81,9 +84,6 @@
src\parsers
-
- src\parsers
-
src\protocols\admin
diff --git a/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj b/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj
index c1d26b50..e90a146d 100644
--- a/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj
+++ b/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj
@@ -122,19 +122,22 @@
-
+
+
+
+
+
+
+
-
-
-
@@ -188,7 +191,11 @@
-
+
+
+
+
+
@@ -210,16 +217,16 @@
+
+
+
-
-
-
diff --git a/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj.filters
index 7eab2f40..6c9dae31 100644
--- a/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj.filters
+++ b/builds/msvc/vs2026/libbitcoin-server/libbitcoin-server.vcxproj.filters
@@ -19,61 +19,76 @@
{73CE0AC2-ECB2-4E8D-0000-000000000003}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000004}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000005}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000006}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000007}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000008}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000009}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000A}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000B}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000C}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000D}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000E}
-
+
{73CE0AC2-ECB2-4E8D-0000-00000000000F}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000001}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000002}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000003}
-
+
{73CE0AC2-ECB2-4E8D-0000-000000000004}
+
+ {73CE0AC2-ECB2-4E8D-0000-000000000005}
+
+
+ {73CE0AC2-ECB2-4E8D-0000-000000000006}
+
src
-
- src
+
+ src\error
+
+
+ src\error
+
+
+ src\error
+
+
+ src\error
src
@@ -84,19 +99,22 @@
src\parsers
-
+
src\parsers
-
+
src\parsers
-
+
src\parsers
-
+
+ src\parsers
+
+
src\parsers
-
+
src\parsers
@@ -108,9 +126,6 @@
src\parsers
-
- src\parsers
-
src\protocols\admin
@@ -266,8 +281,20 @@
include\bitcoin\server
-
- include\bitcoin\server
+
+ include\bitcoin\server\error
+
+
+ include\bitcoin\server\error
+
+
+ include\bitcoin\server\error
+
+
+ include\bitcoin\server\error
+
+
+ include\bitcoin\server\error
include\bitcoin\server\interfaces
@@ -332,19 +359,22 @@
include\bitcoin\server\parsers
-
+
include\bitcoin\server\parsers
-
+
include\bitcoin\server\parsers
-
+
include\bitcoin\server\parsers
-
+
+ include\bitcoin\server\parsers
+
+
include\bitcoin\server\parsers
-
+
include\bitcoin\server\parsers
@@ -359,9 +389,6 @@
include\bitcoin\server\parsers
-
- include\bitcoin\server\parsers
-
include\bitcoin\server\protocols
diff --git a/include/bitcoin/server.hpp b/include/bitcoin/server.hpp
index 2be1321c..187668f3 100644
--- a/include/bitcoin/server.hpp
+++ b/include/bitcoin/server.hpp
@@ -17,7 +17,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -28,6 +27,11 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
#include
#include
#include
@@ -48,16 +52,16 @@
#include
#include
#include
+#include
+#include
+#include
#include
#include
-#include
#include
-#include
#include
#include
#include
#include
-#include
#include
#include
#include
diff --git a/include/bitcoin/server/define.hpp b/include/bitcoin/server/define.hpp
index 26c35454..4ad36222 100644
--- a/include/bitcoin/server/define.hpp
+++ b/include/bitcoin/server/define.hpp
@@ -20,7 +20,7 @@
#define LIBBITCOIN_SERVER_DEFINE_HPP
#include
-#include
+#include
/// Now we use the generic helper definitions above to define BCS_API
/// and BCS_INTERNAL. BCS_API is used for the public API symbols. It either DLL
diff --git a/include/bitcoin/server/error/bitcoind_error_t.hpp b/include/bitcoin/server/error/bitcoind_error_t.hpp
new file mode 100644
index 00000000..d0d4d05b
--- /dev/null
+++ b/include/bitcoin/server/error/bitcoind_error_t.hpp
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2011-2026 libbitcoin developers
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#ifndef LIBBITCOIN_SERVER_ERROR_BITCOIND_ERROR_T_HPP
+#define LIBBITCOIN_SERVER_ERROR_BITCOIND_ERROR_T_HPP
+
+#include
+#include
+
+namespace libbitcoin {
+namespace server {
+namespace error {
+namespace bitcoind {
+
+/// Values are bitcoind wire codes, published as the json-rpc error code.
+enum error_t : int32_t
+{
+ /// general
+ success = 0,
+
+ /// json-rpc
+ invalid_request = -32600,
+ method_not_found = -32601,
+ invalid_params = -32602,
+ internal_error = -32603,
+ parse_error = -32700,
+
+ /// application
+ misc_error = -1,
+ forbidden_by_safe_mode = -2,
+ type_error = -3,
+ invalid_address_or_key = -5,
+ out_of_memory = -7,
+ invalid_parameter = -8,
+ database_error = -20,
+ deserialization_error = -22,
+ verify_error = -25,
+ verify_rejected = -26,
+ verify_already_in_utxo_set = -27,
+ in_warmup = -28,
+ method_deprecated = -32,
+ limit_exceeded = -37,
+
+ /// peer-to-peer client
+ client_not_connected = -9,
+ client_in_initial_download = -10,
+ client_node_already_added = -23,
+ client_node_not_added = -24,
+ client_node_not_connected = -29,
+ client_invalid_ip_or_subnet = -30,
+ client_p2p_disabled = -31,
+ client_node_capacity_reached = -34,
+
+ /// chain
+ client_mempool_disabled = -33,
+
+ /// wallet
+ wallet_error = -4,
+ wallet_insufficient_funds = -6,
+ wallet_invalid_label_name = -11,
+ wallet_keypool_ran_out = -12,
+ wallet_unlock_needed = -13,
+ wallet_passphrase_incorrect = -14,
+ wallet_wrong_enc_state = -15,
+ wallet_encryption_failed = -16,
+ wallet_already_unlocked = -17,
+ wallet_not_found = -18,
+ wallet_not_specified = -19,
+ wallet_already_loaded = -35,
+ wallet_already_exists = -36
+};
+
+// No current need for error_code equivalence mapping.
+DECLARE_ERROR_T_CODE_CATEGORY(error);
+
+/// Map a foreign category code to the bitcoind code space, where a store
+/// fault is internal and any other failure is reported as the given code.
+/// A code of this category passes through unchanged.
+BC_API code translate(const code& ec, error_t failure) NOEXCEPT;
+
+/// The bitcoind (bip22) reject token for a validation code, message otherwise.
+BC_API std::string reject(const code& ec) NOEXCEPT;
+
+} // namespace bitcoind
+} // namespace error
+} // namespace server
+} // namespace libbitcoin
+
+DECLARE_STD_ERROR_REGISTRATION(bc::server::error::bitcoind::error)
+
+#endif
diff --git a/include/bitcoin/server/error/btcd_error_t.hpp b/include/bitcoin/server/error/btcd_error_t.hpp
new file mode 100644
index 00000000..4014490f
--- /dev/null
+++ b/include/bitcoin/server/error/btcd_error_t.hpp
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2011-2026 libbitcoin developers
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#ifndef LIBBITCOIN_SERVER_ERROR_BTCD_ERROR_T_HPP
+#define LIBBITCOIN_SERVER_ERROR_BTCD_ERROR_T_HPP
+
+#include
+#include
+
+namespace libbitcoin {
+namespace server {
+namespace error {
+namespace btcd {
+
+/// Values are btcjson wire codes, published as the json-rpc error code.
+/// unimplemented aliases misc_error, as btcd reports both as -1.
+enum error_t : int32_t
+{
+ /// general
+ success = 0,
+
+ /// json-rpc
+ invalid_request = -32600,
+ method_not_found = -32601,
+ invalid_params = -32602,
+ internal_error = -32603,
+ parse_error = -32700,
+
+ /// application
+ misc_error = -1,
+ unimplemented = -1,
+ forbidden_by_safe_mode = -2,
+ type_error = -3,
+ wallet_error = -4,
+ invalid_address_or_key = -5,
+ wallet_insufficient_funds = -6,
+ out_of_memory = -7,
+ invalid_parameter = -8,
+ client_not_connected = -9,
+ client_in_initial_download = -10,
+ wallet_invalid_account_name = -11,
+ wallet_keypool_ran_out = -12,
+ wallet_unlock_needed = -13,
+ wallet_passphrase_incorrect = -14,
+ wallet_wrong_enc_state = -15,
+ wallet_encryption_failed = -16,
+ wallet_already_unlocked = -17,
+ wallet_not_found = -18,
+ wallet_not_specified = -19,
+ database_error = -20,
+ deserialization_error = -22,
+ client_node_already_added = -23,
+ client_node_not_added = -24,
+ verify_error = -25,
+ verify_rejected = -26,
+ verify_already_in_chain = -27,
+ in_warmup = -28,
+ client_node_not_connected = -29,
+ client_invalid_ip_or_subnet = -30,
+ method_deprecated = -32,
+ client_mempool_disabled = -33
+};
+
+// No current need for error_code equivalence mapping.
+DECLARE_ERROR_T_CODE_CATEGORY(error);
+
+/// Map a foreign category code to the btcd code space, where a store fault
+/// is internal and any other failure is reported as the given code.
+/// A code of this category passes through unchanged.
+BC_API code translate(const code& ec, error_t failure) NOEXCEPT;
+
+} // namespace btcd
+} // namespace error
+} // namespace server
+} // namespace libbitcoin
+
+DECLARE_STD_ERROR_REGISTRATION(bc::server::error::btcd::error)
+
+#endif
diff --git a/include/bitcoin/server/error/electrum_error_t.hpp b/include/bitcoin/server/error/electrum_error_t.hpp
new file mode 100644
index 00000000..33b53337
--- /dev/null
+++ b/include/bitcoin/server/error/electrum_error_t.hpp
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2011-2026 libbitcoin developers
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#ifndef LIBBITCOIN_SERVER_ERROR_ELECTRUM_ERROR_T_HPP
+#define LIBBITCOIN_SERVER_ERROR_ELECTRUM_ERROR_T_HPP
+
+#include
+#include
+
+namespace libbitcoin {
+namespace server {
+namespace error {
+namespace electrum {
+
+/// Values are electrumx/aiorpcx wire codes, published as the json-rpc error
+/// code. The electrum client disconnects on method_not_found, internal_error,
+/// excessive_resource_usage and server_busy.
+enum error_t : int32_t
+{
+ /// general
+ success = 0,
+
+ /// application (electrumx)
+ bad_request = 1,
+ daemon_error = 2,
+ excessive_history = 10'001,
+
+ /// json-rpc (aiorpcx)
+ invalid_request = -32600,
+ method_not_found = -32601,
+ invalid_args = -32602,
+ internal_error = -32603,
+ parse_error = -32700,
+
+ /// resource (aiorpcx)
+ unavailable = -100,
+ excessive_resource_usage = -101,
+ server_busy = -102
+};
+
+// No current need for error_code equivalence mapping.
+DECLARE_ERROR_T_CODE_CATEGORY(error);
+
+/// Map a foreign category code to the electrum code space, where a depth
+/// limit is excessive history, any other store fault is a daemon error, and
+/// any other failure is reported as the given code. A code of this category
+/// passes through unchanged.
+BC_API code translate(const code& ec, error_t failure) NOEXCEPT;
+
+} // namespace electrum
+} // namespace error
+} // namespace server
+} // namespace libbitcoin
+
+DECLARE_STD_ERROR_REGISTRATION(bc::server::error::electrum::error)
+
+#endif
diff --git a/include/bitcoin/server/error/error.hpp b/include/bitcoin/server/error/error.hpp
new file mode 100644
index 00000000..614d124d
--- /dev/null
+++ b/include/bitcoin/server/error/error.hpp
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2011-2026 libbitcoin developers
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#ifndef LIBBITCOIN_SERVER_ERROR_ERROR_HPP
+#define LIBBITCOIN_SERVER_ERROR_ERROR_HPP
+
+#include
+#include
+#include
+#include
+
+#endif
diff --git a/include/bitcoin/server/error.hpp b/include/bitcoin/server/error/error_t.hpp
similarity index 94%
rename from include/bitcoin/server/error.hpp
rename to include/bitcoin/server/error/error_t.hpp
index 3160cf4c..5d5ba7cf 100644
--- a/include/bitcoin/server/error.hpp
+++ b/include/bitcoin/server/error/error_t.hpp
@@ -16,8 +16,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-#ifndef LIBBITCOIN_SERVER_ERROR_HPP
-#define LIBBITCOIN_SERVER_ERROR_HPP
+#ifndef LIBBITCOIN_SERVER_ERROR_ERROR_T_HPP
+#define LIBBITCOIN_SERVER_ERROR_ERROR_T_HPP
#include
#include
@@ -68,8 +68,7 @@ enum error_t : uint8_t
target_overflow,
maximum_depth,
wrong_version,
- server_error,
- method_unauthorized
+ server_error
};
// No current need for error_code equivalence mapping.
diff --git a/include/bitcoin/server/parsers/block_stats.hpp b/include/bitcoin/server/parsers/bitcoind_block_stats.hpp
similarity index 90%
rename from include/bitcoin/server/parsers/block_stats.hpp
rename to include/bitcoin/server/parsers/bitcoind_block_stats.hpp
index 4137540a..4cd542c1 100644
--- a/include/bitcoin/server/parsers/block_stats.hpp
+++ b/include/bitcoin/server/parsers/bitcoind_block_stats.hpp
@@ -16,8 +16,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-#ifndef LIBBITCOIN_SERVER_PARSERS_BLOCK_STATS_HPP
-#define LIBBITCOIN_SERVER_PARSERS_BLOCK_STATS_HPP
+#ifndef LIBBITCOIN_SERVER_PARSERS_BITCOIND_BLOCK_STATS_HPP
+#define LIBBITCOIN_SERVER_PARSERS_BITCOIND_BLOCK_STATS_HPP
#include
diff --git a/include/bitcoin/server/parsers/descriptor.hpp b/include/bitcoin/server/parsers/bitcoind_descriptor.hpp
similarity index 83%
rename from include/bitcoin/server/parsers/descriptor.hpp
rename to include/bitcoin/server/parsers/bitcoind_descriptor.hpp
index 5bee7dc9..0b819c07 100644
--- a/include/bitcoin/server/parsers/descriptor.hpp
+++ b/include/bitcoin/server/parsers/bitcoind_descriptor.hpp
@@ -16,8 +16,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-#ifndef LIBBITCOIN_SERVER_PARSERS_DESCRIPTOR_HPP
-#define LIBBITCOIN_SERVER_PARSERS_DESCRIPTOR_HPP
+#ifndef LIBBITCOIN_SERVER_PARSERS_BITCOIND_DESCRIPTOR_HPP
+#define LIBBITCOIN_SERVER_PARSERS_BITCOIND_DESCRIPTOR_HPP
#include
@@ -25,8 +25,7 @@ namespace libbitcoin {
namespace server {
/// The bip380 output descriptor checksum, empty on invalid characters.
-BCS_API std::string descriptor_checksum(
- const std::string& descriptor) NOEXCEPT;
+BCS_API std::string descriptor_checksum(const std::string& descriptor) NOEXCEPT;
} // namespace server
} // namespace libbitcoin
diff --git a/include/bitcoin/server/parsers/partial_merkle.hpp b/include/bitcoin/server/parsers/bitcoind_merkle.hpp
similarity index 94%
rename from include/bitcoin/server/parsers/partial_merkle.hpp
rename to include/bitcoin/server/parsers/bitcoind_merkle.hpp
index 0495bad1..a5281c2b 100644
--- a/include/bitcoin/server/parsers/partial_merkle.hpp
+++ b/include/bitcoin/server/parsers/bitcoind_merkle.hpp
@@ -16,8 +16,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-#ifndef LIBBITCOIN_SERVER_PARSERS_PARTIAL_MERKLE_HPP
-#define LIBBITCOIN_SERVER_PARSERS_PARTIAL_MERKLE_HPP
+#ifndef LIBBITCOIN_SERVER_PARSERS_BITCOIND_MERKLE_HPP
+#define LIBBITCOIN_SERVER_PARSERS_BITCOIND_MERKLE_HPP
#include
diff --git a/include/bitcoin/server/parsers/parsers.hpp b/include/bitcoin/server/parsers/parsers.hpp
index 526a1655..917c93ac 100644
--- a/include/bitcoin/server/parsers/parsers.hpp
+++ b/include/bitcoin/server/parsers/parsers.hpp
@@ -21,14 +21,14 @@
#include
#include
+#include
+#include
+#include
#include
#include
-#include
#include
-#include
#include
#include
#include
-#include
#endif
diff --git a/src/error/bitcoind_error_t.cpp b/src/error/bitcoind_error_t.cpp
new file mode 100644
index 00000000..d4b74b45
--- /dev/null
+++ b/src/error/bitcoind_error_t.cpp
@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) 2011-2026 libbitcoin developers
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#include
+
+#include
+
+namespace libbitcoin {
+namespace server {
+namespace error {
+namespace bitcoind {
+
+DEFINE_ERROR_T_MESSAGE_MAP(error)
+{
+ // general
+ { success, "success" },
+
+ // json-rpc
+ { invalid_request, "invalid_request" },
+ { method_not_found, "method_not_found" },
+ { invalid_params, "invalid_params" },
+ { internal_error, "internal_error" },
+ { parse_error, "parse_error" },
+
+ // application
+ { misc_error, "misc_error" },
+ { forbidden_by_safe_mode, "forbidden_by_safe_mode" },
+ { type_error, "type_error" },
+ { invalid_address_or_key, "invalid_address_or_key" },
+ { out_of_memory, "out_of_memory" },
+ { invalid_parameter, "invalid_parameter" },
+ { database_error, "database_error" },
+ { deserialization_error, "deserialization_error" },
+ { verify_error, "verify_error" },
+ { verify_rejected, "verify_rejected" },
+ { verify_already_in_utxo_set, "verify_already_in_utxo_set" },
+ { in_warmup, "in_warmup" },
+ { method_deprecated, "method_deprecated" },
+ { limit_exceeded, "limit_exceeded" },
+
+ // peer-to-peer client
+ { client_not_connected, "client_not_connected" },
+ { client_in_initial_download, "client_in_initial_download" },
+ { client_node_already_added, "client_node_already_added" },
+ { client_node_not_added, "client_node_not_added" },
+ { client_node_not_connected, "client_node_not_connected" },
+ { client_invalid_ip_or_subnet, "client_invalid_ip_or_subnet" },
+ { client_p2p_disabled, "client_p2p_disabled" },
+ { client_node_capacity_reached, "client_node_capacity_reached" },
+
+ // chain
+ { client_mempool_disabled, "client_mempool_disabled" },
+
+ // wallet
+ { wallet_error, "wallet_error" },
+ { wallet_insufficient_funds, "wallet_insufficient_funds" },
+ { wallet_invalid_label_name, "wallet_invalid_label_name" },
+ { wallet_keypool_ran_out, "wallet_keypool_ran_out" },
+ { wallet_unlock_needed, "wallet_unlock_needed" },
+ { wallet_passphrase_incorrect, "wallet_passphrase_incorrect" },
+ { wallet_wrong_enc_state, "wallet_wrong_enc_state" },
+ { wallet_encryption_failed, "wallet_encryption_failed" },
+ { wallet_already_unlocked, "wallet_already_unlocked" },
+ { wallet_not_found, "wallet_not_found" },
+ { wallet_not_specified, "wallet_not_specified" },
+ { wallet_already_loaded, "wallet_already_loaded" },
+ { wallet_already_exists, "wallet_already_exists" }
+};
+
+DEFINE_ERROR_T_CATEGORY(error, "bitcoind", "bitcoind code")
+
+code translate(const code& ec, error_t failure) NOEXCEPT
+{
+ if (!ec)
+ return success;
+
+ if (error_category::contains(ec))
+ return ec;
+
+ if (database::error::error_category::contains(ec))
+ return internal_error;
+
+ return failure;
+}
+
+// bitcoind reject tokens by transaction code (mempool vocabulary).
+static const message_map
+transaction_rejects
+{
+ { system::error::empty_transaction, "bad-txns-vin-empty" },
+ { system::error::previous_output_null, "bad-txns-prevout-null" },
+ { system::error::spend_overflow, "bad-txns-txouttotal-toolarge" },
+ { system::error::invalid_coinbase_script_size, "bad-cb-length" },
+ { system::error::coinbase_transaction, "coinbase" },
+ { system::error::transaction_internal_double_spend, "bad-txns-inputs-duplicate" },
+ { system::error::transaction_size_limit, "bad-txns-oversize" },
+ { system::error::transaction_legacy_sigop_limit, "bad-txns-too-many-sigops" },
+ { system::error::unspent_duplicate, "bad-txns-BIP30" },
+ { system::error::missing_previous_output, "bad-txns-inputs-missingorspent" },
+ { system::error::coinbase_maturity, "bad-txns-premature-spend-of-coinbase" },
+ { system::error::spend_exceeds_value, "bad-txns-in-belowout" },
+ { system::error::transaction_sigop_limit, "bad-txns-too-many-sigops" },
+ { system::error::absolute_time_locked, "non-final" },
+ { system::error::relative_time_locked, "non-BIP68-final" },
+ { system::error::transaction_weight_limit, "tx-size" },
+ { system::error::confirmed_double_spend, "bad-txns-inputs-missingorspent" }
+};
+
+// bitcoind reject tokens by block code (submission vocabulary).
+static const message_map
+block_rejects
+{
+ { system::error::invalid_proof_of_work, "high-hash" },
+ { system::error::futuristic_timestamp, "time-too-new" },
+ { system::error::insufficient_block_version, "bad-version" },
+ { system::error::anachronistic_timestamp, "time-too-old" },
+ { system::error::incorrect_proof_of_work, "bad-diffbits" },
+ { system::error::early_timestamp, "time-too-old" },
+ { system::error::orphan_block, "prev-blk-not-found" },
+ { system::error::block_size_limit, "bad-blk-length" },
+ { system::error::empty_block, "bad-blk-length" },
+ { system::error::first_not_coinbase, "bad-cb-missing" },
+ { system::error::extra_coinbases, "bad-cb-multiple" },
+ { system::error::internal_duplicate, "bad-txns-duplicate" },
+ { system::error::block_internal_double_spend, "bad-txns-inputs-missingorspent" },
+ { system::error::forward_reference, "bad-txns-inputs-missingorspent" },
+ { system::error::invalid_transaction_commitment, "bad-txnmrklroot" },
+ { system::error::block_legacy_sigop_limit, "bad-blk-sigops" },
+ { system::error::block_non_final, "bad-txns-nonfinal" },
+ { system::error::coinbase_height_mismatch, "bad-cb-height" },
+ { system::error::coinbase_value_limit, "bad-cb-amount" },
+ { system::error::block_sigop_limit, "bad-blk-sigops" },
+ { system::error::invalid_witness_commitment, "bad-witness-merkle-match" },
+ { system::error::block_weight_limit, "bad-blk-weight" },
+ { system::error::invalid_signature, "mandatory-script-verify-flag-failed" },
+ { system::error::unspent_coinbase_collision, "bad-txns-BIP30" }
+};
+
+std::string reject(const code& ec) NOEXCEPT
+{
+ // The organizer reports an unassociated block as a node orphan.
+ if ((ec == node::error::orphan_block) || (ec == node::error::orphan_header))
+ return "prev-blk-not-found";
+
+ if ((ec == node::error::duplicate_block) ||
+ (ec == node::error::duplicate_header))
+ return "duplicate";
+
+ using namespace system::error;
+ if (transaction_error_category::contains(ec))
+ {
+ const auto token = transaction_rejects.find(
+ static_cast(ec.value()));
+ if (token != transaction_rejects.end())
+ return token->second;
+ }
+
+ if (block_error_category::contains(ec))
+ {
+ const auto token = block_rejects.find(
+ static_cast(ec.value()));
+ if (token != block_rejects.end())
+ return token->second;
+ }
+
+ return ec.message();
+}
+
+} // namespace bitcoind
+} // namespace error
+} // namespace server
+} // namespace libbitcoin
diff --git a/src/error/btcd_error_t.cpp b/src/error/btcd_error_t.cpp
new file mode 100644
index 00000000..a7dba399
--- /dev/null
+++ b/src/error/btcd_error_t.cpp
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) 2011-2026 libbitcoin developers
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#include
+
+#include
+
+namespace libbitcoin {
+namespace server {
+namespace error {
+namespace btcd {
+
+DEFINE_ERROR_T_MESSAGE_MAP(error)
+{
+ // general
+ { success, "success" },
+
+ // json-rpc
+ { invalid_request, "invalid_request" },
+ { method_not_found, "method_not_found" },
+ { invalid_params, "invalid_params" },
+ { internal_error, "internal_error" },
+ { parse_error, "parse_error" },
+
+ // application
+ { misc_error, "misc_error" },
+ { forbidden_by_safe_mode, "forbidden_by_safe_mode" },
+ { type_error, "type_error" },
+ { wallet_error, "wallet_error" },
+ { invalid_address_or_key, "invalid_address_or_key" },
+ { wallet_insufficient_funds, "wallet_insufficient_funds" },
+ { out_of_memory, "out_of_memory" },
+ { invalid_parameter, "invalid_parameter" },
+ { client_not_connected, "client_not_connected" },
+ { client_in_initial_download, "client_in_initial_download" },
+ { wallet_invalid_account_name, "wallet_invalid_account_name" },
+ { wallet_keypool_ran_out, "wallet_keypool_ran_out" },
+ { wallet_unlock_needed, "wallet_unlock_needed" },
+ { wallet_passphrase_incorrect, "wallet_passphrase_incorrect" },
+ { wallet_wrong_enc_state, "wallet_wrong_enc_state" },
+ { wallet_encryption_failed, "wallet_encryption_failed" },
+ { wallet_already_unlocked, "wallet_already_unlocked" },
+ { wallet_not_found, "wallet_not_found" },
+ { wallet_not_specified, "wallet_not_specified" },
+ { database_error, "database_error" },
+ { deserialization_error, "deserialization_error" },
+ { client_node_already_added, "client_node_already_added" },
+ { client_node_not_added, "client_node_not_added" },
+ { verify_error, "verify_error" },
+ { verify_rejected, "verify_rejected" },
+ { verify_already_in_chain, "verify_already_in_chain" },
+ { in_warmup, "in_warmup" },
+ { client_node_not_connected, "client_node_not_connected" },
+ { client_invalid_ip_or_subnet, "client_invalid_ip_or_subnet" },
+ { method_deprecated, "method_deprecated" },
+ { client_mempool_disabled, "client_mempool_disabled" }
+};
+
+DEFINE_ERROR_T_CATEGORY(error, "btcd", "btcd code")
+
+code translate(const code& ec, error_t failure) NOEXCEPT
+{
+ if (!ec)
+ return success;
+
+ if (error_category::contains(ec))
+ return ec;
+
+ if (database::error::error_category::contains(ec))
+ return internal_error;
+
+ return failure;
+}
+
+} // namespace btcd
+} // namespace error
+} // namespace server
+} // namespace libbitcoin
diff --git a/src/error/electrum_error_t.cpp b/src/error/electrum_error_t.cpp
new file mode 100644
index 00000000..50c83321
--- /dev/null
+++ b/src/error/electrum_error_t.cpp
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2011-2026 libbitcoin developers
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#include
+
+#include
+
+namespace libbitcoin {
+namespace server {
+namespace error {
+namespace electrum {
+
+DEFINE_ERROR_T_MESSAGE_MAP(error)
+{
+ // general
+ { success, "success" },
+
+ // application
+ { bad_request, "bad_request" },
+ { daemon_error, "daemon_error" },
+ { excessive_history, "excessive_history" },
+
+ // json-rpc
+ { invalid_request, "invalid_request" },
+ { method_not_found, "method_not_found" },
+ { invalid_args, "invalid_args" },
+ { internal_error, "internal_error" },
+ { parse_error, "parse_error" },
+
+ // resource
+ { unavailable, "unavailable" },
+ { excessive_resource_usage, "excessive_resource_usage" },
+ { server_busy, "server_busy" }
+};
+
+DEFINE_ERROR_T_CATEGORY(error, "electrum", "electrum code")
+
+code translate(const code& ec, error_t failure) NOEXCEPT
+{
+ if (!ec)
+ return success;
+
+ if (error_category::contains(ec))
+ return ec;
+
+ if (ec == database::error::depth_limited)
+ return excessive_history;
+
+ if (database::error::error_category::contains(ec))
+ return daemon_error;
+
+ return failure;
+}
+
+} // namespace electrum
+} // namespace error
+} // namespace server
+} // namespace libbitcoin
diff --git a/src/error.cpp b/src/error/error_t.cpp
similarity index 94%
rename from src/error.cpp
rename to src/error/error_t.cpp
index e38084cb..af3fabbe 100644
--- a/src/error.cpp
+++ b/src/error/error_t.cpp
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-#include
+#include
#include
@@ -58,8 +58,7 @@ DEFINE_ERROR_T_MESSAGE_MAP(error)
{ target_overflow, "target_overflow" },
{ maximum_depth, "maximum_depth" },
{ wrong_version, "wrong_version" },
- { server_error, "server_error" },
- { method_unauthorized, "method_unauthorized" }
+ { server_error, "server_error" }
};
DEFINE_ERROR_T_CATEGORY(error, "server", "server code")
diff --git a/src/parsers/block_stats.cpp b/src/parsers/bitcoind_block_stats.cpp
similarity index 99%
rename from src/parsers/block_stats.cpp
rename to src/parsers/bitcoind_block_stats.cpp
index 1a5b5504..cc09df34 100644
--- a/src/parsers/block_stats.cpp
+++ b/src/parsers/bitcoind_block_stats.cpp
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-#include
+#include
#include
#include
diff --git a/src/parsers/descriptor.cpp b/src/parsers/bitcoind_descriptor.cpp
similarity index 98%
rename from src/parsers/descriptor.cpp
rename to src/parsers/bitcoind_descriptor.cpp
index 918f66d5..23b70ccb 100644
--- a/src/parsers/descriptor.cpp
+++ b/src/parsers/bitcoind_descriptor.cpp
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-#include
+#include
#include
diff --git a/src/parsers/partial_merkle.cpp b/src/parsers/bitcoind_merkle.cpp
similarity index 99%
rename from src/parsers/partial_merkle.cpp
rename to src/parsers/bitcoind_merkle.cpp
index 5152dec5..cf98a45a 100644
--- a/src/parsers/partial_merkle.cpp
+++ b/src/parsers/bitcoind_merkle.cpp
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-#include
+#include
#include
diff --git a/src/protocols/bitcoind/protocol_bitcoind.cpp b/src/protocols/bitcoind/protocol_bitcoind.cpp
index 89f97616..2efb605d 100644
--- a/src/protocols/bitcoind/protocol_bitcoind.cpp
+++ b/src/protocols/bitcoind/protocol_bitcoind.cpp
@@ -132,12 +132,12 @@ void protocol_bitcoind::handle_receive_post(const code& ec,
// The credential may be restricted to a subset of interface methods.
if (!permitted(message.method))
{
- send_error(error::method_unauthorized);
+ send_forbidden(*post);
return;
}
// No subgroup interface defines the method.
- send_error(network::error::unexpected_method);
+ send_error(error::bitcoind::method_not_found);
}
// The websocket transport of the interface: subgroup protocols handle claimed
@@ -174,12 +174,12 @@ void protocol_bitcoind::dispatch_websocket(
// The credential may be restricted to a subset of interface methods.
if (!permitted(message.method))
{
- send_error(error::method_unauthorized);
+ stop(network::error::unauthorized);
return;
}
// No subgroup interface defines the method.
- send_error(network::error::unexpected_method);
+ send_error(error::bitcoind::method_not_found);
}
// Help.
diff --git a/src/protocols/bitcoind/protocol_bitcoind_blockchain.cpp b/src/protocols/bitcoind/protocol_bitcoind_blockchain.cpp
index b7831b1a..8179518c 100644
--- a/src/protocols/bitcoind/protocol_bitcoind_blockchain.cpp
+++ b/src/protocols/bitcoind/protocol_bitcoind_blockchain.cpp
@@ -154,24 +154,28 @@ bool protocol_bitcoind_blockchain::handle_get_block(const code& ec,
hash_digest hash{};
if (!decode_hash(hash, blockhash))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
- size_t level{};
- if (!to_integer(level, verbosity) || level > block_verbosity::prevouts)
+ int64_t requested{};
+ if (!to_integer(requested, verbosity))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::misc_error);
return true;
}
+ // bitcoind clamps out of range verbosity.
+ const auto level = limit(requested, block_verbosity::prevouts);
+
constexpr auto witness = true;
const auto& query = archive();
const auto link = query.to_header(hash);
const auto block = query.get_block(link, witness);
if (!block)
{
- send_error(error::not_found, blockhash, blockhash.size());
+ send_error(error::bitcoind::invalid_address_or_key, blockhash,
+ blockhash.size());
return true;
}
@@ -219,7 +223,7 @@ bool protocol_bitcoind_blockchain::handle_get_block_chain_info(const code& ec,
if (!chain_info(out, archive(), node_settings().limited_blocks,
is_current_chain(true)))
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -247,21 +251,21 @@ bool protocol_bitcoind_blockchain::handle_get_block_filter(const code& ec,
if (filtertype != basic_filter)
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_address_or_key);
return true;
}
hash_digest hash{};
if (!decode_hash(hash, blockhash))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
const auto& query = archive();
if (!query.filter_enabled())
{
- send_error(error::not_implemented);
+ send_error(error::bitcoind::misc_error);
return true;
}
@@ -271,7 +275,8 @@ bool protocol_bitcoind_blockchain::handle_get_block_filter(const code& ec,
if (!query.get_filter_body(filter, link) ||
!query.get_filter_head(filter_header, link))
{
- send_error(error::not_found, blockhash, blockhash.size());
+ send_error(error::bitcoind::invalid_address_or_key, blockhash,
+ blockhash.size());
return true;
}
@@ -292,7 +297,7 @@ bool protocol_bitcoind_blockchain::handle_get_block_hash(const code& ec,
size_t block_height{};
if (!to_integer(block_height, height))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -300,7 +305,7 @@ bool protocol_bitcoind_blockchain::handle_get_block_hash(const code& ec,
const auto link = query.to_confirmed(block_height);
if (link.is_terminal())
{
- send_error(error::not_found);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -318,7 +323,7 @@ bool protocol_bitcoind_blockchain::handle_get_block_header(const code& ec,
hash_digest hash{};
if (!decode_hash(hash, blockhash))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -327,7 +332,8 @@ bool protocol_bitcoind_blockchain::handle_get_block_header(const code& ec,
const auto header = query.get_header(link);
if (!header)
{
- send_error(error::not_found, blockhash, blockhash.size());
+ send_error(error::bitcoind::invalid_address_or_key, blockhash,
+ blockhash.size());
return true;
}
@@ -358,7 +364,7 @@ bool protocol_bitcoind_blockchain::handle_get_block_stats(const code& ec,
hash_digest hash{};
if (!decode_hash(hash, std::get(hash_or_height.value())))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -369,7 +375,7 @@ bool protocol_bitcoind_blockchain::handle_get_block_stats(const code& ec,
size_t height{};
if (!to_integer(height, std::get(hash_or_height.value())))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -377,14 +383,14 @@ bool protocol_bitcoind_blockchain::handle_get_block_stats(const code& ec,
}
else
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::type_error);
return true;
}
size_t height{};
if (!query.get_height(height, link) || query.to_confirmed(height) != link)
{
- send_error(error::not_found);
+ send_error(error::bitcoind::invalid_address_or_key);
return true;
}
@@ -392,7 +398,7 @@ bool protocol_bitcoind_blockchain::handle_get_block_stats(const code& ec,
const auto block = query.get_block(link, true);
if (!block || !query.populate_without_metadata(*block))
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::misc_error);
return true;
}
@@ -416,7 +422,7 @@ bool protocol_bitcoind_blockchain::handle_get_block_stats(const code& ec,
{
if (!std::holds_alternative(stat.value()))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::type_error);
return true;
}
@@ -424,7 +430,7 @@ bool protocol_bitcoind_blockchain::handle_get_block_stats(const code& ec,
const auto it = result.find(name);
if (it == result.end())
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -453,7 +459,7 @@ bool protocol_bitcoind_blockchain::handle_get_chain_tx_stats(const code& ec,
hash_digest hash{};
if (!decode_hash(hash, blockhash))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -463,7 +469,8 @@ bool protocol_bitcoind_blockchain::handle_get_chain_tx_stats(const code& ec,
size_t height{};
if (!query.get_height(height, link) || query.to_confirmed(height) != link)
{
- send_error(error::not_found, blockhash, blockhash.size());
+ send_error(error::bitcoind::invalid_address_or_key, blockhash,
+ blockhash.size());
return true;
}
@@ -480,7 +487,7 @@ bool protocol_bitcoind_blockchain::handle_get_chain_tx_stats(const code& ec,
if (!to_integer(window, nblocks) ||
(is_nonzero(window) && window >= height))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
}
@@ -488,7 +495,7 @@ bool protocol_bitcoind_blockchain::handle_get_chain_tx_stats(const code& ec,
const auto header = query.get_header(link);
if (!header)
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -534,7 +541,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out(const code& ec,
hash_digest hash{};
if (!decode_hash(hash, txid) || !to_integer(index, n))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -561,7 +568,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out(const code& ec,
const auto tx_link = query.to_tx(hash);
if (tx_link.is_terminal())
{
- send_error(error::server_error);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -626,7 +633,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out_set_info(const code& ec,
type = set_hash::none;
else
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -637,7 +644,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out_set_info(const code& ec,
// bitcoind restricts specific block queries (coinstatsindex bounds).
if ((type == set_hash::serialized) || !use_index)
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -647,7 +654,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out_set_info(const code& ec,
hash_digest hash{};
if (!decode_hash(hash, std::get(hash_or_height.value())))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -658,7 +665,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out_set_info(const code& ec,
if (!to_integer(height,
std::get(hash_or_height.value())))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::misc_error);
return true;
}
@@ -666,14 +673,14 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out_set_info(const code& ec,
}
else
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::type_error);
return true;
}
if (!query.get_height(height, link) ||
query.to_confirmed(height) != link)
{
- send_error(error::not_found);
+ send_error(error::bitcoind::invalid_address_or_key);
return true;
}
}
@@ -696,7 +703,7 @@ void protocol_bitcoind_blockchain::do_get_tx_out_set_info(set_hash type,
database::header_links branch{};
if (!query.get_ancestry(branch, link, height))
{
- POST(complete_scan, database::error::integrity, std::move(result),
+ POST(complete_scan, error::bitcoind::internal_error, std::move(result),
zero);
return;
}
@@ -740,7 +747,7 @@ void protocol_bitcoind_blockchain::do_get_tx_out_set_info(set_hash type,
if (ec)
{
- POST(complete_scan, ec,
+ POST(complete_scan, error::bitcoind::internal_error,
std::move(result), zero);
return;
}
@@ -748,7 +755,8 @@ void protocol_bitcoind_blockchain::do_get_tx_out_set_info(set_hash type,
// A reorganization across the pinned top voids the scan.
if (!query.is_confirmed_block(link))
{
- POST(complete_scan, error::server_error, std::move(result), zero);
+ POST(complete_scan, error::bitcoind::internal_error, std::move(result),
+ zero);
return;
}
@@ -782,7 +790,7 @@ bool protocol_bitcoind_blockchain::handle_prune_block_chain(const code& ec,
rpc_interface::prune_block_chain, double) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::misc_error);
return true;
}
@@ -790,7 +798,7 @@ bool protocol_bitcoind_blockchain::handle_save_mempool(const code& ec,
rpc_interface::save_mempool) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
@@ -819,7 +827,7 @@ bool protocol_bitcoind_blockchain::handle_scan_tx_out_set(const code& ec,
if (action != "start")
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -839,8 +847,8 @@ void protocol_bitcoind_blockchain::do_scan_tx_out_set(
{
if (!expand_scan_object(scripts, item))
{
- POST(complete_scan, error::invalid_argument, std::move(result),
- zero);
+ POST(complete_scan, error::bitcoind::invalid_address_or_key,
+ std::move(result), zero);
return;
}
}
@@ -930,7 +938,7 @@ void protocol_bitcoind_blockchain::do_scan_tx_out_set(
if (ec)
{
- POST(complete_scan, ec,
+ POST(complete_scan, error::bitcoind::internal_error,
std::move(result), zero);
return;
}
@@ -938,7 +946,8 @@ void protocol_bitcoind_blockchain::do_scan_tx_out_set(
// A reorganization across the pinned top voids the scan.
if (!query.is_confirmed_block(link))
{
- POST(complete_scan, error::server_error, std::move(result), zero);
+ POST(complete_scan, error::bitcoind::internal_error,
+ std::move(result), zero);
return;
}
@@ -1021,7 +1030,7 @@ bool protocol_bitcoind_blockchain::handle_dump_tx_out_set(const code& ec,
rpc_interface::dump_tx_out_set) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -1029,7 +1038,7 @@ bool protocol_bitcoind_blockchain::handle_load_tx_out_set(const code& ec,
rpc_interface::load_tx_out_set) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -1047,7 +1056,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out_proof(const code& ec,
if (txids.empty())
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -1059,7 +1068,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out_proof(const code& ec,
!decode_hash(hash, std::get(item.value())) ||
!targets.insert(hash).second)
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
}
@@ -1073,7 +1082,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out_proof(const code& ec,
hash_digest hash{};
if (!decode_hash(hash, blockhash))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -1082,7 +1091,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out_proof(const code& ec,
if (!query.is_associated(link))
{
- send_error(error::not_found);
+ send_error(error::bitcoind::invalid_address_or_key);
return true;
}
@@ -1090,7 +1099,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out_proof(const code& ec,
const auto keys = query.get_tx_keys(link);
if (keys.empty())
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -1107,14 +1116,14 @@ bool protocol_bitcoind_blockchain::handle_get_tx_out_proof(const code& ec,
if (to_unsigned(std::count(match.begin(), match.end(), true)) !=
targets.size())
{
- send_error(error::not_found);
+ send_error(error::bitcoind::invalid_address_or_key);
return true;
}
const auto header = query.get_header(link);
if (!header)
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -1142,7 +1151,7 @@ bool protocol_bitcoind_blockchain::handle_verify_tx_out_proof(const code& ec,
data_chunk data{};
if (!decode_base16(data, proof))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -1150,7 +1159,7 @@ bool protocol_bitcoind_blockchain::handle_verify_tx_out_proof(const code& ec,
const auto merkle = merkle_block::deserialize(version, data);
if (!merkle)
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::misc_error);
return true;
}
@@ -1174,7 +1183,7 @@ bool protocol_bitcoind_blockchain::handle_verify_tx_out_proof(const code& ec,
if (!query.is_confirmed_block(link) ||
query.get_tx_count(link) != merkle->transactions)
{
- send_error(error::not_found);
+ send_error(error::bitcoind::invalid_address_or_key);
return true;
}
@@ -1190,7 +1199,7 @@ bool protocol_bitcoind_blockchain::handle_get_block_from_peer(const code& ec,
rpc_interface::get_block_from_peer) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -1207,7 +1216,7 @@ bool protocol_bitcoind_blockchain::handle_get_chain_states(const code& ec,
auto entry = chain_states_entry(query, link, 1.0, true);
if (entry.empty())
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -1228,7 +1237,7 @@ bool protocol_bitcoind_blockchain::handle_get_chain_states(const code& ec,
entry = chain_states_entry(query, link, validated, false);
if (entry.empty())
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -1335,7 +1344,7 @@ bool protocol_bitcoind_blockchain::handle_get_deployment_info(const code& ec,
hash_digest hash{};
if (!decode_hash(hash, blockhash))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -1345,7 +1354,8 @@ bool protocol_bitcoind_blockchain::handle_get_deployment_info(const code& ec,
size_t height{};
if (!query.get_height(height, link))
{
- send_error(error::not_found, blockhash, blockhash.size());
+ send_error(error::bitcoind::invalid_address_or_key, blockhash,
+ blockhash.size());
return true;
}
@@ -1385,7 +1395,7 @@ bool protocol_bitcoind_blockchain::handle_get_descriptor_activity(
{
if (!expand_scan_object(derived, item))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_address_or_key);
return true;
}
}
@@ -1402,7 +1412,7 @@ bool protocol_bitcoind_blockchain::handle_get_descriptor_activity(
if (!std::holds_alternative(item.value()) ||
!decode_hash(hash, std::get(item.value())))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -1412,7 +1422,7 @@ bool protocol_bitcoind_blockchain::handle_get_descriptor_activity(
size_t height{};
if (!block || !query.get_height(height, link))
{
- send_error(error::not_found);
+ send_error(error::bitcoind::invalid_address_or_key);
return true;
}
@@ -1494,7 +1504,7 @@ bool protocol_bitcoind_blockchain::handle_get_difficulty(const code& ec,
const auto header = query.get_header(query.to_confirmed(top));
if (!header)
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -1506,7 +1516,7 @@ bool protocol_bitcoind_blockchain::handle_precious_block(const code& ec,
rpc_interface::precious_block) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -1598,17 +1608,28 @@ bool protocol_bitcoind_blockchain::handle_scan_blocks(const code& ec,
if (stopped(ec))
return false;
- if (action != "start" || filtertype != basic_filter ||
- scanobjects.empty())
+ if (action != "start")
+ {
+ send_error(error::bitcoind::invalid_parameter);
+ return true;
+ }
+
+ if (filtertype != basic_filter)
+ {
+ send_error(error::bitcoind::invalid_address_or_key);
+ return true;
+ }
+
+ if (scanobjects.empty())
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::misc_error);
return true;
}
const auto& query = archive();
if (!query.filter_enabled())
{
- send_error(error::not_implemented);
+ send_error(error::bitcoind::misc_error);
return true;
}
@@ -1618,14 +1639,14 @@ bool protocol_bitcoind_blockchain::handle_scan_blocks(const code& ec,
if (!to_integer(from, start_height) ||
(stop_height >= 0 && !to_integer(to, stop_height)))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::misc_error);
return true;
}
to = std::min(to, top);
if (from > to)
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::misc_error);
return true;
}
@@ -1634,7 +1655,7 @@ bool protocol_bitcoind_blockchain::handle_scan_blocks(const code& ec,
{
if (!expand_scan_object(scripts, item))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_address_or_key);
return true;
}
}
@@ -1647,7 +1668,7 @@ bool protocol_bitcoind_blockchain::handle_scan_blocks(const code& ec,
neutrino::block_filter filter{ hash, {} };
if (!query.get_filter_body(filter.filter, link))
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -1676,7 +1697,7 @@ bool protocol_bitcoind_blockchain::handle_wait_for_block(const code& ec,
if (!decode_hash(wait_hash_, blockhash))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -1694,7 +1715,7 @@ bool protocol_bitcoind_blockchain::handle_wait_for_block_height(const code& ec,
if (!to_integer(wait_height_, height))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -1761,7 +1782,7 @@ void protocol_bitcoind_blockchain::arm_wait(double timeout) NOEXCEPT
if (!to_integer(span, timeout))
{
wait_ = wait::none;
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::misc_error);
return;
}
@@ -1821,7 +1842,7 @@ bool protocol_bitcoind_blockchain::handle_get_mempool_ancestors(const code& ec,
rpc_interface::get_mempool_ancestors) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
@@ -1829,7 +1850,7 @@ bool protocol_bitcoind_blockchain::handle_get_mempool_cluster(const code& ec,
rpc_interface::get_mempool_cluster) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
@@ -1837,7 +1858,7 @@ bool protocol_bitcoind_blockchain::handle_get_mempool_descendants(const code& ec
rpc_interface::get_mempool_descendants) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
@@ -1845,7 +1866,7 @@ bool protocol_bitcoind_blockchain::handle_get_mempool_entry(const code& ec,
rpc_interface::get_mempool_entry) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
@@ -1853,7 +1874,7 @@ bool protocol_bitcoind_blockchain::handle_get_mempool_info(const code& ec,
rpc_interface::get_mempool_info) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
@@ -1861,7 +1882,7 @@ bool protocol_bitcoind_blockchain::handle_get_raw_mempool(const code& ec,
rpc_interface::get_raw_mempool) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
@@ -1869,7 +1890,7 @@ bool protocol_bitcoind_blockchain::handle_get_tx_spending_prevout(const code& ec
rpc_interface::get_tx_spending_prevout) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
@@ -1877,7 +1898,7 @@ bool protocol_bitcoind_blockchain::handle_import_mempool(const code& ec,
rpc_interface::import_mempool) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
diff --git a/src/protocols/bitcoind/protocol_bitcoind_control.cpp b/src/protocols/bitcoind/protocol_bitcoind_control.cpp
index f2e05238..89b7e3fa 100644
--- a/src/protocols/bitcoind/protocol_bitcoind_control.cpp
+++ b/src/protocols/bitcoind/protocol_bitcoind_control.cpp
@@ -133,7 +133,7 @@ bool protocol_bitcoind_control::handle_stop(const code& ec,
rpc_interface::stop) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -148,7 +148,7 @@ bool protocol_bitcoind_control::handle_get_memory_info(const code& ec,
// mallocinfo is a glibc-specific malloc dump.
if (mode != "stats")
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -264,7 +264,7 @@ bool protocol_bitcoind_control::handle_logging(const code& ec,
if (!include.empty() || !exclude.empty())
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
diff --git a/src/protocols/bitcoind/protocol_bitcoind_dispatch.cpp b/src/protocols/bitcoind/protocol_bitcoind_dispatch.cpp
index 393c45b9..dd9421c6 100644
--- a/src/protocols/bitcoind/protocol_bitcoind_dispatch.cpp
+++ b/src/protocols/bitcoind/protocol_bitcoind_dispatch.cpp
@@ -97,7 +97,7 @@ void CLASS::handle_receive_post(const code& ec,
// The credential may be restricted to a subset of interface methods.
if (!permitted(message.method))
{
- send_error(error::method_unauthorized);
+ send_forbidden(*post);
return;
}
@@ -140,7 +140,7 @@ void CLASS::dispatch_websocket(
// The credential may be restricted to a subset of interface methods.
if (!permitted(message.method))
{
- send_error(error::method_unauthorized);
+ stop(network::error::unauthorized);
return;
}
diff --git a/src/protocols/bitcoind/protocol_bitcoind_mining.cpp b/src/protocols/bitcoind/protocol_bitcoind_mining.cpp
index 688db09d..c8e1d71f 100644
--- a/src/protocols/bitcoind/protocol_bitcoind_mining.cpp
+++ b/src/protocols/bitcoind/protocol_bitcoind_mining.cpp
@@ -84,7 +84,7 @@ bool protocol_bitcoind_mining::handle_get_network_hash_ps(const code& ec,
}
else if (!to_integer(target, height))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
else
@@ -100,7 +100,7 @@ bool protocol_bitcoind_mining::handle_get_network_hash_ps(const code& ec,
}
else if (!to_integer(window, nblocks))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -120,7 +120,7 @@ bool protocol_bitcoind_mining::handle_get_network_hash_ps(const code& ec,
const auto header = query.get_header(query.to_confirmed(index));
if (!header)
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -139,7 +139,7 @@ bool protocol_bitcoind_mining::handle_get_network_hash_ps(const code& ec,
if (!query.get_branch_work(start_work, query.to_confirmed(first)) ||
!query.get_branch_work(end_work, query.to_confirmed(target)))
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -166,7 +166,7 @@ bool protocol_bitcoind_mining::handle_get_mining_info(const code& ec,
const auto top = query.get_header(link);
if (!top)
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -176,7 +176,7 @@ bool protocol_bitcoind_mining::handle_get_mining_info(const code& ec,
const auto state = query.get_chain_state(bitcoin, key);
if (!state)
{
- send_error(database::error::integrity);
+ send_error(error::bitcoind::internal_error);
return true;
}
@@ -223,7 +223,7 @@ bool protocol_bitcoind_mining::handle_submit_block(const code& ec,
data_chunk data{};
if (!decode_base16(data, hexdata))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::deserialization_error);
return true;
}
@@ -231,7 +231,7 @@ bool protocol_bitcoind_mining::handle_submit_block(const code& ec,
const auto block = to_shared(data, witness);
if (!block->is_valid())
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::deserialization_error);
return true;
}
@@ -255,14 +255,14 @@ bool protocol_bitcoind_mining::handle_submit_header(const code& ec,
data_chunk data{};
if (!decode_base16(data, hexdata))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::deserialization_error);
return true;
}
const auto header = to_shared(data);
if (!header->is_valid())
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::deserialization_error);
return true;
}
@@ -294,12 +294,12 @@ void protocol_bitcoind_mining::handle_organize_header(const code& ec,
POST(do_submit_header, ec);
}
-// bitcoind returns null on acceptance and a reason string on rejection.
+// bitcoind returns null on acceptance and a reject token on rejection.
void protocol_bitcoind_mining::do_submit_block(const code& ec) NOEXCEPT
{
BC_ASSERT(stranded());
if (ec)
- send_result(ec.message(), 64);
+ send_result(error::bitcoind::reject(ec), 64);
else
send_result(null_t{}, 8);
}
@@ -307,8 +307,9 @@ void protocol_bitcoind_mining::do_submit_block(const code& ec) NOEXCEPT
void protocol_bitcoind_mining::do_submit_header(const code& ec) NOEXCEPT
{
BC_ASSERT(stranded());
+ using namespace error::bitcoind;
if (ec)
- send_error(ec);
+ send_error(translate(ec, verify_error));
else
send_result(null_t{}, 8);
}
@@ -317,7 +318,7 @@ bool protocol_bitcoind_mining::handle_get_block_template(const code& ec,
rpc_interface::get_block_template) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
@@ -325,7 +326,7 @@ bool protocol_bitcoind_mining::handle_get_prioritised_transactions(const code& e
rpc_interface::get_prioritised_transactions) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
@@ -333,7 +334,7 @@ bool protocol_bitcoind_mining::handle_prioritise_transaction(const code& ec,
rpc_interface::prioritise_transaction) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_mempool_disabled);
return true;
}
diff --git a/src/protocols/bitcoind/protocol_bitcoind_network.cpp b/src/protocols/bitcoind/protocol_bitcoind_network.cpp
index f83779ee..38c5a4cf 100644
--- a/src/protocols/bitcoind/protocol_bitcoind_network.cpp
+++ b/src/protocols/bitcoind/protocol_bitcoind_network.cpp
@@ -220,7 +220,7 @@ bool protocol_bitcoind_network::handle_get_node_addresses(const code& ec,
if (!to_integer(node_count_, count) ||
(!network.empty() && network != "ipv4" && network != "ipv6"))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -310,7 +310,7 @@ bool protocol_bitcoind_network::handle_clear_banned(const code& ec,
rpc_interface::clear_banned) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::database_error);
return true;
}
@@ -318,7 +318,7 @@ bool protocol_bitcoind_network::handle_list_banned(const code& ec,
rpc_interface::list_banned) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::database_error);
return true;
}
@@ -326,7 +326,7 @@ bool protocol_bitcoind_network::handle_set_ban(const code& ec,
rpc_interface::set_ban) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::database_error);
return true;
}
@@ -341,8 +341,8 @@ bool protocol_bitcoind_network::handle_add_node(const code& ec,
if (command != "add" && command != "onetry")
{
- send_error(command == "remove" ? error::not_implemented :
- error::invalid_argument);
+ send_error(command == "remove" ? error::bitcoind::client_node_not_added :
+ error::bitcoind::misc_error);
return true;
}
@@ -353,7 +353,7 @@ bool protocol_bitcoind_network::handle_add_node(const code& ec,
}
catch (const std::exception&)
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -365,7 +365,7 @@ bool protocol_bitcoind_network::handle_disconnect_node(const code& ec,
rpc_interface::disconnect_node) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -373,7 +373,7 @@ bool protocol_bitcoind_network::handle_export_asmap(const code& ec,
rpc_interface::export_asmap) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -381,7 +381,7 @@ bool protocol_bitcoind_network::handle_get_added_node_info(const code& ec,
rpc_interface::get_added_node_info) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::client_node_not_added);
return true;
}
@@ -428,7 +428,7 @@ bool protocol_bitcoind_network::handle_get_peer_info(const code& ec,
rpc_interface::get_peer_info) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
diff --git a/src/protocols/bitcoind/protocol_bitcoind_test.cpp b/src/protocols/bitcoind/protocol_bitcoind_test.cpp
index 43d0d79a..b77eb436 100644
--- a/src/protocols/bitcoind/protocol_bitcoind_test.cpp
+++ b/src/protocols/bitcoind/protocol_bitcoind_test.cpp
@@ -82,7 +82,7 @@ bool protocol_bitcoind_test::handle_add_connection(const code& ec,
rpc_interface::add_connection) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -90,7 +90,7 @@ bool protocol_bitcoind_test::handle_add_peer_address(const code& ec,
rpc_interface::add_peer_address) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -98,7 +98,7 @@ bool protocol_bitcoind_test::handle_echo(const code& ec,
rpc_interface::echo) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -106,7 +106,7 @@ bool protocol_bitcoind_test::handle_echo_ipc(const code& ec,
rpc_interface::echo_ipc) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -114,7 +114,7 @@ bool protocol_bitcoind_test::handle_echo_json(const code& ec,
rpc_interface::echo_json) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -122,7 +122,7 @@ bool protocol_bitcoind_test::handle_estimate_raw_fee(const code& ec,
rpc_interface::estimate_raw_fee) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -130,7 +130,7 @@ bool protocol_bitcoind_test::handle_generate(const code& ec,
rpc_interface::generate) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -138,7 +138,7 @@ bool protocol_bitcoind_test::handle_generate_block(const code& ec,
rpc_interface::generate_block) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -146,7 +146,7 @@ bool protocol_bitcoind_test::handle_generate_to_address(const code& ec,
rpc_interface::generate_to_address) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -154,7 +154,7 @@ bool protocol_bitcoind_test::handle_generate_to_descriptor(const code& ec,
rpc_interface::generate_to_descriptor) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -162,7 +162,7 @@ bool protocol_bitcoind_test::handle_get_mempool_fee_rate_diagram(const code& ec,
rpc_interface::get_mempool_fee_rate_diagram) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -170,7 +170,7 @@ bool protocol_bitcoind_test::handle_get_orphan_txs(const code& ec,
rpc_interface::get_orphan_txs) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -178,7 +178,7 @@ bool protocol_bitcoind_test::handle_get_raw_addrman(const code& ec,
rpc_interface::get_raw_addrman) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -186,7 +186,7 @@ bool protocol_bitcoind_test::handle_invalidate_block(const code& ec,
rpc_interface::invalidate_block) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -194,7 +194,7 @@ bool protocol_bitcoind_test::handle_mock_scheduler(const code& ec,
rpc_interface::mock_scheduler) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -202,7 +202,7 @@ bool protocol_bitcoind_test::handle_reconsider_block(const code& ec,
rpc_interface::reconsider_block) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -210,7 +210,7 @@ bool protocol_bitcoind_test::handle_send_msg_to_peer(const code& ec,
rpc_interface::send_msg_to_peer) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -218,7 +218,7 @@ bool protocol_bitcoind_test::handle_set_mock_time(const code& ec,
rpc_interface::set_mock_time) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
@@ -226,7 +226,7 @@ bool protocol_bitcoind_test::handle_sync_with_validation_interface_queue(const c
rpc_interface::sync_with_validation_interface_queue) NOEXCEPT
{
if (stopped(ec)) return false;
- send_error(error::not_implemented);
+ send_error(error::bitcoind::method_not_found);
return true;
}
diff --git a/src/protocols/bitcoind/protocol_bitcoind_transaction.cpp b/src/protocols/bitcoind/protocol_bitcoind_transaction.cpp
index 866541ad..465cc44d 100644
--- a/src/protocols/bitcoind/protocol_bitcoind_transaction.cpp
+++ b/src/protocols/bitcoind/protocol_bitcoind_transaction.cpp
@@ -88,7 +88,7 @@ bool protocol_bitcoind_transaction::handle_get_raw_transaction(const code& ec,
hash_digest hash{};
if (!decode_hash(hash, txid))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -98,7 +98,7 @@ bool protocol_bitcoind_transaction::handle_get_raw_transaction(const code& ec,
const auto tx = query.get_transaction(link, witness);
if (!tx)
{
- send_error(error::not_found, txid, txid.size());
+ send_error(error::bitcoind::invalid_address_or_key, txid, txid.size());
return true;
}
@@ -109,13 +109,16 @@ bool protocol_bitcoind_transaction::handle_get_raw_transaction(const code& ec,
json_verbose = 2
};
- size_t level{};
- if (!to_integer(level, verbose) || level > verbosity::json_verbose)
+ int64_t requested{};
+ if (!to_integer(requested, verbose))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::misc_error);
return true;
}
+ // bitcoind clamps out of range verbosity.
+ const auto level = limit(requested, verbosity::json_verbose);
+
if (level == verbosity::hexadecimal)
{
send_text(to_text(*tx, tx->serialized_size(witness), witness));
@@ -146,20 +149,45 @@ bool protocol_bitcoind_transaction::handle_send_raw_transaction(const code& ec,
data_chunk data{};
if (!decode_base16(data, hexstring))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::deserialization_error);
return true;
}
const auto tx = to_shared(data, true);
if (!tx->is_valid())
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::deserialization_error);
return true;
}
+ // A confirmed tx with any unspent output is reported without validating.
+ const auto& query = archive();
+ const auto link = query.to_tx(tx->hash(false));
+ if (!link.is_terminal() && query.is_confirmed_tx(link))
+ {
+ const auto outs = query.to_outputs(link);
+ const auto unspent = [&query](const auto& out) NOEXCEPT
+ {
+ return !query.is_confirmed_spent(out);
+ };
+
+ if (std::any_of(outs.begin(), outs.end(), unspent))
+ {
+ send_error(error::bitcoind::verify_already_in_utxo_set);
+ return true;
+ }
+ }
+
if (const auto fault = broadcast_tx(tx); fault)
{
- send_error(fault);
+ using namespace error::bitcoind;
+
+ // Absent and confirmed-spent inputs are missing coins (as bitcoind).
+ const auto missing =
+ (fault == system::error::missing_previous_output) ||
+ (fault == system::error::confirmed_double_spend);
+
+ send_error(translate(fault, missing ? verify_error : verify_rejected));
return true;
}
@@ -176,7 +204,7 @@ bool protocol_bitcoind_transaction::handle_test_mempool_accept(const code& ec,
if (rawtxs.empty())
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::invalid_parameter);
return true;
}
@@ -186,7 +214,7 @@ bool protocol_bitcoind_transaction::handle_test_mempool_accept(const code& ec,
{
if (!std::holds_alternative(item.value()))
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::type_error);
return true;
}
@@ -194,7 +222,7 @@ bool protocol_bitcoind_transaction::handle_test_mempool_accept(const code& ec,
const chain::transaction tx{ hexer, true };
if (!tx.is_valid() || !hexer.is_exhausted())
{
- send_error(error::invalid_argument);
+ send_error(error::bitcoind::deserialization_error);
return true;
}
@@ -207,7 +235,7 @@ bool protocol_bitcoind_transaction::handle_test_mempool_accept(const code& ec,
};
if (fault)
- result.emplace("reject-reason", fault.message());
+ result.emplace("reject-reason", error::bitcoind::reject(fault));
results.emplace_back(std::move(result));
}
@@ -224,7 +252,7 @@ code protocol_bitcoind_transaction::build_transaction(chain::transaction& out,
{
uint32_t lock_time{};
if (!to_integer(lock_time, locktime))
- return error::invalid_argument;
+ return error::bitcoind::invalid_parameter;
using namespace chain;
const auto sequence = replaceable ? messages::peer::bip125_sequence :
@@ -238,7 +266,7 @@ code protocol_bitcoind_transaction::build_transaction(chain::transaction& out,
for (const auto& item: inputs)
{
if (!std::holds_alternative(item.value()))
- return error::invalid_argument;
+ return error::bitcoind::type_error;
const auto& fields = std::get(item.value());
const auto txid_it = fields.find("txid");
@@ -246,11 +274,11 @@ code protocol_bitcoind_transaction::build_transaction(chain::transaction& out,
if (txid_it == fields.end() || vout_it == fields.end() ||
!std::holds_alternative(txid_it->second.value()) ||
!std::holds_alternative(vout_it->second.value()))
- return error::invalid_argument;
+ return error::bitcoind::invalid_parameter;
if (!decode_hash(hash, std::get(txid_it->second.value())) ||
!to_integer(vout, std::get(vout_it->second.value())))
- return error::invalid_argument;
+ return error::bitcoind::invalid_parameter;
ins->push_back(to_shared(point{ hash, vout }, script{}, sequence));
}
@@ -268,7 +296,7 @@ code protocol_bitcoind_transaction::build_transaction(chain::transaction& out,
if (!std::holds_alternative(pair.second.value()) ||
!decode_base16(data, std::get(pair.second.value())) ||
data.size() > max_null_data_size)
- return error::invalid_argument;
+ return error::bitcoind::invalid_parameter;
outs->push_back(to_shared