diff --git a/Cargo.lock b/Cargo.lock index 1ff7dc36cb93d3..8aea0bc5014d71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1096,6 +1096,21 @@ version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" +[[package]] +name = "futures" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.5" @@ -1103,6 +1118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -1117,10 +1133,21 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" dependencies = [ - "futures", + "futures 0.1.29", "num_cpus", ] +[[package]] +name = "futures-executor" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.5" @@ -1160,9 +1187,11 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", + "futures-sink", "futures-task", "memchr 2.3.3", "pin-project", @@ -1285,7 +1314,7 @@ dependencies = [ "byteorder", "bytes 0.4.12", "fnv", - "futures", + "futures 0.1.29", "http 0.1.21", "indexmap", "log 0.4.8", @@ -1310,7 +1339,7 @@ dependencies = [ "log 0.4.8", "slab", "tokio 0.2.21", - "tokio-util", + "tokio-util 0.3.1", ] [[package]] @@ -1420,7 +1449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" dependencies = [ "bytes 0.4.12", - "futures", + "futures 0.1.29", "http 0.1.21", "tokio-buf", ] @@ -1482,7 +1511,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" dependencies = [ "bytes 0.4.12", - "futures", + "futures 0.1.29", "futures-cpupool", "h2 0.1.26", "http 0.1.21", @@ -1699,7 +1728,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecbdaacc17243168d9d1fa6b2bd7556a27e1e60a621d8a2a6e590ae2b145d158" dependencies = [ "failure", - "futures", + "futures 0.1.29", "jsonrpc-core", "jsonrpc-pubsub", "log 0.4.8", @@ -1716,7 +1745,7 @@ version = "14.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0747307121ffb9703afd93afbd0fb4f854c38fb873f2c8b90e0e902f27c7b62" dependencies = [ - "futures", + "futures 0.1.29", "log 0.4.8", "serde", "serde_derive", @@ -2815,6 +2844,12 @@ dependencies = [ "nibble_vec", ] +[[package]] +name = "raii-counter" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2cc9eb8fd5c1faa55b5ec00c3088edcef008fc388647bd34bf3677c2f9d3e4" + [[package]] name = "rand" version = "0.4.6" @@ -4497,6 +4532,7 @@ dependencies = [ "flate2", "fnv", "fs_extra", + "futures 0.3.5", "itertools 0.9.0", "lazy_static", "libc", @@ -4522,8 +4558,10 @@ dependencies = [ "solana-vote-program", "symlink", "tar", + "tarpc", "tempfile", "thiserror", + "tokio 0.2.21", "zstd", ] @@ -5068,7 +5106,7 @@ version = "0.0.1-sol5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94edebdee2305eabf8ccd7571eecaaa4328d4aba493c3a3e988db67230a8a8c4" dependencies = [ - "futures", + "futures 0.1.29", "hyper 0.12.35", "lazy_static", "prometheus", @@ -5459,6 +5497,37 @@ dependencies = [ "xattr", ] +[[package]] +name = "tarpc" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43966b393fd4c09e6c34df314d9e6184e87a9c191da6afb400276bb384d81ece" +dependencies = [ + "fnv", + "futures 0.3.5", + "humantime 1.3.0", + "log 0.4.8", + "pin-project", + "raii-counter", + "rand 0.7.3", + "serde", + "tarpc-plugins", + "tokio 0.2.21", + "tokio-serde", + "tokio-util 0.2.0", +] + +[[package]] +name = "tarpc-plugins" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "137af8d98d0fbb502b06e0ab113c5ed4dc6432e272f4be2e261c3b94f43296a0" +dependencies = [ + "proc-macro2 1.0.17", + "quote 1.0.6", + "syn 1.0.27", +] + [[package]] name = "tempdir" version = "0.3.7" @@ -5649,7 +5718,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" dependencies = [ "bytes 0.4.12", - "futures", + "futures 0.1.29", "mio", "num_cpus", "tokio-codec", @@ -5677,11 +5746,14 @@ dependencies = [ "futures-core", "iovec", "lazy_static", + "libc", "memchr 2.3.3", "mio", + "mio-uds", "num_cpus", "pin-project-lite", "slab", + "tokio-macros", ] [[package]] @@ -5692,7 +5764,7 @@ checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" dependencies = [ "bytes 0.4.12", "either", - "futures", + "futures 0.1.29", ] [[package]] @@ -5702,7 +5774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" dependencies = [ "bytes 0.4.12", - "futures", + "futures 0.1.29", "tokio-io", ] @@ -5712,7 +5784,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" dependencies = [ - "futures", + "futures 0.1.29", "tokio-executor", ] @@ -5723,7 +5795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" dependencies = [ "crossbeam-utils", - "futures", + "futures 0.1.29", ] [[package]] @@ -5732,7 +5804,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" dependencies = [ - "futures", + "futures 0.1.29", "tokio-io", "tokio-threadpool", ] @@ -5744,10 +5816,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" dependencies = [ "bytes 0.4.12", - "futures", + "futures 0.1.29", "log 0.4.8", ] +[[package]] +name = "tokio-macros" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" +dependencies = [ + "proc-macro2 1.0.17", + "quote 1.0.6", + "syn 1.0.27", +] + [[package]] name = "tokio-reactor" version = "0.1.12" @@ -5755,7 +5838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" dependencies = [ "crossbeam-utils", - "futures", + "futures 0.1.29", "lazy_static", "log 0.4.8", "mio", @@ -5779,6 +5862,17 @@ dependencies = [ "webpki", ] +[[package]] +name = "tokio-serde" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebdd897b01021779294eb09bb3b52b6e11b0747f9f7e333a84bef532b656de99" +dependencies = [ + "bytes 0.5.4", + "futures 0.3.5", + "pin-project", +] + [[package]] name = "tokio-sync" version = "0.1.8" @@ -5786,7 +5880,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" dependencies = [ "fnv", - "futures", + "futures 0.1.29", ] [[package]] @@ -5796,7 +5890,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" dependencies = [ "bytes 0.4.12", - "futures", + "futures 0.1.29", "iovec", "mio", "tokio-io", @@ -5812,7 +5906,7 @@ dependencies = [ "crossbeam-deque", "crossbeam-queue", "crossbeam-utils", - "futures", + "futures 0.1.29", "lazy_static", "log 0.4.8", "num_cpus", @@ -5827,7 +5921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" dependencies = [ "crossbeam-utils", - "futures", + "futures 0.1.29", "slab", "tokio-executor", ] @@ -5838,7 +5932,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c" dependencies = [ - "futures", + "futures 0.1.29", "native-tls", "tokio-io", ] @@ -5850,7 +5944,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" dependencies = [ "bytes 0.4.12", - "futures", + "futures 0.1.29", "log 0.4.8", "mio", "tokio-codec", @@ -5865,7 +5959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5076db410d6fdc6523df7595447629099a1fdc47b3d9f896220780fa48faf798" dependencies = [ "bytes 0.4.12", - "futures", + "futures 0.1.29", "iovec", "libc", "log 0.4.8", @@ -5876,6 +5970,20 @@ dependencies = [ "tokio-reactor", ] +[[package]] +name = "tokio-util" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "571da51182ec208780505a32528fc5512a8fe1443ab960b3f2f3ef093cd16930" +dependencies = [ + "bytes 0.5.4", + "futures-core", + "futures-sink", + "log 0.4.8", + "pin-project-lite", + "tokio 0.2.21", +] + [[package]] name = "tokio-util" version = "0.3.1" @@ -6145,7 +6253,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" dependencies = [ - "futures", + "futures 0.1.29", "log 0.4.8", "try-lock", ] @@ -6270,7 +6378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413b37840b9e27b340ce91b319ede10731de8c72f5bc4cb0206ec1ca4ce581d0" dependencies = [ "bytes 0.4.12", - "futures", + "futures 0.1.29", "hyper 0.10.16", "native-tls", "rand 0.6.5", @@ -6294,7 +6402,7 @@ dependencies = [ "bitflags", "byteorder", "bytes 0.4.12", - "futures", + "futures 0.1.29", "native-tls", "rand 0.6.5", "sha1", diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 22e4e31763e260..a85fddac5dbb4a 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -17,6 +17,7 @@ dir-diff = "0.3.2" flate2 = "1.0.14" fnv = "1.0.7" fs_extra = "1.1.0" +futures = "0.3" itertools = "0.9.0" lazy_static = "1.4.0" libc = "0.2.71" @@ -41,6 +42,7 @@ solana-stake-program = { path = "../programs/stake", version = "1.3.0" } solana-vote-program = { path = "../programs/vote", version = "1.3.0" } symlink = "0.1.0" tar = "0.4.28" +tarpc = { version = "0.20.0", features = ["full"] } tempfile = "3.1.0" thiserror = "1.0" zstd = "0.5.1" @@ -52,6 +54,7 @@ name = "solana_runtime" [dev-dependencies] assert_matches = "1.3.0" solana-noop-program = { path = "../programs/noop", version = "1.3.0" } +tokio = { version = "0.2", features = ["macros"] } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/runtime/src/bank_forks_client.rs b/runtime/src/bank_forks_client.rs new file mode 100644 index 00000000000000..a42df4e12b835b --- /dev/null +++ b/runtime/src/bank_forks_client.rs @@ -0,0 +1,156 @@ +use crate::{bank::Bank, bank_forks::BankForks}; +use futures::future::{self, Ready}; +use solana_sdk::{ + clock::Slot, + fee_calculator::FeeCalculator, + hash::Hash, + signature::Signature, + transaction::{self, Transaction}, +}; +use std::{ + sync::{ + mpsc::{channel, Receiver, Sender}, + Arc, + }, + thread::Builder, +}; +use tarpc::context::Context; + +#[tarpc::service] +trait BankForksRpc { + async fn get_recent_blockhash() -> (Hash, FeeCalculator, Slot); + async fn send_transaction(transaction: Transaction) -> Signature; + async fn get_signature_status(signature: Signature) -> Option>; + async fn get_root_slot() -> Slot; +} + +#[derive(Clone)] +pub struct BankForksServer { + bank_forks: Arc, + transaction_sender: Sender, +} + +impl BankForksServer { + /// Return a BankForksServer that forwards transactions to the + /// given sender. If unit-testing, those transactions can go to + /// a bank in the given BankForks. Otherwise, the receiver should + /// forward them to a validator in the leader schedule. + pub fn new_with_sender( + bank_forks: Arc, + transaction_sender: Sender, + ) -> Self { + Self { + bank_forks, + transaction_sender, + } + } + + fn run(bank: &Bank, transaction_receiver: Receiver) { + while let Ok(tx) = transaction_receiver.recv() { + let mut transactions = vec![tx]; + while let Ok(tx) = transaction_receiver.try_recv() { + transactions.push(tx); + } + let _ = bank.process_transactions(&transactions); + } + } + + /// Useful for unit-testing + pub fn new(bank_forks: Arc) -> Self { + let (transaction_sender, transaction_receiver) = channel(); + let bank = bank_forks.working_bank(); + Builder::new() + .name("solana-bank-forks-client".to_string()) + .spawn(move || Self::run(&bank, transaction_receiver)) + .unwrap(); + Self::new_with_sender(bank_forks, transaction_sender) + } +} + +impl BankForksRpc for BankForksServer { + type GetRecentBlockhashFut = Ready<(Hash, FeeCalculator, Slot)>; + fn get_recent_blockhash(self, _: Context) -> Self::GetRecentBlockhashFut { + let bank = self.bank_forks.root_bank(); + let (blockhash, fee_calculator) = bank.last_blockhash_with_fee_calculator(); + let last_valid_slot = bank.get_blockhash_last_valid_slot(&blockhash).unwrap(); + future::ready((blockhash, fee_calculator, last_valid_slot)) + } + + type SendTransactionFut = Ready; + fn send_transaction(self, _: Context, transaction: Transaction) -> Self::SendTransactionFut { + let signature = transaction.signatures.get(0).cloned().unwrap_or_default(); + self.transaction_sender.send(transaction).unwrap(); + future::ready(signature) + } + + type GetSignatureStatusFut = Ready>>; + fn get_signature_status(self, _: Context, signature: Signature) -> Self::GetSignatureStatusFut { + let bank = self.bank_forks.root_bank(); + future::ready(bank.get_signature_status(&signature)) + } + + type GetRootSlotFut = Ready; + fn get_root_slot(self, _: Context) -> Self::GetRootSlotFut { + future::ready(self.bank_forks.root()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::genesis_utils::create_genesis_config; + use futures::prelude::*; + use solana_sdk::{message::Message, pubkey::Pubkey, signature::Signer, system_instruction}; + use std::{io, time::Duration}; + use tarpc::{ + client, context, + server::{self, Handler}, + }; + + #[tokio::test] + async fn test_bank_forks_rpc_client_transfer() -> io::Result<()> { + let (client_transport, server_transport) = tarpc::transport::channel::unbounded(); + + let genesis = create_genesis_config(10); + let bank = Bank::new(&genesis.genesis_config); + let bank_forks = Arc::new(BankForks::new(bank)); + let bank_forks_server = BankForksServer::new(bank_forks); + let server = server::new(server::Config::default()) + .incoming(stream::once(future::ready(server_transport))) + .respond_with(bank_forks_server.serve()); + tokio::spawn(server); + + let mut client = + BankForksRpcClient::new(client::Config::default(), client_transport).spawn()?; + + let (recent_blockhash, _fee_calculator, last_valid_slot) = + client.get_recent_blockhash(context::current()).await?; + + let mint_pubkey = &genesis.mint_keypair.pubkey(); + let bob_pubkey = Pubkey::new_rand(); + let instruction = system_instruction::transfer(&mint_pubkey, &bob_pubkey, 1); + let message = Message::new_with_payer(&[instruction], Some(&mint_pubkey)); + let transaction = Transaction::new(&[&genesis.mint_keypair], message, recent_blockhash); + let signature = client + .send_transaction(context::current(), transaction) + .await?; + + let mut status = client + .get_signature_status(context::current(), signature) + .await?; + while status.is_none() { + let root_slot = client.get_root_slot(context::current()).await?; + if root_slot > last_valid_slot { + break; + } + tokio::time::delay_for(Duration::from_millis(100u64)).await; + status = client + .get_signature_status(context::current(), signature) + .await?; + } + + assert_eq!(status, Some(Ok(()))); + + Ok(()) + } +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 49b33d2572b737..28eb499ee46722 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -5,6 +5,7 @@ pub mod append_vec; pub mod bank; pub mod bank_client; pub mod bank_forks; +pub mod bank_forks_client; mod blockhash_queue; pub mod bloom; pub mod builtin_programs;