mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-12 10:30:08 +01:00
Add capnp wrapper for Chain interface
This commit is contained in:
parent
136a73db9f
commit
6c42cf41be
9 changed files with 542 additions and 3 deletions
|
@ -357,7 +357,7 @@ public:
|
|||
//! 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, const SettingsUpdate& update_function) = 0;
|
||||
virtual bool updateRwSetting(const std::string& name, SettingsUpdate update_function) = 0;
|
||||
|
||||
//! Replace a setting in <datadir>/settings.json with a new value.
|
||||
//! Null can be passed to erase the setting.
|
||||
|
@ -404,7 +404,8 @@ public:
|
|||
//! Load saved state.
|
||||
virtual bool load() = 0;
|
||||
|
||||
//! Start client execution and provide a scheduler.
|
||||
//! Start client execution and provide a scheduler. (Scheduler is
|
||||
//! ignored if client is out-of-process).
|
||||
virtual void start(CScheduler& scheduler) = 0;
|
||||
|
||||
//! Save state to disk.
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# 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
|
||||
|
@ -10,6 +11,7 @@ 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
|
||||
|
|
91
src/ipc/capnp/chain-types.h
Normal file
91
src/ipc/capnp/chain-types.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
// 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 <ipc/capnp/chain.capnp.proxy.h>
|
||||
#include <ipc/capnp/common.capnp.proxy-types.h>
|
||||
#include <ipc/capnp/handler.capnp.proxy-types.h>
|
||||
#include <interfaces/chain.h>
|
||||
#include <policy/fees.h>
|
||||
#include <rpc/server.h>
|
||||
|
||||
//! 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<ipc::capnp::messages::Chain::HandleRpcParams>
|
||||
{
|
||||
using Context = ServerContext<ipc::capnp::messages::Chain,
|
||||
ipc::capnp::messages::Chain::HandleRpcParams,
|
||||
ipc::capnp::messages::Chain::HandleRpcResults>;
|
||||
static ::capnp::Void invoke(Context& context);
|
||||
};
|
||||
|
||||
//! Specialization of start method needed to provide CScheduler& reference
|
||||
//! argument.
|
||||
template <>
|
||||
struct mp::ProxyServerMethodTraits<ipc::capnp::messages::ChainClient::StartParams>
|
||||
{
|
||||
using ChainContext = ServerContext<ipc::capnp::messages::ChainClient,
|
||||
ipc::capnp::messages::ChainClient::StartParams,
|
||||
ipc::capnp::messages::ChainClient::StartResults>;
|
||||
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<void(const interfaces::FoundBlock&)>&& 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<void(const interfaces::BlockInfo&)>&& fn);
|
||||
|
||||
//! CScheduler& server-side argument handling. Skips argument so it can
|
||||
//! be handled by ProxyServerMethodTraits ChainClient::Start code.
|
||||
template <typename Accessor, typename ServerContext, typename Fn, typename... Args>
|
||||
void CustomPassField(TypeList<CScheduler&>, ServerContext& server_context, const Fn& fn, Args&&... args)
|
||||
{
|
||||
fn.invoke(server_context, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
//! CRPCCommand& server-side argument handling. Skips argument so it can
|
||||
//! be handled by ProxyServerMethodTraits Chain::HandleRpc code.
|
||||
template <typename Accessor, typename ServerContext, typename Fn, typename... Args>
|
||||
void CustomPassField(TypeList<const CRPCCommand&>, ServerContext& server_context, const Fn& fn, Args&&... args)
|
||||
{
|
||||
fn.invoke(server_context, std::forward<Args>(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
|
196
src/ipc/capnp/chain.capnp
Normal file
196
src/ipc/capnp/chain.capnp
Normal file
|
@ -0,0 +1,196 @@
|
|||
# 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);
|
||||
}
|
||||
|
||||
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) -> ();
|
||||
flush @5 (context :Proxy.Context) -> ();
|
||||
stop @6 (context :Proxy.Context) -> ();
|
||||
setMockTime @7 (context :Proxy.Context, time :Int64) -> ();
|
||||
schedulerMockForward @8 (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<CRPCCommand::Actor>") {
|
||||
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<std::function<void()>>") {
|
||||
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<interfaces::SettingsUpdate>") {
|
||||
destroy @0 (context :Proxy.Context) -> ();
|
||||
call @1 (context :Proxy.Context, value :Text) -> (value :Text, result: Int32, hasResult: Bool);
|
||||
}
|
205
src/ipc/capnp/chain.cpp
Normal file
205
src/ipc/capnp/chain.cpp
Normal file
|
@ -0,0 +1,205 @@
|
|||
// 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 <capnp/blob.h>
|
||||
#include <capnp/capability.h>
|
||||
#include <capnp/list.h>
|
||||
#include <coins.h>
|
||||
#include <interfaces/chain.h>
|
||||
#include <interfaces/handler.h>
|
||||
#include <interfaces/ipc.h>
|
||||
#include <ipc/capnp/chain-types.h>
|
||||
#include <ipc/capnp/chain.capnp.h>
|
||||
#include <ipc/capnp/chain.capnp.proxy.h>
|
||||
#include <ipc/capnp/chain.capnp.proxy-types.h>
|
||||
#include <ipc/capnp/common-types.h>
|
||||
#include <ipc/capnp/context.h>
|
||||
#include <ipc/capnp/handler.capnp.proxy.h>
|
||||
#include <mp/proxy-io.h>
|
||||
#include <mp/proxy-types.h>
|
||||
#include <mp/util.h>
|
||||
#include <primitives/block.h>
|
||||
#include <rpc/server.h>
|
||||
#include <streams.h>
|
||||
#include <uint256.h>
|
||||
#include <undo.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
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<void()>& 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<void(const interfaces::FoundBlock&)>&& 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<uint256>(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<CBlockLocator>(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<CBlock>(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<interfaces::BlockInfo>(), invoke_context, builder, block);
|
||||
}
|
||||
|
||||
void CustomPassMessage(InvokeContext& invoke_context,
|
||||
const ipc::capnp::messages::BlockInfo::Reader& reader,
|
||||
::capnp::Void builder,
|
||||
std::function<void(const interfaces::BlockInfo&)>&& 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<uint256>(reader.getHash());
|
||||
std::optional<const uint256> prev_hash;
|
||||
std::optional<const CBlock> data;
|
||||
std::optional<const CBlockUndo> undo_data;
|
||||
interfaces::BlockInfo block{hash};
|
||||
if (reader.hasPrevHash()) {
|
||||
prev_hash.emplace(ipc::capnp::ToBlob<uint256>(reader.getPrevHash()));
|
||||
block.prev_hash = &*prev_hash;
|
||||
}
|
||||
if (reader.hasData()) {
|
||||
data.emplace(ipc::capnp::Unserialize<CBlock>(reader.getData()));
|
||||
block.data = &*data;
|
||||
}
|
||||
if (reader.hasUndoData()) {
|
||||
undo_data.emplace(ipc::capnp::Unserialize<CBlockUndo>(reader.getUndoData()));
|
||||
block.undo_data = &*undo_data;
|
||||
}
|
||||
mp::ReadField(mp::TypeList<interfaces::BlockInfo>(), invoke_context,
|
||||
mp::Make<mp::ValueField>(reader), mp::ReadDestUpdate(block));
|
||||
fn(block);
|
||||
}
|
||||
|
||||
::capnp::Void ProxyServerMethodTraits<ipc::capnp::messages::Chain::HandleRpcParams>::invoke(
|
||||
Context& context)
|
||||
{
|
||||
auto params = context.call_context.getParams();
|
||||
auto command = params.getCommand();
|
||||
|
||||
CRPCCommand::Actor actor;
|
||||
ReadField(TypeList<decltype(actor)>(), context, Make<ValueField>(command.getActor()), ReadDestUpdate(actor));
|
||||
std::vector<std::pair<std::string, bool>> args;
|
||||
ReadField(TypeList<decltype(args)>(), context, Make<ValueField>(command.getArgNames()), ReadDestUpdate(args));
|
||||
|
||||
auto rpc_command = std::make_unique<CRPCCommand>(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<ProxyServer<ipc::capnp::messages::Handler>>(std::shared_ptr<interfaces::Handler>(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<ipc::capnp::messages::ChainClient::StartParams>::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
|
|
@ -21,7 +21,10 @@
|
|||
#include <mp/type-context.h>
|
||||
#include <mp/type-data.h>
|
||||
#include <mp/type-decay.h>
|
||||
#include <mp/type-exception.h>
|
||||
#include <mp/type-function.h>
|
||||
#include <mp/type-interface.h>
|
||||
#include <mp/type-map.h>
|
||||
#include <mp/type-message.h>
|
||||
#include <mp/type-number.h>
|
||||
#include <mp/type-optional.h>
|
||||
|
@ -30,6 +33,7 @@
|
|||
#include <mp/type-struct.h>
|
||||
#include <mp/type-threadmap.h>
|
||||
#include <mp/type-vector.h>
|
||||
#include <mp/type-void.h>
|
||||
#include <type_traits>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
@ -223,6 +227,39 @@ decltype(auto) CustomReadField(TypeList<util::Result<LocalType>>, Priority<1>, I
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 <typename LocalType, typename Hash, typename Input, typename ReadDest>
|
||||
decltype(auto) CustomReadField(TypeList<std::unordered_set<LocalType, Hash>>, 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<LocalType>(), invoke_context, Make<ValueField>(item),
|
||||
ReadDestEmplace(
|
||||
TypeList<const LocalType>(), [&](auto&&... args) -> auto& {
|
||||
return *value.emplace(std::forward<decltype(args)>(args)...).first;
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <typename LocalType, typename Hash, typename Value, typename Output>
|
||||
void CustomBuildField(TypeList<std::unordered_set<LocalType, Hash>>, 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<LocalType>(), invoke_context, ListOutput<typename decltype(list)::Builds>(list, i), elem);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
} // namespace mp
|
||||
|
||||
#endif // BITCOIN_IPC_CAPNP_COMMON_TYPES_H
|
||||
|
|
|
@ -34,3 +34,8 @@ struct Pair(Key, Value) {
|
|||
key @0 :Key;
|
||||
value @1 :Value;
|
||||
}
|
||||
|
||||
struct PairInt64(Key) {
|
||||
key @0 :Key;
|
||||
value @1 :Int64;
|
||||
}
|
||||
|
|
|
@ -826,7 +826,7 @@ public:
|
|||
return result;
|
||||
}
|
||||
bool updateRwSetting(const std::string& name,
|
||||
const interfaces::SettingsUpdate& update_settings_func) override
|
||||
interfaces::SettingsUpdate update_settings_func) override
|
||||
{
|
||||
std::optional<interfaces::SettingsAction> action;
|
||||
args().LockSettings([&](common::Settings& settings) {
|
||||
|
|
|
@ -44,6 +44,8 @@ public:
|
|||
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; };
|
||||
|
|
Loading…
Add table
Reference in a new issue