Skip to content

Commit 1ac06d2

Browse files
progress on client
1 parent e6f79b2 commit 1ac06d2

5 files changed

Lines changed: 76 additions & 25 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ documentation = "https://docs.rs/alto-client"
1212

1313
[dependencies]
1414
alto-types = { workspace = true }
15+
commonware-codec = { workspace = true }
16+
commonware-consensus = { workspace = true }
1517
commonware-cryptography = { workspace = true }
1618
commonware-utils = { workspace = true }
1719
bytes = { workspace = true }

client/src/consensus.rs

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use crate::{Client, Error, IndexQuery, Query};
2-
use alto_types::{Block, Finalized, Kind, Notarized, Seed};
2+
use alto_types::{Block, Finalized, Kind, Notarized, NAMESPACE};
33
use bytes::Bytes;
4+
use commonware_codec::DecodeExt;
5+
use commonware_consensus::threshold_simplex::types::{Seed, Viewable};
6+
use commonware_cryptography::Digestible;
47
use futures::{channel::mpsc::unbounded, Stream, StreamExt};
58
use tokio_tungstenite::{connect_async, tungstenite::Message as TMessage};
69

@@ -76,18 +79,21 @@ impl Client {
7679
return Err(Error::Failed(result.status()));
7780
}
7881
let bytes = result.bytes().await.map_err(Error::Reqwest)?;
79-
let result = Seed::deserialize(Some(&self.public), &bytes).ok_or(Error::InvalidData)?;
82+
let seed = Seed::decode(bytes.as_ref()).map_err(Error::InvalidData)?;
83+
if !seed.verify(NAMESPACE, self.public.as_ref()) {
84+
return Err(Error::InvalidSignature);
85+
}
8086

8187
// Verify the seed matches the query
8288
match query {
8389
IndexQuery::Latest => {}
8490
IndexQuery::Index(index) => {
85-
if result.view != index {
86-
return Err(Error::InvalidData);
91+
if seed.view() != index {
92+
return Err(Error::UnexpectedResponse);
8793
}
8894
}
8995
}
90-
Ok(result)
96+
Ok(seed)
9197
}
9298

