Skip to content

Commit

Permalink
Merge pull request #13 from freenet/186394182-minor-store-fixes
Browse files Browse the repository at this point in the history
Consistency changes in key construction
  • Loading branch information
iduartgomez committed Nov 8, 2023
2 parents f364755 + 525d44c commit 08d0017
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 99 deletions.
1 change: 0 additions & 1 deletion rust/Cargo.toml
Expand Up @@ -10,7 +10,6 @@ repository = "https://github.com/freenet/freenet-stdlib"

[dependencies]
arbitrary = { version = "1", optional = true, features = ["derive"] }
arrayvec = { version = "0.7", features = ["serde"] }
bincode = "1"
byteorder = "1"
blake3 = { version = "1", features = ["std", "traits-preview"] }
Expand Down
10 changes: 5 additions & 5 deletions rust/src/client_api/client_events.rs
Expand Up @@ -645,7 +645,7 @@ impl HostResponse {
match self {
HostResponse::ContractResponse(res) => match res {
ContractResponse::PutResponse { key } => {
let instance_data = builder.create_vector(key.bytes());
let instance_data = builder.create_vector(key.as_bytes());
let instance_offset = ContractInstanceId::create(
&mut builder,
&ContractInstanceIdArgs {
Expand Down Expand Up @@ -691,7 +691,7 @@ impl HostResponse {
Ok(builder.finished_data().to_vec())
}
ContractResponse::UpdateResponse { key, summary } => {
let instance_data = builder.create_vector(key.bytes());
let instance_data = builder.create_vector(key.as_bytes());
let instance_offset = ContractInstanceId::create(
&mut builder,
&ContractInstanceIdArgs {
Expand Down Expand Up @@ -745,7 +745,7 @@ impl HostResponse {
contract: contract_container,
state,
} => {
let instance_data = builder.create_vector(key.bytes());
let instance_data = builder.create_vector(key.as_bytes());
let instance_offset = ContractInstanceId::create(
&mut builder,
&ContractInstanceIdArgs {
Expand All @@ -763,7 +763,7 @@ impl HostResponse {
);

let container_offset = if let Some(contract) = contract_container {
let data = builder.create_vector(contract.key().bytes());
let data = builder.create_vector(contract.key().as_bytes());

let instance_offset = ContractInstanceId::create(
&mut builder,
Expand Down Expand Up @@ -851,7 +851,7 @@ impl HostResponse {
Ok(builder.finished_data().to_vec())
}
ContractResponse::UpdateNotification { key, update } => {
let instance_data = builder.create_vector(key.bytes());
let instance_data = builder.create_vector(key.as_bytes());
let instance_offset = ContractInstanceId::create(
&mut builder,
&ContractInstanceIdArgs {
Expand Down
35 changes: 33 additions & 2 deletions rust/src/code_hash.rs
@@ -1,4 +1,4 @@
use std::fmt::Display;
use std::{fmt::Display, ops::Deref};

use blake3::{traits::digest::Digest, Hasher as Blake3};
use serde::{Deserialize, Serialize};
Expand All @@ -12,7 +12,11 @@ const CONTRACT_KEY_SIZE: usize = 32;
pub struct CodeHash(#[serde_as(as = "[_; CONTRACT_KEY_SIZE]")] pub(crate) [u8; CONTRACT_KEY_SIZE]);

impl CodeHash {
pub fn new(wasm_code: &[u8]) -> Self {
pub const fn new(value: [u8; CONTRACT_KEY_SIZE]) -> Self {
Self(value)
}

pub fn from_code(wasm_code: &[u8]) -> Self {
let mut hasher = Blake3::new();
hasher.update(wasm_code);
let hashed = hasher.finalize();
Expand All @@ -29,12 +33,39 @@ impl CodeHash {
}
}

impl Deref for CodeHash {
type Target = [u8; CONTRACT_KEY_SIZE];

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl AsRef<[u8]> for CodeHash {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}

impl From<&[u8; CONTRACT_KEY_SIZE]> for CodeHash {
fn from(value: &[u8; CONTRACT_KEY_SIZE]) -> Self {
Self(*value)
}
}

impl TryFrom<&[u8]> for CodeHash {
type Error = std::io::Error;

fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() != CONTRACT_KEY_SIZE {
return Err(std::io::ErrorKind::InvalidData.into());
}
let mut this = [0u8; CONTRACT_KEY_SIZE];
this.copy_from_slice(value);
Ok(Self(this))
}
}

impl Display for CodeHash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.encode())
Expand Down
125 changes: 64 additions & 61 deletions rust/src/contract_interface.rs
Expand Up @@ -499,7 +499,7 @@ pub struct Contract<'a> {
impl<'a> Contract<'a> {
/// Returns a contract from [contract code](ContractCode) and given [parameters](Parameters).
pub fn new(contract: ContractCode<'a>, parameters: Parameters<'a>) -> Contract<'a> {
let key = ContractKey::from((&parameters, &contract));
let key = ContractKey::from_params_and_code(&parameters, &contract);
Contract {
parameters,
data: contract,
Expand Down Expand Up @@ -534,7 +534,7 @@ impl TryFrom<Vec<u8>> for Contract<'static> {
reader.read_exact(&mut contract_buf)?;
let contract = ContractCode::from(contract_buf);

let key = ContractKey::from((&parameters, &contract));
let key = ContractKey::from_params_and_code(&parameters, &contract);

Ok(Contract {
parameters,
Expand Down Expand Up @@ -922,6 +922,13 @@ impl std::fmt::Display for ContractCode<'_> {
pub struct ContractInstanceId(#[serde_as(as = "[_; CONTRACT_KEY_SIZE]")] [u8; CONTRACT_KEY_SIZE]);

impl ContractInstanceId {
pub fn from_params_and_code<'a>(
params: impl Borrow<Parameters<'a>>,
code: impl Borrow<ContractCode<'a>>,
) -> Self {
generate_id(params.borrow(), code.borrow())
}

pub const fn new(key: [u8; CONTRACT_KEY_SIZE]) -> Self {
Self(key)
}
Expand All @@ -947,6 +954,14 @@ impl ContractInstanceId {
}
}

impl Deref for ContractInstanceId {
type Target = [u8; CONTRACT_KEY_SIZE];

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl FromStr for ContractInstanceId {
type Err = bs58::decode::Error;

Expand All @@ -963,17 +978,6 @@ impl TryFrom<String> for ContractInstanceId {
}
}

impl<'a, T, U> From<(T, U)> for ContractInstanceId
where
T: Borrow<Parameters<'a>>,
U: Borrow<ContractCode<'a>>,
{
fn from(val: (T, U)) -> Self {
let (parameters, code_data) = (val.0.borrow(), val.1.borrow());
generate_id(parameters, code_data)
}
}

impl Display for ContractInstanceId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.encode())
Expand All @@ -989,50 +993,20 @@ pub struct ContractKey {
code: Option<CodeHash>,
}

impl PartialEq for ContractKey {
fn eq(&self, other: &Self) -> bool {
self.instance == other.instance
}
}

impl std::hash::Hash for ContractKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.instance.0.hash(state);
}
}

impl From<ContractInstanceId> for ContractKey {
fn from(instance: ContractInstanceId) -> Self {
Self {
instance,
code: None,
}
}
}

impl From<ContractKey> for ContractInstanceId {
fn from(key: ContractKey) -> Self {
key.instance
}
}

impl<'a, T, U> From<(T, U)> for ContractKey
where
T: Borrow<Parameters<'a>>,
U: Borrow<ContractCode<'a>>,
{
fn from(val: (T, U)) -> Self {
let (parameters, code_data) = (val.0.borrow(), val.1.borrow());
let id = generate_id(parameters, code_data);
let code_hash = code_data.hash();
impl ContractKey {
pub fn from_params_and_code<'a>(
params: impl Borrow<Parameters<'a>>,
wasm_code: impl Borrow<ContractCode<'a>>,
) -> Self {
let code = wasm_code.borrow();
let id = generate_id(params.borrow(), code);
let code_hash = code.hash();
Self {
instance: id,
code: Some(*code_hash),
}
}
}

impl ContractKey {
/// Builds a partial [`ContractKey`](ContractKey), the contract code part is unspecified.
pub fn from_id(instance: impl Into<String>) -> Result<Self, bs58::decode::Error> {
let instance = ContractInstanceId::try_from(instance.into())?;
Expand All @@ -1043,7 +1017,7 @@ impl ContractKey {
}

/// Gets the whole spec key hash.
pub fn bytes(&self) -> &[u8] {
pub fn as_bytes(&self) -> &[u8] {
self.instance.0.as_ref()
}

Expand Down Expand Up @@ -1090,13 +1064,40 @@ impl ContractKey {
self.instance.encode()
}

pub fn id(&self) -> ContractInstanceId {
self.instance
pub fn id(&self) -> &ContractInstanceId {
&self.instance
}
}

impl PartialEq for ContractKey {
fn eq(&self, other: &Self) -> bool {
self.instance == other.instance
}
}

impl std::hash::Hash for ContractKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.instance.0.hash(state);
}
}

impl From<ContractInstanceId> for ContractKey {
fn from(instance: ContractInstanceId) -> Self {
Self {
instance,
code: None,
}
}
}

impl From<ContractKey> for ContractInstanceId {
fn from(key: ContractKey) -> Self {
key.instance
}
}

impl Deref for ContractKey {
type Target = [u8];
type Target = [u8; CONTRACT_KEY_SIZE];

fn deref(&self) -> &Self::Target {
&self.instance.0
Expand All @@ -1113,7 +1114,9 @@ impl<'a> TryFromFbs<&FbsContractKey<'a>> for ContractKey {
fn try_decode_fbs(key: &FbsContractKey<'a>) -> Result<Self, WsApiError> {
let key_bytes: [u8; CONTRACT_KEY_SIZE] = key.instance().data().bytes().try_into().unwrap();
let instance = ContractInstanceId::new(key_bytes);
let code = key.code().map(|code_hash| CodeHash::new(code_hash.bytes()));
let code = key
.code()
.map(|code_hash| CodeHash::from_code(code_hash.bytes()));
Ok(ContractKey { instance, code })
}
}
Expand Down Expand Up @@ -1265,7 +1268,7 @@ impl Eq for WrappedContract {}

impl WrappedContract {
pub fn new(data: Arc<ContractCode<'static>>, params: Parameters<'static>) -> WrappedContract {
let key = ContractKey::from((&params, &*data));
let key = ContractKey::from_params_and_code(&params, &*data);
WrappedContract { data, params, key }
}

Expand Down Expand Up @@ -1324,7 +1327,7 @@ impl<'a> arbitrary::Arbitrary<'a> for WrappedContract {
let data = <ContractCode as Arbitrary>::arbitrary(u)?.into_owned();
let param_bytes: Vec<u8> = Arbitrary::arbitrary(u)?;
let params = Parameters::from(param_bytes);
let key = ContractKey::from((&params, &data));
let key = ContractKey::from_params_and_code(&params, &data);
Ok(Self {
data: Arc::new(data),
params,
Expand Down Expand Up @@ -1572,7 +1575,7 @@ mod test {
#[test]
fn key_encoding() -> Result<(), Box<dyn std::error::Error>> {
let code = ContractCode::from(vec![1, 2, 3]);
let expected = ContractKey::from((Parameters::from(vec![]), &code));
let expected = ContractKey::from_params_and_code(Parameters::from(vec![]), &code);
// let encoded_key = expected.encode();
// println!("encoded key: {encoded_key}");
// let encoded_code = expected.contract_part_as_str();
Expand All @@ -1588,12 +1591,12 @@ mod test {
fn key_ser() -> Result<(), Box<dyn std::error::Error>> {
let mut gen = arbitrary::Unstructured::new(&*RND_BYTES);
let expected: ContractKey = gen.arbitrary()?;
let encoded = bs58::encode(expected.bytes()).into_string();
let encoded = bs58::encode(expected.as_bytes()).into_string();
// println!("encoded key: {encoded}");

let serialized = bincode::serialize(&expected)?;
let deserialized: ContractKey = bincode::deserialize(&serialized)?;
let decoded = bs58::encode(deserialized.bytes()).into_string();
let decoded = bs58::encode(deserialized.as_bytes()).into_string();
assert_eq!(encoded, decoded);
assert_eq!(deserialized, expected);
Ok(())
Expand Down

0 comments on commit 08d0017

Please sign in to comment.