Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POC Ink content directory #137

Draft
wants to merge 3 commits into
base: development
Choose a base branch
from
Draft
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
4 changes: 4 additions & 0 deletions src/content_directory/.cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[target.wasm32-unknown-unknown]
rustflags = [
"-C", "link-args=-z stack-size=65536 --import-memory"
]
9 changes: 9 additions & 0 deletions src/content_directory/.gitignore
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions src/content_directory/.ink/abi_gen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "abi-gen"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
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"
7 changes: 7 additions & 0 deletions src/content_directory/.ink/abi_gen/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn main() -> Result<(), std::io::Error> {
let abi = <contract::ContentDirectory as ink_lang::GenerateAbi>::generate_abi();
let contents = serde_json::to_string_pretty(&abi)?;
std::fs::create_dir("target").ok();
std::fs::write("target/metadata.json", contents)?;
Ok(())
}
60 changes: 60 additions & 0 deletions src/content_directory/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
]
244 changes: 244 additions & 0 deletions src/content_directory/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
#![cfg_attr(not(feature = "std"), no_std)]

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 {

#[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 {

// 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<bool>,

users: storage::HashMap::<UserId, User>,
curators: storage::HashMap::<CuratorId, Curator>,
user_video_channels: storage::HashMap<UserVideoChannelId, UserVideoChannel>,
videos: storage::HashMap<VideoId, Video>,

video_categories: storage::HashMap<VideoCategoryId, VideoCategory>

}

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)
}

//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.
#[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
}
}

///...
#[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
}

///...
#[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<u8>

// 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<VideoCategoryId>,
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<u8>
}
}
25 changes: 25 additions & 0 deletions src/content_directory/test/test.rs
Original file line number Diff line number Diff line change
@@ -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);
}