Skip to content
This repository has been archived by the owner on Feb 28, 2021. It is now read-only.

Version all state #519

Merged
merged 4 commits into from
Jun 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ Upcoming

### Breaking changes

* client: `ClientT::get_checkpoint` returns a new `Checkpoint` structure
* runtime: abandon `Checkpoints` storage in favor of `Checkpoints1`
* runtime: abandon `InitialCheckpoints` storage in favor of `InitialCheckpoints1`
* runtime: abandon `Projects` storage in favor of `Projects1`
* runtime: abandon `Users` storage in favor of `Users1`
* runtime: abandon `Orgs` storage in favor of `Orgs1`
* runtime: We introduce the `CheckVersion` transaction validation that requires
authors to include the runtime version in the transaction.
Expand Down
91 changes: 90 additions & 1 deletion client/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,95 @@ impl Org {
}
}

/// User
///
/// Different from [state::UserV1] in which this type gathers
/// both the [`Id`] and the other [`User`] fields, respectively stored
/// as an User's storage key and data, into one complete type.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct User {
// Unique id of a User.
pub id: Id,

/// See [state::UserV1::account_id]
pub account_id: AccountId,

/// See [state::UserV1::projects]
pub projects: Vec<ProjectName>,
}

impl User {
pub fn new(id: Id, user: state::Users1Data) -> Self {
match user {
state::Users1Data::V1(user) => Self {
id,
account_id: user.account_id,
projects: user.projects,
},
}
}
}

/// Project
///
/// Different from [state::ProjectV1] in which this type gathers
/// [`ProjectName`], [`ProjectDomain`] and the other [`Project`] fields into one complete type.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Project {
/// The name of the project, unique within its org.
pub name: ProjectName,

/// The domain to which the project belongs.
pub domain: ProjectDomain,

/// See [state::ProjectV1::current_cp]
pub current_cp: CheckpointId,

/// See [state::ProjectV1::metadata]
pub metadata: Bytes128,
}

impl Project {
/// Build a [crate::Project] given all its properties obtained from storage.
pub fn new(name: ProjectName, domain: ProjectDomain, project: state::Projects1Data) -> Self {
match project {
state::Projects1Data::V1(project) => Project {
name,
domain,
current_cp: project.current_cp,
metadata: project.metadata,
},
}
}
}

/// Checkpoint
///
/// Different from [state::CheckpointV1] in which this type gathers
/// both the [`CheckpointId`] and the other [`Checkpoint`] fields, respectively stored
/// as an Checkpoint's storage key and data, into one complete type.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Checkpoint {
/// Checkpoint ID.
pub id: CheckpointId,
/// Previous checkpoint in the project history.
pub parent: Option<CheckpointId>,
/// Hash that identifies a project’s off-chain data.
pub hash: H256,
}

impl Checkpoint {
pub fn new(cp: state::Checkpoints1Data) -> Self {
match cp {
state::Checkpoints1Data::V1(cp) => Self {
id: cp.id(),
parent: cp.parent,
hash: cp.hash,
},
}
}
}

/// Result of a transaction being included in a block.
///
/// Returned after submitting an transaction to the blockchain.
Expand Down Expand Up @@ -175,7 +264,7 @@ pub trait ClientT {

async fn list_projects(&self) -> Result<Vec<ProjectId>, Error>;

async fn get_checkpoint(&self, id: CheckpointId) -> Result<Option<state::Checkpoint>, Error>;
async fn get_checkpoint(&self, id: CheckpointId) -> Result<Option<Checkpoint>, Error>;

async fn onchain_runtime_version(&self) -> Result<RuntimeVersion, Error>;
}
19 changes: 10 additions & 9 deletions client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,17 +265,17 @@ impl ClientT for Client {
}

async fn get_user(&self, id: Id) -> Result<Option<User>, Error> {
self.fetch_map_value::<registry::store::Users, _, _>(id.clone())
self.fetch_map_value::<registry::store::Users1, _, _>(id.clone())
.await
.map(|maybe_user: Option<state::User>| maybe_user.map(|user| User::new(id, user)))
.map(|maybe_user| maybe_user.map(|user| User::new(id, user)))
}

