OpenCBDC Transaction Processor
Loading...
Searching...
No Matches
http_server.cpp
Go to the documentation of this file.
1// Copyright (c) 2021 MIT Digital Currency Initiative,
2// Federal Reserve Bank of Boston
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include "http_server.hpp"
7
8#include "impl.hpp"
15#include "util/common/hash.hpp"
17
18#include <future>
19
20using namespace cbdc::parsec::agent::runner;
21
23 http_server::http_server(std::unique_ptr<server_type> srv,
24 std::shared_ptr<broker::interface> broker,
25 std::shared_ptr<logging::log> log,
26 const cbdc::parsec::config& cfg)
27 : server_interface(std::move(broker), std::move(log), cfg),
28 m_srv(std::move(srv)) {
29 m_srv->register_handler_callback(
30 [&](const std::string& method,
31 const Json::Value& params,
32 const server_type::result_callback_type& callback) {
33 return request_handler(method, params, callback);
34 });
35 }
36
38 m_log->trace("Agent server shutting down...");
39 m_srv.reset();
40 m_log->trace("Shut down agent server");
41 }
42
43 auto http_server::init() -> bool {
44 return m_srv->init();
45 }
46
47 auto http_server::request_handler(
48 const std::string& method,
49 const Json::Value& params,
50 const server_type::result_callback_type& callback) -> bool {
51 m_log->trace("http_server::request_handler() received request",
52 method);
53
54 auto maybe_handled = handle_supported(method, params, callback);
55 if(maybe_handled.has_value()) {
56 return maybe_handled.value();
57 }
58
59 maybe_handled = handle_static(method, params, callback);
60 if(maybe_handled.has_value()) {
61 return maybe_handled.value();
62 }
63
64 return handle_unsupported(method, params, callback);
65 }
66
67 auto http_server::handle_supported(
68 const std::string& method,
69 const Json::Value& params,
70 const server_type::result_callback_type& callback)
71 -> std::optional<bool> {
72 if(method == "eth_sendRawTransaction") {
73 return handle_send_raw_transaction(params, callback);
74 }
75
76 if(method == "eth_sendTransaction") {
77 return handle_send_transaction(params, callback);
78 }
79
80 if(method == "eth_getTransactionCount") {
81 return handle_get_transaction_count(params, callback);
82 }
83
84 if(method == "eth_call") {
85 return handle_call(params, callback);
86 }
87
88 if(method == "eth_gasPrice") {
89 return handle_gas_price(params, callback);
90 }
91
92 if(method == "eth_getCode") {
93 return handle_get_code(params, callback);
94 }
95
96 if(method == "eth_getBalance") {
97 return handle_get_balance(params, callback);
98 }
99
100 if(method == "eth_accounts") {
101 return handle_accounts(params, callback);
102 }
103
104 if(method == "eth_getTransactionByHash") {
105 return handle_get_transaction_by_hash(params, callback);
106 }
107
108 if(method == "eth_getTransactionReceipt") {
109 return handle_get_transaction_receipt(params, callback);
110 }
111
112 if(method == "eth_getBlockByNumber"
113 || method == "eth_getBlockByHash") {
114 return handle_get_block(params, callback);
115 }
116
117 if(method == "eth_getBlockTransactionCountByHash"
118 || method == "eth_getBlockTransactionCountByNumber") {
119 return handle_get_block_txcount(params, callback);
120 }
121
122 if(method == "eth_getTransactionByBlockHashAndIndex"
123 || method == "eth_getTransactionByBlockNumberAndIndex") {
124 return handle_get_block_tx(params, callback);
125 }
126
127 if(method == "eth_blockNumber") {
128 return handle_block_number(params, callback);
129 }
130
131 if(method == "eth_feeHistory") {
132 return handle_fee_history(params, callback);
133 }
134
135 if(method == "eth_getLogs") {
136 return handle_get_logs(params, callback);
137 }
138
139 if(method == "eth_getStorageAt") {
140 return handle_get_storage_at(params, callback);
141 }
142
143 return std::nullopt;
144 }
145
146 auto http_server::handle_static(
147 const std::string& method,
148 const Json::Value& params,
149 const server_type::result_callback_type& callback)
150 -> std::optional<bool> {
151 if(method == "eth_chainId" || method == "net_version") {
152 return handle_chain_id(params, callback);
153 }
154
155 if(method == "web3_clientVersion") {
156 return handle_client_version(params, callback);
157 }
158
159 if(method == "eth_decodeRawTransaction") {
160 return handle_decode_raw_transaction(params, callback);
161 }
162
163 if(method == "web3_sha3") {
164 return handle_sha3(params, callback);
165 }
166
167 if(method == "eth_estimateGas") {
168 return handle_estimate_gas(params, callback);
169 }
170
171 return std::nullopt;
172 }
173
174 auto http_server::handle_unsupported(
175 const std::string& method,
176 const Json::Value& params,
177 const server_type::result_callback_type& callback) -> bool {
178 if(method == "eth_signTransaction" || method == "eth_sign") {
179 return handle_error(
180 params,
181 callback,
182 error_code::wallet_not_supported,
183 "Wallet support not enabled - sign transactions "
184 "locally before submitting");
185 }
186
187 if(method == "eth_uninstallFilter"
188 || method == "eth_newPendingTransactionFilter"
189 || method == "eth_newFilter" || method == "eth_newBlockFilter"
190 || method == "eth_getFilterLogs"
191 || method == "eth_getFilterChanges") {
192 return handle_error(params,
193 callback,
194 error_code::wallet_not_supported,
195 "OpenCBDC does not support filters");
196 }
197
198 if(method == "eth_getWork" || method == "eth_submitWork"
199 || method == "eth_submitHashrate") {
200 return handle_error(params,
201 callback,
202 error_code::mining_not_supported,
203 "OpenCBDC does not use mining");
204 }
205
206 if(method == "evm_increaseTime") {
207 return handle_error(params,
208 callback,
209 error_code::time_travel_not_supported,
210 "OpenCBDC does not support time travel");
211 }
212
213 if(method == "eth_getCompilers" || method == "eth_compileSolidity"
214 || method == "eth_compileLLL" || method == "eth_compileSerpent") {
215 return handle_error(params,
216 callback,
217 error_code::compiler_not_supported,
218 "OpenCBDC does not provide compiler support - "
219 "compile contracts locally before submitting");
220 }
221
222 if(method == "eth_coinbase") {
223 return handle_error(params,
224 callback,
225 error_code::coinbase_not_supported,
226 "Coinbase payouts are not used in OpenCBDC");
227 }
228
229 if(method == "eth_getUncleByBlockHashAndIndex"
230 || method == "eth_getUncleByBlockNumberAndIndex") {
231 // There are no uncle blocks in OpenCBDC ever
232 return handle_error(params,
233 callback,
234 error_code::uncles_not_supported,
235 "Uncle block not found");
236 }
237
238 if(method == "eth_getUncleCountByBlockHash"
239 || method == "eth_getUncleCountByBlockNumber"
240 || method == "eth_hashrate") {
241 // There are no uncle blocks in OpenCBDC ever
242 return handle_number(params, callback, 0);
243 }
244
245 if(method == "eth_mining") {
246 return handle_boolean(params, callback, false);
247 }
248
249 if(method == "eth_syncing") {
250 return handle_boolean(params, callback, false);
251 }
252
253 if(method == "net_listening") {
254 return handle_boolean(params, callback, false);
255 }
256
257 if(method == "net_peerCount") {
258 return handle_number(params, callback, 1);
259 }
260
261 m_log->warn("Unknown method", method);
262 return handle_error(params,
263 callback,
264 error_code::unknown_method,
265 "Unknown method: " + method);
266 }
267
268 auto http_server::handle_decode_raw_transaction(
269 Json::Value params,
270 const server_type::result_callback_type& callback) -> bool {
271 auto maybe_tx = raw_tx_from_json(params[0]);
272 if(!maybe_tx.has_value()) {
273 m_log->warn("Unable to deserialize transaction");
274 return false;
275 }
276 auto& tx = maybe_tx.value();
277 auto ret = Json::Value();
278 ret["result"] = tx_to_json(*tx, m_secp);
279 callback(ret);
280 return true;
281 }
282
283 auto http_server::handle_send_raw_transaction(
284 Json::Value params,
285 const server_type::result_callback_type& callback) -> bool {
286 auto res_cb = std::function<void(interface::exec_return_type)>();
287
288 auto maybe_tx = raw_tx_from_json(params[0]);
289 if(!maybe_tx.has_value()) {
290 m_log->warn("Unable to deserialize transaction");
291 return false;
292 }
293 auto& tx = maybe_tx.value();
294 auto runner_params = make_buffer(*tx);
295
296 return exec_tx(callback,
298 runner_params,
299 false,
300 [callback, tx](const interface::exec_return_type&) {
301 auto txid = cbdc::make_buffer(tx_id(*tx));
302 auto ret = Json::Value();
303 ret["result"] = "0x" + txid.to_hex();
304 callback(ret);
305 });
306 }
307
308 auto http_server::handle_fee_history(
309 Json::Value params,
310 const server_type::result_callback_type& callback) -> bool {
311 auto ret = Json::Value();
312
313 if(!params.isArray() || params.size() < 3 || !params[0].isString()
314 || !params[1].isString() || !params[2].isArray()) {
315 m_log->warn("Invalid parameters to feeHistory");
316 return false;
317 }
318
319 auto blocks_str = params[0].asString();
320 uint64_t blocks = 0;
321 auto end_block_str = params[1].asString();
322 uint64_t end_block = 0;
323 if(end_block_str == "latest" || end_block_str == "pending") {
324 end_block = m_broker->highest_ticket();
325 } else {
326 auto maybe_block = uint256be_from_json(params[1]);
327 if(!maybe_block) {
328 ret["error"] = Json::Value();
329 ret["error"]["code"] = error_code::invalid_block_identifier;
330 ret["error"]["message"] = "Invalid block identifier";
331 callback(ret);
332 return true;
333 }
334 end_block = to_uint64(maybe_block.value());
335 }
336 blocks = std::stoull(blocks_str);
337 if(blocks > end_block) {
338 blocks = end_block;
339 }
340 ret["result"] = Json::Value();
341 ret["result"]["oldestBlock"]
342 = to_hex_trimmed(evmc::uint256be(end_block - blocks));
343 ret["result"]["reward"] = Json::Value(Json::arrayValue);
344 ret["result"]["baseFeePerGas"] = Json::Value(Json::arrayValue);
345 ret["result"]["gasUsedRatio"] = Json::Value(Json::arrayValue);
346 for(uint64_t i = 0; i < blocks; i++) {
347 auto rwd = Json::Value(Json::arrayValue);
348 for(Json::ArrayIndex j = 0; j < params[2].size(); j++) {
349 rwd.append("0x0");
350 }
351 ret["result"]["reward"].append(rwd);
352 ret["result"]["baseFeePerGas"].append("0x0");
353 ret["result"]["gasUsedRatio"].append(0.0);
354 }
355 ret["result"]["baseFeePerGas"].append("0x0");
356 callback(ret);
357 return true;
358 }
359
360 auto http_server::handle_get_transaction_count(
361 Json::Value params,
362 const server_type::result_callback_type& callback) -> bool {
363 if(!params.isArray() || params.empty() || !params[0].isString()) {
364 m_log->warn("Invalid parameters to getTransactionCount");
365 return false;
366 }
367
368 auto params_str = params[0].asString();
369 auto maybe_runner_params
370 = cbdc::buffer::from_hex(params_str.substr(2));
371 if(!maybe_runner_params.has_value()) {
372 m_log->warn("Unable to decode params", params_str);
373 return false;
374 }
375 auto runner_params = std::move(maybe_runner_params.value());
376 return exec_tx(
377 callback,
379 runner_params,
380 true,
381 [callback, runner_params](interface::exec_return_type res) {
382 auto ret = Json::Value();
383
384 auto& updates = std::get<return_type>(res);
385 auto it = updates.find(runner_params);
386
387 if(it == updates.end() || it->second.size() == 0) {
388 // For accounts that don't exist yet, return 1
389 ret["result"] = to_hex_trimmed(evmc::uint256be(1));
390 callback(ret);
391 return;
392 }
393
394 auto maybe_acc
396 if(!maybe_acc.has_value()) {
397 ret["error"] = Json::Value();
398 ret["error"]["code"] = error_code::internal_error;
399 ret["error"]["message"] = "Internal error";
400 callback(ret);
401 return;
402 }
403
404 auto& acc = maybe_acc.value();
405
406 auto tx_count = acc.m_nonce + evmc::uint256be(1);
407 ret["result"] = to_hex_trimmed(tx_count);
408 callback(ret);
409 });
410 }
411
412 auto http_server::handle_get_balance(
413 Json::Value params,
414 const server_type::result_callback_type& callback) -> bool {
415 if(!params.isArray() || params.empty() || !params[0].isString()) {
416 m_log->warn("Invalid parameters to getBalance");
417 return false;
418 }
419
420 auto params_str = params[0].asString();
421 auto maybe_runner_params
422 = cbdc::buffer::from_hex(params_str.substr(2));
423 if(!maybe_runner_params.has_value()) {
424 m_log->warn("Unable to decode params", params_str);
425 return false;
426 }
427 auto runner_params = std::move(maybe_runner_params.value());
428 return exec_tx(
429 callback,
431 runner_params,
432 true,
433 [callback, runner_params](interface::exec_return_type res) {
434 auto ret = Json::Value();
435 auto& updates = std::get<return_type>(res);
436 auto it = updates.find(runner_params);
437 if(it == updates.end() || it->second.size() == 0) {
438 // Return 0 for non-existent accounts
439 ret["result"] = "0x0";
440 callback(ret);
441 return;
442 }
443
444 auto maybe_acc
446 if(!maybe_acc.has_value()) {
447 ret["error"] = Json::Value();
448 ret["error"]["code"] = error_code::internal_error;
449 ret["error"]["message"] = "Internal error";
450 callback(ret);
451 return;
452 }
453
454 auto& acc = maybe_acc.value();
455 ret["result"] = to_hex_trimmed(acc.m_balance);
456 callback(ret);
457 });
458 }
459
460 auto http_server::handle_get_storage_at(
461 Json::Value params,
462 const server_type::result_callback_type& callback) -> bool {
463 if(!params.isArray() || params.empty() || !params[0].isString()
464 || !params[1].isString()) {
465 m_log->warn("Invalid parameters to getBalance");
466 return false;
467 }
468
469 auto maybe_addr = address_from_json(params[0]);
470 if(!maybe_addr.has_value()) {
471 m_log->warn("Unable to decode params");
472 return false;
473 }
474 auto key_str = params[1].asString();
475 auto maybe_key = from_hex<evmc::bytes32>(key_str);
476 if(!maybe_key.has_value()) {
477 m_log->warn("Unable to decode params", key_str);
478 return false;
479 }
480
481 auto runner_params = cbdc::make_buffer(
482 storage_key{maybe_addr.value(), maybe_key.value()});
483 return exec_tx(
484 callback,
486 runner_params,
487 true,
488 [callback, runner_params](interface::exec_return_type res) {
489 auto ret = Json::Value();
490 auto& updates = std::get<return_type>(res);
491 auto it = updates.find(runner_params);
492 if(it == updates.end() || it->second.size() == 0) {
493 // Return empty for non-existent data
494 ret["result"] = "0x";
495 callback(ret);
496 return;
497 }
498
499 ret["result"] = "0x" + it->second.to_hex();
500 callback(ret);
501 });
502 }
503
504 auto http_server::handle_get_transaction_by_hash(
505 Json::Value params,
506 const server_type::result_callback_type& callback) -> bool {
507 if(!params.isArray() || params.empty() || !params[0].isString()) {
508 m_log->warn("Invalid parameters to getTransactionByHash");
509 return false;
510 }
511 auto params_str = params[0].asString();
512 auto maybe_runner_params
513 = cbdc::buffer::from_hex(params_str.substr(2));
514 if(!maybe_runner_params.has_value()) {
515 m_log->warn("Unable to decode params", params_str);
516 return false;
517 }
518 auto runner_params = std::move(maybe_runner_params.value());
519 return exec_tx(
520 callback,
522 runner_params,
523 true,
524 [callback, runner_params, this](interface::exec_return_type res) {
525 auto ret = Json::Value();
526 auto& updates = std::get<return_type>(res);
527 auto it = updates.find(runner_params);
528 if(it == updates.end() || it->second.size() == 0) {
529 ret["error"] = Json::Value();
530 ret["error"]["code"] = error_code::not_found;
531 ret["error"]["message"] = "Transaction not found";
532 callback(ret);
533 return;
534 }
535
536 auto maybe_tx
538 if(!maybe_tx.has_value()) {
539 ret["error"] = Json::Value();
540 ret["error"]["code"] = error_code::internal_error;
541 ret["error"]["message"] = "Internal error";
542 callback(ret);
543 return;
544 }
545
546 auto& tx_rcpt = maybe_tx.value();
547 auto json_tx = tx_to_json(tx_rcpt.m_tx, m_secp);
548
549 // Append block data
550 auto block_num = evmc::uint256be(tx_rcpt.m_ticket_number);
551 json_tx["blockHash"] = "0x" + to_hex(block_num);
552 json_tx["blockNumber"] = to_hex_trimmed(block_num);
553 json_tx["transactionIndex"] = "0x0";
554
555 ret["result"] = json_tx;
556 callback(ret);
557 });
558 }
559
560 auto http_server::extract_evm_log_query_addresses(
561 Json::Value params,
562 const server_type::result_callback_type& callback,
563 evm_log_query& qry) -> bool {
564 auto parseError = false;
565 if(params[0]["address"].isString()) {
566 auto maybe_addr = address_from_json(params[0]["address"]);
567 if(maybe_addr) {
568 qry.m_addresses.push_back(maybe_addr.value());
569 } else {
570 parseError = true;
571 }
572 } else if(params[0]["address"].isArray()) {
573 for(auto& val : params[0]["address"]) {
574 auto maybe_addr = address_from_json(val);
575 if(maybe_addr) {
576 qry.m_addresses.push_back(maybe_addr.value());
577 } else {
578 parseError = true;
579 }
580 }
581 }
582
583 if(qry.m_addresses.empty() || parseError) {
584 auto ret = Json::Value();
585 ret["error"] = Json::Value();
586 ret["error"]["code"] = error_code::invalid_address;
587 ret["error"]["message"]
588 = "Address(es) in your query are either absent or invalid";
589 callback(ret);
590 return false;
591 }
592
593 return true;
594 }
595
596 auto http_server::extract_evm_log_query_topics(
597 Json::Value params,
598 const server_type::result_callback_type& callback,
599 evm_log_query& qry) -> bool {
600 auto parseError = false;
601 if(params[0]["topics"].isArray()) {
602 for(auto& val : params[0]["topics"]) {
603 auto maybe_topic = from_hex<evmc::bytes32>(val.asString());
604 if(maybe_topic) {
605 qry.m_topics.push_back(maybe_topic.value());
606 } else {
607 parseError = true;
608 }
609 }
610 }
611
612 if(qry.m_topics.empty() || parseError) {
613 auto ret = Json::Value();
614 ret["error"] = Json::Value();
615 ret["error"]["code"] = error_code::invalid_topic;
616 ret["error"]["message"]
617 = "Topic(s) in your query are either absent or invalid";
618 callback(ret);
619 return false;
620 }
621
622 return true;
623 }
624
625 auto http_server::extract_evm_log_query_block(
626 Json::Value params,
627 const server_type::result_callback_type& callback,
628 evm_log_query& qry) -> bool {
629 auto ret = Json::Value();
630
631 if(params[0]["blockhash"].isString()) {
632 auto maybe_block_num
633 = uint256be_from_hex(params[0]["blockhash"].asString());
634 if(!maybe_block_num) {
635 m_log->warn("Invalid blockNumber / hash parameter");
636 // return error to user through callback
637 ret["error"] = Json::Value();
638 ret["error"]["code"] = error_code::invalid_block_parameter;
639 ret["error"]["message"]
640 = "Invalid blockNumber / hash parameter";
641 callback(ret);
642 return false;
643 }
644 qry.m_from_block = to_uint64(maybe_block_num.value());
645 qry.m_to_block = qry.m_from_block;
646 } else if(params[0]["fromBlock"].isString()
647 && params[0]["toBlock"].isString()) {
648 auto highest_ticket_number = m_broker->highest_ticket();
649 if(params[0]["fromBlock"].asString() == "latest") {
650 qry.m_from_block = highest_ticket_number;
651 } else {
652 auto maybe_block_num
653 = uint256be_from_hex(params[0]["fromBlock"].asString());
654 if(!maybe_block_num) {
655 m_log->warn("Invalid fromBlock parameter");
656 ret["error"] = Json::Value();
657 ret["error"]["code"] = error_code::invalid_block_parameter;
658 ret["error"]["message"] = "Invalid fromBlock parameter";
659 callback(ret);
660 return false;
661 }
662 qry.m_from_block = to_uint64(maybe_block_num.value());
663 }
664
665 if(params[0]["toBlock"].asString() == "latest") {
666 qry.m_to_block = highest_ticket_number;
667 } else {
668 auto maybe_block_num
669 = uint256be_from_hex(params[0]["toBlock"].asString());
670 if(!maybe_block_num) {
671 m_log->warn("Invalid toBlock parameter");
672 ret["error"] = Json::Value();
673 ret["error"]["code"] = error_code::invalid_block_parameter;
674 ret["error"]["message"] = "Invalid toBlock parameter";
675 callback(ret);
676 return false;
677 }
678 qry.m_to_block = to_uint64(maybe_block_num.value());
679 }
680 } else {
681 ret["error"] = Json::Value();
682 ret["error"]["code"] = error_code::invalid_block_parameter;
683 ret["error"]["message"]
684 = "from/toBlock or blockHash parameter missing";
685 callback(ret);
686 return false;
687 }
688
689 auto block_count = static_cast<int64_t>(qry.m_to_block)
690 - static_cast<int64_t>(qry.m_from_block);
691
692 if(block_count < 0) {
693 ret["error"] = Json::Value();
694 ret["error"]["code"] = error_code::from_block_after_to;
695 ret["error"]["message"] = "From block cannot be after to block";
696 callback(ret);
697 return false;
698 }
699
700 auto uint_block_count = static_cast<uint64_t>(block_count);
701
702 constexpr auto max_block_count = 100;
703 if(uint_block_count * qry.m_addresses.size() > max_block_count) {
704 ret["error"] = Json::Value();
705 ret["error"]["code"] = error_code::block_range_too_large;
706 ret["error"]["message"] = "The product of address count and block "
707 "range in your query cannot exceed 100";
708 callback(ret);
709 return false;
710 }
711
712 return true;
713 }
714
715 auto http_server::parse_evm_log_query(
716 const Json::Value& params,
717 const server_type::result_callback_type& callback)
718 -> std::optional<parsec::agent::runner::evm_log_query> {
719 evm_log_query qry;
720
721 auto success = extract_evm_log_query_addresses(params, callback, qry);
722 if(!success) {
723 return std::nullopt;
724 }
725
726 success = extract_evm_log_query_topics(params, callback, qry);
727 if(!success) {
728 return std::nullopt;
729 }
730
731 success = extract_evm_log_query_block(params, callback, qry);
732 if(!success) {
733 return std::nullopt;
734 }
735
736 return qry;
737 }
738
739 void http_server::handle_get_logs_result(
740 const server_type::result_callback_type& callback,
741 const cbdc::buffer& runner_params,
742 const runner::evm_log_query& qry,
744 auto ret = Json::Value();
745 auto& updates = std::get<return_type>(res);
746 auto it = updates.find(runner_params);
747 if(it == updates.end() || it->second.size() == 0) {
748 ret["error"] = Json::Value();
749 ret["error"]["code"] = error_code::not_found;
750 ret["error"]["message"] = "Logs not found";
751 callback(ret);
752 return;
753 }
754
755 auto maybe_logs
757 if(!maybe_logs.has_value()) {
758 ret["error"] = Json::Value();
759 ret["error"]["code"] = error_code::internal_error;
760 ret["error"]["message"] = "Internal error";
761 callback(ret);
762 return;
763 }
764
765 auto& logs = maybe_logs.value();
766 ret["result"] = Json::Value(Json::arrayValue);
767 for(auto& log_idx : logs) {
768 for(auto& log : log_idx.m_logs) {
769 auto match = false;
770 for(auto& have_topic : log.m_topics) {
771 for(const auto& want_topic : qry.m_topics) {
772 if(have_topic == want_topic) {
773 match = true;
774 break;
775 }
776 }
777 if(match) {
778 break;
779 }
780 }
781 if(match) {
782 ret["result"].append(
783 tx_log_to_json(log,
784 log_idx.m_ticket_number,
785 log_idx.m_txid));
786 }
787 }
788 }
789 callback(ret);
790 }
791
792 auto http_server::handle_get_logs(
793 Json::Value params,
794 const server_type::result_callback_type& callback) -> bool {
795 if(!params.isArray() || params.empty() || !params[0].isObject()) {
796 m_log->warn("Invalid parameters to getLogs");
797 auto ret = Json::Value();
798 ret["error"] = Json::Value();
799 // TODO: Is this the correct error code?
800 ret["error"]["code"] = error_code::invalid_block_parameter;
801 ret["error"]["message"] = "Invalid parameters to getLogs";
802 callback(ret);
803 return false;
804 }
805
806 auto maybe_qry = parse_evm_log_query(params, callback);
807 if(!maybe_qry) {
808 // parse_evm_log_query has already reported the error back to the
809 // client
810 return true;
811 }
812 auto qry = maybe_qry.value();
813 auto runner_params = cbdc::make_buffer(qry);
814 return exec_tx(
815 callback,
817 runner_params,
818 true,
819 [callback, runner_params, qry](interface::exec_return_type res) {
820 handle_get_logs_result(callback,
821 runner_params,
822 qry,
823 std::move(res));
824 });
825 }
826
827 auto http_server::handle_get_transaction_receipt(
828 Json::Value params,
829 const server_type::result_callback_type& callback) -> bool {
830 if(!params.isArray() || params.empty() || !params[0].isString()) {
831 m_log->warn("Invalid parameters to getTransactionReceipt");
832 auto ret = Json::Value();
833 ret["error"] = Json::Value();
834 ret["error"]["code"] = error_code::invalid_block_parameter;
835 ret["error"]["message"]
836 = "Invalid parameters to getTransactionReceipt";
837 callback(ret);
838 return false;
839 }
840 auto params_str = params[0].asString();
841 auto maybe_runner_params
842 = cbdc::buffer::from_hex(params_str.substr(2));
843 if(!maybe_runner_params.has_value()) {
844 m_log->warn("Unable to decode params", params_str);
845 return false;
846 }
847 auto runner_params = std::move(maybe_runner_params.value());
848 return exec_tx(
849 callback,
851 runner_params,
852 true,
853 [callback, runner_params, this](interface::exec_return_type res) {
854 auto ret = Json::Value();
855 auto& updates = std::get<return_type>(res);
856 auto it = updates.find(runner_params);
857 if(it == updates.end() || it->second.size() == 0) {
858 ret["error"] = Json::Value();
859 ret["error"]["code"] = error_code::not_found;
860 ret["error"]["message"] = "Transaction not found";
861 callback(ret);
862 return;
863 }
864
865 auto maybe_rcpt
867 if(!maybe_rcpt.has_value()) {
868 ret["error"] = Json::Value();
869 ret["error"]["code"] = error_code::internal_error;
870 ret["error"]["message"] = "Internal error";
871 callback(ret);
872 return;
873 }
874
875 auto& rcpt = maybe_rcpt.value();
876
877 ret["result"] = tx_receipt_to_json(rcpt, m_secp);
878 callback(ret);
879 });
880 }
881
882 auto http_server::handle_get_code(
883 Json::Value params,
884 const server_type::result_callback_type& callback) -> bool {
885 if(!params.isArray() || params.empty() || !params[0].isString()) {
886 m_log->warn("Invalid parameters to getCode");
887 auto ret = Json::Value();
888 ret["error"] = Json::Value();
889 ret["error"]["code"] = error_code::invalid_block_parameter;
890 ret["error"]["message"] = "Invalid parameters to getCode";
891 callback(ret);
892 return false;
893 }
894
895 auto params_str = params[0].asString();
896 auto maybe_runner_params
897 = cbdc::buffer::from_hex(params_str.substr(2));
898 if(!maybe_runner_params.has_value()) {
899 m_log->warn("Unable to decode params", params_str);
900 auto ret = Json::Value();
901 ret["error"] = Json::Value();
902 ret["error"]["code"] = error_code::execution_error;
903 ret["error"]["message"]
904 = "Unable to decode getCode parameters: " + params_str;
905 callback(ret);
906 return false;
907 }
908 auto runner_params = std::move(maybe_runner_params.value());
909 return exec_tx(
910 callback,
912 runner_params,
913 true,
914 [callback, runner_params](interface::exec_return_type res) {
915 auto ret = Json::Value();
916 auto& updates = std::get<return_type>(res);
917 auto it = updates.find(runner_params);
918 if(it == updates.end() || it->second.size() == 0) {
919 // Return empty buffer when code not found
920 ret["result"] = "0x";
921 callback(ret);
922 return;
923 }
924 ret["result"] = "0x" + it->second.to_hex();
925 callback(ret);
926 });
927 }
928
929 auto http_server::handle_chain_id(
930 const Json::Value& /*params*/,
931 const server_type::result_callback_type& callback) -> bool {
932 auto ret = Json::Value();
933 ret["result"] = to_hex_trimmed(evmc::uint256be(opencbdc_chain_id));
934 callback(ret);
935 return true;
936 }
937
938 auto http_server::handle_block_number(
939 const Json::Value& /*params*/,
940 const server_type::result_callback_type& callback) -> bool {
941 auto highest_ticket_number = m_broker->highest_ticket();
942 auto ret = Json::Value();
943 ret["result"] = to_hex_trimmed(evmc::uint256be(highest_ticket_number));
944 callback(ret);
945 return true;
946 }
947
948 auto http_server::fetch_block(
949 Json::Value params,
950 const server_type::result_callback_type& callback,
951 const std::function<void(interface::exec_return_type, cbdc::buffer)>&
952 res_cb) -> bool {
953 if(!params.isArray() || params.empty() || !params[0].isString()
954 || (params.size() > 1 && !params[1].isBool())) {
955 m_log->warn("Invalid parameters to getBlock", params.size());
956 auto ret = Json::Value();
957 ret["error"] = Json::Value();
958 ret["error"]["code"] = error_code::invalid_block_parameter;
959 ret["error"]["message"] = "Invalid parameters to getBlock (size: "
960 + std::to_string(params.size()) + ")";
961 callback(ret);
962 return false;
963 }
964
965 cbdc::buffer runner_params;
966 if(params[0].asString() == "latest") {
967 runner_params = cbdc::make_buffer(
968 evmc::uint256be(m_broker->highest_ticket()));
969 } else {
970 auto maybe_block_num = uint256be_from_hex(params[0].asString());
971 if(!maybe_block_num) {
972 m_log->warn("Invalid blockNumber / hash parameter");
973 auto ret = Json::Value();
974 ret["error"] = Json::Value();
975 ret["error"]["code"] = error_code::invalid_block_parameter;
976 ret["error"]["message"]
977 = "Invalid blockNumber / hash parameter";
978 callback(ret);
979 return false;
980 }
981 runner_params = cbdc::make_buffer(maybe_block_num.value());
982 }
983
984 return exec_tx(
985 callback,
987 runner_params,
988 true,
989 [res_cb, runner_params](interface::exec_return_type res) {
990 res_cb(std::move(res), runner_params);
991 });
992 }
993
994 auto http_server::handle_get_block(
995 Json::Value params,
996 const server_type::result_callback_type& callback) -> bool {
997 auto include_tx_details = params[1].asBool();
998 return fetch_block(
999 params,
1000 callback,
1001 [this, callback, include_tx_details](
1003 const cbdc::buffer& runner_params) {
1004 auto& updates = std::get<return_type>(res);
1005 auto it = updates.find(runner_params);
1006 auto ret = Json::Value();
1007 if(it == updates.end() || it->second.size() == 0) {
1008 ret["error"] = Json::Value();
1009 ret["error"]["code"] = error_code::not_found;
1010 ret["error"]["message"] = "Data was not found";
1011 callback(ret);
1012 return;
1013 }
1014
1015 auto maybe_pretend_block
1017 if(!maybe_pretend_block) {
1018 ret["error"] = Json::Value();
1019 ret["error"]["code"] = error_code::internal_error;
1020 ret["error"]["message"] = "Internal error";
1021 callback(ret);
1022 return;
1023 }
1024 ret["result"] = Json::Value();
1025 auto blk = maybe_pretend_block.value();
1026 auto tn256 = evmc::uint256be(blk.m_ticket_number);
1027 ret["result"]["number"] = to_hex_trimmed(tn256);
1028 ret["result"]["hash"] = "0x" + to_hex(tn256);
1029 ret["result"]["parentHash"]
1030 = "0x" + to_hex(evmc::uint256be(blk.m_ticket_number - 1));
1031 ret["result"]["gasLimit"] = "0xffffffff";
1032 ret["result"]["gasUsed"] = "0x0";
1033 ret["result"]["baseFeePerGas"] = "0x0";
1034 ret["result"]["miner"]
1035 = "0x0000000000000000000000000000000000000000";
1036 ret["result"]["transactions"] = Json::Value(Json::arrayValue);
1037 ret["result"]["nonce"] = "0x0000000000000000";
1038
1039 auto bloom = cbdc::buffer();
1040 constexpr auto bits_in_32_bytes = 256;
1041 bloom.extend(bits_in_32_bytes);
1042 uint64_t timestamp = 0;
1043 for(auto& tx_rcpt : blk.m_transactions) {
1044 if(tx_rcpt.m_timestamp > timestamp) {
1045 timestamp = tx_rcpt.m_timestamp;
1046 }
1047 for(auto& l : tx_rcpt.m_logs) {
1048 add_to_bloom(bloom, cbdc::make_buffer(l.m_addr));
1049 for(auto& t : l.m_topics) {
1051 }
1052 }
1053 if(include_tx_details) {
1054 auto json_tx = tx_to_json(tx_rcpt.m_tx, m_secp);
1055 json_tx["blockHash"] = "0x" + to_hex(tn256);
1056 json_tx["blockNumber"] = to_hex_trimmed(tn256);
1057 json_tx["transactionIndex"] = "0x0";
1058 ret["result"]["transactions"].append(json_tx);
1059 } else {
1060 ret["result"]["transactions"].append(
1061 "0x" + to_string(tx_id(tx_rcpt.m_tx)));
1062 }
1063 }
1064 ret["result"]["timestamp"]
1065 = to_hex_trimmed(evmc::uint256be(timestamp));
1066 ret["result"]["extraData"] = "0x" + to_hex(evmc::uint256be(0));
1067 ret["result"]["logsBloom"] = bloom.to_hex_prefixed();
1068 // We don't have any uncles ever
1069 ret["result"]["uncles"] = Json::Value(Json::arrayValue);
1070 callback(ret);
1071 });
1072 }
1073
1074 auto http_server::handle_get_block_txcount(
1075 Json::Value params,
1076 const server_type::result_callback_type& callback) -> bool {
1077 return fetch_block(
1078 std::move(params),
1079 callback,
1080 [callback](interface::exec_return_type res,
1081 const cbdc::buffer& runner_params) {
1082 auto& updates = std::get<return_type>(res);
1083 auto it = updates.find(runner_params);
1084 auto ret = Json::Value();
1085 if(it == updates.end() || it->second.size() == 0) {
1086 ret["error"] = Json::Value();
1087 ret["error"]["code"] = error_code::not_found;
1088 ret["error"]["message"] = "Data was not found";
1089 callback(ret);
1090 return;
1091 }
1092
1093 auto maybe_pretend_block
1095 if(!maybe_pretend_block) {
1096 ret["error"] = Json::Value();
1097 ret["error"]["code"] = error_code::internal_error;
1098 ret["error"]["message"] = "Internal error";
1099 callback(ret);
1100 return;
1101 }
1102 auto blk = maybe_pretend_block.value();
1103 ret["result"] = to_hex_trimmed(
1104 evmc::uint256be(blk.m_transactions.size()));
1105 callback(ret);
1106 });
1107 }
1108
1109 auto
1110 http_server::handle_sha3(Json::Value params,
1111 const server_type::result_callback_type& callback)
1112 -> bool {
1113 if(!params.isArray() || params.empty() || !params[0].isString()) {
1114 m_log->warn("Invalid parameters to sha3");
1115 return false;
1116 }
1117
1118 auto maybe_buf = buffer_from_json(params[0]);
1119 if(!maybe_buf) {
1120 m_log->warn("Could not parse argument as buffer");
1121 return false;
1122 }
1123
1124 auto input = maybe_buf.value();
1125 auto sha3 = keccak_data(input.data(), input.size());
1126
1127 auto ret = Json::Value();
1128 ret["result"] = "0x" + cbdc::to_string(sha3);
1129 callback(ret);
1130 return true;
1131 }
1132
1133 auto http_server::handle_error(
1134 const Json::Value& /*params*/,
1135 const server_type::result_callback_type& callback,
1136 int code,
1137 const std::string& message) -> bool {
1138 auto ret = Json::Value();
1139 ret["error"] = Json::Value();
1140 ret["error"]["code"] = code;
1141 ret["error"]["message"] = message;
1142 callback(ret);
1143 return true;
1144 }
1145
1146 auto http_server::handle_number(
1147 const Json::Value& /*params*/,
1148 const server_type::result_callback_type& callback,
1149 uint64_t number) -> bool {
1150 auto ret = Json::Value();
1151 ret["result"] = to_hex_trimmed(evmc::uint256be(number));
1152 callback(ret);
1153 return true;
1154 }
1155
1156 auto http_server::handle_boolean(
1157 const Json::Value& /*params*/,
1158 const server_type::result_callback_type& callback,
1159 bool result) -> bool {
1160 auto ret = Json::Value();
1161 ret["result"] = result;
1162 callback(ret);
1163 return true;
1164 }
1165
1166 auto http_server::handle_get_block_tx(
1167 Json::Value params,
1168 const server_type::result_callback_type& callback) -> bool {
1169 if(!params.isArray() || params.size() < 2 || !params[0].isString()
1170 || !params[1].isString()) {
1171 m_log->warn("Invalid parameters to "
1172 "getTransacionByBlock{Hash/Number}AndIndex");
1173 auto ret = Json::Value();
1174 ret["error"] = Json::Value();
1175 ret["error"]["code"] = error_code::invalid_block_parameter;
1176 ret["error"]["message"]
1177 = "Invalid parameters to "
1178 "getTransacionByBlock{Hash/Number}AndIndex";
1179 callback(ret);
1180 return false;
1181 }
1182
1183 auto shadow_params = Json::Value(Json::arrayValue);
1184 shadow_params.append(params[0]);
1185
1186 return fetch_block(
1187 shadow_params,
1188 callback,
1189 [this, callback, params](interface::exec_return_type res,
1190 const cbdc::buffer& runner_params) {
1191 auto& updates = std::get<return_type>(res);
1192 auto it = updates.find(runner_params);
1193 auto ret = Json::Value();
1194 if(it == updates.end() || it->second.size() == 0) {
1195 ret["error"] = Json::Value();
1196 ret["error"]["code"] = error_code::not_found;
1197 ret["error"]["message"] = "Data was not found";
1198 callback(ret);
1199 return;
1200 }
1201
1202 auto maybe_pretend_block
1204 if(!maybe_pretend_block) {
1205 ret["error"] = Json::Value();
1206 ret["error"]["code"] = error_code::internal_error;
1207 ret["error"]["message"] = "Internal error";
1208 callback(ret);
1209 return;
1210 }
1211
1212 auto maybe_idx256 = uint256be_from_hex(params[1].asString());
1213 if(!maybe_idx256) {
1214 ret["error"] = Json::Value();
1215 ret["error"]["code"]
1216 = error_code::invalid_transaction_index;
1217 ret["error"]["message"]
1218 = "Transaction index was invalid - expect hex format";
1219 callback(ret);
1220 return;
1221 }
1222 auto idx = to_uint64(maybe_idx256.value());
1223 auto blk = maybe_pretend_block.value();
1224 if(blk.m_transactions.size() < idx) {
1225 ret["error"] = Json::Value();
1226 ret["error"]["code"] = error_code::not_found;
1227 ret["error"]["message"] = "Data was not found";
1228 callback(ret);
1229 return;
1230 }
1231
1232 auto json_tx
1233 = tx_to_json(blk.m_transactions[idx].m_tx, m_secp);
1234 auto tn256 = evmc::uint256be(blk.m_ticket_number);
1235 json_tx["blockHash"] = "0x" + to_hex(tn256);
1236 json_tx["blockNumber"] = to_hex_trimmed(tn256);
1237 json_tx["transactionIndex"] = "0x0";
1238 ret["result"] = json_tx;
1239 callback(ret);
1240 });
1241 }
1242
1243 auto http_server::handle_accounts(
1244 const Json::Value& /*params*/,
1245 const server_type::result_callback_type& callback) -> bool {
1246 auto ret = Json::Value();
1247 ret["result"] = Json::Value(Json::arrayValue);
1248 callback(ret);
1249 return true;
1250 }
1251
1252 auto http_server::handle_estimate_gas(
1253 const Json::Value& /*params*/,
1254 const server_type::result_callback_type& callback) -> bool {
1255 auto ret = Json::Value();
1256
1257 // TODO: actually estimate gas
1258 ret["result"] = "0xffffffffff";
1259 callback(ret);
1260 return true;
1261 }
1262
1263 auto http_server::handle_client_version(
1264 const Json::Value& /*params*/,
1265 const server_type::result_callback_type& callback) -> bool {
1266 auto ret = Json::Value();
1267 ret["result"] = "opencbdc/v0.0";
1268 callback(ret);
1269 return true;
1270 }
1271
1272 auto http_server::handle_gas_price(
1273 const Json::Value& /*params*/,
1274 const server_type::result_callback_type& callback) -> bool {
1275 auto ret = Json::Value();
1276 ret["result"] = "0x0";
1277 callback(ret);
1278 return true;
1279 }
1280
1281 auto
1282 http_server::handle_call(Json::Value params,
1283 const server_type::result_callback_type& callback)
1284 -> bool {
1285 if(!params.isArray() || params.empty() || !params[0].isObject()) {
1286 m_log->warn("Parameter to call is invalid");
1287 auto ret = Json::Value();
1288 ret["error"] = Json::Value();
1289 ret["error"]["code"] = error_code::invalid_block_parameter;
1290 ret["error"]["message"] = "Parameter to call is invalid";
1291 callback(ret);
1292 return false;
1293 }
1294
1295 auto maybe_tx = dryrun_tx_from_json(params[0]);
1296 if(!maybe_tx) {
1297 m_log->warn("Parameter is not a valid transaction");
1298 auto ret = Json::Value();
1299 ret["error"] = Json::Value();
1300 ret["error"]["code"] = error_code::invalid_transaction_index;
1301 ret["error"]["message"]
1302 = "Parameter to call is not a valid transaction";
1303 callback(ret);
1304 return false;
1305 }
1306
1307 auto& tx = maybe_tx.value();
1308 auto runner_params = make_buffer(*tx);
1309
1310 return exec_tx(callback,
1312 runner_params,
1313 true,
1314 [callback, tx](interface::exec_return_type res) {
1315 auto ret = Json::Value();
1316 auto txid = cbdc::make_buffer(tx_id(tx->m_tx));
1317
1318 auto& updates = std::get<return_type>(res);
1319 auto it = updates.find(txid);
1320 if(it == updates.end()) {
1321 ret["error"] = Json::Value();
1322 ret["error"]["code"] = error_code::not_found;
1323 ret["error"]["message"] = "Data was not found";
1324 callback(ret);
1325 return;
1326 }
1327
1328 auto maybe_receipt
1330 if(!maybe_receipt) {
1331 ret["error"] = Json::Value();
1332 ret["error"]["code"]
1333 = error_code::internal_error;
1334 ret["error"]["message"] = "Internal error";
1335 callback(ret);
1336 return;
1337 }
1338
1339 auto buf = cbdc::buffer();
1340 buf.extend(maybe_receipt->m_output_data.size());
1341 std::memcpy(buf.data(),
1342 maybe_receipt->m_output_data.data(),
1343 maybe_receipt->m_output_data.size());
1344 ret["result"] = "0x" + buf.to_hex();
1345 callback(ret);
1346 });
1347 }
1348
1349 auto http_server::handle_send_transaction(
1350 Json::Value params,
1351 const server_type::result_callback_type& callback) -> bool {
1352 if(!params.isArray() || params.empty() || !params[0].isObject()) {
1353 m_log->warn("Invalid parameters to sendTransaction");
1354 auto ret = Json::Value();
1355 ret["error"] = Json::Value();
1356 ret["error"]["code"] = error_code::invalid_block_parameter;
1357 ret["error"]["message"] = "Invalid parameters to sendTransaction";
1358 callback(ret);
1359 return false;
1360 }
1361
1362 auto maybe_tx = tx_from_json(params[0]);
1363 if(!maybe_tx) {
1364 m_log->warn("Parameter is not a valid transaction");
1365 auto ret = Json::Value();
1366 ret["error"] = Json::Value();
1367 ret["error"]["code"] = error_code::invalid_transaction_index;
1368 ret["error"]["message"]
1369 = "Parameter to sendTransaction is not a valid transaction";
1370 callback(ret);
1371 return false;
1372 }
1373
1374 auto& tx = maybe_tx.value();
1375 auto runner_params = make_buffer(*tx);
1376 return exec_tx(callback,
1378 runner_params,
1379 false,
1380 [callback, tx](const interface::exec_return_type&) {
1381 auto txid = cbdc::make_buffer(tx_id(*tx));
1382 auto ret = Json::Value();
1383 ret["result"] = "0x" + txid.to_hex();
1384 callback(ret);
1385 });
1386 }
1387
1388 auto http_server::exec_tx(
1389 const server_type::result_callback_type& json_ret_callback,
1391 cbdc::buffer& runner_params,
1392 bool is_readonly_run,
1393 const std::function<void(interface::exec_return_type)>& res_success_cb)
1394 -> bool {
1395 auto function = cbdc::buffer();
1396 function.append(&f_type, sizeof(f_type));
1397 auto id = m_next_id++;
1398
1399 const auto res_cb_for_agent =
1400 [this, id, res_success_cb, json_ret_callback](
1402 const auto success = std::holds_alternative<return_type>(res);
1403 if(success) {
1404 res_success_cb(res);
1405 m_cleanup_queue.push(id);
1406 } else {
1407 // Handle error:
1408 const auto ec = std::get<interface::error_code>(res);
1409
1411 m_retry_queue.push(id);
1412 } else {
1413 auto ret = Json::Value();
1414 ret["error"] = Json::Value();
1415 ret["error"]["code"] = error_code::execution_error
1416 - static_cast<int>(ec);
1417 ret["error"]["message"] = "Execution error";
1418 json_ret_callback(ret);
1419 }
1420 }
1421 };
1422
1423 auto a = [&]() {
1424 auto agent = std::make_shared<impl>(
1425 m_log,
1426 m_cfg,
1428 m_broker,
1429 function,
1430 runner_params,
1431 res_cb_for_agent,
1433 is_readonly_run,
1434 m_secp,
1435 m_threads);
1436 {
1437 std::unique_lock l(m_agents_mut);
1438 m_agents.emplace(id, agent);
1439 }
1440 return agent;
1441 }();
1442 return a->exec();
1443 }
1444}
Buffer to store and retrieve byte data.
Definition buffer.hpp:15
static auto from_hex(const std::string &hex) -> std::optional< cbdc::buffer >
Creates a new buffer from the provided hex string.
Definition buffer.cpp:85
std::variant< return_type, error_code > exec_return_type
Return type from function execution.
@ retry
Transient error, execution should be retried.
~http_server() override
Stops listening for incoming connections, waits for existing connections to drain.
auto init() -> bool override
Starts listening for incoming connections and processing requests.
static constexpr auto initial_lock_type
Initial lock type for the agent to request when retrieving the function key.
Runner factory for agents to intiantiate new runners of a particular type while only worrying about t...
std::function< void(std::optional< Json::Value >)> result_callback_type
Type alias for the callback function for returning response values to the server.
auto tx_to_json(cbdc::parsec::agent::runner::evm_tx &tx, const std::shared_ptr< secp256k1_context > &ctx) -> Json::Value
Encodes the given transaction into a eth-RPC compatible representation in JSON - as Json::Value.
auto raw_tx_from_json(const Json::Value &param) -> std::optional< std::shared_ptr< cbdc::parsec::agent::runner::evm_tx > >
Converts a given Json::Value to an evm_tx.
auto to_hex_trimmed(const evmc::bytes32 &b, const std::string &prefix) -> std::string
auto address_from_json(const Json::Value &addr) -> std::optional< evmc::address >
Converts a given Json::Value to an evmc::address.
evm_runner_function
Commands accepted by the EVM contract runner.
@ get_transaction_receipt
Return the receipt for a transaction.
@ read_account_code
Read the contract code of an account.
@ get_logs
Query the logs for a particular address, block range and topic filter.
@ get_block
Return a pretend block that is based on the ticket number, and the transaction (potentially) correspo...
@ execute_transaction
Execute a normal transaction.
@ read_account_storage
Read a specific key of an account's storage.
@ read_account
Read the metadata of an account.
@ dryrun_transaction
Execute a transaction without applying any changes.
auto tx_log_to_json(cbdc::parsec::agent::runner::evm_log &log, interface::ticket_number_type tn, cbdc::hash_t txid) -> Json::Value
Encodes the given transaction log into a eth-RPC compatible representation in JSON - as Json::Value.
auto tx_receipt_to_json(cbdc::parsec::agent::runner::evm_tx_receipt &rcpt, const std::shared_ptr< secp256k1_context > &ctx) -> Json::Value
Encodes the given transaction receipt into a eth-RPC compatible representation in JSON - as Json::Val...
auto to_hex(const evmc::address &addr) -> std::string
auto buffer_from_json(const Json::Value &val) -> std::optional< cbdc::buffer >
Converts a given Json::Value to a cbdc::buffer.
auto dryrun_tx_from_json(const Json::Value &json, uint64_t chain_id) -> std::optional< std::shared_ptr< cbdc::parsec::agent::runner::evm_dryrun_tx > >
Converts a given Json::Value to an evm_dryrun_tx.
auto uint256be_from_hex(const std::string &hex) -> std::optional< evmc::uint256be >
Generates a uint256be from a hex string.
auto tx_from_json(const Json::Value &json, uint64_t) -> std::optional< std::shared_ptr< cbdc::parsec::agent::runner::evm_tx > >
Converts a given Json::Value to an evm_tx.
auto uint256be_from_json(const Json::Value &val) -> std::optional< evmc::uint256be >
Converts a given Json::Value to an evmc::uint256be.
auto from_hex(const std::string &hex) -> typename std::enable_if_t< std::is_same< T, evmc::bytes32 >::value||std::is_same< T, evmc::address >::value, std::optional< T > >
Parses hexadecimal representation in string format to T.
void add_to_bloom(cbdc::buffer &bloom, const cbdc::buffer &entry)
Adds an entry to a bloom value.
auto to_uint64(const evmc::uint256be &v) -> uint64_t
Converts an uint256be to a uint64_t, ignoring higher order bits.
auto tx_id(const cbdc::parsec::agent::runner::evm_tx &tx, uint64_t chain_id) -> cbdc::hash_t
Calculate ethereum-compatible txid.
auto from_buffer(nuraft::buffer &buf) -> std::optional< T >
Deserialize object of given type from a nuraft::buffer.
@ buffer
A singular RLP value (byte array)
auto keccak_data(const void *data, size_t len) -> hash_t
Calculates the Keccak256 hash of the specified data.
auto to_string(const hash_t &val) -> std::string
Converts a hash to a hexadecimal string.
auto make_buffer(const T &obj) -> std::enable_if_t< std::is_same_v< B, nuraft::ptr< nuraft::buffer > >, nuraft::ptr< nuraft::buffer > >
Serialize object into nuraft::buffer using a cbdc::nuraft_serializer.
Describes the parameters of a query on EVM logs - used to transfer these parameters from the getLogs ...
std::vector< evmc::bytes32 > m_topics
The topics for which logs are queried.
Configuration parameters for a phase two system.