Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Registry.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2024, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "etl/Models.hpp"
23#include "etl/RegistryInterface.hpp"
24#include "etl/SystemState.hpp"
25
26#include <xrpl/protocol/TxFormats.h>
27
28#include <concepts>
29#include <cstdint>
30#include <functional>
31#include <string>
32#include <tuple>
33#include <type_traits>
34#include <utility>
35#include <vector>
36
37namespace etl::impl {
38
39template <typename T>
40concept HasLedgerDataHook = requires(T p) {
41 { p.onLedgerData(std::declval<model::LedgerData>()) } -> std::same_as<void>;
42};
43
44template <typename T>
45concept HasInitialDataHook = requires(T p) {
46 { p.onInitialData(std::declval<model::LedgerData>()) } -> std::same_as<void>;
47};
48
49template <typename T>
50concept HasTransactionHook = requires(T p) {
51 { p.onTransaction(uint32_t{}, std::declval<model::Transaction>()) } -> std::same_as<void>;
52};
53
54template <typename T>
55concept HasObjectHook = requires(T p) {
56 { p.onObject(uint32_t{}, std::declval<model::Object>()) } -> std::same_as<void>;
57};
58
59template <typename T>
60concept HasInitialTransactionHook = requires(T p) {
61 { p.onInitialTransaction(uint32_t{}, std::declval<model::Transaction>()) } -> std::same_as<void>;
62};
63
64template <typename T>
65concept HasInitialObjectsHook = requires(T p) {
66 { p.onInitialObjects(uint32_t{}, std::declval<std::vector<model::Object>>(), std::string{}) } -> std::same_as<void>;
67};
68
69template <typename T>
70concept HasInitialObjectHook = requires(T p) {
71 { p.onInitialObject(uint32_t{}, std::declval<model::Object>()) } -> std::same_as<void>;
72};
73
74template <typename T>
75concept ContainsSpec = std::decay_t<T>::spec::kSPEC_TAG;
76
77template <typename T>
81
82template <typename T>
86
87template <typename T>
89
90template <SomeExtension... Ps>
91class Registry : public RegistryInterface {
92 std::reference_wrapper<SystemState const> state_;
93 std::tuple<Ps...> store_;
94
95 static_assert(
97 "Spec must be specified when 'onTransaction' function exists."
98 );
99
100 static_assert(
102 "Spec must be specified when 'onInitialTransaction' function exists."
103 );
104
105public:
106 explicit constexpr Registry(SystemState const& state, SomeExtension auto&&... exts)
107 requires(std::is_same_v<std::decay_t<decltype(exts)>, std::decay_t<Ps>> and ...)
108 : state_{state}, store_(std::forward<Ps>(exts)...)
109 {
110 }
111
112 ~Registry() override = default;
113 Registry(Registry const&) = delete;
114 Registry(Registry&&) = default;
115 Registry&
116 operator=(Registry const&) = delete;
117 Registry&
118 operator=(Registry&&) = default;
119
120 constexpr void
122 {
123 // send entire batch of data at once
124 {
125 auto const expand = [&](auto& p) {
126 if constexpr (requires { p.onLedgerData(data); })
127 executeIfAllowed(p, [&data](auto& p) { p.onLedgerData(data); });
128 };
129
130 std::apply([&expand](auto&&... xs) { (expand(xs), ...); }, store_);
131 }
132
133 // send filtered transactions
134 {
135 auto const expand = [&]<typename P>(P& p, model::Transaction const& t) {
136 if constexpr (requires { p.onTransaction(data.seq, t); }) {
137 if (std::decay_t<P>::spec::wants(t.type))
138 executeIfAllowed(p, [&data, &t](auto& p) { p.onTransaction(data.seq, t); });
139 }
140 };
141
142 for (auto const& t : data.transactions) {
143 std::apply([&expand, &t](auto&&... xs) { (expand(xs, t), ...); }, store_);
144 }
145 }
146
147 // send per object path
148 {
149 auto const expand = [&]<typename P>(P&& p, model::Object const& o) {
150 if constexpr (requires { p.onObject(data.seq, o); })
151 executeIfAllowed(p, [&data, &o](auto& p) { p.onObject(data.seq, o); });
152 };
153
154 for (auto const& obj : data.objects) {
155 std::apply([&expand, &obj](auto&&... xs) { (expand(xs, obj), ...); }, store_);
156 }
157 }
158 }
159
160 constexpr void
161 dispatchInitialObjects(uint32_t seq, std::vector<model::Object> const& data, std::string lastKey) override
162 {
163 // send entire vector path
164 {
165 auto const expand = [&](auto&& p) {
166 if constexpr (requires { p.onInitialObjects(seq, data, lastKey); })
167 executeIfAllowed(p, [seq, &data, &lastKey](auto& p) { p.onInitialObjects(seq, data, lastKey); });
168 };
169
170 std::apply([&expand](auto&&... xs) { (expand(xs), ...); }, store_);
171 }
172
173 // send per object path
174 {
175 auto const expand = [&]<typename P>(P&& p, model::Object const& o) {
176 if constexpr (requires { p.onInitialObject(seq, o); })
177 executeIfAllowed(p, [seq, &o](auto& p) { p.onInitialObject(seq, o); });
178 };
179
180 for (auto const& obj : data) {
181 std::apply([&expand, &obj](auto&&... xs) { (expand(xs, obj), ...); }, store_);
182 }
183 }
184 }
185
186 constexpr void
188 {
189 // send entire batch path
190 {
191 auto const expand = [&](auto&& p) {
192 if constexpr (requires { p.onInitialData(data); })
193 executeIfAllowed(p, [&data](auto& p) { p.onInitialData(data); });
194 };
195
196 std::apply([&expand](auto&&... xs) { (expand(xs), ...); }, store_);
197 }
198
199 // send per tx path
200 {
201 auto const expand = [&]<typename P>(P&& p, model::Transaction const& tx) {
202 if constexpr (requires { p.onInitialTransaction(data.seq, tx); }) {
203 if (std::decay_t<P>::spec::wants(tx.type))
204 executeIfAllowed(p, [&data, &tx](auto& p) { p.onInitialTransaction(data.seq, tx); });
205 }
206 };
207
208 for (auto const& tx : data.transactions) {
209 std::apply([&expand, &tx](auto&&... xs) { (expand(xs, tx), ...); }, store_);
210 }
211 }
212 }
213
214private:
215 void
216 executeIfAllowed(auto& p, auto&& fn)
217 {
218 if constexpr (requires { p.allowInReadonly(); }) {
219 if (state_.get().isWriting or p.allowInReadonly())
220 fn(p);
221 } else {
222 if (state_.get().isWriting)
223 fn(p);
224 }
225 }
226};
227
228static auto
229makeRegistry(SystemState const& state, auto&&... exts)
230{
231 return std::make_unique<Registry<std::decay_t<decltype(exts)>...>>(state, std::forward<decltype(exts)>(exts)...);
232}
233
234} // namespace etl::impl
Definition Registry.hpp:91
constexpr void dispatch(model::LedgerData const &data) override
Dispatch an entire ledger diff.
Definition Registry.hpp:121
constexpr void dispatchInitialObjects(uint32_t seq, std::vector< model::Object > const &data, std::string lastKey) override
Dispatch initial objects.
Definition Registry.hpp:161
constexpr void dispatchInitialData(model::LedgerData const &data) override
Dispatch initial ledger data.
Definition Registry.hpp:187
Definition Registry.hpp:75
Definition Registry.hpp:78
Definition Registry.hpp:45
Definition Registry.hpp:70
Definition Registry.hpp:65
Definition Registry.hpp:60
Definition Registry.hpp:40
Definition Registry.hpp:55
Definition Registry.hpp:50
Definition Registry.hpp:83
Definition Registry.hpp:88
This namespace implements the data access layer and related components.
Definition AmendmentCenter.cpp:70
The interface for a registry that can dispatch transactions and objects to extensions.
Definition RegistryInterface.hpp:72
Represents the state of the ETL subsystem.
Definition SystemState.hpp:33
Represents an entire ledger diff worth of transactions and objects.
Definition Models.hpp:143
Represents a single object on the ledger.
Definition Models.hpp:105
Represents a single transaction on the ledger.
Definition Models.hpp:71