From f3d30ee2486b272304bd9d9e111d2984a8d83a1d Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Fri, 21 Aug 2020 17:53:52 -0400 Subject: [PATCH 01/43] initial commit --- node/rpc/Cargo.toml | 3 +++ node/rpc/src/lib.rs | 52 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 6646fb226eb..3e8f42bf016 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -32,6 +32,9 @@ forest_libp2p = { path = "../forest_libp2p" } interpreter = { path = "../../vm/interpreter/" } fil_types = { path = "../../types" } bitfield = { path = "../../utils/bitfield",features = ["json"] } +futures = "0.3.5" +async-tungstenite = "0.8.0" + [dev-dependencies] db = { path = "../db" } diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 46c69e53b9b..c7db9b807f0 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -18,7 +18,14 @@ use state_manager::StateManager; use std::sync::Arc; use tide::{Request, Response, StatusCode}; use wallet::KeyStore; - +use async_std::net::{TcpListener, TcpStream}; +use async_std::task; +use futures::stream::futures_unordered::FuturesUnordered; +use futures::stream::{StreamExt,TryStreamExt}; +use futures::sink::SinkExt; +use futures::future; +use async_tungstenite::tungstenite::{Message,error::Error}; +use std::borrow::Cow; /// This is where you store persistant data, or at least access to stateful data. pub struct RpcState where @@ -34,12 +41,6 @@ where pub network_name: String, } -async fn handle_json_rpc(mut req: Request>) -> tide::Result { - let call: RequestObject = req.body_json().await?; - let res = req.state().handle(call).await; - Ok(Response::new(StatusCode::Ok).body_json(&res)?) -} - pub async fn start_rpc(state: RpcState, rpc_endpoint: &str) where DB: BlockStore + Send + Sync + 'static, @@ -146,7 +147,38 @@ where .with_method("Filecoin.StateWaitMsg", state_wait_msg::) .finish_unwrapped(); - let mut app = tide::Server::with_state(rpc); - app.at("/rpc/v0").post(handle_json_rpc); - app.listen(rpc_endpoint).await.unwrap(); + let try_socket = TcpListener::bind("127.0.0.1").await; + let listener = try_socket.expect("Failed to bind to addr"); + let state = Arc::new(rpc); + let futures_unordered = FuturesUnordered::new(); + while let Ok((stream, addr)) = listener.accept().await { + futures_unordered.push(task::spawn(handle_connection(state.clone(), stream))); + } +} + +async fn handle_connection(state: Arc>,tcp_stream: TcpStream) -> Result<(),Error> +{ + let ws_stream = async_tungstenite::accept_async(tcp_stream) + .await + .expect("Error during the websocket handshake occurred"); + let (mut ws_sender, ws_receiver) = ws_stream.split(); + let responses = ws_receiver + .try_filter(|s|future::ready(!s.is_text())) + .try_fold(Vec::new(),|mut responses,s|async { + let request_text = s.into_text()?; + let call: RequestObject = serde_json::from_str(&request_text).map_err(|s|Error::Protocol(Cow::from(s.to_string())))?; + let response = state.handle(call).await; + let response_text = serde_json::to_string(&response).map_err(|s|Error::Protocol(Cow::from(s.to_string())))?; + responses.push(response_text); + Ok(responses) + + }).await?; + + //send back responses + for response_text in responses + { + ws_sender.send(Message::text(response_text)).await? + } + Ok(()) + } From dfff7985ed10a9977a29d1298ad0eec32e79e529 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Thu, 27 Aug 2020 16:37:08 -0400 Subject: [PATCH 02/43] added changes --- blockchain/beacon/Cargo.toml | 4 +- blockchain/beacon/proto/api-common-protos | 1 + blockchain/blocks/src/tipset.rs | 7 ++ blockchain/chain/Cargo.toml | 3 +- blockchain/chain/src/store/chain_store.rs | 73 +++++++++++++++++++- blockchain/chain_sync/Cargo.toml | 2 +- blockchain/chain_sync/src/sync.rs | 83 +++++++++++++++-------- blockchain/message_pool/Cargo.toml | 2 +- blockchain/state_manager/Cargo.toml | 2 +- forest/Cargo.toml | 2 +- forest/src/cli/genesis.rs | 1 - forest/src/daemon.rs | 5 +- ipld/Cargo.toml | 2 +- ipld/graphsync/Cargo.toml | 2 +- node/forest_libp2p/Cargo.toml | 2 +- node/rpc/Cargo.toml | 2 +- node/rpc/src/chain_api.rs | 20 ++++++ node/rpc/src/lib.rs | 58 ++++++++-------- utils/test_utils/Cargo.toml | 2 +- 19 files changed, 203 insertions(+), 70 deletions(-) create mode 160000 blockchain/beacon/proto/api-common-protos diff --git a/blockchain/beacon/Cargo.toml b/blockchain/beacon/Cargo.toml index 927b35a2182..789a245588a 100644 --- a/blockchain/beacon/Cargo.toml +++ b/blockchain/beacon/Cargo.toml @@ -9,7 +9,7 @@ features = ["json"] [dependencies] ahash = "0.4" -async-std = { version = "1.6.0", features = ["unstable"] } +async-std = { version = "1.6.3", features = ["unstable"] } clock = { path = "../../node/clock" } bls-signatures = "0.6.0" serde = { version = "1.0", features = ["derive"] } @@ -24,7 +24,7 @@ hex = "0.4.2" [dev-dependencies] base64 = "0.12.1" -async-std = { version = "1.6.0", features = ["unstable", "attributes"] } +async-std = { version = "1.6.3", features = ["unstable", "attributes"] } serde_json = "1.0" [build-dependencies] diff --git a/blockchain/beacon/proto/api-common-protos b/blockchain/beacon/proto/api-common-protos new file mode 160000 index 00000000000..be41e82ef4a --- /dev/null +++ b/blockchain/beacon/proto/api-common-protos @@ -0,0 +1 @@ +Subproject commit be41e82ef4af6406b4cf331af00a837f813c0c3b diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index 981368cef9f..dbb0aa17f47 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -291,6 +291,13 @@ pub mod tipset_json { } } + + impl<'a> From<&'a Tipset> for TipsetJsonRef<'a> { + fn from(wrapper: &'a Tipset) -> Self { + TipsetJsonRef(wrapper) + } + } + pub fn serialize(m: &Tipset, serializer: S) -> Result where S: Serializer, diff --git a/blockchain/chain/Cargo.toml b/blockchain/chain/Cargo.toml index 015e10a2e42..777b4c1debf 100644 --- a/blockchain/chain/Cargo.toml +++ b/blockchain/chain/Cargo.toml @@ -26,7 +26,8 @@ byteorder = "1.3.4" beacon = { path = "../beacon" } flo_stream = "0.4.0" address = { package = "forest_address", path = "../../vm/address" } - +futures ="0.3.5" +async-std = { version = "1.6.3", features = ["unstable", "attributes"] } [dev-dependencies] multihash = "0.10.0" test_utils = { version = "0.1.0", path = "../../utils/test_utils/", features = [ diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 0e5d4d48b3c..c5e6331e1c9 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -4,9 +4,12 @@ use super::{Error, TipIndex, TipsetMetadata}; use actor::{power::State as PowerState, STORAGE_POWER_ACTOR_ADDR}; use address::Address; +use async_std::sync::channel; +use async_std::sync::Receiver; +use async_std::task; use beacon::BeaconEntry; use blake2b_simd::Params; -use blocks::{Block, BlockHeader, FullTipset, Tipset, TipsetKeys, TxMeta}; +use blocks::{Block, BlockHeader, FullTipset, Tipset, TipsetKeys, TxMeta,tipset_json::TipsetJson}; use byteorder::{BigEndian, WriteBytesExt}; use cid::multihash::Blake2b256; use cid::Cid; @@ -14,17 +17,19 @@ use clock::ChainEpoch; use crypto::DomainSeparationTag; use encoding::{blake2b_256, de::DeserializeOwned, from_slice, Cbor}; use flo_stream::{MessagePublisher, Publisher, Subscriber}; +use futures::StreamExt; use ipld_amt::Amt; use ipld_blockstore::BlockStore; use log::{info, warn}; use message::{ChainMessage, Message, MessageReceipt, SignedMessage, UnsignedMessage}; use num_bigint::{BigInt, Sign}; use num_traits::Zero; -use serde::Serialize; use state_tree::StateTree; use std::collections::HashMap; use std::io::Write; use std::sync::Arc; +use serde::{Deserialize, Serialize}; + const GENESIS_KEY: &str = "gen_block"; const HEAD_KEY: &str = "head"; @@ -45,6 +50,29 @@ pub enum HeadChange { Apply(Arc), Revert(Arc), } +#[derive(Debug,Serialize,Deserialize)] +pub enum HeadChangeJson{ + Current(TipsetJson), + Apply(TipsetJson), + Revert(TipsetJson) +} + +impl From for HeadChangeJson { + fn from(wrapper: HeadChange) -> Self { + match wrapper + { + HeadChange::Current(tipset) => + HeadChangeJson::Revert((*tipset).clone().into()), + + HeadChange::Apply(tipset) => + HeadChangeJson::Revert((*tipset).clone().into()), + HeadChange::Revert(tipset) => + HeadChangeJson::Revert((*tipset).clone().into()), + + } + } +} + /// Generic implementation of the datastore trait and structures pub struct ChainStore { @@ -212,6 +240,27 @@ where } Ok(()) } + + pub async fn sub_head_changes(&mut self) -> Result, Error> { + let mut subscribed_head_change = self.subscribe(); + let head = self + .heaviest_tipset() + .ok_or_else(|| Error::Other("Could not get heaviest tipset".to_string()))?; + let (sender, reciever) = channel(16); + sender.send(HeadChange::Current(head)).await; + task::spawn(async move { + while let Some(val) = subscribed_head_change.next().await { + if !sender.is_empty() { + warn!( + "head change sub is slow, has {:} buffered entries", + sender.len() + ) + } + sender.send(val).await + } + }); + Ok(reciever) + } } /// Returns messages for a given tipset from db @@ -245,6 +294,26 @@ where Ok((bls_msgs, secp_msgs)) } +/// Constructs and returns a full tipset if messages from storage exists - non self version +pub fn fill_tipsets(db: &DB, ts: Tipset) -> Result +where + DB: BlockStore, +{ + let mut blocks: Vec = Vec::with_capacity(ts.blocks().len()); + + for header in ts.into_blocks() { + let (bls_messages, secp_messages) = block_messages(db, &header)?; + blocks.push(Block { + header, + bls_messages, + secp_messages, + }); + } + + // the given tipset has already been verified, so this cannot fail + Ok(FullTipset::new(blocks).unwrap()) +} + /// Returns a tuple of UnsignedMessage and SignedMessages from their Cid pub fn block_messages_from_cids( db: &DB, diff --git a/blockchain/chain_sync/Cargo.toml b/blockchain/chain_sync/Cargo.toml index ab601652076..eed8e94b7b4 100644 --- a/blockchain/chain_sync/Cargo.toml +++ b/blockchain/chain_sync/Cargo.toml @@ -22,7 +22,7 @@ state_manager = { path = "../state_manager/" } num-bigint = { path = "../../utils/bigint", package = "forest_bigint" } crypto = { package = "forest_crypto", path = "../../crypto" } log = "0.4.8" -async-std = { version = "1.6.0", features = ["unstable"] } +async-std = { version = "1.6.3", features = ["unstable"] } forest_libp2p = { path = "../../node/forest_libp2p" } futures = "0.3.5" lru = "0.5.1" diff --git a/blockchain/chain_sync/src/sync.rs b/blockchain/chain_sync/src/sync.rs index c18b0c811bd..930fe42a7ac 100644 --- a/blockchain/chain_sync/src/sync.rs +++ b/blockchain/chain_sync/src/sync.rs @@ -68,7 +68,7 @@ pub struct ChainSyncer { next_sync_target: SyncBucket, /// access and store tipsets / blocks / messages - chain_store: ChainStore, + chain_store: Arc>>, /// Context to be able to send requests to p2p network network: SyncNetworkContext, @@ -98,14 +98,14 @@ where TBeacon: Beacon + Send, DB: BlockStore + Sync + Send + 'static, { - pub fn new( - chain_store: ChainStore, + pub async fn new( + chain_store: Arc>>, beacon: Arc, network_send: Sender, network_rx: Receiver, genesis: Tipset, ) -> Result { - let state_manager = Arc::new(StateManager::new(chain_store.db.clone())); + let state_manager = Arc::new(StateManager::new(chain_store.read().await.db.clone())); // Split incoming channel to handle blocksync requests let mut event_send = Publisher::new(30); @@ -167,7 +167,7 @@ where } } NetworkEvent::PeerDialed { peer_id } => { - let heaviest = self.chain_store.heaviest_tipset().unwrap(); + let heaviest = self.chain_store.read().await.heaviest_tipset().unwrap(); self.network .hello_request( peer_id, @@ -202,7 +202,7 @@ where } // Get heaviest tipset from storage to sync toward - let heaviest = self.chain_store.heaviest_tipset().unwrap(); + let heaviest = self.chain_store.read().await.heaviest_tipset().unwrap(); info!("Starting block sync..."); @@ -225,7 +225,7 @@ where // Persist header chain pulled from network self.set_stage(SyncStage::PersistHeaders).await; let headers: Vec<&BlockHeader> = tipsets.iter().map(|t| t.blocks()).flatten().collect(); - if let Err(e) = persist_objects(self.chain_store.blockstore(), &headers) { + if let Err(e) = persist_objects(self.state_manager.get_block_store_ref(), &headers) { self.state.write().await.error(e.to_string()); return Err(e.into()); } @@ -239,7 +239,11 @@ where self.set_stage(SyncStage::Complete).await; // At this point the head is synced and the head can be set as the heaviest. - self.chain_store.put_tipset(head.as_ref()).await?; + self.chain_store + .write() + .await + .put_tipset(head.as_ref()) + .await?; Ok(()) } @@ -254,7 +258,10 @@ where while i >= 0 { // check storage first to see if we have full tipset - let fts = match self.chain_store.fill_tipsets(ts[i as usize].clone()) { + let fts = match chain::fill_tipsets( + self.state_manager.get_block_store_ref(), + ts[i as usize].clone(), + ) { Ok(fts) => fts, Err(_) => { // no full tipset in storage; request messages via blocksync @@ -294,8 +301,8 @@ where self.state.write().await.set_epoch(curr_epoch); // store messages - self.chain_store.put_messages(&b.bls_msgs)?; - self.chain_store.put_messages(&b.secp_msgs)?; + self.chain_store.write().await.put_messages(&b.bls_msgs)?; + self.chain_store.write().await.put_messages(&b.secp_msgs)?; } } i -= REQUEST_WINDOW; @@ -328,11 +335,11 @@ where return Err(Error::Other("Block marked as bad".to_string())); } // validate message data - self.validate_msg_meta(block)?; + self.validate_msg_meta(block).await?; } // compare target_weight to heaviest weight stored; ignore otherwise - let best_weight = match self.chain_store.heaviest_tipset() { + let best_weight = match self.chain_store.read().await.heaviest_tipset() { Some(ts) => ts.weight().clone(), None => Zero::zero(), }; @@ -417,9 +424,9 @@ where } /// Validates message root from header matches message root generated from the /// bls and secp messages contained in the passed in block and stores them in a key-value store - fn validate_msg_meta(&self, block: &Block) -> Result<(), Error> { + async fn validate_msg_meta(&self, block: &Block) -> Result<(), Error> { let sm_root = compute_msg_meta( - self.chain_store.blockstore(), + self.state_manager.get_block_store_ref(), block.bls_msgs(), block.secp_msgs(), )?; @@ -427,8 +434,14 @@ where return Err(Error::InvalidRoots); } - self.chain_store.put_messages(block.bls_msgs())?; - self.chain_store.put_messages(block.secp_msgs())?; + self.chain_store + .write() + .await + .put_messages(block.bls_msgs())?; + self.chain_store + .write() + .await + .put_messages(block.secp_msgs())?; Ok(()) } @@ -451,11 +464,11 @@ where fn load_fts(&self, keys: &TipsetKeys) -> Result { let mut blocks = Vec::new(); // retrieve tipset from store based on passed in TipsetKeys - let ts = self.chain_store.tipset_from_keys(keys)?; + let ts = chain::tipset_from_keys(self.state_manager.get_block_store_ref(), keys)?; for header in ts.blocks() { // retrieve bls and secp messages from specified BlockHeader let (bls_msgs, secp_msgs) = - chain::block_messages(self.chain_store.blockstore(), &header)?; + chain::block_messages(self.state_manager.get_block_store_ref(), &header)?; // construct a full block let full_block = Block { @@ -600,7 +613,8 @@ where error_vec.push("Signature is nil in header".to_owned()); } - let parent_tipset = self.chain_store.tipset_from_keys(header.parents())?; + let parent_tipset = + chain::tipset_from_keys(self.state_manager.get_block_store_ref(), header.parents())?; // time stamp checks if let Err(err) = header.validate_timestamps(&parent_tipset) { @@ -653,9 +667,14 @@ where error_vec.push("Received block was from slashed or invalid miner".to_owned()) } - let prev_beacon = self - .chain_store - .latest_beacon_entry(&self.chain_store.tipset_from_keys(header.parents())?)?; + let prev_beacon = + self.chain_store + .read() + .await + .latest_beacon_entry(&chain::tipset_from_keys( + self.state_manager.get_block_store_ref(), + header.parents(), + )?)?; header .validate_block_drand(Arc::clone(&self.beacon), prev_beacon) .await?; @@ -701,7 +720,10 @@ where self.bad_blocks.put(b.cid().clone(), e.to_string()).await; return Err(Error::Other("Invalid blocks detected".to_string())); } - self.chain_store.set_tipset_tracker(b.header())?; + self.chain_store + .write() + .await + .set_tipset_tracker(b.header())?; } Ok(()) } @@ -816,7 +838,9 @@ where } // Try to load parent tipset from local storage - if let Ok(ts) = self.chain_store.tipset_from_keys(cur_ts.parents()) { + if let Ok(ts) = + chain::tipset_from_keys(self.state_manager.get_block_store_ref(), cur_ts.parents()) + { // Add blocks in tipset to accepted chain and push the tipset to return set accepted_blocks.extend_from_slice(ts.cids()); return_set.push(ts); @@ -915,7 +939,8 @@ where .await .map_err(|_| Error::Other("Could not retrieve tipset".to_string()))?; - let mut ts = self.chain_store.tipset_from_keys(to.parents())?; + let mut ts = + chain::tipset_from_keys(self.state_manager.get_block_store_ref(), to.parents())?; for i in 0..tips.len() { while ts.epoch() > tips[i].epoch() { @@ -924,7 +949,11 @@ where "Synced chain forked at genesis, refusing to sync".to_string(), )); } - ts = self.chain_store.tipset_from_keys(ts.parents())?; + ts = self + .chain_store + .read() + .await + .tipset_from_keys(ts.parents())?; } if ts == tips[i] { return Ok(tips[0..=i].to_vec()); diff --git a/blockchain/message_pool/Cargo.toml b/blockchain/message_pool/Cargo.toml index 00a132d3391..3a287234b91 100644 --- a/blockchain/message_pool/Cargo.toml +++ b/blockchain/message_pool/Cargo.toml @@ -25,7 +25,7 @@ futures = "0.3.5" libsecp256k1 = "0.3.4" blake2b_simd = "0.5.10" log = "0.4.8" -async-std = "1.6.0" +async-std = "1.6.3" key_management = { path = "../../key_management"} [dev-dependencies] diff --git a/blockchain/state_manager/Cargo.toml b/blockchain/state_manager/Cargo.toml index 6b88e3c5da6..66baa1dd3d9 100644 --- a/blockchain/state_manager/Cargo.toml +++ b/blockchain/state_manager/Cargo.toml @@ -19,7 +19,7 @@ interpreter = { path = "../../vm/interpreter/" } ipld_amt = { path = "../../ipld/amt/" } clock = { path = "../../node/clock" } chain = { path = "../chain" } -async-std = "1.5.0" +async-std = "1.6.3" async-log = "2.0.0" log = "0.4.8" fil_types = { path = "../../types" } diff --git a/forest/Cargo.toml b/forest/Cargo.toml index b4c909a2f1f..ddbbf3557af 100644 --- a/forest/Cargo.toml +++ b/forest/Cargo.toml @@ -12,7 +12,7 @@ libp2p = "0.21.1" futures = "0.3.5" log = "0.4.8" async-log = "2.0.0" -async-std = { version = "1.6.0", features = ["attributes"] } +async-std = { version = "1.6.3", features = ["attributes"] } serde = { version = "1.0", features = ["derive"] } pretty_env_logger = "0.4.0" ctrlc = "3.1.4" diff --git a/forest/src/cli/genesis.rs b/forest/src/cli/genesis.rs index dc5c92f0f1a..cd8afd187d1 100644 --- a/forest/src/cli/genesis.rs +++ b/forest/src/cli/genesis.rs @@ -47,7 +47,6 @@ where "Genesis not initialized properly, failed to retrieve network name. \ Requires either a previously initialized genesis or with genesis config option set", ); - Ok((Tipset::new(vec![genesis])?, network_name)) } diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index 7de6d61c483..48327601800 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -77,13 +77,15 @@ pub(super) async fn start(config: Config) { .unwrap(); // Initialize ChainSyncer + let chain_store = Arc::new(RwLock::new(chain_store)); let chain_syncer = ChainSyncer::new( - chain_store, + chain_store.clone(), Arc::new(beacon), network_send.clone(), network_rx, genesis, ) + .await .unwrap(); let bad_blocks = chain_syncer.bad_blocks_cloned(); let sync_state = chain_syncer.sync_state_cloned(); @@ -105,6 +107,7 @@ pub(super) async fn start(config: Config) { start_rpc( RpcState { state_manager: db_rpc, + chain_store, keystore: keystore_rpc, mpool, bad_blocks, diff --git a/ipld/Cargo.toml b/ipld/Cargo.toml index 18820717a29..232e134e28c 100644 --- a/ipld/Cargo.toml +++ b/ipld/Cargo.toml @@ -28,6 +28,6 @@ submodule_tests = ["json"] [dev-dependencies] serde_json = "1.0" -async-std = { version = "1.6.0", features = ["attributes"] } +async-std = { version = "1.6.3", features = ["attributes"] } ipld_blockstore = { path = "blockstore" } db = { path = "../node/db" } diff --git a/ipld/graphsync/Cargo.toml b/ipld/graphsync/Cargo.toml index 2c17911a2f6..a49174f67a0 100644 --- a/ipld/graphsync/Cargo.toml +++ b/ipld/graphsync/Cargo.toml @@ -27,5 +27,5 @@ protoc-rust = "2.14.0" [dev-dependencies] multihash = "0.10" -async-std = "1.5" +async-std = "1.6.3" rand = "0.7" \ No newline at end of file diff --git a/node/forest_libp2p/Cargo.toml b/node/forest_libp2p/Cargo.toml index 0b75e86c95f..3db1dcc2341 100644 --- a/node/forest_libp2p/Cargo.toml +++ b/node/forest_libp2p/Cargo.toml @@ -12,7 +12,7 @@ futures = "0.3.5" futures-util = "0.3.5" futures_codec = "0.4.0" log = "0.4.8" -async-std = { version = "1.6.0", features = ["unstable"] } +async-std = { version = "1.6.3", features = ["unstable"] } serde = { version = "1.0", features = ["derive"] } forest_blocks = { path = "../../blockchain/blocks" } forest_message = { path = "../../vm/message" } diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 3e8f42bf016..64897a10eb1 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] actor = { path = "../../vm/actor/" } -async-std = { version = "1.6.0", features = ["attributes"] } +async-std = { version = "1.6.3", features = ["attributes"] } tide = "0.9.0" serde = { version = "1.0.101", default-features = false, features = ["derive"] } serde_json = "1.0.48" diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index 73d233b1998..143b08754c0 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -10,6 +10,7 @@ use cid::{json::CidJson, Cid}; use clock::ChainEpoch; use crypto::DomainSeparationTag; +use async_std::prelude::*; use jsonrpc_v2::{Data, Error as JsonRpcError, Params}; use message::{ signed_message, @@ -56,6 +57,25 @@ where Ok(UnsignedMessageJson(ret)) } +pub(crate) async fn chain_notify( + data: Data> +) -> Result, JsonRpcError> +where + DB: BlockStore + Send + Sync + 'static, + KS: KeyStore + Send + Sync + 'static, +{ + + Ok(data + .chain_store + .write() + .await + .sub_head_changes() + .await? + .map(|s|s.into()) + .collect() + .await) +} + pub(crate) async fn chain_read_obj( data: Data>, Params(params): Params<(CidJson,)>, diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index c7db9b807f0..3f874a63416 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -8,24 +8,24 @@ mod sync_api; mod wallet_api; use crate::state_api::*; +use async_std::net::{TcpListener, TcpStream}; use async_std::sync::{RwLock, Sender}; +use async_std::task; +use async_tungstenite::tungstenite::{error::Error, Message}; use blockstore::BlockStore; +use chain::ChainStore; use chain_sync::{BadBlockCache, SyncState}; use forest_libp2p::NetworkMessage; +use futures::future; +use futures::sink::SinkExt; +use futures::stream::futures_unordered::FuturesUnordered; +use futures::stream::{StreamExt, TryStreamExt}; use jsonrpc_v2::{Data, MapRouter, RequestObject, Server}; use message_pool::{MessagePool, MpoolRpcProvider}; use state_manager::StateManager; +use std::borrow::Cow; use std::sync::Arc; -use tide::{Request, Response, StatusCode}; use wallet::KeyStore; -use async_std::net::{TcpListener, TcpStream}; -use async_std::task; -use futures::stream::futures_unordered::FuturesUnordered; -use futures::stream::{StreamExt,TryStreamExt}; -use futures::sink::SinkExt; -use futures::future; -use async_tungstenite::tungstenite::{Message,error::Error}; -use std::borrow::Cow; /// This is where you store persistant data, or at least access to stateful data. pub struct RpcState where @@ -33,6 +33,7 @@ where KS: KeyStore + Send + Sync + 'static, { pub state_manager: StateManager, + pub chain_store: Arc>>, pub keystore: Arc>, pub mpool: Arc>>, pub bad_blocks: Arc, @@ -75,6 +76,7 @@ where "Filecoin.ChainGetBlock", chain_api::chain_get_block::, ) + .with_method("Filecoin.ChainNotify", chain_notify::) .with_method("Filecoin.ChainHead", chain_head::) // Message Pool API .with_method( @@ -147,38 +149,40 @@ where .with_method("Filecoin.StateWaitMsg", state_wait_msg::) .finish_unwrapped(); - let try_socket = TcpListener::bind("127.0.0.1").await; + let try_socket = TcpListener::bind(rpc_endpoint).await; let listener = try_socket.expect("Failed to bind to addr"); let state = Arc::new(rpc); let futures_unordered = FuturesUnordered::new(); - while let Ok((stream, addr)) = listener.accept().await { + while let Ok((stream, _addr)) = listener.accept().await { futures_unordered.push(task::spawn(handle_connection(state.clone(), stream))); } } -async fn handle_connection(state: Arc>,tcp_stream: TcpStream) -> Result<(),Error> -{ +async fn handle_connection( + state: Arc>, + tcp_stream: TcpStream, +) -> Result<(), Error> { let ws_stream = async_tungstenite::accept_async(tcp_stream) .await .expect("Error during the websocket handshake occurred"); let (mut ws_sender, ws_receiver) = ws_stream.split(); let responses = ws_receiver - .try_filter(|s|future::ready(!s.is_text())) - .try_fold(Vec::new(),|mut responses,s|async { - let request_text = s.into_text()?; - let call: RequestObject = serde_json::from_str(&request_text).map_err(|s|Error::Protocol(Cow::from(s.to_string())))?; - let response = state.handle(call).await; - let response_text = serde_json::to_string(&response).map_err(|s|Error::Protocol(Cow::from(s.to_string())))?; - responses.push(response_text); - Ok(responses) - - }).await?; + .try_filter(|s| future::ready(!s.is_text())) + .try_fold(Vec::new(), |mut responses, s| async { + let request_text = s.into_text()?; + let call: RequestObject = serde_json::from_str(&request_text) + .map_err(|s| Error::Protocol(Cow::from(s.to_string())))?; + let response = state.handle(call).await; + let response_text = serde_json::to_string(&response) + .map_err(|s| Error::Protocol(Cow::from(s.to_string())))?; + responses.push(response_text); + Ok(responses) + }) + .await?; //send back responses - for response_text in responses - { - ws_sender.send(Message::text(response_text)).await? + for response_text in responses { + ws_sender.send(Message::text(response_text)).await? } Ok(()) - } diff --git a/utils/test_utils/Cargo.toml b/utils/test_utils/Cargo.toml index 6e4b39fef83..f73c4dea548 100644 --- a/utils/test_utils/Cargo.toml +++ b/utils/test_utils/Cargo.toml @@ -16,7 +16,7 @@ chain = { path = "../../blockchain/chain/", optional = true } message = { package = "forest_message", path = "../../vm/message", optional = true } num-bigint = { path = "../../utils/bigint", package = "forest_bigint" } crypto = { package = "forest_crypto", path = "../../crypto" } -async-std = { version = "1.6.0", features = ["unstable"] } +async-std = { version = "1.6.3", features = ["unstable"] } forest_libp2p = { path = "../../node/forest_libp2p/", optional = true } encoding = { package = "forest_encoding", path = "../../encoding/"} base64 = "0.12.1" From 84a2dc196ea59c71d0d7f070da4469e512499e97 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Mon, 31 Aug 2020 10:54:43 -0400 Subject: [PATCH 03/43] removed info trace --- forest/src/daemon.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index e7cd60ce0d9..1c20359f54e 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -130,8 +130,6 @@ pub(super) async fn start(config: Config) { None }; - info!("daemon started"); - // Block until ctrl-c is hit block_until_sigint().await; From 04ae565219f08ee2387586bf40e71c9877bcf0d2 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Mon, 31 Aug 2020 13:54:30 -0400 Subject: [PATCH 04/43] fixed tests --- blockchain/chain_sync/src/sync.rs | 9 ++++----- blockchain/chain_sync/src/sync/peer_test.rs | 10 +++++----- node/rpc/src/sync_api.rs | 1 + 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/blockchain/chain_sync/src/sync.rs b/blockchain/chain_sync/src/sync.rs index b381ed1b427..e4e53cb5ab8 100644 --- a/blockchain/chain_sync/src/sync.rs +++ b/blockchain/chain_sync/src/sync.rs @@ -1057,14 +1057,13 @@ mod tests { let genesis_ts = Tipset::new(vec![gen]).unwrap(); ( - ChainSyncer::new( - chain_store, + task::block_on(ChainSyncer::new( + Arc::new(RwLock::new(chain_store)), beacon, local_sender, event_receiver, genesis_ts, - ) - .unwrap(), + )).unwrap(), event_sender, test_receiver, ) @@ -1139,7 +1138,7 @@ mod tests { Cid::from_raw_cid("bafy2bzaceasssikoiintnok7f3sgnekfifarzobyr3r4f25sgxmn23q4c35ic") .unwrap(); - let root = compute_msg_meta(cs.chain_store.blockstore(), &[bls], &[secp]).unwrap(); + let root = compute_msg_meta(cs.state_manager.get_block_store_ref(), &[bls], &[secp]).unwrap(); assert_eq!(root, expected_root); } diff --git a/blockchain/chain_sync/src/sync/peer_test.rs b/blockchain/chain_sync/src/sync/peer_test.rs index 23ec5c004af..407b6e6cbc3 100644 --- a/blockchain/chain_sync/src/sync/peer_test.rs +++ b/blockchain/chain_sync/src/sync/peer_test.rs @@ -31,13 +31,13 @@ fn peer_manager_update() { let genesis_ts = Tipset::new(vec![dummy_header]).unwrap(); let beacon = Arc::new(MockBeacon::new(Duration::from_secs(1))); - let cs = ChainSyncer::new( - chain_store, + let cs = task::block_on(ChainSyncer::new( + Arc::new(RwLock::new(chain_store)), beacon, local_sender, event_receiver, genesis_ts, - ) + )) .unwrap(); let peer_manager = Arc::clone(&cs.peer_manager); @@ -64,7 +64,7 @@ fn peer_manager_update() { // Would be ideal to not have to sleep here and have it deterministic task::sleep(Duration::from_millis(50)).await; - assert_eq!(peer_manager.len().await, 1); - assert_eq!(peer_manager.get_peer().await, Some(source_clone)); + assert_eq!((*peer_manager).len().await, 1); + assert_eq!((*peer_manager).get_peer().await, Some(source_clone)); }); } diff --git a/node/rpc/src/sync_api.rs b/node/rpc/src/sync_api.rs index cad7b20e8cc..0658c80cf53 100644 --- a/node/rpc/src/sync_api.rs +++ b/node/rpc/src/sync_api.rs @@ -129,6 +129,7 @@ mod tests { }); let state = Arc::new(RpcState { + chain_store : Arc::new(RwLock::new(ChainStore::new(Arc::new(MemoryDB::default())))), state_manager: StateManager::new(Arc::new(MemoryDB::default())), keystore: Arc::new(RwLock::new(wallet::MemKeyStore::new())), mpool: Arc::new(pool), From 665312cf27b01368ca12e5a4ebe5ea70e3a1120a Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Mon, 31 Aug 2020 14:29:40 -0400 Subject: [PATCH 05/43] lint applied --- blockchain/chain_sync/src/sync.rs | 6 ++++-- node/rpc/src/sync_api.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/blockchain/chain_sync/src/sync.rs b/blockchain/chain_sync/src/sync.rs index e4e53cb5ab8..215cfc168d1 100644 --- a/blockchain/chain_sync/src/sync.rs +++ b/blockchain/chain_sync/src/sync.rs @@ -1063,7 +1063,8 @@ mod tests { local_sender, event_receiver, genesis_ts, - )).unwrap(), + )) + .unwrap(), event_sender, test_receiver, ) @@ -1138,7 +1139,8 @@ mod tests { Cid::from_raw_cid("bafy2bzaceasssikoiintnok7f3sgnekfifarzobyr3r4f25sgxmn23q4c35ic") .unwrap(); - let root = compute_msg_meta(cs.state_manager.get_block_store_ref(), &[bls], &[secp]).unwrap(); + let root = + compute_msg_meta(cs.state_manager.get_block_store_ref(), &[bls], &[secp]).unwrap(); assert_eq!(root, expected_root); } diff --git a/node/rpc/src/sync_api.rs b/node/rpc/src/sync_api.rs index 0658c80cf53..b89d7ad76ad 100644 --- a/node/rpc/src/sync_api.rs +++ b/node/rpc/src/sync_api.rs @@ -129,7 +129,7 @@ mod tests { }); let state = Arc::new(RpcState { - chain_store : Arc::new(RwLock::new(ChainStore::new(Arc::new(MemoryDB::default())))), + chain_store: Arc::new(RwLock::new(ChainStore::new(Arc::new(MemoryDB::default())))), state_manager: StateManager::new(Arc::new(MemoryDB::default())), keystore: Arc::new(RwLock::new(wallet::MemKeyStore::new())), mpool: Arc::new(pool), From e10433b93adfc81aab12b0bdcf775b889c03ed98 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Mon, 31 Aug 2020 15:01:02 -0400 Subject: [PATCH 06/43] changed function --- blockchain/chain/src/store/chain_store.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 20f5d24e2fd..e431cd295bf 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -59,9 +59,9 @@ pub enum HeadChangeJson { impl From for HeadChangeJson { fn from(wrapper: HeadChange) -> Self { match wrapper { - HeadChange::Current(tipset) => HeadChangeJson::Revert((*tipset).clone().into()), + HeadChange::Current(tipset) => HeadChangeJson::Current((*tipset).clone().into()), - HeadChange::Apply(tipset) => HeadChangeJson::Revert((*tipset).clone().into()), + HeadChange::Apply(tipset) => HeadChangeJson::Apply((*tipset).clone().into()), HeadChange::Revert(tipset) => HeadChangeJson::Revert((*tipset).clone().into()), } } From bea4feb104170ce147b54398ee8c547f5f0a54a0 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Tue, 1 Sep 2020 11:56:30 -0400 Subject: [PATCH 07/43] Added json flag --- blockchain/chain/Cargo.toml | 3 ++ blockchain/chain/src/store/chain_store.rs | 47 +++++++++++++++-------- node/rpc/Cargo.toml | 2 +- node/rpc/src/chain_api.rs | 2 +- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/blockchain/chain/Cargo.toml b/blockchain/chain/Cargo.toml index c64dd1856d9..1eefbb3785f 100644 --- a/blockchain/chain/Cargo.toml +++ b/blockchain/chain/Cargo.toml @@ -30,6 +30,9 @@ futures ="0.3.5" async-std = { version = "1.6.3", features = ["unstable", "attributes"] } lazy_static = "1.4" +[features] +json = [] + [dev-dependencies] multihash = "0.10.0" test_utils = { version = "0.1.0", path = "../../utils/test_utils/", features = [ diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index e431cd295bf..62b690cebb8 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -9,7 +9,7 @@ use async_std::sync::Receiver; use async_std::task; use beacon::BeaconEntry; use blake2b_simd::Params; -use blocks::{tipset_json::TipsetJson, Block, BlockHeader, FullTipset, Tipset, TipsetKeys, TxMeta}; +use blocks::{Block, BlockHeader, FullTipset, Tipset, TipsetKeys, TxMeta}; use byteorder::{BigEndian, WriteBytesExt}; use cid::multihash::Blake2b256; use cid::Cid; @@ -24,7 +24,7 @@ use log::{info, warn}; use message::{ChainMessage, Message, MessageReceipt, SignedMessage, UnsignedMessage}; use num_bigint::BigInt; use num_traits::Zero; -use serde::{Deserialize, Serialize}; +use serde::{Serialize}; use state_tree::StateTree; use std::collections::HashMap; use std::io::Write; @@ -49,23 +49,8 @@ pub enum HeadChange { Apply(Arc), Revert(Arc), } -#[derive(Debug, Serialize, Deserialize)] -pub enum HeadChangeJson { - Current(TipsetJson), - Apply(TipsetJson), - Revert(TipsetJson), -} -impl From for HeadChangeJson { - fn from(wrapper: HeadChange) -> Self { - match wrapper { - HeadChange::Current(tipset) => HeadChangeJson::Current((*tipset).clone().into()), - HeadChange::Apply(tipset) => HeadChangeJson::Apply((*tipset).clone().into()), - HeadChange::Revert(tipset) => HeadChangeJson::Revert((*tipset).clone().into()), - } - } -} /// Generic implementation of the datastore trait and structures pub struct ChainStore { @@ -675,6 +660,34 @@ where Ok(out) } + +#[cfg(feature = "json")] +pub mod headchange_json { + use super::*; + use serde::{Deserialize, Serialize}; + use blocks::tipset_json::TipsetJson; + + #[derive(Debug, Serialize, Deserialize)] + pub enum HeadChangeJson { + Current(TipsetJson), + Apply(TipsetJson), + Revert(TipsetJson), + } + + impl From for HeadChangeJson { + fn from(wrapper: HeadChange) -> Self { + match wrapper { + HeadChange::Current(tipset) => HeadChangeJson::Current((*tipset).clone().into()), + + HeadChange::Apply(tipset) => HeadChangeJson::Apply((*tipset).clone().into()), + HeadChange::Revert(tipset) => HeadChangeJson::Revert((*tipset).clone().into()), + } + } + } + + +} + #[cfg(test)] mod tests { use super::*; diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index cd4b2897b87..996222d90e0 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -9,7 +9,7 @@ actor = { path = "../../vm/actor/" } async-std = { version = "1.6.3", features = ["attributes"] } serde = { version = "1.0.101", default-features = false, features = ["derive"] } serde_json = "1.0.48" -chain = { path = "../../blockchain/chain" } +chain = { path = "../../blockchain/chain" , features = ["json"]} chain_sync = { path = "../../blockchain/chain_sync" } blockstore = { package = "ipld_blockstore", path = "../../ipld/blockstore" } cid = { package = "forest_cid", path = "../../ipld/cid", features = ["json"] } diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index 66fc015e870..bc5aee0cc39 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -59,7 +59,7 @@ where pub(crate) async fn chain_notify( data: Data>, -) -> Result, JsonRpcError> +) -> Result, JsonRpcError> where DB: BlockStore + Send + Sync + 'static, KS: KeyStore + Send + Sync + 'static, From a4db0385f2a20840b48041ccf247ea92d7dcac60 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Tue, 1 Sep 2020 11:56:54 -0400 Subject: [PATCH 08/43] cargo fmt --- blockchain/chain/src/store/chain_store.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 62b690cebb8..25f3c2405c4 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -24,7 +24,7 @@ use log::{info, warn}; use message::{ChainMessage, Message, MessageReceipt, SignedMessage, UnsignedMessage}; use num_bigint::BigInt; use num_traits::Zero; -use serde::{Serialize}; +use serde::Serialize; use state_tree::StateTree; use std::collections::HashMap; use std::io::Write; @@ -50,8 +50,6 @@ pub enum HeadChange { Revert(Arc), } - - /// Generic implementation of the datastore trait and structures pub struct ChainStore { publisher: Publisher, @@ -660,12 +658,11 @@ where Ok(out) } - #[cfg(feature = "json")] pub mod headchange_json { use super::*; - use serde::{Deserialize, Serialize}; use blocks::tipset_json::TipsetJson; + use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] pub enum HeadChangeJson { @@ -684,8 +681,6 @@ pub mod headchange_json { } } } - - } #[cfg(test)] From d9324548c117878e8bc02c868f502aa7d44c47d4 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Thu, 3 Sep 2020 08:01:12 -0400 Subject: [PATCH 09/43] functional changes --- blockchain/chain/src/store/chain_store.rs | 41 +++++++++----- blockchain/chain_sync/src/sync.rs | 29 +++++----- node/forest_libp2p/src/service.rs | 3 +- node/rpc/Cargo.toml | 2 +- node/rpc/src/chain_api.rs | 13 ++--- node/rpc/src/lib.rs | 67 ++++++++++++----------- 6 files changed, 83 insertions(+), 72 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 25f3c2405c4..25d5a806aa5 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -4,8 +4,7 @@ use super::{Error, TipIndex, TipsetMetadata}; use actor::{power::State as PowerState, STORAGE_POWER_ACTOR_ADDR}; use address::Address; -use async_std::sync::channel; -use async_std::sync::Receiver; +use async_std::future; use async_std::task; use beacon::BeaconEntry; use blake2b_simd::Params; @@ -17,6 +16,9 @@ use clock::ChainEpoch; use crypto::DomainSeparationTag; use encoding::{blake2b_256, de::DeserializeOwned, from_slice, Cbor}; use flo_stream::{MessagePublisher, Publisher, Subscriber}; +use futures::channel::mpsc::channel; +use futures::channel::mpsc::Receiver; +use futures::sink::SinkExt; use futures::StreamExt; use ipld_amt::Amt; use ipld_blockstore::BlockStore; @@ -29,6 +31,7 @@ use state_tree::StateTree; use std::collections::HashMap; use std::io::Write; use std::sync::Arc; +use std::time::Duration; const GENESIS_KEY: &str = "gen_block"; const HEAD_KEY: &str = "head"; @@ -198,22 +201,29 @@ where } pub async fn sub_head_changes(&mut self) -> Result, Error> { - let mut subscribed_head_change = self.subscribe(); + let subscribed_head_change = self.subscribe(); + info!("sub head changes"); let head = self .heaviest_tipset() .ok_or_else(|| Error::Other("Could not get heaviest tipset".to_string()))?; - let (sender, reciever) = channel(16); - sender.send(HeadChange::Current(head)).await; + let (mut sender, reciever) = channel(16); + sender + .send(HeadChange::Current(head)) + .await + .map_err(|e| Error::Other(format!("Could not send to channel {:?}", e)))?; task::spawn(async move { - while let Some(val) = subscribed_head_change.next().await { - if !sender.is_empty() { - warn!( - "head change sub is slow, has {:} buffered entries", - sender.len() - ) - } - sender.send(val).await - } + let sender = &sender.clone(); + let wait_for_each = subscribed_head_change.for_each(|s| async move { + sender + .clone() + .send(s) + .await + .unwrap_or_else(|e| warn!("failed to send to channel : {:?}", e)); + }); + let dur = Duration::from_millis(10); + future::timeout(dur, wait_for_each) + .await + .unwrap_or_else(|_| info!("waited for head_change for 10 miliseconds")); }); Ok(reciever) } @@ -665,6 +675,8 @@ pub mod headchange_json { use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] + #[serde(untagged)] + #[serde(rename_all = "PascalCase")] pub enum HeadChangeJson { Current(TipsetJson), Apply(TipsetJson), @@ -675,7 +687,6 @@ pub mod headchange_json { fn from(wrapper: HeadChange) -> Self { match wrapper { HeadChange::Current(tipset) => HeadChangeJson::Current((*tipset).clone().into()), - HeadChange::Apply(tipset) => HeadChangeJson::Apply((*tipset).clone().into()), HeadChange::Revert(tipset) => HeadChangeJson::Revert((*tipset).clone().into()), } diff --git a/blockchain/chain_sync/src/sync.rs b/blockchain/chain_sync/src/sync.rs index 215cfc168d1..d9a69ac5d0d 100644 --- a/blockchain/chain_sync/src/sync.rs +++ b/blockchain/chain_sync/src/sync.rs @@ -301,8 +301,14 @@ where self.state.write().await.set_epoch(curr_epoch); // store messages - self.chain_store.write().await.put_messages(&b.bls_msgs)?; - self.chain_store.write().await.put_messages(&b.secp_msgs)?; + chain::persist_objects( + self.state_manager.get_block_store_ref(), + &b.bls_msgs, + )?; + chain::persist_objects( + self.state_manager.get_block_store_ref(), + &b.secp_msgs, + )?; } } i -= REQUEST_WINDOW; @@ -434,14 +440,8 @@ where return Err(Error::InvalidRoots); } - self.chain_store - .write() - .await - .put_messages(block.bls_msgs())?; - self.chain_store - .write() - .await - .put_messages(block.secp_msgs())?; + chain::persist_objects(self.state_manager.get_block_store_ref(), block.bls_msgs())?; + chain::persist_objects(self.state_manager.get_block_store_ref(), block.secp_msgs())?; Ok(()) } @@ -960,11 +960,10 @@ where "Synced chain forked at genesis, refusing to sync".to_string(), )); } - ts = self - .chain_store - .read() - .await - .tipset_from_keys(ts.parents())?; + ts = chain::tipset_from_keys( + self.state_manager.get_block_store_ref(), + ts.parents(), + )?; } if ts == tips[i] { return Ok(tips[0..=i].to_vec()); diff --git a/node/forest_libp2p/src/service.rs b/node/forest_libp2p/src/service.rs index ed16cb10032..f305a529f8a 100644 --- a/node/forest_libp2p/src/service.rs +++ b/node/forest_libp2p/src/service.rs @@ -259,7 +259,8 @@ where None => { break; } }, interval_event = interval.next() => if interval_event.is_some() { - info!("Peers connected: {}", swarm_stream.get_ref().peers().len()); + //info!("Peers connected: {}", swarm_stream.get_ref().peers().len()); + (); } }; } diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 996222d90e0..51661614be4 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -16,7 +16,7 @@ cid = { package = "forest_cid", path = "../../ipld/cid", features = ["json"] } blocks = { package = "forest_blocks", path = "../../blockchain/blocks", features = ["json"] } clock = { path = "../clock" } message = { package = "forest_message", path = "../../vm/message", features = ["json"] } -jsonrpc-v2 = { version = "0.5.2", features = ["easy-errors", "macros"] } +jsonrpc-v2 = { version = "0.5.2", path="../../../jsonrpc-v2", features = ["easy-errors", "macros"] } message_pool = { path = "../../blockchain/message_pool" } crypto = { package = "forest_crypto", path = "../../crypto", features = ["json"] } num-traits = "0.2.11" diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index bc5aee0cc39..31d58761dab 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -64,15 +64,10 @@ where DB: BlockStore + Send + Sync + 'static, KS: KeyStore + Send + Sync + 'static, { - Ok(data - .chain_store - .write() - .await - .sub_head_changes() - .await? - .map(|s| s.into()) - .collect() - .await) + let recieve_subhead_changes = data.chain_store.write().await.sub_head_changes().await?; + let vec: Vec = + recieve_subhead_changes.map(|s| s.into()).collect().await; + Ok(vec) } pub(crate) async fn chain_read_obj( diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index df07f6ef889..b2d6c327345 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -13,19 +13,17 @@ use async_log::span; use async_std::net::{TcpListener, TcpStream}; use async_std::sync::{RwLock, Sender}; use async_std::task; -use async_tungstenite::tungstenite::{error::Error, Message}; +use async_tungstenite::tungstenite::Message; use blockstore::BlockStore; use chain::ChainStore; use chain_sync::{BadBlockCache, SyncState}; use forest_libp2p::NetworkMessage; -use futures::future; use futures::sink::SinkExt; -use futures::stream::{StreamExt, TryStreamExt}; +use futures::stream::StreamExt; use jsonrpc_v2::{Data, MapRouter, RequestObject, Server}; -use log::{error, info}; +use log::{error, info, warn}; use message_pool::{MessagePool, MpoolRpcProvider}; use state_manager::StateManager; -use std::borrow::Cow; use std::sync::Arc; use wallet::KeyStore; /// This is where you store persistant data, or at least access to stateful data. @@ -178,36 +176,43 @@ async fn handle_connection_and_log( tcp_stream: TcpStream, addr: std::net::SocketAddr, ) { - span!("handle_connection", { + span!("handle_connection_and_log", { if let Ok(ws_stream) = async_tungstenite::accept_async(tcp_stream).await { info!("accepted websocket connection at {:}", addr); - let (mut ws_sender, ws_receiver) = ws_stream.split(); - let responses_result = ws_receiver - .try_filter(|s| future::ready(!s.is_text())) - .try_fold(Vec::new(), |mut responses, s| async { - let request_text = s.into_text()?; - let call: RequestObject = serde_json::from_str(&request_text) - .map_err(|s| Error::Protocol(Cow::from(s.to_string())))?; - let response = state.handle(call).await; - let response_text = serde_json::to_string(&response) - .map_err(|s| Error::Protocol(Cow::from(s.to_string())))?; - responses.push(response_text); - Ok(responses) - }) - .await; - - if let Err(error) = responses_result { - error!("error obtaining request {:?}", error) - } else { - for response_text in responses_result.unwrap() { - ws_sender - .send(Message::text(response_text)) - .await - .unwrap_or_else(|s| error!("Error sending response {:?}", s)) - } + let (mut ws_sender, mut ws_receiver) = ws_stream.split(); + while let Some(message_result) = ws_receiver.next().await { + let response_text = match message_result { + Ok(message) => { + let request_text = message.into_text().unwrap(); + info!( + "serde request {:?}", + serde_json::to_string_pretty(&request_text).unwrap() + ); + match serde_json::from_str(&request_text) as Result { + Ok(call) => { + let response = state.handle(call).await; + let response_text = serde_json::to_string_pretty(&response) + .expect("all items returned should be properly serialized"); + Message::text(response_text) + } + Err(e) => { + let error_string = format!("error : {:?}", e); + Message::text(error_string) + } + } + } + Err(e) => { + let error_string = format!("error : {:?}", e); + Message::text(error_string) + } + }; + ws_sender + .send(response_text) + .await + .unwrap_or_else(|e| error!("error obtaining result {:?}", e)); } } else { - error!("web socket connection failed at {:}", addr) + warn!("web socket connection failed at {:}", addr) } }) } From ebcff0fc3a65a83112dd44f090dadd90a0612971 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Thu, 3 Sep 2020 08:07:17 -0400 Subject: [PATCH 10/43] removed path from compilation --- node/rpc/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 51661614be4..996222d90e0 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -16,7 +16,7 @@ cid = { package = "forest_cid", path = "../../ipld/cid", features = ["json"] } blocks = { package = "forest_blocks", path = "../../blockchain/blocks", features = ["json"] } clock = { path = "../clock" } message = { package = "forest_message", path = "../../vm/message", features = ["json"] } -jsonrpc-v2 = { version = "0.5.2", path="../../../jsonrpc-v2", features = ["easy-errors", "macros"] } +jsonrpc-v2 = { version = "0.5.2", features = ["easy-errors", "macros"] } message_pool = { path = "../../blockchain/message_pool" } crypto = { package = "forest_crypto", path = "../../crypto", features = ["json"] } num-traits = "0.2.11" From 8ae4202ba729d77cc54f06f5363eb0a3765ce2d3 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Thu, 3 Sep 2020 08:14:06 -0400 Subject: [PATCH 11/43] moar fixes --- blockchain/chain/src/store/chain_store.rs | 14 +------------- forest/src/daemon.rs | 1 - 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 25d5a806aa5..ed989f0a96c 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -165,19 +165,7 @@ where /// Constructs and returns a full tipset if messages from storage exists pub fn fill_tipsets(&self, ts: Tipset) -> Result { - let mut blocks: Vec = Vec::with_capacity(ts.blocks().len()); - - for header in ts.into_blocks() { - let (bls_messages, secp_messages) = block_messages(self.blockstore(), &header)?; - blocks.push(Block { - header, - bls_messages, - secp_messages, - }); - } - - // the given tipset has already been verified, so this cannot fail - Ok(FullTipset::new(blocks).unwrap()) + fill_tipsets(self.blockstore(), ts) } /// Determines if provided tipset is heavier than existing known heaviest tipset diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index 1c20359f54e..375308598ca 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -92,7 +92,6 @@ pub(super) async fn start(config: Config) { ) .await .unwrap(); - info!("init chain syncher"); let bad_blocks = chain_syncer.bad_blocks_cloned(); let sync_state = chain_syncer.sync_state_cloned(); let sync_task = task::spawn(async { From b744a3909d8079865e811ddf9ecccfb2d8ae896b Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Thu, 10 Sep 2020 13:01:06 -0400 Subject: [PATCH 12/43] removed chain store mutex --- Cargo.lock | 186 ++++++++-------------- blockchain/chain/src/store/chain_store.rs | 141 +++++++++++----- blockchain/chain_sync/src/sync.rs | 53 +++--- blockchain/message_pool/src/msgpool.rs | 5 +- forest/src/daemon.rs | 15 +- node/rpc/Cargo.toml | 1 + node/rpc/src/chain_api.rs | 4 +- node/rpc/src/lib.rs | 7 +- 8 files changed, 220 insertions(+), 192 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e3073256c0..f047b6d2308 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,7 +79,7 @@ dependencies = [ "lazy_static", "log", "mime", - "percent-encoding 2.1.0", + "percent-encoding", "pin-project", "rand 0.7.3", "regex", @@ -543,7 +543,7 @@ dependencies = [ "async-std", "byte-pool", "futures-core", - "http-types 2.4.0", + "http-types", "httparse", "lazy_static", "log", @@ -623,19 +623,6 @@ dependencies = [ "syn 1.0.38", ] -[[package]] -name = "async-sse" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6de73294dd1287b32b10f4c884186446353048f183071dff38c1481f82c053b3" -dependencies = [ - "async-std", - "http-types 1.3.1", - "log", - "memchr", - "pin-project-lite", -] - [[package]] name = "async-std" version = "1.6.3" @@ -706,6 +693,19 @@ dependencies = [ "syn 1.0.38", ] +[[package]] +name = "async-tungstenite" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5c45a0dd44b7e6533ac4e7acc38ead1a3b39885f5bbb738140d30ea528abc7c" +dependencies = [ + "futures-io", + "futures-util", + "log", + "pin-project", + "tungstenite", +] + [[package]] name = "atomic" version = "0.4.6" @@ -751,7 +751,7 @@ dependencies = [ "futures-core", "log", "mime", - "percent-encoding 2.1.0", + "percent-encoding", "rand 0.7.3", "serde", "serde_json", @@ -1225,6 +1225,7 @@ name = "chain" version = "0.1.0" dependencies = [ "actor", + "async-std", "beacon", "blake2b_simd", "byteorder 1.3.4", @@ -1238,6 +1239,7 @@ dependencies = [ "forest_crypto", "forest_encoding", "forest_message", + "futures 0.3.5", "ipld_amt", "ipld_blockstore", "lazy_static", @@ -1476,15 +1478,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -[[package]] -name = "cookie" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" -dependencies = [ - "time 0.1.43", -] - [[package]] name = "cookie" version = "0.14.2" @@ -1495,7 +1488,7 @@ dependencies = [ "base64 0.12.3", "hkdf 0.9.0", "hmac 0.8.1", - "percent-encoding 2.1.0", + "percent-encoding", "rand 0.7.3", "sha2 0.9.1", "time 0.2.16", @@ -2134,22 +2127,6 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bd3bdaaf0a72155260a1c098989b60db1cbb22d6a628e64f16237aa4da93cc7" -[[package]] -name = "femme" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af1a24f391a5a94d756db5092c6576aad494b88a71a5a36b20c67b63e0df034" -dependencies = [ - "cfg-if", - "js-sys", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "ff-cl-gen" version = "0.1.3" @@ -3164,7 +3141,7 @@ dependencies = [ "async-native-tls", "async-std", "futures 0.3.5", - "http-types 2.4.0", + "http-types", "isahc", "js-sys", "log", @@ -3173,23 +3150,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "http-types" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49d9f44462c2e59d5d5826e7ba74b121ee2fb0ff091ef849692694f1d77aaf50" -dependencies = [ - "anyhow", - "async-std", - "cookie 0.12.0", - "infer", - "omnom", - "pin-project-lite", - "serde", - "serde_json", - "url", -] - [[package]] name = "http-types" version = "2.4.0" @@ -3198,13 +3158,13 @@ checksum = "bb4daf8dc001485f4a32a7a17c54c67fa8a10340188f30ba87ac0fe1a9451e97" dependencies = [ "anyhow", "async-std", - "cookie 0.14.2", + "cookie", "infer", "pin-project-lite", "rand 0.7.3", "serde", "serde_json", - "serde_qs 0.6.1", + "serde_qs", "serde_urlencoded", "url", ] @@ -3313,6 +3273,15 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6854dd77ddc4f9ba1a448f487e27843583d407648150426a30c2ea3a2c39490a" +[[package]] +name = "input_buffer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754" +dependencies = [ + "bytes 0.5.6", +] + [[package]] name = "instant" version = "0.1.6" @@ -4716,15 +4685,6 @@ dependencies = [ "num", ] -[[package]] -name = "omnom" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b216cee2e0d6e680f73158d15468c80b39e571c11669cd90556f9a644e9fd3" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.4.1" @@ -4828,7 +4788,7 @@ dependencies = [ "byteorder 1.3.4", "data-encoding", "multihash 0.11.2", - "percent-encoding 2.1.0", + "percent-encoding", "serde", "static_assertions", "unsigned-varint 0.4.0", @@ -4947,12 +4907,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.1.0" @@ -5542,7 +5496,7 @@ dependencies = [ "mime", "mime_guess", "native-tls", - "percent-encoding 2.1.0", + "percent-encoding", "pin-project-lite", "serde", "serde_urlencoded", @@ -5590,24 +5544,21 @@ dependencies = [ "librocksdb-sys", ] -[[package]] -name = "route-recognizer" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea509065eb0b3c446acdd0102f0d46567dc30902dc0be91d6552035d92b0f4f8" - [[package]] name = "rpc" version = "0.1.0" dependencies = [ "actor", + "async-log", "async-std", + "async-tungstenite", "bitfield", "chain", "chain_sync", "clock", "db", "fil_types", + "flo_stream", "forest_address", "forest_bigint", "forest_blocks", @@ -5622,6 +5573,7 @@ dependencies = [ "ipld_blockstore", "jsonrpc-v2", "key_management", + "log", "message_pool", "num-traits 0.2.12", "rand 0.7.3", @@ -5632,7 +5584,6 @@ dependencies = [ "state_tree", "test_utils", "thiserror", - "tide", ] [[package]] @@ -5935,18 +5886,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_qs" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43eef44996bbe16e99ac720e1577eefa16f7b76b5172165c98ced20ae9903e1" -dependencies = [ - "data-encoding", - "error-chain", - "percent-encoding 1.0.1", - "serde", -] - [[package]] name = "serde_qs" version = "0.6.1" @@ -5955,7 +5894,7 @@ checksum = "c6f3acf84e23ab27c01cb5917551765c01c50b2000089db8fa47fe018a3260cf" dependencies = [ "data-encoding", "error-chain", - "percent-encoding 2.1.0", + "percent-encoding", "serde", ] @@ -6596,7 +6535,7 @@ dependencies = [ "encoding_rs", "futures 0.3.5", "http-client", - "http-types 2.4.0", + "http-types", "log", "mime", "mime_guess", @@ -6771,26 +6710,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "tide" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9620c27936f084db0613d82507e3c6e8be64cb1a26e0c721a2796b5a8c7a515" -dependencies = [ - "async-h1", - "async-sse", - "async-std", - "femme", - "http-types 2.4.0", - "kv-log-macro", - "mime", - "mime_guess", - "route-recognizer", - "serde", - "serde_json", - "serde_qs 0.5.2", -] - [[package]] name = "time" version = "0.1.43" @@ -7080,6 +6999,25 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +[[package]] +name = "tungstenite" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0308d80d86700c5878b9ef6321f020f29b1bb9d5ff3cab25e75e23f3a492a23" +dependencies = [ + "base64 0.12.3", + "byteorder 1.3.4", + "bytes 0.5.6", + "http", + "httparse", + "input_buffer", + "log", + "rand 0.7.3", + "sha-1 0.9.1", + "url", + "utf-8", +] + [[package]] name = "twofish" version = "0.2.0" @@ -7210,10 +7148,16 @@ checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" dependencies = [ "idna", "matches", - "percent-encoding 2.1.0", + "percent-encoding", "serde", ] +[[package]] +name = "utf-8" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" + [[package]] name = "utils" version = "0.1.0" diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index ed989f0a96c..53110b76601 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -32,6 +32,7 @@ use std::collections::HashMap; use std::io::Write; use std::sync::Arc; use std::time::Duration; +use async_std::sync::RwLock; const GENESIS_KEY: &str = "gen_block"; const HEAD_KEY: &str = "head"; @@ -55,16 +56,16 @@ pub enum HeadChange { /// Generic implementation of the datastore trait and structures pub struct ChainStore { - publisher: Publisher, + publisher: Arc>>, // key-value datastore pub db: Arc, // Tipset at the head of the best-known chain. - heaviest: Option>, + heaviest: Arc>>>, // tip_index tracks tipsets by epoch/parentset for use by expected consensus. - tip_index: TipIndex, + tip_index: Arc>, } impl ChainStore @@ -78,34 +79,36 @@ where .map(Arc::new); Self { db, - publisher: Publisher::new(SINK_CAP), - tip_index: TipIndex::new(), - heaviest, + publisher: Arc::new(RwLock::new(Publisher::new(SINK_CAP))), + tip_index: Arc::new(RwLock::new(TipIndex::new())), + heaviest : Arc::new(RwLock::new(heaviest)), } } /// Sets heaviest tipset within ChainStore and store its tipset cids under HEAD_KEY pub async fn set_heaviest_tipset(&mut self, ts: Arc) -> Result<(), Error> { self.db.write(HEAD_KEY, ts.key().marshal_cbor()?)?; - self.heaviest = Some(ts.clone()); - self.publisher.publish(HeadChange::Current(ts)).await; + *self.heaviest.write().await = Some(ts.clone()); + self.publisher.write().await.publish(HeadChange::Current(ts)).await; Ok(()) } + + // subscribing returns a future sink that we can essentially iterate over using future streams - pub fn subscribe(&mut self) -> Subscriber { - self.publisher.subscribe() + pub async fn subscribe(&mut self) -> Subscriber { + self.publisher.write().await.subscribe() } /// Sets tip_index tracker - pub fn set_tipset_tracker(&mut self, header: &BlockHeader) -> Result<(), Error> { + pub async fn set_tipset_tracker(&mut self, header: &BlockHeader) -> Result<(), Error> { let ts: Tipset = Tipset::new(vec![header.clone()])?; let meta = TipsetMetadata { tipset_state_root: header.state_root().clone(), tipset_receipts_root: header.message_receipts().clone(), tipset: ts, }; - self.tip_index.put(&meta); + self.tip_index.write().await.put(&meta); Ok(()) } @@ -136,8 +139,10 @@ where // set as heaviest tipset let heaviest_ts = Arc::new(heaviest_ts); - self.heaviest = Some(heaviest_ts.clone()); + *self.heaviest.write().await = Some(heaviest_ts.clone()); self.publisher + .write() + .await .publish(HeadChange::Current(heaviest_ts)) .await; Ok(()) @@ -149,10 +154,31 @@ where } /// Returns heaviest tipset from blockstore - pub fn heaviest_tipset(&self) -> Option> { + pub async fn heaviest_tipset(&self) -> Option> { + (*self.heaviest.read().await).clone() + } + + pub fn heaviest_tipset_ref(&mut self) -> Arc>>> + { self.heaviest.clone() } + pub fn publisher_ref(&self) -> Arc>> + { + self.publisher.clone() + } + + pub fn tip_index_ref(&mut self) -> Arc> + { + self.tip_index.clone() + } + + + pub fn blockstore_arc(&self) -> Arc + { + self.db.clone() + } + /// Returns key-value store instance pub fn blockstore(&self) -> &DB { &self.db @@ -170,7 +196,9 @@ where /// Determines if provided tipset is heavier than existing known heaviest tipset async fn update_heaviest(&mut self, ts: &Tipset) -> Result<(), Error> { - match &self.heaviest { + + + match &*self.heaviest.clone().read().await { Some(heaviest) => { let new_weight = weight(self.blockstore(), ts)?; let curr_weight = weight(self.blockstore(), &heaviest)?; @@ -188,33 +216,64 @@ where Ok(()) } - pub async fn sub_head_changes(&mut self) -> Result, Error> { - let subscribed_head_change = self.subscribe(); - info!("sub head changes"); - let head = self - .heaviest_tipset() - .ok_or_else(|| Error::Other("Could not get heaviest tipset".to_string()))?; - let (mut sender, reciever) = channel(16); - sender - .send(HeadChange::Current(head)) - .await - .map_err(|e| Error::Other(format!("Could not send to channel {:?}", e)))?; - task::spawn(async move { - let sender = &sender.clone(); - let wait_for_each = subscribed_head_change.for_each(|s| async move { - sender - .clone() - .send(s) - .await - .unwrap_or_else(|e| warn!("failed to send to channel : {:?}", e)); - }); - let dur = Duration::from_millis(10); - future::timeout(dur, wait_for_each) - .await - .unwrap_or_else(|_| info!("waited for head_change for 10 miliseconds")); - }); - Ok(reciever) + + + +} + + +pub async fn put_tipset_lock(heaviest_lock : Arc>>>,ts: &Tipset,publisher:Arc>>,db : Arc) -> Result<(), Error> where DB : BlockStore +{ + persist_objects(&*db, ts.blocks())?; + update_heaviest_lock(heaviest_lock,ts,publisher,db).await +} + +pub async fn set_heaviest_tipset_lock(heaviest : Arc>>>,ts: Arc,publisher:Arc>>,db : Arc) -> Result<(), Error> where DB : BlockStore +{ + db.write(HEAD_KEY, ts.key().marshal_cbor()?)?; + let mut heaviest = heaviest.write().await; + *heaviest = Some(ts.clone()); + publisher.write().await.publish(HeadChange::Current(ts)).await; + Ok(()) +} + +pub async fn update_heaviest_lock(heaviest_lock : Arc>>>,ts: &Tipset,publisher:Arc>>,db : Arc) -> Result<(), Error> where DB : BlockStore{ + match &*heaviest_lock.read().await { + Some(heaviest) => { + let new_weight = weight(&*db, &ts)?; + let curr_weight = weight(&*db, &heaviest)?; + if new_weight > curr_weight { + // TODO potentially need to deal with re-orgs here + info!("New heaviest tipset"); + set_heaviest_tipset_lock(heaviest_lock.clone(),Arc::new(ts.clone()),publisher,db).await?; + } + } + None => { + info!("set heaviest tipset"); + set_heaviest_tipset_lock(heaviest_lock.clone(),Arc::new(ts.clone()),publisher,db).await?; + } } + Ok(()) +} + +pub async fn sub_head_changes(mut subscribed_head_change : Subscriber,heaviest_tipset : &Option>) -> Result, Error> { + + info!("sub head changes"); + let head = heaviest_tipset.as_ref() + .ok_or_else(|| Error::Other("Could not get heaviest tipset".to_string()))?; + let (mut sender, reciever) = channel(16); + sender + .send(HeadChange::Current(head.clone())) + .await + .map_err(|e| Error::Other(format!("Could not send to channel {:?}", e)))?; + task::spawn(async move { + let dur = Duration::from_millis(10); + while let Ok(Some(change)) = future::timeout(dur,subscribed_head_change.next()).await + { + sender.clone().send(change).await.unwrap_or_else(|e| warn!("failed to send to channel : {:?}", e)); + } + }); + Ok(reciever) } /// Returns messages for a given tipset from db diff --git a/blockchain/chain_sync/src/sync.rs b/blockchain/chain_sync/src/sync.rs index d9a69ac5d0d..27321cbfa10 100644 --- a/blockchain/chain_sync/src/sync.rs +++ b/blockchain/chain_sync/src/sync.rs @@ -16,7 +16,7 @@ use async_std::sync::{Receiver, RwLock, Sender}; use async_std::task; use beacon::{Beacon, BeaconEntry}; use blocks::{Block, BlockHeader, FullTipset, Tipset, TipsetKeys, TxMeta}; -use chain::{persist_objects, ChainStore}; +use chain::persist_objects; use cid::{multihash::Blake2b256, Cid}; use commcid::cid_to_replica_commitment_v1; use core::time::Duration; @@ -46,6 +46,8 @@ use std::collections::{BTreeMap, HashMap}; use std::convert::{TryFrom, TryInto}; use std::sync::Arc; use vm::TokenAmount; +use chain::{TipIndex,HeadChange}; +use chain::TipsetMetadata; /// Struct that handles the ChainSync logic. This handles incoming network events such as /// gossipsub messages, Hello protocol requests, as well as sending and receiving BlockSync @@ -67,8 +69,14 @@ pub struct ChainSyncer { /// Represents next tipset to be synced next_sync_target: SyncBucket, - /// access and store tipsets / blocks / messages - chain_store: Arc>>, + // heaviest tipset + heaviest_tipset : Arc>>>, + + // publisher chain store + publisher : Arc>>, + + // refrence to tip_index + tip_index : Arc>, /// Context to be able to send requests to p2p network network: SyncNetworkContext, @@ -98,14 +106,17 @@ where TBeacon: Beacon + Send, DB: BlockStore + Sync + Send + 'static, { - pub async fn new( - chain_store: Arc>>, + pub fn new( + data_store: Arc, beacon: Arc, network_send: Sender, network_rx: Receiver, genesis: Tipset, + heaviest_tipset : Arc>>>, + publisher : Arc>>, + tip_index : Arc> ) -> Result { - let state_manager = Arc::new(StateManager::new(chain_store.read().await.db.clone())); + let state_manager = Arc::new(StateManager::new(data_store.clone())); // Split incoming channel to handle blocksync requests let mut event_send = Publisher::new(30); @@ -119,14 +130,16 @@ where state: Arc::new(RwLock::new(SyncState::default())), beacon, state_manager, - chain_store, + heaviest_tipset, network, genesis, + publisher, bad_blocks: Arc::new(BadBlockCache::default()), net_handler, peer_manager, sync_queue: SyncBucketSet::default(), next_sync_target: SyncBucket::default(), + tip_index }) } @@ -167,7 +180,7 @@ where } } NetworkEvent::PeerDialed { peer_id } => { - let heaviest = self.chain_store.read().await.heaviest_tipset().unwrap(); + let heaviest = (self.heaviest_tipset.read().await).as_ref().unwrap().clone(); self.network .hello_request( peer_id, @@ -202,7 +215,7 @@ where } // Get heaviest tipset from storage to sync toward - let heaviest = self.chain_store.read().await.heaviest_tipset().unwrap(); + let heaviest = self.heaviest_tipset.read().await.as_ref().unwrap().clone(); info!("Starting block sync..."); @@ -212,7 +225,7 @@ where .await .init(heaviest.clone(), head.clone()); let tipsets = match self - .sync_headers_reverse(head.as_ref().clone(), &heaviest) + .sync_headers_reverse(head.as_ref().clone(), &heaviest.clone()) .await { Ok(ts) => ts, @@ -239,11 +252,7 @@ where self.set_stage(SyncStage::Complete).await; // At this point the head is synced and the head can be set as the heaviest. - self.chain_store - .write() - .await - .put_tipset(head.as_ref()) - .await?; + chain::put_tipset_lock(self.heaviest_tipset.clone(),&head,self.publisher.clone(),self.state_manager.get_block_store()).await?; Ok(()) } @@ -345,7 +354,7 @@ where } // compare target_weight to heaviest weight stored; ignore otherwise - let best_weight = match self.chain_store.read().await.heaviest_tipset() { + let best_weight = match &*self.heaviest_tipset.read().await { Some(ts) => ts.weight().clone(), None => Zero::zero(), }; @@ -731,10 +740,14 @@ where self.bad_blocks.put(b.cid().clone(), e.to_string()).await; return Err(Error::Other("Invalid blocks detected".to_string())); } - self.chain_store - .write() - .await - .set_tipset_tracker(b.header())?; + let header = b.header(); + let ts: Tipset = Tipset::new(vec![header.clone()])?; + let meta = TipsetMetadata { + tipset_state_root: header.state_root().clone(), + tipset_receipts_root: header.message_receipts().clone(), + tipset: ts, + }; + self.tip_index.write().await.put(&meta); } Ok(()) } diff --git a/blockchain/message_pool/src/msgpool.rs b/blockchain/message_pool/src/msgpool.rs index 1dbf3724f2d..77671a0ee7f 100644 --- a/blockchain/message_pool/src/msgpool.rs +++ b/blockchain/message_pool/src/msgpool.rs @@ -118,11 +118,12 @@ where DB: BlockStore, { fn subscribe_head_changes(&mut self) -> Subscriber { - self.cs.subscribe() + task::block_on(self.cs.subscribe()) + } fn get_heaviest_tipset(&mut self) -> Option { - let ts = self.cs.heaviest_tipset()?; + let ts = task::block_on(self.cs.heaviest_tipset())?; Some(ts.as_ref().clone()) } diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index 4c3bf3f7af8..e250189c0fb 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -61,7 +61,7 @@ pub(super) async fn start(config: Config) { let network_send = p2p_service.network_sender(); // Initialize mpool let subscriber = chain_store.subscribe(); - let provider = MpoolRpcProvider::new(subscriber, Arc::clone(&db)); + let provider = MpoolRpcProvider::new(subscriber.await, Arc::clone(&db)); let mpool = Arc::new( MessagePool::new(provider, network_name.clone()) .await @@ -81,15 +81,18 @@ pub(super) async fn start(config: Config) { .unwrap(); // Initialize ChainSyncer - let chain_store = Arc::new(RwLock::new(chain_store)); + let heaviest_tipset = chain_store.heaviest_tipset_ref(); + let publisher = chain_store.publisher_ref(); let chain_syncer = ChainSyncer::new( - chain_store.clone(), + chain_store.blockstore_arc(), Arc::new(beacon), network_send.clone(), network_rx, genesis, + heaviest_tipset.clone(), + publisher, + chain_store.tip_index_ref() ) - .await .unwrap(); let bad_blocks = chain_syncer.bad_blocks_cloned(); let sync_state = chain_syncer.sync_state_cloned(); @@ -102,6 +105,7 @@ pub(super) async fn start(config: Config) { p2p_service.run().await; }); + let subscriber = chain_store.subscribe().await; let rpc_task = if config.enable_rpc { let db_rpc = StateManager::new(Arc::clone(&db)); let keystore_rpc = Arc::clone(&keystore); @@ -111,13 +115,14 @@ pub(super) async fn start(config: Config) { start_rpc( RpcState { state_manager: db_rpc, - chain_store, keystore: keystore_rpc, mpool, bad_blocks, sync_state, network_send, network_name, + heaviest_tipset, + subscriber }, &rpc_listen, ) diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 996222d90e0..096a4c380f7 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -37,6 +37,7 @@ futures = "0.3.5" async-tungstenite = "0.8.0" async-log = "2.0.0" log ="0.4.8" +flo_stream = "0.4.0" [dev-dependencies] db = { path = "../db" } diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index 31d58761dab..62ff92878b0 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -64,9 +64,11 @@ where DB: BlockStore + Send + Sync + 'static, KS: KeyStore + Send + Sync + 'static, { - let recieve_subhead_changes = data.chain_store.write().await.sub_head_changes().await?; + let heaviest_tipset = data.heaviest_tipset.read().await; + let recieve_subhead_changes = chain::sub_head_changes(data.subscriber.clone(),&heaviest_tipset).await?; let vec: Vec = recieve_subhead_changes.map(|s| s.into()).collect().await; + Ok(vec) } diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index b2d6c327345..efae548b095 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -15,7 +15,6 @@ use async_std::sync::{RwLock, Sender}; use async_std::task; use async_tungstenite::tungstenite::Message; use blockstore::BlockStore; -use chain::ChainStore; use chain_sync::{BadBlockCache, SyncState}; use forest_libp2p::NetworkMessage; use futures::sink::SinkExt; @@ -26,6 +25,9 @@ use message_pool::{MessagePool, MpoolRpcProvider}; use state_manager::StateManager; use std::sync::Arc; use wallet::KeyStore; +use blocks::Tipset; +use flo_stream::Subscriber; +use chain::HeadChange; /// This is where you store persistant data, or at least access to stateful data. pub struct RpcState where @@ -33,8 +35,9 @@ where KS: KeyStore + Send + Sync + 'static, { pub state_manager: StateManager, - pub chain_store: Arc>>, pub keystore: Arc>, + pub heaviest_tipset : Arc>>>, + pub subscriber : Subscriber, pub mpool: Arc>>, pub bad_blocks: Arc, pub sync_state: Arc>, From 1ce8bc9909031744d830e10c3edc821cb0413d2b Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Tue, 15 Sep 2020 14:07:46 -0400 Subject: [PATCH 13/43] changes to streaming --- blockchain/blocks/src/tipset.rs | 2 +- blockchain/chain/src/store/chain_store.rs | 126 +++++---- blockchain/chain_sync/src/sync.rs | 33 ++- blockchain/message_pool/src/msgpool.rs | 1 - forest/Cargo.toml | 1 + forest/src/daemon.rs | 7 +- node/rpc/Cargo.toml | 2 +- node/rpc/src/chain_api.rs | 40 +-- node/rpc/src/gas_api.rs | 10 +- node/rpc/src/lib.rs | 315 +++++++++++++++++----- node/rpc/src/mpool_api.rs | 15 +- node/rpc/src/state_api.rs | 44 ++- node/rpc/src/sync_api.rs | 9 +- node/rpc/src/wallet_api.rs | 22 +- 14 files changed, 441 insertions(+), 186 deletions(-) diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index 124db17563e..d844b2277c6 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -271,7 +271,7 @@ pub mod tipset_json { use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; /// Wrapper for serializing and deserializing a SignedMessage from JSON. - #[derive(Deserialize, Serialize, Debug)] + #[derive(Deserialize, Serialize, Debug, Clone)] #[serde(transparent)] pub struct TipsetJson(#[serde(with = "self")] pub Tipset); diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 53110b76601..42643175350 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -5,6 +5,7 @@ use super::{Error, TipIndex, TipsetMetadata}; use actor::{power::State as PowerState, STORAGE_POWER_ACTOR_ADDR}; use address::Address; use async_std::future; +use async_std::sync::RwLock; use async_std::task; use beacon::BeaconEntry; use blake2b_simd::Params; @@ -32,7 +33,6 @@ use std::collections::HashMap; use std::io::Write; use std::sync::Arc; use std::time::Duration; -use async_std::sync::RwLock; const GENESIS_KEY: &str = "gen_block"; const HEAD_KEY: &str = "head"; @@ -81,7 +81,7 @@ where db, publisher: Arc::new(RwLock::new(Publisher::new(SINK_CAP))), tip_index: Arc::new(RwLock::new(TipIndex::new())), - heaviest : Arc::new(RwLock::new(heaviest)), + heaviest: Arc::new(RwLock::new(heaviest)), } } @@ -89,12 +89,14 @@ where pub async fn set_heaviest_tipset(&mut self, ts: Arc) -> Result<(), Error> { self.db.write(HEAD_KEY, ts.key().marshal_cbor()?)?; *self.heaviest.write().await = Some(ts.clone()); - self.publisher.write().await.publish(HeadChange::Current(ts)).await; + self.publisher + .write() + .await + .publish(HeadChange::Current(ts)) + .await; Ok(()) } - - // subscribing returns a future sink that we can essentially iterate over using future streams pub async fn subscribe(&mut self) -> Subscriber { self.publisher.write().await.subscribe() @@ -158,24 +160,19 @@ where (*self.heaviest.read().await).clone() } - pub fn heaviest_tipset_ref(&mut self) -> Arc>>> - { + pub fn heaviest_tipset_ref(&mut self) -> Arc>>> { self.heaviest.clone() } - pub fn publisher_ref(&self) -> Arc>> - { + pub fn publisher_ref(&self) -> Arc>> { self.publisher.clone() } - pub fn tip_index_ref(&mut self) -> Arc> - { + pub fn tip_index_ref(&mut self) -> Arc> { self.tip_index.clone() } - - pub fn blockstore_arc(&self) -> Arc - { + pub fn blockstore_arc(&self) -> Arc { self.db.clone() } @@ -196,8 +193,6 @@ where /// Determines if provided tipset is heavier than existing known heaviest tipset async fn update_heaviest(&mut self, ts: &Tipset) -> Result<(), Error> { - - match &*self.heaviest.clone().read().await { Some(heaviest) => { let new_weight = weight(self.blockstore(), ts)?; @@ -215,29 +210,50 @@ where } Ok(()) } - - - - } - -pub async fn put_tipset_lock(heaviest_lock : Arc>>>,ts: &Tipset,publisher:Arc>>,db : Arc) -> Result<(), Error> where DB : BlockStore +pub async fn put_tipset_lock( + heaviest_lock: Arc>>>, + ts: &Tipset, + publisher: Arc>>, + db: Arc, +) -> Result<(), Error> +where + DB: BlockStore, { persist_objects(&*db, ts.blocks())?; - update_heaviest_lock(heaviest_lock,ts,publisher,db).await + update_heaviest_lock(heaviest_lock, ts, publisher, db).await } -pub async fn set_heaviest_tipset_lock(heaviest : Arc>>>,ts: Arc,publisher:Arc>>,db : Arc) -> Result<(), Error> where DB : BlockStore +pub async fn set_heaviest_tipset_lock( + heaviest: Arc>>>, + ts: Arc, + publisher: Arc>>, + db: Arc, +) -> Result<(), Error> +where + DB: BlockStore, { db.write(HEAD_KEY, ts.key().marshal_cbor()?)?; let mut heaviest = heaviest.write().await; *heaviest = Some(ts.clone()); - publisher.write().await.publish(HeadChange::Current(ts)).await; + publisher + .write() + .await + .publish(HeadChange::Current(ts)) + .await; Ok(()) } -pub async fn update_heaviest_lock(heaviest_lock : Arc>>>,ts: &Tipset,publisher:Arc>>,db : Arc) -> Result<(), Error> where DB : BlockStore{ +pub async fn update_heaviest_lock( + heaviest_lock: Arc>>>, + ts: &Tipset, + publisher: Arc>>, + db: Arc, +) -> Result<(), Error> +where + DB: BlockStore, +{ match &*heaviest_lock.read().await { Some(heaviest) => { let new_weight = weight(&*db, &ts)?; @@ -245,37 +261,24 @@ pub async fn update_heaviest_lock(heaviest_lock : Arc curr_weight { // TODO potentially need to deal with re-orgs here info!("New heaviest tipset"); - set_heaviest_tipset_lock(heaviest_lock.clone(),Arc::new(ts.clone()),publisher,db).await?; + set_heaviest_tipset_lock( + heaviest_lock.clone(), + Arc::new(ts.clone()), + publisher, + db, + ) + .await?; } } None => { info!("set heaviest tipset"); - set_heaviest_tipset_lock(heaviest_lock.clone(),Arc::new(ts.clone()),publisher,db).await?; + set_heaviest_tipset_lock(heaviest_lock.clone(), Arc::new(ts.clone()), publisher, db) + .await?; } } Ok(()) } -pub async fn sub_head_changes(mut subscribed_head_change : Subscriber,heaviest_tipset : &Option>) -> Result, Error> { - - info!("sub head changes"); - let head = heaviest_tipset.as_ref() - .ok_or_else(|| Error::Other("Could not get heaviest tipset".to_string()))?; - let (mut sender, reciever) = channel(16); - sender - .send(HeadChange::Current(head.clone())) - .await - .map_err(|e| Error::Other(format!("Could not send to channel {:?}", e)))?; - task::spawn(async move { - let dur = Duration::from_millis(10); - while let Ok(Some(change)) = future::timeout(dur,subscribed_head_change.next()).await - { - sender.clone().send(change).await.unwrap_or_else(|e| warn!("failed to send to channel : {:?}", e)); - } - }); - Ok(reciever) -} - /// Returns messages for a given tipset from db pub fn unsigned_messages_for_tipset(db: &DB, h: &Tipset) -> Result, Error> where @@ -719,9 +722,10 @@ where pub mod headchange_json { use super::*; use blocks::tipset_json::TipsetJson; + use futures::Sink; use serde::{Deserialize, Serialize}; - #[derive(Debug, Serialize, Deserialize)] + #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(untagged)] #[serde(rename_all = "PascalCase")] pub enum HeadChangeJson { @@ -739,6 +743,30 @@ pub mod headchange_json { } } } + + pub async fn sub_head_changes( + mut publisher: Arc>>, + mut subscribed_head_change: Subscriber, + heaviest_tipset: &Option>, + current_index : usize + ) -> Result { + info!("sub head changes"); + let head = heaviest_tipset + .as_ref() + .ok_or_else(|| Error::Other("Could not get heaviest tipset".to_string()))?; + + publisher + .write() + .await + .publish(HeadChange::Current(head.clone()).into()) + .await; + task::spawn(async move { + while let Some(change) = subscribed_head_change.next().await { + publisher.write().await.publish(change.into()).await; + } + }); + Ok(current_index) + } } #[cfg(test)] diff --git a/blockchain/chain_sync/src/sync.rs b/blockchain/chain_sync/src/sync.rs index 27321cbfa10..00ec6b4f337 100644 --- a/blockchain/chain_sync/src/sync.rs +++ b/blockchain/chain_sync/src/sync.rs @@ -17,6 +17,8 @@ use async_std::task; use beacon::{Beacon, BeaconEntry}; use blocks::{Block, BlockHeader, FullTipset, Tipset, TipsetKeys, TxMeta}; use chain::persist_objects; +use chain::TipsetMetadata; +use chain::{HeadChange, TipIndex}; use cid::{multihash::Blake2b256, Cid}; use commcid::cid_to_replica_commitment_v1; use core::time::Duration; @@ -46,8 +48,6 @@ use std::collections::{BTreeMap, HashMap}; use std::convert::{TryFrom, TryInto}; use std::sync::Arc; use vm::TokenAmount; -use chain::{TipIndex,HeadChange}; -use chain::TipsetMetadata; /// Struct that handles the ChainSync logic. This handles incoming network events such as /// gossipsub messages, Hello protocol requests, as well as sending and receiving BlockSync @@ -70,13 +70,13 @@ pub struct ChainSyncer { next_sync_target: SyncBucket, // heaviest tipset - heaviest_tipset : Arc>>>, - + heaviest_tipset: Arc>>>, + // publisher chain store - publisher : Arc>>, + publisher: Arc>>, // refrence to tip_index - tip_index : Arc>, + tip_index: Arc>, /// Context to be able to send requests to p2p network network: SyncNetworkContext, @@ -112,9 +112,9 @@ where network_send: Sender, network_rx: Receiver, genesis: Tipset, - heaviest_tipset : Arc>>>, - publisher : Arc>>, - tip_index : Arc> + heaviest_tipset: Arc>>>, + publisher: Arc>>, + tip_index: Arc>, ) -> Result { let state_manager = Arc::new(StateManager::new(data_store.clone())); @@ -139,7 +139,7 @@ where peer_manager, sync_queue: SyncBucketSet::default(), next_sync_target: SyncBucket::default(), - tip_index + tip_index, }) } @@ -180,7 +180,10 @@ where } } NetworkEvent::PeerDialed { peer_id } => { - let heaviest = (self.heaviest_tipset.read().await).as_ref().unwrap().clone(); + let heaviest = (self.heaviest_tipset.read().await) + .as_ref() + .unwrap() + .clone(); self.network .hello_request( peer_id, @@ -252,7 +255,13 @@ where self.set_stage(SyncStage::Complete).await; // At this point the head is synced and the head can be set as the heaviest. - chain::put_tipset_lock(self.heaviest_tipset.clone(),&head,self.publisher.clone(),self.state_manager.get_block_store()).await?; + chain::put_tipset_lock( + self.heaviest_tipset.clone(), + &head, + self.publisher.clone(), + self.state_manager.get_block_store(), + ) + .await?; Ok(()) } diff --git a/blockchain/message_pool/src/msgpool.rs b/blockchain/message_pool/src/msgpool.rs index 77671a0ee7f..51b37f6c9a5 100644 --- a/blockchain/message_pool/src/msgpool.rs +++ b/blockchain/message_pool/src/msgpool.rs @@ -119,7 +119,6 @@ where { fn subscribe_head_changes(&mut self) -> Subscriber { task::block_on(self.cs.subscribe()) - } fn get_heaviest_tipset(&mut self) -> Option { diff --git a/forest/Cargo.toml b/forest/Cargo.toml index 28ab34ac5d4..d33f6eaa012 100644 --- a/forest/Cargo.toml +++ b/forest/Cargo.toml @@ -20,6 +20,7 @@ chain_sync = { path = "../blockchain/chain_sync" } state_manager = { path = "../blockchain/state_manager" } cid = { package = "forest_cid", path = "../ipld/cid", features = ["json"] } forest_car = { path = "../ipld/car" } +flo_stream = "0.4.0" blocks = { package = "forest_blocks", path = "../blockchain/blocks" } ipld_blockstore = { path = "../ipld/blockstore", features = ["rocksdb"] } chain = { path = "../blockchain/chain" } diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index e250189c0fb..04d5f5f379b 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -9,6 +9,7 @@ use beacon::{DrandBeacon, DEFAULT_DRAND_URL}; use chain::ChainStore; use chain_sync::ChainSyncer; use db::RocksDb; +use flo_stream::Publisher; use forest_libp2p::{get_keypair, Libp2pService}; use libp2p::identity::{ed25519, Keypair}; use log::{debug, info, trace}; @@ -91,7 +92,7 @@ pub(super) async fn start(config: Config) { genesis, heaviest_tipset.clone(), publisher, - chain_store.tip_index_ref() + chain_store.tip_index_ref(), ) .unwrap(); let bad_blocks = chain_syncer.bad_blocks_cloned(); @@ -122,7 +123,9 @@ pub(super) async fn start(config: Config) { network_send, network_name, heaviest_tipset, - subscriber + subscriber, + next_id: 0, + publisher: Arc::new(RwLock::new(Publisher::new(1000))), }, &rpc_listen, ) diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 096a4c380f7..f39c14574a1 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -16,7 +16,7 @@ cid = { package = "forest_cid", path = "../../ipld/cid", features = ["json"] } blocks = { package = "forest_blocks", path = "../../blockchain/blocks", features = ["json"] } clock = { path = "../clock" } message = { package = "forest_message", path = "../../vm/message", features = ["json"] } -jsonrpc-v2 = { version = "0.5.2", features = ["easy-errors", "macros"] } +jsonrpc-v2 = { version = "0.5.2", path="../../../jsonrpc-v2" ,features = ["easy-errors", "macros"] } message_pool = { path = "../../blockchain/message_pool" } crypto = { package = "forest_crypto", path = "../../crypto", features = ["json"] } num-traits = "0.2.11" diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index 62ff92878b0..bcd4e0d535a 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -54,22 +54,24 @@ where .get_block_store_ref() .get(&msg_cid)? .ok_or("can't find message with that cid")?; - Ok(UnsignedMessageJson(ret)) + Ok(UnsignedMessageJson(ret).into()) } -pub(crate) async fn chain_notify( - data: Data>, -) -> Result, JsonRpcError> +pub(crate) async fn chain_notify(data: Data>,Params(params): Params) -> Result<(), JsonRpcError> where DB: BlockStore + Send + Sync + 'static, KS: KeyStore + Send + Sync + 'static, { - let heaviest_tipset = data.heaviest_tipset.read().await; - let recieve_subhead_changes = chain::sub_head_changes(data.subscriber.clone(),&heaviest_tipset).await?; - let vec: Vec = - recieve_subhead_changes.map(|s| s.into()).collect().await; - Ok(vec) + let heaviest_tipset = data.heaviest_tipset.read().await; + chain::headchange_json::sub_head_changes( + data.publisher.clone(), + data.subscriber.clone(), + &heaviest_tipset, + params + ) + .await?; + Ok(()) } pub(crate) async fn chain_read_obj( @@ -86,7 +88,7 @@ where .get_block_store_ref() .get_bytes(&obj_cid)? .ok_or("can't find object with that cid")?; - Ok(ret) + Ok(ret.into()) } pub(crate) async fn chain_has_obj( @@ -102,7 +104,8 @@ where .state_manager .get_block_store_ref() .get_bytes(&obj_cid)? - .is_some()) + .is_some() + .into()) } pub(crate) async fn chain_block_messages( @@ -137,7 +140,7 @@ where secp_msg, cids, }; - Ok(ret) + Ok(ret.into()) } pub(crate) async fn chain_get_tipset_by_height( @@ -151,7 +154,7 @@ where let (height, tsk) = params; let ts = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &tsk)?; let tss = chain::tipset_by_height(data.state_manager.get_block_store_ref(), height, ts, true)?; - Ok(TipsetJson(tss)) + Ok(TipsetJson(tss).into()) } pub(crate) async fn chain_get_genesis( @@ -164,7 +167,7 @@ where let genesis = chain::genesis(data.state_manager.get_block_store_ref())? .ok_or("can't find genesis tipset")?; let gen_ts = Tipset::new(vec![genesis])?; - Ok(Some(TipsetJson(gen_ts))) + Ok(Some(TipsetJson(gen_ts)).into()) } pub(crate) async fn chain_head( @@ -176,7 +179,7 @@ where { let heaviest = chain::get_heaviest_tipset(data.state_manager.get_block_store_ref())? .ok_or("can't find heaviest tipset")?; - Ok(TipsetJson(heaviest)) + Ok(TipsetJson(heaviest).into()) } pub(crate) async fn chain_tipset_weight( @@ -206,7 +209,7 @@ where .get_block_store_ref() .get(&blk_cid)? .ok_or("can't find BlockHeader with that cid")?; - Ok(BlockHeaderJson(blk)) + Ok(BlockHeaderJson(blk).into()) } pub(crate) async fn chain_get_tipset( @@ -219,7 +222,7 @@ where { let (tsk,) = params; let ts = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &tsk)?; - Ok(TipsetJson(ts)) + Ok(TipsetJson(ts).into()) } pub(crate) async fn chain_get_randomness( @@ -237,5 +240,6 @@ where DomainSeparationTag::from_i64(pers).ok_or("invalid DomainSeparationTag")?, epoch, &entropy, - )?) + )? + .into()) } diff --git a/node/rpc/src/gas_api.rs b/node/rpc/src/gas_api.rs index 1155575502a..fcb2df38890 100644 --- a/node/rpc/src/gas_api.rs +++ b/node/rpc/src/gas_api.rs @@ -53,7 +53,7 @@ where } else { fee_in_future }; - Ok(out.to_string()) + Ok(out.to_string().into()) } /// Estimate the fee cap @@ -116,7 +116,7 @@ where } if prev == 0.into() { let ret: BigInt = price.price + 1; - return Ok(ret.to_string()); + return Ok(ret.to_string().into()); } premium = (&price.price + &prev) / 2 + 1 } @@ -140,7 +140,7 @@ where .ok_or("failed to converrt gas premium f64 to bigint")?; premium /= 1 << precision; - Ok(premium.to_string()) + Ok(premium.to_string().into()) } /// Estimate the gas limit @@ -181,8 +181,8 @@ where if rct.exit_code as u64 != 0 { return Ok(-1); } - Ok(rct.gas_used) + Ok(rct.gas_used.into()) } - None => Ok(-1), + None => return Ok(-1), } } diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index efae548b095..e95e0af35ab 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -11,23 +11,37 @@ mod wallet_api; use crate::state_api::*; use async_log::span; use async_std::net::{TcpListener, TcpStream}; +use async_std::sync::Arc; use async_std::sync::{RwLock, Sender}; use async_std::task; -use async_tungstenite::tungstenite::Message; +use async_tungstenite::{tungstenite::Message, WebSocketStream}; +use blocks::Tipset; use blockstore::BlockStore; +use chain::headchange_json::HeadChangeJson; +use chain::HeadChange; use chain_sync::{BadBlockCache, SyncState}; +use flo_stream::{MessagePublisher, Publisher, Subscriber}; use forest_libp2p::NetworkMessage; use futures::sink::SinkExt; -use futures::stream::StreamExt; -use jsonrpc_v2::{Data, MapRouter, RequestObject, Server}; +use futures::stream::{SplitSink, StreamExt}; +use jsonrpc_v2::{Data, MapRouter, RequestObject,RequestBuilder,ResponseObject, ResponseObjects, Server,V2,Error,Id}; use log::{error, info, warn}; use message_pool::{MessagePool, MpoolRpcProvider}; +use serde::Serialize; use state_manager::StateManager; -use std::sync::Arc; use wallet::KeyStore; -use blocks::Tipset; -use flo_stream::Subscriber; -use chain::HeadChange; +use std::sync::atomic::AtomicUsize; + +type WS_Sink = SplitSink, async_tungstenite::tungstenite::Message>; + +const CHAIN_NOTIFY_METHOD_NAME : &str= "Filecoin.ChainNotify"; +#[derive(Serialize)] +struct StreamingData { + json_rpc: String, + method: String, + params: (usize, Vec), +} + /// This is where you store persistant data, or at least access to stateful data. pub struct RpcState where @@ -36,16 +50,18 @@ where { pub state_manager: StateManager, pub keystore: Arc>, - pub heaviest_tipset : Arc>>>, - pub subscriber : Subscriber, + pub heaviest_tipset: Arc>>>, + pub subscriber: Subscriber, + pub publisher: Arc>>, pub mpool: Arc>>, pub bad_blocks: Arc, pub sync_state: Arc>, pub network_send: Sender, pub network_name: String, + pub next_id: u64, } -pub async fn start_rpc(state: RpcState, rpc_endpoint: &str) +pub async fn start_rpc(mut state: RpcState, rpc_endpoint: &str) where DB: BlockStore + Send + Sync + 'static, KS: KeyStore + Send + Sync + 'static, @@ -55,120 +71,197 @@ where use mpool_api::*; use sync_api::*; use wallet_api::*; - + let subscriber = state.publisher.write().await.subscribe(); let rpc = Server::new() .with_data(Data::new(state)) .with_method( "Filecoin.ChainGetMessage", chain_api::chain_get_message::, + false, ) - .with_method("Filecoin.ChainGetObj", chain_read_obj::) - .with_method("Filecoin.ChainHasObj", chain_has_obj::) + .with_method("Filecoin.ChainGetObj", chain_read_obj::, false) + .with_method("Filecoin.ChainHasObj", chain_has_obj::, false) .with_method( "Filecoin.ChainGetBlockMessages", chain_block_messages::, + false, ) .with_method( "Filecoin.ChainGetTipsetByHeight", chain_get_tipset_by_height::, + false, + ) + .with_method( + "Filecoin.ChainGetGenesis", + chain_get_genesis::, + false, + ) + .with_method( + "Filecoin.ChainTipsetWeight", + chain_tipset_weight::, + false, + ) + .with_method("Filecoin.ChainGetTipset", chain_get_tipset::, false) + .with_method( + "Filecoin.GetRandomness", + chain_get_randomness::, + false, ) - .with_method("Filecoin.ChainGetGenesis", chain_get_genesis::) - .with_method("Filecoin.ChainTipsetWeight", chain_tipset_weight::) - .with_method("Filecoin.ChainGetTipset", chain_get_tipset::) - .with_method("Filecoin.GetRandomness", chain_get_randomness::) .with_method( "Filecoin.ChainGetBlock", chain_api::chain_get_block::, + false, ) - .with_method("Filecoin.ChainNotify", chain_notify::) - .with_method("Filecoin.ChainHead", chain_head::) + .with_method(CHAIN_NOTIFY_METHOD_NAME, chain_notify::, true) + .with_method("Filecoin.ChainHead", chain_head::, false) // Message Pool API .with_method( "Filecoin.MpoolEstimateGasPrice", estimate_gas_premium::, + false, + ) + .with_method( + "Filecoin.MpoolGetNonce", + mpool_get_sequence::, + false, + ) + .with_method("Filecoin.MpoolPending", mpool_pending::, false) + .with_method("Filecoin.MpoolPush", mpool_push::, false) + .with_method( + "Filecoin.MpoolPushMessage", + mpool_push_message::, + false, ) - .with_method("Filecoin.MpoolGetNonce", mpool_get_sequence::) - .with_method("Filecoin.MpoolPending", mpool_pending::) - .with_method("Filecoin.MpoolPush", mpool_push::) - .with_method("Filecoin.MpoolPushMessage", mpool_push_message::) // Sync API - .with_method("Filecoin.SyncCheckBad", sync_check_bad::) - .with_method("Filecoin.SyncMarkBad", sync_mark_bad::) - .with_method("Filecoin.SyncState", sync_state::) - .with_method("Filecoin.SyncSubmitBlock", sync_submit_block::) + .with_method("Filecoin.SyncCheckBad", sync_check_bad::, false) + .with_method("Filecoin.SyncMarkBad", sync_mark_bad::, false) + .with_method("Filecoin.SyncState", sync_state::, false) + .with_method( + "Filecoin.SyncSubmitBlock", + sync_submit_block::, + false, + ) // Wallet API - .with_method("Filecoin.WalletBalance", wallet_balance::) + .with_method("Filecoin.WalletBalance", wallet_balance::, false) .with_method( "Filecoin.WalletDefaultAddress", wallet_default_address::, + false, + ) + .with_method("Filecoin.WalletExport", wallet_export::, false) + .with_method("Filecoin.WalletHas", wallet_has::, false) + .with_method("Filecoin.WalletImport", wallet_import::, false) + .with_method("Filecoin.WalletList", wallet_list::, false) + .with_method("Filecoin.WalletNew", wallet_new::, false) + .with_method( + "Filecoin.WalletSetDefault", + wallet_set_default::, + false, + ) + .with_method("Filecoin.WalletSign", wallet_sign::, false) + .with_method( + "Filecoin.WalletSignMessage", + wallet_sign_message::, + false, ) - .with_method("Filecoin.WalletExport", wallet_export::) - .with_method("Filecoin.WalletHas", wallet_has::) - .with_method("Filecoin.WalletImport", wallet_import::) - .with_method("Filecoin.WalletList", wallet_list::) - .with_method("Filecoin.WalletNew", wallet_new::) - .with_method("Filecoin.WalletSetDefault", wallet_set_default::) - .with_method("Filecoin.WalletSign", wallet_sign::) - .with_method("Filecoin.WalletSignMessage", wallet_sign_message::) - .with_method("Filecoin.WalletVerify", wallet_verify::) + .with_method("Filecoin.WalletVerify", wallet_verify::, false) // State API - .with_method("Filecoin.StateMinerSector", state_miner_sector::) - .with_method("Filecoin.StateCall", state_call::) + .with_method( + "Filecoin.StateMinerSector", + state_miner_sector::, + false, + ) + .with_method("Filecoin.StateCall", state_call::, false) .with_method( "Filecoin.StateMinerDeadlines", state_miner_deadlines::, + false, ) .with_method( "Filecoin.StateSectorPrecommitInfo", state_sector_precommit_info::, + false, + ) + .with_method( + "Filecoin.StateSectorInfo", + state_sector_info::, + false, ) - .with_method("Filecoin.StateSectorInfo", state_sector_info::) .with_method( "Filecoin.StateMinerProvingSet", state_miner_proving_set::, + false, ) .with_method( "Filecoin.StateMinerProvingDeadline", state_miner_proving_deadline::, + false, + ) + .with_method("Filecoin.StateMinerInfo", state_miner_info::, false) + .with_method( + "Filecoin.StateMinerFaults", + state_miner_faults::, + false, ) - .with_method("Filecoin.StateMinerInfo", state_miner_info::) - .with_method("Filecoin.StateMinerFaults", state_miner_faults::) .with_method( "Filecoin.StateAllMinerFaults", state_all_miner_faults::, + false, ) .with_method( "Filecoin.StateMinerRecoveries", state_miner_recoveries::, + false, + ) + .with_method("Filecoin.StateReplay", state_replay::, false) + .with_method("Filecoin.StateGetActor", state_get_actor::, false) + .with_method( + "Filecoin.StateAccountKey", + state_account_key::, + false, ) - .with_method("Filecoin.StateReplay", state_replay::) - .with_method("Filecoin.StateGetActor", state_get_actor::) - .with_method("Filecoin.StateAccountKey", state_account_key::) - .with_method("Filecoin.StateLookupId", state_lookup_id::) + .with_method("Filecoin.StateLookupId", state_lookup_id::, false) .with_method( "Filecoin.StateMartketBalance", state_market_balance::, + false, ) - .with_method("Filecoin.StateGetReceipt", state_get_receipt::) - .with_method("Filecoin.StateWaitMsg", state_wait_msg::) + .with_method( + "Filecoin.StateGetReceipt", + state_get_receipt::, + false, + ) + .with_method("Filecoin.StateWaitMsg", state_wait_msg::, false) // Gas API .with_method( "Filecoin.GasEstimateGasLimit", gas_estimate_gas_limit::, + false, ) .with_method( "Filecoin.GasEstimateGasPremium", gas_estimate_gas_premium::, + false, + ) + .with_method( + "Filecoin.GasEstimateFeeCap", + gas_estimate_fee_cap::, + false, ) - .with_method("Filecoin.GasEstimateFeeCap", gas_estimate_fee_cap::) .finish_unwrapped(); let try_socket = TcpListener::bind(rpc_endpoint).await; let listener = try_socket.expect("Failed to bind to addr"); let state = Arc::new(rpc); + info!("waiting for web socket connections"); while let Ok((stream, addr)) = listener.accept().await { - task::spawn(handle_connection_and_log(state.clone(), stream, addr)); + task::spawn(handle_connection_and_log( + state.clone(), + stream, + addr, + subscriber.clone(), + )); } info!("Stopped accepting websocket connections"); @@ -178,11 +271,14 @@ async fn handle_connection_and_log( state: Arc>, tcp_stream: TcpStream, addr: std::net::SocketAddr, + subscriber: Subscriber, ) { span!("handle_connection_and_log", { if let Ok(ws_stream) = async_tungstenite::accept_async(tcp_stream).await { info!("accepted websocket connection at {:}", addr); let (mut ws_sender, mut ws_receiver) = ws_stream.split(); + let ws_sender = Arc::new(RwLock::new(ws_sender)); + let mut chain_notify_count = 0; while let Some(message_result) = ws_receiver.next().await { let response_text = match message_result { Ok(message) => { @@ -193,29 +289,124 @@ async fn handle_connection_and_log( ); match serde_json::from_str(&request_text) as Result { Ok(call) => { - let response = state.handle(call).await; - let response_text = serde_json::to_string_pretty(&response) - .expect("all items returned should be properly serialized"); - Message::text(response_text) + /// hacky but due to the limitations of jsonrpc_v2 impl + /// if this expands, better to implement some sort of middleware + let call = if &*call.method==CHAIN_NOTIFY_METHOD_NAME + { + info!( + "old request {:?}", + call + ); + + chain_notify_count = chain_notify_count + 1; + RequestBuilder::default() + .with_id(call.id.unwrap_or_default().unwrap_or_default()) + .with_params(chain_notify_count) + .with_method(CHAIN_NOTIFY_METHOD_NAME) + .finish() + } + else + { + call + }; + let response = state.clone().handle(call).await; + streaming_payload_and_log( + ws_sender.clone(), + response, + state.clone(), + subscriber.clone(), + chain_notify_count + ) + .await; } Err(e) => { - let error_string = format!("error : {:?}", e); - Message::text(error_string) + let response = ResponseObjects::One(ResponseObject::Error{ + jsonrpc: V2, + error: Error::Provided{ + code : 1, + message : "Error serialization request" + }, + id: Id::Null + }); + streaming_payload_and_log( + ws_sender.clone(), + response, + state.clone(), + subscriber.clone(), + chain_notify_count + ) + .await; } } } Err(e) => { - let error_string = format!("error : {:?}", e); - Message::text(error_string) + let response = ResponseObjects::One(ResponseObject::Error{ + jsonrpc: V2, + error: Error::Provided{ + code : 2, + message : "Error reading request" + }, + id: Id::Null + }); + streaming_payload_and_log( + ws_sender.clone(), + response, + state.clone(), + subscriber.clone(), + chain_notify_count + ) + .await; } }; - ws_sender - .send(response_text) - .await - .unwrap_or_else(|e| error!("error obtaining result {:?}", e)); } } else { warn!("web socket connection failed at {:}", addr) } }) } + +async fn streaming_payload_and_log( + ws_sender: Arc>, + response_object: ResponseObjects, + state: Arc>, + mut subscriber: Subscriber, + streaming_count : usize +) { + let response_text = serde_json::to_string_pretty(&response_object).unwrap(); + ws_sender + .write() + .await + .send(Message::text(response_text)) + .await + .unwrap_or_else(|_| warn!("Could not send to response to socket")); + if let ResponseObjects::One(ResponseObject::Result { + jsonrpc : _, + result : _, + id : _, + streaming + }) = response_object + { + if streaming { + + task::spawn(async move { + let subcriber = subscriber.clone(); + let sender = ws_sender.clone(); + for resp in subscriber.next().await { + let data = StreamingData { + json_rpc: "2.0".to_string(), + method: "xrpc.ch.val".to_string(), + params: (streaming_count, vec![resp.into()]), + }; + let response_text = + serde_json::to_string_pretty(&data).expect("Bad Serialization of Type"); + sender + .write() + .await + .send(Message::text(response_text)) + .await + .unwrap_or_else(|_| warn!("Could not send to response to socket")); + } + }); + } + } +} diff --git a/node/rpc/src/mpool_api.rs b/node/rpc/src/mpool_api.rs index 68b870d63e7..b7cbcc42581 100644 --- a/node/rpc/src/mpool_api.rs +++ b/node/rpc/src/mpool_api.rs @@ -3,6 +3,7 @@ use crate::RpcState; + use address::Address; use blocks::TipsetKeys; use blockstore::BlockStore; @@ -32,7 +33,7 @@ where let price = data .mpool .estimate_gas_premium(nblocks, sender, gas_limit, tsk)?; - Ok(price.to_string()) + Ok(price.to_string().into()) } /// get the sequence of given address in mpool @@ -47,7 +48,7 @@ where let (addr_str,) = params; let address = Address::from_str(&addr_str)?; let sequence = data.mpool.get_sequence(&address).await?; - Ok(sequence) + Ok(sequence.into()) } /// Return Vec of pending messages in mpool @@ -71,13 +72,13 @@ where } if mpts.epoch() > ts.epoch() { - return Ok(pending); + return Ok(pending.into()); } loop { if mpts.epoch() == ts.epoch() { if mpts == ts { - return Ok(pending); + return Ok(pending.into()); } // mpts has different blocks than ts @@ -100,7 +101,7 @@ where } if mpts.epoch() >= ts.epoch() { - return Ok(pending); + return Ok(pending.into()); } ts = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), ts.parents())?; @@ -120,7 +121,7 @@ where let cid = data.mpool.as_ref().push(smsg).await?; - Ok(CidJson(cid)) + Ok(CidJson(cid).into()) } /// Sign given UnsignedMessage and add it to mpool, return SignedMessage @@ -150,5 +151,5 @@ where data.mpool.as_ref().push(smsg.clone()).await?; - Ok(SignedMessageJson(smsg)) + Ok(SignedMessageJson(smsg).into()) } diff --git a/node/rpc/src/state_api.rs b/node/rpc/src/state_api.rs index 891dda785e8..13fb872aa4f 100644 --- a/node/rpc/src/state_api.rs +++ b/node/rpc/src/state_api.rs @@ -1,6 +1,7 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT + use crate::RpcState; use actor::miner::{ compute_proving_period_deadline, ChainSectorInfo, DeadlineInfo, Deadlines, Fault, MinerInfo, @@ -71,6 +72,7 @@ pub(crate) async fn state_miner_sector< &mut filter, filter_out, ) + .map(|s| s.into()) .map_err(|e| e.into()) } @@ -88,6 +90,7 @@ pub(crate) async fn state_call< let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; state_manager .call(&mut message, Some(tipset)) + .map(|s| s.into()) .map_err(|e| e.into()) } @@ -102,7 +105,9 @@ pub(crate) async fn state_miner_deadlines< let state_manager = &data.state_manager; let (actor, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; - state_manager::utils::get_miner_deadlines(&state_manager, &tipset, &actor).map_err(|e| e.into()) + state_manager::utils::get_miner_deadlines(&state_manager, &tipset, &actor) + .map(|s| s.into()) + .map_err(|e| e.into()) } /// returns the PreCommit info for the specified miner's sector @@ -117,6 +122,7 @@ pub(crate) async fn state_sector_precommit_info< let (address, sector_number, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; state_manager::utils::precommit_info(&state_manager, &address, §or_number, &tipset) + .map(|s| s.into()) .map_err(|e| e.into()) } @@ -134,6 +140,7 @@ pub(crate) async fn state_miner_proving_set< let miner_actor_state: State = state_manager.load_actor_state(&address, &tipset.parent_state())?; state_manager::utils::get_proving_set_raw(&state_manager, &miner_actor_state) + .map(|s| s.into()) .map_err(|e| e.into()) } @@ -148,7 +155,9 @@ pub async fn state_miner_info< let state_manager = &data.state_manager; let (actor, key) = params; let tipset = chain::tipset_from_keys(state_manager.get_block_store_ref(), &key)?; - state_manager::utils::get_miner_info(&state_manager, &tipset, &actor).map_err(|e| e.into()) + state_manager::utils::get_miner_info(&state_manager, &tipset, &actor) + .map(|s| s.into()) + .map_err(|e| e.into()) } /// returns the on-chain info for the specified miner's sector @@ -163,6 +172,7 @@ pub async fn state_sector_info< let (address, sector_number, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; state_manager::utils::miner_sector_info(&state_manager, &address, §or_number, &tipset) + .map(|s| s.into()) .map_err(|e| e.into()) } @@ -180,10 +190,10 @@ pub(crate) async fn state_miner_proving_deadline< let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; let miner_actor_state: State = state_manager.load_actor_state(&actor, &tipset.parent_state())?; - Ok(compute_proving_period_deadline( - miner_actor_state.proving_period_start, - tipset.epoch(), - )) + Ok( + compute_proving_period_deadline(miner_actor_state.proving_period_start, tipset.epoch()) + .into(), + ) } /// returns a single non-expired Faults that occur within lookback epochs of the given tipset @@ -198,7 +208,7 @@ pub(crate) async fn state_miner_faults< let (actor, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; state_manager::utils::get_miner_faults(&state_manager, &tipset, &actor) - .map(|s| s.into()) + .map(|s|s.into()) .map_err(|e| e.into()) } @@ -234,7 +244,7 @@ pub(crate) async fn state_all_miner_faults< }) }) .collect::, _>>()?; - Ok(all_faults) + Ok(all_faults.into()) } /// returns a bitfield indicating the recovering sectors of the given miner pub(crate) async fn state_miner_recoveries< @@ -248,7 +258,7 @@ pub(crate) async fn state_miner_recoveries< let (actor, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; state_manager::utils::get_miner_recoveries(&state_manager, &tipset, &actor) - .map(|s| s.into()) + .map(|s|s.into()) .map_err(|e| e.into()) } @@ -272,7 +282,8 @@ pub(crate) async fn state_replay< error: ret .map(|act| act.act_error.map(|e| e.to_string())) .unwrap_or_default(), - }) + } + .into()) } /// returns the indicated actor's nonce and balance. @@ -287,7 +298,10 @@ pub(crate) async fn state_get_actor< let (actor, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; let state = state_for_ts(&state_manager, Some(tipset))?; - state.get_actor(&actor).map_err(|e| e.into()) + state + .get_actor(&actor) + .map(|s| s.into()) + .map_err(|e| e.into()) } /// returns the public key address of the given ID address @@ -304,7 +318,7 @@ pub(crate) async fn state_account_key< let state = state_for_ts(&state_manager, Some(tipset))?; let address = interpreter::resolve_to_key_addr(&state, state_manager.get_block_store_ref(), &actor)?; - Ok(address.into()) + Ok(Some(address)) } /// retrieves the ID address of the given address pub(crate) async fn state_lookup_id< @@ -318,7 +332,10 @@ pub(crate) async fn state_lookup_id< let (address, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; let state = state_for_ts(&state_manager, Some(tipset))?; - state.lookup_id(&address).map_err(|e| e.into()) + state + .lookup_id(&address) + .map(|s| s.into()) + .map_err(|e| e.into()) } /// looks up the Escrow and Locked balances of the given address in the Storage Market @@ -333,6 +350,7 @@ pub(crate) async fn state_market_balance< let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; data.state_manager .market_balance(&address, &tipset) + .map(|s| s.into()) .map_err(|e| e.into()) } diff --git a/node/rpc/src/sync_api.rs b/node/rpc/src/sync_api.rs index b89d7ad76ad..81208d22838 100644 --- a/node/rpc/src/sync_api.rs +++ b/node/rpc/src/sync_api.rs @@ -28,7 +28,7 @@ where KS: KeyStore + Send + Sync + 'static, { let (CidJson(cid),) = params; - Ok(data.bad_blocks.peek(&cid).await.unwrap_or_default()) + Ok(data.bad_blocks.peek(&cid).await.unwrap_or_default().into()) } /// Marks a block as bad, meaning it will never be synced. @@ -44,7 +44,7 @@ where data.bad_blocks .put(cid, "Marked bad manually through RPC API".to_string()) .await; - Ok(()) + Ok(().into()) } // TODO SyncIncomingBlocks (requires websockets) @@ -60,7 +60,8 @@ where let state = data.sync_state.read().await.clone(); Ok(RPCSyncState { active_syncs: vec![state], - }) + } + .into()) } /// Submits block to be sent through gossipsub. @@ -80,7 +81,7 @@ where message: blk.marshal_cbor().map_err(|e| e.to_string())?, }) .await; - Ok(()) + Ok(().into()) } #[cfg(test)] diff --git a/node/rpc/src/wallet_api.rs b/node/rpc/src/wallet_api.rs index 611fc1cbc5e..fc51461cfa6 100644 --- a/node/rpc/src/wallet_api.rs +++ b/node/rpc/src/wallet_api.rs @@ -40,11 +40,11 @@ where Ok(act) => { let actor = act.ok_or("Could not find actor")?; let actor_balance = actor.balance; - Ok(actor_balance.to_string()) + Ok(actor_balance.to_string().into()) } Err(e) => { if e == "Address not found" { - return Ok(BigUint::default().to_string()); + return Ok(BigUint::default().to_string().into()); } Err(e.into()) } @@ -62,7 +62,7 @@ where let keystore = data.keystore.read().await; let addr = wallet::get_default(&*keystore)?; - Ok(addr.to_string()) + Ok(addr.to_string().into()) } /// Export KeyInfo from the Wallet given its address @@ -80,7 +80,7 @@ where let keystore = data.keystore.read().await; let key_info = wallet::export_key_info(&addr, &*keystore)?; - Ok(KeyInfoJson(key_info)) + Ok(KeyInfoJson(key_info).into()) } /// Return whether or not a Key is in the Wallet @@ -98,7 +98,7 @@ where let keystore = data.keystore.read().await; let key = wallet::find_key(&addr, &*keystore).is_ok(); - Ok(key) + Ok(key.into()) } /// Import Keyinfo to the Wallet, return the Address that corresponds to it @@ -120,7 +120,7 @@ where keystore.put(addr, key.key_info)?; - Ok(key.address.to_string()) + Ok(key.address.to_string().into()) } /// List all Addresses in the Wallet @@ -158,7 +158,7 @@ where keystore.put("default".to_string(), key.key_info)? } - Ok(key.address.to_string()) + Ok(key.address.to_string().into()) } /// Set the default Address for the Wallet @@ -177,7 +177,7 @@ where let key_info = keystore.get(&addr_string)?; keystore.remove("default".to_string())?; // This line should unregister current default key then continue keystore.put("default".to_string(), key_info)?; - Ok(()) + Ok(().into()) } /// Sign a vector of bytes @@ -204,7 +204,7 @@ where msg.as_slice(), )?; - Ok(SignatureJson(sig)) + Ok(SignatureJson(sig).into()) } /// Sign an UnsignedMessage, return SignedMessage @@ -232,7 +232,7 @@ where let smsg = SignedMessage::new_from_parts(msg, sig)?; - Ok(SignedMessageJson(smsg)) + Ok(SignedMessageJson(smsg).into()) } /// Verify a Signature, true if verified, false otherwise @@ -249,5 +249,5 @@ where let msg = Vec::from(msg_str); let ret = sig.verify(&msg, &address).is_ok(); - Ok(ret) + Ok(ret.into()) } From 377a20567f812c91a38d2805c000dc1d8b17fb16 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Wed, 16 Sep 2020 02:30:27 -0400 Subject: [PATCH 14/43] clippy fixes --- blockchain/chain/src/store/chain_store.rs | 6 +- forest/src/daemon.rs | 1 - node/rpc/src/chain_api.rs | 30 +++++----- node/rpc/src/gas_api.rs | 10 ++-- node/rpc/src/lib.rs | 69 +++++++++++------------ node/rpc/src/mpool_api.rs | 15 +++-- node/rpc/src/state_api.rs | 43 +++++--------- node/rpc/src/sync_api.rs | 6 +- node/rpc/src/wallet_api.rs | 18 +++--- 9 files changed, 87 insertions(+), 111 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 192751c9945..c475c1b896e 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -29,7 +29,6 @@ use std::collections::HashMap; use std::io::Write; use std::sync::Arc; - const GENESIS_KEY: &str = "gen_block"; const HEAD_KEY: &str = "head"; // constants for Weight calculation @@ -160,8 +159,7 @@ where self.heaviest.read().await.clone() } - pub fn heaviest_tipset_ref(&self) -> Arc>>> - { + pub fn heaviest_tipset_ref(&self) -> Arc>>> { self.heaviest.clone() } @@ -782,7 +780,7 @@ pub mod headchange_json { publisher: Arc>>, mut subscribed_head_change: Subscriber, heaviest_tipset: &Option>, - current_index : usize + current_index: usize, ) -> Result { info!("sub head changes"); let head = heaviest_tipset diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index 4207e9bdfb2..af155e8c7db 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -113,7 +113,6 @@ pub(super) async fn start(config: Config) { p2p_service.run().await; }); - let rpc_task = if config.enable_rpc { let keystore_rpc = Arc::clone(&keystore); let rpc_listen = format!("127.0.0.1:{}", &config.rpc_port); diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index 3b6e7e84130..3e97bcd1d3b 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -53,21 +53,23 @@ where .get_block_store_ref() .get(&msg_cid)? .ok_or("can't find message with that cid")?; - Ok(UnsignedMessageJson(ret).into()) + Ok(UnsignedMessageJson(ret)) } -pub(crate) async fn chain_notify(data: Data>,Params(params): Params) -> Result +pub(crate) async fn chain_notify( + data: Data>, + Params(params): Params, +) -> Result where DB: BlockStore + Send + Sync + 'static, KS: KeyStore + Send + Sync + 'static, { - let heaviest_tipset = data.heaviest_tipset.read().await; let index = chain::headchange_json::sub_head_changes( data.publisher.clone(), data.subscriber.clone(), &heaviest_tipset, - params + params, ) .await?; Ok(index) @@ -87,7 +89,7 @@ where .get_block_store_ref() .get_bytes(&obj_cid)? .ok_or("can't find object with that cid")?; - Ok(ret.into()) + Ok(ret) } pub(crate) async fn chain_has_obj( @@ -103,8 +105,7 @@ where .state_manager .get_block_store_ref() .get_bytes(&obj_cid)? - .is_some() - .into()) + .is_some()) } pub(crate) async fn chain_block_messages( @@ -139,7 +140,7 @@ where secp_msg, cids, }; - Ok(ret.into()) + Ok(ret) } pub(crate) async fn chain_get_tipset_by_height( @@ -153,7 +154,7 @@ where let (height, tsk) = params; let ts = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &tsk)?; let tss = chain::tipset_by_height(data.state_manager.get_block_store_ref(), height, ts, true)?; - Ok(TipsetJson(tss).into()) + Ok(TipsetJson(tss)) } pub(crate) async fn chain_get_genesis( @@ -166,7 +167,7 @@ where let genesis = chain::genesis(data.state_manager.get_block_store_ref())? .ok_or("can't find genesis tipset")?; let gen_ts = Tipset::new(vec![genesis])?; - Ok(Some(TipsetJson(gen_ts)).into()) + Ok(Some(TipsetJson(gen_ts))) } pub(crate) async fn chain_head( @@ -178,7 +179,7 @@ where { let heaviest = chain::get_heaviest_tipset(data.state_manager.get_block_store_ref())? .ok_or("can't find heaviest tipset")?; - Ok(TipsetJson(heaviest).into()) + Ok(TipsetJson(heaviest)) } pub(crate) async fn chain_tipset_weight( @@ -208,7 +209,7 @@ where .get_block_store_ref() .get(&blk_cid)? .ok_or("can't find BlockHeader with that cid")?; - Ok(BlockHeaderJson(blk).into()) + Ok(BlockHeaderJson(blk)) } pub(crate) async fn chain_get_tipset( @@ -221,7 +222,7 @@ where { let (tsk,) = params; let ts = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &tsk)?; - Ok(TipsetJson(ts).into()) + Ok(TipsetJson(ts)) } pub(crate) async fn chain_get_randomness( @@ -239,6 +240,5 @@ where DomainSeparationTag::from_i64(pers).ok_or("invalid DomainSeparationTag")?, epoch, &entropy, - )? - .into()) + )?) } diff --git a/node/rpc/src/gas_api.rs b/node/rpc/src/gas_api.rs index fcb2df38890..1155575502a 100644 --- a/node/rpc/src/gas_api.rs +++ b/node/rpc/src/gas_api.rs @@ -53,7 +53,7 @@ where } else { fee_in_future }; - Ok(out.to_string().into()) + Ok(out.to_string()) } /// Estimate the fee cap @@ -116,7 +116,7 @@ where } if prev == 0.into() { let ret: BigInt = price.price + 1; - return Ok(ret.to_string().into()); + return Ok(ret.to_string()); } premium = (&price.price + &prev) / 2 + 1 } @@ -140,7 +140,7 @@ where .ok_or("failed to converrt gas premium f64 to bigint")?; premium /= 1 << precision; - Ok(premium.to_string().into()) + Ok(premium.to_string()) } /// Estimate the gas limit @@ -181,8 +181,8 @@ where if rct.exit_code as u64 != 0 { return Ok(-1); } - Ok(rct.gas_used.into()) + Ok(rct.gas_used) } - None => return Ok(-1), + None => Ok(-1), } } diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 7a204170ee5..fdf7923b3b3 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -24,17 +24,19 @@ use flo_stream::{MessagePublisher, Publisher, Subscriber}; use forest_libp2p::NetworkMessage; use futures::sink::SinkExt; use futures::stream::{SplitSink, StreamExt}; -use jsonrpc_v2::{Data, MapRouter, RequestObject,RequestBuilder,ResponseObject, ResponseObjects, Server,V2,Error,Id}; +use jsonrpc_v2::{ + Data, Error, Id, MapRouter, RequestBuilder, RequestObject, ResponseObject, ResponseObjects, + Server, V2, +}; use log::{info, warn}; use message_pool::{MessagePool, MpoolRpcProvider}; use serde::Serialize; use state_manager::StateManager; use wallet::KeyStore; - type WsSink = SplitSink, async_tungstenite::tungstenite::Message>; -const CHAIN_NOTIFY_METHOD_NAME : &str= "Filecoin.ChainNotify"; +const CHAIN_NOTIFY_METHOD_NAME: &str = "Filecoin.ChainNotify"; #[derive(Serialize)] struct StreamingData { json_rpc: String, @@ -50,7 +52,7 @@ where { pub state_manager: Arc>, pub keystore: Arc>, - pub heaviest_tipset:Arc>>>, + pub heaviest_tipset: Arc>>>, pub subscriber: Subscriber, pub publisher: Arc>>, pub mpool: Arc>>, @@ -291,18 +293,14 @@ async fn handle_connection_and_log( Ok(call) => { // hacky but due to the limitations of jsonrpc_v2 impl // if this expands, better to implement some sort of middleware - let call = if &*call.method==CHAIN_NOTIFY_METHOD_NAME - { - - chain_notify_count = chain_notify_count + 1; + let call = if &*call.method == CHAIN_NOTIFY_METHOD_NAME { + chain_notify_count += 1; RequestBuilder::default() - .with_id(call.id.unwrap_or_default().unwrap_or_default()) - .with_params(chain_notify_count) - .with_method(CHAIN_NOTIFY_METHOD_NAME) - .finish() - } - else - { + .with_id(call.id.unwrap_or_default().unwrap_or_default()) + .with_params(chain_notify_count) + .with_method(CHAIN_NOTIFY_METHOD_NAME) + .finish() + } else { call }; let response = state.clone().handle(call).await; @@ -310,43 +308,43 @@ async fn handle_connection_and_log( ws_sender.clone(), response, subscriber.clone(), - chain_notify_count + chain_notify_count, ) .await; } Err(_) => { - let response = ResponseObjects::One(ResponseObject::Error{ + let response = ResponseObjects::One(ResponseObject::Error { jsonrpc: V2, - error: Error::Provided{ - code : 1, - message : "Error serialization request" + error: Error::Provided { + code: 1, + message: "Error serialization request", }, - id: Id::Null + id: Id::Null, }); streaming_payload_and_log( ws_sender.clone(), response, subscriber.clone(), - chain_notify_count + chain_notify_count, ) .await; } } } Err(_) => { - let response = ResponseObjects::One(ResponseObject::Error{ + let response = ResponseObjects::One(ResponseObject::Error { jsonrpc: V2, - error: Error::Provided{ - code : 2, - message : "Error reading request" + error: Error::Provided { + code: 2, + message: "Error reading request", }, - id: Id::Null + id: Id::Null, }); streaming_payload_and_log( ws_sender.clone(), response, subscriber.clone(), - chain_notify_count + chain_notify_count, ) .await; } @@ -362,7 +360,7 @@ async fn streaming_payload_and_log( ws_sender: Arc>, response_object: ResponseObjects, mut subscriber: Subscriber, - streaming_count : usize + streaming_count: usize, ) { let response_text = serde_json::to_string_pretty(&response_object).unwrap(); ws_sender @@ -372,21 +370,20 @@ async fn streaming_payload_and_log( .await .unwrap_or_else(|_| warn!("Could not send to response to socket")); if let ResponseObjects::One(ResponseObject::Result { - jsonrpc : _, - result : _, - id : _, - streaming + jsonrpc: _, + result: _, + id: _, + streaming, }) = response_object { if streaming { - task::spawn(async move { let sender = ws_sender.clone(); - for resp in subscriber.next().await { + while let Some(resp) = subscriber.next().await { let data = StreamingData { json_rpc: "2.0".to_string(), method: "xrpc.ch.val".to_string(), - params: (streaming_count, vec![resp.into()]), + params: (streaming_count, vec![resp]), }; let response_text = serde_json::to_string_pretty(&data).expect("Bad Serialization of Type"); diff --git a/node/rpc/src/mpool_api.rs b/node/rpc/src/mpool_api.rs index b7cbcc42581..68b870d63e7 100644 --- a/node/rpc/src/mpool_api.rs +++ b/node/rpc/src/mpool_api.rs @@ -3,7 +3,6 @@ use crate::RpcState; - use address::Address; use blocks::TipsetKeys; use blockstore::BlockStore; @@ -33,7 +32,7 @@ where let price = data .mpool .estimate_gas_premium(nblocks, sender, gas_limit, tsk)?; - Ok(price.to_string().into()) + Ok(price.to_string()) } /// get the sequence of given address in mpool @@ -48,7 +47,7 @@ where let (addr_str,) = params; let address = Address::from_str(&addr_str)?; let sequence = data.mpool.get_sequence(&address).await?; - Ok(sequence.into()) + Ok(sequence) } /// Return Vec of pending messages in mpool @@ -72,13 +71,13 @@ where } if mpts.epoch() > ts.epoch() { - return Ok(pending.into()); + return Ok(pending); } loop { if mpts.epoch() == ts.epoch() { if mpts == ts { - return Ok(pending.into()); + return Ok(pending); } // mpts has different blocks than ts @@ -101,7 +100,7 @@ where } if mpts.epoch() >= ts.epoch() { - return Ok(pending.into()); + return Ok(pending); } ts = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), ts.parents())?; @@ -121,7 +120,7 @@ where let cid = data.mpool.as_ref().push(smsg).await?; - Ok(CidJson(cid).into()) + Ok(CidJson(cid)) } /// Sign given UnsignedMessage and add it to mpool, return SignedMessage @@ -151,5 +150,5 @@ where data.mpool.as_ref().push(smsg.clone()).await?; - Ok(SignedMessageJson(smsg).into()) + Ok(SignedMessageJson(smsg)) } diff --git a/node/rpc/src/state_api.rs b/node/rpc/src/state_api.rs index 13fb872aa4f..99d41c29a8a 100644 --- a/node/rpc/src/state_api.rs +++ b/node/rpc/src/state_api.rs @@ -1,7 +1,6 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT - use crate::RpcState; use actor::miner::{ compute_proving_period_deadline, ChainSectorInfo, DeadlineInfo, Deadlines, Fault, MinerInfo, @@ -72,7 +71,6 @@ pub(crate) async fn state_miner_sector< &mut filter, filter_out, ) - .map(|s| s.into()) .map_err(|e| e.into()) } @@ -83,7 +81,7 @@ pub(crate) async fn state_call< >( data: Data>, Params(params): Params<(UnsignedMessageJson, TipsetKeys)>, -) -> Result { +) -> Result { let state_manager = &data.state_manager; let (unsigned_msg_json, key) = params; let mut message: UnsignedMessage = unsigned_msg_json.into(); @@ -105,9 +103,7 @@ pub(crate) async fn state_miner_deadlines< let state_manager = &data.state_manager; let (actor, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; - state_manager::utils::get_miner_deadlines(&state_manager, &tipset, &actor) - .map(|s| s.into()) - .map_err(|e| e.into()) + state_manager::utils::get_miner_deadlines(&state_manager, &tipset, &actor).map_err(|e| e.into()) } /// returns the PreCommit info for the specified miner's sector @@ -122,7 +118,6 @@ pub(crate) async fn state_sector_precommit_info< let (address, sector_number, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; state_manager::utils::precommit_info(&state_manager, &address, §or_number, &tipset) - .map(|s| s.into()) .map_err(|e| e.into()) } @@ -140,7 +135,6 @@ pub(crate) async fn state_miner_proving_set< let miner_actor_state: State = state_manager.load_actor_state(&address, &tipset.parent_state())?; state_manager::utils::get_proving_set_raw(&state_manager, &miner_actor_state) - .map(|s| s.into()) .map_err(|e| e.into()) } @@ -155,9 +149,7 @@ pub async fn state_miner_info< let state_manager = &data.state_manager; let (actor, key) = params; let tipset = chain::tipset_from_keys(state_manager.get_block_store_ref(), &key)?; - state_manager::utils::get_miner_info(&state_manager, &tipset, &actor) - .map(|s| s.into()) - .map_err(|e| e.into()) + state_manager::utils::get_miner_info(&state_manager, &tipset, &actor).map_err(|e| e.into()) } /// returns the on-chain info for the specified miner's sector @@ -172,7 +164,6 @@ pub async fn state_sector_info< let (address, sector_number, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; state_manager::utils::miner_sector_info(&state_manager, &address, §or_number, &tipset) - .map(|s| s.into()) .map_err(|e| e.into()) } @@ -190,10 +181,10 @@ pub(crate) async fn state_miner_proving_deadline< let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; let miner_actor_state: State = state_manager.load_actor_state(&actor, &tipset.parent_state())?; - Ok( - compute_proving_period_deadline(miner_actor_state.proving_period_start, tipset.epoch()) - .into(), - ) + Ok(compute_proving_period_deadline( + miner_actor_state.proving_period_start, + tipset.epoch(), + )) } /// returns a single non-expired Faults that occur within lookback epochs of the given tipset @@ -208,7 +199,7 @@ pub(crate) async fn state_miner_faults< let (actor, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; state_manager::utils::get_miner_faults(&state_manager, &tipset, &actor) - .map(|s|s.into()) + .map(|s| s.into()) .map_err(|e| e.into()) } @@ -244,7 +235,7 @@ pub(crate) async fn state_all_miner_faults< }) }) .collect::, _>>()?; - Ok(all_faults.into()) + Ok(all_faults) } /// returns a bitfield indicating the recovering sectors of the given miner pub(crate) async fn state_miner_recoveries< @@ -258,7 +249,7 @@ pub(crate) async fn state_miner_recoveries< let (actor, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; state_manager::utils::get_miner_recoveries(&state_manager, &tipset, &actor) - .map(|s|s.into()) + .map(|s| s.into()) .map_err(|e| e.into()) } @@ -282,8 +273,7 @@ pub(crate) async fn state_replay< error: ret .map(|act| act.act_error.map(|e| e.to_string())) .unwrap_or_default(), - } - .into()) + }) } /// returns the indicated actor's nonce and balance. @@ -298,10 +288,7 @@ pub(crate) async fn state_get_actor< let (actor, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; let state = state_for_ts(&state_manager, Some(tipset))?; - state - .get_actor(&actor) - .map(|s| s.into()) - .map_err(|e| e.into()) + state.get_actor(&actor).map_err(|e| e.into()) } /// returns the public key address of the given ID address @@ -332,10 +319,7 @@ pub(crate) async fn state_lookup_id< let (address, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; let state = state_for_ts(&state_manager, Some(tipset))?; - state - .lookup_id(&address) - .map(|s| s.into()) - .map_err(|e| e.into()) + state.lookup_id(&address).map_err(|e| e.into()) } /// looks up the Escrow and Locked balances of the given address in the Storage Market @@ -350,7 +334,6 @@ pub(crate) async fn state_market_balance< let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; data.state_manager .market_balance(&address, &tipset) - .map(|s| s.into()) .map_err(|e| e.into()) } diff --git a/node/rpc/src/sync_api.rs b/node/rpc/src/sync_api.rs index 38b6f47939d..2738698b9e5 100644 --- a/node/rpc/src/sync_api.rs +++ b/node/rpc/src/sync_api.rs @@ -30,7 +30,7 @@ where KS: KeyStore + Send + Sync + 'static, { let (CidJson(cid),) = params; - Ok(data.bad_blocks.peek(&cid).await.unwrap_or_default().into()) + Ok(data.bad_blocks.peek(&cid).await.unwrap_or_default()) } /// Marks a block as bad, meaning it will never be synced. @@ -46,7 +46,7 @@ where data.bad_blocks .put(cid, "Marked bad manually through RPC API".to_string()) .await; - Ok(().into()) + Ok(()) } // TODO SyncIncomingBlocks (requires websockets) @@ -88,7 +88,7 @@ where message: blk.marshal_cbor().map_err(|e| e.to_string())?, }) .await; - Ok(().into()) + Ok(()) } #[cfg(test)] diff --git a/node/rpc/src/wallet_api.rs b/node/rpc/src/wallet_api.rs index fbba737e23d..6daa9648c93 100644 --- a/node/rpc/src/wallet_api.rs +++ b/node/rpc/src/wallet_api.rs @@ -60,7 +60,7 @@ where let keystore = data.keystore.read().await; let addr = wallet::get_default(&*keystore)?; - Ok(addr.to_string().into()) + Ok(addr.to_string()) } /// Export KeyInfo from the Wallet given its address @@ -78,7 +78,7 @@ where let keystore = data.keystore.read().await; let key_info = wallet::export_key_info(&addr, &*keystore)?; - Ok(KeyInfoJson(key_info).into()) + Ok(KeyInfoJson(key_info)) } /// Return whether or not a Key is in the Wallet @@ -96,7 +96,7 @@ where let keystore = data.keystore.read().await; let key = wallet::find_key(&addr, &*keystore).is_ok(); - Ok(key.into()) + Ok(key) } /// Import Keyinfo to the Wallet, return the Address that corresponds to it @@ -118,7 +118,7 @@ where keystore.put(addr, key.key_info)?; - Ok(key.address.to_string().into()) + Ok(key.address.to_string()) } /// List all Addresses in the Wallet @@ -156,7 +156,7 @@ where keystore.put("default".to_string(), key.key_info)? } - Ok(key.address.to_string().into()) + Ok(key.address.to_string()) } /// Set the default Address for the Wallet @@ -175,7 +175,7 @@ where let key_info = keystore.get(&addr_string)?; keystore.remove("default".to_string())?; // This line should unregister current default key then continue keystore.put("default".to_string(), key_info)?; - Ok(().into()) + Ok(()) } /// Sign a vector of bytes @@ -202,7 +202,7 @@ where msg.as_slice(), )?; - Ok(SignatureJson(sig).into()) + Ok(SignatureJson(sig)) } /// Sign an UnsignedMessage, return SignedMessage @@ -230,7 +230,7 @@ where let smsg = SignedMessage::new_from_parts(msg, sig)?; - Ok(SignedMessageJson(smsg).into()) + Ok(SignedMessageJson(smsg)) } /// Verify a Signature, true if verified, false otherwise @@ -247,5 +247,5 @@ where let msg = Vec::from(msg_str); let ret = sig.verify(&msg, &address).is_ok(); - Ok(ret.into()) + Ok(ret) } From 90df9696df3d971d83101caf9bc79d1e3e419dd6 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Wed, 16 Sep 2020 04:00:49 -0400 Subject: [PATCH 15/43] filtered with ids --- blockchain/blocks/src/tipset.rs | 10 +++--- blockchain/chain/src/store/chain_store.rs | 16 ++++++--- forest/src/daemon.rs | 1 - node/rpc/Cargo.toml | 2 +- node/rpc/src/lib.rs | 41 ++++++++++++----------- node/rpc/src/sync_api.rs | 14 +++++--- 6 files changed, 48 insertions(+), 36 deletions(-) diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index d844b2277c6..5fb9e012a10 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -276,7 +276,7 @@ pub mod tipset_json { pub struct TipsetJson(#[serde(with = "self")] pub Tipset); /// Wrapper for serializing a SignedMessage reference to JSON. - #[derive(Serialize)] + #[derive(Serialize, Clone, Debug)] #[serde(transparent)] pub struct TipsetJsonRef<'a>(#[serde(with = "self")] pub &'a Tipset); @@ -305,10 +305,10 @@ pub mod tipset_json { #[derive(Serialize)] #[serde(rename_all = "PascalCase")] struct TipsetSer<'a> { - #[serde(with = "super::super::header::json::vec")] - blocks: &'a [BlockHeader], #[serde(with = "super::tipset_keys_json")] cids: &'a TipsetKeys, + #[serde(with = "super::super::header::json::vec")] + blocks: &'a [BlockHeader], height: ChainEpoch, } TipsetSer { @@ -326,10 +326,10 @@ pub mod tipset_json { #[derive(Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] struct TipsetDe { - #[serde(with = "super::super::header::json::vec")] - blocks: Vec, #[serde(with = "super::tipset_keys_json")] cids: TipsetKeys, + #[serde(with = "super::super::header::json::vec")] + blocks: Vec, height: ChainEpoch, } let TipsetDe { blocks, .. } = Deserialize::deserialize(deserializer)?; diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index c475c1b896e..4860d9d44bf 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -758,14 +758,16 @@ pub mod headchange_json { use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] - #[serde(untagged)] - #[serde(rename_all = "PascalCase")] + #[serde(rename_all = "lowercase")] + #[serde(tag = "type", content = "val")] pub enum HeadChangeJson { Current(TipsetJson), Apply(TipsetJson), Revert(TipsetJson), } + #[derive(Debug, Clone)] + pub struct IndexToHeadChangeJson(pub usize, pub HeadChangeJson); impl From for HeadChangeJson { fn from(wrapper: HeadChange) -> Self { match wrapper { @@ -777,7 +779,7 @@ pub mod headchange_json { } pub async fn sub_head_changes( - publisher: Arc>>, + publisher: Arc>>, mut subscribed_head_change: Subscriber, heaviest_tipset: &Option>, current_index: usize, @@ -790,11 +792,15 @@ pub mod headchange_json { publisher .write() .await - .publish(HeadChange::Current(head.clone()).into()) + .publish(IndexToHeadChangeJson( + current_index, + HeadChange::Current(head.clone()).into(), + )) .await; task::spawn(async move { while let Some(change) = subscribed_head_change.next().await { - publisher.write().await.publish(change.into()).await; + let index_to_head_change = IndexToHeadChangeJson(current_index, change.into()); + publisher.write().await.publish(index_to_head_change).await; } }); Ok(current_index) diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index af155e8c7db..b6ca36909f4 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -129,7 +129,6 @@ pub(super) async fn start(config: Config) { network_name, heaviest_tipset, subscriber, - next_id: 0, publisher: Arc::new(RwLock::new(Publisher::new(1000))), }, &rpc_listen, diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index f39c14574a1..823a3c463af 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -16,7 +16,7 @@ cid = { package = "forest_cid", path = "../../ipld/cid", features = ["json"] } blocks = { package = "forest_blocks", path = "../../blockchain/blocks", features = ["json"] } clock = { path = "../clock" } message = { package = "forest_message", path = "../../vm/message", features = ["json"] } -jsonrpc-v2 = { version = "0.5.2", path="../../../jsonrpc-v2" ,features = ["easy-errors", "macros"] } +jsonrpc-v2 = { version = "0.5.2", git="https://github.com/AshantiMutinta/jsonrpc-v2" ,features = ["easy-errors", "macros"] } message_pool = { path = "../../blockchain/message_pool" } crypto = { package = "forest_crypto", path = "../../crypto", features = ["json"] } num-traits = "0.2.11" diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index fdf7923b3b3..3cf7b186a94 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -17,7 +17,7 @@ use async_std::task; use async_tungstenite::{tungstenite::Message, WebSocketStream}; use blocks::Tipset; use blockstore::BlockStore; -use chain::headchange_json::HeadChangeJson; +use chain::headchange_json::{HeadChangeJson, IndexToHeadChangeJson}; use chain::HeadChange; use chain_sync::{BadBlockCache, SyncState}; use flo_stream::{MessagePublisher, Publisher, Subscriber}; @@ -54,13 +54,12 @@ where pub keystore: Arc>, pub heaviest_tipset: Arc>>>, pub subscriber: Subscriber, - pub publisher: Arc>>, + pub publisher: Arc>>, pub mpool: Arc>>, pub bad_blocks: Arc, pub sync_state: Arc>>>>, pub network_send: Sender, pub network_name: String, - pub next_id: u64, } pub async fn start_rpc(state: RpcState, rpc_endpoint: &str) @@ -273,7 +272,7 @@ async fn handle_connection_and_log( state: Arc>, tcp_stream: TcpStream, addr: std::net::SocketAddr, - subscriber: Subscriber, + subscriber: Subscriber, ) { span!("handle_connection_and_log", { if let Ok(ws_stream) = async_tungstenite::accept_async(tcp_stream).await { @@ -359,10 +358,10 @@ async fn handle_connection_and_log( async fn streaming_payload_and_log( ws_sender: Arc>, response_object: ResponseObjects, - mut subscriber: Subscriber, + mut subscriber: Subscriber, streaming_count: usize, ) { - let response_text = serde_json::to_string_pretty(&response_object).unwrap(); + let response_text = serde_json::to_string(&response_object).unwrap(); ws_sender .write() .await @@ -379,20 +378,22 @@ async fn streaming_payload_and_log( if streaming { task::spawn(async move { let sender = ws_sender.clone(); - while let Some(resp) = subscriber.next().await { - let data = StreamingData { - json_rpc: "2.0".to_string(), - method: "xrpc.ch.val".to_string(), - params: (streaming_count, vec![resp]), - }; - let response_text = - serde_json::to_string_pretty(&data).expect("Bad Serialization of Type"); - sender - .write() - .await - .send(Message::text(response_text)) - .await - .unwrap_or_else(|_| warn!("Could not send to response to socket")); + while let Some(index_to_head_change) = subscriber.next().await { + if streaming_count == index_to_head_change.0 { + let data = StreamingData { + json_rpc: "2.0".to_string(), + method: "xrpc.ch.val".to_string(), + params: (streaming_count, vec![index_to_head_change.1]), + }; + let response_text = + serde_json::to_string(&data).expect("Bad Serialization of Type"); + sender + .write() + .await + .send(Message::text(response_text)) + .await + .unwrap_or_else(|_| warn!("Could not send to response to socket")); + } } }); } diff --git a/node/rpc/src/sync_api.rs b/node/rpc/src/sync_api.rs index 2738698b9e5..3376d30db74 100644 --- a/node/rpc/src/sync_api.rs +++ b/node/rpc/src/sync_api.rs @@ -100,6 +100,7 @@ mod tests { use chain::ChainStore; use chain_sync::SyncStage; use db::{MemoryDB, Store}; + use flo_stream::Publisher; use forest_libp2p::NetworkMessage; use futures::StreamExt; use message_pool::{MessagePool, MpoolRpcProvider}; @@ -117,9 +118,11 @@ mod tests { let (network_send, network_rx) = channel(5); let db = Arc::new(MemoryDB::default()); let state_manager = Arc::new(StateManager::new(db.clone())); - - let pool = task::block_on(async { - let cs = ChainStore::new(db.clone()); + let cs = ChainStore::new(db.clone()); + let heaviest_tipset = cs.heaviest_tipset_ref(); + let subscriber = cs.subscribe().await; + let state_manager_for_thread = state_manager.clone(); + let pool = task::block_on(async move { let bz = hex::decode("904300e80781586082cb7477a801f55c1f2ea5e5d1167661feea60a39f697e1099af132682b81cc5047beacf5b6e80d5f52b9fd90323fb8510a5396416dd076c13c85619e176558582744053a3faef6764829aa02132a1571a76aabdc498a638ea0054d3bb57f41d82015860812d2396cc4592cdf7f829374b01ffd03c5469a4b0a9acc5ccc642797aa0a5498b97b28d90820fedc6f79ff0a6005f5c15dbaca3b8a45720af7ed53000555667207a0ccb50073cd24510995abd4c4e45c1e9e114905018b2da9454190499941e818201582012dd0a6a7d0e222a97926da03adb5a7768d31cc7c5c2bd6828e14a7d25fa3a608182004b76616c69642070726f6f6681d82a5827000171a0e4022030f89a8b0373ad69079dbcbc5addfe9b34dce932189786e50d3eb432ede3ba9c43000f0001d82a5827000171a0e4022052238c7d15c100c1b9ebf849541810c9e3c2d86e826512c6c416d2318fcd496dd82a5827000171a0e40220e5658b3d18cd06e1db9015b4b0ec55c123a24d5be1ea24d83938c5b8397b4f2fd82a5827000171a0e4022018d351341c302a21786b585708c9873565a0d07c42521d4aaf52da3ff6f2e461586102c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a5f2c5439586102b5cd48724dce0fec8799d77fd6c5113276e7f470c8391faa0b5a6033a3eaf357d635705c36abe10309d73592727289680515afd9d424793ba4796b052682d21b03c5c8a37d94827fecc59cdc5750e198fdf20dee012f4d627c6665132298ab95004500053724e0").unwrap(); let header = BlockHeader::unmarshal_cbor(&bz).unwrap(); let ts = Tipset::new(vec![header]).unwrap(); @@ -132,7 +135,7 @@ mod tests { let bz2 = bz.clone(); db.as_ref().write(i.key(), bz2).unwrap(); } - let provider = MpoolRpcProvider::new(subscriber, state_manager.clone()); + let provider = MpoolRpcProvider::new(subscriber, state_manager_for_thread.clone()); MessagePool::new(provider, "test".to_string()) .await .unwrap() @@ -146,6 +149,9 @@ mod tests { sync_state: Arc::new(RwLock::new(vec![Default::default()])), network_send, network_name: TEST_NET_NAME.to_owned(), + heaviest_tipset, + publisher: Arc::new(RwLock::new(Publisher::new(1000))), + subscriber: subscriber, }); (state, network_rx) } From 4791a584dd80a67452ca9ef2ecc0d220a45a54d7 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Wed, 16 Sep 2020 04:13:20 -0400 Subject: [PATCH 16/43] attempting to remove submodule commit --- blockchain/beacon/proto/api-common-protos | 1 - blockchain/chain/src/store/chain_store.rs | 32 +++++++---------------- node/forest_libp2p/src/service.rs | 2 +- 3 files changed, 11 insertions(+), 24 deletions(-) delete mode 160000 blockchain/beacon/proto/api-common-protos diff --git a/blockchain/beacon/proto/api-common-protos b/blockchain/beacon/proto/api-common-protos deleted file mode 160000 index be41e82ef4a..00000000000 --- a/blockchain/beacon/proto/api-common-protos +++ /dev/null @@ -1 +0,0 @@ -Subproject commit be41e82ef4af6406b4cf331af00a837f813c0c3b diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 4860d9d44bf..70a273e67f8 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -187,28 +187,7 @@ where /// Constructs and returns a full tipset if messages from storage exists pub fn fill_tipsets(&self, ts: Tipset) -> Result { - let mut blocks: Vec = Vec::with_capacity(ts.blocks().len()); - - for header in ts.into_blocks() { - let (bls_messages, secp_messages) = block_messages(self.blockstore(), &header)?; - debug!( - "Fill Tipsets for header {:?} with bls_messages: {:?}", - header.cid(), - bls_messages - .iter() - .map(|b| b.cid().unwrap()) - .collect::>() - ); - - blocks.push(Block { - header, - bls_messages, - secp_messages, - }); - } - - // the given tipset has already been verified, so this cannot fail - Ok(FullTipset::new(blocks).unwrap()) + fill_tipsets(self.blockstore(), ts) } /// Determines if provided tipset is heavier than existing known heaviest tipset @@ -339,6 +318,15 @@ where for header in ts.into_blocks() { let (bls_messages, secp_messages) = block_messages(db, &header)?; + debug!( + "Fill Tipsets for header {:?} with bls_messages: {:?}", + header.cid(), + bls_messages + .iter() + .map(|b| b.cid().unwrap()) + .collect::>() + ); + blocks.push(Block { header, bls_messages, diff --git a/node/forest_libp2p/src/service.rs b/node/forest_libp2p/src/service.rs index 57b54969605..67b773f481a 100644 --- a/node/forest_libp2p/src/service.rs +++ b/node/forest_libp2p/src/service.rs @@ -260,7 +260,7 @@ where None => { break; } }, interval_event = interval.next() => if interval_event.is_some() { - //info!("Peers connected: {}", swarm_stream.get_ref().peers().len()); + info!("Peers connected: {}", swarm_stream.get_ref().peers().len()); (); } }; From 3420573667be2c3c0bc188e72bdae13e660902fe Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Wed, 16 Sep 2020 10:49:53 -0400 Subject: [PATCH 17/43] change to forest fork --- node/rpc/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 823a3c463af..b30098eff13 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -16,7 +16,7 @@ cid = { package = "forest_cid", path = "../../ipld/cid", features = ["json"] } blocks = { package = "forest_blocks", path = "../../blockchain/blocks", features = ["json"] } clock = { path = "../clock" } message = { package = "forest_message", path = "../../vm/message", features = ["json"] } -jsonrpc-v2 = { version = "0.5.2", git="https://github.com/AshantiMutinta/jsonrpc-v2" ,features = ["easy-errors", "macros"] } +jsonrpc-v2 = { version = "0.5.2", git="https://github.com/ChainSafe/jsonrpc-v2" ,features = ["easy-errors", "macros"] } message_pool = { path = "../../blockchain/message_pool" } crypto = { package = "forest_crypto", path = "../../crypto", features = ["json"] } num-traits = "0.2.11" From 5963d8938f3157c0af9c7117ada038ed6fe232bc Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Thu, 17 Sep 2020 05:33:27 -0400 Subject: [PATCH 18/43] serialize takes in reference --- blockchain/chain/src/store/chain_store.rs | 30 +++++++++++------------ node/rpc/src/lib.rs | 7 +++--- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 70a273e67f8..5088db74ad3 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -742,26 +742,26 @@ where #[cfg(feature = "json")] pub mod headchange_json { use super::*; - use blocks::tipset_json::TipsetJson; - use serde::{Deserialize, Serialize}; + use blocks::tipset_json::TipsetJsonRef; + use serde::Serialize; - #[derive(Debug, Serialize, Deserialize, Clone)] + #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "lowercase")] #[serde(tag = "type", content = "val")] - pub enum HeadChangeJson { - Current(TipsetJson), - Apply(TipsetJson), - Revert(TipsetJson), + pub enum HeadChangeJson<'a> { + Current(TipsetJsonRef<'a>), + Apply(TipsetJsonRef<'a>), + Revert(TipsetJsonRef<'a>), } #[derive(Debug, Clone)] - pub struct IndexToHeadChangeJson(pub usize, pub HeadChangeJson); - impl From for HeadChangeJson { - fn from(wrapper: HeadChange) -> Self { + pub struct IndexToHeadChangeJson(pub usize, pub HeadChange); + impl<'a> From<&'a HeadChange> for HeadChangeJson<'a> { + fn from(wrapper: &'a HeadChange) -> Self { match wrapper { - HeadChange::Current(tipset) => HeadChangeJson::Current((*tipset).clone().into()), - HeadChange::Apply(tipset) => HeadChangeJson::Apply((*tipset).clone().into()), - HeadChange::Revert(tipset) => HeadChangeJson::Revert((*tipset).clone().into()), + HeadChange::Current(tipset) => HeadChangeJson::Current(TipsetJsonRef(&tipset)), + HeadChange::Apply(tipset) => HeadChangeJson::Apply(TipsetJsonRef(&tipset)), + HeadChange::Revert(tipset) => HeadChangeJson::Revert(TipsetJsonRef(&tipset)), } } } @@ -782,12 +782,12 @@ pub mod headchange_json { .await .publish(IndexToHeadChangeJson( current_index, - HeadChange::Current(head.clone()).into(), + HeadChange::Current(head.clone()), )) .await; task::spawn(async move { while let Some(change) = subscribed_head_change.next().await { - let index_to_head_change = IndexToHeadChangeJson(current_index, change.into()); + let index_to_head_change = IndexToHeadChangeJson(current_index, change); publisher.write().await.publish(index_to_head_change).await; } }); diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 3cf7b186a94..296a89d8edb 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -38,10 +38,10 @@ type WsSink = SplitSink, async_tungstenite::tungsteni const CHAIN_NOTIFY_METHOD_NAME: &str = "Filecoin.ChainNotify"; #[derive(Serialize)] -struct StreamingData { +struct StreamingData<'a> { json_rpc: String, method: String, - params: (usize, Vec), + params: (usize, Vec>), } /// This is where you store persistant data, or at least access to stateful data. @@ -380,10 +380,11 @@ async fn streaming_payload_and_log( let sender = ws_sender.clone(); while let Some(index_to_head_change) = subscriber.next().await { if streaming_count == index_to_head_change.0 { + let head_change = (&index_to_head_change.1).into(); let data = StreamingData { json_rpc: "2.0".to_string(), method: "xrpc.ch.val".to_string(), - params: (streaming_count, vec![index_to_head_change.1]), + params: (streaming_count, vec![head_change]), }; let response_text = serde_json::to_string(&data).expect("Bad Serialization of Type"); From 3a85e0907efd23ccf3d104156a414d50e7f64b27 Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Fri, 18 Sep 2020 06:00:55 -0400 Subject: [PATCH 19/43] Update blockchain/blocks/src/tipset.rs Co-authored-by: Austin Abell --- blockchain/blocks/src/tipset.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index 5fb9e012a10..f05b424d50f 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -271,7 +271,7 @@ pub mod tipset_json { use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; /// Wrapper for serializing and deserializing a SignedMessage from JSON. - #[derive(Deserialize, Serialize, Debug, Clone)] + #[derive(Deserialize, Serialize)] #[serde(transparent)] pub struct TipsetJson(#[serde(with = "self")] pub Tipset); From 2e8a74ed7c91510c85dda6f687be5f55c950f023 Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Fri, 18 Sep 2020 06:02:18 -0400 Subject: [PATCH 20/43] Update node/forest_libp2p/src/service.rs Co-authored-by: Austin Abell --- node/forest_libp2p/src/service.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/node/forest_libp2p/src/service.rs b/node/forest_libp2p/src/service.rs index 67b773f481a..5c86fab75c2 100644 --- a/node/forest_libp2p/src/service.rs +++ b/node/forest_libp2p/src/service.rs @@ -261,7 +261,6 @@ where }, interval_event = interval.next() => if interval_event.is_some() { info!("Peers connected: {}", swarm_stream.get_ref().peers().len()); - (); } }; } From 7978fd93a7d3375afe061f59d17a6ff605f80848 Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Fri, 18 Sep 2020 06:03:10 -0400 Subject: [PATCH 21/43] Update node/rpc/src/lib.rs Co-authored-by: Austin Abell --- node/rpc/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 296a89d8edb..64803b3e76b 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -276,7 +276,7 @@ async fn handle_connection_and_log( ) { span!("handle_connection_and_log", { if let Ok(ws_stream) = async_tungstenite::accept_async(tcp_stream).await { - info!("accepted websocket connection at {:}", addr); + debug!("accepted websocket connection at {:}", addr); let (ws_sender, mut ws_receiver) = ws_stream.split(); let ws_sender = Arc::new(RwLock::new(ws_sender)); let mut chain_notify_count = 0; From afbb7886dd34b79729cabf7baf5c70c1aaff281e Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Fri, 18 Sep 2020 06:03:32 -0400 Subject: [PATCH 22/43] Update node/rpc/src/lib.rs Co-authored-by: Austin Abell --- node/rpc/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 64803b3e76b..3375fbac754 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -284,10 +284,6 @@ async fn handle_connection_and_log( match message_result { Ok(message) => { let request_text = message.into_text().unwrap(); - info!( - "serde request {:?}", - serde_json::to_string_pretty(&request_text).unwrap() - ); match serde_json::from_str(&request_text) as Result { Ok(call) => { // hacky but due to the limitations of jsonrpc_v2 impl From 42533b9c6f64e5ace1e5ebe6ca8871c814c534a9 Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Fri, 18 Sep 2020 06:04:31 -0400 Subject: [PATCH 23/43] Update blockchain/blocks/src/tipset.rs Co-authored-by: Austin Abell --- blockchain/blocks/src/tipset.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index f05b424d50f..bfa3fc69011 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -276,7 +276,7 @@ pub mod tipset_json { pub struct TipsetJson(#[serde(with = "self")] pub Tipset); /// Wrapper for serializing a SignedMessage reference to JSON. - #[derive(Serialize, Clone, Debug)] + #[derive(Serialize)] #[serde(transparent)] pub struct TipsetJsonRef<'a>(#[serde(with = "self")] pub &'a Tipset); From 11a387e5d3f6abc6dbf45cd1d604764d007d4d0c Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Fri, 18 Sep 2020 06:11:02 -0400 Subject: [PATCH 24/43] Update blockchain/chain/src/store/chain_store.rs Co-authored-by: Austin Abell --- blockchain/chain/src/store/chain_store.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 5088db74ad3..6235ef80dd0 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -745,7 +745,7 @@ pub mod headchange_json { use blocks::tipset_json::TipsetJsonRef; use serde::Serialize; - #[derive(Debug, Serialize, Clone)] + #[derive(Serialize)] #[serde(rename_all = "lowercase")] #[serde(tag = "type", content = "val")] pub enum HeadChangeJson<'a> { From 86441a8da1ea2a9832a2bf5bb861806061f4a6c4 Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Fri, 18 Sep 2020 06:11:28 -0400 Subject: [PATCH 25/43] Update node/rpc/src/lib.rs Co-authored-by: Austin Abell --- node/rpc/src/lib.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 3375fbac754..bd178aa2750 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -364,12 +364,7 @@ async fn streaming_payload_and_log( .send(Message::text(response_text)) .await .unwrap_or_else(|_| warn!("Could not send to response to socket")); - if let ResponseObjects::One(ResponseObject::Result { - jsonrpc: _, - result: _, - id: _, - streaming, - }) = response_object + if let ResponseObjects::One(ResponseObject::Result { streaming, .. }) = response_object { { if streaming { task::spawn(async move { From 628e5cd3c7ee8deaf9dc27de36431d150a546e06 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Fri, 18 Sep 2020 12:36:37 -0400 Subject: [PATCH 26/43] Using async channels instead of subscribe channel --- blockchain/chain/src/store/chain_store.rs | 153 ++++++++----------- forest/src/daemon.rs | 11 +- node/rpc/src/chain_api.rs | 5 +- node/rpc/src/lib.rs | 170 +++++++++++++--------- node/rpc/src/sync_api.rs | 2 +- 5 files changed, 167 insertions(+), 174 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 5088db74ad3..cd745e3b276 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -5,6 +5,7 @@ use super::{Error, TipIndex, TipsetMetadata}; use actor::{power::State as PowerState, STORAGE_POWER_ACTOR_ADDR}; use address::Address; use async_std::sync::RwLock; +use async_std::sync::{Receiver, Sender}; use async_std::task; use beacon::{BeaconEntry, IGNORE_DRAND_VAR}; use blake2b_simd::Params; @@ -16,10 +17,10 @@ use clock::ChainEpoch; use crypto::DomainSeparationTag; use encoding::{blake2b_256, de::DeserializeOwned, from_slice, Cbor}; use flo_stream::{MessagePublisher, Publisher, Subscriber}; -use futures::StreamExt; +use futures::{future, StreamExt}; use ipld_amt::Amt; use ipld_blockstore::BlockStore; -use log::{debug, info, warn}; +use log::{info, warn}; use message::{ChainMessage, Message, MessageReceipt, SignedMessage, UnsignedMessage}; use num_bigint::BigInt; use num_traits::Zero; @@ -53,7 +54,7 @@ pub enum HeadChange { /// This structure is threadsafe, and all caches are wrapped in a mutex to allow a consistent /// `ChainStore` to be shared across tasks. pub struct ChainStore { - publisher: Arc>>, + publisher: RwLock>, // key-value datastore pub db: Arc, @@ -76,7 +77,7 @@ where .map(Arc::new); Self { db, - publisher: Arc::new(RwLock::new(Publisher::new(SINK_CAP))), + publisher: RwLock::new(Publisher::new(SINK_CAP)), tip_index: Arc::new(RwLock::new(TipIndex::new())), heaviest: Arc::new(RwLock::new(heaviest)), } @@ -96,7 +97,11 @@ where // subscribing returns a future sink that we can essentially iterate over using future streams pub async fn subscribe(&self) -> Subscriber { - self.publisher.write().await.subscribe() + self + .publisher + .write() + .await + .subscribe() } /// Sets tip_index tracker @@ -159,15 +164,11 @@ where self.heaviest.read().await.clone() } - pub fn heaviest_tipset_ref(&self) -> Arc>>> { + pub fn heaviest_tipset_arc(&self) -> Arc>>> { self.heaviest.clone() } - pub fn publisher_ref(&self) -> Arc>> { - self.publisher.clone() - } - - pub fn tip_index_ref(&mut self) -> Arc> { + pub fn tip_index_arc(&mut self) -> Arc> { self.tip_index.clone() } @@ -211,73 +212,6 @@ where } } -pub async fn put_tipset_lock( - heaviest_lock: Arc>>>, - ts: &Tipset, - publisher: Arc>>, - db: Arc, -) -> Result<(), Error> -where - DB: BlockStore, -{ - persist_objects(&*db, ts.blocks())?; - update_heaviest_lock(heaviest_lock, ts, publisher, db).await -} - -pub async fn set_heaviest_tipset_lock( - heaviest: Arc>>>, - ts: Arc, - publisher: Arc>>, - db: Arc, -) -> Result<(), Error> -where - DB: BlockStore, -{ - db.write(HEAD_KEY, ts.key().marshal_cbor()?)?; - let mut heaviest = heaviest.write().await; - *heaviest = Some(ts.clone()); - publisher - .write() - .await - .publish(HeadChange::Current(ts)) - .await; - Ok(()) -} - -pub async fn update_heaviest_lock( - heaviest_lock: Arc>>>, - ts: &Tipset, - publisher: Arc>>, - db: Arc, -) -> Result<(), Error> -where - DB: BlockStore, -{ - match &*heaviest_lock.read().await { - Some(heaviest) => { - let new_weight = weight(&*db, &ts)?; - let curr_weight = weight(&*db, &heaviest)?; - if new_weight > curr_weight { - // TODO potentially need to deal with re-orgs here - info!("New heaviest tipset"); - set_heaviest_tipset_lock( - heaviest_lock.clone(), - Arc::new(ts.clone()), - publisher, - db, - ) - .await?; - } - } - None => { - info!("set heaviest tipset"); - set_heaviest_tipset_lock(heaviest_lock.clone(), Arc::new(ts.clone()), publisher, db) - .await?; - } - } - Ok(()) -} - /// Returns messages for a given tipset from db pub fn unsigned_messages_for_tipset(db: &DB, h: &Tipset) -> Result, Error> where @@ -318,15 +252,6 @@ where for header in ts.into_blocks() { let (bls_messages, secp_messages) = block_messages(db, &header)?; - debug!( - "Fill Tipsets for header {:?} with bls_messages: {:?}", - header.cid(), - bls_messages - .iter() - .map(|b| b.cid().unwrap()) - .collect::>() - ); - blocks.push(Block { header, bls_messages, @@ -766,29 +691,65 @@ pub mod headchange_json { } } + pub enum EventsPayload { + TaskCancel(usize, ()), + SubHeadChanges(IndexToHeadChangeJson), + } + + impl EventsPayload { + pub fn sub_head_changes(&self) -> Option<&IndexToHeadChangeJson> { + match self { + EventsPayload::SubHeadChanges(s) => Some(s), + _ => None, + } + } + + pub fn task_cancel(&self) -> Option<(usize, ())> { + match self { + EventsPayload::TaskCancel(val, _) => Some((*val, ())), + _ => None, + } + } + } + pub async fn sub_head_changes( - publisher: Arc>>, mut subscribed_head_change: Subscriber, heaviest_tipset: &Option>, current_index: usize, + events_sender: Sender, + events_receiver: Receiver, ) -> Result { - info!("sub head changes"); let head = heaviest_tipset .as_ref() .ok_or_else(|| Error::Other("Could not get heaviest tipset".to_string()))?; - publisher - .write() - .await - .publish(IndexToHeadChangeJson( + events_sender + .send(EventsPayload::SubHeadChanges(IndexToHeadChangeJson( current_index, HeadChange::Current(head.clone()), - )) + ))) .await; - task::spawn(async move { + let handle = task::spawn(async move { while let Some(change) = subscribed_head_change.next().await { let index_to_head_change = IndexToHeadChangeJson(current_index, change); - publisher.write().await.publish(index_to_head_change).await; + events_sender + .send(EventsPayload::SubHeadChanges(index_to_head_change)) + .await; + } + }); + task::spawn(async move { + if let Some(_) = events_receiver + .filter(|s| { + future::ready( + s.task_cancel() + .map(|(s, _)| s == current_index) + .unwrap_or_default(), + ) + }) + .next() + .await + { + handle.cancel().await; } }); Ok(current_index) diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index b6ca36909f4..cc5069a0661 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -3,13 +3,13 @@ use super::cli::{block_until_sigint, initialize_genesis, Config}; use actor::EPOCH_DURATION_SECONDS; +use async_std::sync::channel; use async_std::sync::RwLock; use async_std::task; use beacon::{DrandBeacon, DEFAULT_DRAND_URL}; use chain::ChainStore; use chain_sync::ChainSyncer; use db::RocksDb; -use flo_stream::Publisher; use forest_libp2p::{get_keypair, Libp2pService}; use libp2p::identity::{ed25519, Keypair}; use log::{debug, info, trace}; @@ -92,7 +92,7 @@ pub(super) async fn start(config: Config) { let subscriber = chain_store.subscribe().await; // Initialize ChainSyncer - let heaviest_tipset = chain_store.heaviest_tipset_ref(); + let heaviest_tipset = chain_store.heaviest_tipset_arc(); let chain_syncer = ChainSyncer::new( Arc::new(chain_store), Arc::clone(&state_manager), @@ -112,7 +112,7 @@ pub(super) async fn start(config: Config) { let p2p_task = task::spawn(async { p2p_service.run().await; }); - + let (events_sender, events_receiver) = channel(1000); let rpc_task = if config.enable_rpc { let keystore_rpc = Arc::clone(&keystore); let rpc_listen = format!("127.0.0.1:{}", &config.rpc_port); @@ -128,8 +128,9 @@ pub(super) async fn start(config: Config) { network_send, network_name, heaviest_tipset, - subscriber, - publisher: Arc::new(RwLock::new(Publisher::new(1000))), + events_receiver, + events_sender, + subscriber }, &rpc_listen, ) diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index 3e97bcd1d3b..ada54e9e2c1 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -56,7 +56,7 @@ where Ok(UnsignedMessageJson(ret)) } -pub(crate) async fn chain_notify( +pub(crate) async fn chain_notify<'a, DB, KS>( data: Data>, Params(params): Params, ) -> Result @@ -66,10 +66,11 @@ where { let heaviest_tipset = data.heaviest_tipset.read().await; let index = chain::headchange_json::sub_head_changes( - data.publisher.clone(), data.subscriber.clone(), &heaviest_tipset, params, + data.events_sender.clone(), + data.events_receiver.clone(), ) .await?; Ok(index) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 296a89d8edb..8c800be708d 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -12,35 +12,38 @@ use crate::state_api::*; use async_log::span; use async_std::net::{TcpListener, TcpStream}; use async_std::sync::Arc; -use async_std::sync::{RwLock, Sender}; +use async_std::sync::{Receiver, RwLock, Sender}; use async_std::task; +use async_std::task::JoinHandle; use async_tungstenite::{tungstenite::Message, WebSocketStream}; use blocks::Tipset; use blockstore::BlockStore; -use chain::headchange_json::{HeadChangeJson, IndexToHeadChangeJson}; +use chain::headchange_json::{HeadChangeJson, EventsPayload}; use chain::HeadChange; use chain_sync::{BadBlockCache, SyncState}; -use flo_stream::{MessagePublisher, Publisher, Subscriber}; +use flo_stream::Subscriber; use forest_libp2p::NetworkMessage; use futures::sink::SinkExt; use futures::stream::{SplitSink, StreamExt}; +use futures::future; use jsonrpc_v2::{ Data, Error, Id, MapRouter, RequestBuilder, RequestObject, ResponseObject, ResponseObjects, Server, V2, }; -use log::{info, warn}; +use log::{info,error, warn}; use message_pool::{MessagePool, MpoolRpcProvider}; use serde::Serialize; use state_manager::StateManager; use wallet::KeyStore; +use futures::TryFutureExt; type WsSink = SplitSink, async_tungstenite::tungstenite::Message>; const CHAIN_NOTIFY_METHOD_NAME: &str = "Filecoin.ChainNotify"; #[derive(Serialize)] struct StreamingData<'a> { - json_rpc: String, - method: String, + json_rpc: &'a str, + method: &'a str, params: (usize, Vec>), } @@ -54,7 +57,8 @@ where pub keystore: Arc>, pub heaviest_tipset: Arc>>>, pub subscriber: Subscriber, - pub publisher: Arc>>, + pub events_sender: Sender, + pub events_receiver: Receiver, pub mpool: Arc>>, pub bad_blocks: Arc, pub sync_state: Arc>>>>, @@ -62,6 +66,9 @@ where pub network_name: String, } + + + pub async fn start_rpc(state: RpcState, rpc_endpoint: &str) where DB: BlockStore + Send + Sync + 'static, @@ -72,7 +79,8 @@ where use mpool_api::*; use sync_api::*; use wallet_api::*; - let subscriber = state.publisher.write().await.subscribe(); + let events_receiver = state.events_sender.clone(); + let events_sender = state.events_receiver.clone(); let rpc = Server::new() .with_data(Data::new(state)) .with_method( @@ -253,15 +261,16 @@ where let try_socket = TcpListener::bind(rpc_endpoint).await; let listener = try_socket.expect("Failed to bind to addr"); - let state = Arc::new(rpc); + let rpc_state = Arc::new(rpc); info!("waiting for web socket connections"); while let Ok((stream, addr)) = listener.accept().await { task::spawn(handle_connection_and_log( - state.clone(), + rpc_state.clone(), stream, addr, - subscriber.clone(), + events_receiver.clone(), + events_sender.clone(), )); } @@ -272,14 +281,15 @@ async fn handle_connection_and_log( state: Arc>, tcp_stream: TcpStream, addr: std::net::SocketAddr, - subscriber: Subscriber, + events_sender : Sender, + subscriber: Receiver, ) { span!("handle_connection_and_log", { if let Ok(ws_stream) = async_tungstenite::accept_async(tcp_stream).await { info!("accepted websocket connection at {:}", addr); let (ws_sender, mut ws_receiver) = ws_stream.split(); let ws_sender = Arc::new(RwLock::new(ws_sender)); - let mut chain_notify_count = 0; + let mut chain_notify_count: usize = 0; while let Some(message_result) = ws_receiver.next().await { match message_result { Ok(message) => { @@ -288,7 +298,7 @@ async fn handle_connection_and_log( "serde request {:?}", serde_json::to_string_pretty(&request_text).unwrap() ); - match serde_json::from_str(&request_text) as Result { + match serde_json::from_str(&request_text) as Result { Ok(call) => { // hacky but due to the limitations of jsonrpc_v2 impl // if this expands, better to implement some sort of middleware @@ -303,49 +313,34 @@ async fn handle_connection_and_log( call }; let response = state.clone().handle(call).await; - streaming_payload_and_log( + let error_send = ws_sender.clone(); + streaming_payload( ws_sender.clone(), response, - subscriber.clone(), chain_notify_count, + subscriber.clone(), + events_sender.clone(), ) - .await; + .map_err(|e|async move{ + send_error(3,error_send,format!("channel id {:}, error {:?}",chain_notify_count,e.message())) + .await.unwrap_or_else(|e|error!("error {:?} on socket {:?}",e.message(),addr)) + }).await.unwrap_or_else(|_|error!("error sending on socket {:?}",addr)) } - Err(_) => { - let response = ResponseObjects::One(ResponseObject::Error { - jsonrpc: V2, - error: Error::Provided { - code: 1, - message: "Error serialization request", - }, - id: Id::Null, - }); - streaming_payload_and_log( + Err(e) => { + send_error( + 1, ws_sender.clone(), - response, - subscriber.clone(), - chain_notify_count, - ) - .await; + e.to_string() + ).await.unwrap_or_else(|e|error!("error {:?} on socket {:?}",e.message(),addr)) } } } - Err(_) => { - let response = ResponseObjects::One(ResponseObject::Error { - jsonrpc: V2, - error: Error::Provided { - code: 2, - message: "Error reading request", - }, - id: Id::Null, - }); - streaming_payload_and_log( + Err(e) => { + send_error( + 2, ws_sender.clone(), - response, - subscriber.clone(), - chain_notify_count, - ) - .await; + e.to_string() + ).await.unwrap_or_else(|e|error!("error {:?} on socket {:?}",e.message(),addr)) } }; } @@ -355,19 +350,41 @@ async fn handle_connection_and_log( }) } -async fn streaming_payload_and_log( + +async fn send_error(code:i64,ws_sender: Arc>,message : String) -> Result<(),Error> +{ + let response = ResponseObjects::One(ResponseObject::Error { + jsonrpc: V2, + error: Error::Full { + code, + message, + data : None + }, + id: Id::Null, + }); + let response_text = serde_json::to_string(&response)?; + ws_sender + .write() + .await + .send(Message::text(response_text)) + .await?; + Ok(()) + +} +async fn streaming_payload( ws_sender: Arc>, response_object: ResponseObjects, - mut subscriber: Subscriber, streaming_count: usize, -) { + events_receiver: Receiver, + events_sender: Sender, +)->Result<(),Error> { let response_text = serde_json::to_string(&response_object).unwrap(); ws_sender .write() .await .send(Message::text(response_text)) .await - .unwrap_or_else(|_| warn!("Could not send to response to socket")); + ?; if let ResponseObjects::One(ResponseObject::Result { jsonrpc: _, result: _, @@ -376,27 +393,40 @@ async fn streaming_payload_and_log( }) = response_object { if streaming { - task::spawn(async move { + let handle : JoinHandle> = task::spawn(async move { let sender = ws_sender.clone(); - while let Some(index_to_head_change) = subscriber.next().await { - if streaming_count == index_to_head_change.0 { - let head_change = (&index_to_head_change.1).into(); - let data = StreamingData { - json_rpc: "2.0".to_string(), - method: "xrpc.ch.val".to_string(), - params: (streaming_count, vec![head_change]), - }; - let response_text = - serde_json::to_string(&data).expect("Bad Serialization of Type"); - sender - .write() - .await - .send(Message::text(response_text)) - .await - .unwrap_or_else(|_| warn!("Could not send to response to socket")); - } - } + let mut sub_head_changes = events_receiver + .filter(|payload| future::ready(payload.sub_head_changes().map(|s|s.0==streaming_count).unwrap_or_default())); + while let Some(events) = sub_head_changes.next().await { + if let EventsPayload::SubHeadChanges(index_to_head_change) = events + { + let head_change = (&index_to_head_change.1).into(); + let data = StreamingData { + json_rpc: "2.0", + method: "xrpc.ch.val", + params: (streaming_count, vec![head_change]), + }; + let response_text = + serde_json::to_string(&data)?; + sender + .write() + .await + .send(Message::text(response_text)) + .await + ?; + } + }; + + Ok(()) }); + handle.await + } + else + { + Ok(()) } + } else { + events_sender.send(EventsPayload::TaskCancel(streaming_count,())).await; + Ok(()) } } diff --git a/node/rpc/src/sync_api.rs b/node/rpc/src/sync_api.rs index 3376d30db74..87e34993efb 100644 --- a/node/rpc/src/sync_api.rs +++ b/node/rpc/src/sync_api.rs @@ -119,7 +119,7 @@ mod tests { let db = Arc::new(MemoryDB::default()); let state_manager = Arc::new(StateManager::new(db.clone())); let cs = ChainStore::new(db.clone()); - let heaviest_tipset = cs.heaviest_tipset_ref(); + let heaviest_tipset = cs.heaviest_tipset_arc(); let subscriber = cs.subscribe().await; let state_manager_for_thread = state_manager.clone(); let pool = task::block_on(async move { From a58e401dde7b130700dce9f756599f5c0c0ecc2e Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Mon, 21 Sep 2020 07:55:52 -0400 Subject: [PATCH 27/43] made various changes --- blockchain/chain/src/store/chain_store.rs | 37 ++-- forest/src/daemon.rs | 13 +- node/rpc/src/chain_api.rs | 10 +- node/rpc/src/lib.rs | 210 ++++++++++++++-------- 4 files changed, 169 insertions(+), 101 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index cd745e3b276..803089f23a1 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -5,7 +5,6 @@ use super::{Error, TipIndex, TipsetMetadata}; use actor::{power::State as PowerState, STORAGE_POWER_ACTOR_ADDR}; use address::Address; use async_std::sync::RwLock; -use async_std::sync::{Receiver, Sender}; use async_std::task; use beacon::{BeaconEntry, IGNORE_DRAND_VAR}; use blake2b_simd::Params; @@ -54,7 +53,7 @@ pub enum HeadChange { /// This structure is threadsafe, and all caches are wrapped in a mutex to allow a consistent /// `ChainStore` to be shared across tasks. pub struct ChainStore { - publisher: RwLock>, + publisher: Arc>>, // key-value datastore pub db: Arc, @@ -77,7 +76,7 @@ where .map(Arc::new); Self { db, - publisher: RwLock::new(Publisher::new(SINK_CAP)), + publisher: Arc::new(RwLock::new(Publisher::new(SINK_CAP))), tip_index: Arc::new(RwLock::new(TipIndex::new())), heaviest: Arc::new(RwLock::new(heaviest)), } @@ -97,11 +96,7 @@ where // subscribing returns a future sink that we can essentially iterate over using future streams pub async fn subscribe(&self) -> Subscriber { - self - .publisher - .write() - .await - .subscribe() + self.publisher.write().await.subscribe() } /// Sets tip_index tracker @@ -168,10 +163,14 @@ where self.heaviest.clone() } - pub fn tip_index_arc(&mut self) -> Arc> { + pub fn tip_index_arc(&self) -> Arc> { self.tip_index.clone() } + pub fn publisher_arc(&self) -> Arc>> { + self.publisher.clone() + } + pub fn blockstore_arc(&self) -> Arc { self.db.clone() } @@ -691,6 +690,7 @@ pub mod headchange_json { } } + #[derive(Clone)] pub enum EventsPayload { TaskCancel(usize, ()), SubHeadChanges(IndexToHeadChangeJson), @@ -716,33 +716,36 @@ pub mod headchange_json { mut subscribed_head_change: Subscriber, heaviest_tipset: &Option>, current_index: usize, - events_sender: Sender, - events_receiver: Receiver, + events_pubsub: Arc>>, ) -> Result { let head = heaviest_tipset .as_ref() .ok_or_else(|| Error::Other("Could not get heaviest tipset".to_string()))?; - events_sender - .send(EventsPayload::SubHeadChanges(IndexToHeadChangeJson( + (*events_pubsub.write().await) + .publish(EventsPayload::SubHeadChanges(IndexToHeadChangeJson( current_index, HeadChange::Current(head.clone()), ))) .await; + let subhead_sender = events_pubsub.clone(); let handle = task::spawn(async move { while let Some(change) = subscribed_head_change.next().await { let index_to_head_change = IndexToHeadChangeJson(current_index, change); - events_sender - .send(EventsPayload::SubHeadChanges(index_to_head_change)) + subhead_sender + .write() + .await + .publish(EventsPayload::SubHeadChanges(index_to_head_change)) .await; } }); + let cancel_sender = events_pubsub.write().await.subscribe(); task::spawn(async move { - if let Some(_) = events_receiver + if let Some(EventsPayload::TaskCancel(_, ())) = cancel_sender .filter(|s| { future::ready( s.task_cancel() - .map(|(s, _)| s == current_index) + .map(|s| s.0 == current_index) .unwrap_or_default(), ) }) diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index cc5069a0661..7f080448f0b 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -3,13 +3,13 @@ use super::cli::{block_until_sigint, initialize_genesis, Config}; use actor::EPOCH_DURATION_SECONDS; -use async_std::sync::channel; use async_std::sync::RwLock; use async_std::task; use beacon::{DrandBeacon, DEFAULT_DRAND_URL}; use chain::ChainStore; use chain_sync::ChainSyncer; use db::RocksDb; +use flo_stream::{MessagePublisher, Publisher}; use forest_libp2p::{get_keypair, Libp2pService}; use libp2p::identity::{ed25519, Keypair}; use log::{debug, info, trace}; @@ -69,7 +69,8 @@ pub(super) async fn start(config: Config) { let state_manager = Arc::new(StateManager::new(Arc::clone(&db))); // Initialize mpool - let subscriber = chain_store.subscribe().await; + let publisher = chain_store.publisher_arc(); + let subscriber = (*publisher.write().await).subscribe(); let provider = MpoolRpcProvider::new(subscriber, Arc::clone(&state_manager)); let mpool = Arc::new( MessagePool::new(provider, network_name.clone()) @@ -89,8 +90,6 @@ pub(super) async fn start(config: Config) { .await .unwrap(); - let subscriber = chain_store.subscribe().await; - // Initialize ChainSyncer let heaviest_tipset = chain_store.heaviest_tipset_arc(); let chain_syncer = ChainSyncer::new( @@ -112,7 +111,6 @@ pub(super) async fn start(config: Config) { let p2p_task = task::spawn(async { p2p_service.run().await; }); - let (events_sender, events_receiver) = channel(1000); let rpc_task = if config.enable_rpc { let keystore_rpc = Arc::clone(&keystore); let rpc_listen = format!("127.0.0.1:{}", &config.rpc_port); @@ -128,9 +126,8 @@ pub(super) async fn start(config: Config) { network_send, network_name, heaviest_tipset, - events_receiver, - events_sender, - subscriber + publisher, + events_pubsub: Arc::new(RwLock::new(Publisher::new(1000))), }, &rpc_listen, ) diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index ada54e9e2c1..388601b5c2a 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -10,6 +10,7 @@ use cid::{json::CidJson, Cid}; use clock::ChainEpoch; use crypto::DomainSeparationTag; +use flo_stream::MessagePublisher; use jsonrpc_v2::{Data, Error as JsonRpcError, Params}; use message::{ signed_message, @@ -64,13 +65,12 @@ where DB: BlockStore + Send + Sync + 'static, KS: KeyStore + Send + Sync + 'static, { - let heaviest_tipset = data.heaviest_tipset.read().await; + let data_subscribe = data.publisher.write().await.subscribe(); let index = chain::headchange_json::sub_head_changes( - data.subscriber.clone(), - &heaviest_tipset, + data_subscribe, + &*data.heaviest_tipset.read().await, params, - data.events_sender.clone(), - data.events_receiver.clone(), + data.events_pubsub.clone(), ) .await?; Ok(index) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 8c800be708d..b27bbff22bf 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -12,30 +12,31 @@ use crate::state_api::*; use async_log::span; use async_std::net::{TcpListener, TcpStream}; use async_std::sync::Arc; -use async_std::sync::{Receiver, RwLock, Sender}; +use async_std::sync::{RwLock, Sender}; use async_std::task; use async_std::task::JoinHandle; use async_tungstenite::{tungstenite::Message, WebSocketStream}; use blocks::Tipset; use blockstore::BlockStore; -use chain::headchange_json::{HeadChangeJson, EventsPayload}; +use chain::headchange_json::{EventsPayload, HeadChangeJson}; use chain::HeadChange; use chain_sync::{BadBlockCache, SyncState}; -use flo_stream::Subscriber; +use flo_stream::MessagePublisher; +use flo_stream::{Publisher, Subscriber}; use forest_libp2p::NetworkMessage; +use futures::future; use futures::sink::SinkExt; use futures::stream::{SplitSink, StreamExt}; -use futures::future; +use futures::TryFutureExt; use jsonrpc_v2::{ Data, Error, Id, MapRouter, RequestBuilder, RequestObject, ResponseObject, ResponseObjects, Server, V2, }; -use log::{info,error, warn}; +use log::{error, info, warn}; use message_pool::{MessagePool, MpoolRpcProvider}; use serde::Serialize; use state_manager::StateManager; use wallet::KeyStore; -use futures::TryFutureExt; type WsSink = SplitSink, async_tungstenite::tungstenite::Message>; @@ -56,9 +57,8 @@ where pub state_manager: Arc>, pub keystore: Arc>, pub heaviest_tipset: Arc>>>, - pub subscriber: Subscriber, - pub events_sender: Sender, - pub events_receiver: Receiver, + pub publisher: Arc>>, + pub events_pubsub: Arc>>, pub mpool: Arc>>, pub bad_blocks: Arc, pub sync_state: Arc>>>>, @@ -66,9 +66,6 @@ where pub network_name: String, } - - - pub async fn start_rpc(state: RpcState, rpc_endpoint: &str) where DB: BlockStore + Send + Sync + 'static, @@ -79,8 +76,7 @@ where use mpool_api::*; use sync_api::*; use wallet_api::*; - let events_receiver = state.events_sender.clone(); - let events_sender = state.events_receiver.clone(); + let events_pubsub = state.events_pubsub.clone(); let rpc = Server::new() .with_data(Data::new(state)) .with_method( @@ -265,12 +261,13 @@ where info!("waiting for web socket connections"); while let Ok((stream, addr)) = listener.accept().await { + let subscriber = (*events_pubsub.write().await).subscribe(); task::spawn(handle_connection_and_log( rpc_state.clone(), stream, addr, - events_receiver.clone(), - events_sender.clone(), + events_pubsub.clone(), + subscriber, )); } @@ -281,8 +278,8 @@ async fn handle_connection_and_log( state: Arc>, tcp_stream: TcpStream, addr: std::net::SocketAddr, - events_sender : Sender, - subscriber: Receiver, + events_out: Arc>>, + events_in: Subscriber, ) { span!("handle_connection_and_log", { if let Ok(ws_stream) = async_tungstenite::accept_async(tcp_stream).await { @@ -298,7 +295,9 @@ async fn handle_connection_and_log( "serde request {:?}", serde_json::to_string_pretty(&request_text).unwrap() ); - match serde_json::from_str(&request_text) as Result { + match serde_json::from_str(&request_text) + as Result + { Ok(call) => { // hacky but due to the limitations of jsonrpc_v2 impl // if this expands, better to implement some sort of middleware @@ -313,35 +312,97 @@ async fn handle_connection_and_log( call }; let response = state.clone().handle(call).await; - let error_send = ws_sender.clone(); - streaming_payload( + let error_send = ws_sender.clone(); + + // initiate response and streaming if applicable + let join_handle = streaming_payload( ws_sender.clone(), response, chain_notify_count, - subscriber.clone(), - events_sender.clone(), + events_out.clone(), + events_in.clone(), ) - .map_err(|e|async move{ - send_error(3,error_send,format!("channel id {:}, error {:?}",chain_notify_count,e.message())) - .await.unwrap_or_else(|e|error!("error {:?} on socket {:?}",e.message(),addr)) - }).await.unwrap_or_else(|_|error!("error sending on socket {:?}",addr)) - } - Err(e) => { - send_error( - 1, - ws_sender.clone(), - e.to_string() - ).await.unwrap_or_else(|e|error!("error {:?} on socket {:?}",e.message(),addr)) + .map_err(|e| async move { + send_error( + 3, + error_send, + format!( + "channel id {:}, error {:?}", + chain_notify_count, + e.message() + ), + ) + .await + .unwrap_or_else(|e| { + error!("error {:?} on socket {:?}", e.message(), addr) + }); + }) + .await + .unwrap_or_else(|_| { + error!("error sending on socket {:?}", addr); + None + }); + + // wait for join handle to complete if there is error and send it over the network and cancel streaming + let error_join_send = ws_sender.clone(); + let handle_events_out = events_out.clone(); + task::spawn(async move { + if let Some(handle) = join_handle { + handle + .map_err(|e| async move { + send_error( + 3, + error_join_send, + format!( + "channel id {:}, error {:?}", + chain_notify_count, + e.message() + ), + ) + .await + .unwrap_or_else(|e| { + error!( + "error {:?} on socket {:?}", + e.message(), + addr + ) + }); + }) + .await + .unwrap_or_else(|_| { + error!("error sending on socket {:?}", addr) + }); + + handle_events_out + .write() + .await + .publish(EventsPayload::TaskCancel( + chain_notify_count, + (), + )) + .await; + } else { + handle_events_out + .write() + .await + .publish(EventsPayload::TaskCancel( + chain_notify_count, + (), + )) + .await + } + }); } + Err(e) => send_error(1, ws_sender.clone(), e.to_string()) + .await + .unwrap_or_else(|e| { + error!("error {:?} on socket {:?}", e.message(), addr) + }), } } - Err(e) => { - send_error( - 2, - ws_sender.clone(), - e.to_string() - ).await.unwrap_or_else(|e|error!("error {:?} on socket {:?}",e.message(),addr)) - } + Err(e) => send_error(2, ws_sender.clone(), e.to_string()) + .await + .unwrap_or_else(|e| error!("error {:?} on socket {:?}", e.message(), addr)), }; } } else { @@ -350,15 +411,17 @@ async fn handle_connection_and_log( }) } - -async fn send_error(code:i64,ws_sender: Arc>,message : String) -> Result<(),Error> -{ +async fn send_error( + code: i64, + ws_sender: Arc>, + message: String, +) -> Result<(), Error> { let response = ResponseObjects::One(ResponseObject::Error { jsonrpc: V2, error: Error::Full { code, message, - data : None + data: None, }, id: Id::Null, }); @@ -369,22 +432,20 @@ async fn send_error(code:i64,ws_sender: Arc>,message : String) -> .send(Message::text(response_text)) .await?; Ok(()) - } async fn streaming_payload( ws_sender: Arc>, response_object: ResponseObjects, streaming_count: usize, - events_receiver: Receiver, - events_sender: Sender, -)->Result<(),Error> { - let response_text = serde_json::to_string(&response_object).unwrap(); + events_out: Arc>>, + events_in: Subscriber, +) -> Result>>, Error> { + let response_text = serde_json::to_string(&response_object)?; ws_sender .write() .await .send(Message::text(response_text)) - .await - ?; + .await?; if let ResponseObjects::One(ResponseObject::Result { jsonrpc: _, result: _, @@ -393,40 +454,47 @@ async fn streaming_payload( }) = response_object { if streaming { - let handle : JoinHandle> = task::spawn(async move { + let handle = task::spawn(async move { let sender = ws_sender.clone(); - let mut sub_head_changes = events_receiver - .filter(|payload| future::ready(payload.sub_head_changes().map(|s|s.0==streaming_count).unwrap_or_default())); - while let Some(events) = sub_head_changes.next().await { - if let EventsPayload::SubHeadChanges(index_to_head_change) = events - { + let mut filter_on_channel_id = events_in.filter(|s| { + future::ready( + s.sub_head_changes() + .map(|s| s.0 == streaming_count) + .unwrap_or_default(), + ) + }); + while let Some(event) = filter_on_channel_id.next().await { + if let EventsPayload::SubHeadChanges(ref index_to_head_change) = event { + if streaming_count == index_to_head_change.0 { let head_change = (&index_to_head_change.1).into(); let data = StreamingData { json_rpc: "2.0", method: "xrpc.ch.val", params: (streaming_count, vec![head_change]), }; - let response_text = - serde_json::to_string(&data)?; + let response_text = serde_json::to_string(&data)?; sender .write() .await .send(Message::text(response_text)) - .await - ?; + .await?; } - }; + } + } - Ok(()) + Ok::<(), Error>(()) }); - handle.await - } - else - { - Ok(()) + + Ok(Some(handle)) + } else { + Ok(None) } } else { - events_sender.send(EventsPayload::TaskCancel(streaming_count,())).await; - Ok(()) + events_out + .write() + .await + .publish(EventsPayload::TaskCancel(streaming_count, ())) + .await; + Ok(None) } } From c40a6b1d067b306fb3aa682ea0c6312788f0d57f Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Mon, 21 Sep 2020 08:04:50 -0400 Subject: [PATCH 28/43] fixed test --- node/rpc/src/sync_api.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/node/rpc/src/sync_api.rs b/node/rpc/src/sync_api.rs index 87e34993efb..ec20adcfe94 100644 --- a/node/rpc/src/sync_api.rs +++ b/node/rpc/src/sync_api.rs @@ -120,7 +120,6 @@ mod tests { let state_manager = Arc::new(StateManager::new(db.clone())); let cs = ChainStore::new(db.clone()); let heaviest_tipset = cs.heaviest_tipset_arc(); - let subscriber = cs.subscribe().await; let state_manager_for_thread = state_manager.clone(); let pool = task::block_on(async move { let bz = hex::decode("904300e80781586082cb7477a801f55c1f2ea5e5d1167661feea60a39f697e1099af132682b81cc5047beacf5b6e80d5f52b9fd90323fb8510a5396416dd076c13c85619e176558582744053a3faef6764829aa02132a1571a76aabdc498a638ea0054d3bb57f41d82015860812d2396cc4592cdf7f829374b01ffd03c5469a4b0a9acc5ccc642797aa0a5498b97b28d90820fedc6f79ff0a6005f5c15dbaca3b8a45720af7ed53000555667207a0ccb50073cd24510995abd4c4e45c1e9e114905018b2da9454190499941e818201582012dd0a6a7d0e222a97926da03adb5a7768d31cc7c5c2bd6828e14a7d25fa3a608182004b76616c69642070726f6f6681d82a5827000171a0e4022030f89a8b0373ad69079dbcbc5addfe9b34dce932189786e50d3eb432ede3ba9c43000f0001d82a5827000171a0e4022052238c7d15c100c1b9ebf849541810c9e3c2d86e826512c6c416d2318fcd496dd82a5827000171a0e40220e5658b3d18cd06e1db9015b4b0ec55c123a24d5be1ea24d83938c5b8397b4f2fd82a5827000171a0e4022018d351341c302a21786b585708c9873565a0d07c42521d4aaf52da3ff6f2e461586102c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a5f2c5439586102b5cd48724dce0fec8799d77fd6c5113276e7f470c8391faa0b5a6033a3eaf357d635705c36abe10309d73592727289680515afd9d424793ba4796b052682d21b03c5c8a37d94827fecc59cdc5750e198fdf20dee012f4d627c6665132298ab95004500053724e0").unwrap(); @@ -151,7 +150,7 @@ mod tests { network_name: TEST_NET_NAME.to_owned(), heaviest_tipset, publisher: Arc::new(RwLock::new(Publisher::new(1000))), - subscriber: subscriber, + events_pubsub: Arc::new(RwLock::new(Publisher::new(1000))) }); (state, network_rx) } From 011bf720ea50c001b3a4f69478cb4c0ad0042fa3 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Mon, 21 Sep 2020 08:17:34 -0400 Subject: [PATCH 29/43] cargo fmt applied --- node/rpc/src/lib.rs | 2 +- node/rpc/src/sync_api.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 4f5e52293d8..fe3ecb6f378 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -32,7 +32,7 @@ use jsonrpc_v2::{ Data, Error, Id, MapRouter, RequestBuilder, RequestObject, ResponseObject, ResponseObjects, Server, V2, }; -use log::{error,debug, info, warn}; +use log::{debug, error, info, warn}; use message_pool::{MessagePool, MpoolRpcProvider}; use serde::Serialize; use state_manager::StateManager; diff --git a/node/rpc/src/sync_api.rs b/node/rpc/src/sync_api.rs index ec20adcfe94..3f1e022cedd 100644 --- a/node/rpc/src/sync_api.rs +++ b/node/rpc/src/sync_api.rs @@ -150,7 +150,7 @@ mod tests { network_name: TEST_NET_NAME.to_owned(), heaviest_tipset, publisher: Arc::new(RwLock::new(Publisher::new(1000))), - events_pubsub: Arc::new(RwLock::new(Publisher::new(1000))) + events_pubsub: Arc::new(RwLock::new(Publisher::new(1000))), }); (state, network_rx) } From 32ac9b34cbf564144d3a222f02fee75c6980c71c Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Mon, 21 Sep 2020 08:45:45 -0400 Subject: [PATCH 30/43] removed invocjsonresult --- blockchain/state_manager/src/lib.rs | 3 +++ node/rpc/src/state_api.rs | 31 ++++++----------------------- vm/message/src/message_receipt.rs | 24 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/blockchain/state_manager/src/lib.rs b/blockchain/state_manager/src/lib.rs index 4e5268ab06d..756563e8cf7 100644 --- a/blockchain/state_manager/src/lib.rs +++ b/blockchain/state_manager/src/lib.rs @@ -31,6 +31,7 @@ use state_tree::StateTree; use std::collections::HashMap; use std::error::Error as StdError; use std::sync::Arc; +use message::{message_receipt,unsigned_message}; /// Intermediary for retrieving state objects and updating actor states pub type CidPair = (Cid, Cid); @@ -39,7 +40,9 @@ pub type CidPair = (Cid, Cid); #[derive(Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct InvocResult { + #[serde(with = "unsigned_message::json")] pub msg: UnsignedMessage, + #[serde(with = "message_receipt::json::opt")] pub msg_rct: Option, pub error: Option, } diff --git a/node/rpc/src/state_api.rs b/node/rpc/src/state_api.rs index 99d41c29a8a..8d32b12f9d2 100644 --- a/node/rpc/src/state_api.rs +++ b/node/rpc/src/state_api.rs @@ -19,7 +19,7 @@ use message::{ message_receipt::json::MessageReceiptJson, unsigned_message::{json::UnsignedMessageJson, UnsignedMessage}, }; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use state_manager::{InvocResult, MarketBalance, StateManager}; use state_tree::StateTree; use wallet::KeyStore; @@ -31,24 +31,6 @@ pub struct MessageLookup { pub tipset: TipsetJson, } -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "PascalCase")] -pub struct InvocResultJson { - pub msg: UnsignedMessageJson, - pub msg_rct: Option, - pub error: Option, -} - -impl From for InvocResultJson { - fn from(invoc: InvocResult) -> Self { - InvocResultJson { - msg: invoc.msg.into(), - msg_rct: invoc.msg_rct.map(|s| s.into()), - error: invoc.error, - } - } -} - /// returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included. /// If the filterOut boolean is set to true, any sectors in the filter are excluded. /// If false, only those sectors in the filter are included. @@ -81,14 +63,13 @@ pub(crate) async fn state_call< >( data: Data>, Params(params): Params<(UnsignedMessageJson, TipsetKeys)>, -) -> Result { +) -> Result { let state_manager = &data.state_manager; let (unsigned_msg_json, key) = params; let mut message: UnsignedMessage = unsigned_msg_json.into(); let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; state_manager .call(&mut message, Some(tipset)) - .map(|s| s.into()) .map_err(|e| e.into()) } @@ -260,16 +241,16 @@ pub(crate) async fn state_replay< >( data: Data>, Params(params): Params<(CidJson, TipsetKeys)>, -) -> Result { +) -> Result { let state_manager = &data.state_manager; let (cidjson, key) = params; let cid = cidjson.into(); let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; let (msg, ret) = state_manager.replay(&tipset, &cid)?; - Ok(InvocResultJson { - msg: msg.into(), - msg_rct: ret.as_ref().map(|s| s.msg_receipt.clone().into()), + Ok(InvocResult { + msg, + msg_rct: ret.as_ref().map(|s| s.msg_receipt.clone()), error: ret .map(|act| act.act_error.map(|e| e.to_string())) .unwrap_or_default(), diff --git a/vm/message/src/message_receipt.rs b/vm/message/src/message_receipt.rs index 9f7d9ecda4f..edd3c1cf000 100644 --- a/vm/message/src/message_receipt.rs +++ b/vm/message/src/message_receipt.rs @@ -108,4 +108,28 @@ pub mod json { deserializer.deserialize_any(GoVecVisitor::::new()) } } + + pub mod opt { + use super::*; + + + pub fn serialize(v: &Option, serializer: S) -> Result + where + S: Serializer, + { + v.as_ref() + .map(|s| MessageReceiptJsonRef(s)) + .serialize(serializer) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let s: Option = Deserialize::deserialize(deserializer)?; + Ok(s) + } + } + + } From b0c36953a64c99d1b3f68094708df58306df1aff Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Mon, 21 Sep 2020 08:53:08 -0400 Subject: [PATCH 31/43] changes to cargo fmt --- blockchain/state_manager/src/lib.rs | 2 +- vm/message/src/message_receipt.rs | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/blockchain/state_manager/src/lib.rs b/blockchain/state_manager/src/lib.rs index 756563e8cf7..28665e9163d 100644 --- a/blockchain/state_manager/src/lib.rs +++ b/blockchain/state_manager/src/lib.rs @@ -24,6 +24,7 @@ use interpreter::{ }; use ipld_amt::Amt; use log::{trace, warn}; +use message::{message_receipt, unsigned_message}; use message::{ChainMessage, Message, MessageReceipt, UnsignedMessage}; use num_bigint::{bigint_ser, BigInt}; use serde::{Deserialize, Serialize}; @@ -31,7 +32,6 @@ use state_tree::StateTree; use std::collections::HashMap; use std::error::Error as StdError; use std::sync::Arc; -use message::{message_receipt,unsigned_message}; /// Intermediary for retrieving state objects and updating actor states pub type CidPair = (Cid, Cid); diff --git a/vm/message/src/message_receipt.rs b/vm/message/src/message_receipt.rs index edd3c1cf000..ff484b23ead 100644 --- a/vm/message/src/message_receipt.rs +++ b/vm/message/src/message_receipt.rs @@ -112,7 +112,6 @@ pub mod json { pub mod opt { use super::*; - pub fn serialize(v: &Option, serializer: S) -> Result where S: Serializer, @@ -130,6 +129,4 @@ pub mod json { Ok(s) } } - - } From 6f1a5cbde217ce417879616995bc11ee578333d6 Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Tue, 22 Sep 2020 14:30:43 -0400 Subject: [PATCH 32/43] Update forest/src/daemon.rs Co-authored-by: Austin Abell --- forest/src/daemon.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index 7f080448f0b..00aba8cbfee 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -70,7 +70,7 @@ pub(super) async fn start(config: Config) { // Initialize mpool let publisher = chain_store.publisher_arc(); - let subscriber = (*publisher.write().await).subscribe(); + let subscriber = publisher.write().await.subscribe(); let provider = MpoolRpcProvider::new(subscriber, Arc::clone(&state_manager)); let mpool = Arc::new( MessagePool::new(provider, network_name.clone()) From e409d7760e85b1706fab406b1b7911640727d055 Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Tue, 22 Sep 2020 14:31:52 -0400 Subject: [PATCH 33/43] Update node/rpc/src/lib.rs Co-authored-by: Austin Abell --- node/rpc/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index fe3ecb6f378..152f8eaa648 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -11,10 +11,8 @@ mod wallet_api; use crate::state_api::*; use async_log::span; use async_std::net::{TcpListener, TcpStream}; -use async_std::sync::Arc; -use async_std::sync::{RwLock, Sender}; -use async_std::task; -use async_std::task::JoinHandle; +use async_std::sync::{RwLock, Sender, Arc}; +use async_std::task::{self,JoinHandle}; use async_tungstenite::{tungstenite::Message, WebSocketStream}; use blocks::Tipset; use blockstore::BlockStore; From ee1297adbf8f006d1bb4b63ee10d364a7449ad1d Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Tue, 22 Sep 2020 14:41:07 -0400 Subject: [PATCH 34/43] Update node/rpc/src/lib.rs Co-authored-by: Austin Abell --- node/rpc/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 152f8eaa648..c959c604a2d 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -259,7 +259,7 @@ where info!("waiting for web socket connections"); while let Ok((stream, addr)) = listener.accept().await { - let subscriber = (*events_pubsub.write().await).subscribe(); + let subscriber = events_pubsub.write().await.subscribe(); task::spawn(handle_connection_and_log( rpc_state.clone(), stream, From d5bb1fc00de452a4883ddb4099b719a5f3540a74 Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Tue, 22 Sep 2020 14:41:19 -0400 Subject: [PATCH 35/43] Update node/rpc/src/lib.rs Co-authored-by: Austin Abell --- node/rpc/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index c959c604a2d..2ae9978b171 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -19,8 +19,7 @@ use blockstore::BlockStore; use chain::headchange_json::{EventsPayload, HeadChangeJson}; use chain::HeadChange; use chain_sync::{BadBlockCache, SyncState}; -use flo_stream::MessagePublisher; -use flo_stream::{Publisher, Subscriber}; +use flo_stream::{MessagePublisher, Publisher, Subscriber}; use forest_libp2p::NetworkMessage; use futures::future; use futures::sink::SinkExt; From fa027b69669923d1fbf8077b296fccf4d5eb4ce2 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Wed, 23 Sep 2020 07:12:52 -0400 Subject: [PATCH 36/43] changes to pr --- blockchain/chain_sync/src/sync.rs | 4 ++-- node/rpc/src/lib.rs | 15 +++++++-------- node/rpc/src/state_api.rs | 6 +++--- vm/address/src/lib.rs | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/blockchain/chain_sync/src/sync.rs b/blockchain/chain_sync/src/sync.rs index 3eeada3ef16..b564673a75a 100644 --- a/blockchain/chain_sync/src/sync.rs +++ b/blockchain/chain_sync/src/sync.rs @@ -269,7 +269,7 @@ where if candidate_ts { // Check message meta after all other checks (expensive) for block in ts.blocks() { - self.validate_msg_meta(block).await?; + self.validate_msg_meta(block)?; } self.set_peer_head(peer, Arc::new(ts.to_tipset())).await; } @@ -346,7 +346,7 @@ where } /// Validates message root from header matches message root generated from the /// bls and secp messages contained in the passed in block and stores them in a key-value store - async fn validate_msg_meta(&self, block: &Block) -> Result<(), Error> { + fn validate_msg_meta(&self, block: &Block) -> Result<(), Error> { let sm_root = compute_msg_meta( self.state_manager.get_block_store_ref(), block.bls_msgs(), diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index fe3ecb6f378..58745889843 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -321,7 +321,7 @@ async fn handle_connection_and_log( .map_err(|e| async move { send_error( 3, - error_send, + &error_send, format!( "channel id {:}, error {:?}", chain_notify_count, @@ -346,9 +346,9 @@ async fn handle_connection_and_log( if let Some(handle) = join_handle { handle .map_err(|e| async move { - send_error( + &send_error( 3, - error_join_send, + &error_join_send, format!( "channel id {:}, error {:?}", chain_notify_count, @@ -389,14 +389,14 @@ async fn handle_connection_and_log( } }); } - Err(e) => send_error(1, ws_sender.clone(), e.to_string()) + Err(e) => send_error(1, &ws_sender, e.to_string()) .await .unwrap_or_else(|e| { error!("error {:?} on socket {:?}", e.message(), addr) }), } } - Err(e) => send_error(2, ws_sender.clone(), e.to_string()) + Err(e) => send_error(2, &ws_sender, e.to_string()) .await .unwrap_or_else(|e| error!("error {:?} on socket {:?}", e.message(), addr)), }; @@ -409,7 +409,7 @@ async fn handle_connection_and_log( async fn send_error( code: i64, - ws_sender: Arc>, + ws_sender: &RwLock, message: String, ) -> Result<(), Error> { let response = ResponseObjects::One(ResponseObject::Error { @@ -451,7 +451,6 @@ async fn streaming_payload( { if streaming { let handle = task::spawn(async move { - let sender = ws_sender.clone(); let mut filter_on_channel_id = events_in.filter(|s| { future::ready( s.sub_head_changes() @@ -469,7 +468,7 @@ async fn streaming_payload( params: (streaming_count, vec![head_change]), }; let response_text = serde_json::to_string(&data)?; - sender + ws_sender .write() .await .send(Message::text(response_text)) diff --git a/node/rpc/src/state_api.rs b/node/rpc/src/state_api.rs index 8d32b12f9d2..bb636fc4fa0 100644 --- a/node/rpc/src/state_api.rs +++ b/node/rpc/src/state_api.rs @@ -6,7 +6,7 @@ use actor::miner::{ compute_proving_period_deadline, ChainSectorInfo, DeadlineInfo, Deadlines, Fault, MinerInfo, SectorOnChainInfo, SectorPreCommitOnChainInfo, State, }; -use address::Address; +use address::{json::AddressJson,Address}; use async_std::task; use bitfield::json::BitFieldJson; use blocks::{tipset_json::TipsetJson, Tipset, TipsetKeys}; @@ -279,14 +279,14 @@ pub(crate) async fn state_account_key< >( data: Data>, Params(params): Params<(Address, TipsetKeys)>, -) -> Result, JsonRpcError> { +) -> Result, JsonRpcError> { let state_manager = &data.state_manager; let (actor, key) = params; let tipset = chain::tipset_from_keys(data.state_manager.get_block_store_ref(), &key)?; let state = state_for_ts(&state_manager, Some(tipset))?; let address = interpreter::resolve_to_key_addr(&state, state_manager.get_block_store_ref(), &actor)?; - Ok(Some(address)) + Ok(Some(address.into())) } /// retrieves the ID address of the given address pub(crate) async fn state_lookup_id< diff --git a/vm/address/src/lib.rs b/vm/address/src/lib.rs index ef991cd1ef2..a6d5be528a3 100644 --- a/vm/address/src/lib.rs +++ b/vm/address/src/lib.rs @@ -322,6 +322,25 @@ pub mod json { use serde::{Deserialize, Deserializer, Serializer}; use std::borrow::Cow; + /// Wrapper for serializing and deserializing a SignedMessage from JSON. + #[derive(Deserialize, Serialize)] + #[serde(transparent)] + pub struct AddressJson(#[serde(with = "self")] pub Address); + + /// Wrapper for serializing a SignedMessage reference to JSON. + #[derive(Serialize)] + #[serde(transparent)] + pub struct AddressJsonRef<'a>(#[serde(with = "self")] pub &'a Address); + + impl From
for AddressJson + { + fn from(address:Address) -> Self + { + Self(address) + } + } + + pub fn serialize(m: &Address, serializer: S) -> Result where S: Serializer, From 263a4be4c1fd9ff31d7a3f55bdce04d471187b9b Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Wed, 23 Sep 2020 07:30:22 -0400 Subject: [PATCH 37/43] changed to arc --- blockchain/chain/src/store/chain_store.rs | 24 +++++++++--------- forest/src/daemon.rs | 7 +++-- node/rpc/src/chain_api.rs | 5 ++-- node/rpc/src/lib.rs | 16 +++++------- node/rpc/src/state_api.rs | 2 +- vm/address/src/lib.rs | 31 ++++++++++------------- 6 files changed, 38 insertions(+), 47 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index b55fd54c166..2dd03810c26 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -53,16 +53,16 @@ pub enum HeadChange { /// This structure is threadsafe, and all caches are wrapped in a mutex to allow a consistent /// `ChainStore` to be shared across tasks. pub struct ChainStore { - publisher: Arc>>, + publisher: RwLock>, // key-value datastore pub db: Arc, // Tipset at the head of the best-known chain. - heaviest: Arc>>>, + heaviest: RwLock>>, // tip_index tracks tipsets by epoch/parentset for use by expected consensus. - tip_index: Arc>, + tip_index: RwLock, } impl ChainStore @@ -76,9 +76,9 @@ where .map(Arc::new); Self { db, - publisher: Arc::new(RwLock::new(Publisher::new(SINK_CAP))), - tip_index: Arc::new(RwLock::new(TipIndex::new())), - heaviest: Arc::new(RwLock::new(heaviest)), + publisher: RwLock::new(Publisher::new(SINK_CAP)), + tip_index: RwLock::new(TipIndex::new()), + heaviest: RwLock::new(heaviest), } } @@ -159,16 +159,16 @@ where self.heaviest.read().await.clone() } - pub fn heaviest_tipset_arc(&self) -> Arc>>> { - self.heaviest.clone() + pub fn heaviest_tipset_arc(&self) -> &RwLock>> { + &self.heaviest } - pub fn tip_index_arc(&self) -> Arc> { - self.tip_index.clone() + pub fn tip_index_arc(&self) -> &RwLock { + &self.tip_index } - pub fn publisher_arc(&self) -> Arc>> { - self.publisher.clone() + pub fn publisher_arc(&self) -> &RwLock> { + &self.publisher } pub fn blockstore_arc(&self) -> Arc { diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index 7f080448f0b..2f440a77b96 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -91,9 +91,9 @@ pub(super) async fn start(config: Config) { .unwrap(); // Initialize ChainSyncer - let heaviest_tipset = chain_store.heaviest_tipset_arc(); + let chain_store_arc = Arc::new(chain_store); let chain_syncer = ChainSyncer::new( - Arc::new(chain_store), + chain_store_arc.clone(), Arc::clone(&state_manager), Arc::new(beacon), network_send.clone(), @@ -125,8 +125,7 @@ pub(super) async fn start(config: Config) { sync_state, network_send, network_name, - heaviest_tipset, - publisher, + chain_store: chain_store_arc, events_pubsub: Arc::new(RwLock::new(Publisher::new(1000))), }, &rpc_listen, diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index 388601b5c2a..162954d0a5b 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -10,7 +10,6 @@ use cid::{json::CidJson, Cid}; use clock::ChainEpoch; use crypto::DomainSeparationTag; -use flo_stream::MessagePublisher; use jsonrpc_v2::{Data, Error as JsonRpcError, Params}; use message::{ signed_message, @@ -65,10 +64,10 @@ where DB: BlockStore + Send + Sync + 'static, KS: KeyStore + Send + Sync + 'static, { - let data_subscribe = data.publisher.write().await.subscribe(); + let data_subscribe = data.chain_store.subscribe().await; let index = chain::headchange_json::sub_head_changes( data_subscribe, - &*data.heaviest_tipset.read().await, + &*data.chain_store.heaviest_tipset_arc().read().await, params, data.events_pubsub.clone(), ) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 58745889843..dab84bf5450 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -16,10 +16,11 @@ use async_std::sync::{RwLock, Sender}; use async_std::task; use async_std::task::JoinHandle; use async_tungstenite::{tungstenite::Message, WebSocketStream}; -use blocks::Tipset; use blockstore::BlockStore; -use chain::headchange_json::{EventsPayload, HeadChangeJson}; -use chain::HeadChange; +use chain::{ + headchange_json::{EventsPayload, HeadChangeJson}, + ChainStore, +}; use chain_sync::{BadBlockCache, SyncState}; use flo_stream::MessagePublisher; use flo_stream::{Publisher, Subscriber}; @@ -56,14 +57,13 @@ where { pub state_manager: Arc>, pub keystore: Arc>, - pub heaviest_tipset: Arc>>>, - pub publisher: Arc>>, pub events_pubsub: Arc>>, pub mpool: Arc>>, pub bad_blocks: Arc, pub sync_state: Arc>>>>, pub network_send: Sender, pub network_name: String, + pub chain_store: Arc>, } pub async fn start_rpc(state: RpcState, rpc_endpoint: &str) @@ -407,11 +407,7 @@ async fn handle_connection_and_log( }) } -async fn send_error( - code: i64, - ws_sender: &RwLock, - message: String, -) -> Result<(), Error> { +async fn send_error(code: i64, ws_sender: &RwLock, message: String) -> Result<(), Error> { let response = ResponseObjects::One(ResponseObject::Error { jsonrpc: V2, error: Error::Full { diff --git a/node/rpc/src/state_api.rs b/node/rpc/src/state_api.rs index bb636fc4fa0..39eedc2a76a 100644 --- a/node/rpc/src/state_api.rs +++ b/node/rpc/src/state_api.rs @@ -6,7 +6,7 @@ use actor::miner::{ compute_proving_period_deadline, ChainSectorInfo, DeadlineInfo, Deadlines, Fault, MinerInfo, SectorOnChainInfo, SectorPreCommitOnChainInfo, State, }; -use address::{json::AddressJson,Address}; +use address::{json::AddressJson, Address}; use async_std::task; use bitfield::json::BitFieldJson; use blocks::{tipset_json::TipsetJson, Tipset, TipsetKeys}; diff --git a/vm/address/src/lib.rs b/vm/address/src/lib.rs index a6d5be528a3..f23f20ef6d5 100644 --- a/vm/address/src/lib.rs +++ b/vm/address/src/lib.rs @@ -322,24 +322,21 @@ pub mod json { use serde::{Deserialize, Deserializer, Serializer}; use std::borrow::Cow; - /// Wrapper for serializing and deserializing a SignedMessage from JSON. - #[derive(Deserialize, Serialize)] - #[serde(transparent)] - pub struct AddressJson(#[serde(with = "self")] pub Address); - - /// Wrapper for serializing a SignedMessage reference to JSON. - #[derive(Serialize)] - #[serde(transparent)] - pub struct AddressJsonRef<'a>(#[serde(with = "self")] pub &'a Address); - - impl From
for AddressJson - { - fn from(address:Address) -> Self - { - Self(address) - } + /// Wrapper for serializing and deserializing a SignedMessage from JSON. + #[derive(Deserialize, Serialize)] + #[serde(transparent)] + pub struct AddressJson(#[serde(with = "self")] pub Address); + + /// Wrapper for serializing a SignedMessage reference to JSON. + #[derive(Serialize)] + #[serde(transparent)] + pub struct AddressJsonRef<'a>(#[serde(with = "self")] pub &'a Address); + + impl From
for AddressJson { + fn from(address: Address) -> Self { + Self(address) } - + } pub fn serialize(m: &Address, serializer: S) -> Result where From 260d37260b15e3da020e4a6f12fc49bdb10956b9 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Wed, 23 Sep 2020 07:51:07 -0400 Subject: [PATCH 38/43] fixed tests --- blockchain/chain/src/store/chain_store.rs | 6 +++--- forest/src/daemon.rs | 2 +- node/rpc/src/chain_api.rs | 2 +- node/rpc/src/lib.rs | 2 +- node/rpc/src/sync_api.rs | 12 ++++++------ 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 2dd03810c26..d807b5264fd 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -159,15 +159,15 @@ where self.heaviest.read().await.clone() } - pub fn heaviest_tipset_arc(&self) -> &RwLock>> { + pub fn heaviest_tipset_rwlock(&self) -> &RwLock>> { &self.heaviest } - pub fn tip_index_arc(&self) -> &RwLock { + pub fn tip_index_rwlock(&self) -> &RwLock { &self.tip_index } - pub fn publisher_arc(&self) -> &RwLock> { + pub fn publisher_rwlock(&self) -> &RwLock> { &self.publisher } diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index 2f440a77b96..7dfe5304f79 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -69,7 +69,7 @@ pub(super) async fn start(config: Config) { let state_manager = Arc::new(StateManager::new(Arc::clone(&db))); // Initialize mpool - let publisher = chain_store.publisher_arc(); + let publisher = chain_store.publisher_rwlock(); let subscriber = (*publisher.write().await).subscribe(); let provider = MpoolRpcProvider::new(subscriber, Arc::clone(&state_manager)); let mpool = Arc::new( diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index 162954d0a5b..da3dbf0c6ae 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -67,7 +67,7 @@ where let data_subscribe = data.chain_store.subscribe().await; let index = chain::headchange_json::sub_head_changes( data_subscribe, - &*data.chain_store.heaviest_tipset_arc().read().await, + &*data.chain_store.heaviest_tipset_rwlock().read().await, params, data.events_pubsub.clone(), ) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index dab84bf5450..04eac343fec 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -346,7 +346,7 @@ async fn handle_connection_and_log( if let Some(handle) = join_handle { handle .map_err(|e| async move { - &send_error( + send_error( 3, &error_join_send, format!( diff --git a/node/rpc/src/sync_api.rs b/node/rpc/src/sync_api.rs index 3f1e022cedd..680d70934ec 100644 --- a/node/rpc/src/sync_api.rs +++ b/node/rpc/src/sync_api.rs @@ -119,16 +119,17 @@ mod tests { let db = Arc::new(MemoryDB::default()); let state_manager = Arc::new(StateManager::new(db.clone())); let cs = ChainStore::new(db.clone()); - let heaviest_tipset = cs.heaviest_tipset_arc(); + let cs_arc = Arc::new(cs); let state_manager_for_thread = state_manager.clone(); + let cs_move = cs_arc.clone(); let pool = task::block_on(async move { let bz = hex::decode("904300e80781586082cb7477a801f55c1f2ea5e5d1167661feea60a39f697e1099af132682b81cc5047beacf5b6e80d5f52b9fd90323fb8510a5396416dd076c13c85619e176558582744053a3faef6764829aa02132a1571a76aabdc498a638ea0054d3bb57f41d82015860812d2396cc4592cdf7f829374b01ffd03c5469a4b0a9acc5ccc642797aa0a5498b97b28d90820fedc6f79ff0a6005f5c15dbaca3b8a45720af7ed53000555667207a0ccb50073cd24510995abd4c4e45c1e9e114905018b2da9454190499941e818201582012dd0a6a7d0e222a97926da03adb5a7768d31cc7c5c2bd6828e14a7d25fa3a608182004b76616c69642070726f6f6681d82a5827000171a0e4022030f89a8b0373ad69079dbcbc5addfe9b34dce932189786e50d3eb432ede3ba9c43000f0001d82a5827000171a0e4022052238c7d15c100c1b9ebf849541810c9e3c2d86e826512c6c416d2318fcd496dd82a5827000171a0e40220e5658b3d18cd06e1db9015b4b0ec55c123a24d5be1ea24d83938c5b8397b4f2fd82a5827000171a0e4022018d351341c302a21786b585708c9873565a0d07c42521d4aaf52da3ff6f2e461586102c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a5f2c5439586102b5cd48724dce0fec8799d77fd6c5113276e7f470c8391faa0b5a6033a3eaf357d635705c36abe10309d73592727289680515afd9d424793ba4796b052682d21b03c5c8a37d94827fecc59cdc5750e198fdf20dee012f4d627c6665132298ab95004500053724e0").unwrap(); let header = BlockHeader::unmarshal_cbor(&bz).unwrap(); let ts = Tipset::new(vec![header]).unwrap(); - let subscriber = cs.subscribe().await; - let db = cs.db.clone(); + let subscriber = cs_move.subscribe().await; + let db = cs_move.db.clone(); let tsk = ts.key().cids.clone(); - cs.set_heaviest_tipset(Arc::new(ts)).await.unwrap(); + cs_move.set_heaviest_tipset(Arc::new(ts)).await.unwrap(); for i in tsk { let bz2 = bz.clone(); @@ -148,9 +149,8 @@ mod tests { sync_state: Arc::new(RwLock::new(vec![Default::default()])), network_send, network_name: TEST_NET_NAME.to_owned(), - heaviest_tipset, - publisher: Arc::new(RwLock::new(Publisher::new(1000))), events_pubsub: Arc::new(RwLock::new(Publisher::new(1000))), + chain_store: cs_arc, }); (state, network_rx) } From 449fd05b00e4c13b33646eae453dd0354ee209e0 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Wed, 23 Sep 2020 07:57:32 -0400 Subject: [PATCH 39/43] cargo fmt --- node/rpc/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 35a3d19e688..1ebac65a693 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -11,8 +11,8 @@ mod wallet_api; use crate::state_api::*; use async_log::span; use async_std::net::{TcpListener, TcpStream}; -use async_std::sync::{RwLock, Sender, Arc}; -use async_std::task::{self,JoinHandle}; +use async_std::sync::{Arc, RwLock, Sender}; +use async_std::task::{self, JoinHandle}; use async_tungstenite::{tungstenite::Message, WebSocketStream}; use blockstore::BlockStore; use chain::{ From c760a9cc30cb204a1fb3dc085257e2bc928efb2a Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Wed, 23 Sep 2020 09:24:58 -0400 Subject: [PATCH 40/43] changed function names --- blockchain/chain/src/store/chain_store.rs | 13 ++----------- forest/src/daemon.rs | 2 +- node/rpc/src/chain_api.rs | 2 +- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index d807b5264fd..d49e10852eb 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -159,22 +159,13 @@ where self.heaviest.read().await.clone() } - pub fn heaviest_tipset_rwlock(&self) -> &RwLock>> { - &self.heaviest - } - - pub fn tip_index_rwlock(&self) -> &RwLock { + pub fn tip_index(&self) -> &RwLock { &self.tip_index } - pub fn publisher_rwlock(&self) -> &RwLock> { + pub fn publisher(&self) -> &RwLock> { &self.publisher } - - pub fn blockstore_arc(&self) -> Arc { - self.db.clone() - } - /// Returns key-value store instance pub fn blockstore(&self) -> &DB { &self.db diff --git a/forest/src/daemon.rs b/forest/src/daemon.rs index ddcb1c46799..e89e7b86c01 100644 --- a/forest/src/daemon.rs +++ b/forest/src/daemon.rs @@ -69,7 +69,7 @@ pub(super) async fn start(config: Config) { let state_manager = Arc::new(StateManager::new(Arc::clone(&db))); // Initialize mpool - let publisher = chain_store.publisher_rwlock(); + let publisher = chain_store.publisher(); let subscriber = publisher.write().await.subscribe(); let provider = MpoolRpcProvider::new(subscriber, Arc::clone(&state_manager)); let mpool = Arc::new( diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index da3dbf0c6ae..4679dd7b63c 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -67,7 +67,7 @@ where let data_subscribe = data.chain_store.subscribe().await; let index = chain::headchange_json::sub_head_changes( data_subscribe, - &*data.chain_store.heaviest_tipset_rwlock().read().await, + &data.chain_store.heaviest_tipset().await, params, data.events_pubsub.clone(), ) From 16fff8b55f8a787c2b7ebe6532aed997a8449a5d Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Thu, 24 Sep 2020 14:40:56 -0700 Subject: [PATCH 41/43] made changes to tests --- blockchain/chain_sync/src/sync.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/blockchain/chain_sync/src/sync.rs b/blockchain/chain_sync/src/sync.rs index d733c119260..6c6fcd2b201 100644 --- a/blockchain/chain_sync/src/sync.rs +++ b/blockchain/chain_sync/src/sync.rs @@ -499,8 +499,7 @@ mod tests { Cid::from_raw_cid("bafy2bzaceasssikoiintnok7f3sgnekfifarzobyr3r4f25sgxmn23q4c35ic") .unwrap(); - let root = - compute_msg_meta(cs.state_manager.get_block_store_ref(), &[bls], &[secp]).unwrap(); + let root = compute_msg_meta(cs.chain_store.blockstore(), &[bls], &[secp]).unwrap(); assert_eq!(root, expected_root); } From 744622d02bb14d943198bcc55be2d7efc1ac0474 Mon Sep 17 00:00:00 2001 From: Purple Hair Rust Bard Date: Fri, 25 Sep 2020 14:56:26 -0700 Subject: [PATCH 42/43] Update blockchain/chain/Cargo.toml Co-authored-by: Austin Abell --- blockchain/chain/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockchain/chain/Cargo.toml b/blockchain/chain/Cargo.toml index 56239dce6b1..816f7807315 100644 --- a/blockchain/chain/Cargo.toml +++ b/blockchain/chain/Cargo.toml @@ -26,7 +26,7 @@ byteorder = "1.3.4" beacon = { path = "../beacon" } flo_stream = "0.4.0" address = { package = "forest_address", path = "../../vm/address" } -futures ="0.3.5" +futures = "0.3.5" async-std = "1.6.3" types = { package = "fil_types", path = "../../types" } lazy_static = "1.4" From fe4fd962210fe0a3e5388a2799d56f9c7e0f9605 Mon Sep 17 00:00:00 2001 From: Ashanti Mutinta Date: Fri, 25 Sep 2020 15:10:57 -0700 Subject: [PATCH 43/43] moved out of json module --- blockchain/chain/src/store/chain_store.rs | 142 +++++++++++----------- node/rpc/src/chain_api.rs | 2 +- node/rpc/src/lib.rs | 5 +- 3 files changed, 73 insertions(+), 76 deletions(-) diff --git a/blockchain/chain/src/store/chain_store.rs b/blockchain/chain/src/store/chain_store.rs index 72607a7507d..b0c3b8efe56 100644 --- a/blockchain/chain/src/store/chain_store.rs +++ b/blockchain/chain/src/store/chain_store.rs @@ -52,6 +52,31 @@ pub enum HeadChange { Revert(Arc), } +#[derive(Debug, Clone)] +pub struct IndexToHeadChange(pub usize, pub HeadChange); + +#[derive(Clone)] +pub enum EventsPayload { + TaskCancel(usize, ()), + SubHeadChanges(IndexToHeadChange), +} + +impl EventsPayload { + pub fn sub_head_changes(&self) -> Option<&IndexToHeadChange> { + match self { + EventsPayload::SubHeadChanges(s) => Some(s), + _ => None, + } + } + + pub fn task_cancel(&self) -> Option<(usize, ())> { + match self { + EventsPayload::TaskCancel(val, _) => Some((*val, ())), + _ => None, + } + } +} + /// Stores chain data such as heaviest tipset and cached tipset info at each epoch. /// This structure is threadsafe, and all caches are wrapped in a mutex to allow a consistent /// `ChainStore` to be shared across tasks. @@ -713,6 +738,52 @@ where Ok(out) } +pub async fn sub_head_changes( + mut subscribed_head_change: Subscriber, + heaviest_tipset: &Option>, + current_index: usize, + events_pubsub: Arc>>, +) -> Result { + let head = heaviest_tipset + .as_ref() + .ok_or_else(|| Error::Other("Could not get heaviest tipset".to_string()))?; + + (*events_pubsub.write().await) + .publish(EventsPayload::SubHeadChanges(IndexToHeadChange( + current_index, + HeadChange::Current(head.clone()), + ))) + .await; + let subhead_sender = events_pubsub.clone(); + let handle = task::spawn(async move { + while let Some(change) = subscribed_head_change.next().await { + let index_to_head_change = IndexToHeadChange(current_index, change); + subhead_sender + .write() + .await + .publish(EventsPayload::SubHeadChanges(index_to_head_change)) + .await; + } + }); + let cancel_sender = events_pubsub.write().await.subscribe(); + task::spawn(async move { + if let Some(EventsPayload::TaskCancel(_, ())) = cancel_sender + .filter(|s| { + future::ready( + s.task_cancel() + .map(|s| s.0 == current_index) + .unwrap_or_default(), + ) + }) + .next() + .await + { + handle.cancel().await; + } + }); + Ok(current_index) +} + #[cfg(feature = "json")] pub mod headchange_json { use super::*; @@ -728,8 +799,6 @@ pub mod headchange_json { Revert(TipsetJsonRef<'a>), } - #[derive(Debug, Clone)] - pub struct IndexToHeadChangeJson(pub usize, pub HeadChange); impl<'a> From<&'a HeadChange> for HeadChangeJson<'a> { fn from(wrapper: &'a HeadChange) -> Self { match wrapper { @@ -739,76 +808,7 @@ pub mod headchange_json { } } } - - #[derive(Clone)] - pub enum EventsPayload { - TaskCancel(usize, ()), - SubHeadChanges(IndexToHeadChangeJson), - } - - impl EventsPayload { - pub fn sub_head_changes(&self) -> Option<&IndexToHeadChangeJson> { - match self { - EventsPayload::SubHeadChanges(s) => Some(s), - _ => None, - } - } - - pub fn task_cancel(&self) -> Option<(usize, ())> { - match self { - EventsPayload::TaskCancel(val, _) => Some((*val, ())), - _ => None, - } - } - } - - pub async fn sub_head_changes( - mut subscribed_head_change: Subscriber, - heaviest_tipset: &Option>, - current_index: usize, - events_pubsub: Arc>>, - ) -> Result { - let head = heaviest_tipset - .as_ref() - .ok_or_else(|| Error::Other("Could not get heaviest tipset".to_string()))?; - - (*events_pubsub.write().await) - .publish(EventsPayload::SubHeadChanges(IndexToHeadChangeJson( - current_index, - HeadChange::Current(head.clone()), - ))) - .await; - let subhead_sender = events_pubsub.clone(); - let handle = task::spawn(async move { - while let Some(change) = subscribed_head_change.next().await { - let index_to_head_change = IndexToHeadChangeJson(current_index, change); - subhead_sender - .write() - .await - .publish(EventsPayload::SubHeadChanges(index_to_head_change)) - .await; - } - }); - let cancel_sender = events_pubsub.write().await.subscribe(); - task::spawn(async move { - if let Some(EventsPayload::TaskCancel(_, ())) = cancel_sender - .filter(|s| { - future::ready( - s.task_cancel() - .map(|s| s.0 == current_index) - .unwrap_or_default(), - ) - }) - .next() - .await - { - handle.cancel().await; - } - }); - Ok(current_index) - } } - #[cfg(test)] mod tests { use super::*; diff --git a/node/rpc/src/chain_api.rs b/node/rpc/src/chain_api.rs index 874b5a9350d..6ccac9183a0 100644 --- a/node/rpc/src/chain_api.rs +++ b/node/rpc/src/chain_api.rs @@ -65,7 +65,7 @@ where KS: KeyStore + Send + Sync + 'static, { let data_subscribe = data.chain_store.subscribe().await; - let index = chain::headchange_json::sub_head_changes( + let index = chain::sub_head_changes( data_subscribe, &data.chain_store.heaviest_tipset().await, params, diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 1ebac65a693..9462d89f461 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -15,10 +15,7 @@ use async_std::sync::{Arc, RwLock, Sender}; use async_std::task::{self, JoinHandle}; use async_tungstenite::{tungstenite::Message, WebSocketStream}; use blockstore::BlockStore; -use chain::{ - headchange_json::{EventsPayload, HeadChangeJson}, - ChainStore, -}; +use chain::{headchange_json::HeadChangeJson, ChainStore, EventsPayload}; use chain_sync::{BadBlockCache, SyncState}; use flo_stream::{MessagePublisher, Publisher, Subscriber}; use forest_libp2p::NetworkMessage;