Removes JSON serde, moves slots computation logic to appointment.rs

The JSON serialization logic was added to deal with data storage. Given won't be using LevelDB for this implementation, but a SQL database, all that serialization logic in unnecessary.
This commit is contained in:
Sergi Delgado Segura 2021-10-18 17:22:35 +02:00
parent 66868fd0b1
commit b5da110cbb
No known key found for this signature in database
GPG key ID: 633B3A2298D70DD8
6 changed files with 39 additions and 188 deletions

View file

@ -7,8 +7,6 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = {version = "1.0.126", features = ["derive"]}
serde_json = "1.0"
uuid = { version = "0.8", features = ["serde", "v4"] }
hex = "0.4.3"

View file

@ -1,11 +1,9 @@
use hex;
use serde::{Deserialize, Serialize};
use serde_json::{Error as JSONError, Value};
use std::fmt;
use bitcoin::Txid;
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone, Hash)]
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct Locator([u8; 16]);
impl Locator {
@ -15,19 +13,30 @@ impl Locator {
Locator(raw_locator)
}
pub fn to_vec(&self) -> Vec<u8> {
pub fn serialize(&self) -> Vec<u8> {
self.0.to_vec()
}
pub fn deserialize(data: Vec<u8>) -> Result<Self, ()> {
if data.len() == 16 {
let mut raw_locator = [0; 16];
raw_locator.copy_from_slice(&data);
Ok(Self(raw_locator))
} else {
// TODO: Maybe add a more expressive error?
Err(())
}
}
}
impl std::fmt::Display for Locator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", hex::encode(self.to_vec()))
write!(f, "{}", hex::encode(self.serialize()))
}
}
/// Contains data regarding an appointment between a client and the Watchtower. An appointment is requested for every new channel update.
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Appointment {
pub locator: Locator,
pub encrypted_blob: Vec<u8>,
@ -50,14 +59,6 @@ impl Appointment {
}
}
pub fn from_json(data: &str) -> Result<Self, JSONError> {
serde_json::from_str::<Appointment>(data)
}
pub fn to_json(self) -> Value {
serde_json::to_value(&self).unwrap()
}
/// Serializes an appointment to be signed.
/// The serialization follows the same ordering as the fields in the appointment:
///
@ -65,44 +66,9 @@ impl Appointment {
///
/// All values are big endian.
pub fn serialize(&self) -> Vec<u8> {
let mut result = self.locator.to_vec();
let mut result = self.locator.serialize();
result.extend(&self.encrypted_blob);
result.extend(self.to_self_delay.to_be_bytes().to_vec());
result
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_from_json() {
let locator = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let encrypted_blob = [1, 2, 3, 4].to_vec();
let to_self_delay = 21;
let appointment = Appointment::new(locator, encrypted_blob.clone(), to_self_delay);
let data = json!(appointment).to_string();
let a = Appointment::from_json(&data).unwrap();
assert_eq!(a.locator, Locator(locator));
assert_eq!(a.encrypted_blob, encrypted_blob);
assert_eq!(a.to_self_delay, to_self_delay);
}
#[test]
fn test_to_json() {
let locator = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let encrypted_blob = [1, 2, 3, 4].to_vec();
let to_self_delay = 21;
let appointment = Appointment::new(locator, encrypted_blob.clone(), to_self_delay);
let a_json = appointment.to_json();
assert_eq!(a_json["locator"], json!(locator));
assert_eq!(a_json["encrypted_blob"], json!(encrypted_blob));
assert_eq!(a_json["to_self_delay"], json!(to_self_delay));
}
}

View file

@ -3,65 +3,17 @@ pub mod constants;
pub mod cryptography;
pub mod receipts;
use serde::de::{self, SeqAccess, Unexpected, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use bitcoin::secp256k1::PublicKey;
use bitcoin::secp256k1::{Error, PublicKey};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct UserId(pub PublicKey);
struct UserIdVisitor;
impl UserId {
pub fn serialize(&self) -> Vec<u8> {
self.0.serialize().to_vec()
}
impl Serialize for UserId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(&self.0.serialize())
}
}
impl<'de> Visitor<'de> for UserIdVisitor {
type Value = UserId;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a 33-byte long array or sequence")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
match PublicKey::from_slice(v) {
Ok(pk) => Ok(UserId(pk)),
Err(_) => Err(de::Error::invalid_value(Unexpected::Bytes(v), &self)),
}
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut vec = Vec::new();
while let Some(elem) = seq.next_element()? {
vec.push(elem);
}
match PublicKey::from_slice(&vec) {
Ok(pk) => Ok(UserId(pk)),
Err(_) => Err(de::Error::invalid_value(Unexpected::Seq, &self)),
}
}
}
impl<'de> Deserialize<'de> for UserId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_bytes(UserIdVisitor)
pub fn deserialize(data: &[u8]) -> Result<Self, Error> {
Ok(UserId(PublicKey::from_slice(data)?))
}
}

View file

@ -13,7 +13,6 @@ base64 = "0.13.0"
futures = "0.3"
log = "0.4"
simple_logger = "1.12.1"
serde = "1.0.126"
serde_json = "1.0"
tokio = { version = "1.5", features = [ "io-util", "macros", "rt", "rt-multi-thread", "sync", "net", "time" ] }

View file