9399
pub async fn notarization_upload(&self, notarized: Bytes) -> Result<(), Error> {
@@ -116,19 +122,21 @@ impl Client {
116122
return Err(Error::Failed(result.status()));
117123
}
118124
let bytes = result.bytes().await.map_err(Error::Reqwest)?;
119-
let result =
120-
Notarized::deserialize(Some(&self.public), &bytes).ok_or(Error::InvalidData)?;
125+
let notarized = Notarized::decode(bytes.as_ref()).map_err(Error::InvalidData)?;
126+
if !notarized.verify(self.public.as_ref()) {
127+
return Err(Error::InvalidSignature);
128+
}
121129

122130
// Verify the notarization matches the query
123131
match query {
124132
IndexQuery::Latest => {}
125133
IndexQuery::Index(index) => {
126-
if result.proof.view != index {
127-
return Err(Error::InvalidData);
134+
if notarized.proof.view() != index {
135+
return Err(Error::UnexpectedResponse);
128136
}
129137
}
130138
}
131-
Ok(result)
139+
Ok(notarized)
132140
}
133141

134142
pub async fn finalization_upload(&self, finalized: Bytes) -> Result<(), Error> {
@@ -157,19 +165,21 @@ impl Client {
157165
return Err(Error::Failed(result.status()));
158166
}
159167
let bytes = result.bytes().await.map_err(Error::Reqwest)?;
160-
let result =
161-
Finalized::deserialize(Some(&self.public), &bytes).ok_or(Error::InvalidData)?;
168+
let finalized = Finalized::decode(bytes.as_ref()).map_err(Error::InvalidData)?;
169+
if !finalized.verify(self.public.as_ref()) {
170+
return Err(Error::InvalidSignature);
171+
}
162172

163173
// Verify the finalization matches the query
164174
match query {
165175
IndexQuery::Latest => {}
166176
IndexQuery::Index(index) => {
167-
if result.proof.view != index {
168-
return Err(Error::InvalidData);
177+
if finalized.proof.view() != index {
178+
return Err(Error::UnexpectedResponse);
169179
}
170180
}
171181
}
172-
Ok(result)
182+
Ok(finalized)
173183
}
174184

175185
pub async fn block_get(&self, query: Query) -> Result<Payload, Error> {
@@ -188,22 +198,26 @@ impl Client {
188198
// Verify the block matches the query
189199
let result = match query {
190200
Query::Latest => {
191-
let result =
192-
Finalized::deserialize(Some(&self.public), &bytes).ok_or(Error::InvalidData)?;
201+
let result = Finalized::decode(bytes.as_ref()).map_err(Error::InvalidData)?;
202+
if !result.verify(self.public.as_ref()) {
203+
return Err(Error::InvalidSignature);
204+
}
193205
Payload::Finalized(Box::new(result))
194206
}
195207
Query::Index(index) => {
196-
let result =
197-
Finalized::deserialize(Some(&self.public), &bytes).ok_or(Error::InvalidData)?;
208+
let result = Finalized::decode(bytes.as_ref()).map_err(Error::InvalidData)?;
209+
if !result.verify(self.public.as_ref()) {
210+
return Err(Error::InvalidSignature);
211+
}
198212
if result.block.height != index {
199-
return Err(Error::InvalidData);
213+
return Err(Error::UnexpectedResponse);
200214
}
201215
Payload::Finalized(Box::new(result))
202216
}
203217
Query::Digest(digest) => {
204-
let result = Block::deserialize(&bytes).ok_or(Error::InvalidData)?;
218+
let result = Block::decode(bytes.as_ref()).map_err(Error::InvalidData)?;
205219
if result.digest() != digest {
206-
return Err(Error::InvalidData);
220+
return Err(Error::UnexpectedResponse);
207221
}
208222
Payload::Block(result)
209223
}

client/src/lib.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,12 @@ pub enum Error {
4747
Tungstenite(#[from] tokio_tungstenite::tungstenite::Error),
4848
#[error("failed: {0}")]
4949
Failed(reqwest::StatusCode),
50-
#[error("invalid data")]
51-
InvalidData,
50+
#[error("invalid data: {0}")]
51+
InvalidData(#[from] commonware_codec::Error),
52+
#[error("invalid signature")]
53+
InvalidSignature,
54+
#[error("unexpected response")]
55+
UnexpectedResponse,
5256
}
5357

5458
#[derive(Clone)]

types/src/lib.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,41 @@
33
mod block;
44
pub use block::{Block, Finalized, Notarized};
55
mod consensus;
6+
use commonware_utils::hex;
67
pub use consensus::leader_index;
78
pub mod wasm;
89

9-
// We don't use functions here to guard against silent changes.
1010
pub const NAMESPACE: &[u8] = b"_ALTO";
1111

12+
#[repr(u8)]
13+
pub enum Kind {
14+
Seed = 0,
15+
Notarization = 1,
16+
Nullification = 2,
17+
Finalization = 3,
18+
}
19+
20+
impl Kind {
21+
pub fn from_u8(value: u8) -> Option<Self> {
22+
match value {
23+
0 => Some(Self::Seed),
24+
1 => Some(Self::Notarization),
25+
2 => Some(Self::Nullification),
26+
3 => Some(Self::Finalization),
27+
_ => None,
28+
}
29+
}
30+
31+
pub fn to_hex(&self) -> String {
32+
match self {
33+
Self::Seed => hex(&[0]),
34+
Self::Notarization => hex(&[1]),
35+
Self::Nullification => hex(&[2]),
36+
Self::Finalization => hex(&[3]),
37+
}
38+
}
39+
}
40+
1241
#[cfg(test)]
1342
mod tests {
1443
use super::*;

0 commit comments

Comments
 (0)