Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
chain_plugin.cpp
Go to the documentation of this file.
18
20
22
24
25#include <boost/signals2/connection.hpp>
26#include <boost/algorithm/string.hpp>
27#include <boost/lexical_cast.hpp>
28#include <boost/filesystem.hpp>
29#include <boost/filesystem/path.hpp>
30
31#include <fc/io/json.hpp>
32#include <fc/variant.hpp>
33#include <signal.h>
34#include <cstdlib>
35
36// reflect chainbase::environment for --print-build-info option
42
43const fc::string deep_mind_logger_name("deep-mind");
45
46namespace sysio {
47
48//declare operator<< and validate funciton for read_mode in the same namespace as read_mode itself
49namespace chain {
50
51std::ostream& operator<<(std::ostream& osm, sysio::chain::db_read_mode m) {
53 osm << "speculative";
54 } else if ( m == sysio::chain::db_read_mode::HEAD ) {
55 osm << "head";
56 } else if ( m == sysio::chain::db_read_mode::READ_ONLY ) { // deprecated
57 osm << "read-only";
59 osm << "irreversible";
60 }
61
62 return osm;
63}
64
65void validate(boost::any& v,
66 const std::vector<std::string>& values,
67 sysio::chain::db_read_mode* /* target_type */,
68 int)
69{
70 using namespace boost::program_options;
71
72 // Make sure no previous assignment to 'v' was made.
73 validators::check_first_occurrence(v);
74
75 // Extract the first string from 'values'. If there is more than
76 // one string, it's an error, and exception will be thrown.
77 std::string const& s = validators::get_single_string(values);
78
79 if ( s == "speculative" ) {
81 } else if ( s == "head" ) {
83 } else if ( s == "read-only" ) {
85 } else if ( s == "irreversible" ) {
87 } else {
88 throw validation_error(validation_error::invalid_option_value);
89 }
90}
91
92std::ostream& operator<<(std::ostream& osm, sysio::chain::validation_mode m) {
94 osm << "full";
95 } else if ( m == sysio::chain::validation_mode::LIGHT ) {
96 osm << "light";
97 }
98
99 return osm;
100}
101
102void validate(boost::any& v,
103 const std::vector<std::string>& values,
104 sysio::chain::validation_mode* /* target_type */,
105 int)
106{
107 using namespace boost::program_options;
108
109 // Make sure no previous assignment to 'v' was made.
110 validators::check_first_occurrence(v);
111
112 // Extract the first string from 'values'. If there is more than
113 // one string, it's an error, and exception will be thrown.
114 std::string const& s = validators::get_single_string(values);
115
116 if ( s == "full" ) {
118 } else if ( s == "light" ) {
120 } else {
121 throw validation_error(validation_error::invalid_option_value);
122 }
123}
124
125}
126
127using namespace sysio;
128using namespace sysio::chain;
129using namespace sysio::chain::config;
130using namespace sysio::chain::plugin_interface;
132using fc::flat_map;
133
134using boost::signals2::scoped_connection;
135
137public:
139 :pre_accepted_block_channel(app().get_channel<channels::pre_accepted_block>())
140 ,accepted_block_header_channel(app().get_channel<channels::accepted_block_header>())
141 ,accepted_block_channel(app().get_channel<channels::accepted_block>())
142 ,irreversible_block_channel(app().get_channel<channels::irreversible_block>())
143 ,accepted_transaction_channel(app().get_channel<channels::accepted_transaction>())
144 ,applied_transaction_channel(app().get_channel<channels::applied_transaction>())
145 ,incoming_block_sync_method(app().get_method<incoming::methods::block_sync>())
146 ,incoming_transaction_async_method(app().get_method<incoming::methods::transaction_async>())
147 {}
148
149 bfs::path blocks_dir;
150 bool readonly = false;
151 flat_map<uint32_t,block_id_type> loaded_checkpoints;
155
156 std::optional<controller::config> chain_config;
157 std::optional<controller> chain;
158 std::optional<genesis_state> genesis;
159 //txn_msg_rate_limits rate_limits;
160 std::optional<vm_type> wasm_runtime;
162 std::optional<bfs::path> snapshot_path;
163
164
165 // retained references to channels for easy publication
172
173 // retained references to methods for easy calling
176
177 // method provider handles
178 methods::get_block_by_number::method_type::handle get_block_by_number_provider;
179 methods::get_block_by_id::method_type::handle get_block_by_id_provider;
180 methods::get_head_block_id::method_type::handle get_head_block_id_provider;
181 methods::get_last_irreversible_block_number::method_type::handle get_last_irreversible_block_number_provider;
182
183 // scoped connections for chain controller
184 std::optional<scoped_connection> pre_accepted_block_connection;
185 std::optional<scoped_connection> accepted_block_header_connection;
186 std::optional<scoped_connection> accepted_block_connection;
187 std::optional<scoped_connection> irreversible_block_connection;
188 std::optional<scoped_connection> accepted_transaction_connection;
189 std::optional<scoped_connection> applied_transaction_connection;
190 std::optional<scoped_connection> block_start_connection;
191
192
193 std::optional<chain_apis::account_query_db> _account_query_db;
195 std::optional<chain_apis::trx_retry_db> _trx_retry_db;
197};
198
206
208
209void chain_plugin::set_program_options(options_description& cli, options_description& cfg)
210{
211 // build wasm_runtime help text
212 std::string wasm_runtime_opt = "Override default WASM runtime (";
213 std::string wasm_runtime_desc;
214 std::string delim;
215#ifdef SYSIO_SYS_VM_JIT_RUNTIME_ENABLED
216 wasm_runtime_opt += " \"sys-vm-jit\"";
217 wasm_runtime_desc += "\"sys-vm-jit\" : A WebAssembly runtime that compiles WebAssembly code to native x86 code prior to execution.\n";
218 delim = ", ";
219#endif
220
221#ifdef SYSIO_SYS_VM_RUNTIME_ENABLED
222 wasm_runtime_opt += delim + "\"sys-vm\"";
223 wasm_runtime_desc += "\"sys-vm\" : A WebAssembly interpreter.\n";
224 delim = ", ";
225#endif
226
227#ifdef SYSIO_SYS_VM_OC_DEVELOPER
228 wasm_runtime_opt += delim + "\"sys-vm-oc\"";
229 wasm_runtime_desc += "\"sys-vm-oc\" : Unsupported. Instead, use one of the other runtimes along with the option enable-sys-vm-oc.\n";
230#endif
231 wasm_runtime_opt += ")\n" + wasm_runtime_desc;
232
233 std::string default_wasm_runtime_str= sysio::chain::wasm_interface::vm_type_string(sysio::chain::config::default_wasm_runtime);
234
235 cfg.add_options()
236 ("blocks-dir", bpo::value<bfs::path>()->default_value("blocks"),
237 "the location of the blocks directory (absolute path or relative to application data dir)")
238 ("protocol-features-dir", bpo::value<bfs::path>()->default_value("protocol_features"),
239 "the location of the protocol_features directory (absolute path or relative to application config dir)")
240 ("checkpoint", bpo::value<vector<string>>()->composing(), "Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints.")
241 ("wasm-runtime", bpo::value<sysio::chain::wasm_interface::vm_type>()->value_name("runtime")->notifier([](const auto& vm){
242#ifndef SYSIO_SYS_VM_OC_DEVELOPER
243 //throwing an exception here (like SYS_ASSERT) is just gobbled up with a "Failed to initialize" error :(
244 if(vm == wasm_interface::vm_type::eos_vm_oc) {
245 elog("SYS VM OC is a tier-up compiler and works in conjunction with the configured base WASM runtime. Enable SYS VM OC via 'sys-vm-oc-enable' option");
246 SYS_ASSERT(false, plugin_exception, "");
247 }
248#endif
249 })->default_value(sysio::chain::config::default_wasm_runtime, default_wasm_runtime_str), wasm_runtime_opt.c_str()
250 )
251 ("profile-account", boost::program_options::value<vector<string>>()->composing(),
252 "The name of an account whose code will be profiled")
253 ("abi-serializer-max-time-ms", bpo::value<uint32_t>()->default_value(config::default_abi_serializer_max_time_us / 1000),
254 "Override default maximum ABI serialization time allowed in ms")
255 ("chain-state-db-size-mb", bpo::value<uint64_t>()->default_value(config::default_state_size / (1024 * 1024)), "Maximum size (in MiB) of the chain state database")
256 ("chain-state-db-guard-size-mb", bpo::value<uint64_t>()->default_value(config::default_state_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the chain state database drops below this size (in MiB).")
257 ("signature-cpu-billable-pct", bpo::value<uint32_t>()->default_value(config::default_sig_cpu_bill_pct / config::percent_1),
258 "Percentage of actual signature recovery cpu to bill. Whole number percentages, e.g. 50 for 50%")
259 ("chain-threads", bpo::value<uint16_t>()->default_value(config::default_controller_thread_pool_size),
260 "Number of worker threads in controller thread pool")
261 ("contracts-console", bpo::bool_switch()->default_value(false),
262 "print contract's output to console")
263 ("deep-mind", bpo::bool_switch()->default_value(false),
264 "print deeper information about chain operations")
265 ("actor-whitelist", boost::program_options::value<vector<string>>()->composing()->multitoken(),
266 "Account added to actor whitelist (may specify multiple times)")
267 ("actor-blacklist", boost::program_options::value<vector<string>>()->composing()->multitoken(),
268 "Account added to actor blacklist (may specify multiple times)")
269 ("contract-whitelist", boost::program_options::value<vector<string>>()->composing()->multitoken(),
270 "Contract account added to contract whitelist (may specify multiple times)")
271 ("contract-blacklist", boost::program_options::value<vector<string>>()->composing()->multitoken(),
272 "Contract account added to contract blacklist (may specify multiple times)")
273 ("action-blacklist", boost::program_options::value<vector<string>>()->composing()->multitoken(),
274 "Action (in the form code::action) added to action blacklist (may specify multiple times)")
275 ("key-blacklist", boost::program_options::value<vector<string>>()->composing()->multitoken(),
276 "Public key added to blacklist of keys that should not be included in authorities (may specify multiple times)")
277 ("sender-bypass-whiteblacklist", boost::program_options::value<vector<string>>()->composing()->multitoken(),
278 "Deferred transactions sent by accounts in this list do not have any of the subjective whitelist/blacklist checks applied to them (may specify multiple times)")
279 ("read-mode", boost::program_options::value<sysio::chain::db_read_mode>()->default_value(sysio::chain::db_read_mode::SPECULATIVE),
280 "Database read mode (\"speculative\", \"head\", \"read-only\", \"irreversible\").\n"
281 "In \"speculative\" mode: database contains state changes by transactions in the blockchain up to the head block as well as some transactions not yet included in the blockchain.\n"
282 "In \"head\" mode: database contains state changes by only transactions in the blockchain up to the head block; transactions received by the node are relayed if valid.\n"
283 "In \"read-only\" mode: (DEPRECATED: see p2p-accept-transactions & api-accept-transactions) database contains state changes by only transactions in the blockchain up to the head block; transactions received via the P2P network are not relayed and transactions cannot be pushed via the chain API.\n"
284 "In \"irreversible\" mode: database contains state changes by only transactions in the blockchain up to the last irreversible block; transactions received via the P2P network are not relayed and transactions cannot be pushed via the chain API.\n"
285 )
286 ( "api-accept-transactions", bpo::value<bool>()->default_value(true), "Allow API transactions to be evaluated and relayed if valid.")
287 ("validation-mode", boost::program_options::value<sysio::chain::validation_mode>()->default_value(sysio::chain::validation_mode::FULL),
288 "Chain validation mode (\"full\" or \"light\").\n"
289 "In \"full\" mode all incoming blocks will be fully validated.\n"
290 "In \"light\" mode all incoming blocks headers will be fully validated; transactions in those validated blocks will be trusted \n")
291 ("disable-ram-billing-notify-checks", bpo::bool_switch()->default_value(false),
292 "Disable the check which subjectively fails a transaction if a contract bills more RAM to another account within the context of a notification handler (i.e. when the receiver is not the code of the action).")
293#ifdef SYSIO_DEVELOPER
294 ("disable-all-subjective-mitigations", bpo::bool_switch()->default_value(false),
295 "Disable all subjective mitigations checks in the entire codebase.")
296#endif
297 ("maximum-variable-signature-length", bpo::value<uint32_t>()->default_value(16384u),
298 "Subjectively limit the maximum length of variable components in a variable legnth signature to this size in bytes")
299 ("trusted-producer", bpo::value<vector<string>>()->composing(), "Indicate a producer whose blocks headers signed by it will be fully validated, but transactions in those validated blocks will be trusted.")
300 ("database-map-mode", bpo::value<chainbase::pinnable_mapped_file::map_mode>()->default_value(chainbase::pinnable_mapped_file::map_mode::mapped),
301 "Database map mode (\"mapped\", \"heap\", or \"locked\").\n"
302 "In \"mapped\" mode database is memory mapped as a file.\n"
303#ifndef _WIN32
304 "In \"heap\" mode database is preloaded in to swappable memory and will use huge pages if available.\n"
305 "In \"locked\" mode database is preloaded, locked in to memory, and will use huge pages if available.\n"
306#endif
307 )
308
309#ifdef SYSIO_SYS_VM_OC_RUNTIME_ENABLED
310 ("sys-vm-oc-cache-size-mb", bpo::value<uint64_t>()->default_value(eosvmoc::config().cache_size / (1024u*1024u)), "Maximum size (in MiB) of the SYS VM OC code cache")
311 ("sys-vm-oc-compile-threads", bpo::value<uint64_t>()->default_value(1u)->notifier([](const auto t) {
312 if(t == 0) {
313 elog("sys-vm-oc-compile-threads must be set to a non-zero value");
314 SYS_ASSERT(false, plugin_exception, "");
315 }
316 }), "Number of threads to use for SYS VM OC tier-up")
317 ("sys-vm-oc-enable", bpo::bool_switch(), "Enable SYS VM OC tier-up runtime")
318#endif
319 ("enable-account-queries", bpo::value<bool>()->default_value(false), "enable queries to find accounts by various metadata.")
320 ("max-nonprivileged-inline-action-size", bpo::value<uint32_t>()->default_value(config::default_max_nonprivileged_inline_action_size), "maximum allowed size (in bytes) of an inline action for a nonprivileged account")
321 ("transaction-retry-max-storage-size-gb", bpo::value<uint64_t>(),
322 "Maximum size (in GiB) allowed to be allocated for the Transaction Retry feature. Setting above 0 enables this feature.")
323 ("transaction-retry-interval-sec", bpo::value<uint32_t>()->default_value(20),
324 "How often, in seconds, to resend an incoming transaction to network if not seen in a block.")
325 ("transaction-retry-max-expiration-sec", bpo::value<uint32_t>()->default_value(120),
326 "Maximum allowed transaction expiration for retry transactions, will retry transactions up to this value.")
327 ("transaction-finality-status-max-storage-size-gb", bpo::value<uint64_t>(),
328 "Maximum size (in GiB) allowed to be allocated for the Transaction Finality Status feature. Setting above 0 enables this feature.")
329 ("transaction-finality-status-success-duration-sec", bpo::value<uint64_t>()->default_value(config::default_max_transaction_finality_status_success_duration_sec),
330 "Duration (in seconds) a successful transaction's Finality Status will remain available from being first identified.")
331 ("transaction-finality-status-failure-duration-sec", bpo::value<uint64_t>()->default_value(config::default_max_transaction_finality_status_failure_duration_sec),
332 "Duration (in seconds) a failed transaction's Finality Status will remain available from being first identified.");
333
335 cfg.add_options()("block-log-retain-blocks", bpo::value<uint32_t>(), "if set, periodically prune the block log to store only configured number of most recent blocks");
336
337
338// TODO: rate limiting
339 /*("per-authorized-account-transaction-msg-rate-limit-time-frame-sec", bpo::value<uint32_t>()->default_value(default_per_auth_account_time_frame_seconds),
340 "The time frame, in seconds, that the per-authorized-account-transaction-msg-rate-limit is imposed over.")
341 ("per-authorized-account-transaction-msg-rate-limit", bpo::value<uint32_t>()->default_value(default_per_auth_account),
342 "Limits the maximum rate of transaction messages that an account is allowed each per-authorized-account-transaction-msg-rate-limit-time-frame-sec.")
343 ("per-code-account-transaction-msg-rate-limit-time-frame-sec", bpo::value<uint32_t>()->default_value(default_per_code_account_time_frame_seconds),
344 "The time frame, in seconds, that the per-code-account-transaction-msg-rate-limit is imposed over.")
345 ("per-code-account-transaction-msg-rate-limit", bpo::value<uint32_t>()->default_value(default_per_code_account),
346 "Limits the maximum rate of transaction messages that an account's code is allowed each per-code-account-transaction-msg-rate-limit-time-frame-sec.")*/
347
348 cli.add_options()
349 ("genesis-json", bpo::value<bfs::path>(), "File to read Genesis State from")
350 ("genesis-timestamp", bpo::value<string>(), "override the initial timestamp in the Genesis State file")
351 ("print-genesis-json", bpo::bool_switch()->default_value(false),
352 "extract genesis_state from blocks.log as JSON, print to console, and exit")
353 ("extract-genesis-json", bpo::value<bfs::path>(),
354 "extract genesis_state from blocks.log as JSON, write into specified file, and exit")
355 ("print-build-info", bpo::bool_switch()->default_value(false),
356 "print build environment information to console as JSON and exit")
357 ("extract-build-info", bpo::value<bfs::path>(),
358 "extract build environment information as JSON, write into specified file, and exit")
359 ("force-all-checks", bpo::bool_switch()->default_value(false),
360 "do not skip any validation checks while replaying blocks (useful for replaying blocks from untrusted source)")
361 ("disable-replay-opts", bpo::bool_switch()->default_value(false),
362 "disable optimizations that specifically target replay")
363 ("replay-blockchain", bpo::bool_switch()->default_value(false),
364 "clear chain state database and replay all blocks")
365 ("hard-replay-blockchain", bpo::bool_switch()->default_value(false),
366 "clear chain state database, recover as many blocks as possible from the block log, and then replay those blocks")
367 ("delete-all-blocks", bpo::bool_switch()->default_value(false),
368 "clear chain state database and block log")
369 ("truncate-at-block", bpo::value<uint32_t>()->default_value(0),
370 "stop hard replay / block log recovery at this block number (if set to non-zero number)")
371 ("terminate-at-block", bpo::value<uint32_t>()->default_value(0),
372 "terminate after reaching this block number (if set to a non-zero number)")
373 ("snapshot", bpo::value<bfs::path>(), "File to read Snapshot State from")
374 ;
375
376}
377
378#define LOAD_VALUE_SET(options, op_name, container) \
379if( options.count(op_name) ) { \
380 const std::vector<std::string>& ops = options[op_name].as<std::vector<std::string>>(); \
381 for( const auto& v : ops ) { \
382 container.emplace( sysio::chain::name( v ) ); \
383 } \
384}
385
387 fc::time_point genesis_timestamp;
388 if( strcasecmp (tstr.c_str(), "now") == 0 ) {
389 genesis_timestamp = fc::time_point::now();
390 } else {
391 genesis_timestamp = time_point::from_iso_string( tstr );
392 }
393
394 auto epoch_us = genesis_timestamp.time_since_epoch().count();
395 auto diff_us = epoch_us % config::block_interval_us;
396 if (diff_us > 0) {
397 auto delay_us = (config::block_interval_us - diff_us);
398 genesis_timestamp += fc::microseconds(delay_us);
399 dlog("pausing ${us} microseconds to the next interval",("us",delay_us));
400 }
401
402 ilog( "Adjusting genesis timestamp to ${timestamp}", ("timestamp", genesis_timestamp) );
403 return genesis_timestamp;
404}
405
407 using boost::filesystem::directory_iterator;
408
409 if( !fc::is_directory( p ) )
410 return;
411
412 for( directory_iterator enditr, itr{p}; itr != enditr; ++itr ) {
413 fc::remove_all( itr->path() );
414 }
415}
416
418 if( !fc::is_directory( p ) )
419 return;
420
421 fc::remove( p / "shared_memory.bin" );
422 fc::remove( p / "shared_memory.meta" );
423}
424
425std::optional<builtin_protocol_feature> read_builtin_protocol_feature( const fc::path& p ) {
426 try {
428 } catch( const fc::exception& e ) {
429 wlog( "problem encountered while reading '${path}':\n${details}",
430 ("path", p.generic_string())("details",e.to_detail_string()) );
431 } catch( ... ) {
432 dlog( "unknown problem encountered while reading '${path}'",
433 ("path", p.generic_string()) );
434 }
435 return {};
436}
437
438protocol_feature_set initialize_protocol_features( const fc::path& p, bool populate_missing_builtins = true ) {
439 using boost::filesystem::directory_iterator;
440
442
443 bool directory_exists = true;
444
445 if( fc::exists( p ) ) {
446 SYS_ASSERT( fc::is_directory( p ), plugin_exception,
447 "Path to protocol-features is not a directory: ${path}",
448 ("path", p.generic_string())
449 );
450 } else {
451 if( populate_missing_builtins )
452 bfs::create_directories( p );
453 else
454 directory_exists = false;
455 }
456
457 auto log_recognized_protocol_feature = []( const builtin_protocol_feature& f, const digest_type& feature_digest ) {
458 if( f.subjective_restrictions.enabled ) {
459 if( f.subjective_restrictions.preactivation_required ) {
460 if( f.subjective_restrictions.earliest_allowed_activation_time == time_point{} ) {
461 ilog( "Support for builtin protocol feature '${codename}' (with digest of '${digest}') is enabled with preactivation required",
462 ("codename", builtin_protocol_feature_codename(f.get_codename()))
463 ("digest", feature_digest)
464 );
465 } else {
466 ilog( "Support for builtin protocol feature '${codename}' (with digest of '${digest}') is enabled with preactivation required and with an earliest allowed activation time of ${earliest_time}",
467 ("codename", builtin_protocol_feature_codename(f.get_codename()))
468 ("digest", feature_digest)
469 ("earliest_time", f.subjective_restrictions.earliest_allowed_activation_time)
470 );
471 }
472 } else {
473 if( f.subjective_restrictions.earliest_allowed_activation_time == time_point{} ) {
474 ilog( "Support for builtin protocol feature '${codename}' (with digest of '${digest}') is enabled without activation restrictions",
475 ("codename", builtin_protocol_feature_codename(f.get_codename()))
476 ("digest", feature_digest)
477 );
478 } else {
479 ilog( "Support for builtin protocol feature '${codename}' (with digest of '${digest}') is enabled without preactivation required but with an earliest allowed activation time of ${earliest_time}",
480 ("codename", builtin_protocol_feature_codename(f.get_codename()))
481 ("digest", feature_digest)
482 ("earliest_time", f.subjective_restrictions.earliest_allowed_activation_time)
483 );
484 }
485 }
486 } else {
487 ilog( "Recognized builtin protocol feature '${codename}' (with digest of '${digest}') but support for it is not enabled",
488 ("codename", builtin_protocol_feature_codename(f.get_codename()))
489 ("digest", feature_digest)
490 );
491 }
492 };
493
494 map<builtin_protocol_feature_t, fc::path> found_builtin_protocol_features;
495 map<digest_type, std::pair<builtin_protocol_feature, bool> > builtin_protocol_features_to_add;
496 // The bool in the pair is set to true if the builtin protocol feature has already been visited to add
497 map< builtin_protocol_feature_t, std::optional<digest_type> > visited_builtins;
498
499 // Read all builtin protocol features
500 if( directory_exists ) {
501 for( directory_iterator enditr, itr{p}; itr != enditr; ++itr ) {
502 auto file_path = itr->path();
503 if( !fc::is_regular_file( file_path ) || file_path.extension().generic_string().compare( ".json" ) != 0 )
504 continue;
505
506 auto f = read_builtin_protocol_feature( file_path );
507
508 if( !f ) continue;
509
510 auto res = found_builtin_protocol_features.emplace( f->get_codename(), file_path );
511
512 SYS_ASSERT( res.second, plugin_exception,
513 "Builtin protocol feature '${codename}' was already included from a previous_file",
514 ("codename", builtin_protocol_feature_codename(f->get_codename()))
515 ("current_file", file_path.generic_string())
516 ("previous_file", res.first->second.generic_string())
517 );
518
519 const auto feature_digest = f->digest();
520
521 builtin_protocol_features_to_add.emplace( std::piecewise_construct,
522 std::forward_as_tuple( feature_digest ),
523 std::forward_as_tuple( *f, false ) );
524 }
525 }
526
527 // Add builtin protocol features to the protocol feature manager in the right order (to satisfy dependencies)
528 using itr_type = map<digest_type, std::pair<builtin_protocol_feature, bool>>::iterator;
529 std::function<void(const itr_type&)> add_protocol_feature =
530 [&pfs, &builtin_protocol_features_to_add, &visited_builtins, &log_recognized_protocol_feature, &add_protocol_feature]( const itr_type& itr ) -> void {
531 if( itr->second.second ) {
532 return;
533 } else {
534 itr->second.second = true;
535 visited_builtins.emplace( itr->second.first.get_codename(), itr->first );
536 }
537
538 for( const auto& d : itr->second.first.dependencies ) {
539 auto itr2 = builtin_protocol_features_to_add.find( d );
540 if( itr2 != builtin_protocol_features_to_add.end() ) {
541 add_protocol_feature( itr2 );
542 }
543 }
544
545 pfs.add_feature( itr->second.first );
546
547 log_recognized_protocol_feature( itr->second.first, itr->first );
548 };
549
550 for( auto itr = builtin_protocol_features_to_add.begin(); itr != builtin_protocol_features_to_add.end(); ++itr ) {
551 add_protocol_feature( itr );
552 }
553
554 auto output_protocol_feature = [&p]( const builtin_protocol_feature& f, const digest_type& feature_digest ) {
555 string filename( "BUILTIN-" );
556 filename += builtin_protocol_feature_codename( f.get_codename() );
557 filename += ".json";
558
559 auto file_path = p / filename;
560
561 SYS_ASSERT( !fc::exists( file_path ), plugin_exception,
562 "Could not save builtin protocol feature with codename '${codename}' because a file at the following path already exists: ${path}",
563 ("codename", builtin_protocol_feature_codename( f.get_codename() ))
564 ("path", file_path.generic_string())
565 );
566
567 if( fc::json::save_to_file( f, file_path ) ) {
568 ilog( "Saved default specification for builtin protocol feature '${codename}' (with digest of '${digest}') to: ${path}",
569 ("codename", builtin_protocol_feature_codename(f.get_codename()))
570 ("digest", feature_digest)
571 ("path", file_path.generic_string())
572 );
573 } else {
574 elog( "Error occurred while writing default specification for builtin protocol feature '${codename}' (with digest of '${digest}') to: ${path}",
575 ("codename", builtin_protocol_feature_codename(f.get_codename()))
576 ("digest", feature_digest)
577 ("path", file_path.generic_string())
578 );
579 }
580 };
581
582 std::function<digest_type(builtin_protocol_feature_t)> add_missing_builtins =
583 [&pfs, &visited_builtins, &output_protocol_feature, &log_recognized_protocol_feature, &add_missing_builtins, populate_missing_builtins]
585 auto res = visited_builtins.emplace( codename, std::optional<digest_type>() );
586 if( !res.second ) {
587 SYS_ASSERT( res.first->second, protocol_feature_exception,
588 "invariant failure: cycle found in builtin protocol feature dependencies"
589 );
590 return *res.first->second;
591 }
592
594 [&add_missing_builtins]( builtin_protocol_feature_t d ) {
595 return add_missing_builtins( d );
596 } );
597
598 if( !populate_missing_builtins )
599 f.subjective_restrictions.enabled = false;
600
601 const auto& pf = pfs.add_feature( f );
602 res.first->second = pf.feature_digest;
603
604 log_recognized_protocol_feature( f, pf.feature_digest );
605
606 if( populate_missing_builtins )
607 output_protocol_feature( f, pf.feature_digest );
608
609 return pf.feature_digest;
610 };
611
612 for( const auto& p : builtin_protocol_feature_codenames ) {
613 auto itr = found_builtin_protocol_features.find( p.first );
614 if( itr != found_builtin_protocol_features.end() ) continue;
615
616 add_missing_builtins( p.first );
617 }
618
619 return pfs;
620}
621
622namespace {
623 // This can be removed when versions of sysio that support reversible chainbase state file no longer supported.
624 void upgrade_from_reversible_to_fork_db(chain_plugin_impl* my) {
625 namespace bfs = boost::filesystem;
626 bfs::path old_fork_db = my->chain_config->state_dir / config::forkdb_filename;
627 bfs::path new_fork_db = my->blocks_dir / config::reversible_blocks_dir_name / config::forkdb_filename;
628 if( bfs::exists( old_fork_db ) && bfs::is_regular_file( old_fork_db ) ) {
629 bool copy_file = false;
630 if( bfs::exists( new_fork_db ) && bfs::is_regular_file( new_fork_db ) ) {
631 if( bfs::last_write_time( old_fork_db ) > bfs::last_write_time( new_fork_db ) ) {
632 copy_file = true;
633 }
634 } else {
635 copy_file = true;
636 bfs::create_directories( my->blocks_dir / config::reversible_blocks_dir_name );
637 }
638 if( copy_file ) {
639 fc::rename( old_fork_db, new_fork_db );
640 } else {
641 fc::remove( old_fork_db );
642 }
643 }
644 }
645}
646
647void
648chain_plugin::do_hard_replay(const variables_map& options) {
649 ilog( "Hard replay requested: deleting state database" );
650 clear_directory_contents( my->chain_config->state_dir );
651 auto backup_dir = block_log::repair_log( my->blocks_dir, options.at( "truncate-at-block" ).as<uint32_t>(), config::reversible_blocks_dir_name);
652}
653
654void chain_plugin::plugin_initialize(const variables_map& options) {
655 ilog("initializing chain plugin");
656
657 try {
658 try {
659 genesis_state gs; // Check if SYSIO_ROOT_KEY is bad
660 } catch ( const std::exception& ) {
661 elog( "SYSIO_ROOT_KEY ('${root_key}') is invalid. Recompile with a valid public key.",
662 ("root_key", genesis_state::sysio_root_key));
663 throw;
664 }
665
667
668 if( options.at( "print-build-info" ).as<bool>() || options.count( "extract-build-info") ) {
669 if( options.at( "print-build-info" ).as<bool>() ) {
670 ilog( "Build environment JSON:\n${e}", ("e", json::to_pretty_string( chainbase::environment() )) );
671 }
672 if( options.count( "extract-build-info") ) {
673 auto p = options.at( "extract-build-info" ).as<bfs::path>();
674
675 if( p.is_relative()) {
676 p = bfs::current_path() / p;
677 }
678
679 SYS_ASSERT( fc::json::save_to_file( chainbase::environment(), p, true ), misc_exception,
680 "Error occurred while writing build info JSON to '${path}'",
681 ("path", p.generic_string())
682 );
683
684 ilog( "Saved build info JSON to '${path}'", ("path", p.generic_string()) );
685 }
686
687 SYS_THROW( node_management_success, "reported build environment information" );
688 }
689
690 LOAD_VALUE_SET( options, "sender-bypass-whiteblacklist", my->chain_config->sender_bypass_whiteblacklist );
691 LOAD_VALUE_SET( options, "actor-whitelist", my->chain_config->actor_whitelist );
692 LOAD_VALUE_SET( options, "actor-blacklist", my->chain_config->actor_blacklist );
693 LOAD_VALUE_SET( options, "contract-whitelist", my->chain_config->contract_whitelist );
694 LOAD_VALUE_SET( options, "contract-blacklist", my->chain_config->contract_blacklist );
695
696 LOAD_VALUE_SET( options, "trusted-producer", my->chain_config->trusted_producers );
697
698 if( options.count( "action-blacklist" )) {
699 const std::vector<std::string>& acts = options["action-blacklist"].as<std::vector<std::string>>();
700 auto& list = my->chain_config->action_blacklist;
701 for( const auto& a : acts ) {
702 auto pos = a.find( "::" );
703 SYS_ASSERT( pos != std::string::npos, plugin_config_exception, "Invalid entry in action-blacklist: '${a}'", ("a", a));
704 account_name code( a.substr( 0, pos ));
705 action_name act( a.substr( pos + 2 ));
706 list.emplace( code, act );
707 }
708 }
709
710 if( options.count( "key-blacklist" )) {
711 const std::vector<std::string>& keys = options["key-blacklist"].as<std::vector<std::string>>();
712 auto& list = my->chain_config->key_blacklist;
713 for( const auto& key_str : keys ) {
714 list.emplace( key_str );
715 }
716 }
717
718 if( options.count( "blocks-dir" )) {
719 auto bld = options.at( "blocks-dir" ).as<bfs::path>();
720 if( bld.is_relative())
721 my->blocks_dir = app().data_dir() / bld;
722 else
723 my->blocks_dir = bld;
724 }
725
727 {
728 fc::path protocol_features_dir;
729 auto pfd = options.at( "protocol-features-dir" ).as<bfs::path>();
730 if( pfd.is_relative())
731 protocol_features_dir = app().config_dir() / pfd;
732 else
733 protocol_features_dir = pfd;
734
735 pfs = initialize_protocol_features( protocol_features_dir );
736 }
737
738 if( options.count("checkpoint") ) {
739 auto cps = options.at("checkpoint").as<vector<string>>();
740 my->loaded_checkpoints.reserve(cps.size());
741 for( const auto& cp : cps ) {
742 auto item = fc::json::from_string(cp).as<std::pair<uint32_t,block_id_type>>();
743 auto itr = my->loaded_checkpoints.find(item.first);
744 if( itr != my->loaded_checkpoints.end() ) {
745 SYS_ASSERT( itr->second == item.second,
746 plugin_config_exception,
747 "redefining existing checkpoint at block number ${num}: original: ${orig} new: ${new}",
748 ("num", item.first)("orig", itr->second)("new", item.second)
749 );
750 } else {
751 my->loaded_checkpoints[item.first] = item.second;
752 }
753 }
754 }
755
756 if( options.count( "wasm-runtime" ))
757 my->wasm_runtime = options.at( "wasm-runtime" ).as<vm_type>();
758
759 LOAD_VALUE_SET( options, "profile-account", my->chain_config->profile_accounts );
760
761 if(options.count("abi-serializer-max-time-ms"))
762 my->abi_serializer_max_time_us = fc::microseconds(options.at("abi-serializer-max-time-ms").as<uint32_t>() * 1000);
763
764 my->chain_config->blocks_dir = my->blocks_dir;
765 my->chain_config->state_dir = app().data_dir() / config::default_state_dir_name;
766 my->chain_config->read_only = my->readonly;
767
768 if (auto resmon_plugin = app().find_plugin<resource_monitor_plugin>()) {
769 resmon_plugin->monitor_directory(my->chain_config->blocks_dir);
770 resmon_plugin->monitor_directory(my->chain_config->state_dir);
771 }
772
773 if( options.count( "chain-state-db-size-mb" ))
774 my->chain_config->state_size = options.at( "chain-state-db-size-mb" ).as<uint64_t>() * 1024 * 1024;
775
776 if( options.count( "chain-state-db-guard-size-mb" ))
777 my->chain_config->state_guard_size = options.at( "chain-state-db-guard-size-mb" ).as<uint64_t>() * 1024 * 1024;
778
779 if( options.count( "max-nonprivileged-inline-action-size" ))
780 my->chain_config->max_nonprivileged_inline_action_size = options.at( "max-nonprivileged-inline-action-size" ).as<uint32_t>();
781
782 if( options.count( "transaction-finality-status-max-storage-size-gb" )) {
783 const uint64_t max_storage_size = options.at( "transaction-finality-status-max-storage-size-gb" ).as<uint64_t>() * 1024 * 1024 * 1024;
784 if (max_storage_size > 0) {
785 const fc::microseconds success_duration = fc::seconds(options.at( "transaction-finality-status-success-duration-sec" ).as<uint64_t>());
786 const fc::microseconds failure_duration = fc::seconds(options.at( "transaction-finality-status-failure-duration-sec" ).as<uint64_t>());
788 new chain_apis::trx_finality_status_processing(max_storage_size, success_duration, failure_duration));
789 }
790 }
791
792 if( options.count( "chain-threads" )) {
793 my->chain_config->thread_pool_size = options.at( "chain-threads" ).as<uint16_t>();
794 SYS_ASSERT( my->chain_config->thread_pool_size > 0, plugin_config_exception,
795 "chain-threads ${num} must be greater than 0", ("num", my->chain_config->thread_pool_size) );
796 }
797
798 my->chain_config->sig_cpu_bill_pct = options.at("signature-cpu-billable-pct").as<uint32_t>();
799 SYS_ASSERT( my->chain_config->sig_cpu_bill_pct >= 0 && my->chain_config->sig_cpu_bill_pct <= 100, plugin_config_exception,
800 "signature-cpu-billable-pct must be 0 - 100, ${pct}", ("pct", my->chain_config->sig_cpu_bill_pct) );
801 my->chain_config->sig_cpu_bill_pct *= config::percent_1;
802
803 if( my->wasm_runtime )
804 my->chain_config->wasm_runtime = *my->wasm_runtime;
805
806 my->chain_config->force_all_checks = options.at( "force-all-checks" ).as<bool>();
807 my->chain_config->disable_replay_opts = options.at( "disable-replay-opts" ).as<bool>();
808 my->chain_config->contracts_console = options.at( "contracts-console" ).as<bool>();
809 my->chain_config->allow_ram_billing_in_notify = options.at( "disable-ram-billing-notify-checks" ).as<bool>();
810
811#ifdef SYSIO_DEVELOPER
812 my->chain_config->disable_all_subjective_mitigations = options.at( "disable-all-subjective-mitigations" ).as<bool>();
813#endif
814
815 my->chain_config->maximum_variable_signature_length = options.at( "maximum-variable-signature-length" ).as<uint32_t>();
816
817 if( options.count( "terminate-at-block" ))
818 my->chain_config->terminate_at_block = options.at( "terminate-at-block" ).as<uint32_t>();
819
820 if( options.count( "extract-genesis-json" ) || options.at( "print-genesis-json" ).as<bool>()) {
821 std::optional<genesis_state> gs;
822
823 if( fc::exists( my->blocks_dir / "blocks.log" )) {
825 SYS_ASSERT( gs,
826 plugin_config_exception,
827 "Block log at '${path}' does not contain a genesis state, it only has the chain-id.",
828 ("path", (my->blocks_dir / "blocks.log").generic_string())
829 );
830 } else {
831 wlog( "No blocks.log found at '${p}'. Using default genesis state.",
832 ("p", (my->blocks_dir / "blocks.log").generic_string()));
833 gs.emplace();
834 }
835
836 if( options.at( "print-genesis-json" ).as<bool>()) {
837 ilog( "Genesis JSON:\n${genesis}", ("genesis", json::to_pretty_string( *gs )));
838 }
839
840 if( options.count( "extract-genesis-json" )) {
841 auto p = options.at( "extract-genesis-json" ).as<bfs::path>();
842
843 if( p.is_relative()) {
844 p = bfs::current_path() / p;
845 }
846
847 SYS_ASSERT( fc::json::save_to_file( *gs, p, true ),
848 misc_exception,
849 "Error occurred while writing genesis JSON to '${path}'",
850 ("path", p.generic_string())
851 );
852
853 ilog( "Saved genesis JSON to '${path}'", ("path", p.generic_string()) );
854 }
855
856 SYS_THROW( extract_genesis_state_exception, "extracted genesis state from blocks.log" );
857 }
858
859 // move fork_db to new location
860 upgrade_from_reversible_to_fork_db( my.get() );
861
862 if(options.count( "block-log-retain-blocks" )) {
863 my->chain_config->prune_config.emplace();
864 my->chain_config->prune_config->prune_blocks = options.at( "block-log-retain-blocks" ).as<uint32_t>();
865 SYS_ASSERT(my->chain_config->prune_config->prune_blocks, plugin_config_exception, "block-log-retain-blocks cannot be 0");
866 }
867
868 if( options.at( "delete-all-blocks" ).as<bool>()) {
869 ilog( "Deleting state database and blocks" );
870 if( options.at( "truncate-at-block" ).as<uint32_t>() > 0 )
871 wlog( "The --truncate-at-block option does not make sense when deleting all blocks." );
872 clear_directory_contents( my->chain_config->state_dir );
874 } else if( options.at( "hard-replay-blockchain" ).as<bool>()) {
875 do_hard_replay(options);
876 } else if( options.at( "replay-blockchain" ).as<bool>()) {
877 ilog( "Replay requested: deleting state database" );
878 if( options.at( "truncate-at-block" ).as<uint32_t>() > 0 )
879 wlog( "The --truncate-at-block option does not work for a regular replay of the blockchain." );
880 clear_chainbase_files( my->chain_config->state_dir );
881 } else if( options.at( "truncate-at-block" ).as<uint32_t>() > 0 ) {
882 wlog( "The --truncate-at-block option can only be used with --hard-replay-blockchain." );
883 }
884
885 std::optional<chain_id_type> chain_id;
886 if (options.count( "snapshot" )) {
887 my->snapshot_path = options.at( "snapshot" ).as<bfs::path>();
888 SYS_ASSERT( fc::exists(*my->snapshot_path), plugin_config_exception,
889 "Cannot load snapshot, ${name} does not exist", ("name", my->snapshot_path->generic_string()) );
890
891 // recover genesis information from the snapshot
892 // used for validation code below
893 auto infile = std::ifstream(my->snapshot_path->generic_string(), (std::ios::in | std::ios::binary));
894 istream_snapshot_reader reader(infile);
895 reader.validate();
896 chain_id = controller::extract_chain_id(reader);
897 infile.close();
898
899 SYS_ASSERT( options.count( "genesis-timestamp" ) == 0,
900 plugin_config_exception,
901 "--snapshot is incompatible with --genesis-timestamp as the snapshot contains genesis information");
902 SYS_ASSERT( options.count( "genesis-json" ) == 0,
903 plugin_config_exception,
904 "--snapshot is incompatible with --genesis-json as the snapshot contains genesis information");
905
906 auto shared_mem_path = my->chain_config->state_dir / "shared_memory.bin";
907 SYS_ASSERT( !fc::is_regular_file(shared_mem_path),
908 plugin_config_exception,
909 "Snapshot can only be used to initialize an empty database." );
910
911 if( fc::is_regular_file( my->blocks_dir / "blocks.log" )) {
912 auto block_log_genesis = block_log::extract_genesis_state(my->blocks_dir);
913 if( block_log_genesis ) {
914 const auto& block_log_chain_id = block_log_genesis->compute_chain_id();
915 SYS_ASSERT( *chain_id == block_log_chain_id,
916 plugin_config_exception,
917 "snapshot chain ID (${snapshot_chain_id}) does not match the chain ID from the genesis state in the block log (${block_log_chain_id})",
918 ("snapshot_chain_id", *chain_id)
919 ("block_log_chain_id", block_log_chain_id)
920 );
921 } else {
922 const auto& block_log_chain_id = block_log::extract_chain_id(my->blocks_dir);
923 SYS_ASSERT( *chain_id == block_log_chain_id,
924 plugin_config_exception,
925 "snapshot chain ID (${snapshot_chain_id}) does not match the chain ID (${block_log_chain_id}) in the block log",
926 ("snapshot_chain_id", *chain_id)
927 ("block_log_chain_id", block_log_chain_id)
928 );
929 }
930 }
931
932 } else {
933
934 chain_id = controller::extract_chain_id_from_db( my->chain_config->state_dir );
935
936 std::optional<genesis_state> block_log_genesis;
937 std::optional<chain_id_type> block_log_chain_id;
938
939 if( fc::is_regular_file( my->blocks_dir / "blocks.log" ) ) {
940 block_log_genesis = block_log::extract_genesis_state( my->blocks_dir );
941 if( block_log_genesis ) {
942 block_log_chain_id = block_log_genesis->compute_chain_id();
943 } else {
944 block_log_chain_id = block_log::extract_chain_id( my->blocks_dir );
945 }
946
947 if( chain_id ) {
948 SYS_ASSERT( *block_log_chain_id == *chain_id, block_log_exception,
949 "Chain ID in blocks.log (${block_log_chain_id}) does not match the existing "
950 " chain ID in state (${state_chain_id}).",
951 ("block_log_chain_id", *block_log_chain_id)
952 ("state_chain_id", *chain_id)
953 );
954 } else if( block_log_genesis ) {
955 ilog( "Starting fresh blockchain state using genesis state extracted from blocks.log." );
956 my->genesis = block_log_genesis;
957 // Delay setting chain_id until later so that the code handling genesis-json below can know
958 // that chain_id still only represents a chain ID extracted from the state (assuming it exists).
959 }
960 }
961
962 if( options.count( "genesis-json" ) ) {
963 bfs::path genesis_file = options.at( "genesis-json" ).as<bfs::path>();
964 if( genesis_file.is_relative()) {
965 genesis_file = bfs::current_path() / genesis_file;
966 }
967
968 SYS_ASSERT( fc::is_regular_file( genesis_file ),
969 plugin_config_exception,
970 "Specified genesis file '${genesis}' does not exist.",
971 ("genesis", genesis_file.generic_string()));
972
973 genesis_state provided_genesis = fc::json::from_file( genesis_file ).as<genesis_state>();
974
975 if( options.count( "genesis-timestamp" ) ) {
976 provided_genesis.initial_timestamp = calculate_genesis_timestamp( options.at( "genesis-timestamp" ).as<string>() );
977
978 ilog( "Using genesis state provided in '${genesis}' but with adjusted genesis timestamp",
979 ("genesis", genesis_file.generic_string()) );
980 } else {
981 ilog( "Using genesis state provided in '${genesis}'", ("genesis", genesis_file.generic_string()));
982 }
983
984 if( block_log_genesis ) {
985 SYS_ASSERT( *block_log_genesis == provided_genesis, plugin_config_exception,
986 "Genesis state, provided via command line arguments, does not match the existing genesis state"
987 " in blocks.log. It is not necessary to provide genesis state arguments when a full blocks.log "
988 "file already exists."
989 );
990 } else {
991 const auto& provided_genesis_chain_id = provided_genesis.compute_chain_id();
992 if( chain_id ) {
993 SYS_ASSERT( provided_genesis_chain_id == *chain_id, plugin_config_exception,
994 "Genesis state, provided via command line arguments, has a chain ID (${provided_genesis_chain_id}) "
995 "that does not match the existing chain ID in the database state (${state_chain_id}). "
996 "It is not necessary to provide genesis state arguments when an initialized database state already exists.",
997 ("provided_genesis_chain_id", provided_genesis_chain_id)
998 ("state_chain_id", *chain_id)
999 );
1000 } else {
1001 if( block_log_chain_id ) {
1002 SYS_ASSERT( provided_genesis_chain_id == *block_log_chain_id, plugin_config_exception,
1003 "Genesis state, provided via command line arguments, has a chain ID (${provided_genesis_chain_id}) "
1004 "that does not match the existing chain ID in blocks.log (${block_log_chain_id}).",
1005 ("provided_genesis_chain_id", provided_genesis_chain_id)
1006 ("block_log_chain_id", *block_log_chain_id)
1007 );
1008 }
1009
1010 chain_id = provided_genesis_chain_id;
1011
1012 ilog( "Starting fresh blockchain state using provided genesis state." );
1013 my->genesis = std::move(provided_genesis);
1014 }
1015 }
1016 } else {
1017 SYS_ASSERT( options.count( "genesis-timestamp" ) == 0,
1018 plugin_config_exception,
1019 "--genesis-timestamp is only valid if also passed in with --genesis-json");
1020 }
1021
1022 if( !chain_id ) {
1023 if( my->genesis ) {
1024 // Uninitialized state database and genesis state extracted from block log
1025 chain_id = my->genesis->compute_chain_id();
1026 } else {
1027 // Uninitialized state database and no genesis state provided
1028
1029 SYS_ASSERT( !block_log_chain_id, plugin_config_exception,
1030 "Genesis state is necessary to initialize fresh blockchain state but genesis state could not be "
1031 "found in the blocks log. Please either load from snapshot or find a blocks log that starts "
1032 "from genesis."
1033 );
1034
1035 ilog( "Starting fresh blockchain state using default genesis state." );
1036 my->genesis.emplace();
1037 chain_id = my->genesis->compute_chain_id();
1038 }
1039 }
1040 }
1041
1042 if ( options.count("read-mode") ) {
1043 my->chain_config->read_mode = options.at("read-mode").as<db_read_mode>();
1044 }
1045 my->api_accept_transactions = options.at( "api-accept-transactions" ).as<bool>();
1046
1047 if( my->chain_config->read_mode == db_read_mode::IRREVERSIBLE || my->chain_config->read_mode == db_read_mode::READ_ONLY ) {
1048 if( my->chain_config->read_mode == db_read_mode::READ_ONLY ) {
1049 wlog( "read-mode = read-only is deprecated use p2p-accept-transactions = false, api-accept-transactions = false instead." );
1050 }
1051 if( my->api_accept_transactions ) {
1052 my->api_accept_transactions = false;
1053 std::stringstream ss; ss << my->chain_config->read_mode;
1054 wlog( "api-accept-transactions set to false due to read-mode: ${m}", ("m", ss.str()) );
1055 }
1056 }
1057 if( my->api_accept_transactions ) {
1059 }
1060
1061 if ( options.count("validation-mode") ) {
1062 my->chain_config->block_validation_mode = options.at("validation-mode").as<validation_mode>();
1063 }
1064
1065 my->chain_config->db_map_mode = options.at("database-map-mode").as<pinnable_mapped_file::map_mode>();
1066
1067#ifdef SYSIO_SYS_VM_OC_RUNTIME_ENABLED
1068 if( options.count("sys-vm-oc-cache-size-mb") )
1069 my->chain_config->eosvmoc_config.cache_size = options.at( "sys-vm-oc-cache-size-mb" ).as<uint64_t>() * 1024u * 1024u;
1070 if( options.count("sys-vm-oc-compile-threads") )
1071 my->chain_config->eosvmoc_config.threads = options.at("sys-vm-oc-compile-threads").as<uint64_t>();
1072 if( options["sys-vm-oc-enable"].as<bool>() )
1073 my->chain_config->eosvmoc_tierup = true;
1074#endif
1075
1076 my->account_queries_enabled = options.at("enable-account-queries").as<bool>();
1077
1078 my->chain.emplace( *my->chain_config, std::move(pfs), *chain_id );
1079
1080 if( options.count( "transaction-retry-max-storage-size-gb" )) {
1081 SYS_ASSERT( !options.count( "producer-name"), plugin_config_exception,
1082 "Transaction retry not allowed on producer nodes." );
1083 const uint64_t max_storage_size = options.at( "transaction-retry-max-storage-size-gb" ).as<uint64_t>() * 1024 * 1024 * 1024;
1084 if( max_storage_size > 0 ) {
1085 const uint32_t p2p_dedup_time_s = options.at( "p2p-dedup-cache-expire-time-sec" ).as<uint32_t>();
1086 const uint32_t trx_retry_interval = options.at( "transaction-retry-interval-sec" ).as<uint32_t>();
1087 const uint32_t trx_retry_max_expire = options.at( "transaction-retry-max-expiration-sec" ).as<uint32_t>();
1088 SYS_ASSERT( trx_retry_interval >= 2 * p2p_dedup_time_s, plugin_config_exception,
1089 "transaction-retry-interval-sec ${ri} must be greater than 2 times p2p-dedup-cache-expire-time-sec ${dd}",
1090 ("ri", trx_retry_interval)("dd", p2p_dedup_time_s) );
1091 SYS_ASSERT( trx_retry_max_expire > trx_retry_interval, plugin_config_exception,
1092 "transaction-retry-max-expiration-sec ${m} should be configured larger than transaction-retry-interval-sec ${i}",
1093 ("m", trx_retry_max_expire)("i", trx_retry_interval) );
1094 my->_trx_retry_db.emplace( *my->chain, max_storage_size,
1095 fc::seconds(trx_retry_interval), fc::seconds(trx_retry_max_expire),
1097 }
1098 }
1099
1100 // initialize deep mind logging
1101 if ( options.at( "deep-mind" ).as<bool>() ) {
1102 // The actual `fc::dmlog_appender` implementation that is currently used by deep mind
1103 // logger is using `stdout` to prints it's log line out. Deep mind logging outputs
1104 // massive amount of data out of the process, which can lead under pressure to some
1105 // of the system calls (i.e. `fwrite`) to fail abruptly without fully writing the
1106 // entire line.
1107 //
1108 // Recovering from errors on a buffered (line or full) and continuing retrying write
1109 // is merely impossible to do right, because the buffer is actually held by the
1110 // underlying `libc` implementation nor the operation system.
1111 //
1112 // To ensure good functionalities of deep mind tracer, the `stdout` is made unbuffered
1113 // and the actual `fc::dmlog_appender` deals with retry when facing error, enabling a much
1114 // more robust deep mind output.
1115 //
1116 // Changing the standard `stdout` behavior from buffered to unbuffered can is disruptive
1117 // and can lead to weird scenarios in the logging process if `stdout` is used there too.
1118 //
1119 // In a future version, the `fc::dmlog_appender` implementation will switch to a `FIFO` file
1120 // approach, which will remove the dependency on `stdout` and hence this call.
1121 //
1122 // For the time being, when `deep-mind = true` is activated, we set `stdout` here to
1123 // be an unbuffered I/O stream.
1124 setbuf(stdout, NULL);
1125
1126 //verify configuration is correct
1127 SYS_ASSERT( options.at("api-accept-transactions").as<bool>() == false, plugin_config_exception,
1128 "api-accept-transactions must be set to false in order to enable deep-mind logging.");
1129
1130 SYS_ASSERT( options.at("p2p-accept-transactions").as<bool>() == false, plugin_config_exception,
1131 "p2p-accept-transactions must be set to false in order to enable deep-mind logging.");
1132
1133 my->chain->enable_deep_mind( &_deep_mind_log );
1134 }
1135
1136 // set up method providers
1138 [this]( uint32_t block_num ) -> signed_block_ptr {
1139 return my->chain->fetch_block_by_number( block_num );
1140 } );
1141
1143 [this]( block_id_type id ) -> signed_block_ptr {
1144 return my->chain->fetch_block_by_id( id );
1145 } );
1146
1147 my->get_head_block_id_provider = app().get_method<methods::get_head_block_id>().register_provider( [this]() {
1148 return my->chain->head_block_id();
1149 } );
1150
1152 [this]() {
1153 return my->chain->last_irreversible_block_num();
1154 } );
1155
1156 // relay signals to channels
1157 my->pre_accepted_block_connection = my->chain->pre_accepted_block.connect([this](const signed_block_ptr& blk) {
1158 auto itr = my->loaded_checkpoints.find( blk->block_num() );
1159 if( itr != my->loaded_checkpoints.end() ) {
1160 auto id = blk->calculate_id();
1161 SYS_ASSERT( itr->second == id, checkpoint_exception,
1162 "Checkpoint does not match for block number ${num}: expected: ${expected} actual: ${actual}",
1163 ("num", blk->block_num())("expected", itr->second)("actual", id)
1164 );
1165 }
1166
1168 });
1169
1170 my->accepted_block_header_connection = my->chain->accepted_block_header.connect(
1171 [this]( const block_state_ptr& blk ) {
1173 } );
1174
1175 my->accepted_block_connection = my->chain->accepted_block.connect( [this]( const block_state_ptr& blk ) {
1176 if (my->_account_query_db) {
1177 my->_account_query_db->commit_block(blk);
1178 }
1179
1180 if (my->_trx_retry_db) {
1181 my->_trx_retry_db->on_accepted_block(blk);
1182 }
1183
1185 my->_trx_finality_status_processing->signal_accepted_block(blk);
1186 }
1187
1189 } );
1190
1191 my->irreversible_block_connection = my->chain->irreversible_block.connect( [this]( const block_state_ptr& blk ) {
1192 if (my->_trx_retry_db) {
1193 my->_trx_retry_db->on_irreversible_block(blk);
1194 }
1195
1197 my->_trx_finality_status_processing->signal_irreversible_block(blk);
1198 }
1199
1201 } );
1202
1203 my->accepted_transaction_connection = my->chain->accepted_transaction.connect(
1204 [this]( const transaction_metadata_ptr& meta ) {
1206 } );
1207
1208 my->applied_transaction_connection = my->chain->applied_transaction.connect(
1209 [this]( std::tuple<const transaction_trace_ptr&, const packed_transaction_ptr&> t ) {
1210 if (my->_account_query_db) {
1211 my->_account_query_db->cache_transaction_trace(std::get<0>(t));
1212 }
1213
1214 if (my->_trx_retry_db) {
1215 my->_trx_retry_db->on_applied_transaction(std::get<0>(t), std::get<1>(t));
1216 }
1217
1219 my->_trx_finality_status_processing->signal_applied_transaction(std::get<0>(t), std::get<1>(t));
1220 }
1221
1222 my->applied_transaction_channel.publish( priority::low, std::get<0>(t) );
1223 } );
1224
1226 my->block_start_connection = my->chain->block_start.connect(
1227 [this]( uint32_t block_num ) {
1228 if (my->_trx_retry_db) {
1229 my->_trx_retry_db->on_block_start(block_num);
1230 }
1232 my->_trx_finality_status_processing->signal_block_start( block_num );
1233 }
1234 } );
1235 }
1236 my->chain->add_indices();
1238
1239}
1240
1242{ try {
1243 handle_sighup(); // Sets loggers
1244
1245 SYS_ASSERT( my->chain_config->read_mode != db_read_mode::IRREVERSIBLE || !accept_transactions(), plugin_config_exception,
1246 "read-mode = irreversible. transactions should not be enabled by enable_accept_transactions" );
1247 try {
1249 SYS_ASSERT(my->producer_plug, plugin_exception, "Failed to find producer_plugin");
1250
1251 auto shutdown = [](){ return app().quit(); };
1252 auto check_shutdown = [](){ return app().is_quiting(); };
1253 if (my->snapshot_path) {
1254 auto infile = std::ifstream(my->snapshot_path->generic_string(), (std::ios::in | std::ios::binary));
1255 auto reader = std::make_shared<istream_snapshot_reader>(infile);
1256 my->chain->startup(shutdown, check_shutdown, reader);
1257 infile.close();
1258 } else if( my->genesis ) {
1259 my->chain->startup(shutdown, check_shutdown, *my->genesis);
1260 } else {
1261 my->chain->startup(shutdown, check_shutdown);
1262 }
1263 } catch (const database_guard_exception& e) {
1264 log_guard_exception(e);
1265 // make sure to properly close the db
1266 my->chain.reset();
1267 throw;
1268 }
1269
1270 if(!my->readonly) {
1271 ilog("starting chain in read/write mode");
1272 }
1273
1274 if (my->genesis) {
1275 ilog("Blockchain started; head block is #${num}, genesis timestamp is ${ts}",
1276 ("num", my->chain->head_block_num())("ts", (std::string)my->genesis->initial_timestamp));
1277 }
1278 else {
1279 ilog("Blockchain started; head block is #${num}", ("num", my->chain->head_block_num()));
1280 }
1281
1282 my->chain_config.reset();
1283
1284 if (my->account_queries_enabled) {
1285 my->account_queries_enabled = false;
1286 try {
1287 my->_account_query_db.emplace(*my->chain);
1288 my->account_queries_enabled = true;
1289 } FC_LOG_AND_DROP(("Unable to enable account queries"));
1290 }
1291
1292
1294
1298 my->accepted_block_connection.reset();
1302 my->block_start_connection.reset();
1303 if(app().is_quiting())
1304 my->chain->get_wasm_interface().indicate_shutting_down();
1305 my->chain.reset();
1306}
1307
1309 _deep_mind_log.update_logger( deep_mind_logger_name );
1310}
1311
1312chain_apis::read_write::read_write(controller& db, std::optional<trx_retry_db>& trx_retry, const fc::microseconds& abi_serializer_max_time, bool api_accept_transactions)
1313: db(db)
1314, trx_retry(trx_retry)
1316, api_accept_transactions(api_accept_transactions)
1317{
1318}
1319
1321 SYS_ASSERT( api_accept_transactions, missing_chain_api_plugin_exception,
1322 "Not allowed, node has api-accept-transactions = false" );
1323}
1324
1326 return chain_apis::read_write(chain(), my->_trx_retry_db, get_abi_serializer_max_time(), api_accept_transactions());
1327}
1328
1330 return chain_apis::read_only(chain(), my->_account_query_db, get_abi_serializer_max_time(), my->producer_plug, my->_trx_finality_status_processing.get());
1331}
1332
1333
1335 return my->incoming_block_sync_method(block, id, bsp);
1336}
1337
1341
1343const controller& chain_plugin::chain() const { return *my->chain; }
1344
1346 return my->chain->get_chain_id();
1347}
1348
1352
1356
1358 return my->accept_transactions;
1359}
1360
1364
1365
1366void chain_plugin::log_guard_exception(const chain::guard_exception&e ) {
1367 if (e.code() == chain::database_guard_exception::code_value) {
1368 elog("Database has reached an unsafe level of usage, shutting down to avoid corrupting the database. "
1369 "Please increase the value set for \"chain-state-db-size-mb\" and restart the process!");
1370 }
1371
1372 dlog("Details: ${details}", ("details", e.to_detail_string()));
1373}
1374
1376 log_guard_exception(e);
1377
1378 elog("database chain::guard_exception, quitting..."); // log string searched for in: tests/nodeop_under_min_avail_ram.py
1379 // quit the app
1380 app().quit();
1381}
1382
1384 elog("database memory exhausted: increase chain-state-db-size-mb");
1385 //return 1 -- it's what programs/nodeop/main.cpp considers "BAD_ALLOC"
1386 std::_Exit(1);
1387}
1388
1390 elog("std::bad_alloc - memory exhausted");
1391 //return -2 -- it's what programs/nodeop/main.cpp reports for std::exception
1392 std::_Exit(-2);
1393}
1394
1398
1402
1403namespace chain_apis {
1404
1405const string read_only::KEYi64 = "i64";
1406
1407template<typename I>
1408std::string itoh(I n, size_t hlen = sizeof(I)<<1) {
1409 static const char* digits = "0123456789abcdef";
1410 std::string r(hlen, '0');
1411 for(size_t i = 0, j = (hlen - 1) * 4 ; i < hlen; ++i, j -= 4)
1412 r[i] = digits[(n>>j) & 0x0f];
1413 return r;
1414}
1415
1417 const auto& rm = db.get_resource_limits_manager();
1418
1419 return {
1420 itoh(static_cast<uint32_t>(app().version())),
1421 db.get_chain_id(),
1422 db.head_block_num(),
1423 db.last_irreversible_block_num(),
1424 db.last_irreversible_block_id(),
1425 db.head_block_id(),
1426 db.head_block_time(),
1427 db.head_block_producer(),
1428 rm.get_virtual_block_cpu_limit(),
1429 rm.get_virtual_block_net_limit(),
1430 rm.get_block_cpu_limit(),
1431 rm.get_block_net_limit(),
1432 //std::bitset<64>(db.get_dynamic_global_properties().recent_slots_filled).to_string(),
1433 //__builtin_popcountll(db.get_dynamic_global_properties().recent_slots_filled) / 64.0,
1434 app().version_string(),
1435 db.fork_db_pending_head_block_num(),
1436 db.fork_db_pending_head_block_id(),
1438 rm.get_total_cpu_weight(),
1439 rm.get_total_net_weight(),
1440 db.earliest_available_block_num(),
1441 db.last_irreversible_block_time()
1442 };
1443}
1444
1446 SYS_ASSERT(trx_finality_status_proc, unsupported_feature, "Transaction Status Interface not enabled. To enable, configure nodeop with '--transaction-finality-status-max-storage-size-gb <size>'.");
1447
1448 trx_finality_status_processing::chain_state ch_state = trx_finality_status_proc->get_chain_state();
1449
1450 const auto trx_st = trx_finality_status_proc->get_trx_state(param.id);
1451 // check if block_id is set to a valid value, since trx_finality_status_proc does not use optionals for the block data
1452 const auto trx_block_valid = trx_st && trx_st->block_id != chain::block_id_type{};
1453
1454 return {
1455 trx_st ? trx_st->status : "UNKNOWN",
1456 trx_block_valid ? std::optional<uint32_t>(chain::block_header::num_from_id(trx_st->block_id)) : std::optional<uint32_t>{},
1457 trx_block_valid ? std::optional<chain::block_id_type>(trx_st->block_id) : std::optional<chain::block_id_type>{},
1458 trx_block_valid ? std::optional<fc::time_point>(trx_st->block_timestamp) : std::optional<fc::time_point>{},
1459 trx_st ? std::optional<fc::time_point_sec>(trx_st->expiration) : std::optional<fc::time_point_sec>{},
1460 chain::block_header::num_from_id(ch_state.head_id),
1461 ch_state.head_id,
1462 ch_state.head_block_timestamp,
1463 chain::block_header::num_from_id(ch_state.irr_id),
1464 ch_state.irr_id,
1465 ch_state.irr_block_timestamp,
1467 chain::block_header::num_from_id(ch_state.earliest_tracked_block_id)
1468 };
1469}
1470
1472read_only::get_activated_protocol_features( const read_only::get_activated_protocol_features_params& params )const {
1474 const auto& pfm = db.get_protocol_feature_manager();
1475
1476 uint32_t lower_bound_value = std::numeric_limits<uint32_t>::lowest();
1477 uint32_t upper_bound_value = std::numeric_limits<uint32_t>::max();
1478
1479 if( params.lower_bound ) {
1480 lower_bound_value = *params.lower_bound;
1481 }
1482
1483 if( params.upper_bound ) {
1484 upper_bound_value = *params.upper_bound;
1485 }
1486
1487 if( upper_bound_value < lower_bound_value )
1488 return result;
1489
1490 auto walk_range = [&]( auto itr, auto end_itr, auto&& convert_iterator ) {
1492 mvo( "activation_ordinal", 0 );
1493 mvo( "activation_block_num", 0 );
1494
1495 auto& activation_ordinal_value = mvo["activation_ordinal"];
1496 auto& activation_block_num_value = mvo["activation_block_num"];
1497
1498 auto cur_time = fc::time_point::now();
1499 auto end_time = cur_time + fc::microseconds(1000 * 10);
1500 for( unsigned int count = 0;
1501 cur_time <= end_time && count < params.limit && itr != end_itr;
1502 ++itr, cur_time = fc::time_point::now() )
1503 {
1504 const auto& conv_itr = convert_iterator( itr );
1505 activation_ordinal_value = conv_itr.activation_ordinal();
1506 activation_block_num_value = conv_itr.activation_block_num();
1507
1508 result.activated_protocol_features.emplace_back( conv_itr->to_variant( false, &mvo ) );
1509 ++count;
1510 }
1511 if( itr != end_itr ) {
1512 result.more = convert_iterator( itr ).activation_ordinal() ;
1513 }
1514 };
1515
1516 auto get_next_if_not_end = [&pfm]( auto&& itr ) {
1517 if( itr == pfm.cend() ) return itr;
1518
1519 ++itr;
1520 return itr;
1521 };
1522
1523 auto lower = ( params.search_by_block_num ? pfm.lower_bound( lower_bound_value )
1524 : pfm.at_activation_ordinal( lower_bound_value ) );
1525
1526 auto upper = ( params.search_by_block_num ? pfm.upper_bound( upper_bound_value )
1527 : get_next_if_not_end( pfm.at_activation_ordinal( upper_bound_value ) ) );
1528
1529 if( params.reverse ) {
1530 walk_range( std::make_reverse_iterator(upper), std::make_reverse_iterator(lower),
1531 []( auto&& ritr ) { return --(ritr.base()); } );
1532 } else {
1533 walk_range( lower, upper, []( auto&& itr ) { return itr; } );
1534 }
1535
1536 return result;
1537}
1538
1539uint64_t read_only::get_table_index_name(const read_only::get_table_rows_params& p, bool& primary) {
1540 using boost::algorithm::starts_with;
1541 // see multi_index packing of index name
1542 const uint64_t table = p.table.to_uint64_t();
1543 uint64_t index = table & 0xFFFFFFFFFFFFFFF0ULL;
1544 SYS_ASSERT( index == table, chain::contract_table_query_exception, "Unsupported table name: ${n}", ("n", p.table) );
1545
1546 primary = false;
1547 uint64_t pos = 0;
1548 if (p.index_position.empty() || p.index_position == "first" || p.index_position == "primary" || p.index_position == "one") {
1549 primary = true;
1550 } else if (starts_with(p.index_position, "sec") || p.index_position == "two") { // second, secondary
1551 } else if (starts_with(p.index_position , "ter") || starts_with(p.index_position, "th")) { // tertiary, ternary, third, three
1552 pos = 1;
1553 } else if (starts_with(p.index_position, "fou")) { // four, fourth
1554 pos = 2;
1555 } else if (starts_with(p.index_position, "fi")) { // five, fifth
1556 pos = 3;
1557 } else if (starts_with(p.index_position, "six")) { // six, sixth
1558 pos = 4;
1559 } else if (starts_with(p.index_position, "sev")) { // seven, seventh
1560 pos = 5;
1561 } else if (starts_with(p.index_position, "eig")) { // eight, eighth
1562 pos = 6;
1563 } else if (starts_with(p.index_position, "nin")) { // nine, ninth
1564 pos = 7;
1565 } else if (starts_with(p.index_position, "ten")) { // ten, tenth
1566 pos = 8;
1567 } else {
1568 try {
1569 pos = fc::to_uint64( p.index_position );
1570 } catch(...) {
1571 SYS_ASSERT( false, chain::contract_table_query_exception, "Invalid index_position: ${p}", ("p", p.index_position));
1572 }
1573 if (pos < 2) {
1574 primary = true;
1575 pos = 0;
1576 } else {
1577 pos -= 2;
1578 }
1579 }
1580 index |= (pos & 0x000000000000000FULL);
1581 return index;
1582}
1583
1584template<>
1585uint64_t convert_to_type(const string& str, const string& desc) {
1586
1587 try {
1588 return boost::lexical_cast<uint64_t>(str.c_str(), str.size());
1589 } catch( ... ) { }
1590
1591 try {
1592 auto trimmed_str = str;
1593 boost::trim(trimmed_str);
1594 name s(trimmed_str);
1595 return s.to_uint64_t();
1596 } catch( ... ) { }
1597
1598 if (str.find(',') != string::npos) { // fix #6274 only match formats like 4,SYS
1599 try {
1600 auto symb = sysio::chain::symbol::from_string(str);
1601 return symb.value();
1602 } catch( ... ) { }
1603 }
1604
1605 try {
1606 return ( sysio::chain::string_to_symbol( 0, str.c_str() ) >> 8 );
1607 } catch( ... ) {
1608 SYS_ASSERT( false, chain_type_exception, "Could not convert ${desc} string '${str}' to any of the following: "
1609 "uint64_t, valid name, or valid symbol (with or without the precision)",
1610 ("desc", desc)("str", str));
1611 }
1612}
1613
1614template<>
1615double convert_to_type(const string& str, const string& desc) {
1616 double val{};
1617 try {
1618 val = fc::variant(str).as<double>();
1619 } FC_RETHROW_EXCEPTIONS(warn, "Could not convert ${desc} string '${str}' to key type.", ("desc", desc)("str",str) )
1620
1621 SYS_ASSERT( !std::isnan(val), chain::contract_table_query_exception,
1622 "Converted ${desc} string '${str}' to NaN which is not a permitted value for the key type", ("desc", desc)("str",str) );
1623
1624 return val;
1625}
1626
1627template<typename Type>
1628string convert_to_string(const Type& source, const string& key_type, const string& encode_type, const string& desc) {
1629 try {
1630 return fc::variant(source).as<string>();
1631 } FC_RETHROW_EXCEPTIONS(warn, "Could not convert ${desc} from '${source}' to string.", ("desc", desc)("source",source) )
1632}
1633
1634template<>
1635string convert_to_string(const chain::key256_t& source, const string& key_type, const string& encode_type, const string& desc) {
1636 try {
1637 if (key_type == chain_apis::sha256 || (key_type == chain_apis::i256 && encode_type == chain_apis::hex)) {
1638 auto byte_array = fixed_bytes<32>(source).extract_as_byte_array();
1639 fc::sha256 val(reinterpret_cast<char *>(byte_array.data()), byte_array.size());
1640 return std::string(val);
1641 } else if (key_type == chain_apis::i256) {
1642 auto byte_array = fixed_bytes<32>(source).extract_as_byte_array();
1643 fc::sha256 val(reinterpret_cast<char *>(byte_array.data()), byte_array.size());
1644 return std::string("0x") + std::string(val);
1645 } else if (key_type == chain_apis::ripemd160) {
1646 auto byte_array = fixed_bytes<20>(source).extract_as_byte_array();
1647 fc::ripemd160 val;
1648 memcpy(val._hash, byte_array.data(), byte_array.size() );
1649 return std::string(val);
1650 }
1651 SYS_ASSERT( false, chain_type_exception, "Incompatible key_type and encode_type for key256_t next_key" );
1652
1653 } FC_RETHROW_EXCEPTIONS(warn, "Could not convert ${desc} source '${source}' to string.", ("desc", desc)("source",source) )
1654}
1655
1656template<>
1657string convert_to_string(const float128_t& source, const string& key_type, const string& encode_type, const string& desc) {
1658 try {
1660 return fc::variant(f).as<string>();
1661 } FC_RETHROW_EXCEPTIONS(warn, "Could not convert ${desc} from '${source}' to string.", ("desc", desc)("source",source) )
1662}
1663
1664abi_def get_abi( const controller& db, const name& account ) {
1665 const auto &d = db.db();
1666 const account_object *code_accnt = d.find<account_object, by_name>(account);
1667 SYS_ASSERT(code_accnt != nullptr, chain::account_query_exception, "Fail to retrieve account for ${account}", ("account", account) );
1668 abi_def abi;
1669 abi_serializer::to_abi(code_accnt->abi, abi);
1670 return abi;
1671}
1672
1673string get_table_type( const abi_def& abi, const name& table_name ) {
1674 for( const auto& t : abi.tables ) {
1675 if( t.name == table_name ){
1676 return t.index_type;
1677 }
1678 }
1679 SYS_ASSERT( false, chain::contract_table_query_exception, "Table ${table} is not specified in the ABI", ("table",table_name) );
1680}
1681
1683 const abi_def abi = sysio::chain_apis::get_abi( db, p.code );
1684 bool primary = false;
1685 auto table_with_index = get_table_index_name( p, primary );
1686 if( primary ) {
1687 SYS_ASSERT( p.table == table_with_index, chain::contract_table_query_exception, "Invalid table name ${t}", ( "t", p.table ));
1688 auto table_type = get_table_type( abi, p.table );
1689 if( table_type == KEYi64 || p.key_type == "i64" || p.key_type == "name" ) {
1690 return get_table_rows_ex<key_value_index>(p,abi);
1691 }
1692 SYS_ASSERT( false, chain::contract_table_query_exception, "Invalid table type ${type}", ("type",table_type)("abi",abi));
1693 } else {
1694 SYS_ASSERT( !p.key_type.empty(), chain::contract_table_query_exception, "key type required for non-primary index" );
1695
1696 if (p.key_type == chain_apis::i64 || p.key_type == "name") {
1697 return get_table_rows_by_seckey<index64_index, uint64_t>(p, abi, [](uint64_t v)->uint64_t {
1698 return v;
1699 });
1700 }
1701 else if (p.key_type == chain_apis::i128) {
1702 return get_table_rows_by_seckey<index128_index, uint128_t>(p, abi, [](uint128_t v)->uint128_t {
1703 return v;
1704 });
1705 }
1706 else if (p.key_type == chain_apis::i256) {
1707 if ( p.encode_type == chain_apis::hex) {
1709 return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, abi, conv::function());
1710 }
1712 return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, abi, conv::function());
1713 }
1714 else if (p.key_type == chain_apis::float64) {
1715 return get_table_rows_by_seckey<index_double_index, double>(p, abi, [](double v)->float64_t {
1716 float64_t f;
1717 double_to_float64(v, f);
1718 return f;
1719 });
1720 }
1721 else if (p.key_type == chain_apis::float128) {
1722 if ( p.encode_type == chain_apis::hex) {
1723 return get_table_rows_by_seckey<index_long_double_index, uint128_t>(p, abi, [](uint128_t v)->float128_t{
1724 float128_t f;
1726 return f;
1727 });
1728 }
1729 return get_table_rows_by_seckey<index_long_double_index, double>(p, abi, [](double v)->float128_t{
1730 float64_t f;
1731 double_to_float64(v, f);
1732 float128_t f128;
1733 f64_to_f128M(f, &f128);
1734 return f128;
1735 });
1736 }
1737 else if (p.key_type == chain_apis::sha256) {
1739 return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, abi, conv::function());
1740 }
1741 else if(p.key_type == chain_apis::ripemd160) {
1743 return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, abi, conv::function());
1744 }
1745 SYS_ASSERT(false, chain::contract_table_query_exception, "Unsupported secondary index type: ${t}", ("t", p.key_type));
1746 }
1747}
1748
1751 const auto& d = db.db();
1752
1753 const auto& idx = d.get_index<chain::table_id_multi_index, chain::by_code_scope_table>();
1754 auto lower_bound_lookup_tuple = std::make_tuple( p.code, name(std::numeric_limits<uint64_t>::lowest()), p.table );
1755 auto upper_bound_lookup_tuple = std::make_tuple( p.code, name(std::numeric_limits<uint64_t>::max()),
1756 (p.table.empty() ? name(std::numeric_limits<uint64_t>::max()) : p.table) );
1757
1758 if( p.lower_bound.size() ) {
1759 uint64_t scope = convert_to_type<uint64_t>(p.lower_bound, "lower_bound scope");
1760 std::get<1>(lower_bound_lookup_tuple) = name(scope);
1761 }
1762
1763 if( p.upper_bound.size() ) {
1764 uint64_t scope = convert_to_type<uint64_t>(p.upper_bound, "upper_bound scope");
1765 std::get<1>(upper_bound_lookup_tuple) = name(scope);
1766 }
1767
1768 if( upper_bound_lookup_tuple < lower_bound_lookup_tuple )
1769 return result;
1770
1771 auto walk_table_range = [&]( auto itr, auto end_itr ) {
1772 auto cur_time = fc::time_point::now();
1773 auto end_time = cur_time + fc::microseconds(1000 * 10);
1774 for( unsigned int count = 0; cur_time <= end_time && count < p.limit && itr != end_itr; ++itr, cur_time = fc::time_point::now() ) {
1775 if( p.table && itr->table != p.table ) continue;
1776
1777 result.rows.push_back( {itr->code, itr->scope, itr->table, itr->payer, itr->count} );
1778
1779 ++count;
1780 }
1781 if( itr != end_itr ) {
1782 result.more = itr->scope.to_string();
1783 }
1784 };
1785
1786 auto lower = idx.lower_bound( lower_bound_lookup_tuple );
1787 auto upper = idx.upper_bound( upper_bound_lookup_tuple );
1788 if( p.reverse && *p.reverse ) {
1789 walk_table_range( boost::make_reverse_iterator(upper), boost::make_reverse_iterator(lower) );
1790 } else {
1791 walk_table_range( lower, upper );
1792 }
1793
1794 return result;
1795}
1796
1797vector<asset> read_only::get_currency_balance( const read_only::get_currency_balance_params& p )const {
1798
1799 const abi_def abi = sysio::chain_apis::get_abi( db, p.code );
1800 (void)get_table_type( abi, name("accounts") );
1801
1803 walk_key_value_table(p.code, p.account, "accounts"_n, [&](const key_value_object& obj){
1804 SYS_ASSERT( obj.value.size() >= sizeof(asset), chain::asset_type_exception, "Invalid data on table");
1805
1806 asset cursor;
1807 fc::datastream<const char *> ds(obj.value.data(), obj.value.size());
1808 fc::raw::unpack(ds, cursor);
1809
1810 SYS_ASSERT( cursor.get_symbol().valid(), chain::asset_type_exception, "Invalid asset");
1811
1812 if( !p.symbol || boost::iequals(cursor.symbol_name(), *p.symbol) ) {
1813 results.emplace_back(cursor);
1814 }
1815
1816 // return false if we are looking for one and found it, true otherwise
1817 return !(p.symbol && boost::iequals(cursor.symbol_name(), *p.symbol));
1818 });
1819
1820 return results;
1821}
1822
1825
1826 const abi_def abi = sysio::chain_apis::get_abi( db, p.code );
1827 (void)get_table_type( abi, name("stat") );
1828
1829 uint64_t scope = ( sysio::chain::string_to_symbol( 0, boost::algorithm::to_upper_copy(p.symbol).c_str() ) >> 8 );
1830
1831 walk_key_value_table(p.code, name(scope), "stat"_n, [&](const key_value_object& obj){
1832 SYS_ASSERT( obj.value.size() >= sizeof(read_only::get_currency_stats_result), chain::asset_type_exception, "Invalid data on table");
1833
1836
1837 fc::raw::unpack(ds, result.supply);
1838 fc::raw::unpack(ds, result.max_supply);
1839 fc::raw::unpack(ds, result.issuer);
1840
1841 results[result.supply.symbol_name()] = result;
1842 return true;
1843 });
1844
1845 return results;
1846}
1847
1848fc::variant get_global_row( const database& db, const abi_def& abi, const abi_serializer& abis, const fc::microseconds& abi_serializer_max_time_us, bool shorten_abi_errors ) {
1849 const auto table_type = get_table_type(abi, "global"_n);
1850 SYS_ASSERT(table_type == read_only::KEYi64, chain::contract_table_query_exception, "Invalid table type ${type} for table global", ("type",table_type));
1851
1852 const auto* const table_id = db.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple(config::system_account_name, config::system_account_name, "global"_n));
1853 SYS_ASSERT(table_id, chain::contract_table_query_exception, "Missing table global");
1854
1855 const auto& kv_index = db.get_index<key_value_index, by_scope_primary>();
1856 const auto it = kv_index.find(boost::make_tuple(table_id->id, "global"_n.to_uint64_t()));
1857 SYS_ASSERT(it != kv_index.end(), chain::contract_table_query_exception, "Missing row in table global");
1858
1859 vector<char> data;
1860 read_only::copy_inline_row(*it, data);
1861 return abis.binary_to_variant(abis.get_table_type("global"_n), data, abi_serializer::create_yield_function( abi_serializer_max_time_us ), shorten_abi_errors );
1862}
1863
1865 const abi_def abi = sysio::chain_apis::get_abi(db, config::system_account_name);
1866 const auto table_type = get_table_type(abi, "producers"_n);
1868 SYS_ASSERT(table_type == KEYi64, chain::contract_table_query_exception, "Invalid table type ${type} for table producers", ("type",table_type));
1869
1870 const auto& d = db.db();
1871 const auto lower = name{p.lower_bound};
1872
1873 static const uint8_t secondary_index_num = 0;
1874 const auto* const table_id = d.find<chain::table_id_object, chain::by_code_scope_table>(
1875 boost::make_tuple(config::system_account_name, config::system_account_name, "producers"_n));
1876 const auto* const secondary_table_id = d.find<chain::table_id_object, chain::by_code_scope_table>(
1877 boost::make_tuple(config::system_account_name, config::system_account_name, name("producers"_n.to_uint64_t() | secondary_index_num)));
1878 SYS_ASSERT(table_id && secondary_table_id, chain::contract_table_query_exception, "Missing producers table");
1879
1880 const auto& kv_index = d.get_index<key_value_index, by_scope_primary>();
1881 const auto& secondary_index = d.get_index<index_double_index>().indices();
1882 const auto& secondary_index_by_primary = secondary_index.get<by_primary>();
1883 const auto& secondary_index_by_secondary = secondary_index.get<by_secondary>();
1884
1886 const auto stopTime = fc::time_point::now() + fc::microseconds(1000 * 10); // 10ms
1887 vector<char> data;
1888
1889 auto it = [&]{
1890 if(lower.to_uint64_t() == 0)
1891 return secondary_index_by_secondary.lower_bound(
1892 boost::make_tuple(secondary_table_id->id, to_softfloat64(std::numeric_limits<double>::lowest()), 0));
1893 else
1894 return secondary_index.project<by_secondary>(
1895 secondary_index_by_primary.lower_bound(
1896 boost::make_tuple(secondary_table_id->id, lower.to_uint64_t())));
1897 }();
1898
1899 for( ; it != secondary_index_by_secondary.end() && it->t_id == secondary_table_id->id; ++it ) {
1900 if (result.rows.size() >= p.limit || fc::time_point::now() > stopTime) {
1901 result.more = name{it->primary_key}.to_string();
1902 break;
1903 }
1904 copy_inline_row(*kv_index.find(boost::make_tuple(table_id->id, it->primary_key)), data);
1905 if (p.json)
1906 result.rows.emplace_back( abis.binary_to_variant( abis.get_table_type("producers"_n), data, abi_serializer::create_yield_function( abi_serializer_max_time ), shorten_abi_errors ) );
1907 else
1908 result.rows.emplace_back(fc::variant(data));
1909 }
1910
1911 result.total_producer_vote_weight = get_global_row(d, abi, abis, abi_serializer_max_time, shorten_abi_errors)["total_producer_vote_weight"].as_double();
1912 return result;
1913} catch (...) {
1915
1916 for (auto p : db.active_producers().producers) {
1917 auto row = fc::mutable_variant_object()
1918 ("owner", p.producer_name)
1919 ("producer_authority", p.authority)
1920 ("url", "")
1921 ("total_votes", 0.0f);
1922
1923 // detect a legacy key and maintain API compatibility for those entries
1924 if (std::holds_alternative<block_signing_authority_v0>(p.authority)) {
1925 const auto& auth = std::get<block_signing_authority_v0>(p.authority);
1926 if (auth.keys.size() == 1 && auth.keys.back().weight == auth.threshold) {
1927 row("producer_key", auth.keys.back().key);
1928 }
1929 }
1930
1931 result.rows.push_back(row);
1932 }
1933
1934 return result;
1935}
1936
1939 to_variant(db.active_producers(), result.active);
1940 if(!db.pending_producers().producers.empty())
1941 to_variant(db.pending_producers(), result.pending);
1942 auto proposed = db.proposed_producers();
1943 if(proposed && !proposed->producers.empty())
1944 to_variant(*proposed, result.proposed);
1945 return result;
1946}
1947
1948
1950 static auto make(const controller& control, abi_serializer::yield_function_t yield) {
1951 return [&control, yield{std::move(yield)}](const account_name &name) -> std::optional<abi_serializer> {
1952 const auto* accnt = control.db().template find<account_object, by_name>(name);
1953 if (accnt != nullptr) {
1954 abi_def abi;
1955 if (abi_serializer::to_abi(accnt->abi, abi)) {
1956 return abi_serializer(abi, yield);
1957 }
1958 }
1959 return std::optional<abi_serializer>();
1960 };
1961 }
1962};
1963
1965 return resolver_factory::make(control, std::move( yield ));
1966}
1967
1968read_only::get_scheduled_transactions_result
1970 const auto& d = db.db();
1971
1972 const auto& idx_by_delay = d.get_index<generated_transaction_multi_index,by_delay>();
1973 auto itr = ([&](){
1974 if (!p.lower_bound.empty()) {
1975 try {
1976 auto when = time_point::from_iso_string( p.lower_bound );
1977 return idx_by_delay.lower_bound(boost::make_tuple(when));
1978 } catch (...) {
1979 try {
1980 auto txid = transaction_id_type(p.lower_bound);
1981 const auto& by_txid = d.get_index<generated_transaction_multi_index,by_trx_id>();
1982 auto itr = by_txid.find( txid );
1983 if (itr == by_txid.end()) {
1984 SYS_THROW(transaction_exception, "Unknown Transaction ID: ${txid}", ("txid", txid));
1985 }
1986
1987 return d.get_index<generated_transaction_multi_index>().indices().project<by_delay>(itr);
1988
1989 } catch (...) {
1990 return idx_by_delay.end();
1991 }
1992 }
1993 } else {
1994 return idx_by_delay.begin();
1995 }
1996 })();
1997
1999
2000 auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time ));
2001
2002 uint32_t remaining = p.limit;
2003 auto time_limit = fc::time_point::now() + fc::microseconds(1000 * 10);
2004 while (itr != idx_by_delay.end() && remaining > 0 && time_limit > fc::time_point::now()) {
2005 auto row = fc::mutable_variant_object()
2006 ("trx_id", itr->trx_id)
2007 ("sender", itr->sender)
2008 ("sender_id", itr->sender_id)
2009 ("payer", itr->payer)
2010 ("delay_until", itr->delay_until)
2011 ("expiration", itr->expiration)
2012 ("published", itr->published)
2013 ;
2014
2015 if (p.json) {
2016 fc::variant pretty_transaction;
2017
2018 transaction trx;
2019 fc::datastream<const char*> ds( itr->packed_trx.data(), itr->packed_trx.size() );
2020 fc::raw::unpack(ds,trx);
2021
2022 abi_serializer::to_variant(trx, pretty_transaction, resolver, abi_serializer::create_yield_function( abi_serializer_max_time ));
2023 row("transaction", pretty_transaction);
2024 } else {
2025 auto packed_transaction = bytes(itr->packed_trx.begin(), itr->packed_trx.end());
2026 row("transaction", packed_transaction);
2027 }
2028
2029 result.transactions.emplace_back(std::move(row));
2030 ++itr;
2031 remaining--;
2032 }
2033
2034 if (itr != idx_by_delay.end()) {
2035 result.more = string(itr->trx_id);
2036 }
2037
2038 return result;
2039}
2040
2042 signed_block_ptr block;
2043 std::optional<uint64_t> block_num;
2044
2045 SYS_ASSERT( !params.block_num_or_id.empty() && params.block_num_or_id.size() <= 64,
2046 chain::block_id_type_exception,
2047 "Invalid Block number or ID, must be greater than 0 and less than 64 characters"
2048 );
2049
2050 try {
2051 block_num = fc::to_uint64(params.block_num_or_id);
2052 } catch( ... ) {}
2053
2054 if( block_num ) {
2055 block = db.fetch_block_by_number( *block_num );
2056 } else {
2057 try {
2058 block = db.fetch_block_by_id( fc::variant(params.block_num_or_id).as<block_id_type>() );
2059 } SYS_RETHROW_EXCEPTIONS(chain::block_id_type_exception, "Invalid block ID: ${block_num_or_id}", ("block_num_or_id", params.block_num_or_id))
2060 }
2061
2062 SYS_ASSERT( block, unknown_block_exception, "Could not find block: ${block}", ("block", params.block_num_or_id));
2063
2064 fc::variant pretty_output;
2065 abi_serializer::to_variant(*block, pretty_output, make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time )),
2066 abi_serializer::create_yield_function( abi_serializer_max_time ));
2067
2068 const auto block_id = block->calculate_id();
2069 uint32_t ref_block_prefix = block_id._hash[1];
2070
2071 return fc::mutable_variant_object(pretty_output.get_object())
2072 ("id", block_id)
2073 ("block_num",block->block_num())
2074 ("ref_block_prefix", ref_block_prefix);
2075}
2076
2078
2079 signed_block_ptr block;
2080 try {
2081 block = db.fetch_block_by_number( params.block_num );
2082 } catch (...) {
2083 // assert below will handle the invalid block num
2084 }
2085
2086 SYS_ASSERT( block, unknown_block_exception, "Could not find block: ${block}", ("block", params.block_num));
2087
2088 const auto id = block->calculate_id();
2089 const uint32_t ref_block_prefix = id._hash[1];
2090
2092 ("block_num", block->block_num())
2093 ("ref_block_num", static_cast<uint16_t>(block->block_num()))
2094 ("id", id)
2095 ("timestamp", block->timestamp)
2096 ("producer", block->producer)
2097 ("confirmed", block->confirmed)
2098 ("previous", block->previous)
2099 ("transaction_mroot", block->transaction_mroot)
2100 ("action_mroot", block->action_mroot)
2101 ("schedule_version", block->schedule_version)
2102 ("producer_signature", block->producer_signature)
2103 ("ref_block_prefix", ref_block_prefix);
2104}
2105
2108 std::optional<uint64_t> block_num;
2109 std::exception_ptr e;
2110 try {
2111 block_num = fc::to_uint64(params.block_num_or_id);
2112 } catch( ... ) {}
2113
2114 if( block_num ) {
2115 b = db.fetch_block_state_by_number(*block_num);
2116 } else {
2117 try {
2118 b = db.fetch_block_state_by_id(fc::variant(params.block_num_or_id).as<block_id_type>());
2119 } SYS_RETHROW_EXCEPTIONS(chain::block_id_type_exception, "Invalid block ID: ${block_num_or_id}", ("block_num_or_id", params.block_num_or_id))
2120 }
2121
2122 SYS_ASSERT( b, unknown_block_exception, "Could not find reversible block: ${block}", ("block", params.block_num_or_id));
2123
2124 fc::variant vo;
2125 fc::to_variant( static_cast<const block_header_state&>(*b), vo );
2126 return vo;
2127}
2128
2130 try {
2131 app().get_method<incoming::methods::block_sync>()(std::make_shared<signed_block>( std::move(params) ), std::optional<block_id_type>{}, block_state_ptr{});
2132 } catch ( boost::interprocess::bad_alloc& ) {
2134 } catch ( const std::bad_alloc& ) {
2136 } FC_LOG_AND_DROP()
2138}
2139
2141 try {
2142 auto pretty_input = std::make_shared<packed_transaction>();
2143 auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time ));
2144 try {
2145 abi_serializer::from_variant(params, *pretty_input, std::move( resolver ), abi_serializer::create_yield_function( abi_serializer_max_time ));
2146 } SYS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction")
2147
2148 app().get_method<incoming::methods::transaction_async>()(pretty_input, true, false, false,
2149 [this, next](const std::variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void {
2150 if (std::holds_alternative<fc::exception_ptr>(result)) {
2151 next(std::get<fc::exception_ptr>(result));
2152 } else {
2153 auto trx_trace_ptr = std::get<transaction_trace_ptr>(result);
2154
2155 try {
2156 fc::variant output;
2157 try {
2158 output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer::create_yield_function( abi_serializer_max_time ) );
2159
2160 // Create map of (closest_unnotified_ancestor_action_ordinal, global_sequence) with action trace
2161 std::map< std::pair<uint32_t, uint64_t>, fc::mutable_variant_object > act_traces_map;
2162 for( const auto& act_trace : output["action_traces"].get_array() ) {
2163 if (act_trace["receipt"].is_null() && act_trace["except"].is_null()) continue;
2164 auto closest_unnotified_ancestor_action_ordinal =
2165 act_trace["closest_unnotified_ancestor_action_ordinal"].as<fc::unsigned_int>().value;
2166 auto global_sequence = act_trace["receipt"].is_null() ?
2167 std::numeric_limits<uint64_t>::max() :
2168 act_trace["receipt"]["global_sequence"].as<uint64_t>();
2169 act_traces_map.emplace( std::make_pair( closest_unnotified_ancestor_action_ordinal,
2170 global_sequence ),
2171 act_trace.get_object() );
2172 }
2173
2174 std::function<vector<fc::variant>(uint32_t)> convert_act_trace_to_tree_struct =
2175 [&](uint32_t closest_unnotified_ancestor_action_ordinal) {
2176 vector<fc::variant> restructured_act_traces;
2177 auto it = act_traces_map.lower_bound(
2178 std::make_pair( closest_unnotified_ancestor_action_ordinal, 0)
2179 );
2180 for( ;
2181 it != act_traces_map.end() && it->first.first == closest_unnotified_ancestor_action_ordinal; ++it )
2182 {
2183 auto& act_trace_mvo = it->second;
2184
2185 auto action_ordinal = act_trace_mvo["action_ordinal"].as<fc::unsigned_int>().value;
2186 act_trace_mvo["inline_traces"] = convert_act_trace_to_tree_struct(action_ordinal);
2187 if (act_trace_mvo["receipt"].is_null()) {
2188 act_trace_mvo["receipt"] = fc::mutable_variant_object()
2189 ("abi_sequence", 0)
2190 ("act_digest", digest_type::hash(trx_trace_ptr->action_traces[action_ordinal-1].act))
2191 ("auth_sequence", flat_map<account_name,uint64_t>())
2192 ("code_sequence", 0)
2193 ("global_sequence", 0)
2194 ("receiver", act_trace_mvo["receiver"])
2195 ("recv_sequence", 0);
2196 }
2197 restructured_act_traces.push_back( std::move(act_trace_mvo) );
2198 }
2199 return restructured_act_traces;
2200 };
2201
2202 fc::mutable_variant_object output_mvo(output);
2203 output_mvo["action_traces"] = convert_act_trace_to_tree_struct(0);
2204
2205 output = output_mvo;
2206 } catch( chain::abi_exception& ) {
2207 output = *trx_trace_ptr;
2208 }
2209
2210 const chain::transaction_id_type& id = trx_trace_ptr->id;
2212 } CATCH_AND_CALL(next);
2213 }
2214 });
2215 } catch ( boost::interprocess::bad_alloc& ) {
2217 } catch ( const std::bad_alloc& ) {
2219 } CATCH_AND_CALL(next);
2220}
2221
2222static void push_recurse(read_write* rw, int index, const std::shared_ptr<read_write::push_transactions_params>& params, const std::shared_ptr<read_write::push_transactions_results>& results, const next_function<read_write::push_transactions_results>& next) {
2223 auto wrapped_next = [=](const std::variant<fc::exception_ptr, read_write::push_transaction_results>& result) {
2224 if (std::holds_alternative<fc::exception_ptr>(result)) {
2225 const auto& e = std::get<fc::exception_ptr>(result);
2226 results->emplace_back( read_write::push_transaction_results{ transaction_id_type(), fc::mutable_variant_object( "error", e->to_detail_string() ) } );
2227 } else {
2228 const auto& r = std::get<read_write::push_transaction_results>(result);
2229 results->emplace_back( r );
2230 }
2231
2232 size_t next_index = index + 1;
2233 if (next_index < params->size()) {
2234 push_recurse(rw, next_index, params, results, next );
2235 } else {
2236 next(*results);
2237 }
2238 };
2239
2240 rw->push_transaction(params->at(index), wrapped_next);
2241}
2242
2244 try {
2245 SYS_ASSERT( params.size() <= 1000, too_many_tx_at_once, "Attempt to push too many transactions at once" );
2246 auto params_copy = std::make_shared<read_write::push_transactions_params>(params.begin(), params.end());
2247 auto result = std::make_shared<read_write::push_transactions_results>();
2248 result->reserve(params.size());
2249
2250 push_recurse(this, 0, params_copy, result, next);
2251 } catch ( boost::interprocess::bad_alloc& ) {
2253 } catch ( const std::bad_alloc& ) {
2255 } CATCH_AND_CALL(next);
2256}
2257
2259
2260 try {
2261 auto pretty_input = std::make_shared<packed_transaction>();
2262 auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time ));
2263 try {
2264 abi_serializer::from_variant(params, *pretty_input, resolver, abi_serializer::create_yield_function( abi_serializer_max_time ));
2265 } SYS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction")
2266
2267 app().get_method<incoming::methods::transaction_async>()(pretty_input, true, false, false,
2268 [this, next](const std::variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void {
2269 if (std::holds_alternative<fc::exception_ptr>(result)) {
2270 next(std::get<fc::exception_ptr>(result));
2271 } else {
2272 auto trx_trace_ptr = std::get<transaction_trace_ptr>(result);
2273
2274 try {
2275 fc::variant output;
2276 try {
2277 output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer::create_yield_function( abi_serializer_max_time ) );
2278 } catch( chain::abi_exception& ) {
2279 output = *trx_trace_ptr;
2280 }
2281
2282 const chain::transaction_id_type& id = trx_trace_ptr->id;
2284 } CATCH_AND_CALL(next);
2285 }
2286 });
2287 } catch ( boost::interprocess::bad_alloc& ) {
2289 } catch ( const std::bad_alloc& ) {
2291 } CATCH_AND_CALL(next);
2292}
2293
2295 try {
2296 auto ptrx = std::make_shared<packed_transaction>();
2297 auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time ));
2298 try {
2299 abi_serializer::from_variant(params.transaction, *ptrx, resolver, abi_serializer::create_yield_function( abi_serializer_max_time ));
2300 } SYS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction")
2301
2302 bool retry = params.retry_trx;
2303 std::optional<uint16_t> retry_num_blocks = params.retry_trx_num_blocks;
2304
2305 SYS_ASSERT( !retry || trx_retry.has_value(), unsupported_feature, "Transaction retry not enabled on node" );
2306 SYS_ASSERT( !retry || (ptrx->expiration() <= trx_retry->get_max_expiration_time()), tx_exp_too_far_exception,
2307 "retry transaction expiration ${e} larger than allowed ${m}",
2308 ("e", ptrx->expiration())("m", trx_retry->get_max_expiration_time()) );
2309
2310 app().get_method<incoming::methods::transaction_async>()(ptrx, true, false, static_cast<bool>(params.return_failure_trace),
2311 [this, ptrx, next, retry, retry_num_blocks](const std::variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void {
2312 if( std::holds_alternative<fc::exception_ptr>( result ) ) {
2313 next( std::get<fc::exception_ptr>( result ) );
2314 } else {
2315 try {
2316 auto trx_trace_ptr = std::get<transaction_trace_ptr>( result );
2317 if( retry && trx_retry.has_value() && !trx_trace_ptr->except) {
2318 // will be ack'ed via next later
2319 trx_retry->track_transaction( ptrx, retry_num_blocks,
2320 [ptrx, next](const std::variant<fc::exception_ptr, std::unique_ptr<fc::variant>>& result ) {
2321 if( std::holds_alternative<fc::exception_ptr>( result ) ) {
2322 next( std::get<fc::exception_ptr>( result ) );
2323 } else {
2324 fc::variant& output = *std::get<std::unique_ptr<fc::variant>>( result );
2325 next( read_write::send_transaction_results{ptrx->id(), std::move( output )} );
2326 }
2327 } );
2328 } else {
2329 fc::variant output;
2330 try {
2331 output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer::create_yield_function( abi_serializer_max_time ) );
2332 } catch( chain::abi_exception& ) {
2333 output = *trx_trace_ptr;
2334 }
2335 const chain::transaction_id_type& id = trx_trace_ptr->id;
2336 next( read_write::send_transaction_results{id, std::move( output )} );
2337 }
2338 } CATCH_AND_CALL( next );
2339 }
2340 });
2341 } catch ( boost::interprocess::bad_alloc& ) {
2343 } catch ( const std::bad_alloc& ) {
2345 } CATCH_AND_CALL(next);
2346}
2347
2348read_only::get_abi_results read_only::get_abi( const get_abi_params& params )const {
2349 get_abi_results result;
2350 result.account_name = params.account_name;
2351 const auto& d = db.db();
2352 const auto& accnt = d.get<account_object,by_name>( params.account_name );
2353
2354 abi_def abi;
2355 if( abi_serializer::to_abi(accnt.abi, abi) ) {
2356 result.abi = std::move(abi);
2357 }
2358
2359 return result;
2360}
2361
2362read_only::get_code_results read_only::get_code( const get_code_params& params )const {
2363 get_code_results result;
2364 result.account_name = params.account_name;
2365 const auto& d = db.db();
2366 const auto& accnt_obj = d.get<account_object,by_name>( params.account_name );
2367 const auto& accnt_metadata_obj = d.get<account_metadata_object,by_name>( params.account_name );
2368
2369 SYS_ASSERT( params.code_as_wasm, unsupported_feature, "Returning WAST from get_code is no longer supported" );
2370
2371 if( accnt_metadata_obj.code_hash != digest_type() ) {
2372 const auto& code_obj = d.get<code_object, by_code_hash>(accnt_metadata_obj.code_hash);
2373 result.wasm = string(code_obj.code.begin(), code_obj.code.end());
2374 result.code_hash = code_obj.code_hash;
2375 }
2376
2377 abi_def abi;
2378 if( abi_serializer::to_abi(accnt_obj.abi, abi) ) {
2379 result.abi = std::move(abi);
2380 }
2381
2382 return result;
2383}
2384
2385read_only::get_code_hash_results read_only::get_code_hash( const get_code_hash_params& params )const {
2386 get_code_hash_results result;
2387 result.account_name = params.account_name;
2388 const auto& d = db.db();
2389 const auto& accnt = d.get<account_metadata_object,by_name>( params.account_name );
2390
2391 if( accnt.code_hash != digest_type() )
2392 result.code_hash = accnt.code_hash;
2393
2394 return result;
2395}
2396
2399 result.account_name = params.account_name;
2400
2401 const auto& d = db.db();
2402 const auto& accnt_obj = d.get<account_object,by_name>(params.account_name);
2403 const auto& accnt_metadata_obj = d.get<account_metadata_object,by_name>(params.account_name);
2404 if( accnt_metadata_obj.code_hash != digest_type() ) {
2405 const auto& code_obj = d.get<code_object, by_code_hash>(accnt_metadata_obj.code_hash);
2406 result.wasm = blob{{code_obj.code.begin(), code_obj.code.end()}};
2407 }
2408 result.abi = blob{{accnt_obj.abi.begin(), accnt_obj.abi.end()}};
2409
2410 return result;
2411}
2412
2413read_only::get_raw_abi_results read_only::get_raw_abi( const get_raw_abi_params& params )const {
2414 get_raw_abi_results result;
2415 result.account_name = params.account_name;
2416
2417 const auto& d = db.db();
2418 const auto& accnt_obj = d.get<account_object,by_name>(params.account_name);
2419 const auto& accnt_metadata_obj = d.get<account_metadata_object,by_name>(params.account_name);
2420 result.abi_hash = fc::sha256::hash( accnt_obj.abi.data(), accnt_obj.abi.size() );
2421 if( accnt_metadata_obj.code_hash != digest_type() )
2422 result.code_hash = accnt_metadata_obj.code_hash;
2423 if( !params.abi_hash || *params.abi_hash != result.abi_hash )
2424 result.abi = blob{{accnt_obj.abi.begin(), accnt_obj.abi.end()}};
2425
2426 return result;
2427}
2428
2429read_only::get_account_results read_only::get_account( const get_account_params& params )const {
2430 get_account_results result;
2431 result.account_name = params.account_name;
2432
2433 const auto& d = db.db();
2434 const auto& rm = db.get_resource_limits_manager();
2435
2436 result.head_block_num = db.head_block_num();
2437 result.head_block_time = db.head_block_time();
2438
2439 rm.get_account_limits( result.account_name, result.ram_quota, result.net_weight, result.cpu_weight );
2440
2441 const auto& accnt_obj = db.get_account( result.account_name );
2442 const auto& accnt_metadata_obj = db.db().get<account_metadata_object,by_name>( result.account_name );
2443
2444 result.privileged = accnt_metadata_obj.is_privileged();
2445 result.last_code_update = accnt_metadata_obj.last_code_update;
2446 result.created = accnt_obj.creation_date;
2447
2448 uint32_t greylist_limit = db.is_resource_greylisted(result.account_name) ? 1 : config::maximum_elastic_resource_multiplier;
2449 result.net_limit = rm.get_account_net_limit_ex( result.account_name, greylist_limit).first;
2450 result.cpu_limit = rm.get_account_cpu_limit_ex( result.account_name, greylist_limit).first;
2451 result.ram_usage = rm.get_account_ram_usage( result.account_name );
2452
2453 if ( producer_plug ) { // producer_plug is null when called from chain_plugin_tests.cpp and get_table_tests.cpp
2454 account_resource_limit subjective_cpu_bill_limit;
2455 subjective_cpu_bill_limit.used = producer_plug->get_subjective_bill( result.account_name, fc::time_point::now() );
2456 result.subjective_cpu_bill_limit = subjective_cpu_bill_limit;
2457 }
2458
2459 const auto linked_action_map = ([&](){
2460 const auto& links = d.get_index<permission_link_index,by_permission_name>();
2461 auto iter = links.lower_bound( boost::make_tuple( params.account_name ) );
2462
2463 std::multimap<name, linked_action> result;
2464 while (iter != links.end() && iter->account == params.account_name ) {
2465 auto action = iter->message_type.empty() ? std::optional<name>() : std::optional<name>(iter->message_type);
2466 result.emplace(std::make_pair(iter->required_permission, linked_action{iter->code, std::move(action)}));
2467 ++iter;
2468 }
2469
2470 return result;
2471 })();
2472
2473 auto get_linked_actions = [&](chain::name perm_name) {
2474 auto link_bounds = linked_action_map.equal_range(perm_name);
2475 auto linked_actions = std::vector<linked_action>();
2476 linked_actions.reserve(linked_action_map.count(perm_name));
2477 for (auto link = link_bounds.first; link != link_bounds.second; ++link) {
2478 linked_actions.push_back(link->second);
2479 }
2480 return linked_actions;
2481 };
2482
2483 const auto& permissions = d.get_index<permission_index,by_owner>();
2484 auto perm = permissions.lower_bound( boost::make_tuple( params.account_name ) );
2485 while( perm != permissions.end() && perm->owner == params.account_name ) {
2487 name parent;
2488
2489 // Don't lookup parent if null
2490 if( perm->parent._id ) {
2491 const auto* p = d.find<permission_object,by_id>( perm->parent );
2492 if( p ) {
2493 SYS_ASSERT(perm->owner == p->owner, invalid_parent_permission, "Invalid parent permission");
2494 parent = p->name;
2495 }
2496 }
2497
2498 auto linked_actions = get_linked_actions(perm->name);
2499
2500 result.permissions.push_back( permission{ perm->name, parent, perm->auth.to_authority(), std::move(linked_actions)} );
2501 ++perm;
2502 }
2503
2504 // add sysio.any linked authorizations
2505 result.sysio_any_linked_actions = get_linked_actions(chain::config::sysio_any_name);
2506
2507 const auto& code_account = db.db().get<account_object,by_name>( config::system_account_name );
2508
2509 abi_def abi;
2510 if( abi_serializer::to_abi(code_account.abi, abi) ) {
2512
2513 const auto token_code = "sysio.token"_n;
2514
2515 auto core_symbol = extract_core_symbol();
2516
2517 if (params.expected_core_symbol)
2518 core_symbol = *(params.expected_core_symbol);
2519
2520 const auto* t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple( token_code, params.account_name, "accounts"_n ));
2521 if( t_id != nullptr ) {
2522 const auto &idx = d.get_index<key_value_index, by_scope_primary>();
2523 auto it = idx.find(boost::make_tuple( t_id->id, core_symbol.to_symbol_code() ));
2524 if( it != idx.end() && it->value.size() >= sizeof(asset) ) {
2525 asset bal;
2526 fc::datastream<const char *> ds(it->value.data(), it->value.size());
2527 fc::raw::unpack(ds, bal);
2528
2529 if( bal.get_symbol().valid() && bal.get_symbol() == core_symbol ) {
2530 result.core_liquid_balance = bal;
2531 }
2532 }
2533 }
2534
2535 t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple( config::system_account_name, params.account_name, "userres"_n ));
2536 if (t_id != nullptr) {
2537 const auto &idx = d.get_index<key_value_index, by_scope_primary>();
2538 auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() ));
2539 if ( it != idx.end() ) {
2540 vector<char> data;
2541 copy_inline_row(*it, data);
2542 result.total_resources = abis.binary_to_variant( "user_resources", data, abi_serializer::create_yield_function( abi_serializer_max_time ), shorten_abi_errors );
2543 }
2544 }
2545
2546 t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple( config::system_account_name, params.account_name, "delband"_n ));
2547 if (t_id != nullptr) {
2548 const auto &idx = d.get_index<key_value_index, by_scope_primary>();
2549 auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() ));
2550 if ( it != idx.end() ) {
2551 vector<char> data;
2552 copy_inline_row(*it, data);
2553 result.self_delegated_bandwidth = abis.binary_to_variant( "delegated_bandwidth", data, abi_serializer::create_yield_function( abi_serializer_max_time ), shorten_abi_errors );
2554 }
2555 }
2556
2557 t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple( config::system_account_name, params.account_name, "refunds"_n ));
2558 if (t_id != nullptr) {
2559 const auto &idx = d.get_index<key_value_index, by_scope_primary>();
2560 auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() ));
2561 if ( it != idx.end() ) {
2562 vector<char> data;
2563 copy_inline_row(*it, data);
2564 result.refund_request = abis.binary_to_variant( "refund_request", data, abi_serializer::create_yield_function( abi_serializer_max_time ), shorten_abi_errors );
2565 }
2566 }
2567
2568 t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple( config::system_account_name, config::system_account_name, "voters"_n ));
2569 if (t_id != nullptr) {
2570 const auto &idx = d.get_index<key_value_index, by_scope_primary>();
2571 auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() ));
2572 if ( it != idx.end() ) {
2573 vector<char> data;
2574 copy_inline_row(*it, data);
2575 result.voter_info = abis.binary_to_variant( "voter_info", data, abi_serializer::create_yield_function( abi_serializer_max_time ), shorten_abi_errors );
2576 }
2577 }
2578
2579 t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple( config::system_account_name, config::system_account_name, "rexbal"_n ));
2580 if (t_id != nullptr) {
2581 const auto &idx = d.get_index<key_value_index, by_scope_primary>();
2582 auto it = idx.find(boost::make_tuple( t_id->id, params.account_name.to_uint64_t() ));
2583 if( it != idx.end() ) {
2584 vector<char> data;
2585 copy_inline_row(*it, data);
2586 result.rex_info = abis.binary_to_variant( "rex_balance", data, abi_serializer::create_yield_function( abi_serializer_max_time ), shorten_abi_errors );
2587 }
2588 }
2589 }
2590 return result;
2591}
2592
2593static fc::variant action_abi_to_variant( const abi_def& abi, type_name action_type ) {
2594 fc::variant v;
2595 auto it = std::find_if(abi.structs.begin(), abi.structs.end(), [&](auto& x){return x.name == action_type;});
2596 if( it != abi.structs.end() )
2597 to_variant( it->fields, v );
2598 return v;
2599};
2600
2603 const auto code_account = db.db().find<account_object,by_name>( params.code );
2604 SYS_ASSERT(code_account != nullptr, contract_query_exception, "Contract can't be found ${contract}", ("contract", params.code));
2605
2606 abi_def abi;
2607 if( abi_serializer::to_abi(code_account->abi, abi) ) {
2609 auto action_type = abis.get_action_type(params.action);
2610 SYS_ASSERT(!action_type.empty(), action_validate_exception, "Unknown action ${action} in contract ${contract}", ("action", params.action)("contract", params.code));
2611 try {
2612 result.binargs = abis.variant_to_binary( action_type, params.args, abi_serializer::create_yield_function( abi_serializer_max_time ), shorten_abi_errors );
2613 } SYS_RETHROW_EXCEPTIONS(chain::invalid_action_args_exception,
2614 "'${args}' is invalid args for action '${action}' code '${code}'. expected '${proto}'",
2615 ("args", params.args)("action", params.action)("code", params.code)("proto", action_abi_to_variant(abi, action_type)))
2616 } else {
2617 SYS_ASSERT(false, abi_not_found_exception, "No ABI found for ${contract}", ("contract", params.code));
2618 }
2619 return result;
2620} FC_RETHROW_EXCEPTIONS( warn, "code: ${code}, action: ${action}, args: ${args}",
2621 ("code", params.code)( "action", params.action )( "args", params.args ))
2622
2623read_only::abi_bin_to_json_result read_only::abi_bin_to_json( const read_only::abi_bin_to_json_params& params )const {
2624 abi_bin_to_json_result result;
2625 const auto& code_account = db.db().get<account_object,by_name>( params.code );
2626 abi_def abi;
2627 if( abi_serializer::to_abi(code_account.abi, abi) ) {
2628 abi_serializer abis( abi, abi_serializer::create_yield_function( abi_serializer_max_time ) );
2629 result.args = abis.binary_to_variant( abis.get_action_type( params.action ), params.binargs, abi_serializer::create_yield_function( abi_serializer_max_time ), shorten_abi_errors );
2630 } else {
2631 SYS_ASSERT(false, abi_not_found_exception, "No ABI found for ${contract}", ("contract", params.code));
2632 }
2633 return result;
2634}
2635
2636read_only::get_required_keys_result read_only::get_required_keys( const get_required_keys_params& params )const {
2637 transaction pretty_input;
2638 auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time ));
2639 try {
2641 } SYS_RETHROW_EXCEPTIONS(chain::transaction_type_exception, "Invalid transaction")
2642
2643 auto required_keys_set = db.get_authorization_manager().get_required_keys( pretty_input, params.available_keys, fc::seconds( pretty_input.delay_sec ));
2644 get_required_keys_result result;
2645 result.required_keys = required_keys_set;
2646 return result;
2647}
2648void read_only::compute_transaction(const compute_transaction_params& params, next_function<compute_transaction_results> next) const {
2649
2650 try {
2651 auto pretty_input = std::make_shared<packed_transaction>();
2652 auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time ));
2653 try {
2655 } SYS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction")
2656
2657 app().get_method<incoming::methods::transaction_async>()(pretty_input, false, true, true,
2658 [this, next](const std::variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void {
2659 if (std::holds_alternative<fc::exception_ptr>(result)) {
2660 next(std::get<fc::exception_ptr>(result));
2661 } else {
2662 auto trx_trace_ptr = std::get<transaction_trace_ptr>(result);
2663
2664 try {
2665 fc::variant output;
2666 try {
2667 output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer::create_yield_function( abi_serializer_max_time ) );
2668 } catch( chain::abi_exception& ) {
2669 output = *trx_trace_ptr;
2670 }
2671
2672 const chain::transaction_id_type& id = trx_trace_ptr->id;
2673 next(compute_transaction_results{id, output});
2674 } CATCH_AND_CALL(next);
2675 }
2676 });
2677 } catch ( boost::interprocess::bad_alloc& ) {
2679 } catch ( const std::bad_alloc& ) {
2681 } CATCH_AND_CALL(next);
2682}
2683read_only::get_transaction_id_result read_only::get_transaction_id( const read_only::get_transaction_id_params& params)const {
2684 return params.id();
2685}
2686
2687
2688account_query_db::get_accounts_by_authorizers_result read_only::get_accounts_by_authorizers( const account_query_db::get_accounts_by_authorizers_params& args) const
2689{
2690 SYS_ASSERT(aqdb.has_value(), plugin_config_exception, "Account Queries being accessed when not enabled");
2691 return aqdb->get_accounts_by_authorizers(args);
2692}
2693
2694namespace detail {
2695 struct ram_market_exchange_state_t {
2696 asset ignore1;
2697 asset ignore2;
2698 double ignore3;
2699 asset core_symbol;
2700 double ignore4;
2701 };
2702}
2703
2704chain::symbol read_only::extract_core_symbol()const {
2705 symbol core_symbol(0);
2706
2707 // The following code makes assumptions about the contract deployed on sysio account (i.e. the system contract) and how it stores its data.
2708 const auto& d = db.db();
2709 const auto* t_id = d.find<chain::table_id_object, chain::by_code_scope_table>(boost::make_tuple( "sysio"_n, "sysio"_n, "rammarket"_n ));
2710 if( t_id != nullptr ) {
2711 const auto &idx = d.get_index<key_value_index, by_scope_primary>();
2712 auto it = idx.find(boost::make_tuple( t_id->id, sysio::chain::string_to_symbol_c(4,"RAMCORE") ));
2713 if( it != idx.end() ) {
2714 detail::ram_market_exchange_state_t ram_market_exchange_state;
2715
2716 fc::datastream<const char *> ds( it->value.data(), it->value.size() );
2717
2718 try {
2719 fc::raw::unpack(ds, ram_market_exchange_state);
2720 } catch( ... ) {
2721 return core_symbol;
2722 }
2723
2724 if( ram_market_exchange_state.core_symbol.get_symbol().valid() ) {
2725 core_symbol = ram_market_exchange_state.core_symbol.get_symbol();
2726 }
2727 }
2728 }
2729
2730 return core_symbol;
2731}
2732
2733} // namespace chain_apis
2734
2736 fc::variant pretty_output;
2737 try {
2738 abi_serializer::to_log_variant(trx_trace, pretty_output,
2741 } catch (...) {
2742 pretty_output = trx_trace;
2743 }
2744 return pretty_output;
2745}
2746
2748 fc::variant pretty_output;
2749 try {
2750 abi_serializer::to_log_variant(trx, pretty_output,
2753 } catch (...) {
2754 pretty_output = trx;
2755 }
2756 return pretty_output;
2757}
2758} // namespace sysio
2759
2760FC_REFLECT( sysio::chain_apis::detail::ram_market_exchange_state_t, (ignore1)(ignore2)(ignore3)(core_symbol)(ignore4) )
const mie::Vuint & p
Definition bn.cpp:27
const mie::Vuint & r
Definition bn.cpp:28
std::string name
#define SYS_THROW(exc_type, FORMAT,...)
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
Definition exceptions.hpp:7
#define SYS_RETHROW_EXCEPTIONS(exception_type, FORMAT,...)
#define CATCH_AND_CALL(NEXT)
FC_REFLECT_ENUM(chainbase::environment::os_t,(OS_LINUX)(OS_MACOS)(OS_WINDOWS)(OS_OTHER)) FC_REFLECT_ENUM(chainbase sysio::chain::deep_mind_handler _deep_mind_log
#define LOAD_VALUE_SET(options, op_name, container)
abstract_plugin * find_plugin(const string &name) const
bfs::path data_dir() const
Get data directory.
string version_string() const
Get version string; generated from git describe if available.
auto get_method() -> std::enable_if_t< is_method_decl< MethodDecl >::value, typename MethodDecl::method_type & >
bfs::path config_dir() const
Get config directory.
bool is_quiting() const
string full_version_string() const
Get full version string; same as version_string() unless set differently.
void publish(int priority, const Data &data)
virtual void shutdown() override
const generic_index< MultiIndexType > & get_index() const
const ObjectType * find(CompatibleKey &&key) const
static bool supports_hole_punching()
Definition cfile.hpp:182
Used to generate a useful error report when an exception is thrown.
Definition exception.hpp:58
std::string to_detail_string(log_level ll=log_level::all) const
static variant from_file(const fc::path &p, const parse_type ptype=parse_type::legacy_parser, const uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
Definition json.cpp:797
static bool save_to_file(const T &v, const fc::path &fi, const bool pretty=true, const output_formatting format=output_formatting::stringify_large_ints_and_doubles)
Definition json.hpp:45
static string to_pretty_string(const variant &v, const yield_function_t &yield, const output_formatting format=output_formatting::stringify_large_ints_and_doubles)
Definition json.cpp:775
static variant from_string(const string &utf8_str, const parse_type ptype=parse_type::legacy_parser, uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
Definition json.cpp:442
constexpr int64_t count() const
Definition time.hpp:26
An order-preserving dictionary of variants.
wraps boost::filesystem::path to provide platform independent path manipulation.
uint32_t _hash[5]
Definition ripemd160.hpp:71
static sha256 hash(const char *d, uint32_t dlen)
Definition sha256.cpp:44
static time_point now()
Definition time.cpp:14
constexpr const microseconds & time_since_epoch() const
Definition time.hpp:52
static time_point from_iso_string(const fc::string &s)
Definition time.cpp:67
An order-preserving dictionary of variants.
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition variant.hpp:191
variant_object & get_object()
Definition variant.cpp:554
double as_double() const
Definition variant.cpp:420
T as() const
Definition variant.hpp:327
static std::optional< genesis_state > extract_genesis_state(const fc::path &data_dir)
static fc::path repair_log(const fc::path &data_dir, uint32_t truncate_at_block=0, const char *reversible_block_dir_name="")
static chain_id_type extract_chain_id(const fc::path &data_dir)
block_state_ptr fetch_block_state_by_number(uint32_t block_num) const
const chainbase::database & db() const
signed_block_ptr fetch_block_by_number(uint32_t block_num) const
static std::optional< chain_id_type > extract_chain_id_from_db(const path &state_dir)
static chain_id_type extract_chain_id(snapshot_reader &snapshot)
std::optional< producer_authority_schedule > proposed_producers() const
const producer_authority_schedule & pending_producers() const
signed_block_ptr fetch_block_by_id(block_id_type id) const
block_state_ptr fetch_block_state_by_id(block_id_type id) const
const producer_authority_schedule & active_producers() const
fc::variant to_variant_with_abi(const T &obj, const abi_serializer::yield_function_t &yield) const
void update_logger(const std::string &logger_name)
Definition deep_mind.cpp:34
static builtin_protocol_feature make_default_builtin_protocol_feature(builtin_protocol_feature_t codename, const std::function< digest_type(builtin_protocol_feature_t dependency)> &handle_dependency)
const protocol_feature & add_feature(const builtin_protocol_feature &f)
bool valid() const
Definition symbol.hpp:83
static symbol from_string(const string &from)
Definition symbol.hpp:68
The table_id_object class tracks the mapping of (scope, code, table) to an opaque identifier.
static std::string vm_type_string(vm_type vmtype)
void walk_key_value_table(const name &code, const name &scope, const name &table, Function f) const
static void copy_inline_row(const chain::key_value_object &obj, vector< char > &data)
static const string KEYi64
fc::variant get_block_info(const get_block_info_params &params) const
fc::variant get_block(const get_block_params &params) const
fc::variant get_currency_stats(const get_currency_stats_params &params) const
get_producers_result get_producers(const get_producers_params &params) const
get_scheduled_transactions_result get_scheduled_transactions(const get_scheduled_transactions_params &params) const
fc::variant get_block_header_state(const get_block_header_state_params &params) const
get_producer_schedule_result get_producer_schedule(const get_producer_schedule_params &params) const
void push_block(push_block_params &&params, chain::plugin_interface::next_function< push_block_results > next)
void push_transactions(const push_transactions_params &params, chain::plugin_interface::next_function< push_transactions_results > next)
void send_transaction(const send_transaction_params &params, chain::plugin_interface::next_function< send_transaction_results > next)
read_write(controller &db, std::optional< trx_retry_db > &trx_retry, const fc::microseconds &abi_serializer_max_time, bool api_accept_transactions)
void send_transaction2(const send_transaction2_params &params, chain::plugin_interface::next_function< send_transaction_results > next)
void push_transaction(const push_transaction_params &params, chain::plugin_interface::next_function< push_transaction_results > next)
std::optional< controller > chain
fc::microseconds abi_serializer_max_time_us
std::optional< vm_type > wasm_runtime
methods::get_last_irreversible_block_number::method_type::handle get_last_irreversible_block_number_provider
methods::get_head_block_id::method_type::handle get_head_block_id_provider
std::optional< scoped_connection > accepted_block_header_connection
methods::get_block_by_id::method_type::handle get_block_by_id_provider
std::optional< genesis_state > genesis
std::optional< scoped_connection > accepted_transaction_connection
channels::pre_accepted_block::channel_type & pre_accepted_block_channel
channels::irreversible_block::channel_type & irreversible_block_channel
incoming::methods::block_sync::method_type & incoming_block_sync_method
std::optional< scoped_connection > block_start_connection
const producer_plugin * producer_plug
std::optional< scoped_connection > accepted_block_connection
chain_apis::trx_finality_status_processing_ptr _trx_finality_status_processing
flat_map< uint32_t, block_id_type > loaded_checkpoints
std::optional< scoped_connection > pre_accepted_block_connection
channels::accepted_block_header::channel_type & accepted_block_header_channel
methods::get_block_by_number::method_type::handle get_block_by_number_provider
channels::accepted_transaction::channel_type & accepted_transaction_channel
std::optional< scoped_connection > applied_transaction_connection
incoming::methods::transaction_async::method_type & incoming_transaction_async_method
std::optional< chain_apis::account_query_db > _account_query_db
std::optional< scoped_connection > irreversible_block_connection
channels::applied_transaction::channel_type & applied_transaction_channel
channels::accepted_block::channel_type & accepted_block_channel
std::optional< chain_apis::trx_retry_db > _trx_retry_db
std::optional< controller::config > chain_config
std::optional< bfs::path > snapshot_path
void plugin_initialize(const variables_map &options)
static void handle_db_exhaustion()
bool accept_block(const chain::signed_block_ptr &block, const chain::block_id_type &id, const chain::block_state_ptr &bsp)
bool api_accept_transactions() const
fc::microseconds get_abi_serializer_max_time() const
chain_apis::read_write get_read_write_api()
bool account_queries_enabled() const
void do_hard_replay(const variables_map &options)
chain_apis::read_only get_read_only_api() const
static void handle_guard_exception(const chain::guard_exception &e)
bool transaction_finality_status_enabled() const
chain::chain_id_type get_chain_id() const
static void handle_bad_alloc()
virtual void set_program_options(options_description &cli, options_description &cfg) override
void accept_transaction(const chain::packed_transaction_ptr &trx, chain::plugin_interface::next_function< chain::transaction_trace_ptr > next)
fc::variant get_log_trx_trace(const chain::transaction_trace_ptr &trx_trace) const
bool accept_transactions() const
fc::variant get_log_trx(const transaction &trx) const
void handle_sighup() override
std::array< uint8_t, Size > extract_as_byte_array() const
uint64_t id
Definition code_cache.cpp:0
bool starts_with(std::string const &str, std::string const &pref)
os_t os
bool debug
@ OS_OTHER
@ OS_WINDOWS
@ OS_LINUX
@ OS_MACOS
arch_t arch
unsigned boost_version
@ ARCH_X86_64
@ ARCH_OTHER
@ ARCH_ARM
@ ARCH_RISCV
char compiler[256]
#define FC_CAPTURE_AND_RETHROW(...)
#define FC_LOG_AND_RETHROW()
#define FC_LOG_AND_DROP(...)
#define FC_RETHROW_EXCEPTIONS(LOG_LEVEL, FORMAT,...)
Catchs all exception's, std::exceptions, and ... and rethrows them after appending the provided log m...
int * count
return
#define wlog(FORMAT,...)
Definition logger.hpp:124
#define dlog(FORMAT,...)
Definition logger.hpp:101
#define ilog(FORMAT,...)
Definition logger.hpp:118
#define elog(FORMAT,...)
Definition logger.hpp:130
static const Segment ds(Segment::ds)
application & app()
void unpack(Stream &s, std::deque< T > &value)
Definition raw.hpp:540
namespace sysio::chain
Definition authority.cpp:3
void rename(const path &from, const path &to)
bool remove(const path &p)
std::string string
Definition string.hpp:10
std::shared_ptr< exception > exception_ptr
@ read_only
bool exists(const path &p)
void remove_all(const path &p)
void uint128_to_float128(const sysio::chain::uint128_t &u, float128_t &f)
bool is_regular_file(const path &p)
void double_to_float64(const double &d, float64_t &f)
constexpr microseconds seconds(int64_t s)
Definition time.hpp:32
bool is_directory(const path &p)
uint64_t to_uint64(const fc::string &)
Definition string.cpp:105
datastream< ST > & operator<<(datastream< ST > &s, const sysio::chain::may_not_exist< T > &v)
Definition abi_def.hpp:146
void to_variant(const sysio::chain::shared_public_key &var, fc::variant &vo)
Definition authority.cpp:4
Definition name.hpp:106
__uint128_t uint128_t
Definition config.hpp:8
std::function< void(const std::variant< fc::exception_ptr, T > &)> next_function
string convert_to_string(const Type &source, const string &key_type, const string &encode_type, const string &desc)
string get_table_type(const abi_def &abi, const name &table_name)
auto make_resolver(const controller &control, abi_serializer::yield_function_t yield)
abi_def get_abi(const controller &db, const name &account)
std::function< void(const std::variant< fc::exception_ptr, T > &)> next_function
std::string itoh(I n, size_t hlen=sizeof(I)<< 1)
uint64_t convert_to_type(const string &str, const string &desc)
fc::variant get_global_row(const database &db, const abi_def &abi, const abi_serializer &abis, const fc::microseconds &abi_serializer_max_time_us, bool shorten_abi_errors)
std::unique_ptr< trx_finality_status_processing > trx_finality_status_processing_ptr
string type_name
Definition abi_def.hpp:7
const std::unordered_map< builtin_protocol_feature_t, builtin_protocol_feature_spec, enum_hash< builtin_protocol_feature_t > > builtin_protocol_feature_codenames
chainbase::shared_multi_index_container< permission_link_object, indexed_by< ordered_unique< tag< by_id >, >, ordered_unique< tag< by_action_name >, composite_key< permission_link_object, BOOST_MULTI_INDEX_MEMBER(permission_link_object, account_name, account), BOOST_MULTI_INDEX_MEMBER(permission_link_object, account_name, code), > >, ordered_unique< tag< by_permission_name >, composite_key< permission_link_object, BOOST_MULTI_INDEX_MEMBER(permission_link_object, account_name, account), BOOST_MULTI_INDEX_MEMBER(permission_link_object, permission_name, required_permission), > > > > permission_link_index
checksum_type digest_type
Definition types.hpp:237
std::array< uint128_t, 2 > key256_t
chainbase::shared_multi_index_container< permission_object, indexed_by< ordered_unique< tag< by_id >, member< permission_object, permission_object::id_type, &permission_object::id > >, ordered_unique< tag< by_parent >, composite_key< permission_object, member< permission_object, permission_object::id_type, &permission_object::parent >, member< permission_object, permission_object::id_type, &permission_object::id > > >, ordered_unique< tag< by_owner >, composite_key< permission_object, member< permission_object, account_name, &permission_object::owner >, member< permission_object, permission_name, &permission_object::name > > >, ordered_unique< tag< by_name >, composite_key< permission_object, member< permission_object, permission_name, &permission_object::name >, member< permission_object, permission_object::id_type, &permission_object::id > > > > > permission_index
std::shared_ptr< transaction_trace > transaction_trace_ptr
Definition trace.hpp:20
key Invalid authority Invalid transaction Invalid block ID Invalid packed transaction Invalid chain ID Invalid symbol Signature type is not a currently activated type Block can not be found Unlinkable block Block does not guarantee concurrent execution without conflicts Block exhausted allowed resources Block is from the future Block is not signed by expected producer Block includes an ill formed protocol feature activation extension Block includes an ill formed additional block signature extension transaction_exception
secondary_index< float64_t, index_double_object_type, soft_double_less >::index_index index_double_index
key Invalid authority Invalid transaction Invalid block ID Invalid packed transaction Invalid chain ID Invalid symbol Signature type is not a currently activated type Block can not be found Unlinkable block Block does not guarantee concurrent execution without conflicts Block exhausted allowed resources Block is from the future Block is not signed by expected producer Block includes an ill formed protocol feature activation extension Block includes an ill formed additional block signature extension Error decompressing transaction Transaction should have at least one required authority Expired Transaction Invalid Reference Block Duplicate deferred transaction The transaction can not be found Transaction is too big Invalid transaction extension Transaction includes disallowed Transaction exceeded transient resource limit Account name already exists sysio_assert_message assertion failure Action can not be found Attempt to use unaccessible API Inline Action exceeds maximum size limit sysio_assert_code assertion failure uses restricted error code value action return value size too big Permission Query Exception Contract Table Query Exception Database is an unknown or unsupported version guard_exception
std::shared_ptr< const packed_transaction > packed_transaction_ptr
key Invalid authority Invalid transaction Invalid block ID Invalid packed transaction Invalid chain ID Invalid symbol Signature type is not a currently activated type Block can not be found Unlinkable block Block does not guarantee concurrent execution without conflicts Block exhausted allowed resources Block is from the future Block is not signed by expected producer Block includes an ill formed protocol feature activation extension Block includes an ill formed additional block signature extension Error decompressing transaction Transaction should have at least one required authority Expired Transaction Invalid Reference Block Duplicate deferred transaction The transaction can not be found Transaction is too big Invalid transaction extension Transaction includes disallowed Transaction exceeded transient resource limit action_validate_exception
sysio::chain::action_name action_name
chain type exception chain_type_exception
const char * builtin_protocol_feature_codename(builtin_protocol_feature_t)
chainbase::shared_multi_index_container< generated_transaction_object, indexed_by< ordered_unique< tag< by_id >, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, generated_transaction_object::id_type, id)>, ordered_unique< tag< by_trx_id >, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, transaction_id_type, trx_id)>, ordered_unique< tag< by_expiration >, composite_key< generated_transaction_object, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, time_point, expiration), > >, ordered_unique< tag< by_delay >, composite_key< generated_transaction_object, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, time_point, delay_until), > >, ordered_unique< tag< by_sender_id >, composite_key< generated_transaction_object, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, account_name, sender), > > > > generated_transaction_multi_index
std::shared_ptr< signed_block > signed_block_ptr
Definition block.hpp:105
bool validate(const Authority &auth)
checksum_type transaction_id_type
Definition types.hpp:236
chainbase::shared_multi_index_container< key_value_object, indexed_by< ordered_unique< tag< by_id >, member< key_value_object, key_value_object::id_type, &key_value_object::id > >, ordered_unique< tag< by_scope_primary >, composite_key< key_value_object, member< key_value_object, table_id, &key_value_object::t_id >, member< key_value_object, uint64_t, &key_value_object::primary_key > >, composite_key_compare< std::less< table_id >, std::less< uint64_t > > > > > key_value_index
chainbase::shared_multi_index_container< table_id_object, indexed_by< ordered_unique< tag< by_id >, member< table_id_object, table_id_object::id_type, &table_id_object::id > >, ordered_unique< tag< by_code_scope_table >, composite_key< table_id_object, member< table_id_object, account_name, &table_id_object::code >, member< table_id_object, scope_name, &table_id_object::scope >, member< table_id_object, table_name, &table_id_object::table > > > > > table_id_multi_index
std::shared_ptr< block_state > block_state_ptr
vector< char > bytes
Definition types.hpp:243
std::shared_ptr< transaction_metadata > transaction_metadata_ptr
fc::time_point calculate_genesis_timestamp(string tstr)
protocol_feature_set initialize_protocol_features(const fc::path &p, bool populate_missing_builtins=true)
std::optional< builtin_protocol_feature > read_builtin_protocol_feature(const fc::path &p)
void clear_chainbase_files(const fc::path &p)
void clear_directory_contents(const fc::path &p)
uint32_t next(octet_iterator &it, octet_iterator end)
Definition checked.h:137
#define value
Definition pkcs11.h:157
const CharType(& source)[N]
Definition pointer.h:1204
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1181
const fc::microseconds abi_serializer_max_time
Definition main.cpp:173
Type
Type of JSON value.
Definition rapidjson.h:644
#define FC_REFLECT(TYPE, MEMBERS)
Specializes fc::reflector for TYPE.
Definition reflect.hpp:311
#define FC_REFLECT_ENUM(ENUM, FIELDS)
Definition reflect.hpp:194
float64_t f128_to_f64(float128_t a)
Definition f128_to_f64.c:44
void f64_to_f128M(float64_t a, float128_t *zPtr)
float64_t to_softfloat64(double d)
unsigned short uint16_t
Definition stdint.h:125
unsigned int uint32_t
Definition stdint.h:126
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
static constexpr int medium
static constexpr int high
size_t size() const
Definition zm.h:519
static yield_function_t create_yield_function(const fc::microseconds &max_serialization_time)
type_name get_table_type(name action) const
static void to_log_variant(const T &o, fc::variant &vo, Resolver resolver, const yield_function_t &yield)
static bool to_abi(const Vec &abi_vec, abi_def &abi)
bytes variant_to_binary(const std::string_view &type, const fc::variant &var, const fc::microseconds &max_serialization_time, bool short_path=false) const
type_name get_action_type(name action) const
static void to_variant(const T &o, fc::variant &vo, Resolver resolver, const yield_function_t &yield)
namespace sysio::chain::impl
fc::variant binary_to_variant(const std::string_view &type, const bytes &binary, const yield_function_t &yield, bool short_path=false) const
static void from_variant(const fc::variant &v, T &o, Resolver resolver, const yield_function_t &yield)
const symbol & get_symbol() const
Definition asset.hpp:34
defines the minimum state necessary to validate transaction headers
static const string sysio_root_key
chain_id_type compute_chain_id() const
Immutable except for fc::from_variant.
Definition name.hpp:43
std::string to_string() const
Definition name.cpp:19
int64_t used
quantity used in current window
static auto make(const controller &control, abi_serializer::yield_function_t yield)
account_query_db::get_accounts_by_authorizers_result results
account_query_db::get_accounts_by_authorizers_params params
void cli()
CK_ULONG d
char * s
uint16_t j
memcpy((char *) pInfo->slotDescription, s, l)
struct @108 key_type