From 7499598bd47f251a6b9b29e125064a4a7eb659a2 Mon Sep 17 00:00:00 2001 From: Bedeho Mender Date: Tue, 4 Feb 2020 12:08:48 +0100 Subject: [PATCH 1/3] Created stub Ink project --- content_directory/.cargo/config | 4 ++ content_directory/.gitignore | 9 +++ content_directory/.ink/abi_gen/Cargo.toml | 16 +++++ content_directory/.ink/abi_gen/main.rs | 7 +++ content_directory/Cargo.toml | 60 ++++++++++++++++++ content_directory/lib.rs | 76 +++++++++++++++++++++++ 6 files changed, 172 insertions(+) create mode 100755 content_directory/.cargo/config create mode 100755 content_directory/.gitignore create mode 100755 content_directory/.ink/abi_gen/Cargo.toml create mode 100755 content_directory/.ink/abi_gen/main.rs create mode 100755 content_directory/Cargo.toml create mode 100755 content_directory/lib.rs diff --git a/content_directory/.cargo/config b/content_directory/.cargo/config new file mode 100755 index 0000000000..9ed784e6e2 --- /dev/null +++ b/content_directory/.cargo/config @@ -0,0 +1,4 @@ +[target.wasm32-unknown-unknown] +rustflags = [ + "-C", "link-args=-z stack-size=65536 --import-memory" +] \ No newline at end of file diff --git a/content_directory/.gitignore b/content_directory/.gitignore new file mode 100755 index 0000000000..bf910de10a --- /dev/null +++ b/content_directory/.gitignore @@ -0,0 +1,9 @@ +# Ignore build artifacts from the local tests sub-crate. +/target/ + +# Ignore backup files creates by cargo fmt. +**/*.rs.bk + +# Remove Cargo.lock when creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock \ No newline at end of file diff --git a/content_directory/.ink/abi_gen/Cargo.toml b/content_directory/.ink/abi_gen/Cargo.toml new file mode 100755 index 0000000000..11e7750728 --- /dev/null +++ b/content_directory/.ink/abi_gen/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "abi-gen" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" +publish = false + +[[bin]] +name = "abi-gen" +path = "main.rs" + +[dependencies] +contract = { path = "../..", package = "content_directory", default-features = false, features = ["ink-generate-abi"] } +ink_lang = { git = "https://github.com/paritytech/ink", package = "ink_lang", default-features = false, features = ["ink-generate-abi"] } +serde = "1.0" +serde_json = "1.0" diff --git a/content_directory/.ink/abi_gen/main.rs b/content_directory/.ink/abi_gen/main.rs new file mode 100755 index 0000000000..d9572fb7c9 --- /dev/null +++ b/content_directory/.ink/abi_gen/main.rs @@ -0,0 +1,7 @@ +fn main() -> Result<(), std::io::Error> { + let abi = ::generate_abi(); + let contents = serde_json::to_string_pretty(&abi)?; + std::fs::create_dir("target").ok(); + std::fs::write("target/metadata.json", contents)?; + Ok(()) +} diff --git a/content_directory/Cargo.toml b/content_directory/Cargo.toml new file mode 100755 index 0000000000..e7677173b8 --- /dev/null +++ b/content_directory/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "content_directory" +version = "0.1.0" +authors = ["[your_name] <[your_email]>"] +edition = "2018" + +[dependencies] +ink_abi = { git = "https://github.com/paritytech/ink", package = "ink_abi", default-features = false, features = ["derive"], optional = true } +ink_primitives = { git = "https://github.com/paritytech/ink", package = "ink_primitives", default-features = false } +ink_core = { git = "https://github.com/paritytech/ink", package = "ink_core", default-features = false } +ink_lang = { git = "https://github.com/paritytech/ink", package = "ink_lang", default-features = false } + +scale = { package = "parity-scale-codec", version = "1.1", default-features = false, features = ["derive"] } +type-metadata = { git = "https://github.com/type-metadata/type-metadata.git", default-features = false, features = ["derive"], optional = true } + +[lib] +name = "content_directory" +path = "lib.rs" +crate-type = [ + # Used for normal contract Wasm blobs. + "cdylib", + # Used for ABI generation. + "rlib", +] + +[features] +default = ["test-env"] +std = [ + "ink_abi/std", + "ink_core/std", + "ink_primitives/std", + "scale/std", + "type-metadata/std", +] +test-env = [ + "std", + "ink_lang/test-env", +] +ink-generate-abi = [ + "std", + "ink_abi", + "type-metadata", + "ink_core/ink-generate-abi", + "ink_lang/ink-generate-abi", +] +ink-as-dependency = [] + +[profile.release] +panic = "abort" +lto = true +opt-level = "z" +overflow-checks = true + +[workspace] +members = [ + ".ink/abi_gen" +] +exclude = [ + ".ink" +] diff --git a/content_directory/lib.rs b/content_directory/lib.rs new file mode 100755 index 0000000000..0676cccaa4 --- /dev/null +++ b/content_directory/lib.rs @@ -0,0 +1,76 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use ink_lang as ink; + +#[ink::contract(version = "0.1.0")] +mod content_directory { + use ink_core::storage; + + /// Defines the storage of your contract. + /// Add new fields to the below struct in order + /// to add new static storage fields to your contract. + #[ink(storage)] + struct ContentDirectory { + /// Stores a single `bool` value on the storage. + value: storage::Value, + } + + impl ContentDirectory { + /// Constructor that initializes the `bool` value to the given `init_value`. + #[ink(constructor)] + fn new(&mut self, init_value: bool) { + self.value.set(init_value); + } + + /// Constructor that initializes the `bool` value to `false`. + /// + /// Constructors can delegate to other constructors. + #[ink(constructor)] + fn default(&mut self) { + self.new(false) + } + + /// A message that can be called on instantiated contracts. + /// This one flips the value of the stored `bool` from `true` + /// to `false` and vice versa. + #[ink(message)] + fn flip(&mut self) { + *self.value = !self.get(); + } + + /// Simply returns the current value of our `bool`. + #[ink(message)] + fn get(&self) -> bool { + *self.value + } + } + + /// Unit tests in Rust are normally defined within such a `#[cfg(test)]` + /// module and test functions are marked with a `#[test]` attribute. + /// The below code is technically just normal Rust code. + #[cfg(test)] + mod tests { + /// Imports all the definitions from the outer scope so we can use them here. + use super::*; + + /// We test if the default constructor does its job. + #[test] + fn default_works() { + // Note that even though we defined our `#[ink(constructor)]` + // above as `&mut self` functions that return nothing we can call + // them in test code as if they were normal Rust constructors + // that take no `self` argument but return `Self`. + let content_directory = ContentDirectory::default(); + assert_eq!(content_directory.get(), false); + } + + /// We test a simple use case of our contract. + #[test] + fn it_works() { + let mut content_directory = ContentDirectory::new(false); + assert_eq!(content_directory.get(), false); + content_directory.flip(); + assert_eq!(content_directory.get(), true); + } + } +} From b2b66af9a541e55fe04e68df616c09001b2f7393 Mon Sep 17 00:00:00 2001 From: Bedeho Mender Date: Tue, 4 Feb 2020 12:41:14 +0100 Subject: [PATCH 2/3] Moved project to src subfolder --- {content_directory => src/content_directory}/.cargo/config | 0 {content_directory => src/content_directory}/.gitignore | 0 .../content_directory}/.ink/abi_gen/Cargo.toml | 0 {content_directory => src/content_directory}/.ink/abi_gen/main.rs | 0 {content_directory => src/content_directory}/Cargo.toml | 0 {content_directory => src/content_directory}/lib.rs | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename {content_directory => src/content_directory}/.cargo/config (100%) rename {content_directory => src/content_directory}/.gitignore (100%) rename {content_directory => src/content_directory}/.ink/abi_gen/Cargo.toml (100%) rename {content_directory => src/content_directory}/.ink/abi_gen/main.rs (100%) rename {content_directory => src/content_directory}/Cargo.toml (100%) rename {content_directory => src/content_directory}/lib.rs (100%) diff --git a/content_directory/.cargo/config b/src/content_directory/.cargo/config similarity index 100% rename from content_directory/.cargo/config rename to src/content_directory/.cargo/config diff --git a/content_directory/.gitignore b/src/content_directory/.gitignore similarity index 100% rename from content_directory/.gitignore rename to src/content_directory/.gitignore diff --git a/content_directory/.ink/abi_gen/Cargo.toml b/src/content_directory/.ink/abi_gen/Cargo.toml similarity index 100% rename from content_directory/.ink/abi_gen/Cargo.toml rename to src/content_directory/.ink/abi_gen/Cargo.toml diff --git a/content_directory/.ink/abi_gen/main.rs b/src/content_directory/.ink/abi_gen/main.rs similarity index 100% rename from content_directory/.ink/abi_gen/main.rs rename to src/content_directory/.ink/abi_gen/main.rs diff --git a/content_directory/Cargo.toml b/src/content_directory/Cargo.toml similarity index 100% rename from content_directory/Cargo.toml rename to src/content_directory/Cargo.toml diff --git a/content_directory/lib.rs b/src/content_directory/lib.rs similarity index 100% rename from content_directory/lib.rs rename to src/content_directory/lib.rs From 1d6f8a8734f48658da470b35f1e94056ed9bd1b5 Mon Sep 17 00:00:00 2001 From: Bedeho Mender Date: Tue, 4 Feb 2020 19:05:48 +0100 Subject: [PATCH 3/3] wip --- src/content_directory/lib.rs | 226 +++++++++++++++++++++++++---- src/content_directory/test/test.rs | 25 ++++ 2 files changed, 222 insertions(+), 29 deletions(-) create mode 100644 src/content_directory/test/test.rs diff --git a/src/content_directory/lib.rs b/src/content_directory/lib.rs index 0676cccaa4..155cdc6e19 100755 --- a/src/content_directory/lib.rs +++ b/src/content_directory/lib.rs @@ -2,17 +2,92 @@ use ink_lang as ink; +/* +// 2. Implement `EnvTypes` trait, specifying custom types +impl ink_core::env::EnvTypes for CustomRuntimeTypes { + type AccountId = [u8; 32]; + type Balance = u128; + type Hash = [u8; 32]; + type Moment = u64; +} +*/ + +// TODO +// +// 1. An easy way to parametrise types that come from runtime, such that +// contract deployer need not actually change any source code to build for desired set +// of actual types. For now, I will just use specific types to make progress. + +// To be parametrised types + +// Good side projects? +// double map +// linked double map. + +// 2. Benchmarking improvements. + #[ink::contract(version = "0.1.0")] mod content_directory { - use ink_core::storage; + + #[cfg(not(feature = "ink-as-dependency"))] + use ink_core::storage::{ + self, + Flush + }; + + pub type UserId = u64; + pub type CuratorId = u64; + + pub type VideoId = u64; + pub type VideoCategoryId = u64; + pub type VideoLabelId = u64; + pub type VideoPlaylistId = u64; + + pub type SystemVideoChannelId = u64; + pub type UserVideoChannelId = u64; + + // Perhaps each field map should be in separate contract, to + // aid migration. + // Perhaps a separate map for each field also, to make it even faster to migrate? + // Separate storage from implementation!! + // make general enough that other contracts can do anything a user can do + // such that users can deplpy whatever schemes they want, and also interoprates + // well with future CCM probably. /// Defines the storage of your contract. /// Add new fields to the below struct in order /// to add new static storage fields to your contract. #[ink(storage)] struct ContentDirectory { - /// Stores a single `bool` value on the storage. + + // Migration idea + // Split each storage field into its own pure data contract + // beyond this, for field which are maps to structs, as a second measure + // consider splitting each field into its own map, so they can be migrated + // separately. Add simple get(id) -> T/put(id, T) routines on eaach such contract, + // that work with a full struct type. Each contract should be pausable also, + // so that no puts are allowed. + // + // + // Each write operation desired in the directory is further its own + // contract. It can only be initialized to make/read write operations through + // some ACL hub thing. this allows write operation contracts to only + // access specific things + // question: how do I prevent contract from ebing roughe.. i.e. dialing out + // to outside of contract module, or invoking some contract in some way it sohuld not?? + // + // More thinking is needed in the above, and more familiarity with + // contract security model. + value: storage::Value, + + users: storage::HashMap::, + curators: storage::HashMap::, + user_video_channels: storage::HashMap, + videos: storage::HashMap, + + video_categories: storage::HashMap + } impl ContentDirectory { @@ -30,6 +105,53 @@ mod content_directory { self.new(false) } + //fn new(&mut self, ...) + + // calls related to deploying or adding new contracts??? + // + + /* + // none of these can be accesed here, must be called + // by runtime + pub fn add_user + pub fn update_user + pub fn delete_user <== ???  + */ + + /* + /// User updates own profile + #[ink(message)] + pub user_update_user + */ + + /* + #[ink(message)] + pub curator_updates_user_status() { + + } + */ + + /* + + // Adding and editing videos + + #[ink(message)] + pub add_video() + + #[ink(message)] + pub update_video_as_channel_owner() + + #[ink(message)] + pub update_video_as_curator() + */ + + + /* + #[ink(message)] + pub pay_for_video_access() + */ + + /// A message that can be called on instantiated contracts. /// This one flips the value of the stored `bool` from `true` /// to `false` and vice versa. @@ -45,32 +167,78 @@ mod content_directory { } } - /// Unit tests in Rust are normally defined within such a `#[cfg(test)]` - /// module and test functions are marked with a `#[test]` attribute. - /// The below code is technically just normal Rust code. - #[cfg(test)] - mod tests { - /// Imports all the definitions from the outer scope so we can use them here. - use super::*; - - /// We test if the default constructor does its job. - #[test] - fn default_works() { - // Note that even though we defined our `#[ink(constructor)]` - // above as `&mut self` functions that return nothing we can call - // them in test code as if they were normal Rust constructors - // that take no `self` argument but return `Self`. - let content_directory = ContentDirectory::default(); - assert_eq!(content_directory.get(), false); - } + ///... + #[derive(Debug, Clone, PartialEq, Eq, scale::Encode, scale::Decode, Flush)] + #[cfg_attr(feature = "ink-generate-abi", derive(type_metadata::Metadata))] + pub struct User { + account: AccountId, + status: bool + } - /// We test a simple use case of our contract. - #[test] - fn it_works() { - let mut content_directory = ContentDirectory::new(false); - assert_eq!(content_directory.get(), false); - content_directory.flip(); - assert_eq!(content_directory.get(), true); - } + ///... + #[derive(Debug, Clone, PartialEq, Eq, scale::Encode, scale::Decode, Flush)] + #[cfg_attr(feature = "ink-generate-abi", derive(type_metadata::Metadata))] + pub struct Curator { + account: AccountId, + status: bool } -} + + /// ... + #[derive(Debug, Clone, PartialEq, Eq, scale::Encode, scale::Decode, Flush)] + #[cfg_attr(feature = "ink-generate-abi", derive(type_metadata::Metadata))] + pub struct UserVideoChannel { + owning_user_id: UserId, + channel_revenue_account: AccountId, + + // if we allow setting the owner of an actual video channel contract, + // then people can deploy their own logic for controlling a channel. + + } + + /// .. + #[derive(Debug, Clone, PartialEq, Eq, scale::Encode, scale::Decode, Flush)] + #[cfg_attr(feature = "ink-generate-abi", derive(type_metadata::Metadata))] + pub struct SystemVideoChannel { + // if we allow setting the owner of an actual video channel contract, + // then people can deploy their own logic for controlling a channel. + } + + /// ... + #[derive(Debug, Clone, PartialEq, Eq, scale::Encode, scale::Decode, Flush)] + #[cfg_attr(feature = "ink-generate-abi", derive(type_metadata::Metadata))] + pub enum VideoChannelId { + SystemVideoChannel(SystemVideoChannelId), + UserVideoChannel(UserVideoChannelId) + } + + ///.. + #[derive(Debug, Clone, PartialEq, Eq, scale::Encode, scale::Decode, Flush)] + #[cfg_attr(feature = "ink-generate-abi", derive(type_metadata::Metadata))] + pub struct Video { + video_channel_id: VideoChannelId, + includable_in_foreign_playlists: bool, + title: Vec + + // license + payment + access stuff, ads? + } + + #[derive(Debug, Clone, PartialEq, Eq, scale::Encode, scale::Decode, Flush)] + #[cfg_attr(feature = "ink-generate-abi", derive(type_metadata::Metadata))] + pub struct VideoCategory { + parent_video_category_id: Option, + can_currently_be_used: bool, + } + + #[derive(Debug, Clone, PartialEq, Eq, scale::Encode, scale::Decode, Flush)] + #[cfg_attr(feature = "ink-generate-abi", derive(type_metadata::Metadata))] + pub struct VideoLabel { + can_currently_be_used: bool, + } + + #[derive(Debug, Clone, PartialEq, Eq, scale::Encode, scale::Decode, Flush)] + #[cfg_attr(feature = "ink-generate-abi", derive(type_metadata::Metadata))] + pub struct VideoPlaylist { + video_channel_id: VideoChannelId, + title: Vec + } +} \ No newline at end of file diff --git a/src/content_directory/test/test.rs b/src/content_directory/test/test.rs new file mode 100644 index 0000000000..2dd651c8a0 --- /dev/null +++ b/src/content_directory/test/test.rs @@ -0,0 +1,25 @@ +#![cfg(test)] + +/// Imports all the definitions from the outer scope so we can use them here. +//use super::*; +use crate::content_directorddy::*; + +/// We test if the default constructor does its job. +#[test] +fn default_works() { + // Note that even though we defined our `#[ink(constructor)]` + // above as `&mut self` functions that return nothing we can call + // them in test code as if they were normal Rust constructors + // that take no `self` argument but return `Self`. + let content_directory = ContentDirectory::default(); + assert_eq!(content_directory.get(), false); +} + +/// We test a simple use case of our contract. +#[test] +fn it_works() { + let mut content_directory = ContentDirectory::new(false); + assert_eq!(content_directory.get(), false); + content_directory.flip(); + assert_eq!(content_directory.get(), true); +} \ No newline at end of file