Skip to content

Commit ff92d1a

Browse files
committed
partial bitcoin#28331: BIP324 integration
Co-authored-by: UdjinM6 <[email protected]> excludes: - changes to `src/rpc/util.cpp`
1 parent f9f8805 commit ff92d1a

21 files changed

+547
-89
lines changed

doc/bips.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,5 @@ Versions and PRs are relevant to Bitcoin's core if not mentioned other.
4141
* [`BIP 158`](https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki): Compact Block Filters for Light Clients can be indexed as of **Dash Core v18.0** ([PR dash#4314](https://github.com/dashpay/dash/pull/4314), [PR #14121](https://github.com/bitcoin/bitcoin/pull/14121)).
4242
* [`BIP 159`](https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki): The `NODE_NETWORK_LIMITED` service bit is signalled as of **v0.16.0** ([PR 11740](https://github.com/bitcoin/bitcoin/pull/11740)), and such nodes are connected to as of **v0.17.0** ([PR 10387](https://github.com/bitcoin/bitcoin/pull/10387)).
4343
* [`BIP 174`](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki): RPCs to operate on Partially Signed Bitcoin Transactions (PSBT) are present as of **v18.0** ([PR 13557](https://github.com/bitcoin/bitcoin/pull/13557)).
44+
* [`BIP 324`](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki): The v2 transport protocol specified by BIP324 and the associated `NODE_P2P_V2` service bit are supported as of **v22.0**, but off by default ([PR 28331](https://github.com/bitcoin/bitcoin/pull/28331)).
4445
* [`BIP 339`](https://github.com/bitcoin/bips/blob/master/bip-0339.mediawiki): Relay of transactions by wtxid is supported as of **v0.21.0** ([PR 18044](https://github.com/bitcoin/bitcoin/pull/18044)).

src/init.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,7 @@ void SetupServerArgs(ArgsManager& argsman)
588588
argsman.AddArg("-i2psam=<ip:port>", "I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
589589
argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). Ignored if -i2psam is not set. Listening for inbound I2P connections is done through the SAM proxy, not by binding to a local address and port.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
590590
argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
591+
argsman.AddArg("-v2transport", strprintf("Support v2 transport (default: %u)", DEFAULT_V2_TRANSPORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
591592
argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
592593
argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
593594
argsman.AddArg("-peertimeout=<n>", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
@@ -1147,6 +1148,11 @@ bool AppInitParameterInteraction(const ArgsManager& args)
11471148
}
11481149
}
11491150

1151+
// Signal NODE_P2P_V2 if BIP324 v2 transport is enabled.
1152+
if (args.GetBoolArg("-v2transport", DEFAULT_V2_TRANSPORT)) {
1153+
nLocalServices = ServiceFlags(nLocalServices | NODE_P2P_V2);
1154+
}
1155+
11501156
// Signal NODE_COMPACT_FILTERS if peerblockfilters and basic filters index are both enabled.
11511157
if (args.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)) {
11521158
if (g_enabled_filter_types.count(BlockFilterType::BASIC_FILTER) != 1) {

src/net.cpp

Lines changed: 169 additions & 34 deletions
Large diffs are not rendered by default.

src/net.h

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ static const bool DEFAULT_FIXEDSEEDS = true;
114114
static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000;
115115
static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000;
116116

117+
static constexpr bool DEFAULT_V2_TRANSPORT{false};
118+
117119
#if defined USE_KQUEUE
118120
#define DEFAULT_SOCKETEVENTS "kqueue"
119121
#elif defined USE_EPOLL
@@ -126,9 +128,13 @@ static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000;
126128

127129
typedef int64_t NodeId;
128130

129-
struct AddedNodeInfo
130-
{
131-
std::string strAddedNode;
131+
struct AddedNodeParams {
132+
std::string m_added_node;
133+
bool m_use_v2transport;
134+
};
135+
136+
struct AddedNodeInfo {
137+
AddedNodeParams m_params;
132138
CService resolvedAddress;
133139
bool fConnected;
134140
bool fInbound;
@@ -262,6 +268,10 @@ class CNodeStats
262268
uint256 verifiedPubKeyHash;
263269
bool m_masternode_connection;
264270
ConnectionType m_conn_type;
271+
/** Transport protocol type. */
272+
TransportProtocolType m_transport_type;
273+
/** BIP324 session id string in hex, if any. */
274+
std::string m_session_id;
265275
};
266276

267277

@@ -298,6 +308,15 @@ class Transport {
298308
public:
299309
virtual ~Transport() {}
300310

311+
struct Info
312+
{
313+
TransportProtocolType transport_type;
314+
std::optional<uint256> session_id;
315+
};
316+
317+
/** Retrieve information about this transport. */
318+
virtual Info GetInfo() const noexcept = 0;
319+
301320
// 1. Receiver side functions, for decoding bytes received on the wire into transport protocol
302321
// agnostic CNetMessage (message type & payload) objects.
303322

@@ -391,6 +410,11 @@ class Transport {
391410

392411
/** Return the memory usage of this transport attributable to buffered data to send. */
393412
virtual size_t GetSendMemoryUsage() const noexcept = 0;
413+
414+
// 3. Miscellaneous functions.
415+
416+
/** Whether upon disconnections, a reconnect with V1 is warranted. */
417+
virtual bool ShouldReconnectV1() const noexcept = 0;
394418
};
395419

396420
class V1Transport final : public Transport
@@ -451,6 +475,8 @@ class V1Transport final : public Transport
451475
return WITH_LOCK(m_recv_mutex, return CompleteInternal());
452476
}
453477

478+
Info GetInfo() const noexcept override;
479+
454480
bool ReceivedBytes(Span<const uint8_t>& msg_bytes) override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex)
455481
{
456482
AssertLockNotHeld(m_recv_mutex);
@@ -470,6 +496,7 @@ class V1Transport final : public Transport
470496
BytesToSend GetBytesToSend(bool have_next_message) const noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex);
471497
void MarkBytesSent(size_t bytes_sent) noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex);
472498
size_t GetSendMemoryUsage() const noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex);
499+
bool ShouldReconnectV1() const noexcept override { return false; }
473500
};
474501

475502
class V2Transport final : public Transport
@@ -638,6 +665,8 @@ class V2Transport final : public Transport
638665
std::string m_send_type GUARDED_BY(m_send_mutex);
639666
/** Current sender state. */
640667
SendState m_send_state GUARDED_BY(m_send_mutex);
668+
/** Whether we've sent at least 24 bytes (which would trigger disconnect for V1 peers). */
669+
bool m_sent_v1_header_worth GUARDED_BY(m_send_mutex) {false};
641670

642671
/** Change the receive state. */
643672
void SetReceiveState(RecvState recv_state) noexcept EXCLUSIVE_LOCKS_REQUIRED(m_recv_mutex);
@@ -683,6 +712,10 @@ class V2Transport final : public Transport
683712
BytesToSend GetBytesToSend(bool have_next_message) const noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex);
684713
void MarkBytesSent(size_t bytes_sent) noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex);
685714
size_t GetSendMemoryUsage() const noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex);
715+
716+
// Miscellaneous functions.
717+
bool ShouldReconnectV1() const noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex, !m_send_mutex);
718+
Info GetInfo() const noexcept override EXCLUSIVE_LOCKS_REQUIRED(!m_recv_mutex);
686719
};
687720

688721
struct CNodeOptions
@@ -691,6 +724,7 @@ struct CNodeOptions
691724
std::unique_ptr<i2p::sam::Session> i2p_sam_session = nullptr;
692725
bool prefer_evict = false;
693726
size_t recv_flood_size{DEFAULT_MAXRECEIVEBUFFER * 1000};
727+
bool use_v2transport = false;
694728
};
695729

696730
/** Information about a peer */
@@ -739,6 +773,8 @@ class CNode
739773
// Bind address of our side of the connection
740774
const CAddress addrBind;
741775
const std::string m_addr_name;
776+
/** The pszDest argument provided to ConnectNode(). Only used for reconnections. */
777+
const std::string m_dest;
742778
//! Whether this peer is an inbound onion, i.e. connected via our Tor onion service.
743779
const bool m_inbound_onion;
744780
std::atomic<int> nNumWarningsSkipped{0};
@@ -1197,7 +1233,11 @@ friend class CNode;
11971233
vWhitelistedRange = connOptions.vWhitelistedRange;
11981234
{
11991235
LOCK(m_added_nodes_mutex);
1200-
m_added_nodes = connOptions.m_added_nodes;
1236+
1237+
for (const std::string& added_node : connOptions.m_added_nodes) {
1238+
// -addnode cli arg does not currently have a way to signal BIP324 support
1239+
m_added_node_params.push_back({added_node, false});
1240+
}
12011241
}
12021242
socketEventsMode = connOptions.socketEventsMode;
12031243
m_onion_binds = connOptions.onion_binds;
@@ -1237,8 +1277,8 @@ friend class CNode;
12371277
IsConnection,
12381278
};
12391279

1240-
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound,
1241-
const char* strDest, ConnectionType conn_type,
1280+
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant&& grant_outbound,
1281+
const char* strDest, ConnectionType conn_type, bool use_v2transport,
12421282
MasternodeConn masternode_connection = MasternodeConn::IsNotConnection,
12431283
MasternodeProbeConn masternode_probe_connection = MasternodeProbeConn::IsNotConnection)
12441284
EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex, !mutexMsgProc);
@@ -1425,7 +1465,7 @@ friend class CNode;
14251465
// Count the number of block-relay-only peers we have over our limit.
14261466
int GetExtraBlockRelayCount() const;
14271467