@ -1,5 +1,3 @@
use serde::{Deserialize, Serialize};
use serde_json::{Error as JSONError, Value};
use std::fmt;
use bitcoin::hashes::{ripemd160, Hash};
@ -7,15 +5,19 @@ use bitcoin::hashes::{ripemd160, Hash};
use teos_common::appointment::{Appointment, Locator};
use teos_common::UserId;
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct UUID(pub [u8; 20]);
impl UUID {
pub fn new(locator: &Locator, user_id: &UserId) -> Self {
let mut uuid_data = locator.to_vec();
let mut uuid_data = locator.serialize();
uuid_data.extend(&user_id.0.serialize());
UUID(ripemd160::Hash::hash(&uuid_data).into_inner())
}
pub fn serialize(&self) -> Vec<u8> {
self.0.to_vec()
}
}
impl std::fmt::Display for UUID {
@ -24,7 +26,7 @@ impl std::fmt::Display for UUID {
}
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct ExtendedAppointment {
pub inner: Appointment,
pub user_id: UserId,
@ -32,7 +34,6 @@ pub struct ExtendedAppointment {
pub start_block: u32,
}
#[derive(Serialize, Deserialize)]
pub struct AppointmentSummary {
locator: Locator,
user_id: UserId,
@ -59,14 +60,10 @@ impl ExtendedAppointment {
user_id: self.user_id,
}
}
}
pub fn from_json(data: &str) -> Result<Self, JSONError> {
serde_json::from_str::<ExtendedAppointment>(data)
}
pub fn to_json(self) -> Value {
serde_json::to_value(&self).unwrap()
}
pub fn compute_appointment_slots(blob_size: usize, blob_max_size: usize) -> u32 {
(blob_size as f32 / blob_max_size as f32).ceil() as u32
}
#[cfg(test)]
@ -74,7 +71,6 @@ mod tests {
use super::*;
use bitcoin::secp256k1::key::ONE_KEY;
use bitcoin::secp256k1::{PublicKey, Secp256k1};
use serde_json::json;
use teos_common::appointment::Appointment;
use teos_common::UserId;
@ -92,56 +88,4 @@ mod tests {
assert_eq!(e.inner.locator, s.locator);
assert_eq!(e.user_id, s.user_id);
}
#[test]
fn test_from_json() {
let locator = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let encrypted_blob = [1, 2, 3, 4].to_vec();
let to_self_delay = 21;
let appointment = Appointment::new(locator, encrypted_blob, to_self_delay);
let user_id = UserId(PublicKey::from_secret_key(&Secp256k1::new(), &ONE_KEY));
let user_signature = String::new();
let start_block = 42;
let data = json!({
"inner": appointment,
"user_id": user_id,
"user_signature": user_signature,
"start_block": start_block,
})
.to_string();
let e = ExtendedAppointment::from_json(&data).unwrap();
assert_eq!(e.inner, appointment);
assert_eq!(e.user_id, user_id);
assert_eq!(e.user_signature, user_signature);
assert_eq!(e.start_block, start_block);
}
#[test]
fn test_to_json() {
let locator = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
let encrypted_blob = [1, 2, 3, 4].to_vec();
let to_self_delay = 21;
let appointment = Appointment::new(locator, encrypted_blob, to_self_delay);
let user_id = UserId(PublicKey::from_secret_key(&Secp256k1::new(), &ONE_KEY));
let user_signature = String::new();
let start_block = 42;
let extended_appointment = ExtendedAppointment::new(
appointment.clone(),
user_id,
user_signature.clone(),
start_block,
);
let e_json = extended_appointment.to_json();
assert_eq!(e_json["inner"], json!(appointment));
assert_eq!(e_json["user_id"], json!(user_id));
assert_eq!(e_json["user_signature"], json!(user_signature));
assert_eq!(e_json["start_block"], json!(start_block));
}
}

View file

@ -1,5 +1,3 @@
use serde::{Deserialize, Serialize};
use serde_json::{Error as JSONError, Value};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
@ -11,9 +9,9 @@ use teos_common::cryptography;
use teos_common::receipts::RegistrationReceipt;
use teos_common::UserId;
use crate::extended_appointment::{ExtendedAppointment, UUID};
use crate::extended_appointment::{compute_appointment_slots, ExtendedAppointment, UUID};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UserInfo {
pub(crate) available_slots: u32,
pub(crate) subscription_expiry: u32,
@ -28,13 +26,6 @@ impl UserInfo {
appointments: HashMap::new(),
}
}
pub fn from_json(data: &str) -> Result<Self, JSONError> {
serde_json::from_str::<UserInfo>(data)
}
pub fn to_json(self) -> Value {
serde_json::to_value(&self).unwrap()
}
}
#[derive(Debug, PartialEq)]
@ -143,9 +134,10 @@ impl Gatekeeper {
let user_info = borrowed.get_mut(user_id).unwrap();
let used_slots = user_info.appointments.get(&uuid).map_or(0, |x| x.clone());
let required_slots = (appointment.inner.encrypted_blob.len() as f32
/ ENCRYPTED_BLOB_MAX_SIZE as f32)
.ceil() as u32;
let required_slots = compute_appointment_slots(
appointment.inner.encrypted_blob.len(),
ENCRYPTED_BLOB_MAX_SIZE,
);
let diff = required_slots as i64 - used_slots as i64;
if diff <= user_info.available_slots as i64 {