diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index df73785222..7db3c89064 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -52,11 +52,15 @@ pub fn add_grpc_server(_runtime: &Runtime, _addr: &str) -> Result<(), Box<dyn Er Ok(()) } -pub fn init_runtime() { - log::info!("Starting gRPC and JSON RPC servers"); +pub fn init(_argc: i32, _argv: &[&str]) { LogBuilder::from_env(Env::default().default_filter_or(Level::Info.as_str())) .target(Target::Stdout) .init(); + log::info!("Initializing"); +} + +pub fn init_evm_runtime() { + log::info!("Initializing evm runtime"); let _ = &*RUNTIME; } diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index bff36b8cd7..4ccd6b8964 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -4,6 +4,8 @@ use ain_grpc::*; use ain_evm::runtime::RUNTIME; use log::debug; use std::error::Error; +use std::ffi::CStr; +use std::os::raw::c_char; use ethereum::{EnvelopedEncodable, TransactionAction, TransactionSignature}; use primitive_types::{H160, H256, U256}; @@ -41,7 +43,8 @@ pub mod ffi { miner_address: [u8; 20], ) -> Result<Vec<u8>>; - fn init_runtime(); + unsafe fn init(_argc: i32, _argv: *const *const c_char); + fn init_evm_runtime(); fn start_servers(json_addr: &str, grpc_addr: &str) -> Result<()>; fn stop_runtime(); @@ -157,3 +160,12 @@ fn evm_finalize( .finalize_block(context, update_state, difficulty, Some(eth_address))?; Ok(block.header.rlp_bytes().into()) } + +/// # Safety +/// Ensure that argc passed counts the exact number of argument variables that is passed into init +pub unsafe fn init(argc: i32, argv: *const *const c_char) { + let args: Vec<&str> = (0..argc) + .map(|i| unsafe { CStr::from_ptr(*argv.add(i as usize)).to_str().unwrap() }) + .collect(); + ain_grpc::init(argc, &args); +} diff --git a/src/defid.cpp b/src/defid.cpp index ad8718b62b..b31f75fb7c 100644 --- a/src/defid.cpp +++ b/src/defid.cpp @@ -60,6 +60,7 @@ static void WaitForShutdown() // static bool AppInit(int argc, char* argv[]) { + init(argc, argv); InitInterfaces interfaces; interfaces.chain = interfaces::MakeChain(); @@ -163,6 +164,8 @@ static bool AppInit(int argc, char* argv[]) // If locking the data directory failed, exit immediately return false; } + + init_evm_runtime(); fRet = AppInitMain(interfaces); } catch (const std::exception& e) { diff --git a/src/init.cpp b/src/init.cpp index cdc6c9aea3..5190942012 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -638,8 +638,10 @@ void SetupServerArgs() gArgs.AddArg("-dftxworkers=<n>", strprintf("No. of parallel workers associated with the DfTx related work pool. Stock splits, parallel processing of the chain where appropriate, etc use this worker pool (default: %d)", DEFAULT_DFTX_WORKERS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); gArgs.AddArg("-maxaddrratepersecond=<n>", strprintf("Sets MAX_ADDR_RATE_PER_SECOND limit for ADDR messages(default: %f)", MAX_ADDR_RATE_PER_SECOND), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); gArgs.AddArg("-maxaddrprocessingtokenbucket=<n>", strprintf("Sets MAX_ADDR_PROCESSING_TOKEN_BUCKET limit for ADDR messages(default: %d)", MAX_ADDR_PROCESSING_TOKEN_BUCKET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + gArgs.AddArg("-grpcbind=<addr>[:port]", "Bind to given address to listen for JSON-gRPC connections. Do not expose the gRPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -grpcport. This option can be specified multiple times (default: 127.0.0.1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); gArgs.AddArg("-grpcport=<port>", strprintf("Start GRPC connections on <port> and <port + 1> (default: %u, testnet: %u, devnet: %u, regtest: %u)", defaultBaseParams->GRPCPort(), testnetBaseParams->GRPCPort(), devnetBaseParams->GRPCPort(), regtestBaseParams->GRPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); - gArgs.AddArg("-ethrpcport=<port>", strprintf("Listen for ETH-JASON-RPC connections on <port>> (default: %u, testnet: %u, devnet: %u, regtest: %u)", defaultBaseParams->ETHRPCPort(), testnetBaseParams->ETHRPCPort(), devnetBaseParams->ETHRPCPort(), regtestBaseParams->ETHRPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); + gArgs.AddArg("-ethrpcbind=<addr>[:port]", "Bind to given address to listen for ETH-JSON-RPC connections. Do not expose the ETH-RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -ethrpcport. This option can be specified multiple times (default: 127.0.0.1 i.e., localhost)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); + gArgs.AddArg("-ethrpcport=<port>", strprintf("Listen for ETH-JSON-RPC connections on <port>> (default: %u, testnet: %u, devnet: %u, regtest: %u)", defaultBaseParams->ETHRPCPort(), testnetBaseParams->ETHRPCPort(), devnetBaseParams->ETHRPCPort(), regtestBaseParams->ETHRPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC); #if HAVE_DECL_DAEMON gArgs.AddArg("-daemon", "Run in the background as a daemon and accept commands", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -1553,11 +1555,53 @@ bool AppInitMain(InitInterfaces& interfaces) // ********************************************************* Step 4b: application initialization - init_runtime(); - int grpc_port = gArgs.GetArg("-grpcport", BaseParams().GRPCPort()); + /* Start the ETH RPC and gRPC servers. Current API only allows for one ETH + * RPC/gRPC server to bind to one address. By default, we will only take + * the first address, if multiple addresses are specified. + */ int eth_rpc_port = gArgs.GetArg("-ethrpcport", BaseParams().ETHRPCPort()); - start_servers("127.0.0.1:" + std::to_string(eth_rpc_port), "127.0.0.1:" + std::to_string(grpc_port)); + int grpc_port = gArgs.GetArg("-grpcport", BaseParams().GRPCPort()); + std::vector<std::pair<std::string, uint16_t> > eth_endpoints; + std::vector<std::pair<std::string, uint16_t> > g_endpoints; + + // Determine which addresses to bind to ETH RPC server + if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-ethrpcbind"))) { // Default to loopback if not allowing external IPs + eth_endpoints.push_back(std::make_pair("127.0.0.1", eth_rpc_port)); + if (gArgs.IsArgSet("-rpcallowip")) { + LogPrintf("WARNING: option -rpcallowip was specified without -ethrpcbind; this doesn't usually make sense\n"); + } + if (gArgs.IsArgSet("-ethrpcbind")) { + LogPrintf("WARNING: option -ethrpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n"); + } + } else if (gArgs.IsArgSet("-ethrpcbind")) { // Specific bind address + for (const std::string& strETHRPCBind : gArgs.GetArgs("-ethrpcbind")) { + int port = eth_rpc_port; + std::string host; + SplitHostPort(strETHRPCBind, port, host); + eth_endpoints.push_back(std::make_pair(host, port)); + } + } + + // Determine which addresses to bind to gRPC server + if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-grpcbind"))) { // Default to loopback if not allowing external IPs + g_endpoints.push_back(std::make_pair("127.0.0.1", grpc_port)); + if (gArgs.IsArgSet("-rpcallowip")) { + LogPrintf("WARNING: option -rpcallowip was specified without -grpcbind; this doesn't usually make sense\n"); + } + if (gArgs.IsArgSet("-grpcbind")) { + LogPrintf("WARNING: option -grpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n"); + } + } else if (gArgs.IsArgSet("-grpcbind")) { // Specific bind address + for (const std::string& strGRPCBind : gArgs.GetArgs("-grpcbind")) { + int port = grpc_port; + std::string host; + SplitHostPort(strGRPCBind, port, host); + g_endpoints.push_back(std::make_pair(host, port)); + } + } + // Default to using the first address passed to bind to ETH RPC server and gRPC server + start_servers(eth_endpoints[0].first + ":" + std::to_string(eth_endpoints[0].second), g_endpoints[0].first + "." + std::to_string(g_endpoints[0].second)); // ********************************************************* Step 5: verify wallet database integrity for (const auto& client : interfaces.chain_clients) {