1428-
bool AddNode(const std::string& node) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
1468+
bool AddNode(const AddedNodeParams& add) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
14291469
bool RemoveAddedNode(const std::string& node) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
14301470
std::vector<AddedNodeInfo> GetAddedNodeInfo() const EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
14311471

@@ -1541,12 +1581,12 @@ friend class CNode;
15411581
bool InitBinds(const Options& options);
15421582

15431583
void ThreadOpenAddedConnections()
1544-
EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_unused_i2p_sessions_mutex, !mutexMsgProc);
1584+
EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex, !m_unused_i2p_sessions_mutex, !m_reconnections_mutex, !mutexMsgProc);
15451585
void AddAddrFetch(const std::string& strDest) EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex);
15461586
void ProcessAddrFetch()
15471587
EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_unused_i2p_sessions_mutex, !mutexMsgProc);
15481588
void ThreadOpenConnections(const std::vector<std::string> connect, CDeterministicMNManager& dmnman)
1549-
EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex, !mutexMsgProc);
1589+
EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_added_nodes_mutex, !m_nodes_mutex, !m_unused_i2p_sessions_mutex, !m_reconnections_mutex, !mutexMsgProc);
15501590
void ThreadMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc);
15511591
void ThreadI2PAcceptIncoming(CMasternodeSync& mn_sync) EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc);
15521592
void AcceptConnection(const ListenSocket& hListenSocket, CMasternodeSync& mn_sync)
@@ -1566,7 +1606,7 @@ friend class CNode;
15661606
const CAddress& addr,
15671607
CMasternodeSync& mn_sync) EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc);
15681608

