mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
Merge branch 'master' of https://github.com/darkrenaissance/darkfi
This commit is contained in:
11
Cargo.toml
11
Cargo.toml
@@ -193,6 +193,7 @@ crypto = [
|
||||
"bs58",
|
||||
|
||||
"util",
|
||||
"zkas",
|
||||
]
|
||||
|
||||
wallet = [
|
||||
@@ -223,12 +224,6 @@ zkas = [
|
||||
"util",
|
||||
]
|
||||
|
||||
zkvm = [
|
||||
"crypto",
|
||||
"zkas",
|
||||
]
|
||||
|
||||
|
||||
[[example]]
|
||||
name = "net"
|
||||
path = "example/net.rs"
|
||||
@@ -252,9 +247,9 @@ required-features = ["crypto"]
|
||||
[[example]]
|
||||
name = "mint"
|
||||
path = "proof/mint.rs"
|
||||
required-features = ["cli", "zkvm"]
|
||||
required-features = ["cli", "crypto", "zkas"]
|
||||
|
||||
[[example]]
|
||||
name = "burn"
|
||||
path = "proof/burn.rs"
|
||||
required-features = ["cli", "zkvm"]
|
||||
required-features = ["cli", "crypto", "zkas"]
|
||||
|
||||
16
Makefile
16
Makefile
@@ -37,13 +37,17 @@ test: test-vm test-tx
|
||||
$(CARGO) test --release --all-features --all
|
||||
|
||||
test-tx:
|
||||
$(CARGO) run --release --features=node --example tx
|
||||
$(CARGO) run --release --features=node,zkas --example tx
|
||||
|
||||
test-vm: zkas
|
||||
./zkas proof/mint.zk
|
||||
$(CARGO) run --release --features=cli,zkvm --example mint
|
||||
./zkas proof/burn.zk
|
||||
$(CARGO) run --release --features=cli,zkvm --example burn
|
||||
VM_SRC = proof/mint.zk proof/burn.zk
|
||||
VM_BIN = $(VM_SRC:=.bin)
|
||||
|
||||
$(VM_BIN): zkas $(VM_SRC)
|
||||
./zkas $(basename $@) -o $@
|
||||
|
||||
test-vm: $(VM_BIN)
|
||||
$(CARGO) run --release --features=cli,crypto,zkas --example mint
|
||||
$(CARGO) run --release --features=cli,crypto,zkas --example burn
|
||||
|
||||
clean:
|
||||
rm -f $(BINS)
|
||||
|
||||
@@ -98,25 +98,6 @@ async fn process_user_input(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn channel_loop(
|
||||
p2p: net::P2pPtr,
|
||||
sender: async_channel::Sender<Arc<PrivMsg>>,
|
||||
seen_privmsg_ids: SeenPrivMsgIdsPtr,
|
||||
executor: Arc<Executor<'_>>,
|
||||
) -> Result<()> {
|
||||
let new_channel_sub = p2p.subscribe_channel().await;
|
||||
|
||||
loop {
|
||||
let channel = new_channel_sub.receive().await?;
|
||||
|
||||
let protocol_privmsg =
|
||||
ProtocolPrivMsg::new(channel, sender.clone(), seen_privmsg_ids.clone(), p2p.clone())
|
||||
.await;
|
||||
|
||||
protocol_privmsg.start(executor.clone()).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn start(executor: Arc<Executor<'_>>, options: ProgramOptions) -> Result<()> {
|
||||
let listener = match Async::<TcpListener>::bind(options.irc_accept_addr) {
|
||||
Ok(listener) => listener,
|
||||
@@ -145,7 +126,28 @@ async fn start(executor: Arc<Executor<'_>>, options: ProgramOptions) -> Result<(
|
||||
|
||||
let seen_privmsg_ids = SeenPrivMsgIds::new();
|
||||
|
||||
let p2p = net::P2p::new(options.network_settings);
|
||||
//
|
||||
// PrivMsg protocol
|
||||
//
|
||||
let p2p = net::P2p::new(options.network_settings).await;
|
||||
let registry = p2p.protocol_registry();
|
||||
|
||||
let (sender, recvr) = async_channel::unbounded();
|
||||
let seen_privmsg_ids2 = seen_privmsg_ids.clone();
|
||||
let sender2 = sender.clone();
|
||||
registry.register(
|
||||
!net::SESSION_SEED,
|
||||
move |channel, p2p| {
|
||||
let sender = sender2.clone();
|
||||
let seen_privmsg_ids = seen_privmsg_ids2.clone();
|
||||
async move {
|
||||
ProtocolPrivMsg::new(channel, sender, seen_privmsg_ids, p2p).await
|
||||
}
|
||||
}).await;
|
||||
|
||||
//
|
||||
// p2p network main instance
|
||||
//
|
||||
// Performs seed session
|
||||
p2p.clone().start(executor.clone()).await?;
|
||||
// Actual main p2p session
|
||||
@@ -159,13 +161,9 @@ async fn start(executor: Arc<Executor<'_>>, options: ProgramOptions) -> Result<(
|
||||
})
|
||||
.detach();
|
||||
|
||||
let (sender, recvr) = async_channel::unbounded();
|
||||
// for now the p2p and channel sub sessions just run forever
|
||||
// so detach them as background processes.
|
||||
executor
|
||||
.spawn(channel_loop(p2p.clone(), sender, seen_privmsg_ids.clone(), executor.clone()))
|
||||
.detach();
|
||||
|
||||
//
|
||||
// RPC interface
|
||||
//
|
||||
let ex2 = executor.clone();
|
||||
let ex3 = ex2.clone();
|
||||
let rpc_interface = Arc::new(JsonRpcInterface {});
|
||||
@@ -173,6 +171,9 @@ async fn start(executor: Arc<Executor<'_>>, options: ProgramOptions) -> Result<(
|
||||
.spawn(async move { listen_and_serve(server_config, rpc_interface, ex3).await })
|
||||
.detach();
|
||||
|
||||
//
|
||||
// IRC instance
|
||||
//
|
||||
loop {
|
||||
let (stream, peer_addr) = match listener.accept().await {
|
||||
Ok((s, a)) => (s, a),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use async_trait::async_trait;
|
||||
use async_executor::Executor;
|
||||
|
||||
use darkfi::{net, Result};
|
||||
@@ -20,12 +21,10 @@ impl ProtocolPrivMsg {
|
||||
notify_queue_sender: async_channel::Sender<Arc<PrivMsg>>,
|
||||
seen_privmsg_ids: SeenPrivMsgIdsPtr,
|
||||
p2p: net::P2pPtr,
|
||||
) -> Arc<Self> {
|
||||
) -> net::ProtocolBasePtr {
|
||||
let message_subsytem = channel.get_message_subsystem();
|
||||
message_subsytem.add_dispatch::<PrivMsg>().await;
|
||||
|
||||
debug!("ADDED DISPATCH");
|
||||
|
||||
let privmsg_sub =
|
||||
channel.subscribe_msg::<PrivMsg>().await.expect("Missing PrivMsg dispatcher!");
|
||||
|
||||
@@ -38,15 +37,8 @@ impl ProtocolPrivMsg {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
|
||||
debug!(target: "ircd", "ProtocolPrivMsg::start() [START]");
|
||||
self.jobsman.clone().start(executor.clone());
|
||||
self.jobsman.clone().spawn(self.clone().handle_receive_privmsg(), executor.clone()).await;
|
||||
debug!(target: "ircd", "ProtocolPrivMsg::start() [END]");
|
||||
}
|
||||
|
||||
async fn handle_receive_privmsg(self: Arc<Self>) -> Result<()> {
|
||||
debug!(target: "ircd", "ProtocolAddress::handle_receive_privmsg() [START]");
|
||||
debug!(target: "ircd", "ProtocolPrivMsg::handle_receive_privmsg() [START]");
|
||||
loop {
|
||||
let privmsg = self.privmsg_sub.receive().await?;
|
||||
|
||||
@@ -71,3 +63,21 @@ impl ProtocolPrivMsg {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl net::ProtocolBase for ProtocolPrivMsg {
|
||||
/// Starts ping-pong keep-alive messages exchange. Runs ping-pong in the
|
||||
/// protocol task manager, then queues the reply. Sends out a ping and
|
||||
/// waits for pong reply. Waits for ping and replies with a pong.
|
||||
async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
|
||||
debug!(target: "ircd", "ProtocolPrivMsg::start() [START]");
|
||||
self.jobsman.clone().start(executor.clone());
|
||||
self.jobsman.clone().spawn(self.clone().handle_receive_privmsg(), executor.clone()).await;
|
||||
debug!(target: "ircd", "ProtocolPrivMsg::start() [END]");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"ProtocolPrivMsg"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
use crate::{
|
||||
list::NodeIdList,
|
||||
node_info::{NodeInfo, NodeInfoView},
|
||||
};
|
||||
//use smol::Timer;
|
||||
//use std::{collections::HashMap, time::Duration};
|
||||
|
||||
// make a structure to be able to modify and read them
|
||||
// protect using a mutex
|
||||
// arc reference
|
||||
#[derive(Clone)]
|
||||
pub struct App {
|
||||
pub node_list: NodeIdList,
|
||||
pub node_info: NodeInfoView,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new() -> App {
|
||||
// append to vector of node info
|
||||
let infos = vec![
|
||||
NodeInfo {
|
||||
id: "0385048034sodisofjhosd1111q3434".to_string(),
|
||||
connections: 10,
|
||||
is_active: true,
|
||||
last_message: "hey how are you?".to_string(),
|
||||
},
|
||||
NodeInfo {
|
||||
id: "09w30we9wsnfksdfkdjflsjkdfjdfsd".to_string(),
|
||||
connections: 5,
|
||||
is_active: false,
|
||||
last_message: "lmao".to_string(),
|
||||
},
|
||||
NodeInfo {
|
||||
id: "038043325alsdlasjfrsdfsdfsdjsdf".to_string(),
|
||||
connections: 7,
|
||||
is_active: true,
|
||||
last_message: "gm".to_string(),
|
||||
},
|
||||
NodeInfo {
|
||||
id: "04985034953ldflsdjflsdjflsdjfii".to_string(),
|
||||
connections: 2,
|
||||
is_active: true,
|
||||
last_message: "hihi".to_string(),
|
||||
},
|
||||
NodeInfo {
|
||||
id: "09850249352asdjapsdikalskasdkas".to_string(),
|
||||
connections: 10,
|
||||
is_active: true,
|
||||
last_message: "wtf".to_string(),
|
||||
},
|
||||
];
|
||||
|
||||
let node_info = NodeInfoView::new(infos.clone());
|
||||
|
||||
let ids = vec![
|
||||
infos[0].id.clone(),
|
||||
infos[1].id.clone(),
|
||||
infos[2].id.clone(),
|
||||
infos[3].id.clone(),
|
||||
infos[4].id.clone(),
|
||||
];
|
||||
|
||||
let node_list = NodeIdList::new(ids);
|
||||
App { node_list, node_info }
|
||||
}
|
||||
|
||||
// TODO: implement this
|
||||
//async fn sleep(self, dur: Duration) {
|
||||
// Timer::after(dur).await;
|
||||
//}
|
||||
|
||||
pub async fn update(self, node_vec: Vec<NodeInfo>) -> App {
|
||||
let node_info = NodeInfoView::new(node_vec.clone());
|
||||
|
||||
let ids = vec![node_vec[0].id.clone(), node_vec[1].id.clone(), node_vec[2].id.clone()];
|
||||
|
||||
let node_list = NodeIdList::new(ids);
|
||||
App { node_list, node_info }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for App {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
pub mod app;
|
||||
pub mod list;
|
||||
pub mod node_info;
|
||||
pub mod types;
|
||||
pub mod model;
|
||||
pub mod ui;
|
||||
pub mod view;
|
||||
|
||||
pub use app::App;
|
||||
pub use model::{IdList, InfoList, Model, NodeInfo};
|
||||
pub use ui::ui;
|
||||
pub use view::{IdListView, InfoListView, View};
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
//use std::collections::HashMap;
|
||||
use tui::widgets::ListState;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NodeIdList {
|
||||
pub state: ListState,
|
||||
pub node_id: Vec<String>,
|
||||
}
|
||||
|
||||
impl NodeIdList {
|
||||
pub fn new(node_id: Vec<String>) -> NodeIdList {
|
||||
NodeIdList { state: ListState::default(), node_id }
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
let i = match self.state.selected() {
|
||||
Some(i) => {
|
||||
if i >= self.node_id.len() - 1 {
|
||||
0
|
||||
} else {
|
||||
i + 1
|
||||
}
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
self.state.select(Some(i));
|
||||
}
|
||||
|
||||
pub fn previous(&mut self) {
|
||||
let i = match self.state.selected() {
|
||||
Some(i) => {
|
||||
if i == 0 {
|
||||
self.node_id.len() - 1
|
||||
} else {
|
||||
i - 1
|
||||
}
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
self.state.select(Some(i));
|
||||
}
|
||||
|
||||
pub fn unselect(&mut self) {
|
||||
self.state.select(None);
|
||||
}
|
||||
}
|
||||
|
||||
//pub async fn add_seen(&self, id: u32) {
|
||||
// self.privmsg_ids.lock().await.insert(id);
|
||||
//}
|
||||
@@ -1,14 +1,10 @@
|
||||
// select each connection and show log of traffic
|
||||
// use rpc to get some info from the ircd network
|
||||
// ircd::logger keeps track of network info
|
||||
// map rpc polls logger for info about nodes, etc
|
||||
use darkfi::{
|
||||
error::{Error, Result},
|
||||
rpc::{jsonrpc, jsonrpc::JsonResult},
|
||||
util::async_util,
|
||||
};
|
||||
|
||||
use async_std::sync::Arc;
|
||||
use async_std::sync::{Arc, Mutex};
|
||||
use easy_parallel::Parallel;
|
||||
use log::debug;
|
||||
use serde_json::{json, Value};
|
||||
@@ -20,7 +16,12 @@ use tui::{
|
||||
Terminal,
|
||||
};
|
||||
|
||||
use map::{node_info::NodeInfo, ui, App};
|
||||
use map::{
|
||||
model::{IdList, InfoList, NodeInfo},
|
||||
ui,
|
||||
view::{IdListView, InfoListView},
|
||||
Model, View,
|
||||
};
|
||||
|
||||
struct Map {
|
||||
url: String,
|
||||
@@ -78,7 +79,53 @@ async fn main() -> Result<()> {
|
||||
|
||||
terminal.clear()?;
|
||||
|
||||
let app = App::new();
|
||||
let infos = vec![
|
||||
NodeInfo {
|
||||
id: "0385048034sodisofjhosd1111q3434".to_string(),
|
||||
connections: 10,
|
||||
is_active: true,
|
||||
last_message: "hey how are you?".to_string(),
|
||||
},
|
||||
NodeInfo {
|
||||
id: "09w30we9wsnfksdfkdjflsjkdfjdfsd".to_string(),
|
||||
connections: 5,
|
||||
is_active: false,
|
||||
last_message: "lmao".to_string(),
|
||||
},
|
||||
NodeInfo {
|
||||
id: "038043325alsdlasjfrsdfsdfsdjsdf".to_string(),
|
||||
connections: 7,
|
||||
is_active: true,
|
||||
last_message: "gm".to_string(),
|
||||
},
|
||||
NodeInfo {
|
||||
id: "04985034953ldflsdjflsdjflsdjfii".to_string(),
|
||||
connections: 2,
|
||||
is_active: true,
|
||||
last_message: "hihi".to_string(),
|
||||
},
|
||||
NodeInfo {
|
||||
id: "09850249352asdjapsdikalskasdkas".to_string(),
|
||||
connections: 10,
|
||||
is_active: true,
|
||||
last_message: "wtf".to_string(),
|
||||
},
|
||||
];
|
||||
|
||||
let info_list = InfoList::new(infos.clone());
|
||||
|
||||
let ids = vec![
|
||||
infos[0].id.clone(),
|
||||
infos[1].id.clone(),
|
||||
infos[2].id.clone(),
|
||||
infos[3].id.clone(),
|
||||
infos[4].id.clone(),
|
||||
];
|
||||
|
||||
let id_list = IdList::new(ids);
|
||||
|
||||
let model = Arc::new(Model::new(id_list, info_list));
|
||||
//let model = Model::new(id_list, info_list);
|
||||
|
||||
let nthreads = num_cpus::get();
|
||||
let (signal, shutdown) = async_channel::unbounded::<()>();
|
||||
@@ -91,8 +138,8 @@ async fn main() -> Result<()> {
|
||||
// Run the main future on the current thread.
|
||||
.finish(|| {
|
||||
smol::future::block_on(async move {
|
||||
start(ex2.clone(), app.clone()).await?;
|
||||
run_app(&mut terminal, app).await?;
|
||||
run_rpc(ex2.clone(), model.clone()).await?;
|
||||
render(&mut terminal, model.clone()).await?;
|
||||
drop(signal);
|
||||
Ok::<(), darkfi::Error>(())
|
||||
})
|
||||
@@ -101,98 +148,86 @@ async fn main() -> Result<()> {
|
||||
result
|
||||
}
|
||||
|
||||
async fn start(ex: Arc<Executor<'_>>, app: App) -> Result<()> {
|
||||
async fn run_rpc(ex: Arc<Executor<'_>>, model: Arc<Model>) -> Result<()> {
|
||||
let client = Map::new("tcp://127.0.0.1:8000".to_string());
|
||||
|
||||
ex.spawn(async {
|
||||
let _ = poll(client, app).await;
|
||||
})
|
||||
.detach();
|
||||
ex.spawn(poll(client, model)).detach();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn poll(client: Map, app: App) -> Result<()> {
|
||||
async fn poll(client: Map, _model: Arc<Model>) -> Result<()> {
|
||||
loop {
|
||||
let reply = client.get_info().await?;
|
||||
update(app.clone(), reply).await?;
|
||||
|
||||
if reply.as_object().is_some() && !reply.as_object().unwrap().is_empty() {
|
||||
let nodes = reply.as_object().unwrap().get("nodes").unwrap();
|
||||
|
||||
let node1 = &nodes[0];
|
||||
let node2 = &nodes[1];
|
||||
let node3 = &nodes[2];
|
||||
|
||||
let _infos = vec![NodeInfo {
|
||||
id: node1["id"].to_string(),
|
||||
connections: node1["connections"].as_u64().unwrap() as usize,
|
||||
is_active: node2["is_active"].as_bool().unwrap(),
|
||||
last_message: node3["message"].to_string(),
|
||||
}];
|
||||
|
||||
//model.lock().await.update(infos).await;
|
||||
} else {
|
||||
// TODO: error handling
|
||||
println!("Reply is an error");
|
||||
}
|
||||
|
||||
async_util::sleep(1).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(app: App, reply: Value) -> Result<()> {
|
||||
if reply.as_object().is_some() && !reply.as_object().unwrap().is_empty() {
|
||||
//let args = params.as_array();
|
||||
let nodes = reply.as_object().unwrap().get("nodes").unwrap();
|
||||
|
||||
let node1 = &nodes[0];
|
||||
let node2 = &nodes[1];
|
||||
let _node3 = &nodes[2];
|
||||
|
||||
let infos = vec![
|
||||
NodeInfo {
|
||||
id: node1["id"].to_string(),
|
||||
connections: node1["connections"].as_u64().unwrap() as usize,
|
||||
is_active: node2["is_active"].as_bool().unwrap(),
|
||||
last_message: "message".to_string(),
|
||||
},
|
||||
//NodeInfo {
|
||||
// id: node2["id"].to_string(),
|
||||
// connections: node2["connections"].as_u64().unwrap() as usize,
|
||||
// is_active: node2["is_active"].as_bool().unwrap(),
|
||||
// last_message: node2["message"].to_string(),
|
||||
//},
|
||||
//NodeInfo {
|
||||
// id: node3["id"].to_string(),
|
||||
// connections: node3["connections"].as_u64().unwrap() as usize,
|
||||
// is_active: node3["is_active"].as_bool().unwrap(),
|
||||
// last_message: node3["message"].to_string(),
|
||||
//},
|
||||
];
|
||||
|
||||
//app.node_info(
|
||||
//let node_info = NodeInfoView::new(infos.clone());
|
||||
|
||||
//let ids = vec![node1["id"].to_string(), node2["id"].to_string(), node3["id"].to_string()];
|
||||
|
||||
// mutex
|
||||
app.update(infos).await;
|
||||
//let node_list = NodeIdList::new(ids);
|
||||
//println!("{}", test);
|
||||
// do something
|
||||
} else {
|
||||
// TODO: error handling
|
||||
println!("Reply is an error");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {
|
||||
async fn render<B: Backend>(terminal: &mut Terminal<B>, model: Arc<Model>) -> io::Result<()> {
|
||||
let mut asi = async_stdin();
|
||||
|
||||
terminal.clear()?;
|
||||
|
||||
app.node_list.state.select(Some(0));
|
||||
let mut info_vec = Vec::new();
|
||||
|
||||
app.node_info.index = 0;
|
||||
for info in model.info_list.infos.lock().await.clone() {
|
||||
info_vec.push(info)
|
||||
}
|
||||
|
||||
let mut id_vec = Vec::new();
|
||||
|
||||
for id in model.id_list.node_id.lock().await.clone() {
|
||||
id_vec.push(id)
|
||||
}
|
||||
|
||||
let id_list = IdListView::new(id_vec);
|
||||
|
||||
let info_list = InfoListView::new(info_vec);
|
||||
|
||||
let mut view = View::new(id_list, info_list);
|
||||
|
||||
view.id_list.state.select(Some(0));
|
||||
|
||||
view.info_list.index = 0;
|
||||
|
||||
loop {
|
||||
terminal.draw(|f| ui::ui(f, &mut app))?;
|
||||
|
||||
terminal.draw(|f| {
|
||||
ui::ui(f, view.clone());
|
||||
})?;
|
||||
for k in asi.by_ref().keys() {
|
||||
match k.unwrap() {
|
||||
Key::Char('q') => {
|
||||
terminal.clear()?;
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
Key::Char('j') => {
|
||||
app.node_list.next();
|
||||
app.node_info.next();
|
||||
view.id_list.next();
|
||||
view.info_list.next().await;
|
||||
}
|
||||
Key::Char('k') => {
|
||||
app.node_list.previous();
|
||||
app.node_info.previous();
|
||||
view.id_list.previous();
|
||||
view.info_list.previous().await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
81
bin/map/src/model.rs
Normal file
81
bin/map/src/model.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
use async_std::sync::Mutex;
|
||||
use tui::widgets::ListState;
|
||||
|
||||
pub struct Model {
|
||||
pub id_list: IdList,
|
||||
pub info_list: InfoList,
|
||||
}
|
||||
|
||||
impl Model {
|
||||
pub fn new(id_list: IdList, info_list: InfoList) -> Model {
|
||||
Model { id_list, info_list }
|
||||
}
|
||||
|
||||
pub async fn update(self, node_vec: Vec<NodeInfo>) -> Model {
|
||||
let ids = vec![node_vec[0].id.clone()];
|
||||
|
||||
for id in ids {
|
||||
self.id_list.node_id.lock().await.push(id);
|
||||
}
|
||||
|
||||
let id_list = self.id_list;
|
||||
|
||||
for info in node_vec {
|
||||
self.info_list.infos.lock().await.push(info);
|
||||
}
|
||||
let info_list = self.info_list;
|
||||
|
||||
Model { id_list, info_list }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IdList {
|
||||
pub state: Mutex<ListState>,
|
||||
pub node_id: Mutex<Vec<String>>,
|
||||
}
|
||||
|
||||
impl IdList {
|
||||
pub fn new(node_id: Vec<String>) -> IdList {
|
||||
let node_id = Mutex::new(node_id);
|
||||
IdList { state: Mutex::new(ListState::default()), node_id }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InfoList {
|
||||
pub index: Mutex<usize>,
|
||||
pub infos: Mutex<Vec<NodeInfo>>,
|
||||
}
|
||||
|
||||
impl InfoList {
|
||||
pub fn new(infos: Vec<NodeInfo>) -> InfoList {
|
||||
let index = 0;
|
||||
let index = Mutex::new(index);
|
||||
let infos = Mutex::new(infos);
|
||||
|
||||
InfoList { index, infos }
|
||||
}
|
||||
}
|
||||
|
||||
pub type NodeId = u32;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NodeInfo {
|
||||
pub id: String,
|
||||
pub connections: usize,
|
||||
pub is_active: bool,
|
||||
pub last_message: String,
|
||||
}
|
||||
|
||||
impl NodeInfo {
|
||||
pub fn new() -> NodeInfo {
|
||||
let connections = 0;
|
||||
let is_active = false;
|
||||
NodeInfo { id: String::new(), connections, is_active, last_message: String::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NodeInfo {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#[derive(Clone)]
|
||||
pub struct NodeInfoView {
|
||||
pub index: usize,
|
||||
pub infos: Vec<NodeInfo>,
|
||||
}
|
||||
|
||||
impl NodeInfoView {
|
||||
pub fn new(infos: Vec<NodeInfo>) -> NodeInfoView {
|
||||
let index = 0;
|
||||
|
||||
NodeInfoView { index, infos }
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
self.index = (self.index + 1) % self.infos.len();
|
||||
}
|
||||
|
||||
pub fn previous(&mut self) {
|
||||
if self.index > 0 {
|
||||
self.index -= 1;
|
||||
} else {
|
||||
self.index = self.infos.len() - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NodeInfo {
|
||||
pub id: String,
|
||||
pub connections: usize,
|
||||
pub is_active: bool,
|
||||
pub last_message: String,
|
||||
}
|
||||
|
||||
impl NodeInfo {
|
||||
pub fn new() -> NodeInfo {
|
||||
let connections = 0;
|
||||
let is_active = false;
|
||||
NodeInfo { id: String::new(), connections, is_active, last_message: String::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NodeInfo {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
//pub async fn add_seen(&self, id: u32) {
|
||||
// self.privmsg_ids.lock().await.insert(id);
|
||||
//}
|
||||
@@ -1,56 +0,0 @@
|
||||
use crate::{
|
||||
info::{NodeId, NodeInfo},
|
||||
ui::render_selected,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use tui::widgets::ListState;
|
||||
|
||||
// TODO: make this just a list
|
||||
// hashmaps are owned by App
|
||||
#[derive(Clone)]
|
||||
pub struct StatefulList {
|
||||
pub state: ListState,
|
||||
pub nodes: NodeId,
|
||||
//pub nodes: HashMap<NodeId, NodeInfo>,
|
||||
//pub node_info: NodeInfo,
|
||||
//pub index: HashMap<usize, NodeInfo>,
|
||||
//pub node_info: InfoScreen,
|
||||
}
|
||||
|
||||
impl StatefulList {
|
||||
pub fn new(nodes: NodeId) -> StatefulList {
|
||||
StatefulList { state: ListState::default(), nodes }
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
let i = match self.state.selected() {
|
||||
Some(i) => {
|
||||
if i >= self.nodes.id.len() - 1 {
|
||||
0
|
||||
} else {
|
||||
i + 1
|
||||
}
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
self.state.select(Some(i));
|
||||
}
|
||||
|
||||
pub fn previous(&mut self) {
|
||||
let i = match self.state.selected() {
|
||||
Some(i) => {
|
||||
if i == 0 {
|
||||
self.nodes.id.len() - 1
|
||||
} else {
|
||||
i - 1
|
||||
}
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
self.state.select(Some(i));
|
||||
}
|
||||
|
||||
pub fn unselect(&mut self) {
|
||||
self.state.select(None);
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
//pub type NodeId = String;
|
||||
//pub type NodeInfo = String;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::app::App;
|
||||
use crate::view::View;
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
@@ -8,15 +8,15 @@ use tui::{
|
||||
Frame,
|
||||
};
|
||||
|
||||
pub fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {
|
||||
pub fn ui<B: Backend>(f: &mut Frame<'_, B>, mut view: View) {
|
||||
let slice = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.margin(2)
|
||||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
||||
.split(f.size());
|
||||
|
||||
let nodes: Vec<ListItem> = app
|
||||
.node_list
|
||||
let nodes: Vec<ListItem> = view
|
||||
.id_list
|
||||
.node_id
|
||||
.iter()
|
||||
.map(|id| {
|
||||
@@ -29,18 +29,19 @@ pub fn ui<B: Backend>(f: &mut Frame<B>, app: &mut App) {
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.highlight_style(Style::default().fg(Color::LightCyan).add_modifier(Modifier::BOLD));
|
||||
|
||||
f.render_stateful_widget(nodes, slice[0], &mut app.node_list.state);
|
||||
f.render_stateful_widget(nodes, slice[0], &mut view.id_list.state);
|
||||
|
||||
let index = app.node_info.index;
|
||||
let index = view.info_list.index;
|
||||
|
||||
render_info(app, f, index, slice);
|
||||
render_info(view, f, index, slice);
|
||||
}
|
||||
|
||||
fn render_info<B: Backend>(app: &mut App, f: &mut Frame<B>, index: usize, slice: Vec<Rect>) {
|
||||
let id = &app.node_info.infos[index].id;
|
||||
let connections = app.node_info.infos[index].connections;
|
||||
let is_active = app.node_info.infos[index].is_active;
|
||||
let message = &app.node_info.infos[index].last_message;
|
||||
fn render_info<B: Backend>(view: View, f: &mut Frame<'_, B>, index: usize, slice: Vec<Rect>) {
|
||||
let info = &view.info_list.infos;
|
||||
let id = &info[index].id;
|
||||
let connections = info[index].connections;
|
||||
let is_active = info[index].is_active;
|
||||
let message = &info[index].last_message;
|
||||
let span = vec.
|
||||
[sollet](https://www.sollet.io).
|
||||
|
||||
Follow [this tutorial](https://docs.solana.com/cli) for the Solana
|
||||
command-line. For sollet.io, switch the network to testnet and click
|
||||
|
||||
@@ -15,16 +15,22 @@ use halo2_gadgets::primitives::{
|
||||
poseidon::{ConstantLength, P128Pow5T3},
|
||||
};
|
||||
use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
|
||||
use log::info;
|
||||
use pasta_curves::{
|
||||
arithmetic::{CurveAffine, Field},
|
||||
group::Curve,
|
||||
pallas,
|
||||
};
|
||||
use rand::rngs::OsRng;
|
||||
use simplelog::{ColorChoice::Auto, Config, LevelFilter::Debug, TermLogger, TerminalMode::Mixed};
|
||||
use simplelog::{ColorChoice::Auto, Config, LevelFilter, TermLogger, TerminalMode::Mixed};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
TermLogger::init(Debug, Config::default(), Mixed, Auto)?;
|
||||
let loglevel = match option_env!("RUST_LOG") {
|
||||
Some("debug") => LevelFilter::Debug,
|
||||
Some("trace") => LevelFilter::Trace,
|
||||
Some(_) | None => LevelFilter::Info,
|
||||
};
|
||||
TermLogger::init(loglevel, Config::default(), Mixed, Auto)?;
|
||||
|
||||
/* ANCHOR: main */
|
||||
let bincode = include_bytes!("burn.zk.bin");
|
||||
@@ -114,7 +120,7 @@ fn main() -> Result<()> {
|
||||
// Create the circuit
|
||||
let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
|
||||
|
||||
// Build the proving key and create the zero-knowledge proof
|
||||
info!(target: "PROVER", "Building proving key and creating the zero-knowledge proof");
|
||||
let proving_key = ProvingKey::build(11, &circuit);
|
||||
let proof = Proof::create(&proving_key, &[circuit], &public_inputs)?;
|
||||
|
||||
@@ -139,7 +145,7 @@ fn main() -> Result<()> {
|
||||
// Create the circuit
|
||||
let circuit = ZkCircuit::new(verifier_witnesses, zkbin);
|
||||
|
||||
// Build the verifying key and verify the zero-knowledge proof
|
||||
info!(target: "VERIFIER", "Building verifying key and verifying the zero-knowledge proof");
|
||||
let verifying_key = VerifyingKey::build(11, &circuit);
|
||||
proof.verify(&verifying_key, &public_inputs)?;
|
||||
/* ANCHOR_END: main */
|
||||
|
||||
@@ -13,16 +13,22 @@ use halo2_gadgets::primitives::{
|
||||
poseidon,
|
||||
poseidon::{ConstantLength, P128Pow5T3},
|
||||
};
|
||||
use log::info;
|
||||
use pasta_curves::{
|
||||
arithmetic::{CurveAffine, Field},
|
||||
group::Curve,
|
||||
pallas,
|
||||
};
|
||||
use rand::rngs::OsRng;
|
||||
use simplelog::{ColorChoice::Auto, Config, LevelFilter::Debug, TermLogger, TerminalMode::Mixed};
|
||||
use simplelog::{ColorChoice::Auto, Config, LevelFilter, TermLogger, TerminalMode::Mixed};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
TermLogger::init(Debug, Config::default(), Mixed, Auto)?;
|
||||
let loglevel = match option_env!("RUST_LOG") {
|
||||
Some("debug") => LevelFilter::Debug,
|
||||
Some("trace") => LevelFilter::Trace,
|
||||
Some(_) | None => LevelFilter::Info,
|
||||
};
|
||||
TermLogger::init(loglevel, Config::default(), Mixed, Auto)?;
|
||||
|
||||
/* ANCHOR: main */
|
||||
let bincode = include_bytes!("mint.zk.bin");
|
||||
@@ -69,7 +75,7 @@ fn main() -> Result<()> {
|
||||
// Create the circuit
|
||||
let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
|
||||
|
||||
// Build the proving key and create the zero-knowledge proof
|
||||
info!(target: "PROVER", "Building proving key and creating the zero-knowledge proof");
|
||||
let proving_key = ProvingKey::build(11, &circuit);
|
||||
let proof = Proof::create(&proving_key, &[circuit], &public_inputs)?;
|
||||
|
||||
@@ -92,7 +98,7 @@ fn main() -> Result<()> {
|
||||
// Create the circuit
|
||||
let circuit = ZkCircuit::new(verifier_witnesses, zkbin);
|
||||
|
||||
// Build the verifying key and verify the zero-knowledge proof
|
||||
info!(target: "VERIFIER", "Building verifying key and verifying the zero-knowledge proof");
|
||||
let verifying_key = VerifyingKey::build(11, &circuit);
|
||||
proof.verify(&verifying_key, &public_inputs)?;
|
||||
/* ANCHOR_END: main */
|
||||
|
||||
@@ -16,8 +16,9 @@ use std::sync::{
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
net::{
|
||||
message,
|
||||
message_subscriber::{MessageSubscription, MessageSubsystem},
|
||||
messages,
|
||||
protocol::{ProtocolBase, ProtocolBasePtr},
|
||||
},
|
||||
system::{StoppableTask, StoppableTaskPtr, Subscriber, SubscriberPtr, Subscription},
|
||||
};
|
||||
@@ -107,7 +108,7 @@ impl Channel {
|
||||
/// Sends a message across a channel. Calls function 'send_message' that
|
||||
/// creates a new payload and sends it over the TCP connection as a
|
||||
/// packet. Returns an error if something goes wrong.
|
||||
pub async fn send<M: messages::Message>(&self, message: M) -> Result<()> {
|
||||
pub async fn send<M: message::Message>(&self, message: M) -> Result<()> {
|
||||
debug!(target: "net",
|
||||
"Channel::send() [START, command={:?}, address={}]",
|
||||
M::name(),
|
||||
@@ -138,17 +139,17 @@ impl Channel {
|
||||
/// it. Then creates a message packet- the base type of the network- and
|
||||
/// copies the payload into it. Then we send the packet over the TCP
|
||||
/// stream.
|
||||
async fn send_message<M: messages::Message>(&self, message: M) -> Result<()> {
|
||||
async fn send_message<M: message::Message>(&self, message: M) -> Result<()> {
|
||||
let mut payload = Vec::new();
|
||||
message.encode(&mut payload)?;
|
||||
let packet = messages::Packet { command: String::from(M::name()), payload };
|
||||
let packet = message::Packet { command: String::from(M::name()), payload };
|
||||
|
||||
let stream = &mut *self.writer.lock().await;
|
||||
messages::send_packet(stream, packet).await
|
||||
message::send_packet(stream, packet).await
|
||||
}
|
||||
|
||||
/// Subscribe to a messages on the message subsystem.
|
||||
pub async fn subscribe_msg<M: messages::Message>(&self) -> Result<MessageSubscription<M>> {
|
||||
pub async fn subscribe_msg<M: message::Message>(&self) -> Result<MessageSubscription<M>> {
|
||||
debug!(target: "net",
|
||||
"Channel::subscribe_msg() [START, command={:?}, address={}]",
|
||||
M::name(),
|
||||
@@ -178,12 +179,12 @@ impl Channel {
|
||||
|
||||
/// Perform network handshake for message subsystem dispatchers.
|
||||
async fn setup_dispatchers(message_subsystem: &MessageSubsystem) {
|
||||
message_subsystem.add_dispatch::<messages::VersionMessage>().await;
|
||||
message_subsystem.add_dispatch::<messages::VerackMessage>().await;
|
||||
message_subsystem.add_dispatch::<messages::PingMessage>().await;
|
||||
message_subsystem.add_dispatch::<messages::PongMessage>().await;
|
||||
message_subsystem.add_dispatch::<messages::GetAddrsMessage>().await;
|
||||
message_subsystem.add_dispatch::<messages::AddrsMessage>().await;
|
||||
message_subsystem.add_dispatch::<message::VersionMessage>().await;
|
||||
message_subsystem.add_dispatch::<message::VerackMessage>().await;
|
||||
message_subsystem.add_dispatch::<message::PingMessage>().await;
|
||||
message_subsystem.add_dispatch::<message::PongMessage>().await;
|
||||
message_subsystem.add_dispatch::<message::GetAddrsMessage>().await;
|
||||
message_subsystem.add_dispatch::<message::AddrsMessage>().await;
|
||||
}
|
||||
|
||||
/// Convenience function that returns the Message Subsystem.
|
||||
@@ -202,7 +203,7 @@ impl Channel {
|
||||
let reader = &mut *self.reader.lock().await;
|
||||
|
||||
loop {
|
||||
let packet = match messages::read_packet(reader).await {
|
||||
let packet = match message::read_packet(reader).await {
|
||||
Ok(packet) => packet,
|
||||
Err(err) => {
|
||||
if Self::is_eof_error(err.clone()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use futures::prelude::*;
|
||||
use log::*;
|
||||
use futures::{AsyncRead, AsyncWrite, AsyncReadExt, AsyncWriteExt};
|
||||
use log::debug;
|
||||
use std::{io, net::SocketAddr};
|
||||
|
||||
use crate::{
|
||||
@@ -1,11 +1,11 @@
|
||||
use async_std::sync::Mutex;
|
||||
use async_trait::async_trait;
|
||||
use log::*;
|
||||
use log::{debug, error, warn};
|
||||
use rand::Rng;
|
||||
use std::{any::Any, collections::HashMap, io, io::Cursor, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
net::messages::Message,
|
||||
net::message::Message,
|
||||
util::serial::{Decodable, Encodable},
|
||||
Error, Result,
|
||||
};
|
||||
@@ -87,6 +87,7 @@ impl<M: Message> MessageDispatcher<M> {
|
||||
/// channels.
|
||||
async fn trigger_all(&self, message: MessageResult<M>) {
|
||||
debug!(
|
||||
target: "net",
|
||||
"MessageDispatcher<M={}>::trigger_all({}) [START, subs={}]",
|
||||
M::name(),
|
||||
if message.is_ok() { "msg" } else { "err" },
|
||||
@@ -109,6 +110,7 @@ impl<M: Message> MessageDispatcher<M> {
|
||||
self.collect_garbage(garbage_ids).await;
|
||||
|
||||
debug!(
|
||||
target: "net",
|
||||
"MessageDispatcher<M={}>::trigger_all({}) [END, subs={}]",
|
||||
M::name(),
|
||||
if message.is_ok() { "msg" } else { "err" },
|
||||
|
||||
@@ -46,7 +46,7 @@ pub mod message_subscriber;
|
||||
///
|
||||
/// Implements a type called Packet which is the base message type. Packets are
|
||||
/// converted into messages and passed to an event loop.
|
||||
pub mod messages;
|
||||
pub mod message;
|
||||
|
||||
/// P2P provides all core functionality to interact with the peer-to-peer
|
||||
/// network.
|
||||
@@ -72,7 +72,7 @@ pub mod p2p;
|
||||
///
|
||||
/// Protocol submodule also implements a jobs manager than handles the
|
||||
/// asynchronous execution of the protocols.
|
||||
pub mod protocols;
|
||||
pub mod protocol;
|
||||
|
||||
/// Defines the interaction between nodes during a connection. Consists of an
|
||||
/// inbound session, which describes how to set up an incoming connection, and
|
||||
@@ -80,7 +80,7 @@ pub mod protocols;
|
||||
/// describes the seed session, which is the type of connection used when a node
|
||||
/// connects to the network for the first time. Implements the session trait
|
||||
/// which describes the common functions across all sessions.
|
||||
pub mod sessions;
|
||||
pub mod session;
|
||||
|
||||
/// Network configuration settings.
|
||||
pub mod settings;
|
||||
@@ -89,8 +89,9 @@ pub use acceptor::{Acceptor, AcceptorPtr};
|
||||
pub use channel::{Channel, ChannelPtr};
|
||||
pub use connector::Connector;
|
||||
pub use hosts::{Hosts, HostsPtr};
|
||||
pub use message::Message;
|
||||
pub use message_subscriber::MessageSubscription;
|
||||
pub use messages::Message;
|
||||
pub use p2p::{P2p, P2pPtr};
|
||||
pub use protocols::{ProtocolJobsManager, ProtocolJobsManagerPtr};
|
||||
pub use protocol::{ProtocolJobsManager, ProtocolJobsManagerPtr, ProtocolBasePtr, ProtocolBase};
|
||||
pub use session::{SESSION_ALL, SESSION_INBOUND, SESSION_MANUAL, SESSION_OUTBOUND, SESSION_SEED};
|
||||
pub use settings::{Settings, SettingsPtr};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use async_executor::Executor;
|
||||
use async_std::sync::Mutex;
|
||||
use log::*;
|
||||
use log::debug;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
net::SocketAddr,
|
||||
@@ -10,8 +10,9 @@ use std::{
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
net::{
|
||||
messages::Message,
|
||||
sessions::{InboundSession, ManualSession, OutboundSession, SeedSession},
|
||||
message::Message,
|
||||
protocol::{register_default_protocols, ProtocolRegistry},
|
||||
session::{InboundSession, ManualSession, OutboundSession, SeedSession},
|
||||
Channel, ChannelPtr, Hosts, HostsPtr, Settings, SettingsPtr,
|
||||
},
|
||||
system::{Subscriber, SubscriberPtr, Subscription},
|
||||
@@ -32,21 +33,28 @@ pub struct P2p {
|
||||
// Used both internally and externally
|
||||
stop_subscriber: SubscriberPtr<Error>,
|
||||
hosts: HostsPtr,
|
||||
protocol_registry: ProtocolRegistry,
|
||||
settings: SettingsPtr,
|
||||
}
|
||||
|
||||
impl P2p {
|
||||
/// Create a new p2p network.
|
||||
pub fn new(settings: Settings) -> Arc<Self> {
|
||||
pub async fn new(settings: Settings) -> Arc<Self> {
|
||||
let settings = Arc::new(settings);
|
||||
Arc::new(Self {
|
||||
|
||||
let self_ = Arc::new(Self {
|
||||
pending: Mutex::new(HashSet::new()),
|
||||
channels: Mutex::new(HashMap::new()),
|
||||
channel_subscriber: Subscriber::new(),
|
||||
stop_subscriber: Subscriber::new(),
|
||||
hosts: Hosts::new(),
|
||||
protocol_registry: ProtocolRegistry::new(),
|
||||
settings,
|
||||
})
|
||||
});
|
||||
|
||||
register_default_protocols(self_.clone()).await;
|
||||
|
||||
self_
|
||||
}
|
||||
|
||||
/// Invoke startup and seeding sequence. Call from constructing thread.
|
||||
@@ -140,6 +148,10 @@ impl P2p {
|
||||
self.hosts.clone()
|
||||
}
|
||||
|
||||
pub fn protocol_registry(&self) -> &ProtocolRegistry {
|
||||
&self.protocol_registry
|
||||
}
|
||||
|
||||
/// Subscribe to a channel.
|
||||
pub async fn subscribe_channel(&self) -> Subscription<Result<ChannelPtr>> {
|
||||
self.channel_subscriber.clone().subscribe().await
|
||||
|
||||
@@ -46,8 +46,26 @@ pub mod protocol_seed;
|
||||
/// other node and sending the version acknowledgement.
|
||||
pub mod protocol_version;
|
||||
|
||||
pub mod protocol_base;
|
||||
pub mod protocol_registry;
|
||||
|
||||
pub use protocol_address::ProtocolAddress;
|
||||
pub use protocol_jobs_manager::{ProtocolJobsManager, ProtocolJobsManagerPtr};
|
||||
pub use protocol_ping::ProtocolPing;
|
||||
pub use protocol_seed::ProtocolSeed;
|
||||
pub use protocol_version::ProtocolVersion;
|
||||
|
||||
pub use protocol_base::{ProtocolBase, ProtocolBasePtr};
|
||||
pub use protocol_registry::ProtocolRegistry;
|
||||
|
||||
use crate::net::{
|
||||
session::{SESSION_ALL, SESSION_SEED},
|
||||
P2pPtr,
|
||||
};
|
||||
|
||||
pub async fn register_default_protocols(p2p: P2pPtr) {
|
||||
let registry = p2p.protocol_registry();
|
||||
registry.register(SESSION_ALL, ProtocolPing::new).await;
|
||||
registry.register(!SESSION_SEED, ProtocolAddress::new).await;
|
||||
registry.register(SESSION_SEED, ProtocolSeed::new).await;
|
||||
}
|
||||
@@ -1,22 +1,23 @@
|
||||
use log::*;
|
||||
use async_trait::async_trait;
|
||||
use log::{debug, error};
|
||||
use smol::Executor;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
error::Result,
|
||||
net::{
|
||||
message,
|
||||
message_subscriber::MessageSubscription,
|
||||
messages,
|
||||
protocols::{ProtocolJobsManager, ProtocolJobsManagerPtr},
|
||||
ChannelPtr, HostsPtr,
|
||||
protocol::{ProtocolBase, ProtocolBasePtr, ProtocolJobsManager, ProtocolJobsManagerPtr},
|
||||
ChannelPtr, HostsPtr, P2pPtr,
|
||||
},
|
||||
};
|
||||
|
||||
/// Defines address and get-address messages.
|
||||
pub struct ProtocolAddress {
|
||||
channel: ChannelPtr,
|
||||
addrs_sub: MessageSubscription<messages::AddrsMessage>,
|
||||
get_addrs_sub: MessageSubscription<messages::GetAddrsMessage>,
|
||||
addrs_sub: MessageSubscription<message::AddrsMessage>,
|
||||
get_addrs_sub: MessageSubscription<message::GetAddrsMessage>,
|
||||
hosts: HostsPtr,
|
||||
jobsman: ProtocolJobsManagerPtr,
|
||||
}
|
||||
@@ -24,18 +25,20 @@ pub struct ProtocolAddress {
|
||||
impl ProtocolAddress {
|
||||
/// Create a new address protocol. Makes an address and get-address
|
||||
/// subscription and adds them to the address protocol instance.
|
||||
pub async fn new(channel: ChannelPtr, hosts: HostsPtr) -> Arc<Self> {
|
||||
pub async fn new(channel: ChannelPtr, p2p: P2pPtr) -> ProtocolBasePtr {
|
||||
let hosts = p2p.hosts();
|
||||
|
||||
// Creates a subscription to address message.
|
||||
let addrs_sub = channel
|
||||
.clone()
|
||||
.subscribe_msg::<messages::AddrsMessage>()
|
||||
.subscribe_msg::<message::AddrsMessage>()
|
||||
.await
|
||||
.expect("Missing addrs dispatcher!");
|
||||
|
||||
// Creates a subscription to get-address message.
|
||||
let get_addrs_sub = channel
|
||||
.clone()
|
||||
.subscribe_msg::<messages::GetAddrsMessage>()
|
||||
.subscribe_msg::<message::GetAddrsMessage>()
|
||||
.await
|
||||
.expect("Missing getaddrs dispatcher!");
|
||||
|
||||
@@ -48,21 +51,6 @@ impl ProtocolAddress {
|
||||
})
|
||||
}
|
||||
|
||||
/// Starts the address protocol. Runs receive address and get address
|
||||
/// protocols on the protocol task manager. Then sends get-address
|
||||
/// message.
|
||||
pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
|
||||
debug!(target: "net", "ProtocolAddress::start() [START]");
|
||||
self.jobsman.clone().start(executor.clone());
|
||||
self.jobsman.clone().spawn(self.clone().handle_receive_addrs(), executor.clone()).await;
|
||||
self.jobsman.clone().spawn(self.clone().handle_receive_get_addrs(), executor).await;
|
||||
|
||||
// Send get_address message.
|
||||
let get_addrs = messages::GetAddrsMessage {};
|
||||
let _ = self.channel.clone().send(get_addrs).await;
|
||||
debug!(target: "net", "ProtocolAddress::start() [END]");
|
||||
}
|
||||
|
||||
/// Handles receiving the address message. Loops to continually recieve
|
||||
/// address messages on the address subsciption. Adds the recieved
|
||||
/// addresses to the list of hosts.
|
||||
@@ -101,9 +89,32 @@ impl ProtocolAddress {
|
||||
addrs.len()
|
||||
);
|
||||
// Creates an address messages containing host address.
|
||||
let addrs_msg = messages::AddrsMessage { addrs };
|
||||
let addrs_msg = message::AddrsMessage { addrs };
|
||||
// Sends the address message across the channel.
|
||||
self.channel.clone().send(addrs_msg).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ProtocolBase for ProtocolAddress {
|
||||
/// Starts the address protocol. Runs receive address and get address
|
||||
/// protocols on the protocol task manager. Then sends get-address
|
||||
/// message.
|
||||
async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
|
||||
debug!(target: "net", "ProtocolAddress::start() [START]");
|
||||
self.jobsman.clone().start(executor.clone());
|
||||
self.jobsman.clone().spawn(self.clone().handle_receive_addrs(), executor.clone()).await;
|
||||
self.jobsman.clone().spawn(self.clone().handle_receive_get_addrs(), executor).await;
|
||||
|
||||
// Send get_address message.
|
||||
let get_addrs = message::GetAddrsMessage {};
|
||||
let _ = self.channel.clone().send(get_addrs).await;
|
||||
debug!(target: "net", "ProtocolAddress::start() [END]");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"ProtocolAddress"
|
||||
}
|
||||
}
|
||||
14
src/net/protocol/protocol_base.rs
Normal file
14
src/net/protocol/protocol_base.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use async_trait::async_trait;
|
||||
use smol::Executor;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::error::Result;
|
||||
|
||||
pub type ProtocolBasePtr = Arc<dyn ProtocolBase + Send + Sync>;
|
||||
|
||||
#[async_trait]
|
||||
pub trait ProtocolBase {
|
||||
async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()>;
|
||||
|
||||
fn name(&self) -> &'static str;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
use log::*;
|
||||
use async_trait::async_trait;
|
||||
use log::{debug, error};
|
||||
use rand::Rng;
|
||||
use smol::Executor;
|
||||
use std::{sync::Arc, time::Instant};
|
||||
@@ -6,9 +7,10 @@ use std::{sync::Arc, time::Instant};
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
net::{
|
||||
messages,
|
||||
protocols::{ProtocolJobsManager, ProtocolJobsManagerPtr},
|
||||
ChannelPtr, SettingsPtr,
|
||||
message,
|
||||
message_subscriber::MessageSubscription,
|
||||
protocol::{ProtocolBase, ProtocolBasePtr, ProtocolJobsManager, ProtocolJobsManagerPtr},
|
||||
ChannelPtr, P2pPtr, SettingsPtr,
|
||||
},
|
||||
util::sleep,
|
||||
};
|
||||
@@ -16,45 +18,46 @@ use crate::{
|
||||
/// Defines ping and pong messages.
|
||||
pub struct ProtocolPing {
|
||||
channel: ChannelPtr,
|
||||
ping_sub: MessageSubscription<message::PingMessage>,
|
||||
pong_sub: MessageSubscription<message::PongMessage>,
|
||||
settings: SettingsPtr,
|
||||
jobsman: ProtocolJobsManagerPtr,
|
||||
}
|
||||
|
||||
impl ProtocolPing {
|
||||
/// Create a new ping-pong protocol.
|
||||
pub fn new(channel: ChannelPtr, settings: SettingsPtr) -> Arc<Self> {
|
||||
pub async fn new(channel: ChannelPtr, p2p: P2pPtr) -> ProtocolBasePtr {
|
||||
let settings = p2p.settings();
|
||||
|
||||
// Creates a subscription to ping message.
|
||||
let ping_sub = channel
|
||||
.clone()
|
||||
.subscribe_msg::<message::PingMessage>()
|
||||
.await
|
||||
.expect("Missing ping dispatcher!");
|
||||
|
||||
// Creates a subscription to pong message.
|
||||
let pong_sub = channel
|
||||
.clone()
|
||||
.subscribe_msg::<message::PongMessage>()
|
||||
.await
|
||||
.expect("Missing pong dispatcher!");
|
||||
|
||||
Arc::new(Self {
|
||||
channel: channel.clone(),
|
||||
ping_sub,
|
||||
pong_sub,
|
||||
settings,
|
||||
jobsman: ProtocolJobsManager::new("ProtocolPing", channel),
|
||||
})
|
||||
}
|
||||
|
||||
/// Starts ping-pong keep-alive messages exchange. Runs ping-pong in the
|
||||
/// protocol task manager, then queues the reply. Sends out a ping and
|
||||
/// waits for pong reply. Waits for ping and replies with a pong.
|
||||
pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
|
||||
debug!(target: "net", "ProtocolPing::start() [START]");
|
||||
self.jobsman.clone().start(executor.clone());
|
||||
self.jobsman.clone().spawn(self.clone().run_ping_pong(), executor.clone()).await;
|
||||
self.jobsman.clone().spawn(self.reply_to_ping(), executor).await;
|
||||
debug!(target: "net", "ProtocolPing::start() [END]");
|
||||
}
|
||||
|
||||
/// Runs ping-pong protocol. Creates a subscription to pong, then starts a
|
||||
/// loop. Loop sleeps for the duration of the channel heartbeat, then
|
||||
/// sends a ping message with a random nonce. Loop starts a timer, waits
|
||||
/// for the pong reply and insures the nonce is the same.
|
||||
async fn run_ping_pong(self: Arc<Self>) -> Result<()> {
|
||||
debug!(target: "net", "ProtocolPing::run_ping_pong() [START]");
|
||||
// Creates a subscription to pong message.
|
||||
let pong_sub = self
|
||||
.channel
|
||||
.clone()
|
||||
.subscribe_msg::<messages::PongMessage>()
|
||||
.await
|
||||
.expect("Missing pong dispatcher!");
|
||||
|
||||
loop {
|
||||
// Wait channel_heartbeat amount of time.
|
||||
sleep(self.settings.channel_heartbeat_seconds).await;
|
||||
@@ -63,14 +66,14 @@ impl ProtocolPing {
|
||||
let nonce = Self::random_nonce();
|
||||
|
||||
// Send ping message.
|
||||
let ping = messages::PingMessage { nonce };
|
||||
let ping = message::PingMessage { nonce };
|
||||
self.channel.clone().send(ping).await?;
|
||||
debug!(target: "net", "ProtocolPing::run_ping_pong() send Ping message");
|
||||
// Start the timer for ping timer.
|
||||
let start = Instant::now();
|
||||
|
||||
// Wait for pong, check nonce matches.
|
||||
let pong_msg = pong_sub.receive().await?;
|
||||
let pong_msg = self.pong_sub.receive().await?;
|
||||
if pong_msg.nonce != nonce {
|
||||
error!("Wrong nonce for ping reply. Disconnecting from channel.");
|
||||
self.channel.stop().await;
|
||||
@@ -85,21 +88,13 @@ impl ProtocolPing {
|
||||
/// pong reply.
|
||||
async fn reply_to_ping(self: Arc<Self>) -> Result<()> {
|
||||
debug!(target: "net", "ProtocolPing::reply_to_ping() [START]");
|
||||
// Creates a subscription to ping message.
|
||||
let ping_sub = self
|
||||
.channel
|
||||
.clone()
|
||||
.subscribe_msg::<messages::PingMessage>()
|
||||
.await
|
||||
.expect("Missing ping dispatcher!");
|
||||
|
||||
loop {
|
||||
// Wait for ping, reply with pong that has a matching nonce.
|
||||
let ping = ping_sub.receive().await?;
|
||||
let ping = self.ping_sub.receive().await?;
|
||||
debug!(target: "net", "ProtocolPing::reply_to_ping() received Ping message");
|
||||
|
||||
// Send pong message.
|
||||
let pong = messages::PongMessage { nonce: ping.nonce };
|
||||
let pong = message::PongMessage { nonce: ping.nonce };
|
||||
self.channel.clone().send(pong).await?;
|
||||
debug!(target: "net", "ProtocolPing::reply_to_ping() sent Pong reply");
|
||||
}
|
||||
@@ -110,3 +105,22 @@ impl ProtocolPing {
|
||||
rng.gen()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ProtocolBase for ProtocolPing {
|
||||
/// Starts ping-pong keep-alive messages exchange. Runs ping-pong in the
|
||||
/// protocol task manager, then queues the reply. Sends out a ping and
|
||||
/// waits for pong reply. Waits for ping and replies with a pong.
|
||||
async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
|
||||
debug!(target: "net", "ProtocolPing::start() [START]");
|
||||
self.jobsman.clone().start(executor.clone());
|
||||
self.jobsman.clone().spawn(self.clone().run_ping_pong(), executor.clone()).await;
|
||||
self.jobsman.clone().spawn(self.reply_to_ping(), executor).await;
|
||||
debug!(target: "net", "ProtocolPing::start() [END]");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"ProtocolPing"
|
||||
}
|
||||
}
|
||||
56
src/net/protocol/protocol_registry.rs
Normal file
56
src/net/protocol/protocol_registry.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
use async_std::sync::Mutex;
|
||||
use futures::future::BoxFuture;
|
||||
use std::future::Future;
|
||||
use log::debug;
|
||||
|
||||
use crate::net::{session::SessionBitflag, ChannelPtr, P2pPtr, protocol::ProtocolBasePtr};
|
||||
|
||||
type Constructor = Box<
|
||||
dyn Fn(ChannelPtr, P2pPtr) -> BoxFuture<'static, ProtocolBasePtr>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>;
|
||||
|
||||
pub struct ProtocolRegistry {
|
||||
protocol_constructors: Mutex<Vec<(SessionBitflag, Constructor)>>,
|
||||
}
|
||||
|
||||
impl ProtocolRegistry {
|
||||
pub fn new() -> Self {
|
||||
Self { protocol_constructors: Mutex::new(Vec::new()) }
|
||||
}
|
||||
|
||||
// add_protocol()?
|
||||
pub async fn register<C, F>(&self, session_flags: SessionBitflag, constructor: C)
|
||||
where
|
||||
C: 'static + Fn(ChannelPtr, P2pPtr) -> F + Send + Sync,
|
||||
F: 'static + Future<Output = ProtocolBasePtr> + Send,
|
||||
{
|
||||
let constructor = move |channel, p2p| {
|
||||
Box::pin(constructor(channel, p2p))
|
||||
as BoxFuture<'static, ProtocolBasePtr>
|
||||
};
|
||||
self.protocol_constructors.lock().await.push((session_flags, Box::new(constructor)));
|
||||
}
|
||||
|
||||
pub async fn attach(
|
||||
&self,
|
||||
selector_id: SessionBitflag,
|
||||
channel: ChannelPtr,
|
||||
p2p: P2pPtr,
|
||||
) -> Vec<ProtocolBasePtr> {
|
||||
let mut protocols: Vec<ProtocolBasePtr> = Vec::new();
|
||||
for (session_flags, construct) in self.protocol_constructors.lock().await.iter() {
|
||||
// Skip protocols that are not registered for this session
|
||||
if selector_id & session_flags == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
let protocol: ProtocolBasePtr =
|
||||
construct(channel.clone(), p2p.clone()).await;
|
||||
debug!(target: "net", "Attached {}", protocol.name());
|
||||
protocols.push(protocol)
|
||||
}
|
||||
protocols
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
use log::*;
|
||||
use async_trait::async_trait;
|
||||
use log::debug;
|
||||
use smol::Executor;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
error::Result,
|
||||
net::{messages, ChannelPtr, HostsPtr, SettingsPtr},
|
||||
net::{
|
||||
message,
|
||||
protocol::{ProtocolBase, ProtocolBasePtr},
|
||||
ChannelPtr, HostsPtr, P2pPtr, SettingsPtr,
|
||||
},
|
||||
};
|
||||
|
||||
/// Implements the seed protocol.
|
||||
@@ -16,20 +21,41 @@ pub struct ProtocolSeed {
|
||||
|
||||
impl ProtocolSeed {
|
||||
/// Create a new seed protocol.
|
||||
pub fn new(channel: ChannelPtr, hosts: HostsPtr, settings: SettingsPtr) -> Arc<Self> {
|
||||
pub async fn new(channel: ChannelPtr, p2p: P2pPtr) -> ProtocolBasePtr {
|
||||
let hosts = p2p.hosts();
|
||||
let settings = p2p.settings();
|
||||
|
||||
Arc::new(Self { channel, hosts, settings })
|
||||
}
|
||||
|
||||
/// Sends own external address over a channel. Imports own external address
|
||||
/// from settings, then adds that address to an address message and
|
||||
/// sends it out over the channel.
|
||||
pub async fn send_self_address(&self) -> Result<()> {
|
||||
match self.settings.external_addr {
|
||||
Some(addr) => {
|
||||
debug!(target: "net", "ProtocolSeed::send_own_address() addr={}", addr);
|
||||
let addr = message::AddrsMessage { addrs: vec![addr] };
|
||||
Ok(self.channel.clone().send(addr).await?)
|
||||
}
|
||||
// Do nothing if external address is not configured
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ProtocolBase for ProtocolSeed {
|
||||
/// Starts the seed protocol. Creates a subscription to the address message,
|
||||
/// then sends our address to the seed server. Sends a get-address
|
||||
/// message and receives an address message.
|
||||
pub async fn start(self: Arc<Self>, _executor: Arc<Executor<'_>>) -> Result<()> {
|
||||
async fn start(self: Arc<Self>, _executor: Arc<Executor<'_>>) -> Result<()> {
|
||||
debug!(target: "net", "ProtocolSeed::start() [START]");
|
||||
// Create a subscription to address message.
|
||||
let addr_sub = self
|
||||
.channel
|
||||
.clone()
|
||||
.subscribe_msg::<messages::AddrsMessage>()
|
||||
.subscribe_msg::<message::AddrsMessage>()
|
||||
.await
|
||||
.expect("Missing addrs dispatcher!");
|
||||
|
||||
@@ -37,7 +63,7 @@ impl ProtocolSeed {
|
||||
self.send_self_address().await?;
|
||||
|
||||
// Send get address message.
|
||||
let get_addr = messages::GetAddrsMessage {};
|
||||
let get_addr = message::GetAddrsMessage {};
|
||||
self.channel.clone().send(get_addr).await?;
|
||||
|
||||
// Receive addresses.
|
||||
@@ -49,18 +75,7 @@ impl ProtocolSeed {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sends own external address over a channel. Imports own external address
|
||||
/// from settings, then adds that address to an address message and
|
||||
/// sends it out over the channel.
|
||||
pub async fn send_self_address(&self) -> Result<()> {
|
||||
match self.settings.external_addr {
|
||||
Some(addr) => {
|
||||
debug!(target: "net", "ProtocolSeed::send_own_address() addr={}", addr);
|
||||
let addr = messages::AddrsMessage { addrs: vec![addr] };
|
||||
Ok(self.channel.clone().send(addr).await?)
|
||||
}
|
||||
// Do nothing if external address is not configured
|
||||
None => Ok(()),
|
||||
}
|
||||
fn name(&self) -> &'static str {
|
||||
"ProtocolSeed"
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
net::{message_subscriber::MessageSubscription, messages, ChannelPtr, SettingsPtr},
|
||||
net::{message, message_subscriber::MessageSubscription, ChannelPtr, SettingsPtr},
|
||||
util::sleep,
|
||||
};
|
||||
|
||||
@@ -13,8 +13,8 @@ use crate::{
|
||||
/// of a connection.
|
||||
pub struct ProtocolVersion {
|
||||
channel: ChannelPtr,
|
||||
version_sub: MessageSubscription<messages::VersionMessage>,
|
||||
verack_sub: MessageSubscription<messages::VerackMessage>,
|
||||
version_sub: MessageSubscription<message::VersionMessage>,
|
||||
verack_sub: MessageSubscription<message::VerackMessage>,
|
||||
settings: SettingsPtr,
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@ impl ProtocolVersion {
|
||||
// Creates a version subscription.
|
||||
let version_sub = channel
|
||||
.clone()
|
||||
.subscribe_msg::<messages::VersionMessage>()
|
||||
.subscribe_msg::<message::VersionMessage>()
|
||||
.await
|
||||
.expect("Missing version dispatcher!");
|
||||
|
||||
// Creates a version acknowledgement subscription.
|
||||
let verack_sub = channel
|
||||
.clone()
|
||||
.subscribe_msg::<messages::VerackMessage>()
|
||||
.subscribe_msg::<message::VerackMessage>()
|
||||
.await
|
||||
.expect("Missing verack dispatcher!");
|
||||
|
||||
@@ -71,7 +71,7 @@ impl ProtocolVersion {
|
||||
/// Send version info and wait for version acknowledgement.
|
||||
async fn send_version(self: Arc<Self>) -> Result<()> {
|
||||
debug!(target: "net", "ProtocolVersion::send_version() [START]");
|
||||
let version = messages::VersionMessage {};
|
||||
let version = message::VersionMessage {};
|
||||
self.channel.clone().send(version).await?;
|
||||
|
||||
// Wait for version acknowledgement
|
||||
@@ -90,7 +90,7 @@ impl ProtocolVersion {
|
||||
// Check the message is OK
|
||||
|
||||
// Send version acknowledgement
|
||||
let verack = messages::VerackMessage {};
|
||||
let verack = message::VerackMessage {};
|
||||
self.channel.clone().send(verack).await?;
|
||||
|
||||
debug!(target: "net", "ProtocolVersion::recv_version() [END]");
|
||||
@@ -8,8 +8,8 @@ use std::{
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
net::{
|
||||
protocols::{ProtocolAddress, ProtocolPing},
|
||||
sessions::Session,
|
||||
protocol::{ProtocolAddress, ProtocolBase, ProtocolPing},
|
||||
session::{Session, SessionBitflag, SESSION_INBOUND},
|
||||
Acceptor, AcceptorPtr, ChannelPtr, P2p,
|
||||
},
|
||||
system::{StoppableTask, StoppableTaskPtr},
|
||||
@@ -96,30 +96,34 @@ impl InboundSession {
|
||||
|
||||
self.clone().register_channel(channel.clone(), executor.clone()).await?;
|
||||
|
||||
self.attach_protocols(channel, executor).await
|
||||
//self.attach_protocols(channel, executor).await
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Starts sending keep-alive and address messages across the channels.
|
||||
async fn attach_protocols(
|
||||
// Starts sending keep-alive and address messages across the channels.
|
||||
/*async fn attach_protocols(
|
||||
self: Arc<Self>,
|
||||
channel: ChannelPtr,
|
||||
executor: Arc<Executor<'_>>,
|
||||
) -> Result<()> {
|
||||
let settings = self.p2p().settings().clone();
|
||||
let hosts = self.p2p().hosts();
|
||||
|
||||
let protocol_ping = ProtocolPing::new(channel.clone(), settings.clone());
|
||||
let protocol_ping = ProtocolPing::new(channel.clone(), self.p2p());
|
||||
let protocol_addr = ProtocolAddress::new(channel, hosts).await;
|
||||
|
||||
protocol_ping.start(executor.clone()).await;
|
||||
protocol_addr.start(executor).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
impl Session for InboundSession {
|
||||
fn p2p(&self) -> Arc<P2p> {
|
||||
self.p2p.upgrade().unwrap()
|
||||
}
|
||||
|
||||
fn selector_id(&self) -> SessionBitflag {
|
||||
SESSION_INBOUND
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@ use std::{
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
net::{
|
||||
protocols::{ProtocolAddress, ProtocolPing},
|
||||
sessions::Session,
|
||||
protocol::{ProtocolAddress, ProtocolBase, ProtocolPing},
|
||||
session::{Session, SessionBitflag, SESSION_MANUAL},
|
||||
ChannelPtr, Connector, P2p,
|
||||
},
|
||||
system::{StoppableTask, StoppableTaskPtr},
|
||||
@@ -89,7 +89,7 @@ impl ManualSession {
|
||||
// Remove pending lock since register_channel will add the channel to p2p
|
||||
self.p2p().remove_pending(&addr).await;
|
||||
|
||||
self.clone().attach_protocols(channel, executor.clone()).await?;
|
||||
//self.clone().attach_protocols(channel, executor.clone()).await?;
|
||||
|
||||
// Wait for channel to close
|
||||
stop_sub.receive().await;
|
||||
@@ -112,27 +112,30 @@ impl ManualSession {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Starts sending keep-alive and address messages across the channels.
|
||||
async fn attach_protocols(
|
||||
// Starts sending keep-alive and address messages across the channels.
|
||||
/*async fn attach_protocols(
|
||||
self: Arc<Self>,
|
||||
channel: ChannelPtr,
|
||||
executor: Arc<Executor<'_>>,
|
||||
) -> Result<()> {
|
||||
let settings = self.p2p().settings().clone();
|
||||
let hosts = self.p2p().hosts();
|
||||
|
||||
let protocol_ping = ProtocolPing::new(channel.clone(), settings.clone());
|
||||
let protocol_ping = ProtocolPing::new(channel.clone(), self.p2p());
|
||||
let protocol_addr = ProtocolAddress::new(channel, hosts).await;
|
||||
|
||||
protocol_ping.start(executor.clone()).await;
|
||||
protocol_addr.start(executor).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
impl Session for ManualSession {
|
||||
fn p2p(&self) -> Arc<P2p> {
|
||||
self.p2p.upgrade().unwrap()
|
||||
}
|
||||
|
||||
fn selector_id(&self) -> SessionBitflag {
|
||||
SESSION_MANUAL
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,14 @@ pub mod outbound_session;
|
||||
/// channel and initializing the channel by performing a network handshake.
|
||||
pub mod session;
|
||||
|
||||
// bitwise selectors for the protocol_registry
|
||||
pub type SessionBitflag = u32;
|
||||
pub const SESSION_INBOUND: SessionBitflag = 0b0001;
|
||||
pub const SESSION_OUTBOUND: SessionBitflag = 0b0010;
|
||||
pub const SESSION_MANUAL: SessionBitflag = 0b0100;
|
||||
pub const SESSION_SEED: SessionBitflag = 0b1000;
|
||||
pub const SESSION_ALL: SessionBitflag = 0b1111;
|
||||
|
||||
pub use inbound_session::InboundSession;
|
||||
pub use manual_session::ManualSession;
|
||||
pub use outbound_session::OutboundSession;
|
||||
@@ -9,8 +9,8 @@ use std::{
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
net::{
|
||||
protocols::{ProtocolAddress, ProtocolPing},
|
||||
sessions::Session,
|
||||
protocol::{ProtocolAddress, ProtocolBase, ProtocolPing},
|
||||
session::{Session, SessionBitflag, SESSION_OUTBOUND},
|
||||
ChannelPtr, Connector, P2p,
|
||||
},
|
||||
system::{StoppableTask, StoppableTaskPtr},
|
||||
@@ -91,7 +91,7 @@ impl OutboundSession {
|
||||
// Remove pending lock since register_channel will add the channel to p2p
|
||||
self.p2p().remove_pending(&addr).await;
|
||||
|
||||
self.clone().attach_protocols(channel, executor.clone()).await?;
|
||||
//self.clone().attach_protocols(channel, executor.clone()).await?;
|
||||
|
||||
// Wait for channel to close
|
||||
stop_sub.receive().await;
|
||||
@@ -151,27 +151,30 @@ impl OutboundSession {
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts sending keep-alive and address messages across the channels.
|
||||
async fn attach_protocols(
|
||||
// Starts sending keep-alive and address messages across the channels.
|
||||
/*async fn attach_protocols(
|
||||
self: Arc<Self>,
|
||||
channel: ChannelPtr,
|
||||
executor: Arc<Executor<'_>>,
|
||||
) -> Result<()> {
|
||||
let settings = self.p2p().settings().clone();
|
||||
let hosts = self.p2p().hosts();
|
||||
|
||||
let protocol_ping = ProtocolPing::new(channel.clone(), settings.clone());
|
||||
let protocol_ping = ProtocolPing::new(channel.clone(), self.p2p());
|
||||
let protocol_addr = ProtocolAddress::new(channel, hosts).await;
|
||||
|
||||
protocol_ping.start(executor.clone()).await;
|
||||
protocol_addr.start(executor).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
impl Session for OutboundSession {
|
||||
fn p2p(&self) -> Arc<P2p> {
|
||||
self.p2p.upgrade().unwrap()
|
||||
}
|
||||
|
||||
fn selector_id(&self) -> SessionBitflag {
|
||||
SESSION_OUTBOUND
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@ use std::{
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
net::{
|
||||
protocols::{ProtocolPing, ProtocolSeed},
|
||||
sessions::Session,
|
||||
protocol::{ProtocolBase, ProtocolPing, ProtocolSeed},
|
||||
session::{Session, SessionBitflag, SESSION_SEED},
|
||||
ChannelPtr, Connector, HostsPtr, P2p, SettingsPtr,
|
||||
},
|
||||
util::sleep,
|
||||
@@ -100,7 +100,7 @@ impl SeedSession {
|
||||
|
||||
self.clone().register_channel(channel.clone(), executor.clone()).await?;
|
||||
|
||||
self.attach_protocols(channel, hosts, settings, executor).await?;
|
||||
//self.attach_protocols(channel, hosts, settings, executor).await?;
|
||||
|
||||
debug!(target: "net", "SeedSession::start_seed(i={}) [END]", seed_index);
|
||||
Ok(())
|
||||
@@ -112,15 +112,15 @@ impl SeedSession {
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts keep-alive messages and seed protocol.
|
||||
async fn attach_protocols(
|
||||
// Starts keep-alive messages and seed protocol.
|
||||
/*async fn attach_protocols(
|
||||
self: Arc<Self>,
|
||||
channel: ChannelPtr,
|
||||
hosts: HostsPtr,
|
||||
settings: SettingsPtr,
|
||||
executor: Arc<Executor<'_>>,
|
||||
) -> Result<()> {
|
||||
let protocol_ping = ProtocolPing::new(channel.clone(), settings.clone());
|
||||
let protocol_ping = ProtocolPing::new(channel.clone(), self.p2p());
|
||||
protocol_ping.start(executor.clone()).await;
|
||||
|
||||
let protocol_seed = ProtocolSeed::new(channel.clone(), hosts, settings.clone());
|
||||
@@ -130,11 +130,15 @@ impl SeedSession {
|
||||
channel.stop().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
impl Session for SeedSession {
|
||||
fn p2p(&self) -> Arc<P2p> {
|
||||
self.p2p.upgrade().unwrap()
|
||||
}
|
||||
|
||||
fn selector_id(&self) -> SessionBitflag {
|
||||
SESSION_SEED
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
use async_trait::async_trait;
|
||||
use log::*;
|
||||
use log::debug;
|
||||
use smol::Executor;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
error::Result,
|
||||
net::{p2p::P2pPtr, protocols::ProtocolVersion, ChannelPtr},
|
||||
net::{p2p::P2pPtr, protocol::ProtocolVersion, ChannelPtr},
|
||||
};
|
||||
|
||||
/// Removes channel from the list of connected channels when a stop signal is
|
||||
@@ -37,15 +37,36 @@ pub trait Session: Sync {
|
||||
) -> Result<()> {
|
||||
debug!(target: "net", "Session::register_channel() [START]");
|
||||
|
||||
// Protocols should all be initialized but not started
|
||||
// We do this so that the protocols can begin receiving and buffering messages
|
||||
// while the handshake protocol is ongoing.
|
||||
// They are currently in sleep mode.
|
||||
let p2p = self.p2p();
|
||||
let protocols =
|
||||
p2p.protocol_registry().attach(self.selector_id(), channel.clone(), p2p.clone()).await;
|
||||
|
||||
// Perform the handshake protocol
|
||||
let protocol_version = ProtocolVersion::new(channel.clone(), self.p2p().settings()).await;
|
||||
let handshake_task =
|
||||
self.perform_handshake_protocols(protocol_version, channel.clone(), executor.clone());
|
||||
|
||||
// start channel
|
||||
channel.start(executor);
|
||||
// Switch on the channel
|
||||
channel.start(executor.clone());
|
||||
|
||||
// Wait for handshake to finish.
|
||||
handshake_task.await?;
|
||||
|
||||
// Now the channel is ready
|
||||
debug!(target: "net", "Session handshake complete. Activating remaining protocols");
|
||||
|
||||
// Now start all the protocols
|
||||
// They are responsible for managing their own lifetimes and
|
||||
// correctly self destructing when the channel ends.
|
||||
for protocol in protocols {
|
||||
// Activate protocol
|
||||
protocol.start(executor.clone()).await?;
|
||||
}
|
||||
|
||||
debug!(target: "net", "Session::register_channel() [END]");
|
||||
Ok(())
|
||||
}
|
||||
@@ -76,4 +97,6 @@ pub trait Session: Sync {
|
||||
|
||||
/// Returns a pointer to the p2p network interface.
|
||||
fn p2p(&self) -> P2pPtr;
|
||||
|
||||
fn selector_id(&self) -> u32;
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
pub mod circuit;
|
||||
|
||||
#[cfg(feature = "zkvm")]
|
||||
/// Halo2 zkas virtual machine
|
||||
pub mod vm;
|
||||
|
||||
#[cfg(feature = "zkvm")]
|
||||
mod vm_stack;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Stack type abstractions
|
||||
//! VM stack type abstractions
|
||||
use halo2_gadgets::{
|
||||
ecc::{chip::EccChip, FixedPoint, Point},
|
||||
utilities::CellValue,
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
use std::{
|
||||
io,
|
||||
io::{stdin, stdout, Read, Write},
|
||||
process,
|
||||
str::Chars,
|
||||
};
|
||||
|
||||
use termion::{color, style};
|
||||
|
||||
use super::{
|
||||
ast::{
|
||||
Constant, Constants, StatementType, Statements, Var, Variable, Variables, Witness,
|
||||
Witnesses,
|
||||
},
|
||||
error::ErrorEmitter,
|
||||
types::Type,
|
||||
};
|
||||
|
||||
pub struct Analyzer {
|
||||
file: String,
|
||||
lines: Vec<String>,
|
||||
pub constants: Constants,
|
||||
pub witnesses: Witnesses,
|
||||
pub statements: Statements,
|
||||
pub stack: Variables,
|
||||
error: ErrorEmitter,
|
||||
}
|
||||
|
||||
impl Analyzer {
|
||||
@@ -34,15 +30,10 @@ impl Analyzer {
|
||||
) -> Self {
|
||||
// For nice error reporting, we'll load everything into a string
|
||||
// vector so we have references to lines.
|
||||
let lines = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
Analyzer {
|
||||
file: filename.to_string(),
|
||||
lines,
|
||||
constants,
|
||||
witnesses,
|
||||
statements,
|
||||
stack: vec![],
|
||||
}
|
||||
let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
let error = ErrorEmitter::new("Semantic", filename, lines.clone());
|
||||
|
||||
Analyzer { constants, witnesses, statements, stack: vec![], error }
|
||||
}
|
||||
|
||||
pub fn analyze_types(&mut self) {
|
||||
@@ -62,7 +53,7 @@ impl Analyzer {
|
||||
// It's kinda ugly.
|
||||
if arg_types[0] == Type::BaseArray || arg_types[0] == Type::ScalarArray {
|
||||
if statement.args.is_empty() {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Passed no arguments to `{:?}` call. Expected at least 1.",
|
||||
statement.opcode
|
||||
@@ -81,7 +72,7 @@ impl Analyzer {
|
||||
};
|
||||
|
||||
if arg_types[0] == Type::BaseArray && var_type != Type::Base {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Incorrect argument type. Expected `{:?}`, got `{:?}`",
|
||||
arg_types[0],
|
||||
@@ -93,7 +84,7 @@ impl Analyzer {
|
||||
}
|
||||
|
||||
if arg_types[0] == Type::ScalarArray && var_type != Type::Scalar {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Incorrect argument type. Expected `{:?}`, got `{:?}`",
|
||||
arg_types[0],
|
||||
@@ -108,7 +99,7 @@ impl Analyzer {
|
||||
arg.typ = var_type;
|
||||
args.push(arg);
|
||||
} else {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Unknown argument reference `{}`.", i.name),
|
||||
i.line,
|
||||
i.column,
|
||||
@@ -117,7 +108,7 @@ impl Analyzer {
|
||||
}
|
||||
} else {
|
||||
if statement.args.len() != arg_types.len() {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Incorrent number of args to `{:?}` call. Expected {}, got {}",
|
||||
statement.opcode,
|
||||
@@ -138,7 +129,7 @@ impl Analyzer {
|
||||
};
|
||||
|
||||
if var_type != arg_types[idx] {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Incorrect argument type. Expected `{:?}`, got `{:?}`",
|
||||
arg_types[idx], var_type,
|
||||
@@ -152,7 +143,7 @@ impl Analyzer {
|
||||
arg.typ = var_type;
|
||||
args.push(arg);
|
||||
} else {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Unknown argument reference `{}`.", i.name),
|
||||
i.line,
|
||||
i.column,
|
||||
@@ -213,7 +204,7 @@ impl Analyzer {
|
||||
if let Some(index) = stack.iter().position(|&r| r == &arg.name) {
|
||||
println!("Found at stack index {}", index);
|
||||
} else {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Could not find `{}` on the stack", arg.name),
|
||||
arg.line,
|
||||
arg.column,
|
||||
@@ -283,31 +274,6 @@ impl Analyzer {
|
||||
None
|
||||
}
|
||||
|
||||
fn error(&self, msg: String, ln: usize, col: usize) {
|
||||
let err_msg = format!("{} (line {}, column {})", msg, ln, col);
|
||||
let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
|
||||
let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
|
||||
let caret = format!("{:width$}^", "", width = pad);
|
||||
let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
|
||||
Analyzer::abort(&msg);
|
||||
}
|
||||
|
||||
fn abort(msg: &str) {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
write!(
|
||||
handle,
|
||||
"{}{}Semantic error:{} {}",
|
||||
style::Bold,
|
||||
color::Fg(color::Red),
|
||||
style::Reset,
|
||||
msg,
|
||||
)
|
||||
.unwrap();
|
||||
handle.flush().unwrap();
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
fn pause() {
|
||||
let msg = b"[Press Enter to continue]\r";
|
||||
let mut stdout = stdout();
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use std::{io, io::Write, process, str::Chars};
|
||||
use std::str::Chars;
|
||||
|
||||
use termion::{color, style};
|
||||
|
||||
use super::ast::{Constants, StatementType, Statements, Witnesses};
|
||||
use super::{
|
||||
ast::{Constants, StatementType, Statements, Witnesses},
|
||||
error::ErrorEmitter,
|
||||
};
|
||||
use crate::util::serial::{serialize, VarInt};
|
||||
|
||||
/// Version of the binary
|
||||
@@ -11,12 +12,11 @@ pub const BINARY_VERSION: u8 = 1;
|
||||
pub const MAGIC_BYTES: [u8; 4] = [0x0b, 0x00, 0xb1, 0x35];
|
||||
|
||||
pub struct Compiler {
|
||||
file: String,
|
||||
lines: Vec<String>,
|
||||
constants: Constants,
|
||||
witnesses: Witnesses,
|
||||
statements: Statements,
|
||||
debug_info: bool,
|
||||
error: ErrorEmitter,
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
@@ -30,8 +30,10 @@ impl Compiler {
|
||||
) -> Self {
|
||||
// For nice error reporting, we'll load everything into a string
|
||||
// vector so we have references to lines.
|
||||
let lines = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
Compiler { file: filename.to_string(), lines, constants, witnesses, statements, debug_info }
|
||||
let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
let error = ErrorEmitter::new("Compiler", filename, lines.clone());
|
||||
|
||||
Compiler { constants, witnesses, statements, debug_info, error }
|
||||
}
|
||||
|
||||
pub fn compile(&self) -> Vec<u8> {
|
||||
@@ -77,7 +79,7 @@ impl Compiler {
|
||||
continue
|
||||
}
|
||||
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Failed finding a stack reference for `{}`", arg.name),
|
||||
arg.line,
|
||||
arg.column,
|
||||
@@ -104,29 +106,4 @@ impl Compiler {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn error(&self, msg: String, ln: usize, col: usize) {
|
||||
let err_msg = format!("{} (line {}, column {})", msg, ln, col);
|
||||
let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
|
||||
let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
|
||||
let caret = format!("{:width$}^", "", width = pad);
|
||||
let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
|
||||
Compiler::abort(&msg);
|
||||
}
|
||||
|
||||
fn abort(msg: &str) {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
write!(
|
||||
handle,
|
||||
"{}{}Compiler error:{} {}",
|
||||
style::Bold,
|
||||
color::Fg(color::Red),
|
||||
style::Reset,
|
||||
msg,
|
||||
)
|
||||
.unwrap();
|
||||
handle.flush().unwrap();
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
41
src/zkas/error.rs
Normal file
41
src/zkas/error.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use std::{io, io::Write, process};
|
||||
|
||||
use termion::{color, style};
|
||||
|
||||
pub(super) struct ErrorEmitter {
|
||||
namespace: String,
|
||||
file: String,
|
||||
lines: Vec<String>,
|
||||
}
|
||||
|
||||
impl ErrorEmitter {
|
||||
pub fn new(namespace: &str, file: &str, lines: Vec<String>) -> Self {
|
||||
Self { namespace: namespace.to_string(), file: file.to_string(), lines }
|
||||
}
|
||||
|
||||
pub fn emit(&self, msg: String, ln: usize, col: usize) {
|
||||
let err_msg = format!("{} (line{}, column {})", msg, ln, col);
|
||||
let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
|
||||
let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
|
||||
let caret = format!("{:width$}^", "", width = pad);
|
||||
let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
|
||||
self.abort(&msg);
|
||||
}
|
||||
|
||||
fn abort(&self, msg: &str) {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
write!(
|
||||
handle,
|
||||
"{}{}{} error:{} {}",
|
||||
style::Bold,
|
||||
color::Fg(color::Red),
|
||||
self.namespace,
|
||||
style::Reset,
|
||||
msg,
|
||||
)
|
||||
.unwrap();
|
||||
handle.flush().unwrap();
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{io, io::Write, process, str::Chars};
|
||||
use std::str::Chars;
|
||||
|
||||
use termion::{color, style};
|
||||
use super::error::ErrorEmitter;
|
||||
|
||||
#[derive(Hash, Eq, PartialEq, Clone, Debug)]
|
||||
pub enum TokenType {
|
||||
@@ -33,9 +33,8 @@ impl Token {
|
||||
}
|
||||
|
||||
pub struct Lexer<'a> {
|
||||
file: String,
|
||||
lines: Vec<String>,
|
||||
source: Chars<'a>,
|
||||
error: ErrorEmitter,
|
||||
}
|
||||
|
||||
impl<'a> Lexer<'a> {
|
||||
@@ -43,7 +42,9 @@ impl<'a> Lexer<'a> {
|
||||
// For nice error reporting, we'll load everything into a string
|
||||
// vector so we have references to lines.
|
||||
let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
Lexer { file: filename.to_string(), lines, source }
|
||||
let error = ErrorEmitter::new("Lexer", filename, lines.clone());
|
||||
|
||||
Self { source, error }
|
||||
}
|
||||
|
||||
pub fn lex(self) -> Vec<Token> {
|
||||
@@ -78,7 +79,11 @@ impl<'a> Lexer<'a> {
|
||||
|
||||
if in_string {
|
||||
// TODO: Allow newlines in strings?
|
||||
self.error(format!("Invalid ending in string `{}`", &strbuf), lineno, column);
|
||||
self.error.emit(
|
||||
format!("Invalid ending in string `{}`", &strbuf),
|
||||
lineno,
|
||||
column,
|
||||
);
|
||||
}
|
||||
|
||||
in_comment = false;
|
||||
@@ -141,7 +146,7 @@ impl<'a> Lexer<'a> {
|
||||
|
||||
if c == '"' && !in_string {
|
||||
if in_symbol {
|
||||
self.error(format!("Illegal char `{}` for symbol", c), lineno, column);
|
||||
self.error.emit(format!("Illegal char `{}` for symbol", c), lineno, column);
|
||||
}
|
||||
in_string = true;
|
||||
continue
|
||||
@@ -149,7 +154,11 @@ impl<'a> Lexer<'a> {
|
||||
|
||||
if c == '"' && in_string {
|
||||
if strbuf.is_empty() {
|
||||
self.error(format!("Invalid ending in string `{}`", &strbuf), lineno, column);
|
||||
self.error.emit(
|
||||
format!("Invalid ending in string `{}`", &strbuf),
|
||||
lineno,
|
||||
column,
|
||||
);
|
||||
}
|
||||
|
||||
in_string = false;
|
||||
@@ -229,41 +238,16 @@ impl<'a> Lexer<'a> {
|
||||
tokens.push(Token::new("=".to_string(), TokenType::Assign, lineno, column));
|
||||
continue
|
||||
}
|
||||
_ => self.error(format!("Invalid token `{}`", c), lineno, column - 1),
|
||||
_ => self.error.emit(format!("Invalid token `{}`", c), lineno, column - 1),
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
self.error(format!("Invalid token `{}`", c), lineno, column - 1);
|
||||
self.error.emit(format!("Invalid token `{}`", c), lineno, column - 1);
|
||||
}
|
||||
|
||||
tokens
|
||||
}
|
||||
|
||||
fn error(&self, msg: String, ln: usize, col: usize) {
|
||||
let err_msg = format!("{} (line {}, column {})", msg, ln, col);
|
||||
let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
|
||||
let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
|
||||
let caret = format!("{:width$}^", "", width = pad);
|
||||
let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
|
||||
Lexer::abort(&msg);
|
||||
}
|
||||
|
||||
fn abort(msg: &str) {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
write!(
|
||||
handle,
|
||||
"{}{}Lexer error:{} {}",
|
||||
style::Bold,
|
||||
color::Fg(color::Red),
|
||||
style::Reset,
|
||||
msg,
|
||||
)
|
||||
.unwrap();
|
||||
handle.flush().unwrap();
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_letter(ch: char) -> bool {
|
||||
|
||||
@@ -6,6 +6,8 @@ pub mod ast;
|
||||
pub mod compiler;
|
||||
/// Binary decoder
|
||||
pub mod decoder;
|
||||
/// Error emitter
|
||||
mod error;
|
||||
/// Lexer module
|
||||
pub mod lexer;
|
||||
/// Language opcodes
|
||||
|
||||
@@ -1,31 +1,32 @@
|
||||
use std::{io, io::Write, iter::Peekable, process, str::Chars};
|
||||
use std::{iter::Peekable, str::Chars};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use itertools::Itertools;
|
||||
use termion::{color, style};
|
||||
|
||||
use super::{
|
||||
ast::{
|
||||
Constant, Constants, Statement, StatementType, Statements, UnparsedConstants,
|
||||
UnparsedWitnesses, Variable, Witness, Witnesses,
|
||||
},
|
||||
error::ErrorEmitter,
|
||||
lexer::{Token, TokenType},
|
||||
opcode::Opcode,
|
||||
types::Type,
|
||||
};
|
||||
|
||||
pub struct Parser {
|
||||
file: String,
|
||||
lines: Vec<String>,
|
||||
tokens: Vec<Token>,
|
||||
error: ErrorEmitter,
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn new(filename: &str, source: Chars, tokens: Vec<Token>) -> Self {
|
||||
// For nice error reporting, we'll load everything into a string
|
||||
// vector so we have references to lines.
|
||||
let lines = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
Parser { file: filename.to_string(), lines, tokens }
|
||||
let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
let error = ErrorEmitter::new("Parser", filename, lines.clone());
|
||||
|
||||
Parser { tokens, error }
|
||||
}
|
||||
|
||||
pub fn parse(self) -> (Constants, Witnesses, Statements) {
|
||||
@@ -93,7 +94,9 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
x => self.error(format!("Unknown `{}` proof section", x), t.line, t.column),
|
||||
x => {
|
||||
self.error.emit(format!("Unknown `{}` proof section", x), t.line, t.column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +117,7 @@ impl Parser {
|
||||
|
||||
// TODO: Do we need this?
|
||||
if namespace_found && namespace != constant_tokens[0].token {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Found `{}` namespace. Expected `{}`.",
|
||||
constant_tokens[0].token, namespace
|
||||
@@ -134,7 +137,7 @@ impl Parser {
|
||||
|
||||
while let Some((typ, name, comma)) = constants_inner.next_tuple() {
|
||||
if comma.token_type != TokenType::Comma {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Separator is not a comma".to_string(),
|
||||
comma.line,
|
||||
comma.column,
|
||||
@@ -142,7 +145,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if constants_map.contains_key(name.token.as_str()) {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Section `constant` already contains the token `{}`.",
|
||||
&name.token
|
||||
@@ -164,7 +167,7 @@ impl Parser {
|
||||
|
||||
// TODO: Do we need this?
|
||||
if namespace_found && namespace != contract_tokens[0].token {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Found `{}` namespace. Expected `{}`.",
|
||||
contract_tokens[0].token, namespace
|
||||
@@ -184,7 +187,7 @@ impl Parser {
|
||||
|
||||
while let Some((typ, name, comma)) = contract_inner.next_tuple() {
|
||||
if comma.token_type != TokenType::Comma {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Separator is not a comma".to_string(),
|
||||
comma.line,
|
||||
comma.column,
|
||||
@@ -192,7 +195,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if contract_map.contains_key(name.token.as_str()) {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Section `contract` already contains the token `{}`.",
|
||||
&name.token
|
||||
@@ -213,7 +216,7 @@ impl Parser {
|
||||
self.check_section_structure("circuit", contract_tokens.clone());
|
||||
|
||||
if circuit_tokens[circuit_tokens.len() - 2].token_type != TokenType::Semicolon {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Circuit section does not end with a semicolon. Would never finish parsing.".to_string(),
|
||||
circuit_tokens[circuit_tokens.len()-2].line,
|
||||
circuit_tokens[circuit_tokens.len()-2].column
|
||||
@@ -222,7 +225,7 @@ impl Parser {
|
||||
|
||||
// TODO: Do we need this?
|
||||
if namespace_found && namespace != circuit_tokens[0].token {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Found `{}` namespace. Expected `{}`.",
|
||||
circuit_tokens[0].token, namespace
|
||||
@@ -271,7 +274,7 @@ impl Parser {
|
||||
|
||||
fn check_section_structure(&self, section: &str, tokens: Vec<Token>) {
|
||||
if tokens[0].token_type != TokenType::String {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("{} section declaration must start with a naming string.", section),
|
||||
tokens[0].line,
|
||||
tokens[0].column,
|
||||
@@ -279,7 +282,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if tokens[1].token_type != TokenType::LeftBrace {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"{} section opening is not correct. Must be opened with a left brace `{{`",
|
||||
section
|
||||
@@ -290,7 +293,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if tokens[tokens.len() - 1].token_type != TokenType::RightBrace {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"{} section closing is not correct. Must be closed with a right brace `}}`",
|
||||
section
|
||||
@@ -303,7 +306,7 @@ impl Parser {
|
||||
if (section == "constant" || section == "contract") &&
|
||||
tokens[2..tokens.len() - 1].len() % 3 != 0
|
||||
{
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!(
|
||||
"Invalid number of elements in `{}` section. Must be pairs of `type:name` separated with a comma `,`",
|
||||
section
|
||||
@@ -319,7 +322,7 @@ impl Parser {
|
||||
|
||||
for (k, v) in ast {
|
||||
if &v.0.token != k {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Constant name `{}` doesn't match token `{}`.", v.0.token, k),
|
||||
v.0.line,
|
||||
v.0.column,
|
||||
@@ -327,7 +330,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if v.0.token_type != TokenType::Symbol {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Constant name `{}` is not a symbol.", v.0.token),
|
||||
v.0.line,
|
||||
v.0.column,
|
||||
@@ -335,7 +338,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if v.1.token_type != TokenType::Symbol {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Constant type `{}` is not a symbol.", v.1.token),
|
||||
v.1.line,
|
||||
v.1.column,
|
||||
@@ -353,7 +356,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
x => {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("`{}` is an illegal constant type", x),
|
||||
v.1.line,
|
||||
v.1.column,
|
||||
@@ -370,7 +373,7 @@ impl Parser {
|
||||
|
||||
for (k, v) in ast {
|
||||
if &v.0.token != k {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Witness name `{}` doesn't match token `{}`.", v.0.token, k),
|
||||
v.0.line,
|
||||
v.0.column,
|
||||
@@ -378,7 +381,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if v.0.token_type != TokenType::Symbol {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Witness name `{}` is not a symbol.", v.0.token),
|
||||
v.0.line,
|
||||
v.0.column,
|
||||
@@ -386,7 +389,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if v.1.token_type != TokenType::Symbol {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Witness type `{}` is not a symbol.", v.1.token),
|
||||
v.1.line,
|
||||
v.1.column,
|
||||
@@ -440,7 +443,11 @@ impl Parser {
|
||||
}
|
||||
|
||||
x => {
|
||||
self.error(format!("`{}` is an illegal witness type", x), v.1.line, v.1.column);
|
||||
self.error.emit(
|
||||
format!("`{}` is an illegal witness type", x),
|
||||
v.1.line,
|
||||
v.1.column,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -461,7 +468,7 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
if left_paren != right_paren {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Incorrect number of left and right parenthesis for statement.".to_string(),
|
||||
statement[0].line,
|
||||
statement[0].column,
|
||||
@@ -508,7 +515,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if !parsing {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Illegal token `{}`", next_token.token),
|
||||
next_token.line,
|
||||
next_token.column,
|
||||
@@ -614,7 +621,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
x => {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
format!("Unimplemented function call `{}`", x),
|
||||
token.line,
|
||||
token.column,
|
||||
@@ -635,7 +642,7 @@ impl Parser {
|
||||
) -> Vec<Variable> {
|
||||
if let Some(next_token) = iter.peek() {
|
||||
if next_token.token_type != TokenType::LeftParen {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Invalid function call opening. Must start with a `(`".to_string(),
|
||||
next_token.line,
|
||||
next_token.column,
|
||||
@@ -644,7 +651,7 @@ impl Parser {
|
||||
// Skip the opening parenthesis
|
||||
iter.next();
|
||||
} else {
|
||||
self.error("Premature ending of statement".to_string(), token.line, token.column);
|
||||
self.error.emit("Premature ending of statement".to_string(), token.line, token.column);
|
||||
}
|
||||
|
||||
// Eat up function arguments
|
||||
@@ -663,7 +670,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
if sep.token_type != TokenType::Comma {
|
||||
self.error(
|
||||
self.error.emit(
|
||||
"Argument separator is not a comma (`,`)".to_string(),
|
||||
sep.line,
|
||||
sep.column,
|
||||
@@ -673,29 +680,4 @@ impl Parser {
|
||||
|
||||
args
|
||||
}
|
||||
|
||||
fn error(&self, msg: String, ln: usize, col: usize) {
|
||||
let err_msg = format!("{} (line {}, column {})", msg, ln, col);
|
||||
let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
|
||||
let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
|
||||
let caret = format!("{:width$}^", "", width = pad);
|
||||
let msg = format!("{}\n{}\n{}\n", err_msg, dbg_msg, caret);
|
||||
Parser::abort(&msg);
|
||||
}
|
||||
|
||||
fn abort(msg: &str) {
|
||||
let stderr = io::stderr();
|
||||
let mut handle = stderr.lock();
|
||||
write!(
|
||||
handle,
|
||||
"{}{}Parser error:{} {}",
|
||||
style::Bold,
|
||||
color::Fg(color::Red),
|
||||
style::Reset,
|
||||
msg,
|
||||
)
|
||||
.unwrap();
|
||||
handle.flush().unwrap();
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user