async fn list_users(&self) -> Result<Vec<Id>, Error> {
let users_prefix = registry::store::Users::final_prefix();
let users_prefix = registry::store::Users1::final_prefix();
let keys = self.backend.fetch_keys(&users_prefix, None).await?;
let mut user_ids: Vec<Id> = Vec::with_capacity(keys.len());
for key in keys {
let user_id = registry::store::Users::decode_key(&key)
let user_id = registry::store::Users1::decode_key(&key)
.expect("Invalid runtime state key. Cannot extract user ID");
user_ids.push(user_id);
}
Expand All @@ -289,28 +289,29 @@ impl ClientT for Client {
project_domain: ProjectDomain,
) -> Result<Option<Project>, Error> {
let project_id = (project_name.clone(), project_domain.clone());
self.fetch_map_value::<registry::store::Projects, _, _>(project_id.clone())
self.fetch_map_value::<registry::store::Projects1, _, _>(project_id.clone())
.await
.map(|maybe_project| {
maybe_project.map(|project| Project::new(project_name, project_domain, project))
})
}

async fn list_projects(&self) -> Result<Vec<ProjectId>, Error> {
let project_prefix = registry::store::Projects::final_prefix();
let project_prefix = registry::store::Projects1::final_prefix();
let keys = self.backend.fetch_keys(&project_prefix, None).await?;
let mut project_ids = Vec::with_capacity(keys.len());
for key in keys {
let project_id = registry::store::Projects::decode_key(&key)
let project_id = registry::store::Projects1::decode_key(&key)
.expect("Invalid runtime state key. Cannot extract project ID");
project_ids.push(project_id);
}
Ok(project_ids)
}

async fn get_checkpoint(&self, id: CheckpointId) -> Result<Option<state::Checkpoint>, Error> {
self.fetch_map_value::<registry::store::Checkpoints, _, _>(id)
async fn get_checkpoint(&self, id: CheckpointId) -> Result<Option<Checkpoint>, Error> {
self.fetch_map_value::<registry::store::Checkpoints1, _, _>(id)
.await
.map(|cp_opt| cp_opt.map(Checkpoint::new))
}

async fn onchain_runtime_version(&self) -> Result<RuntimeVersion, Error> {
Expand Down
5 changes: 1 addition & 4 deletions client/tests/end_to_end.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,7 @@ async fn register_project() {
.any(|id| *id == (message.project_name.clone(), message.project_domain.clone()));
assert!(has_project, "Registered project not found in project list");

let checkpoint_ = state::Checkpoint {
parent: None,
hash: project_hash,
};
let checkpoint_ = Checkpoint::new(state::Checkpoints1Data::new(None, project_hash));
let checkpoint = client.get_checkpoint(checkpoint_id).await.unwrap().unwrap();
assert_eq!(checkpoint, checkpoint_);

Expand Down
58 changes: 1 addition & 57 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@

extern crate alloc;

use alloc::vec::Vec;

use parity_scale_codec::{Decode, Encode};
use sp_core::{ed25519, H256};
use sp_runtime::traits::BlakeTwo256;
Expand Down Expand Up @@ -60,7 +58,7 @@ pub type Balance = u128;
/// The id of a project. Used as storage key.
pub type ProjectId = (ProjectName, ProjectDomain);

/// The domain of a [Project]
/// The domain of a [crate::state::Projects1Data]
#[derive(Decode, Encode, Clone, Debug, Eq, PartialEq)]
pub enum ProjectDomain {
Org(Id),
Expand All @@ -74,58 +72,4 @@ impl std::fmt::Display for ProjectDomain {
}
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Project {
/// The name of the project, unique within its org.
pub name: ProjectName,

/// The domain to which the project belongs.
pub domain: ProjectDomain,

/// See [state::Project::current_cp]
pub current_cp: CheckpointId,

/// See [state::Project::metadata]
pub metadata: Bytes128,
}

impl Project {
/// Build a [crate::Project] given all its properties obtained from storage.
pub fn new(name: ProjectName, domain: ProjectDomain, project: state::Project) -> Self {
Project {
name,
domain,
current_cp: project.current_cp,
metadata: project.metadata,
}
}
}

pub type CheckpointId = H256;

/// User
///
/// Different from [state::User] in which this type gathers
/// both the [`Id`] and the other [`User`] fields, respectively stored
/// as an User's storage key and data, into one complete type.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct User {
// Unique id of a User.
pub id: Id,

/// See [state::User::account_id]
pub account_id: AccountId,

/// See [state::User::projects]
pub projects: Vec<ProjectName>,
}

impl User {
pub fn new(id: Id, user: state::User) -> User {
User {
id,
account_id: user.account_id,
projects: user.projects,
}
}
}
14 changes: 8 additions & 6 deletions core/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ pub struct UnregisterOrg {
///
/// # State changes
///
/// If successful, a new [crate::state::User] with the given properties is added to the state.
/// If successful, a new [crate::state::Users1Data] with the given properties is added to the state.
///
/// [crate::state::User::account_id] is generated randomly.
/// [crate::state::Users1Data::account_id] is generated randomly.
///
/// # State-dependent validations
///
Expand Down Expand Up @@ -122,7 +122,7 @@ pub struct RegisterMember {
///
/// # State changes
///
/// If successful, a new [crate::state::Project] with the given
/// If successful, a new [crate::state::Projects1Data] with the given
/// properties is added to the state.
///
///
Expand Down Expand Up @@ -158,7 +158,8 @@ pub struct RegisterProject {
///
/// # State changes
///
/// If successful, adds a new [crate::state::Checkpoint] with the given parameters to the state.
/// If successful, adds a new [crate::state::Checkpoints1Data] with the given parameters
/// to the state.
///
/// # State-dependent validations
///
Expand All @@ -169,11 +170,12 @@ pub struct CreateCheckpoint {
pub previous_checkpoint_id: Option<CheckpointId>,
}

/// Updates [crate::state::Project::current_cp].
/// Updates [crate::state::ProjectV1::current_cp].
///
/// # State changes
///
/// If successful, adds a new [crate::state::Checkpoint] with the given parameters to the state.
/// If successful, adds a new [crate::state::Checkpoints1Data] with the given parameters
/// to the state.
///
/// # State-dependent validations
///
Expand Down