@@ -31,6 +31,7 @@ namespace node {
3131using namespace system ;
3232using namespace network ::rpc;
3333using namespace network ::http;
34+ using namespace network ::json;
3435using namespace network ::monad;
3536using namespace std ::placeholders;
3637using namespace boost ::json;
@@ -130,48 +131,99 @@ void protocol_bitcoind_rpc::handle_receive_post(const code& ec,
130131 return ;
131132 }
132133
133- const auto & body = post -> body ();
134- if (!body.contains <rpcin_value>())
134+ // Endpoint accepts only json-rpc posts.
135+ if (!post -> body () .contains <rpcin_value>())
135136 {
136137 send_not_acceptable (*post );
137138 return ;
138139 }
139140
141+ // Get the parsed json-rpc request object.
142+ // v1 or v2 both supported, batch not yet supported.
143+ // v1 null id and v2 missing id implies notification and no response.
144+ const auto & request = post ->body ().get <rpcin_value>().message ;
145+
140146 // The post is saved off during asynchonous handling and used in send_json
141147 // to formulate response headers, isolating handlers from http semantics.
142- set_request ( post );
148+ set_rpc_request (request. jsonrpc , request. id , post );
143149
144- const auto & request = body. get <rpcin_value>(). message ;
150+ // Dispatch the request to subscribers.
145151 if (const auto code = rpc_dispatcher_.notify (request))
146152 stop (code);
147153}
148154
155+ template <typename Object, typename ...Args>
156+ std::string to_hex (const Object& object, size_t size, Args&&... args) NOEXCEPT
157+ {
158+ std::string out (two * size, ' \0 ' );
159+ stream::out::fast sink{ out };
160+ write::base16::fast writer{ sink };
161+ object.to_data (writer, std::forward<Args>(args)...);
162+ BC_ASSERT (writer);
163+ return out;
164+ }
165+
149166// Handlers.
150167// ----------------------------------------------------------------------------
151168// github.com/bitcoin/bitcoin/blob/master/doc/JSON-RPC-interface.md
152169// TODO: precompute size for buffer hints.
153170
154- // {"jsonrpc": "1.0", "id": "curltest", "method": "getbestblockhash", "params": []}
155171bool protocol_bitcoind_rpc::handle_get_best_block_hash (const code& ec,
156172 rpc_interface::get_best_block_hash) NOEXCEPT
157173{
158174 if (stopped (ec))
159175 return false ;
160176
161- const auto & query = archive ();
162- const auto hash = query.get_header_key (query.to_confirmed (
163- query.get_top_confirmed ()));
164-
165- const response_t model{ .result = encode_hash (hash) };
166- send_json (value_from (model), two * system::hash_size);
177+ const auto hash = archive ().get_top_confirmed_hash ();
178+ send_result (encode_hash (hash), two * system::hash_size);
167179 return true ;
168180}
169181
170- // method<"getblock", string_t, optional<0_u32>>{ "blockhash", "verbosity" },
171182bool protocol_bitcoind_rpc::handle_get_block (const code& ec,
172- rpc_interface::get_block, const std::string&, double ) NOEXCEPT
183+ rpc_interface::get_block, const std::string& blockhash,
184+ double verbosity) NOEXCEPT
173185{
174- return !ec;
186+ if (stopped (ec))
187+ return false ;
188+
189+ hash_digest hash{};
190+ if (!decode_hash (hash, blockhash))
191+ {
192+ send_error (error::not_found, blockhash, blockhash.size ());
193+ return true ;
194+ }
195+
196+ constexpr auto witness = true ;
197+ const auto & query = archive ();
198+ const auto link = query.to_header (hash);
199+
200+ if (verbosity == 0.0 )
201+ {
202+ const auto block = query.get_block (link, witness);
203+ if (is_null (block))
204+ {
205+ send_error (error::not_found, blockhash, blockhash.size ());
206+ return true ;
207+ }
208+
209+ send_text (to_hex (*block, block->serialized_size (witness), witness));
210+ return true ;
211+ }
212+
213+ if (verbosity == 1.0 )
214+ {
215+ send_error (error::not_implemented);
216+ return true ;
217+ }
218+
219+ if (verbosity == 2.0 )
220+ {
221+ send_error (error::not_implemented);
222+ return true ;
223+ }
224+
225+ send_error (error::invalid_argument);
226+ return true ;
175227}
176228
177229bool protocol_bitcoind_rpc::handle_get_block_chain_info (const code& ec,
@@ -277,26 +329,94 @@ bool protocol_bitcoind_rpc::handle_verify_tx_out_set(const code& ec,
277329 return !ec;
278330}
279331
280- // private
332+ // Senders
281333// ----------------------------------------------------------------------------
282334
283- // TODO: post-process response for json-rpc version.
284- void protocol_bitcoind_rpc::send_json (boost::json::value&& model,
335+ void protocol_bitcoind_rpc::send_error (const code& ec) NOEXCEPT
336+ {
337+ send_error (ec, two * ec.message ().size ());
338+ }
339+
340+ void protocol_bitcoind_rpc::send_error (const code& ec,
341+ size_t size_hint) NOEXCEPT
342+ {
343+ send_error (ec, {}, size_hint);
344+ }
345+
346+ void protocol_bitcoind_rpc::send_error (const code& ec, value_option&& error,
347+ size_t size_hint) NOEXCEPT
348+ {
349+ BC_ASSERT (stranded ());
350+ send_rpc (response_t
351+ {
352+ .jsonrpc = version_,
353+ .id = id_,
354+ .error = result_t
355+ {
356+ .code = ec.value (),
357+ .message = ec.message (),
358+ .data = std::move (error)
359+ }
360+ }, size_hint);
361+ }
362+
363+ void protocol_bitcoind_rpc::send_text (std::string&& hexidecimal) NOEXCEPT
364+ {
365+ BC_ASSERT (stranded ());
366+ send_result (hexidecimal, hexidecimal.size ());
367+ }
368+
369+ void protocol_bitcoind_rpc::send_result (value_option&& result,
370+ size_t size_hint) NOEXCEPT
371+ {
372+ BC_ASSERT (stranded ());
373+ send_rpc (response_t
374+ {
375+ .jsonrpc = version_,
376+ .id = id_,
377+ .result = std::move (result)
378+ }, size_hint);
379+ }
380+
381+ // private
382+ void protocol_bitcoind_rpc::send_rpc (response_t && model,
285383 size_t size_hint) NOEXCEPT
286384{
287385 BC_ASSERT (stranded ());
288- using namespace network ::monad;
289- const auto request = reset_request ();
290- constexpr auto json = media_type::application_json;
386+ static const auto json = from_media_type (media_type::application_json);
387+ const auto request = reset_rpc_request ();
291388 response response{ status::ok, request->version () };
292389 add_common_headers (response, *request);
293390 add_access_control_headers (response, *request);
294- response.set (field::content_type, from_media_type (json));
295- response.body () = json_value{ std::move (model), size_hint };
391+ response.set (field::content_type, json);
392+ response.body () = rpcout_value
393+ {
394+ network::json::json_value{ .size_hint = size_hint },
395+ std::move (model),
396+ };
296397 response.prepare_payload ();
297398 SEND (std::move (response), handle_complete, _1, error::success);
298399}
299400
401+ // private
402+ void protocol_bitcoind_rpc::set_rpc_request (version version,
403+ const id_option& id, const request_cptr& request) NOEXCEPT
404+ {
405+ BC_ASSERT (stranded ());
406+ id_ = id;
407+ version_ = version;
408+ set_request (request);
409+ }
410+
411+ // private
412+ request_cptr protocol_bitcoind_rpc::reset_rpc_request () NOEXCEPT
413+ {
414+ BC_ASSERT (stranded ());
415+ id_.reset ();
416+ version_ = version::undefined;
417+ return reset_request ();
418+ }
419+
300420BC_POP_WARNING ()
301421BC_POP_WARNING ()
302422BC_POP_WARNING ()
0 commit comments