use crate::{utils, Error, PublicKey, XorName};
use bincode::serialized_size;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
fmt::{self, Debug, Formatter},
u64,
};
pub const MAX_CHUNK_SIZE_IN_BYTES: u64 = 1024 * 1024 + 10 * 1024;
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
pub struct PrivateChunk {
address: Address,
value: Vec<u8>,
owner: PublicKey,
}
impl PrivateChunk {
pub fn new(value: Vec<u8>, owner: PublicKey) -> Self {
let address = Address::Private(XorName::from_content(&[&value, &owner.to_bytes()]));
Self {
address,
value,
owner,
}
}
pub fn value(&self) -> &Vec<u8> {
&self.value
}
pub fn owner(&self) -> &PublicKey {
&self.owner
}
pub fn address(&self) -> &Address {
&self.address
}
pub fn name(&self) -> &XorName {
self.address.name()
}
pub fn payload_size(&self) -> usize {
self.value.len()
}
pub fn serialised_size(&self) -> u64 {
serialized_size(&self.serialised_structure()).unwrap_or(u64::MAX)
}
pub fn validate_size(&self) -> bool {
self.serialised_size() <= MAX_CHUNK_SIZE_IN_BYTES
}
fn serialised_structure(&self) -> (&[u8], &PublicKey) {
(&self.value, &self.owner)
}
}
impl Serialize for PrivateChunk {
fn serialize<S: Serializer>(&self, serialiser: S) -> Result<S::Ok, S::Error> {
self.serialised_structure().serialize(serialiser)
}
}
impl<'de> Deserialize<'de> for PrivateChunk {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let (value, owner) = Deserialize::deserialize(deserializer)?;
Ok(Self::new(value, owner))
}
}
impl Debug for PrivateChunk {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "PrivateChunk {:?}", self.name())
}
}
#[derive(Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct PublicChunk {
address: Address,
value: Vec<u8>,
}
impl PublicChunk {
pub fn new(value: Vec<u8>) -> Self {
Self {
address: Address::Public(XorName::from_content(&[&value])),
value,
}
}
pub fn value(&self) -> &Vec<u8> {
&self.value
}
pub fn address(&self) -> &Address {
&self.address
}
pub fn name(&self) -> &XorName {
self.address.name()
}
pub fn payload_size(&self) -> usize {
self.value.len()
}
pub fn serialised_size(&self) -> u64 {
serialized_size(self).unwrap_or(u64::MAX)
}
pub fn validate_size(&self) -> bool {
self.serialised_size() <= MAX_CHUNK_SIZE_IN_BYTES
}
}
impl Serialize for PublicChunk {
fn serialize<S: Serializer>(&self, serialiser: S) -> Result<S::Ok, S::Error> {
self.value.serialize(serialiser)
}
}
impl<'de> Deserialize<'de> for PublicChunk {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let value: Vec<u8> = Deserialize::deserialize(deserializer)?;
Ok(PublicChunk::new(value))
}
}
impl Debug for PublicChunk {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "PublicChunk {:?}", self.name())
}
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, Debug)]
pub enum Kind {
Private,
Pub,
}
impl Kind {
pub fn from_flag(published: bool) -> Self {
if published {
Kind::Pub
} else {
Kind::Private
}
}
pub fn is_public(self) -> bool {
self == Kind::Pub
}
pub fn is_private(self) -> bool {
!self.is_public()
}
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, Debug)]
pub enum Address {
Private(XorName),
Public(XorName),
}
impl Address {
pub fn from_kind(kind: Kind, name: XorName) -> Self {
match kind {
Kind::Pub => Address::Public(name),
Kind::Private => Address::Private(name),
}
}
pub fn kind(&self) -> Kind {
match self {
Address::Private(_) => Kind::Private,
Address::Public(_) => Kind::Pub,
}
}
pub fn name(&self) -> &XorName {
match self {
Address::Private(ref name) | Address::Public(ref name) => name,
}
}
pub fn is_public(&self) -> bool {
self.kind().is_public()
}
pub fn is_private(&self) -> bool {
self.kind().is_private()
}
pub fn encode_to_zbase32(&self) -> Result<String, Error> {
utils::encode(&self)
}
pub fn decode_from_zbase32<T: AsRef<str>>(encoded: T) -> Result<Self, Error> {
utils::decode(encoded)
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, Debug)]
pub enum Chunk {
Private(PrivateChunk),
Public(PublicChunk),
}
impl Chunk {
pub fn address(&self) -> &Address {
match self {
Chunk::Private(chunk) => chunk.address(),
Chunk::Public(chunk) => chunk.address(),
}
}
pub fn name(&self) -> &XorName {
self.address().name()
}
pub fn owner(&self) -> Option<&PublicKey> {
match self {
Chunk::Private(chunk) => Some(chunk.owner()),
_ => None,
}
}
pub fn kind(&self) -> Kind {
self.address().kind()
}
pub fn is_public(&self) -> bool {
self.kind().is_public()
}
pub fn is_private(&self) -> bool {
self.kind().is_private()
}
pub fn value(&self) -> &Vec<u8> {
match self {
Chunk::Private(chunk) => chunk.value(),
Chunk::Public(chunk) => chunk.value(),
}
}
pub fn validate_size(&self) -> bool {
match self {
Chunk::Private(chunk) => chunk.validate_size(),
Chunk::Public(chunk) => chunk.validate_size(),
}
}
pub fn serialised_size(&self) -> u64 {
match self {
Chunk::Private(chunk) => chunk.serialised_size(),
Chunk::Public(chunk) => chunk.serialised_size(),
}
}
}
impl From<PrivateChunk> for Chunk {
fn from(chunk: PrivateChunk) -> Self {
Chunk::Private(chunk)
}
}
impl From<PublicChunk> for Chunk {
fn from(chunk: PublicChunk) -> Self {
Chunk::Public(chunk)
}
}
#[cfg(test)]
mod tests {
use super::{Address, PrivateChunk, PublicChunk, PublicKey, XorName};
use crate::{utils, Result};
use hex::encode;
use rand::{self, Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
use std::{env, iter, thread};
use threshold_crypto::SecretKey;
#[test]
fn deterministic_name() {
let chunk1 = b"Hello".to_vec();
let chunk2 = b"Goodbye".to_vec();
let owner1 = PublicKey::Bls(SecretKey::random().public_key());
let owner2 = PublicKey::Bls(SecretKey::random().public_key());
let ichunk1 = PrivateChunk::new(chunk1.clone(), owner1);
let ichunk2 = PrivateChunk::new(chunk1, owner2);
let ichunk3 = PrivateChunk::new(chunk2.clone(), owner1);
let ichunk3_clone = PrivateChunk::new(chunk2, owner1);
assert_eq!(ichunk3, ichunk3_clone);
assert_ne!(ichunk1.name(), ichunk2.name());
assert_ne!(ichunk1.name(), ichunk3.name());
assert_ne!(ichunk2.name(), ichunk3.name());
}
#[test]
fn deterministic_test() {
let value = "immutable chunk value".to_owned().into_bytes();
let chunk = PublicChunk::new(value);
let chunk_name = encode(chunk.name().0.as_ref());
let expected_name = "920f9a03bc90af3a7bfaf50c03abd5ff5b1579bd4006ba28eebcf240d4922519";
assert_eq!(&expected_name, &chunk_name);
}
#[test]
fn serialisation() -> Result<()> {
let mut rng = get_rng();
let len = rng.gen_range(1, 10_000);
let value = iter::repeat_with(|| rng.gen()).take(len).collect();
let chunk = PublicChunk::new(value);
let serialised = utils::serialise(&chunk)?;
let parsed = utils::deserialise(&serialised)?;
assert_eq!(chunk, parsed);
Ok(())
}
fn get_rng() -> XorShiftRng {
let env_var_name = "RANDOM_SEED";
let seed = env::var(env_var_name)
.map(|res| res.parse::<u64>().unwrap_or_else(|_| rand::random()))
.unwrap_or_else(|_| rand::random());
println!(
"To replay this '{}', set env var {}={}",
thread::current().name().unwrap_or(""),
env_var_name,
seed
);
XorShiftRng::seed_from_u64(seed)
}
#[test]
fn zbase32_encode_decode_chunk_address() -> Result<()> {
let name = XorName::random();
let address = Address::Public(name);
let encoded = address.encode_to_zbase32()?;
let decoded = self::Address::decode_from_zbase32(&encoded)?;
assert_eq!(address, decoded);
Ok(())
}
}