xrpld
Loading...
Searching...
No Matches
CapturePeer.h
1#pragma once
2
3#include <test/jtx/Env.h>
4
5#include <xrpld/app/main/Application.h>
6#include <xrpld/overlay/Message.h>
7#include <xrpld/overlay/Peer.h>
8#include <xrpld/overlay/detail/OverlayImpl.h>
9#include <xrpld/overlay/detail/PeerImp.h>
10#include <xrpld/overlay/detail/ProtocolVersion.h>
11
12#include <xrpl/basics/contract.h>
13#include <xrpl/basics/make_SSLContext.h>
14#include <xrpl/beast/net/IPEndpoint.h>
15#include <xrpl/peerfinder/Slot.h>
16#include <xrpl/protocol/KeyType.h>
17#include <xrpl/protocol/PublicKey.h>
18#include <xrpl/protocol/SecretKey.h>
19#include <xrpl/resource/Charge.h>
20#include <xrpl/resource/Consumer.h>
21#include <xrpl/server/Handoff.h>
22
23#include <boost/asio/ip/address.hpp>
24#include <boost/asio/ip/address_v4.hpp>
25#include <boost/asio/ip/tcp.hpp>
26#include <boost/asio/ssl/context.hpp>
27#include <boost/beast/core/tcp_stream.hpp>
28#include <boost/beast/ssl/ssl_stream.hpp>
29
30#include <cstdint>
31#include <memory>
32#include <optional>
33#include <stdexcept>
34#include <string>
35#include <utility>
36#include <vector>
37
38namespace xrpl::test {
39
46class CapturePeer : public PeerImp
47{
48public:
49 using MiddleType = boost::beast::tcp_stream;
50 using StreamType = boost::beast::ssl_stream<MiddleType>;
51 using SocketType = boost::asio::ip::tcp::socket;
52
69 Application& app,
70 Peer::ID id,
72 HttpRequestType request,
73 PublicKey const& publicKey,
75 resource::Consumer consumer,
77 OverlayImpl& overlay)
78 : PeerImp(
79 app,
80 id,
81 slot,
82 std::move(request),
83 publicKey,
85 consumer, // copy-only, so `std::move` would be a copy anyway
86 std::move(streamPtr),
87 overlay)
88 {
89 }
90
91 ~CapturePeer() override = default;
92
97 void
98 run() override
99 {
100 }
101
105 void
107 {
108 sent_.push_back(m);
109 }
110
115 sent() const
116 {
117 return sent_;
118 }
119
124 lastSent() const
125 {
126 return sent_.empty() ? nullptr : sent_.back();
127 }
128
135 feeCharge() const
136 {
137 return currentFeeCharge();
138 }
139
140private:
142};
143
144namespace detail {
145
146// `inline` so the functions below name one entity across translation units.
147inline constexpr std::uint16_t kCapturePeerPort = 51235;
148
156inline Peer::ID
158{
159 static Peer::ID id{0};
160 return ++id;
161}
162
172{
173 // From 172.2.0.1 upward, so ~900k fit before reaching 172.16/12, where the
174 // peer finder would treat them as private rather than as real inbound.
175 static std::uint32_t next{0xAC020001};
176 return beast::ip::Endpoint(boost::asio::ip::address_v4(next++), kCapturePeerPort);
177}
178
185inline boost::asio::ssl::context&
187{
189 return *kContext;
190}
191
192} // namespace detail
193
207template <class PeerType = CapturePeer>
210 jtx::Env& env,
211 std::optional<PublicKey> key = std::nullopt,
212 HttpRequestType request = {})
213{
214 auto& overlay = dynamic_cast<OverlayImpl&>(env.app().getOverlay());
217
218 beast::ip::Endpoint const local(
219 boost::asio::ip::make_address("172.1.1.1"), detail::kCapturePeerPort);
220 auto const remote = detail::nextCapturePeerRemote();
221
222 auto consumer = overlay.resourceManager().newInboundEndpoint(remote);
223 auto [slot, _] = overlay.peerFinder().newInboundSlot(local, remote);
224
225 // Unseated when the endpoint is already connected or at the per-address
226 // limit. `PeerImp` dereferences the slot, so fail here, not there.
227 if (!slot)
228 {
229 Throw<std::runtime_error>("makeCapturePeer: no slot for " + to_string(remote));
230 }
231
232 if (!key)
233 key = PublicKey(std::get<0>(randomKeyPair(KeyType::Ed25519)));
234
235 auto peer = std::make_shared<PeerType>(
236 env.app(),
238 slot,
239 std::move(request),
240 *key,
241 // An unsupported version fails every `supportsFeature` test, so a
242 // version-gated reply would only ever take its legacy branch.
244 consumer,
245 std::move(streamPtr),
246 overlay);
247
248 overlay.addActive(peer);
249 return peer;
250}
251
252} // namespace xrpl::test
A version-independent IP address and port combination.
Definition IPEndpoint.h:24
PeerImp(PeerImp const &)=delete
friend class OverlayImpl
Definition PeerImp.h:216
resource::Charge currentFeeCharge() const
Read-only accessor for the accumulated peer-message charge.
Definition PeerImp.h:756
Peer::ID id() const override
Definition PeerImp.h:361
std::shared_ptr< peer_finder::Slot > const & slot()
Definition PeerImp.h:296
std::uint32_t ID
Uniquely identifies a peer.
A public key.
Definition PublicKey.h:53
virtual boost::asio::io_context & getIOContext()=0
A consumption charge.
Definition Charge.h:13
An endpoint that consumes resources.
Definition Consumer.h:20
std::vector< std::shared_ptr< Message > > sent_
void send(std::shared_ptr< Message > const &m) override
Captures the message instead of writing it, so replies are observable.
boost::asio::ip::tcp::socket SocketType
Definition CapturePeer.h:51
void run() override
Does nothing, so the peer stays registered.
Definition CapturePeer.h:98
boost::beast::tcp_stream MiddleType
Definition CapturePeer.h:49
resource::Charge feeCharge() const
Reads the accumulated charge without draining it through charge().
std::vector< std::shared_ptr< Message > > const & sent() const
std::shared_ptr< Message > lastSent() const
boost::beast::ssl_stream< MiddleType > StreamType
Definition CapturePeer.h:50
CapturePeer(Application &app, Peer::ID id, std::shared_ptr< peer_finder::Slot > const &slot, HttpRequestType request, PublicKey const &publicKey, ProtocolVersion protocol, resource::Consumer consumer, std::unique_ptr< StreamType > streamPtr, OverlayImpl &overlay)
Takes PeerImp's two rvalue-reference parameters by value instead, so a derived double can inherit thi...
Definition CapturePeer.h:68
~CapturePeer() override=default
A transaction testing environment.
Definition Env.h:161
Application & app()
Definition Env.h:300
T make_shared(T... args)
T make_unique(T... args)
STL namespace.
constexpr std::uint16_t kCapturePeerPort
boost::asio::ssl::context & capturePeerSslContext()
Outlives every peer, whose stream keeps a reference to it.
beast::ip::Endpoint nextCapturePeerRemote()
Non-template for the same reason as nextCapturePeerId.
Peer::ID nextCapturePeerId()
Non-template, so all makeCapturePeer instantiations share one counter.
std::shared_ptr< PeerType > makeCapturePeer(jtx::Env &env, std::optional< PublicKey > key=std::nullopt, HttpRequestType request={})
Build an active CapturePeer and register it with the overlay.
ProtocolVersion newestSupportedProtocolVersion()
The version negotiated with a peer that speaks everything we speak, so also the one that enables ever...
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:657
boost::beast::http::request< boost::beast::http::dynamic_body > HttpRequestType
Definition Handoff.h:12
std::shared_ptr< boost::asio::ssl::context > makeSslContext(std::string const &cipherList)
Create a self-signed SSL context that allows anonymous Diffie Hellman.
std::pair< std::uint16_t, std::uint16_t > ProtocolVersion
Represents a particular version of the peer-to-peer protocol.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:52