1569-
void DisconnectNodes();
1609+
void DisconnectNodes() EXCLUSIVE_LOCKS_REQUIRED(!m_reconnections_mutex, !m_nodes_mutex);
15701610
void NotifyNumConnectionsChanged(CMasternodeSync& mn_sync);
15711611
void CalculateNumConnectionsChangedStats();
15721612
/** Return true if the peer is inactive and should be disconnected. */
@@ -1648,7 +1688,8 @@ friend class CNode;
16481688
void SocketHandlerListening(const std::set<SOCKET>& recv_set, CMasternodeSync& mn_sync)
16491689
EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc);
16501690

1651-
void ThreadSocketHandler(CMasternodeSync& mn_sync) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc);
1691+
void ThreadSocketHandler(CMasternodeSync& mn_sync)
1692+
EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex, !mutexMsgProc, !m_nodes_mutex, !m_reconnections_mutex);
16521693
void ThreadDNSAddressSeed() EXCLUSIVE_LOCKS_REQUIRED(!m_addr_fetches_mutex, !m_nodes_mutex);
16531694
void ThreadOpenMasternodeConnections(CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman,
16541695
CMasternodeSync& mn_sync)
@@ -1668,8 +1709,7 @@ friend class CNode;
16681709
bool AlreadyConnectedToAddress(const CAddress& addr);
16691710

16701711
bool AttemptToEvictConnection();
1671-
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = nullptr, bool fCountFailure = false, ConnectionType conn_type = ConnectionType::OUTBOUND_FULL_RELAY)
1672-
EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
1712+
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
16731713
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
16741714

16751715
void DeleteNode(CNode* pnode);
@@ -1729,7 +1769,10 @@ friend class CNode;
17291769
const NetGroupManager& m_netgroupman;
17301770
std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
17311771
Mutex m_addr_fetches_mutex;
1732-
std::vector<std::string> m_added_nodes GUARDED_BY(m_added_nodes_mutex);
1772+
1773+
// connection string and whether to use v2 p2p
1774+
std::vector<AddedNodeParams> m_added_node_params GUARDED_BY(m_added_nodes_mutex);
1775+
17331776
mutable Mutex m_added_nodes_mutex;
17341777
std::vector<CNode*> m_nodes GUARDED_BY(m_nodes_mutex);
17351778
std::list<CNode*> m_nodes_disconnected;
@@ -1896,6 +1939,29 @@ friend class CNode;
18961939
*/
18971940
std::queue<std::unique_ptr<i2p::sam::Session>> m_unused_i2p_sessions GUARDED_BY(m_unused_i2p_sessions_mutex);
18981941

