mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-10 09:06:15 +01:00
multiprocess: Add serialization code for BlockValidationState
Co-authored-by: TheCharlatan <seb.kung@gmail.com>
This commit is contained in:
parent
33c2eee285
commit
d043950ba2
8 changed files with 104 additions and 3 deletions
|
@ -3,6 +3,7 @@
|
||||||
# file COPYING or https://opensource.org/license/mit/.
|
# file COPYING or https://opensource.org/license/mit/.
|
||||||
|
|
||||||
add_library(bitcoin_ipc STATIC EXCLUDE_FROM_ALL
|
add_library(bitcoin_ipc STATIC EXCLUDE_FROM_ALL
|
||||||
|
capnp/mining.cpp
|
||||||
capnp/protocol.cpp
|
capnp/protocol.cpp
|
||||||
interfaces.cpp
|
interfaces.cpp
|
||||||
process.cpp
|
process.cpp
|
||||||
|
|
|
@ -13,4 +13,14 @@
|
||||||
#include <node/types.h>
|
#include <node/types.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
|
|
||||||
|
namespace mp {
|
||||||
|
// Custom serialization for BlockValidationState.
|
||||||
|
void CustomBuildMessage(InvokeContext& invoke_context,
|
||||||
|
const BlockValidationState& src,
|
||||||
|
ipc::capnp::messages::BlockValidationState::Builder&& builder);
|
||||||
|
void CustomReadMessage(InvokeContext& invoke_context,
|
||||||
|
const ipc::capnp::messages::BlockValidationState::Reader& reader,
|
||||||
|
BlockValidationState& dest);
|
||||||
|
} // namespace mp
|
||||||
|
|
||||||
#endif // BITCOIN_IPC_CAPNP_MINING_TYPES_H
|
#endif // BITCOIN_IPC_CAPNP_MINING_TYPES_H
|
||||||
|
|
|
@ -39,6 +39,12 @@ struct BlockCreateOptions $Proxy.wrap("node::BlockCreateOptions") {
|
||||||
coinbaseOutputMaxAdditionalSigops @2 :UInt64 $Proxy.name("coinbase_output_max_additional_sigops");
|
coinbaseOutputMaxAdditionalSigops @2 :UInt64 $Proxy.name("coinbase_output_max_additional_sigops");
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO add fields to this struct
|
# Note: serialization of the BlockValidationState C++ type is somewhat fragile
|
||||||
struct BlockValidationState $Proxy.wrap("BlockValidationState") {
|
# and using the struct can be awkward. It would be good if testBlockValidity
|
||||||
|
# method were changed to return validity information in a simpler format.
|
||||||
|
struct BlockValidationState {
|
||||||
|
mode @0 :Int32;
|
||||||
|
result @1 :Int32;
|
||||||
|
rejectReason @2 :Text;
|
||||||
|
debugMessage @3 :Text;
|
||||||
}
|
}
|
||||||
|
|
47
src/ipc/capnp/mining.cpp
Normal file
47
src/ipc/capnp/mining.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// 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 <ipc/capnp/mining-types.h>
|
||||||
|
#include <ipc/capnp/mining.capnp.proxy-types.h>
|
||||||
|
|
||||||
|
#include <mp/proxy-types.h>
|
||||||
|
|
||||||
|
namespace mp {
|
||||||
|
void CustomBuildMessage(InvokeContext& invoke_context,
|
||||||
|
const BlockValidationState& src,
|
||||||
|
ipc::capnp::messages::BlockValidationState::Builder&& builder)
|
||||||
|
{
|
||||||
|
if (src.IsValid()) {
|
||||||
|
builder.setMode(0);
|
||||||
|
} else if (src.IsInvalid()) {
|
||||||
|
builder.setMode(1);
|
||||||
|
} else if (src.IsError()) {
|
||||||
|
builder.setMode(2);
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
builder.setResult(static_cast<int>(src.GetResult()));
|
||||||
|
builder.setRejectReason(src.GetRejectReason());
|
||||||
|
builder.setDebugMessage(src.GetDebugMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomReadMessage(InvokeContext& invoke_context,
|
||||||
|
const ipc::capnp::messages::BlockValidationState::Reader& reader,
|
||||||
|
BlockValidationState& dest)
|
||||||
|
{
|
||||||
|
if (reader.getMode() == 0) {
|
||||||
|
assert(reader.getResult() == 0);
|
||||||
|
assert(reader.getRejectReason().size() == 0);
|
||||||
|
assert(reader.getDebugMessage().size() == 0);
|
||||||
|
} else if (reader.getMode() == 1) {
|
||||||
|
dest.Invalid(static_cast<BlockValidationResult>(reader.getResult()), reader.getRejectReason(), reader.getDebugMessage());
|
||||||
|
} else if (reader.getMode() == 2) {
|
||||||
|
assert(reader.getResult() == 0);
|
||||||
|
dest.Error(reader.getRejectReason());
|
||||||
|
assert(reader.getDebugMessage().size() == 0);
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace mp
|
|
@ -9,7 +9,9 @@ $Cxx.namespace("gen");
|
||||||
|
|
||||||
using Proxy = import "/mp/proxy.capnp";
|
using Proxy = import "/mp/proxy.capnp";
|
||||||
$Proxy.include("test/ipc_test.h");
|
$Proxy.include("test/ipc_test.h");
|
||||||
$Proxy.includeTypes("ipc/capnp/common-types.h");
|
$Proxy.includeTypes("test/ipc_test_types.h");
|
||||||
|
|
||||||
|
using Mining = import "../ipc/capnp/mining.capnp";
|
||||||
|
|
||||||
interface FooInterface $Proxy.wrap("FooImplementation") {
|
interface FooInterface $Proxy.wrap("FooImplementation") {
|
||||||
add @0 (a :Int32, b :Int32) -> (result :Int32);
|
add @0 (a :Int32, b :Int32) -> (result :Int32);
|
||||||
|
@ -17,4 +19,5 @@ interface FooInterface $Proxy.wrap("FooImplementation") {
|
||||||
passUniValue @2 (arg :Text) -> (result :Text);
|
passUniValue @2 (arg :Text) -> (result :Text);
|
||||||
passTransaction @3 (arg :Data) -> (result :Data);
|
passTransaction @3 (arg :Data) -> (result :Data);
|
||||||
passVectorChar @4 (arg :Data) -> (result :Data);
|
passVectorChar @4 (arg :Data) -> (result :Data);
|
||||||
|
passBlockState @5 (arg :Mining.BlockValidationState) -> (result :Mining.BlockValidationState);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <test/ipc_test.capnp.proxy.h>
|
#include <test/ipc_test.capnp.proxy.h>
|
||||||
#include <test/ipc_test.h>
|
#include <test/ipc_test.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
|
#include <validation.h>
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
@ -101,6 +102,25 @@ void IpcPipeTest()
|
||||||
std::vector<char> vec2{foo->passVectorChar(vec1)};
|
std::vector<char> vec2{foo->passVectorChar(vec1)};
|
||||||
BOOST_CHECK_EQUAL(std::string_view(vec1.begin(), vec1.end()), std::string_view(vec2.begin(), vec2.end()));
|
BOOST_CHECK_EQUAL(std::string_view(vec1.begin(), vec1.end()), std::string_view(vec2.begin(), vec2.end()));
|
||||||
|
|
||||||
|
BlockValidationState bs1;
|
||||||
|
bs1.Invalid(BlockValidationResult::BLOCK_CHECKPOINT, "reject reason", "debug message");
|
||||||
|
BlockValidationState bs2{foo->passBlockState(bs1)};
|
||||||
|
BOOST_CHECK_EQUAL(bs1.IsValid(), bs2.IsValid());
|
||||||
|
BOOST_CHECK_EQUAL(bs1.IsError(), bs2.IsError());
|
||||||
|
BOOST_CHECK_EQUAL(bs1.IsInvalid(), bs2.IsInvalid());
|
||||||
|
BOOST_CHECK_EQUAL(static_cast<int>(bs1.GetResult()), static_cast<int>(bs2.GetResult()));
|
||||||
|
BOOST_CHECK_EQUAL(bs1.GetRejectReason(), bs2.GetRejectReason());
|
||||||
|
BOOST_CHECK_EQUAL(bs1.GetDebugMessage(), bs2.GetDebugMessage());
|
||||||
|
|
||||||
|
BlockValidationState bs3;
|
||||||
|
BlockValidationState bs4{foo->passBlockState(bs3)};
|
||||||
|
BOOST_CHECK_EQUAL(bs3.IsValid(), bs4.IsValid());
|
||||||
|
BOOST_CHECK_EQUAL(bs3.IsError(), bs4.IsError());
|
||||||
|
BOOST_CHECK_EQUAL(bs3.IsInvalid(), bs4.IsInvalid());
|
||||||
|
BOOST_CHECK_EQUAL(static_cast<int>(bs3.GetResult()), static_cast<int>(bs4.GetResult()));
|
||||||
|
BOOST_CHECK_EQUAL(bs3.GetRejectReason(), bs4.GetRejectReason());
|
||||||
|
BOOST_CHECK_EQUAL(bs3.GetDebugMessage(), bs4.GetDebugMessage());
|
||||||
|
|
||||||
// Test cleanup: disconnect pipe and join thread
|
// Test cleanup: disconnect pipe and join thread
|
||||||
disconnect_client();
|
disconnect_client();
|
||||||
thread.join();
|
thread.join();
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
#include <util/fs.h>
|
#include <util/fs.h>
|
||||||
|
#include <validation.h>
|
||||||
|
|
||||||
class FooImplementation
|
class FooImplementation
|
||||||
{
|
{
|
||||||
|
@ -17,6 +18,7 @@ public:
|
||||||
UniValue passUniValue(UniValue v) { return v; }
|
UniValue passUniValue(UniValue v) { return v; }
|
||||||
CTransactionRef passTransaction(CTransactionRef t) { return t; }
|
CTransactionRef passTransaction(CTransactionRef t) { return t; }
|
||||||
std::vector<char> passVectorChar(std::vector<char> v) { return v; }
|
std::vector<char> passVectorChar(std::vector<char> v) { return v; }
|
||||||
|
BlockValidationState passBlockState(BlockValidationState s) { return s; }
|
||||||
};
|
};
|
||||||
|
|
||||||
void IpcPipeTest();
|
void IpcPipeTest();
|
||||||
|
|
12
src/test/ipc_test_types.h
Normal file
12
src/test/ipc_test_types.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// 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_TEST_IPC_TEST_TYPES_H
|
||||||
|
#define BITCOIN_TEST_IPC_TEST_TYPES_H
|
||||||
|
|
||||||
|
#include <ipc/capnp/common-types.h>
|
||||||
|
#include <ipc/capnp/mining-types.h>
|
||||||
|
#include <test/ipc_test.capnp.h>
|
||||||
|
|
||||||
|
#endif // BITCOIN_TEST_IPC_TEST_TYPES_H
|
Loading…
Add table
Reference in a new issue