This commit is contained in:
mohab
2022-02-06 14:45:56 +02:00
43 changed files with 758 additions and 727 deletions

View File

@@ -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"]

View File

@@ -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)

View File

@@ -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),

View File

@@ -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"
}
}

View File

@@ -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()
}
}

View File

@@ -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};

View File

@@ -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);
//}

View File

@@ -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
View 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()
}
}

View File

@@ -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);
//}

View File

@@ -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);
}
}

View File

@@ -1,2 +0,0 @@
//pub type NodeId = String;
//pub type NodeInfo = String;

View File

@@ -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![
Spans::from(format!("NodeId: {}", id)),
Spans::from(format!("Number of connections: {}", connections)),

View File

@@ -107,7 +107,7 @@ tutorial](https://bitzuma.com/posts/a-beginners-guide-to-the-electrum-bitcoin-wa
for more details.
For Solana, you can either install the Solana command-line suite or use
[sollet](sollet.io).
[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

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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()) {

View File

@@ -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::{

View File

@@ -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" },

View File

@@ -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};

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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"
}
}

View 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;
}

View File

@@ -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"
}
}

View 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
}
}

View File

@@ -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"
}
}

View File

@@ -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]");

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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;

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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;
}

View File

@@ -1,7 +1,4 @@
pub mod circuit;
#[cfg(feature = "zkvm")]
/// Halo2 zkas virtual machine
pub mod vm;
#[cfg(feature = "zkvm")]
mod vm_stack;

View File

@@ -1,4 +1,4 @@
//! Stack type abstractions
//! VM stack type abstractions
use halo2_gadgets::{
ecc::{chip::EccChip, FixedPoint, Point},
utilities::CellValue,

View File

@@ -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();

View File

@@ -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
View 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);
}
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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);
}
}