1942+
/**
1943+
* Mutex protecting m_reconnections.
1944+
*/
1945+
Mutex m_reconnections_mutex;
1946+
1947+
/** Struct for entries in m_reconnections. */
1948+
struct ReconnectionInfo
1949+
{
1950+
CAddress addr_connect;
1951+
CSemaphoreGrant grant;
1952+
std::string destination;
1953+
ConnectionType conn_type;
1954+
bool use_v2transport;
1955+
};
1956+
1957+
/**
1958+
* List of reconnections we have to make.
1959+
*/
1960+
std::list<ReconnectionInfo> m_reconnections GUARDED_BY(m_reconnections_mutex);
1961+
1962+
/** Attempt reconnections, if m_reconnections non-empty. */
1963+
void PerformReconnections() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc, !m_reconnections_mutex, !m_unused_i2p_sessions_mutex);
1964+
18991965
/**
19001966
* Cap on the size of `m_unused_i2p_sessions`, to ensure it does not
19011967
* unexpectedly use too much memory.

src/net_processing.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3596,11 +3596,14 @@ void PeerManagerImpl::ProcessMessage(
35963596
return;
35973597
}
35983598

3599-
if (!pfrom.IsInboundConn()) {
3600-
LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s (%s)\n",
3599+
// Log succesful connections unconditionally for outbound, but not for inbound as those
3600+
// can be triggered by an attacker at high rate.
3601+
if (!pfrom.IsInboundConn() || LogAcceptCategory(BCLog::NET)) {
3602+
LogPrintf("New %s %s peer connected: version: %d, blocks=%d, peer=%d%s\n",
3603+
pfrom.ConnectionTypeAsString(),
3604+
TransportTypeAsString(pfrom.m_transport->GetInfo().transport_type),
36013605
pfrom.nVersion.load(), peer->m_starting_height,
3602-
pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToStringAddrPort()) : ""),
3603-
pfrom.ConnectionTypeAsString());
3606+
pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToStringAddrPort()) : ""));
36043607
}
36053608

36063609
if (is_masternode && !pfrom.m_masternode_probe_connection) {

src/node/connection_types.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,17 @@ std::string ConnectionTypeAsString(ConnectionType conn_type)
2424

2525
assert(false);
2626
}
27+
28+
std::string TransportTypeAsString(TransportProtocolType transport_type)
29+
{
30+
switch (transport_type) {
31+
case TransportProtocolType::DETECTING:
32+
return "detecting";
33+
case TransportProtocolType::V1:
34+
return "v1";
35+
case TransportProtocolType::V2:
36+
return "v2";
37+
} // no default case, so the compiler can warn about missing cases
38+
39+
assert(false);
40+
}

src/node/connection_types.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define BITCOIN_NODE_CONNECTION_TYPES_H
77

88
#include <string>
9+
#include <stdint.h>
910

1011
/** Different types of connections to a peer. This enum encapsulates the
1112
* information we have available at the time of opening or accepting the
@@ -79,4 +80,14 @@ enum class ConnectionType {
7980
/** Convert ConnectionType enum to a string value */
8081
std::string ConnectionTypeAsString(ConnectionType conn_type);
8182

83+
/** Transport layer version */
84+
enum class TransportProtocolType : uint8_t {
85+
DETECTING, //!< Peer could be v1 or v2
86+
V1, //!< Unencrypted, plaintext protocol
87+
V2, //!< BIP324 protocol
88+
};
89+
90+
/** Convert TransportProtocolType enum to a string value */
91+
std::string TransportTypeAsString(TransportProtocolType transport_type);
92+
8293
#endif // BITCOIN_NODE_CONNECTION_TYPES_H

src/protocol.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ static std::string serviceFlagToStr(size_t bit)
338338
case NODE_COMPACT_FILTERS: return "COMPACT_FILTERS";
339339
case NODE_NETWORK_LIMITED: return "NETWORK_LIMITED";
340340
case NODE_HEADERS_COMPRESSED: return "HEADERS_COMPRESSED";
341+
case NODE_P2P_V2: return "P2P_V2";
341342
// Not using default, so we get warned when a case is missing
342343
}
343344

src/protocol.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,9 @@ enum ServiceFlags : uint64_t {
328328
// description will be provided
329329
NODE_HEADERS_COMPRESSED = (1 << 11),
330330

331+
// NODE_P2P_V2 means the node supports BIP324 transport
332+
NODE_P2P_V2 = (1 << 12),
333+
331334
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
332335
// isn't getting used, or one not being used much, and notify the
333336
// bitcoin-development mailing list. Remember that service bits are just

src/rpc/client.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
232232
{ "addpeeraddress", 2, "tried"},
233233
{ "sendmsgtopeer", 0, "peer_id" },
234234
{ "stop", 0, "wait" },
235+
{ "addnode", 2, "v2transport" },
235236
{ "verifychainlock", 2, "blockHeight" },
236237
{ "verifyislock", 3, "maxHeight" },
237238
{ "submitchainlock", 2, "blockHeight" },

0 commit comments

Comments
 (0)