diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 614582528d73..56716ec673f5 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -131,11 +131,6 @@ class Chain public: virtual ~Chain() = default; - // This method will remove the specified transaction and all of its descendants - // (transactions that spend outputs from this transaction or its descendants) - // from the mempool. - virtual bool removeTxFromMempool(const uint256& txid) = 0; - //! Get current chain height, not including genesis block (returns 0 if //! chain only contains genesis block, nullopt if chain does not contain //! any blocks) @@ -371,7 +366,7 @@ class Chain //! support for writing null values to settings.json. //! Depending on the action returned by the update function, this will either //! update the setting in memory or write the updated settings to disk. - virtual bool updateRwSetting(const std::string& name, SettingsUpdate update_function) = 0; + virtual bool updateRwSetting(const std::string& name, const SettingsUpdate& update_function) = 0; //! Replace a setting in /settings.json with a new value. //! Null can be passed to erase the setting. @@ -418,8 +413,7 @@ class ChainClient //! Load saved state. virtual bool load() = 0; - //! Start client execution and provide a scheduler. (Scheduler is - //! ignored if client is out-of-process). + //! Start client execution and provide a scheduler. virtual void start(CScheduler& scheduler) = 0; //! Shut down client. diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index 150295e5b7b4..589873da3229 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -81,6 +81,11 @@ class Mining public: virtual ~Mining() = default; + // This method will remove the specified transaction and all of its descendants + // (transactions that spend outputs from this transaction or its descendants) + // from the mempool. + virtual bool removeTxFromMempool(const uint256& txid) = 0; + //! If this chain is exclusively used for testing virtual bool isTestChain() = 0; diff --git a/src/ipc/CMakeLists.txt b/src/ipc/CMakeLists.txt index 40154811124b..904d72f56e13 100644 --- a/src/ipc/CMakeLists.txt +++ b/src/ipc/CMakeLists.txt @@ -3,7 +3,6 @@ # file COPYING or https://opensource.org/license/mit/. add_library(bitcoin_ipc STATIC EXCLUDE_FROM_ALL - capnp/chain.cpp capnp/mining.cpp capnp/protocol.cpp interfaces.cpp @@ -11,10 +10,8 @@ add_library(bitcoin_ipc STATIC EXCLUDE_FROM_ALL ) target_capnp_sources(bitcoin_ipc ${PROJECT_SOURCE_DIR} - capnp/chain.capnp capnp/common.capnp capnp/echo.capnp - capnp/handler.capnp capnp/init.capnp capnp/mining.capnp ) diff --git a/src/ipc/capnp/chain-types.h b/src/ipc/capnp/chain-types.h deleted file mode 100644 index 2287f154426f..000000000000 --- a/src/ipc/capnp/chain-types.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2024 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_IPC_CAPNP_CHAIN_TYPES_H -#define BITCOIN_IPC_CAPNP_CHAIN_TYPES_H - -#include -#include -#include -#include -#include -#include - -//! Specialization of handleRpc needed because it takes a CRPCCommand& reference -//! argument, so a manual cleanup callback is needed to free the passed -//! CRPCCommand struct and proxy ActorCallback object. -template <> -struct mp::ProxyServerMethodTraits -{ - using Context = ServerContext; - static ::capnp::Void invoke(Context& context); -}; - -//! Specialization of start method needed to provide CScheduler& reference -//! argument. -template <> -struct mp::ProxyServerMethodTraits -{ - using ChainContext = ServerContext; - static void invoke(ChainContext& context); -}; - -namespace mp { -//! Overload CustomBuildMessage, CustomPassMessage, and CustomReadMessage to -//! serialize interfaces::FoundBlock parameters. Custom conversion functions are -//! needed because there is not a 1:1 correspondence between members of the C++ -//! FoundBlock class and the Cap'n Proto FoundBlockParam and FoundBlockResult -//! structs. Separate param and result structs are needed because Cap'n Proto -//! only has input and output parameters, not in/out parameters like C++. -void CustomBuildMessage(InvokeContext& invoke_context, - const interfaces::FoundBlock& dest, - ipc::capnp::messages::FoundBlockParam::Builder&& builder); -void CustomPassMessage(InvokeContext& invoke_context, - const ipc::capnp::messages::FoundBlockParam::Reader& reader, - ipc::capnp::messages::FoundBlockResult::Builder&& builder, - std::function&& fn); -void CustomReadMessage(InvokeContext& invoke_context, - const ipc::capnp::messages::FoundBlockResult::Reader& reader, - const interfaces::FoundBlock& dest); - -//! Overload CustomBuildMessage and CustomPassMessage to serialize -//! interfaces::BlockInfo parameters. Custom conversion functions are needed -//! because BlockInfo structs contain pointer and reference members, and custom -//! code is needed to deal with their lifetimes. Specifics are described in the -//! implementation of these functions. -void CustomBuildMessage(InvokeContext& invoke_context, - const interfaces::BlockInfo& block, - ipc::capnp::messages::BlockInfo::Builder&& builder); -void CustomPassMessage(InvokeContext& invoke_context, - const ipc::capnp::messages::BlockInfo::Reader& reader, - ::capnp::Void builder, - std::function&& fn); - -//! CScheduler& server-side argument handling. Skips argument so it can -//! be handled by ProxyServerMethodTraits ChainClient::Start code. -template -void CustomPassField(TypeList, ServerContext& server_context, const Fn& fn, Args&&... args) -{ - fn.invoke(server_context, std::forward(args)...); -} - -//! CRPCCommand& server-side argument handling. Skips argument so it can -//! be handled by ProxyServerMethodTraits Chain::HandleRpc code. -template -void CustomPassField(TypeList, ServerContext& server_context, const Fn& fn, Args&&... args) -{ - fn.invoke(server_context, std::forward(args)...); -} - -//! Override to avoid assert failures that would happen trying to serialize -//! spent coins. Probably it would be best for Coin serialization code not -//! to assert, but avoiding serialization in this case is harmless. -bool CustomHasValue(InvokeContext& invoke_context, const Coin& coin); -} // namespace mp - -#endif // BITCOIN_IPC_CAPNP_CHAIN_TYPES_H diff --git a/src/ipc/capnp/chain.capnp b/src/ipc/capnp/chain.capnp deleted file mode 100644 index d2d405074ab9..000000000000 --- a/src/ipc/capnp/chain.capnp +++ /dev/null @@ -1,196 +0,0 @@ -# Copyright (c) 2024 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -@0x94f21a4864bd2c65; - -using Cxx = import "/capnp/c++.capnp"; -$Cxx.namespace("ipc::capnp::messages"); - -using Proxy = import "/mp/proxy.capnp"; -$Proxy.include("interfaces/chain.h"); -$Proxy.include("rpc/server.h"); -$Proxy.includeTypes("ipc/capnp/chain-types.h"); - -using Common = import "common.capnp"; -using Handler = import "handler.capnp"; - -interface Chain $Proxy.wrap("interfaces::Chain") { - destroy @0 (context :Proxy.Context) -> (); - getHeight @1 (context :Proxy.Context) -> (result :Int32, hasResult :Bool); - getBlockHash @2 (context :Proxy.Context, height :Int32) -> (result :Data); - haveBlockOnDisk @3 (context :Proxy.Context, height :Int32) -> (result :Bool); - getTipLocator @4 (context :Proxy.Context) -> (result :Data); - getActiveChainLocator @5 (context :Proxy.Context, blockHash :Data) -> (result :Data); - findLocatorFork @6 (context :Proxy.Context, locator :Data) -> (result :Int32, hasResult :Bool); - hasBlockFilterIndex @7 (context :Proxy.Context, filterType :UInt8) -> (result :Bool); - blockFilterMatchesAny @8 (context :Proxy.Context, filterType :UInt8, blockHash :Data, filterSet :List(Data)) -> (result :Bool, hasResult :Bool); - findBlock @9 (context :Proxy.Context, hash :Data, block :FoundBlockParam) -> (block :FoundBlockResult, result :Bool); - findFirstBlockWithTimeAndHeight @10 (context :Proxy.Context, minTime :Int64, minHeight :Int32, block :FoundBlockParam) -> (block :FoundBlockResult, result :Bool); - findAncestorByHeight @11 (context :Proxy.Context, blockHash :Data, ancestorHeight :Int32, ancestor :FoundBlockParam) -> (ancestor :FoundBlockResult, result :Bool); - findAncestorByHash @12 (context :Proxy.Context, blockHash :Data, ancestorHash :Data, ancestor :FoundBlockParam) -> (ancestor :FoundBlockResult, result :Bool); - findCommonAncestor @13 (context :Proxy.Context, blockHash1 :Data, blockHash2 :Data, ancestor :FoundBlockParam, block1 :FoundBlockParam, block2 :FoundBlockParam) -> (ancestor :FoundBlockResult, block1 :FoundBlockResult, block2 :FoundBlockResult, result :Bool); - findCoins @14 (context :Proxy.Context, coins :List(Common.Pair(Data, Data))) -> (coins :List(Common.Pair(Data, Data))); - guessVerificationProgress @15 (context :Proxy.Context, blockHash :Data) -> (result :Float64); - hasBlocks @16 (context :Proxy.Context, blockHash :Data, minHeight :Int32, maxHeight: Int32, hasMaxHeight :Bool) -> (result :Bool); - isRBFOptIn @17 (context :Proxy.Context, tx :Data) -> (result :Int32); - isInMempool @18 (context :Proxy.Context, txid :Data) -> (result :Bool); - hasDescendantsInMempool @19 (context :Proxy.Context, txid :Data) -> (result :Bool); - broadcastTransaction @20 (context :Proxy.Context, tx: Data, maxTxFee :Int64, relay :Bool) -> (error: Text, result :Bool); - getTransactionAncestry @21 (context :Proxy.Context, txid :Data) -> (ancestors :UInt64, descendants :UInt64, ancestorsize :UInt64, ancestorfees :Int64); - calculateIndividualBumpFees @22 (context :Proxy.Context, outpoints :List(Data), targetFeerate :Data) -> (result: List(Common.PairInt64(Data))); - calculateCombinedBumpFee @23 (context :Proxy.Context, outpoints :List(Data), targetFeerate :Data) -> (result :Int64, hasResult :Bool); - getPackageLimits @24 (context :Proxy.Context) -> (ancestors :UInt64, descendants :UInt64); - checkChainLimits @25 (context :Proxy.Context, tx :Data) -> (result :Common.ResultVoid); - estimateSmartFee @26 (context :Proxy.Context, numBlocks :Int32, conservative :Bool, wantCalc :Bool) -> (calc :FeeCalculation, result :Data); - estimateMaxBlocks @27 (context :Proxy.Context) -> (result :UInt32); - mempoolMinFee @28 (context :Proxy.Context) -> (result :Data); - relayMinFee @29 (context :Proxy.Context) -> (result :Data); - relayIncrementalFee @30 (context :Proxy.Context) -> (result :Data); - relayDustFee @31 (context :Proxy.Context) -> (result :Data); - havePruned @32 (context :Proxy.Context) -> (result :Bool); - getPruneHeight @33 (context :Proxy.Context) -> (result: Int32, hasResult: Bool); - isReadyToBroadcast @34 (context :Proxy.Context) -> (result :Bool); - isInitialBlockDownload @35 (context :Proxy.Context) -> (result :Bool); - shutdownRequested @36 (context :Proxy.Context) -> (result :Bool); - initMessage @37 (context :Proxy.Context, message :Text) -> (); - initWarning @38 (context :Proxy.Context, message :Common.BilingualStr) -> (); - initError @39 (context :Proxy.Context, message :Common.BilingualStr) -> (); - showProgress @40 (context :Proxy.Context, title :Text, progress :Int32, resumePossible :Bool) -> (); - handleNotifications @41 (context :Proxy.Context, notifications :ChainNotifications) -> (result :Handler.Handler); - waitForNotificationsIfTipChanged @42 (context :Proxy.Context, oldTip :Data) -> (); - handleRpc @43 (context :Proxy.Context, command :RPCCommand) -> (result :Handler.Handler); - rpcEnableDeprecated @44 (context :Proxy.Context, method :Text) -> (result :Bool); - rpcRunLater @45 (context :Proxy.Context, name :Text, fn: RunLaterCallback, seconds: Int64) -> (); - getSetting @46 (context :Proxy.Context, name :Text) -> (result :Text); - getSettingsList @47 (context :Proxy.Context, name :Text) -> (result :List(Text)); - getRwSetting @48 (context :Proxy.Context, name :Text) -> (result :Text); - updateRwSetting @49 (context :Proxy.Context, name :Text, update: SettingsUpdateCallback) -> (result :Bool); - overwriteRwSetting @50 (context :Proxy.Context, name :Text, value :Text, action :Int32) -> (result :Bool); - deleteRwSettings @51 (context :Proxy.Context, name :Text, action: Int32) -> (result :Bool); - requestMempoolTransactions @52 (context :Proxy.Context, notifications :ChainNotifications) -> (); - hasAssumedValidChain @53 (context :Proxy.Context) -> (result :Bool); - removeTxFromMempool @54 (context :Proxy.Context, txid :Data) -> (result :Bool); -} - -interface ChainNotifications $Proxy.wrap("interfaces::Chain::Notifications") { - destroy @0 (context :Proxy.Context) -> (); - transactionAddedToMempool @1 (context :Proxy.Context, tx :Data) -> (); - transactionRemovedFromMempool @2 (context :Proxy.Context, tx :Data, reason :Int32) -> (); - blockConnected @3 (context :Proxy.Context, role: UInt32, block :BlockInfo) -> (); - blockDisconnected @4 (context :Proxy.Context, block :BlockInfo) -> (); - updatedBlockTip @5 (context :Proxy.Context) -> (); - chainStateFlushed @6 (context :Proxy.Context, role: UInt32, locator :Data) -> (); -} - -interface ChainClient $Proxy.wrap("interfaces::ChainClient") { - destroy @0 (context :Proxy.Context) -> (); - registerRpcs @1 (context :Proxy.Context) -> (); - verify @2 (context :Proxy.Context) -> (result :Bool); - load @3 (context :Proxy.Context) -> (result :Bool); - start @4 (context :Proxy.Context, scheduler :Void) -> (); - stop @5 (context :Proxy.Context) -> (); - setMockTime @6 (context :Proxy.Context, time :Int64) -> (); - schedulerMockForward @7 (context :Proxy.Context, time :Int64) -> (); -} - -struct FeeCalculation $Proxy.wrap("FeeCalculation") { - est @0 :EstimationResult; - reason @1 :Int32; - desiredTarget @2 :Int32; - returnedTarget @3 :Int32; -} - -struct EstimationResult $Proxy.wrap("EstimationResult") -{ - pass @0 :EstimatorBucket; - fail @1 :EstimatorBucket; - decay @2 :Float64; - scale @3 :UInt32; -} - -struct EstimatorBucket $Proxy.wrap("EstimatorBucket") -{ - start @0 :Float64; - end @1 :Float64; - withinTarget @2 :Float64; - totalConfirmed @3 :Float64; - inMempool @4 :Float64; - leftMempool @5 :Float64; -} - -struct RPCCommand $Proxy.wrap("CRPCCommand") { - category @0 :Text; - name @1 :Text; - actor @2 :ActorCallback; - argNames @3 :List(RPCArg); - uniqueId @4 :Int64 $Proxy.name("unique_id"); -} - -struct RPCArg { - name @0 :Text; - namedOnly @1: Bool; -} - -interface ActorCallback $Proxy.wrap("ProxyCallback") { - call @0 (context :Proxy.Context, request :JSONRPCRequest, response :Text, lastCallback :Bool) -> (error :Text $Proxy.exception("std::exception"), rpcError :Text $Proxy.exception("UniValue"), typeError :Text $Proxy.exception("UniValue::type_error"), response :Text, result: Bool); -} - -struct JSONRPCRequest $Proxy.wrap("JSONRPCRequest") { - id @0 :Text; - method @1 :Text $Proxy.name("strMethod"); - params @2 :Text; - mode @3 :UInt32; - uri @4 :Text $Proxy.name("URI"); - authUser @5 :Text; - peerAddr @6 :Text; - version @7: Int32 $Proxy.name("m_json_version"); -} - -interface RunLaterCallback $Proxy.wrap("ProxyCallback>") { - destroy @0 (context :Proxy.Context) -> (); - call @1 (context :Proxy.Context) -> (); -} - -struct FoundBlockParam { - wantHash @0 :Bool; - wantHeight @1 :Bool; - wantTime @2 :Bool; - wantMaxTime @3 :Bool; - wantMtpTime @4 :Bool; - wantInActiveChain @5 :Bool; - wantLocator @6 :Bool; - nextBlock @7: FoundBlockParam; - wantData @8 :Bool; -} - -struct FoundBlockResult { - hash @0 :Data; - height @1 :Int32; - time @2 :Int64; - maxTime @3 :Int64; - mtpTime @4 :Int64; - inActiveChain @5 :Int64; - locator @6 :Data; - nextBlock @7: FoundBlockResult; - data @8 :Data; - found @9 :Bool; -} - -struct BlockInfo $Proxy.wrap("interfaces::BlockInfo") { - # Fields skipped below with Proxy.skip are pointer fields manually handled - # by CustomBuildMessage / CustomPassMessage overloads. - hash @0 :Data $Proxy.skip; - prevHash @1 :Data $Proxy.skip; - height @2 :Int32 = -1; - fileNumber @3 :Int32 = -1 $Proxy.name("file_number"); - dataPos @4 :UInt32 = 0 $Proxy.name("data_pos"); - data @5 :Data $Proxy.skip; - undoData @6 :Data $Proxy.skip; - chainTimeMax @7 :UInt32 = 0 $Proxy.name("chain_time_max"); -} - -interface SettingsUpdateCallback $Proxy.wrap("ProxyCallback") { - destroy @0 (context :Proxy.Context) -> (); - call @1 (context :Proxy.Context, value :Text) -> (value :Text, result: Int32, hasResult: Bool); -} diff --git a/src/ipc/capnp/chain.cpp b/src/ipc/capnp/chain.cpp deleted file mode 100644 index 8a24b00a1e95..000000000000 --- a/src/ipc/capnp/chain.cpp +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) 2024 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace mp { -void CustomBuildMessage(InvokeContext& invoke_context, - const interfaces::FoundBlock& dest, - ipc::capnp::messages::FoundBlockParam::Builder&& builder) -{ - if (dest.m_hash) builder.setWantHash(true); - if (dest.m_height) builder.setWantHeight(true); - if (dest.m_time) builder.setWantTime(true); - if (dest.m_max_time) builder.setWantMaxTime(true); - if (dest.m_mtp_time) builder.setWantMtpTime(true); - if (dest.m_in_active_chain) builder.setWantInActiveChain(true); - if (dest.m_locator) builder.setWantLocator(true); - if (dest.m_next_block) CustomBuildMessage(invoke_context, *dest.m_next_block, builder.initNextBlock()); - if (dest.m_data) builder.setWantData(true); -} - -void FindBlock(const std::function& find, - const ipc::capnp::messages::FoundBlockParam::Reader& reader, - ipc::capnp::messages::FoundBlockResult::Builder&& builder, - interfaces::FoundBlock& found_block) -{ - uint256 hash; - int height = -1; - int64_t time = -1; - int64_t max_time = -1; - int64_t mtp_time = -1; - bool in_active_chain = -1; - CBlockLocator locator; - CBlock data; - if (reader.getWantHash()) found_block.hash(hash); - if (reader.getWantHeight()) found_block.height(height); - if (reader.getWantTime()) found_block.time(time); - if (reader.getWantMaxTime()) found_block.maxTime(max_time); - if (reader.getWantMtpTime()) found_block.mtpTime(mtp_time); - if (reader.getWantInActiveChain()) found_block.inActiveChain(in_active_chain); - if (reader.getWantLocator()) found_block.locator(locator); - if (reader.getWantData()) found_block.data(data); - if (reader.hasNextBlock()) { - interfaces::FoundBlock next_block; - found_block.nextBlock(next_block); - FindBlock(find, reader.getNextBlock(), builder.initNextBlock(), next_block); - } else { - find(); - } - if (!found_block.found) return; - if (reader.getWantHash()) builder.setHash(ipc::capnp::ToArray(ipc::capnp::Serialize(hash))); - if (reader.getWantHeight()) builder.setHeight(height); - if (reader.getWantTime()) builder.setTime(time); - if (reader.getWantMaxTime()) builder.setMaxTime(max_time); - if (reader.getWantMtpTime()) builder.setMtpTime(mtp_time); - if (reader.getWantInActiveChain()) builder.setInActiveChain(in_active_chain); - if (reader.getWantLocator()) builder.setLocator(ipc::capnp::ToArray(ipc::capnp::Serialize(locator))); - if (reader.getWantData()) builder.setData(ipc::capnp::ToArray(ipc::capnp::Serialize(data))); - builder.setFound(true); -} - -void CustomPassMessage(InvokeContext& invoke_context, - const ipc::capnp::messages::FoundBlockParam::Reader& reader, - ipc::capnp::messages::FoundBlockResult::Builder&& builder, - std::function&& fn) -{ - interfaces::FoundBlock found_block; - FindBlock([&] { fn(found_block); }, reader, std::move(builder), found_block); -} - -void CustomReadMessage(InvokeContext& invoke_context, - const ipc::capnp::messages::FoundBlockResult::Reader& reader, - const interfaces::FoundBlock& dest) -{ - if (!reader.getFound()) return; - if (dest.m_hash) *dest.m_hash = ipc::capnp::Unserialize(reader.getHash()); - if (dest.m_height) *dest.m_height = reader.getHeight(); - if (dest.m_time) *dest.m_time = reader.getTime(); - if (dest.m_max_time) *dest.m_max_time = reader.getMaxTime(); - if (dest.m_mtp_time) *dest.m_mtp_time = reader.getMtpTime(); - if (dest.m_in_active_chain) *dest.m_in_active_chain = reader.getInActiveChain(); - if (dest.m_locator) *dest.m_locator = ipc::capnp::Unserialize(reader.getLocator()); - if (dest.m_next_block) CustomReadMessage(invoke_context, reader.getNextBlock(), *dest.m_next_block); - if (dest.m_data) *dest.m_data = ipc::capnp::Unserialize(reader.getData()); - dest.found = true; -} - -void CustomBuildMessage(InvokeContext& invoke_context, - const interfaces::BlockInfo& block, - ipc::capnp::messages::BlockInfo::Builder&& builder) -{ - // Pointer fields are annotated with Proxy.skip so need to be filled - // manually. Generated code would actually work correctly, though, so this - // could be dropped if there were a Proxy.skip(read_only=True) half-skip - // option. - builder.setHash(ipc::capnp::ToArray(block.hash)); - if (block.prev_hash) builder.setPrevHash(ipc::capnp::ToArray(*block.prev_hash)); - if (block.data) builder.setData(ipc::capnp::ToArray(ipc::capnp::Serialize(*block.data))); - if (block.undo_data) builder.setUndoData(ipc::capnp::ToArray(ipc::capnp::Serialize(*block.undo_data))); - // Copy the remaining fields using the code generated by Proxy.wrap. - mp::BuildOne<0>(mp::TypeList(), invoke_context, builder, block); -} - -void CustomPassMessage(InvokeContext& invoke_context, - const ipc::capnp::messages::BlockInfo::Reader& reader, - ::capnp::Void builder, - std::function&& fn) -{ - // Pointer fields are annotated with Proxy.skip because code generator can't - // figure out pointer lifetimes to be able to implementat a ReadField - // implementation for the BlockInfo struct, and the default PassField - // function calls readfield. In theory though, code generator could create a - // PassField specialization for the struct which could allocate pointers for - // the lifetime of the call, like the code below is doing manually. This - // would take care of all pointer fields, though the BlockInfo.hash - // reference field would still need to be handled specially. Or even - // BlockInfo.hash field could be handled automatically if the generated code - // used C++20 designated member initialization. - const uint256 hash = ipc::capnp::ToBlob(reader.getHash()); - std::optional prev_hash; - std::optional data; - std::optional undo_data; - interfaces::BlockInfo block{hash}; - if (reader.hasPrevHash()) { - prev_hash.emplace(ipc::capnp::ToBlob(reader.getPrevHash())); - block.prev_hash = &*prev_hash; - } - if (reader.hasData()) { - data.emplace(ipc::capnp::Unserialize(reader.getData())); - block.data = &*data; - } - if (reader.hasUndoData()) { - undo_data.emplace(ipc::capnp::Unserialize(reader.getUndoData())); - block.undo_data = &*undo_data; - } - mp::ReadField(mp::TypeList(), invoke_context, - mp::Make(reader), mp::ReadDestUpdate(block)); - fn(block); -} - -::capnp::Void ProxyServerMethodTraits::invoke( - Context& context) -{ - auto params = context.call_context.getParams(); - auto command = params.getCommand(); - - CRPCCommand::Actor actor; - ReadField(TypeList(), context, Make(command.getActor()), ReadDestUpdate(actor)); - std::vector> args; - ReadField(TypeList(), context, Make(command.getArgNames()), ReadDestUpdate(args)); - - auto rpc_command = std::make_unique(command.getCategory(), command.getName(), std::move(actor), - std::move(args), command.getUniqueId()); - auto handler = context.proxy_server.m_impl->handleRpc(*rpc_command); - auto results = context.call_context.getResults(); - auto result = kj::heap>(std::shared_ptr(handler.release()), *context.proxy_server.m_context.connection); - result->m_context.cleanup_fns.emplace_back([rpc_command = rpc_command.release()] { delete rpc_command; }); - results.setResult(kj::mv(result)); - return {}; -} - -void ProxyServerMethodTraits::invoke(ChainContext& context) -{ - // This method is never called because ChainClient::Start is overridden by - // WalletLoader::Start. The custom implementation is needed just because - // the CScheduler& argument this is supposed to pass is not serializable. - assert(0); -} - -bool CustomHasValue(InvokeContext& invoke_context, const Coin& coin) -{ - // Spent coins cannot be serialized due to an assert in Coin::Serialize. - return !coin.IsSpent(); -} -} // namespace mp diff --git a/src/ipc/capnp/common-types.h b/src/ipc/capnp/common-types.h index 333f90b5b254..934dae5faf3c 100644 --- a/src/ipc/capnp/common-types.h +++ b/src/ipc/capnp/common-types.h @@ -8,12 +8,9 @@ #include #include #include -#include #include #include #include -#include -#include #include #include @@ -21,10 +18,7 @@ #include #include #include -#include -#include #include -#include #include #include #include @@ -33,29 +27,13 @@ #include #include #include -#include #include -#include #include namespace ipc { namespace capnp { -//! Convert kj::ArrayPtr to base_blob. -template -inline T ToBlob(const kj::ArrayPtr& array) -{ - return T({array.begin(), array.begin() + array.size()}); -} - -//! Convert base_blob to kj::ArrayPtr. -template -inline kj::ArrayPtr ToArray(const T& blob) -{ - return {reinterpret_cast(blob.data()), blob.size()}; -} - //! Construct a ParamStream wrapping a data stream with serialization parameters -//! needed to pass transaction and address objects between bitcoin processes. +//! needed to pass transaction objects between bitcoin processes. //! In the future, more params may be added here to serialize other objects that //! require serialization parameters. Params should just be chosen to serialize //! objects completely and ensure that serializing and deserializing objects @@ -64,28 +42,7 @@ inline kj::ArrayPtr ToArray(const T& blob) template auto Wrap(S& s) { - return ParamsStream{s, TX_WITH_WITNESS, CAddress::V2_NETWORK}; -} - -//! Serialize bitcoin value. -template -DataStream Serialize(const T& value) -{ - DataStream stream; - auto wrapper{Wrap(stream)}; - value.Serialize(wrapper); - return stream; -} - -//! Deserialize bitcoin value. -template -T Unserialize(const kj::ArrayPtr& data) -{ - SpanReader stream{{data.begin(), data.end()}}; - T value; - auto wrapper{Wrap(stream)}; - value.Unserialize(wrapper); - return value; + return ParamsStream{s, TX_WITH_WITNESS}; } //! Detect if type has a deserialize_type constructor, which is @@ -170,96 +127,6 @@ decltype(auto) CustomReadField(TypeList, Priority<1>, InvokeContext& i }); } -//! Overload CustomBuildField and CustomReadField to serialize -//! UniValue::type_error exceptions as text strings. -template -void CustomBuildField(TypeList, Priority<1>, InvokeContext& invoke_context, - Value&& value, Output&& output) -{ - BuildField(TypeList(), invoke_context, output, std::string(value.what())); -} - -template -decltype(auto) CustomReadField(TypeList, Priority<1>, InvokeContext& invoke_context, - Input&& input, ReadDest&& read_dest) -{ - read_dest.construct(ReadField(TypeList(), invoke_context, input, mp::ReadDestTemp())); -} - -//! Overload CustomBuildField and CustomReadField to serialize util::Result -//! return values as common.capnp Result and ResultVoid structs -template -void CustomBuildField(TypeList>, Priority<1>, InvokeContext& invoke_context, Value&& value, - Output&& output) -{ - auto result = output.init(); - if (value) { - if constexpr (!std::is_same_v) { - using ValueAccessor = typename ProxyStruct::ValueAccessor; - BuildField(TypeList(), invoke_context, Make(result), *value); - } - } else { - BuildField(TypeList(), invoke_context, Make(result.initError()), - util::ErrorString(value)); - } -} - -template -decltype(auto) CustomReadField(TypeList>, Priority<1>, InvokeContext& invoke_context, - Input&& input, ReadDest&& read_dest) -{ - auto result = input.get(); - if (result.hasError()) { - bilingual_str error; - ReadField(mp::TypeList(), invoke_context, mp::Make(result.getError()), - mp::ReadDestUpdate(error)); - read_dest.construct(util::Error{std::move(error)}); - } else { - if constexpr (!std::is_same_v) { - assert (result.hasValue()); - ReadField(mp::TypeList(), invoke_context, mp::Make(result.getValue()), - mp::ReadDestEmplace( - mp::TypeList(), [&](auto&&... args) -> auto& { - return *read_dest.construct(LocalType{std::forward(args)...}); - })); - } else { - read_dest.construct(); - } - } -} - -// libmultiprocess only provides read/build functions for std::set, not -// std::unordered_set, so copy and paste those functions here. -// TODO: Move these to libmultiprocess and dedup std::set, std::unordered_set, -// and std::vector implementations. -template -decltype(auto) CustomReadField(TypeList>, Priority<1>, - InvokeContext& invoke_context, Input&& input, ReadDest&& read_dest) -{ - return read_dest.update([&](auto& value) { - auto data = input.get(); - value.clear(); - for (auto item : data) { - ReadField(TypeList(), invoke_context, Make(item), - ReadDestEmplace( - TypeList(), [&](auto&&... args) -> auto& { - return *value.emplace(std::forward(args)...).first; - })); - } - }); -} - -template -void CustomBuildField(TypeList>, Priority<1>, InvokeContext& invoke_context, - Value&& value, Output&& output) -{ - auto list = output.init(value.size()); - size_t i = 0; - for (const auto& elem : value) { - BuildField(TypeList(), invoke_context, ListOutput(list, i), elem); - ++i; - } -} } // namespace mp #endif // BITCOIN_IPC_CAPNP_COMMON_TYPES_H diff --git a/src/ipc/capnp/common.capnp b/src/ipc/capnp/common.capnp index 2c14da5b8451..b3359f3f07b8 100644 --- a/src/ipc/capnp/common.capnp +++ b/src/ipc/capnp/common.capnp @@ -14,28 +14,3 @@ struct BlockRef $Proxy.wrap("interfaces::BlockRef") { hash @0 :Data; height @1 :Int32; } - -struct BilingualStr $Proxy.wrap("bilingual_str") { - original @0 :Text; - translated @1 :Text; -} - -struct Result(Value) { - value @0 :Value; - error @1: BilingualStr; -} - -# Wrapper for util::Result -struct ResultVoid(Value) { - error @0: BilingualStr; -} - -struct Pair(Key, Value) { - key @0 :Key; - value @1 :Value; -} - -struct PairInt64(Key) { - key @0 :Key; - value @1 :Int64; -} diff --git a/src/ipc/capnp/handler-types.h b/src/ipc/capnp/handler-types.h deleted file mode 100644 index 9246a2df86a6..000000000000 --- a/src/ipc/capnp/handler-types.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2025 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_IPC_CAPNP_HANDLER_TYPES_H -#define BITCOIN_IPC_CAPNP_HANDLER_TYPES_H - -#include - -#endif // BITCOIN_IPC_CAPNP_HANDLER_TYPES_H diff --git a/src/ipc/capnp/handler.capnp b/src/ipc/capnp/handler.capnp deleted file mode 100644 index 1d3c7296acf2..000000000000 --- a/src/ipc/capnp/handler.capnp +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2021 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -@0xebd8f46e2f369076; - -using Cxx = import "/capnp/c++.capnp"; -$Cxx.namespace("ipc::capnp::messages"); - -using Proxy = import "/mp/proxy.capnp"; -$Proxy.include("interfaces/handler.h"); -$Proxy.includeTypes("ipc/capnp/handler-types.h"); - -interface Handler $Proxy.wrap("interfaces::Handler") { - destroy @0 (context :Proxy.Context) -> (); - disconnect @1 (context :Proxy.Context) -> (); -} diff --git a/src/ipc/capnp/init-types.h b/src/ipc/capnp/init-types.h index d44cd2490807..c3ddca27c047 100644 --- a/src/ipc/capnp/init-types.h +++ b/src/ipc/capnp/init-types.h @@ -5,7 +5,6 @@ #ifndef BITCOIN_IPC_CAPNP_INIT_TYPES_H #define BITCOIN_IPC_CAPNP_INIT_TYPES_H -#include #include #include diff --git a/src/ipc/capnp/init.capnp b/src/ipc/capnp/init.capnp index 81469921e952..1001ee533687 100644 --- a/src/ipc/capnp/init.capnp +++ b/src/ipc/capnp/init.capnp @@ -8,13 +8,11 @@ using Cxx = import "/capnp/c++.capnp"; $Cxx.namespace("ipc::capnp::messages"); using Proxy = import "/mp/proxy.capnp"; -$Proxy.include("interfaces/chain.h"); $Proxy.include("interfaces/echo.h"); $Proxy.include("interfaces/init.h"); $Proxy.include("interfaces/mining.h"); $Proxy.includeTypes("ipc/capnp/init-types.h"); -using Chain = import "chain.capnp"; using Echo = import "echo.capnp"; using Mining = import "mining.capnp"; @@ -22,5 +20,4 @@ interface Init $Proxy.wrap("interfaces::Init") { construct @0 (threadMap: Proxy.ThreadMap) -> (threadMap :Proxy.ThreadMap); makeEcho @1 (context :Proxy.Context) -> (result :Echo.Echo); makeMining @2 (context :Proxy.Context) -> (result :Mining.Mining); - makeChain @3 (context :Proxy.Context) -> (result :Chain.Chain); } diff --git a/src/ipc/capnp/mining.capnp b/src/ipc/capnp/mining.capnp index 8ee4745b8584..14e1b2394721 100644 --- a/src/ipc/capnp/mining.capnp +++ b/src/ipc/capnp/mining.capnp @@ -19,6 +19,7 @@ interface Mining $Proxy.wrap("interfaces::Mining") { waitTipChanged @3 (context :Proxy.Context, currentTip: Data, timeout: Float64) -> (result: Common.BlockRef); createNewBlock @4 (options: BlockCreateOptions) -> (result: BlockTemplate); checkBlock @5 (block: Data, options: BlockCheckOptions) -> (reason: Text, debug: Text, result: Bool); + removeTxFromMempool @6 (context :Proxy.Context, txid :Data) -> (result :Bool); } interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index f97adfc8b9aa..9bc0a14f73ed 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -553,19 +553,6 @@ class ChainImpl : public Chain LOCK(::cs_main); return Assert(chainman().ActiveChain()[height])->GetBlockHash(); } - bool removeTxFromMempool(const uint256& txid) override - { - NodeContext& node = m_node; - if (!node.mempool) return false; - CTxMemPool& mempool = *node.mempool; - LOCK(mempool.cs); - CTransactionRef tx = mempool.get(txid); - if (tx) { - mempool.removeRecursive(*tx, MemPoolRemovalReason::MANUAL); - return true; - } - return false; - } bool haveBlockOnDisk(int height) override { LOCK(::cs_main); @@ -834,7 +821,7 @@ class ChainImpl : public Chain return result; } bool updateRwSetting(const std::string& name, - interfaces::SettingsUpdate update_settings_func) override + const interfaces::SettingsUpdate& update_settings_func) override { std::optional action; args().LockSettings([&](common::Settings& settings) { @@ -1000,6 +987,20 @@ class MinerImpl : public Mining return state.IsValid(); } + bool removeTxFromMempool(const uint256& txid) override + { + NodeContext& node = m_node; + if (!node.mempool) return false; + CTxMemPool& mempool = *node.mempool; + LOCK(mempool.cs); + CTransactionRef tx = mempool.get(txid); + if (tx) { + mempool.removeRecursive(*tx, MemPoolRemovalReason::MANUAL); + return true; + } + return false; + } + NodeContext* context() override { return &m_node; } ChainstateManager& chainman() { return *Assert(m_node.chainman); } KernelNotifications& notifications() { return *Assert(m_node.notifications); } diff --git a/src/rpc/request.h b/src/rpc/request.h index 498b3bc6d6aa..2fb234c1973a 100644 --- a/src/rpc/request.h +++ b/src/rpc/request.h @@ -61,8 +61,6 @@ class JSONRPCRequest std::string peerAddr; std::any context; JSONRPCVersion m_json_version = JSONRPCVersion::V1_LEGACY; - // Note: If you add fields to this struct, you should also update the - // JSONRPCRequest struct in ipc/capnp/chain.capnp. void parse(const UniValue& valRequest); [[nodiscard]] bool IsNotification() const { return !id.has_value() && m_json_version == JSONRPCVersion::V2; };