@@ -32,98 +32,111 @@ using namespace network::rpc;
3232BC_PUSH_WARNING (NO_ARRAY_INDEXING)
3333
3434template <typename Number>
35- Number to_number (const std::string_view& token) THROWS
35+ static bool to_number (Number& out, const std::string_view& token) NOEXCEPT
3636{
37- Number out{};
38- if (token.empty () || token.front () == ' 0' ||
39- !is_ascii_numeric (token) || !deserialize (out, token))
40- throw std::runtime_error (" invalid number" );
41-
42- return out;
37+ return !token.empty () && is_ascii_numeric (token) && token.front () != ' 0' &&
38+ deserialize (out, token);
4339}
4440
45- hash_cptr to_hash (const std::string_view& token) THROWS
41+ static hash_cptr to_hash (const std::string_view& token) NOEXCEPT
4642{
4743 hash_digest out{};
48- if (!decode_hash (out, token))
49- throw std::runtime_error (" invalid hash" );
50-
51- return emplace_shared<const hash_digest>(std::move (out));
44+ return decode_hash (out, token) ?
45+ emplace_shared<const hash_digest>(std::move (out)) : hash_cptr{};
5246}
5347
54- request_t path_to_request (const std::string& url_path) THROWS
48+ code path_to_request (request_t & out, const std::string& path) NOEXCEPT
5549{
5650 // Avoid conflict with node type.
5751 using object_t = network::rpc::object_t ;
5852
5953 // Initialize json-rpc.v2 named params message.
60- request_t request
54+ out = request_t
6155 {
6256 .jsonrpc = version::v2,
6357 .id = null_t {},
6458 .method = {},
6559 .params = object_t {}
6660 };
6761
68- auto & method = request .method ;
69- auto & params = std::get<object_t >(request .params .value ());
70- const auto segments = split (url_path , " /" , false , true );
62+ auto & method = out .method ;
63+ auto & params = std::get<object_t >(out .params .value ());
64+ const auto segments = split (path , " /" , false , true );
7165 if (segments.empty ())
72- throw std::runtime_error ( " empty url path " ) ;
66+ return error::empty_path ;
7367
74- size_t index {};
75- if (!segments[index ].starts_with (' v' ))
76- throw std::runtime_error ( " missing version " ) ;
68+ size_t segment {};
69+ if (!segments[segment ].starts_with (' v' ))
70+ return error::missing_version ;
7771
78- params[" version" ] = to_number<uint8_t >(segments[index++].substr (one));
79- if (index == segments.size ())
80- throw std::runtime_error (" missing target" );
72+ uint8_t version{};
73+ if (!to_number (version, segments[segment++].substr (one)))
74+ return error::invalid_number;
75+
76+ params[" version" ] = version;
77+ if (segment == segments.size ())
78+ return error::missing_target;
8179
8280 // transaction, address, inputs, and outputs are identical excluding names;
8381 // input and output are identical excluding names; block is unique.
84- const auto target = segments[index ++];
82+ const auto target = segments[segment ++];
8583 if (target == " transaction" )
8684 {
87- if (index == segments.size ())
88- throw std::runtime_error (" missing transaction hash" );
85+ if (segment == segments.size ())
86+ return error::missing_hash;
87+
88+ const auto hash = to_hash (segments[segment++]);
89+ if (!hash) return error::invalid_hash;
8990
9091 method = " transaction" ;
91- params[" hash" ] = to_hash (segments[index++]) ;
92+ params[" hash" ] = hash ;
9293 }
9394 else if (target == " address" )
9495 {
95- if (index == segments.size ())
96- throw std::runtime_error (" missing address hash" );
96+ if (segment == segments.size ())
97+ return error::missing_hash;
98+
99+ const auto hash = to_hash (segments[segment++]);
100+ if (!hash) return error::invalid_hash;
97101
98102 method = " address" ;
99- params[" hash" ] = to_hash (segments[index++]) ;
103+ params[" hash" ] = hash ;
100104 }
101105 else if (target == " inputs" )
102106 {
103- if (index == segments.size ())
104- throw std::runtime_error (" missing inputs tx hash" );
107+ if (segment == segments.size ())
108+ return error::missing_hash;
109+
110+ const auto hash = to_hash (segments[segment++]);
111+ if (!hash) return error::invalid_hash;
105112
106113 method = " inputs" ;
107- params[" hash" ] = to_hash (segments[index++]) ;
114+ params[" hash" ] = hash ;
108115 }
109116 else if (target == " outputs" )
110117 {
111- if (index == segments.size ())
112- throw std::runtime_error (" missing outputs tx hash" );
118+ if (segment == segments.size ())
119+ return error::missing_hash;
120+
121+ const auto hash = to_hash (segments[segment++]);
122+ if (!hash) return error::invalid_hash;
113123
114124 method = " outputs" ;
115- params[" hash" ] = to_hash (segments[index++]) ;
125+ params[" hash" ] = hash ;
116126 }
117127 else if (target == " input" )
118128 {
119- if (index == segments.size ())
120- throw std::runtime_error (" missing input tx hash" );
129+ if (segment == segments.size ())
130+ return error::missing_hash;
131+
132+ const auto hash = to_hash (segments[segment++]);
133+ if (!hash) return error::invalid_hash;
121134
122- params[" hash" ] = to_hash (segments[index++]) ;
123- if (index == segments.size ())
124- throw std::runtime_error ( " missing input component " ) ;
135+ params[" hash" ] = hash ;
136+ if (segment == segments.size ())
137+ return error::missing_component ;
125138
126- const auto component = segments[index ++];
139+ const auto component = segments[segment ++];
127140 if (component == " scripts" )
128141 {
129142 method = " input_scripts" ;
@@ -134,33 +147,40 @@ request_t path_to_request(const std::string& url_path) THROWS
134147 }
135148 else
136149 {
137- params[" index" ] = to_number<uint32_t >(component);
138- if (index == segments.size ())
150+ uint32_t index{};
151+ if (!to_number (index, component))
152+ return error::invalid_number;
153+
154+ params[" index" ] = index;
155+ if (segment == segments.size ())
139156 {
140157 method = " input" ;
141158 }
142159 else
143160 {
144- auto subcomponent = segments[index ++];
161+ auto subcomponent = segments[segment ++];
145162 if (subcomponent == " script" )
146163 method = " input_script" ;
147164 else if (subcomponent == " witness" )
148165 method = " input_witness" ;
149166 else
150- throw std::runtime_error ( " unexpected input subcomponent " ) ;
167+ return error::invalid_subcomponent ;
151168 }
152169 }
153170 }
154171 else if (target == " output" )
155172 {
156- if (index == segments.size ())
157- throw std::runtime_error (" missing output tx hash" );
173+ if (segment == segments.size ())
174+ return error::missing_hash;
175+
176+ const auto hash = to_hash (segments[segment++]);
177+ if (!hash) return error::invalid_hash;
158178
159- params[" hash" ] = to_hash (segments[index++]) ;
160- if (index == segments.size ())
161- throw std::runtime_error ( " missing output component " ) ;
179+ params[" hash" ] = hash ;
180+ if (segment == segments.size ())
181+ return error::missing_component ;
162182
163- const auto component = segments[index ++];
183+ const auto component = segments[segment ++];
164184 if (component == " scripts" )
165185 {
166186 method = " output_scripts" ;
@@ -171,82 +191,94 @@ request_t path_to_request(const std::string& url_path) THROWS
171191 }
172192 else
173193 {
174- params[" index" ] = to_number<uint32_t >(component);
175- if (index == segments.size ())
194+ uint32_t index{};
195+ if (!to_number (index, component))
196+ return error::invalid_number;
197+
198+ params[" index" ] = index;
199+ if (segment == segments.size ())
176200 {
177201 method = " output" ;
178202 }
179203 else
180204 {
181- auto subcomponent = segments[index ++];
205+ auto subcomponent = segments[segment ++];
182206 if (subcomponent == " script" )
183207 method = " output_script" ;
184208 else if (subcomponent == " spender" )
185209 method = " output_spender" ;
186210 else
187- throw std::runtime_error ( " unexpected output subcomponent " ) ;
211+ return error::invalid_subcomponent ;
188212 }
189213 }
190214 }
191215 else if (target == " block" )
192216 {
193- if (index == segments.size ())
194- throw std::runtime_error ( " missing block id " ) ;
217+ if (segment == segments.size ())
218+ return error::missing_id_type ;
195219
196- const auto by = segments[index ++];
220+ const auto by = segments[segment ++];
197221 if (by == " hash" )
198222 {
199- if (index == segments.size ())
200- throw std::runtime_error (" missing block hash" );
223+ if (segment == segments.size ())
224+ return error::missing_hash;
225+
226+ const auto hash = to_hash (segments[segment++]);
227+ if (!hash) return error::invalid_hash;
201228
202- params[" hash" ] = to_hash (segments[index++]) ;
203- params[" height" ] = value_t { null_t {} };
229+ params[" hash" ] = hash ;
230+ params[" height" ] = null_t {};
204231 }
205232 else if (by == " height" )
206233 {
207- if (index == segments.size ())
208- throw std::runtime_error ( " missing block height " ) ;
234+ if (segment == segments.size ())
235+ return error::missing_height ;
209236
210- params[" hash" ] = value_t { null_t {} };
211- params[" height" ] = to_number<uint32_t >(segments[index++]);
237+ uint32_t height{};
238+ if (!to_number (height, segments[segment++]))
239+ return error::invalid_number;
240+
241+ params[" hash" ] = null_t {};
242+ params[" height" ] = height;
212243 }
213244 else
214245 {
215- throw std::runtime_error ( " invalid block id " ) ;
246+ return error::invalid_id_type ;
216247 }
217248
218- if (index == segments.size ())
249+ if (segment == segments.size ())
219250 {
220251 method = " block" ;
221252 }
222253 else
223254 {
224- const auto component = segments[index ++];
255+ const auto component = segments[segment ++];
225256 if (component == " header" )
226257 method = " header" ;
227258 else if (component == " filter" )
228259 method = " filter" ;
229260 else if (component == " transactions" )
230261 method = " block_txs" ;
231262 else if (component != " transaction" )
232- throw std::runtime_error (" invalid block component" );
263+ return error::invalid_component;
264+
265+ if (segment == segments.size ())
266+ return error::missing_position;
233267
234- if (index == segments.size ())
235- throw std::runtime_error (" missing tx position" );
268+ uint32_t position{};
269+ if (!to_number (position, segments[segment++]))
270+ return error::invalid_number;
236271
237- params[" position" ] = to_number< uint32_t >(segments[index++]) ;
272+ params[" position" ] = position ;
238273 method = " block_tx" ;
239274 }
240275 }
241276 else
242277 {
243- throw std::runtime_error ( " unknown target " ) ;
278+ return error::invalid_target ;
244279 }
245280
246- if (index != segments.size ())
247- throw std::runtime_error (" extra segments" );
248-
249- return request;
281+ return segment == segments.size () ? error::success : error::extra_segment;
250282}
251283
252284BC_POP_WARNING ()
0 commit comments