Asset contract mostly implemented
This commit is contained in:
parent
6aaabff522
commit
e39d48da82
|
@ -2,35 +2,16 @@
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"voting",
|
"notamon-common",
|
||||||
"multi-voting",
|
"notamon-asset-contract",
|
||||||
"petition",
|
|
||||||
"ping",
|
|
||||||
"mia-game",
|
|
||||||
"nickname",
|
|
||||||
"access-control",
|
|
||||||
"dns",
|
|
||||||
"dns-voting-client",
|
|
||||||
"zk-second-price-auction",
|
|
||||||
"zk-struct-open",
|
|
||||||
"zk-immediate-open",
|
|
||||||
"zk-voting-simple",
|
|
||||||
"zk-average-salary",
|
|
||||||
"zk-statistics",
|
|
||||||
"zk-multi-functional",
|
|
||||||
"zk-file-share",
|
|
||||||
"zk-classification",
|
|
||||||
"upgradable-v1",
|
|
||||||
"upgradable-v2",
|
|
||||||
"upgradable-v3",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "5.203.0"
|
version = "0.1.0"
|
||||||
description = "Example contract for the Partisia Blockchain."
|
description = "TODO"
|
||||||
homepage = "https://gitlab.com/partisiablockchain/language/example-contracts"
|
homepage = "TODO"
|
||||||
repository = "https://gitlab.com/partisiablockchain/language/example-contracts"
|
repository = "TODO"
|
||||||
documentation = "https://gitlab.com/partisiablockchain/language/example-contracts"
|
documentation = "TODO"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ crate-type = ['rlib', 'cdylib']
|
||||||
zk-compute-path = "src/zk_compute.rs"
|
zk-compute-path = "src/zk_compute.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
notamon-common = { path = "../notamon-common" }
|
||||||
|
|
||||||
pbc_contract_common.workspace = true
|
pbc_contract_common.workspace = true
|
||||||
pbc_traits.workspace = true
|
pbc_traits.workspace = true
|
||||||
pbc_lib.workspace = true
|
pbc_lib.workspace = true
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate pbc_contract_codegen;
|
extern crate pbc_contract_codegen;
|
||||||
extern crate pbc_contract_common;
|
|
||||||
extern crate pbc_lib;
|
|
||||||
|
|
||||||
use pbc_contract_common::address::Address;
|
use pbc_contract_common::address::Address;
|
||||||
use pbc_contract_common::context::ContractContext;
|
use pbc_contract_common::context::ContractContext;
|
||||||
|
@ -13,94 +11,135 @@ use pbc_contract_common::zk::{SecretVarId, ZkInputDef, ZkState, ZkStateChange};
|
||||||
use pbc_zk::Sbi8;
|
use pbc_zk::Sbi8;
|
||||||
use read_write_rpc_derive::ReadWriteRPC;
|
use read_write_rpc_derive::ReadWriteRPC;
|
||||||
use read_write_state_derive::ReadWriteState;
|
use read_write_state_derive::ReadWriteState;
|
||||||
|
use pbc_contract_common::avl_tree_map::AvlTreeMap;
|
||||||
|
use pbc_traits::{ReadRPC, WriteRPC, ReadWriteState};
|
||||||
|
use create_type_spec_derive::CreateTypeSpec;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use notamon_common::{AssetId, Permission, Permissions};
|
||||||
|
|
||||||
mod zk_compute;
|
mod zk_compute;
|
||||||
|
|
||||||
/// Metadata for secret-shared files.
|
/// Metadata for secret-shared assets.
|
||||||
#[derive(ReadWriteState, ReadWriteRPC, Debug)]
|
#[derive(ReadWriteState, ReadWriteRPC, Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct SecretVarMetadata {}
|
pub struct AssetMetadata {
|
||||||
|
asset_id: AssetId,
|
||||||
|
}
|
||||||
|
|
||||||
/// Empty contract state, as all stored files are secret-shared.
|
#[derive(ReadWriteState, ReadWriteRPC, Debug, CreateTypeSpec, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum Role {
|
||||||
|
#[discriminant(1)]
|
||||||
|
ADMIN {},
|
||||||
|
#[discriminant(2)]
|
||||||
|
UPLOADER {},
|
||||||
|
#[discriminant(3)]
|
||||||
|
PUBLISHER {},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Empty contract state, as all stored assets are secret-shared.
|
||||||
#[state]
|
#[state]
|
||||||
pub struct CollectionState {}
|
pub struct AssetContractState {
|
||||||
|
asset_id_to_variable_id: AvlTreeMap<AssetId, SecretVarId>,
|
||||||
|
permissions: Permissions<Role>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Initializes contract with empty state.
|
/// Initializes contract with empty state.
|
||||||
#[init(zk = true)]
|
#[init(zk = true)]
|
||||||
pub fn initialize(ctx: ContractContext, zk_state: ZkState<SecretVarMetadata>) -> CollectionState {
|
pub fn initialize(ctx: ContractContext, zk_state: ZkState<AssetMetadata>) -> AssetContractState {
|
||||||
CollectionState {}
|
let mut permissions = Permissions::new();
|
||||||
|
permissions.set_permission(Role::ADMIN { }, Permission::only(ctx.sender));
|
||||||
|
AssetContractState {
|
||||||
|
asset_id_to_variable_id: AvlTreeMap::new(),
|
||||||
|
permissions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Upload a new file with a specific size of `file_length`.
|
/// Upload a new asset with a specific size of `asset_length`.
|
||||||
///
|
///
|
||||||
/// `file_length` is the size of the file in *bytes*.
|
/// `asset_length` is the size of the asset in *bytes*.
|
||||||
/// Fails if the uploaded file has a different size than `file_length`.
|
/// Fails if the uploaded asset has a different size than `asset_length`.
|
||||||
#[zk_on_secret_input(shortname = 0x42)]
|
#[zk_on_secret_input(shortname = 0x42)]
|
||||||
pub fn add_file(
|
pub fn set_asset(
|
||||||
context: ContractContext,
|
context: ContractContext,
|
||||||
state: CollectionState,
|
state: AssetContractState,
|
||||||
zk_state: ZkState<SecretVarMetadata>,
|
zk_state: ZkState<AssetMetadata>,
|
||||||
file_length: u32,
|
asset_id: AssetId,
|
||||||
|
asset_length: u32,
|
||||||
) -> (
|
) -> (
|
||||||
CollectionState,
|
AssetContractState,
|
||||||
Vec<EventGroup>,
|
Vec<EventGroup>,
|
||||||
ZkInputDef<SecretVarMetadata, Vec<Sbi8>>,
|
ZkInputDef<AssetMetadata, Vec<Sbi8>>,
|
||||||
) {
|
) {
|
||||||
let input_def = ZkInputDef::with_metadata_and_size(None, SecretVarMetadata {}, file_length * 8);
|
state.permissions.assert_has_permission(&context.sender, Role::UPLOADER {});
|
||||||
|
let input_def = ZkInputDef::with_metadata_and_size(Some(SHORTNAME_SET_ASSET_INPUTTED), AssetMetadata { asset_id }, asset_length * 8);
|
||||||
(state, vec![], input_def)
|
(state, vec![], input_def)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Changes ownership of the secret-shared file with id `file_id`
|
#[zk_on_variable_inputted(shortname=0x43)]
|
||||||
/// from the sender to `new_owner`.
|
pub fn set_asset_inputted(
|
||||||
///
|
context: ContractContext,
|
||||||
/// Fails if the sender is not the current owner of the referenced file.
|
mut state: AssetContractState,
|
||||||
#[action(shortname = 0x03, zk = true)]
|
zk_state: ZkState<AssetMetadata>,
|
||||||
pub fn change_file_owner(
|
variable_id: SecretVarId,
|
||||||
ctx: ContractContext,
|
) -> AssetContractState {
|
||||||
state: CollectionState,
|
let variable = zk_state.get_variable(variable_id).unwrap();
|
||||||
zk_state: ZkState<SecretVarMetadata>,
|
state.asset_id_to_variable_id.insert(variable.metadata.asset_id,
|
||||||
file_id: u32,
|
variable_id);
|
||||||
new_owner: Address,
|
state
|
||||||
) -> (CollectionState, Vec<EventGroup>, Vec<ZkStateChange>) {
|
|
||||||
let file_id = SecretVarId::new(file_id);
|
|
||||||
let file_owner = zk_state.get_variable(file_id).unwrap().owner;
|
|
||||||
assert_eq!(
|
|
||||||
file_owner, ctx.sender,
|
|
||||||
"Only the owner of the secret file is allowed to change ownership."
|
|
||||||
);
|
|
||||||
|
|
||||||
(
|
|
||||||
state,
|
|
||||||
vec![],
|
|
||||||
vec![ZkStateChange::TransferVariable {
|
|
||||||
variable: file_id,
|
|
||||||
new_owner,
|
|
||||||
}],
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes the secret-shared file with id `file_id`.
|
/// Deletes the secret-shared asset with id `asset_id`.
|
||||||
///
|
///
|
||||||
/// Fails if the sender is not the current owner of the secret file.
|
/// Fails if the sender is not the current owner of the secret asset.
|
||||||
#[action(shortname = 0x05, zk = true)]
|
#[action(shortname = 0x05, zk = true)]
|
||||||
pub fn delete_file(
|
pub fn delete_asset(
|
||||||
ctx: ContractContext,
|
context: ContractContext,
|
||||||
state: CollectionState,
|
state: AssetContractState,
|
||||||
zk_state: ZkState<SecretVarMetadata>,
|
zk_state: ZkState<AssetMetadata>,
|
||||||
file_id: u32,
|
asset_id: AssetId,
|
||||||
) -> (CollectionState, Vec<EventGroup>, Vec<ZkStateChange>) {
|
) -> (AssetContractState, Vec<EventGroup>, Vec<ZkStateChange>) {
|
||||||
let file_id = SecretVarId::new(file_id);
|
state.permissions.assert_has_permission(&context.sender, Role::UPLOADER {});
|
||||||
let file_owner = zk_state.get_variable(file_id).unwrap().owner;
|
|
||||||
assert_eq!(
|
|
||||||
file_owner, ctx.sender,
|
|
||||||
"Only the owner of the secret file is allowed to delete it."
|
|
||||||
);
|
|
||||||
|
|
||||||
|
let variable_id = state.asset_id_to_variable_id.get(&asset_id).unwrap();
|
||||||
(
|
(
|
||||||
state,
|
state,
|
||||||
vec![],
|
vec![],
|
||||||
vec![ZkStateChange::DeleteVariables {
|
vec![ZkStateChange::DeleteVariables {
|
||||||
variables_to_delete: vec![file_id],
|
variables_to_delete: vec![variable_id],
|
||||||
}],
|
}],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[action(shortname = 0x07, zk = true)]
|
||||||
|
pub fn publish_asset(
|
||||||
|
context: ContractContext,
|
||||||
|
state: AssetContractState,
|
||||||
|
zk_state: ZkState<AssetMetadata>,
|
||||||
|
asset_id: AssetId,
|
||||||
|
) -> (AssetContractState, Vec<EventGroup>, Vec<ZkStateChange>) {
|
||||||
|
state.permissions.assert_has_permission(&context.sender, Role::PUBLISHER {});
|
||||||
|
|
||||||
|
let variable_id = state.asset_id_to_variable_id.get(&asset_id).unwrap();
|
||||||
|
(
|
||||||
|
state,
|
||||||
|
vec![],
|
||||||
|
vec![ZkStateChange::OpenVariables {
|
||||||
|
variables: vec![variable_id],
|
||||||
|
}],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[action(shortname = 0x06, zk = true)]
|
||||||
|
pub fn set_permission(
|
||||||
|
context: ContractContext,
|
||||||
|
mut state: AssetContractState,
|
||||||
|
zk_state: ZkState<AssetMetadata>,
|
||||||
|
role: Role,
|
||||||
|
permission: Permission,
|
||||||
|
) -> AssetContractState {
|
||||||
|
state.permissions.assert_has_permission(&context.sender, Role::ADMIN {});
|
||||||
|
state.permissions.set_permission(role, permission);
|
||||||
|
state
|
||||||
|
}
|
||||||
|
|
21
rust/notamon-common/Cargo.toml
Normal file
21
rust/notamon-common/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "notamon-common"
|
||||||
|
readme = "README.md"
|
||||||
|
version.workspace = true
|
||||||
|
description.workspace = true
|
||||||
|
homepage.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
documentation.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
abi = ["pbc_contract_common/abi", "pbc_traits/abi", "create_type_spec_derive/abi", "pbc_lib/abi"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
pbc_contract_common.workspace = true
|
||||||
|
pbc_traits.workspace = true
|
||||||
|
pbc_lib.workspace = true
|
||||||
|
read_write_rpc_derive.workspace = true
|
||||||
|
read_write_state_derive.workspace = true
|
||||||
|
create_type_spec_derive.workspace = true
|
3
rust/notamon-common/README.md
Normal file
3
rust/notamon-common/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Notamon common functionality
|
||||||
|
|
||||||
|
TODO
|
72
rust/notamon-common/src/lib.rs
Normal file
72
rust/notamon-common/src/lib.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#![doc = include_str!("../README.md")]
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
|
use pbc_contract_common::avl_tree_map::AvlTreeMap;
|
||||||
|
use pbc_contract_common::address::Address;
|
||||||
|
use pbc_contract_common::context::ContractContext;
|
||||||
|
use pbc_contract_common::events::EventGroup;
|
||||||
|
use pbc_contract_common::zk::{SecretVarId, ZkInputDef, ZkState, ZkStateChange};
|
||||||
|
use pbc_traits::{ReadRPC, WriteRPC, ReadWriteState};
|
||||||
|
use read_write_rpc_derive::ReadWriteRPC;
|
||||||
|
use read_write_state_derive::ReadWriteState;
|
||||||
|
use create_type_spec_derive::CreateTypeSpec;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(ReadWriteState, ReadWriteRPC, Debug, CreateTypeSpec, PartialEq, Eq)]
|
||||||
|
pub struct AssetId{
|
||||||
|
id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(ReadWriteState, ReadWriteRPC, Debug, CreateTypeSpec, PartialEq, Eq)]
|
||||||
|
pub enum Permission {
|
||||||
|
#[discriminant(0)]
|
||||||
|
None {},
|
||||||
|
#[discriminant(1)]
|
||||||
|
Addresses { addresses: Vec<Address> },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Permission {
|
||||||
|
pub const NONE: Permission = Permission::None { };
|
||||||
|
|
||||||
|
pub fn only(address: Address) -> Permission {
|
||||||
|
Permission::Addresses { addresses: vec![address] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allows(&self, address: &Address) -> bool {
|
||||||
|
match self {
|
||||||
|
Permission::None { } => false,
|
||||||
|
Permission::Addresses { addresses } => addresses.contains(address),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(ReadWriteState, Debug, CreateTypeSpec)]
|
||||||
|
pub struct Permissions<KeyT: ReadWriteState> {
|
||||||
|
permissions: AvlTreeMap<KeyT, Permission>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <KeyT: ReadWriteState> Permissions<KeyT> {
|
||||||
|
|
||||||
|
pub fn new () -> Self {
|
||||||
|
Self { permissions: AvlTreeMap::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_permission(&mut self, permission_key: KeyT, permission: Permission) {
|
||||||
|
self.permissions.insert(permission_key, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_permission(&self, permission: &KeyT) -> Permission {
|
||||||
|
self.permissions.get(permission).unwrap_or(Permission::NONE)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <KeyT: ReadWriteState + Debug> Permissions<KeyT> {
|
||||||
|
pub fn assert_has_permission(&self, address: &Address, permission: KeyT) {
|
||||||
|
if !self.get_permission(&permission).allows(address) {
|
||||||
|
panic!("User {address} does not have permission: {permission:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user