difftreelog
Merge pull request #932 from UniqueNetwork/fix/support_for_old_versions_in_collection_by_id_method
in: master
5 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3712,6 +3712,12 @@
checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0"
[[package]]
+name = "hex-literal"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
+
+[[package]]
name = "hkdf"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4282,7 +4288,7 @@
"frame-system-benchmarking",
"frame-system-rpc-runtime-api",
"frame-try-runtime",
- "hex-literal",
+ "hex-literal 0.3.4",
"kusama-runtime-constants",
"log",
"pallet-authority-discovery",
@@ -5730,7 +5736,7 @@
"frame-system-benchmarking",
"frame-system-rpc-runtime-api",
"frame-try-runtime",
- "hex-literal",
+ "hex-literal 0.4.1",
"impl-trait-for-tuples",
"log",
"num_enum",
@@ -8446,7 +8452,7 @@
source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.41#e203bfb396ed949f102720debf32fb98166787af"
dependencies = [
"bitvec",
- "hex-literal",
+ "hex-literal 0.3.4",
"parity-scale-codec",
"polkadot-core-primitives",
"polkadot-parachain",
@@ -8512,7 +8518,7 @@
"frame-system-benchmarking",
"frame-system-rpc-runtime-api",
"frame-try-runtime",
- "hex-literal",
+ "hex-literal 0.3.4",
"log",
"pallet-authority-discovery",
"pallet-authorship",
@@ -8714,7 +8720,7 @@
"frame-support",
"frame-system-rpc-runtime-api",
"futures",
- "hex-literal",
+ "hex-literal 0.3.4",
"kusama-runtime",
"kvdb",
"kvdb-rocksdb",
@@ -9169,7 +9175,7 @@
"frame-system-benchmarking",
"frame-system-rpc-runtime-api",
"frame-try-runtime",
- "hex-literal",
+ "hex-literal 0.4.1",
"impl-trait-for-tuples",
"log",
"num_enum",
@@ -9637,7 +9643,7 @@
"frame-system-benchmarking",
"frame-system-rpc-runtime-api",
"frame-try-runtime",
- "hex-literal",
+ "hex-literal 0.3.4",
"log",
"pallet-authority-discovery",
"pallet-authorship",
@@ -13327,6 +13333,7 @@
"anyhow",
"app-promotion-rpc",
"frame-benchmarking",
+ "hex-literal 0.4.1",
"jsonrpsee",
"opal-runtime",
"pallet-evm",
@@ -13537,7 +13544,7 @@
"frame-system-benchmarking",
"frame-system-rpc-runtime-api",
"frame-try-runtime",
- "hex-literal",
+ "hex-literal 0.4.1",
"impl-trait-for-tuples",
"log",
"num_enum",
@@ -14437,7 +14444,7 @@
"frame-system-benchmarking",
"frame-system-rpc-runtime-api",
"frame-try-runtime",
- "hex-literal",
+ "hex-literal 0.3.4",
"log",
"pallet-authority-discovery",
"pallet-authorship",
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -187,7 +187,7 @@
derivative = { version = "2.2.0", features = ["use_core"] }
ethereum = { version = "0.14.0", default-features = false }
evm-core = { default-features = false, version = "0.37.0" }
-hex-literal = "0.3.4"
+hex-literal = "0.4.1"
impl-trait-for-tuples = "0.2.2"
jsonrpsee = { version = "0.16.2", features = ["macros", "server"] }
log = { version = "0.4.16", default-features = false }
client/rpc/Cargo.tomldiffbeforeafterboth--- a/client/rpc/Cargo.toml
+++ b/client/rpc/Cargo.toml
@@ -40,6 +40,9 @@
quartz-runtime = { workspace = true, optional = true }
unique-runtime = { workspace = true, optional = true }
+[dev-dependencies]
+hex-literal = { workspace = true }
+
[features]
default = ['opal-runtime']
all-runtimes = [
client/rpc/src/lib.rsdiffbeforeafterboth--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -450,16 +450,10 @@
pass_method!(
collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api;
changed_in 3, collection_by_id_before_version_3(collection) => |value| {
- use codec::IoReader;
- use up_data_structs::RpcCollectionVersion1;
- use up_data_structs::CollectionVersion1;
use sp_runtime::DispatchError;
if let Some(bytes) = value {
- let mut reader = IoReader(bytes.as_slice());
- Ok(Some(RpcCollection::<AccountId>::decode(&mut reader)
- .or_else(|_| RpcCollectionVersion1::<AccountId>::decode(&mut reader).map(|col| col.into()))
- .or_else(|_| CollectionVersion1::<AccountId>::decode(&mut reader).map(|col| col.into()))
+ Ok(Some(detect_type_and_decode_collection(bytes.as_slice())
.map_err(|_| DispatchError::Other("API Error: UniqueApi_collection_by_id"))?))
} else {
Ok(None)
@@ -506,3 +500,73 @@
fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {
keys.map(|keys| keys.into_iter().map(|key| key.into_bytes()).collect())
}
+
+fn decode_collection_from_bytes<T: codec::Decode>(
+ bytes: &[u8],
+) -> core::result::Result<T, codec::Error> {
+ let mut reader = codec::IoReader(bytes);
+ T::decode(&mut reader)
+}
+
+fn detect_type_and_decode_collection<AccountId: Decode>(
+ bytes: &[u8],
+) -> core::result::Result<RpcCollection<AccountId>, codec::Error> {
+ use up_data_structs::{CollectionVersion1, RpcCollectionVersion1};
+
+ decode_collection_from_bytes::<RpcCollection<AccountId>>(bytes)
+ .or_else(|_| {
+ decode_collection_from_bytes::<RpcCollectionVersion1<AccountId>>(bytes)
+ .map(|col| col.into())
+ })
+ .or_else(|_| {
+ decode_collection_from_bytes::<CollectionVersion1<AccountId>>(bytes)
+ .map(|col| col.into())
+ })
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use codec::IoReader;
+ use hex_literal::hex;
+ use up_data_structs::{CollectionVersion1, RawEncoded};
+
+ const ENCODED_COLLECTION_V1: [u8; 180] = hex!("aab94a1ee784bc17f68d76d4d48d736916ca6ff6315b8c1fa1175726c8345a390000285000720069006d00610020004c00690076006500d04500730065006d00700069006f00200064006900200063007200650061007a0069006f006e006500200064006900200075006e00610020006e0075006f0076006100200063006f006c006c0065007a0069006f006e00650020006400690020004e004600540021000c464e5400000000000000000000000000000000");
+ const ENCODED_RPC_COLLECTION_V2: [u8; 618] = hex!("d00dcc24bf66750d3809aa26884b930ec8a3094d6f6f19fdc62020b2fbec013400604d0069006e007400460065007300740020002d002000460075006e006e007900200061006e0069006d0061006c0073008c430072006f00730073006f0076006500720020006200650074007700650065006e00200061006e0069006d0061006c00730020002d00200066006f0072002000660075006e00104d46464100000000000000000000010001000100000004385f6f6c645f636f6e7374446174610001000c5c5f6f6c645f636f6e73744f6e436861696e536368656d6139047b226e6573746564223a7b226f6e436861696e4d65746144617461223a7b226e6573746564223a7b224e46544d657461223a7b226669656c6473223a7b22697066734a736f6e223a7b226964223a312c2272756c65223a227265717569726564222c2274797065223a22737472696e67227d2c2248656164223a7b226964223a322c2272756c65223a227265717569726564222c2274797065223a22737472696e67227d2c22426f6479223a7b226964223a332c2272756c65223a227265717569726564222c2274797065223a22737472696e67227d2c225461696c223a7b226964223a342c2272756c65223a227265717569726564222c2274797065223a22737472696e67227d7d7d7d7d7d7d485f6f6c645f736368656d6156657273696f6e18556e69717565685f6f6c645f7661726961626c654f6e436861696e536368656d6111017b22636f6c6c656374696f6e436f766572223a22516d53557a7139354c357a556777795a584d3731576a3762786b36557048515468633162536965347766706e5435227d000000");
+
+ #[test]
+ fn decoding_collection_v1() {
+ decode_collection_from_bytes::<CollectionVersion1<[u8; 32]>>(
+ ENCODED_COLLECTION_V1.as_slice(),
+ )
+ .unwrap();
+ }
+
+ #[test]
+ fn detecting_and_decoding_collection_v1() {
+ detect_type_and_decode_collection::<[u8; 32]>(ENCODED_COLLECTION_V1.as_slice()).unwrap();
+ }
+
+ #[test]
+ fn decoding_rpc_collection_v2() {
+ decode_collection_from_bytes::<RpcCollection<[u8; 32]>>(
+ ENCODED_RPC_COLLECTION_V2.as_slice(),
+ )
+ .unwrap();
+ }
+
+ #[test]
+ fn detecting_decoding_rpc_collection_v2() {
+ detect_type_and_decode_collection::<[u8; 32]>(ENCODED_RPC_COLLECTION_V2.as_slice())
+ .unwrap();
+ }
+
+ #[test]
+ fn rpc_collection_supports_decoding_through_vec() {
+ let mut bytes = IoReader(ENCODED_RPC_COLLECTION_V2.as_slice());
+ let vec = RawEncoded::decode(&mut bytes).unwrap();
+ println!("{:?}", vec.len());
+ let mut bytes = IoReader(vec.as_slice());
+ RpcCollection::<[u8; 32]>::decode(&mut bytes).unwrap();
+ }
+}
primitives/data-structs/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Primitives crate.18//!19//! This crate contains types, traits and constants.2021#![cfg_attr(not(feature = "std"), no_std)]2223use core::{24 convert::{TryFrom, TryInto},25 fmt,26 ops::Deref,27};28use frame_support::storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet};2930#[cfg(feature = "serde")]31use serde::{Serialize, Deserialize};3233use sp_core::U256;34use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};35use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};36use bondrewd::Bitfields;37use frame_support::{BoundedVec, traits::ConstU32};38use derivative::Derivative;39use scale_info::TypeInfo;4041mod bondrewd_codec;42mod bounded;43pub mod budget;44pub mod mapping;45mod migration;4647/// Maximum of decimal points.48pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;4950/// Maximum pieces for refungible token.51pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;52pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;5354/// Maximum tokens for user.55pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {56 100_00057} else {58 1059};6061/// Maximum for collections can be created.62pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {63 100_00064} else {65 1066};6768/// Maximum for various custom data of token.69pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {70 204871} else {72 1073};7475/// Maximum admins per collection.76pub const COLLECTION_ADMINS_LIMIT: u32 = 5;7778/// Maximum tokens per collection.79pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;8081/// Maximum tokens per account.82pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {83 1_000_00084} else {85 1086};8788/// Default timeout for transfer sponsoring NFT item.89pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;90/// Default timeout for transfer sponsoring fungible item.91pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;92/// Default timeout for transfer sponsoring refungible item.93pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;9495/// Default timeout for sponsored approving.96pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;9798// Schema limits99pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;100pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;101pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;102103// TODO: not used. Delete?104pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;105106/// Maximal length of a collection name.107pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;108109/// Maximal length of a collection description.110pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;111112/// Maximal length of a token prefix.113pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;114115/// Maximal length of a property key.116pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;117118/// Maximal length of a property value.119pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;120121/// A maximum number of token properties.122pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;123124/// Maximal lenght of extended property value.125pub const MAX_AUX_PROPERTY_VALUE_LENGTH: u32 = 2048;126127/// Maximum size for all collection properties.128pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;129130/// Maximum size of all token properties.131pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;132133/// How much items can be created per single134/// create_many call.135pub const MAX_ITEMS_PER_BATCH: u32 = 200;136137/// Used for limit bounded types of token custom data.138pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;139140/// Collection id.141#[derive(142 Encode,143 Decode,144 PartialEq,145 Eq,146 PartialOrd,147 Ord,148 Clone,149 Copy,150 Debug,151 Default,152 TypeInfo,153 MaxEncodedLen,154)]155#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]156pub struct CollectionId(pub u32);157impl EncodeLike<u32> for CollectionId {}158impl EncodeLike<CollectionId> for u32 {}159160impl From<u32> for CollectionId {161 fn from(value: u32) -> Self {162 Self(value)163 }164}165166/// Token id.167#[derive(168 Encode,169 Decode,170 PartialEq,171 Eq,172 PartialOrd,173 Ord,174 Clone,175 Copy,176 Debug,177 Default,178 TypeInfo,179 MaxEncodedLen,180)]181#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]182pub struct TokenId(pub u32);183impl EncodeLike<u32> for TokenId {}184impl EncodeLike<TokenId> for u32 {}185186impl TokenId {187 /// Try to get next token id.188 ///189 /// If next id cause overflow, then [`ArithmeticError::Overflow`] returned.190 pub fn try_next(self) -> Result<TokenId, ArithmeticError> {191 self.0192 .checked_add(1)193 .ok_or(ArithmeticError::Overflow)194 .map(Self)195 }196}197198impl From<TokenId> for U256 {199 fn from(t: TokenId) -> Self {200 t.0.into()201 }202}203204impl TryFrom<U256> for TokenId {205 type Error = &'static str;206207 fn try_from(value: U256) -> Result<Self, Self::Error> {208 Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))209 }210}211212/// Token data.213#[struct_versioning::versioned(version = 2, upper)]214#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]215#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]216pub struct TokenData<CrossAccountId> {217 /// Properties of token.218 pub properties: Vec<Property>,219220 /// Token owner.221 pub owner: Option<CrossAccountId>,222223 /// Token pieces.224 #[version(2.., upper(0))]225 pub pieces: u128,226}227228// TODO: unused type229pub struct OverflowError;230impl From<OverflowError> for &'static str {231 fn from(_: OverflowError) -> Self {232 "overflow occured"233 }234}235236/// Alias for decimal points type.237pub type DecimalPoints = u8;238239/// Collection mode.240///241/// Collection can represent various types of tokens.242/// Each collection can contain only one type of tokens at a time.243/// This type helps to understand which tokens the collection contains.244#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]245#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]246pub enum CollectionMode {247 /// Non fungible tokens.248 NFT,249 /// Fungible tokens.250 Fungible(DecimalPoints),251 /// Refungible tokens.252 ReFungible,253}254255impl CollectionMode {256 /// Get collection mod as number.257 pub fn id(&self) -> u8 {258 match self {259 CollectionMode::NFT => 1,260 CollectionMode::Fungible(_) => 2,261 CollectionMode::ReFungible => 3,262 }263 }264}265266// TODO: unused trait267pub trait SponsoringResolve<AccountId, Call> {268 fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;269}270271/// Access mode for some token operations.272#[derive(Encode, Decode, Eq, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]273#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]274pub enum AccessMode {275 /// Access grant for owner and admins. Used as default.276 Normal,277 /// Like a [`Normal`](AccessMode::Normal) but also users in allow list.278 AllowList,279}280impl Default for AccessMode {281 fn default() -> Self {282 Self::Normal283 }284}285286// TODO: remove in future.287#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]288#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]289pub enum SchemaVersion {290 ImageURL,291 Unique,292}293impl Default for SchemaVersion {294 fn default() -> Self {295 Self::ImageURL296 }297}298299// TODO: unused type300#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]301#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]302pub struct Ownership<AccountId> {303 pub owner: AccountId,304 pub fraction: u128,305}306307/// The state of collection sponsorship.308#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]309#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]310pub enum SponsorshipState<AccountId> {311 /// The fees are applied to the transaction sender.312 Disabled,313 /// The sponsor is under consideration. Until the sponsor gives his consent,314 /// the fee will still be charged to sender.315 Unconfirmed(AccountId),316 /// Transactions are sponsored by specified account.317 Confirmed(AccountId),318}319320impl<AccountId> SponsorshipState<AccountId> {321 /// Get a sponsor of the collection who has confirmed his status.322 pub fn sponsor(&self) -> Option<&AccountId> {323 match self {324 Self::Confirmed(sponsor) => Some(sponsor),325 _ => None,326 }327 }328329 /// Get a sponsor of the collection who has pending or confirmed status.330 pub fn pending_sponsor(&self) -> Option<&AccountId> {331 match self {332 Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),333 _ => None,334 }335 }336337 /// Whether the sponsorship is confirmed.338 pub fn confirmed(&self) -> bool {339 matches!(self, Self::Confirmed(_))340 }341}342343impl<T> Default for SponsorshipState<T> {344 fn default() -> Self {345 Self::Disabled346 }347}348349pub type CollectionName = BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>;350pub type CollectionDescription = BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>;351pub type CollectionTokenPrefix = BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>;352353#[derive(Bitfields, Clone, Copy, PartialEq, Eq, Debug, Default)]354#[bondrewd(enforce_bytes = 1)]355pub struct CollectionFlags {356 /// Tokens in foreign collections can be transferred, but not burnt357 #[bondrewd(bits = "0..1")]358 pub foreign: bool,359 /// Supports ERC721Metadata360 #[bondrewd(bits = "1..2")]361 pub erc721metadata: bool,362 /// External collections can't be managed using `unique` api363 #[bondrewd(bits = "7..8")]364 pub external: bool,365366 #[bondrewd(reserve, bits = "2..7")]367 pub reserved: u8,368}369bondrewd_codec!(CollectionFlags);370371/// Base structure for represent collection.372///373/// Used to provide basic functionality for all types of collections.374///375/// #### Note376/// Collection parameters, used in storage (see [`RpcCollection`] for the RPC version).377#[struct_versioning::versioned(version = 2, upper)]378#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]379pub struct Collection<AccountId> {380 /// Collection owner account.381 pub owner: AccountId,382383 /// Collection mode.384 pub mode: CollectionMode,385386 /// Access mode.387 #[version(..2)]388 pub access: AccessMode,389390 /// Collection name.391 pub name: CollectionName,392393 /// Collection description.394 pub description: CollectionDescription,395396 /// Token prefix.397 pub token_prefix: CollectionTokenPrefix,398399 #[version(..2)]400 pub mint_mode: bool,401402 #[version(..2)]403 pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,404405 #[version(..2)]406 pub schema_version: SchemaVersion,407408 /// The state of sponsorship of the collection.409 pub sponsorship: SponsorshipState<AccountId>,410411 /// Collection limits.412 pub limits: CollectionLimits,413414 /// Collection permissions.415 #[version(2.., upper(Default::default()))]416 pub permissions: CollectionPermissions,417418 #[version(2.., upper(Default::default()))]419 pub flags: CollectionFlags,420421 #[version(..2)]422 pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,423424 #[version(..2)]425 pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,426427 #[version(..2)]428 pub meta_update_permission: MetaUpdatePermission,429}430431#[derive(Debug, Encode, Decode, Clone, PartialEq, TypeInfo)]432#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]433pub struct RpcCollectionFlags {434 /// Is collection is foreign.435 pub foreign: bool,436 /// Collection supports ERC721Metadata.437 pub erc721metadata: bool,438}439440/// Collection parameters, used in RPC calls (see [`Collection`] for the storage version).441#[struct_versioning::versioned(version = 2, upper)]442#[derive(Debug, Encode, Decode, Clone, PartialEq, TypeInfo)]443#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]444pub struct RpcCollection<AccountId> {445 /// Collection owner account.446 pub owner: AccountId,447448 /// Collection mode.449 pub mode: CollectionMode,450451 /// Collection name.452 pub name: Vec<u16>,453454 /// Collection description.455 pub description: Vec<u16>,456457 /// Token prefix.458 pub token_prefix: Vec<u8>,459460 /// The state of sponsorship of the collection.461 pub sponsorship: SponsorshipState<AccountId>,462463 /// Collection limits.464 pub limits: CollectionLimits,465466 /// Collection permissions.467 pub permissions: CollectionPermissions,468469 /// Token property permissions.470 pub token_property_permissions: Vec<PropertyKeyPermission>,471472 /// Collection properties.473 pub properties: Vec<Property>,474475 /// Is collection read only.476 pub read_only: bool,477478 /// Extra collection flags479 #[version(2.., upper(RpcCollectionFlags {foreign: false, erc721metadata: false}))]480 pub flags: RpcCollectionFlags,481}482483impl<AccountId> From<CollectionVersion1<AccountId>> for RpcCollection<AccountId> {484 fn from(value: CollectionVersion1<AccountId>) -> Self {485 let CollectionVersion1 {486 name,487 description,488 owner,489 mode,490 access,491 token_prefix,492 mint_mode,493 sponsorship,494 limits,495 ..496 } = value;497498 RpcCollection {499 name: name.into_inner(),500 description: description.into_inner(),501 owner,502 mode,503 token_prefix: token_prefix.into_inner(),504 sponsorship,505 limits,506 permissions: CollectionPermissions {507 access: Some(access),508 mint_mode: Some(mint_mode),509 nesting: None,510 },511 token_property_permissions: Vec::default(),512 properties: Vec::default(),513 read_only: true,514515 flags: RpcCollectionFlags {516 foreign: false,517 erc721metadata: false,518 },519 }520 }521}522523pub struct RawEncoded(Vec<u8>);524525impl codec::Decode for RawEncoded {526 fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {527 let mut out = Vec::new();528 while let Ok(v) = input.read_byte() {529 out.push(v);530 }531 Ok(Self(out))532 }533}534535impl Deref for RawEncoded {536 type Target = Vec<u8>;537538 fn deref(&self) -> &Self::Target {539 return &self.0;540 }541}542543/// Data used for create collection.544///545/// All fields are wrapped in [`Option`], where `None` means chain default.546#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]547#[derivative(Debug, Default(bound = ""))]548pub struct CreateCollectionData<AccountId> {549 /// Collection mode.550 #[derivative(Default(value = "CollectionMode::NFT"))]551 pub mode: CollectionMode,552553 /// Access mode.554 pub access: Option<AccessMode>,555556 /// Collection name.557 pub name: CollectionName,558559 /// Collection description.560 pub description: CollectionDescription,561562 /// Token prefix.563 pub token_prefix: CollectionTokenPrefix,564565 /// Pending collection sponsor.566 pub pending_sponsor: Option<AccountId>,567568 /// Collection limits.569 pub limits: Option<CollectionLimits>,570571 /// Collection permissions.572 pub permissions: Option<CollectionPermissions>,573574 /// Token property permissions.575 pub token_property_permissions: CollectionPropertiesPermissionsVec,576577 /// Collection properties.578 pub properties: CollectionPropertiesVec,579}580581/// Bounded vector of properties permissions. Max length is [`MAX_PROPERTIES_PER_ITEM`].582// TODO: maybe rename to PropertiesPermissionsVec583pub type CollectionPropertiesPermissionsVec =584 BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;585586/// Bounded vector of properties. Max length is [`MAX_PROPERTIES_PER_ITEM`].587pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;588589/// Limits and restrictions of a collection.590///591/// All fields are wrapped in [`Option`], where `None` means chain default.592///593/// Update with `pallet_common::Pallet::clamp_limits`.594// IMPORTANT: When adding/removing fields from this struct - don't forget to also595#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]596#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]597// When adding/removing fields from this struct - don't forget to also update with `pallet_common::Pallet::clamp_limits`.598// TODO: move `pallet_common::Pallet::clamp_limits` into `impl CollectionLimits`.599// TODO: may be remove [`Option`] and **pub** from fields and create struct with default values.600pub struct CollectionLimits {601 /// How many tokens can a user have on one account.602 /// * Default - [`ACCOUNT_TOKEN_OWNERSHIP_LIMIT`].603 /// * Limit - [`MAX_TOKEN_OWNERSHIP`].604 pub account_token_ownership_limit: Option<u32>,605606 /// How many bytes of data are available for sponsorship.607 /// * Default - [`CUSTOM_DATA_LIMIT`].608 /// * Limit - [`CUSTOM_DATA_LIMIT`].609 pub sponsored_data_size: Option<u32>,610611 // FIXME should we delete this or repurpose it?612 /// Times in how many blocks we sponsor data.613 ///614 /// If is `Some(v)` then **setVariableMetadata** is sponsored if there is `v` block between transactions.615 ///616 /// * Default - [`SponsoringDisabled`](SponsoringRateLimit::SponsoringDisabled).617 /// * Limit - [`MAX_SPONSOR_TIMEOUT`].618 ///619 /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]620 pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,621 /// Maximum amount of tokens inside the collection. Chain default: [`COLLECTION_TOKEN_LIMIT`]622623 /// How many tokens can be mined into this collection.624 ///625 /// * Default - [`COLLECTION_TOKEN_LIMIT`].626 /// * Limit - [`COLLECTION_TOKEN_LIMIT`].627 pub token_limit: Option<u32>,628629 /// Timeouts for transfer sponsoring.630 ///631 /// * Default632 /// - **Fungible** - [`FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]633 /// - **NFT** - [`NFT_SPONSOR_TRANSFER_TIMEOUT`]634 /// - **Refungible** - [`REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT`]635 /// * Limit - [`MAX_SPONSOR_TIMEOUT`].636 pub sponsor_transfer_timeout: Option<u32>,637638 /// Timeout for sponsoring an approval in passed blocks.639 ///640 /// * Default - [`SPONSOR_APPROVE_TIMEOUT`].641 /// * Limit - [`MAX_SPONSOR_TIMEOUT`].642 pub sponsor_approve_timeout: Option<u32>,643644 /// Whether the collection owner of the collection can send tokens (which belong to other users).645 ///646 /// * Default - **false**.647 pub owner_can_transfer: Option<bool>,648649 /// Can the collection owner burn other people's tokens.650 ///651 /// * Default - **true**.652 pub owner_can_destroy: Option<bool>,653654 /// Is it possible to send tokens from this collection between users.655 ///656 /// * Default - **true**.657 pub transfers_enabled: Option<bool>,658}659660impl CollectionLimits {661 pub fn with_default_limits(collection_type: CollectionMode) -> Self {662 CollectionLimits {663 account_token_ownership_limit: Some(ACCOUNT_TOKEN_OWNERSHIP_LIMIT),664 sponsored_data_size: Some(CUSTOM_DATA_LIMIT),665 sponsored_data_rate_limit: Some(SponsoringRateLimit::SponsoringDisabled),666 token_limit: Some(COLLECTION_TOKEN_LIMIT),667 sponsor_transfer_timeout: match collection_type {668 CollectionMode::NFT => Some(NFT_SPONSOR_TRANSFER_TIMEOUT),669 CollectionMode::ReFungible => Some(REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),670 CollectionMode::Fungible(_) => Some(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),671 },672 sponsor_approve_timeout: Some(SPONSOR_APPROVE_TIMEOUT),673 owner_can_transfer: Some(false),674 owner_can_destroy: Some(true),675 transfers_enabled: Some(true),676 }677 }678679 /// Get effective value for [`account_token_ownership_limit`](self.account_token_ownership_limit).680 pub fn account_token_ownership_limit(&self) -> u32 {681 self.account_token_ownership_limit682 .unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)683 .min(MAX_TOKEN_OWNERSHIP)684 }685686 /// Get effective value for [`sponsored_data_size`](self.sponsored_data_size).687 pub fn sponsored_data_size(&self) -> u32 {688 self.sponsored_data_size689 .unwrap_or(CUSTOM_DATA_LIMIT)690 .min(CUSTOM_DATA_LIMIT)691 }692693 /// Get effective value for [`token_limit`](self.token_limit).694 pub fn token_limit(&self) -> u32 {695 self.token_limit696 .unwrap_or(COLLECTION_TOKEN_LIMIT)697 .min(COLLECTION_TOKEN_LIMIT)698 }699700 // TODO: may be replace u32 to mode?701 /// Get effective value for [`sponsor_transfer_timeout`](self.sponsor_transfer_timeout).702 pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {703 self.sponsor_transfer_timeout704 .unwrap_or(default)705 .min(MAX_SPONSOR_TIMEOUT)706 }707708 /// Get effective value for [`sponsor_approve_timeout`](self.sponsor_approve_timeout).709 pub fn sponsor_approve_timeout(&self) -> u32 {710 self.sponsor_approve_timeout711 .unwrap_or(SPONSOR_APPROVE_TIMEOUT)712 .min(MAX_SPONSOR_TIMEOUT)713 }714715 /// Get effective value for [`owner_can_transfer`](self.owner_can_transfer).716 pub fn owner_can_transfer(&self) -> bool {717 self.owner_can_transfer.unwrap_or(false)718 }719720 /// Get effective value for [`owner_can_transfer_instaled`](self.owner_can_transfer_instaled).721 pub fn owner_can_transfer_instaled(&self) -> bool {722 self.owner_can_transfer.is_some()723 }724725 /// Get effective value for [`owner_can_destroy`](self.owner_can_destroy).726 pub fn owner_can_destroy(&self) -> bool {727 self.owner_can_destroy.unwrap_or(true)728 }729730 /// Get effective value for [`transfers_enabled`](self.transfers_enabled).731 pub fn transfers_enabled(&self) -> bool {732 self.transfers_enabled.unwrap_or(true)733 }734735 /// Get effective value for [`sponsored_data_rate_limit`](self.sponsored_data_rate_limit).736 pub fn sponsored_data_rate_limit(&self) -> Option<u32> {737 match self738 .sponsored_data_rate_limit739 .unwrap_or(SponsoringRateLimit::SponsoringDisabled)740 {741 SponsoringRateLimit::SponsoringDisabled => None,742 SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),743 }744 }745}746747/// Permissions on certain operations within a collection.748///749/// Some fields are wrapped in [`Option`], where `None` means chain default.750///751/// Update with `pallet_common::Pallet::clamp_permissions`.752#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]753#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]754// When adding/removing fields from this struct - don't forget to also update `pallet_common::Pallet::clamp_permissions`.755// TODO: move `pallet_common::Pallet::clamp_permissions` into `impl CollectionPermissions`.756pub struct CollectionPermissions {757 /// Access mode.758 ///759 /// * Default - [`AccessMode::Normal`].760 pub access: Option<AccessMode>,761762 /// Minting allowance.763 ///764 /// * Default - **false**.765 pub mint_mode: Option<bool>,766767 /// Permissions for nesting.768 ///769 /// * Default770 /// - `token_owner` - **false**771 /// - `collection_admin` - **false**772 /// - `restricted` - **None**773 pub nesting: Option<NestingPermissions>,774}775776impl CollectionPermissions {777 /// Get effective value for [`access`](self.access).778 pub fn access(&self) -> AccessMode {779 self.access.unwrap_or(AccessMode::Normal)780 }781782 /// Get effective value for [`mint_mode`](self.mint_mode).783 pub fn mint_mode(&self) -> bool {784 self.mint_mode.unwrap_or(false)785 }786787 /// Get effective value for [`nesting`](self.nesting).788 pub fn nesting(&self) -> &NestingPermissions {789 static DEFAULT: NestingPermissions = NestingPermissions {790 token_owner: false,791 collection_admin: false,792 restricted: None,793 #[cfg(feature = "runtime-benchmarks")]794 permissive: false,795 };796 self.nesting.as_ref().unwrap_or(&DEFAULT)797 }798}799800/// Inner set for collections allowed to nest.801type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;802803/// Wraper for collections set allowing nest.804#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]805#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]806#[derivative(Debug)]807pub struct OwnerRestrictedSet(808 #[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]809 #[derivative(Debug(format_with = "bounded::set_debug"))]810 pub OwnerRestrictedSetInner,811);812813impl OwnerRestrictedSet {814 /// Create new set.815 pub fn new() -> Self {816 Self(Default::default())817 }818}819impl core::ops::Deref for OwnerRestrictedSet {820 type Target = OwnerRestrictedSetInner;821 fn deref(&self) -> &Self::Target {822 &self.0823 }824}825impl core::ops::DerefMut for OwnerRestrictedSet {826 fn deref_mut(&mut self) -> &mut Self::Target {827 &mut self.0828 }829}830831/// Part of collection permissions, if set, defines who is able to nest tokens into other tokens.832#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]833#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]834#[derivative(Debug)]835pub struct NestingPermissions {836 /// Owner of token can nest tokens under it.837 pub token_owner: bool,838 /// Admin of token collection can nest tokens under token.839 pub collection_admin: bool,840 /// If set - only tokens from specified collections can be nested.841 pub restricted: Option<OwnerRestrictedSet>,842843 #[cfg(feature = "runtime-benchmarks")]844 /// Anyone can nest tokens, mutually exclusive with `token_owner`, `admin`.845 pub permissive: bool,846}847848/// Enum denominating how often can sponsoring occur if it is enabled.849///850/// Used for [`collection limits`](CollectionLimits).851#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]852#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]853pub enum SponsoringRateLimit {854 /// Sponsoring is disabled, and the collection sponsor will not pay for transactions855 SponsoringDisabled,856 /// Once per how many blocks can sponsorship of a transaction type occur857 Blocks(u32),858}859860/// Data used to describe an NFT at creation.861#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]862#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]863#[derivative(Debug)]864pub struct CreateNftData {865 /// Key-value pairs used to describe the token as metadata866 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]867 #[derivative(Debug(format_with = "bounded::vec_debug"))]868 /// Properties that wil be assignet to created item.869 pub properties: CollectionPropertiesVec,870}871872/// Data used to describe a Fungible token at creation.873#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]874#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]875pub struct CreateFungibleData {876 /// Number of fungible coins minted877 pub value: u128,878}879880/// Data used to describe a Refungible token at creation.881#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]882#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]883#[derivative(Debug)]884pub struct CreateReFungibleData {885 /// Number of pieces the RFT is split into886 pub pieces: u128,887888 /// Key-value pairs used to describe the token as metadata889 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]890 #[derivative(Debug(format_with = "bounded::vec_debug"))]891 pub properties: CollectionPropertiesVec,892}893894// TODO: remove this.895#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]896#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]897pub enum MetaUpdatePermission {898 ItemOwner,899 Admin,900 None,901}902903/// Enum holding data used for creation of all three item types.904/// Unified data for create item.905#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]906#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]907pub enum CreateItemData {908 /// Data for create NFT.909 NFT(CreateNftData),910 /// Data for create Fungible item.911 Fungible(CreateFungibleData),912 /// Data for create ReFungible item.913 ReFungible(CreateReFungibleData),914}915916/// Extended data for create NFT.917#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]918#[derivative(Debug)]919pub struct CreateNftExData<CrossAccountId> {920 /// Properties that wil be assignet to created item.921 #[derivative(Debug(format_with = "bounded::vec_debug"))]922 pub properties: CollectionPropertiesVec,923924 /// Owner of creating item.925 pub owner: CrossAccountId,926}927928/// Extended data for create ReFungible item.929#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]930#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]931pub struct CreateRefungibleExMultipleOwners<CrossAccountId> {932 #[derivative(Debug(format_with = "bounded::map_debug"))]933 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,934 #[derivative(Debug(format_with = "bounded::vec_debug"))]935 pub properties: CollectionPropertiesVec,936}937938/// Extended data for create ReFungible item.939#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]940#[derivative(Debug(bound = "CrossAccountId: fmt::Debug"))]941pub struct CreateRefungibleExSingleOwner<CrossAccountId> {942 pub user: CrossAccountId,943 pub pieces: u128,944 #[derivative(Debug(format_with = "bounded::vec_debug"))]945 pub properties: CollectionPropertiesVec,946}947948/// Unified extended data for creating item.949#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]950#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]951pub enum CreateItemExData<CrossAccountId> {952 /// Extended data for create NFT.953 NFT(954 #[derivative(Debug(format_with = "bounded::vec_debug"))]955 BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,956 ),957958 /// Extended data for create Fungible item.959 Fungible(960 #[derivative(Debug(format_with = "bounded::map_debug"))]961 BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,962 ),963964 /// Extended data for create ReFungible item in case of965 /// many tokens, each may have only one owner966 RefungibleMultipleItems(967 #[derivative(Debug(format_with = "bounded::vec_debug"))]968 BoundedVec<CreateRefungibleExSingleOwner<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,969 ),970971 /// Extended data for create ReFungible item in case of972 /// single token, which may have many owners973 RefungibleMultipleOwners(CreateRefungibleExMultipleOwners<CrossAccountId>),974}975976impl From<CreateNftData> for CreateItemData {977 fn from(item: CreateNftData) -> Self {978 CreateItemData::NFT(item)979 }980}981982impl From<CreateReFungibleData> for CreateItemData {983 fn from(item: CreateReFungibleData) -> Self {984 CreateItemData::ReFungible(item)985 }986}987988impl From<CreateFungibleData> for CreateItemData {989 fn from(item: CreateFungibleData) -> Self {990 CreateItemData::Fungible(item)991 }992}993994/// Token's address, dictated by its collection and token IDs.995#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]996#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]997// todo possibly rename to be used generally as an address pair998pub struct TokenChild {999 /// Token id.1000 pub token: TokenId,10011002 /// Collection id.1003 pub collection: CollectionId,1004}10051006/// Collection statistics.1007#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]1008#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1009pub struct CollectionStats {1010 /// Number of created items.1011 pub created: u32,10121013 /// Number of burned items.1014 pub destroyed: u32,10151016 /// Number of current items.1017 pub alive: u32,1018}10191020/// This type works like [`PhantomData`] but supports generating _scale-info_ descriptions to generate node metadata.1021#[derive(Encode, Decode, Clone, Debug)]1022#[cfg_attr(feature = "std", derive(PartialEq))]1023pub struct PhantomType<T>(core::marker::PhantomData<T>);10241025impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {1026 type Identity = PhantomType<T>;10271028 fn type_info() -> scale_info::Type {1029 use scale_info::{1030 Type, Path,1031 build::{FieldsBuilder, UnnamedFields},1032 form::MetaForm,1033 type_params,1034 };1035 Type::builder()1036 .path(Path::new("up_data_structs", "PhantomType"))1037 .type_params(type_params!(T))1038 .composite(1039 <FieldsBuilder<MetaForm, UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()),1040 )1041 }1042}1043impl<T> MaxEncodedLen for PhantomType<T> {1044 fn max_encoded_len() -> usize {1045 01046 }1047}10481049/// Bounded vector of bytes.1050pub type BoundedBytes<S> = BoundedVec<u8, S>;10511052/// Extra properties for external collections.1053pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;10541055/// Property key.1056pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;10571058/// Property value.1059pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;10601061/// Property permission.1062#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone, Default)]1063#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1064pub struct PropertyPermission {1065 /// Permission to change the property and property permission.1066 ///1067 /// If it **false** then you can not change corresponding property even if [`collection_admin`] and [`token_owner`] are **true**.1068 pub mutable: bool,10691070 /// Change permission for the collection administrator.1071 pub collection_admin: bool,10721073 /// Permission to change the property for the owner of the token.1074 pub token_owner: bool,1075}10761077impl PropertyPermission {1078 /// Creates mutable property permission but changes restricted for collection admin and token owner.1079 pub fn none() -> Self {1080 Self {1081 mutable: true,1082 collection_admin: false,1083 token_owner: false,1084 }1085 }1086}10871088/// Property is simpl key-value record.1089#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]1090#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1091pub struct Property {1092 /// Property key.1093 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1094 pub key: PropertyKey,10951096 /// Property value.1097 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1098 pub value: PropertyValue,1099}11001101impl Into<(PropertyKey, PropertyValue)> for Property {1102 fn into(self) -> (PropertyKey, PropertyValue) {1103 (self.key, self.value)1104 }1105}11061107/// Record for proprty key permission.1108#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]1109#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1110pub struct PropertyKeyPermission {1111 /// Key.1112 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1113 pub key: PropertyKey,11141115 /// Permission.1116 pub permission: PropertyPermission,1117}11181119impl Into<(PropertyKey, PropertyPermission)> for PropertyKeyPermission {1120 fn into(self) -> (PropertyKey, PropertyPermission) {1121 (self.key, self.permission)1122 }1123}11241125/// Errors for properties actions.1126#[derive(Debug)]1127pub enum PropertiesError {1128 /// The space allocated for properties has run out.1129 ///1130 /// * Limit for colection - [`MAX_COLLECTION_PROPERTIES_SIZE`].1131 /// * Limit for token - [`MAX_TOKEN_PROPERTIES_SIZE`].1132 NoSpaceForProperty,11331134 /// The property limit has been reached.1135 ///1136 /// * Limit - [`MAX_PROPERTIES_PER_ITEM`].1137 PropertyLimitReached,11381139 /// Property key contains not allowed character.1140 InvalidCharacterInPropertyKey,11411142 /// Property key length is too long.1143 ///1144 /// * Limit - [`MAX_PROPERTY_KEY_LENGTH`].1145 PropertyKeyIsTooLong,11461147 /// Property key is empty.1148 EmptyPropertyKey,1149}11501151/// Token owner error: it could be either `NotFound` ot `MultipleOwners`.1152#[derive(Debug)]1153pub enum TokenOwnerError {1154 NotFound,1155 MultipleOwners,1156}11571158/// Marker for scope of property.1159///1160/// Scoped property can't be changed by user. Used for external collections.1161#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]1162pub enum PropertyScope {1163 None,1164 Rmrk,1165}11661167impl PropertyScope {1168 pub fn prefix(&self) -> &'static [u8] {1169 match self {1170 Self::None => b"",1171 Self::Rmrk => b"rmrk:",1172 }1173 }1174 /// Apply scope to property key.1175 pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {1176 let prefix = self.prefix();1177 if prefix == b"" {1178 return Ok(key);1179 }1180 [prefix, key.as_slice()]1181 .concat()1182 .try_into()1183 .map_err(|_| PropertiesError::PropertyKeyIsTooLong)1184 }1185}11861187/// Trait for operate with properties.1188pub trait TrySetProperty: Sized {1189 type Value;11901191 /// Try to set property with scope.1192 fn try_scoped_set(1193 &mut self,1194 scope: PropertyScope,1195 key: PropertyKey,1196 value: Self::Value,1197 ) -> Result<Option<Self::Value>, PropertiesError>;11981199 /// Try to set property with scope from iterator.1200 fn try_scoped_set_from_iter<I, KV>(1201 &mut self,1202 scope: PropertyScope,1203 iter: I,1204 ) -> Result<(), PropertiesError>1205 where1206 I: Iterator<Item = KV>,1207 KV: Into<(PropertyKey, Self::Value)>,1208 {1209 for kv in iter {1210 let (key, value) = kv.into();1211 self.try_scoped_set(scope, key, value)?;1212 }12131214 Ok(())1215 }12161217 /// Try to set property.1218 fn try_set(1219 &mut self,1220 key: PropertyKey,1221 value: Self::Value,1222 ) -> Result<Option<Self::Value>, PropertiesError> {1223 self.try_scoped_set(PropertyScope::None, key, value)1224 }12251226 /// Try to set property from iterator.1227 fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>1228 where1229 I: Iterator<Item = KV>,1230 KV: Into<(PropertyKey, Self::Value)>,1231 {1232 self.try_scoped_set_from_iter(PropertyScope::None, iter)1233 }1234}12351236/// Wrapped map for storing properties.1237#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]1238#[derivative(Default(bound = ""))]1239pub struct PropertiesMap<Value>(1240 BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,1241);12421243impl<Value> PropertiesMap<Value> {1244 /// Create new property map.1245 pub fn new() -> Self {1246 Self(BoundedBTreeMap::new())1247 }12481249 /// Remove property from map.1250 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {1251 Self::check_property_key(key)?;12521253 Ok(self.0.remove(key))1254 }12551256 /// Get property with appropriate key from map.1257 pub fn get(&self, key: &PropertyKey) -> Option<&Value> {1258 self.0.get(key)1259 }12601261 /// Check if map contains key.1262 pub fn contains_key(&self, key: &PropertyKey) -> bool {1263 self.0.contains_key(key)1264 }12651266 /// Check if map contains key with key validation.1267 fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {1268 if key.is_empty() {1269 return Err(PropertiesError::EmptyPropertyKey);1270 }12711272 for byte in key.as_slice().iter() {1273 let byte = *byte;12741275 if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {1276 return Err(PropertiesError::InvalidCharacterInPropertyKey);1277 }1278 }12791280 Ok(())1281 }12821283 pub fn values(&self) -> impl Iterator<Item = &Value> {1284 self.0.values()1285 }12861287 pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {1288 self.0.iter()1289 }1290}12911292impl<Value> IntoIterator for PropertiesMap<Value> {1293 type Item = (PropertyKey, Value);1294 type IntoIter = <1295 BoundedBTreeMap<1296 PropertyKey,1297 Value,1298 ConstU32<MAX_PROPERTIES_PER_ITEM>1299 > as IntoIterator1300 >::IntoIter;13011302 fn into_iter(self) -> Self::IntoIter {1303 self.0.into_iter()1304 }1305}13061307impl<Value> TrySetProperty for PropertiesMap<Value> {1308 type Value = Value;13091310 fn try_scoped_set(1311 &mut self,1312 scope: PropertyScope,1313 key: PropertyKey,1314 value: Self::Value,1315 ) -> Result<Option<Self::Value>, PropertiesError> {1316 Self::check_property_key(&key)?;13171318 let key = scope.apply(key)?;1319 self.01320 .try_insert(key, value)1321 .map_err(|_| PropertiesError::PropertyLimitReached)1322 }1323}13241325/// Alias for property permissions map.1326pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;13271328fn slice_size(data: &[u8]) -> u32 {1329 scoped_slice_size(PropertyScope::None, data)1330}1331fn scoped_slice_size(scope: PropertyScope, data: &[u8]) -> u32 {1332 use codec::Compact;1333 let prefix = scope.prefix();1334 <Compact<u32>>::encoded_size(&Compact(data.len() as u32 + prefix.len() as u32)) as u321335 + data.len() as u321336 + prefix.len() as u321337}13381339/// Wrapper for properties map with consumed space control.1340#[derive(Encode, Decode, TypeInfo, Clone, PartialEq)]1341pub struct Properties<const S: u32> {1342 map: PropertiesMap<PropertyValue>,1343 consumed_space: u32,1344 // May be not zero, previously served as a current S generic1345 _reserved: u32,1346}13471348impl<const S: u32> MaxEncodedLen for Properties<S> {1349 fn max_encoded_len() -> usize {1350 // len of map + len of consumed_space + len of space_limit1351 u32::max_encoded_len() * 3 + S as usize1352 }1353}13541355impl<const S: u32> Default for Properties<S> {1356 fn default() -> Self {1357 Self::new()1358 }1359}13601361impl<const S: u32> Properties<S> {1362 /// Create new properies container.1363 pub fn new() -> Self {1364 Self {1365 map: PropertiesMap::new(),1366 consumed_space: 0,1367 _reserved: 0,1368 }1369 }13701371 /// Remove propery with appropiate key.1372 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {1373 let value = self.map.remove(key)?;13741375 if let Some(ref value) = value {1376 let kv_len = slice_size(key) + slice_size(value);1377 self.consumed_space = self.consumed_space.saturating_sub(kv_len);1378 }13791380 Ok(value)1381 }13821383 /// Get property with appropriate key.1384 pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {1385 self.map.get(key)1386 }13871388 /// Recomputes the consumed space for the current properties state.1389 /// Needed to repair a token due to a bug fixed in the [PR #733](https://github.com/UniqueNetwork/unique-chain/pull/773).1390 pub fn recompute_consumed_space(&mut self) {1391 self.consumed_space = self1392 .map1393 .iter()1394 .map(|(key, value)| slice_size(key) + slice_size(value))1395 .sum();1396 }1397}13981399impl<const S: u32> IntoIterator for Properties<S> {1400 type Item = (PropertyKey, PropertyValue);1401 type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;14021403 fn into_iter(self) -> Self::IntoIter {1404 self.map.into_iter()1405 }1406}14071408impl<const S: u32> TrySetProperty for Properties<S> {1409 type Value = PropertyValue;14101411 fn try_scoped_set(1412 &mut self,1413 scope: PropertyScope,1414 key: PropertyKey,1415 value: Self::Value,1416 ) -> Result<Option<Self::Value>, PropertiesError> {1417 let key_size = scoped_slice_size(scope, &key);1418 let value_size = slice_size(&value) as u32;14191420 if self.consumed_space + value_size + key_size > S && !cfg!(feature = "runtime-benchmarks")1421 {1422 return Err(PropertiesError::NoSpaceForProperty);1423 }14241425 let old_value = self.map.try_scoped_set(scope, key, value)?;14261427 if let Some(old_value) = old_value.as_ref() {1428 let old_value_size = slice_size(&old_value);1429 self.consumed_space = self.consumed_space.saturating_sub(old_value_size) + value_size;1430 } else {1431 self.consumed_space += key_size + value_size;1432 }14331434 Ok(old_value)1435 }1436}14371438pub type CollectionProperties = Properties<MAX_COLLECTION_PROPERTIES_SIZE>;1439pub type TokenProperties = Properties<MAX_TOKEN_PROPERTIES_SIZE>;14401441#[cfg(test)]1442mod tests {1443 use super::*;1444 use codec::IoReader;14451446 #[test]1447 fn rpc_collection_supports_decoding_old_versions() {1448 let encoded_rpc_collection: [u8; 1013] = [1449 0, 1, 250, 241, 137, 120, 188, 29, 94, 210, 193, 237, 186, 22, 203, 241, 52, 248, 167,1450 235, 241, 211, 236, 28, 138, 156, 59, 160, 156, 105, 39, 247, 207, 101, 0, 0, 48, 65,1451 0, 73, 0, 32, 0, 67, 0, 114, 0, 101, 0, 97, 0, 116, 0, 105, 0, 111, 0, 110, 0, 115, 0,1452 252, 65, 0, 32, 0, 112, 0, 105, 0, 101, 0, 99, 0, 101, 0, 32, 0, 111, 0, 102, 0, 32, 0,1453 97, 0, 32, 0, 109, 0, 97, 0, 99, 0, 104, 0, 105, 0, 110, 0, 101, 0, 32, 0, 109, 0, 105,1454 0, 110, 0, 100, 0, 46, 0, 32, 0, 69, 0, 118, 0, 101, 0, 114, 0, 121, 0, 32, 0, 78, 0,1455 70, 0, 84, 0, 32, 0, 105, 0, 115, 0, 32, 0, 109, 0, 97, 0, 100, 0, 101, 0, 32, 0, 101,1456 0, 120, 0, 99, 0, 108, 0, 117, 0, 115, 0, 105, 0, 118, 0, 101, 0, 108, 0, 121, 0, 32,1457 0, 98, 0, 121, 0, 32, 0, 65, 0, 73, 0, 46, 0, 12, 65, 73, 67, 0, 0, 1, 0, 0, 0, 0, 0,1458 0, 0, 0, 0, 0, 17, 1, 123, 34, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 67, 111,1459 118, 101, 114, 34, 58, 34, 81, 109, 98, 52, 104, 122, 76, 101, 51, 49, 102, 98, 71, 74,1460 77, 89, 68, 82, 88, 84, 115, 107, 56, 49, 76, 103, 76, 97, 88, 76, 69, 112, 121, 97,1461 122, 102, 66, 85, 103, 111, 110, 118, 49, 118, 84, 85, 34, 125, 125, 11, 123, 34, 110,1462 101, 115, 116, 101, 100, 34, 58, 123, 34, 111, 110, 67, 104, 97, 105, 110, 77, 101,1463 116, 97, 68, 97, 116, 97, 34, 58, 123, 34, 110, 101, 115, 116, 101, 100, 34, 58, 123,1464 34, 78, 70, 84, 77, 101, 116, 97, 34, 58, 123, 34, 102, 105, 101, 108, 100, 115, 34,1465 58, 123, 34, 105, 112, 102, 115, 74, 115, 111, 110, 34, 58, 123, 34, 105, 100, 34, 58,1466 49, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34,1467 44, 34, 116, 121, 112, 101, 34, 58, 34, 115, 116, 114, 105, 110, 103, 34, 125, 44, 34,1468 67, 111, 108, 111, 114, 34, 58, 123, 34, 105, 100, 34, 58, 50, 44, 34, 114, 117, 108,1469 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121, 112,1470 101, 34, 58, 34, 67, 111, 108, 111, 114, 34, 125, 44, 34, 73, 110, 116, 101, 110, 115,1471 105, 111, 110, 115, 34, 58, 123, 34, 105, 100, 34, 58, 51, 44, 34, 114, 117, 108, 101,1472 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121, 112, 101, 34,1473 58, 34, 73, 110, 116, 101, 110, 115, 105, 111, 110, 115, 34, 125, 44, 34, 77, 111, 111,1474 100, 34, 58, 123, 34, 105, 100, 34, 58, 52, 44, 34, 114, 117, 108, 101, 34, 58, 34,1475 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 77,1476 111, 111, 100, 34, 125, 125, 125, 44, 34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 111,1477 112, 116, 105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34,1478 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 67, 111, 108, 111, 114, 101, 100, 92, 34,1479 125, 34, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92,1480 34, 58, 92, 34, 66, 108, 97, 99, 107, 38, 87, 104, 105, 116, 101, 92, 34, 125, 34, 125,1481 44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34,1482 58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 125, 125, 44, 34, 73, 110,1483 116, 101, 110, 115, 105, 111, 110, 115, 34, 58, 123, 34, 111, 112, 116, 105, 111, 110,1484 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92, 34, 101, 110,1485 92, 34, 58, 92, 34, 101, 118, 105, 108, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108,1486 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 103, 111, 111, 100, 92,1487 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 34, 123, 92, 34, 101, 110,1488 92, 34, 58, 92, 34, 110, 101, 117, 116, 114, 97, 108, 92, 34, 125, 34, 125, 44, 34,1489 118, 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 48,1490 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 44, 34, 102, 105, 101, 108, 100, 51,1491 34, 58, 50, 125, 125, 44, 34, 77, 111, 111, 100, 34, 58, 123, 34, 111, 112, 116, 105,1492 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92, 34,1493 101, 110, 92, 34, 58, 92, 34, 65, 98, 115, 116, 114, 97, 99, 116, 92, 34, 125, 34, 44,1494 34, 102, 105, 101, 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34,1495 85, 110, 99, 97, 110, 110, 101, 121, 32, 118, 97, 108, 108, 101, 121, 92, 34, 125, 34,1496 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92,1497 34, 83, 117, 114, 114, 101, 97, 108, 105, 115, 116, 92, 34, 125, 34, 125, 44, 34, 118,1498 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 48, 44,1499 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 44, 34, 102, 105, 101, 108, 100, 51, 34,1500 58, 50, 125, 125, 125, 125, 125, 125, 0,1501 ];1502 let mut bytes = IoReader(encoded_rpc_collection.as_slice());1503 CollectionVersion1::<[u8; 34]>::decode(&mut bytes).unwrap();1504 }15051506 #[test]1507 fn rpc_collection_supports_decoding_new_versions() {1508 let encoded_rpc_collection: [u8; 1576] = [1509 0, 1, 238, 236, 179, 149, 150, 47, 71, 194, 69, 174, 250, 116, 251, 148, 90, 15, 56,1510 220, 91, 79, 49, 79, 45, 197, 171, 98, 14, 171, 80, 23, 58, 92, 0, 96, 77, 0, 105, 0,1511 110, 0, 116, 0, 70, 0, 101, 0, 115, 0, 116, 0, 32, 0, 83, 0, 121, 0, 109, 0, 109, 0,1512 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 66, 0, 114, 0, 101, 0, 97, 0, 99, 0, 104, 0,1513 113, 3, 83, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 104, 0,1514 97, 0, 115, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101, 0, 116, 0, 104, 0, 105, 0, 110, 0,1515 103, 0, 32, 0, 105, 0, 110, 0, 116, 0, 111, 0, 120, 0, 105, 0, 99, 0, 97, 0, 116, 0,1516 105, 0, 110, 0, 103, 0, 32, 0, 116, 0, 104, 0, 97, 0, 116, 0, 32, 0, 100, 0, 114, 0,1517 97, 0, 119, 0, 115, 0, 32, 0, 121, 0, 111, 0, 117, 0, 32, 0, 105, 0, 110, 0, 46, 0, 10,1518 0, 73, 0, 110, 0, 115, 0, 112, 0, 105, 0, 114, 0, 101, 0, 100, 0, 32, 0, 98, 0, 121, 0,1519 32, 0, 116, 0, 104, 0, 101, 0, 32, 0, 112, 0, 101, 0, 114, 0, 102, 0, 101, 0, 99, 0,1520 116, 0, 105, 0, 111, 0, 110, 0, 32, 0, 111, 0, 102, 0, 32, 0, 116, 0, 104, 0, 101, 0,1521 32, 0, 115, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 44, 0, 32, 0,1522 73, 0, 32, 0, 104, 0, 97, 0, 118, 0, 101, 0, 32, 0, 99, 0, 114, 0, 101, 0, 97, 0, 116,1523 0, 101, 0, 100, 0, 32, 0, 115, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 105,1524 0, 99, 0, 97, 0, 108, 0, 32, 0, 105, 0, 109, 0, 97, 0, 103, 0, 101, 0, 115, 0, 32, 0,1525 111, 0, 102, 0, 32, 0, 115, 0, 101, 0, 118, 0, 101, 0, 114, 0, 97, 0, 108, 0, 32, 0,1526 118, 0, 101, 0, 114, 0, 116, 0, 105, 0, 99, 0, 101, 0, 115, 0, 44, 0, 32, 0, 98, 0,1527 117, 0, 116, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101, 0, 32, 0, 115, 0, 121, 0, 109, 0,1528 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 98, 0, 114, 0, 101, 0, 97, 0, 99, 0,1529 104, 0, 101, 0, 115, 0, 32, 0, 97, 0, 110, 0, 100, 0, 32, 0, 99, 0, 111, 0, 108, 0,1530 111, 0, 114, 0, 115, 0, 32, 0, 116, 0, 104, 0, 97, 0, 116, 0, 32, 0, 109, 0, 97, 0,1531 107, 0, 101, 0, 32, 0, 101, 0, 97, 0, 99, 0, 104, 0, 32, 0, 105, 0, 109, 0, 97, 0, 103,1532 0, 101, 0, 32, 0, 85, 0, 78, 0, 73, 0, 81, 0, 85, 0, 69, 0, 46, 0, 12, 83, 121, 66, 0,1533 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 4, 56, 95, 111, 108, 100, 95, 99,1534 111, 110, 115, 116, 68, 97, 116, 97, 0, 1, 0, 12, 92, 95, 111, 108, 100, 95, 99, 111,1535 110, 115, 116, 79, 110, 67, 104, 97, 105, 110, 83, 99, 104, 101, 109, 97, 97, 13, 123,1536 34, 110, 101, 115, 116, 101, 100, 34, 58, 123, 34, 111, 110, 67, 104, 97, 105, 110, 77,1537 101, 116, 97, 68, 97, 116, 97, 34, 58, 123, 34, 110, 101, 115, 116, 101, 100, 34, 58,1538 123, 34, 78, 70, 84, 77, 101, 116, 97, 34, 58, 123, 34, 102, 105, 101, 108, 100, 115,1539 34, 58, 123, 34, 105, 112, 102, 115, 74, 115, 111, 110, 34, 58, 123, 34, 105, 100, 34,1540 58, 49, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100,1541 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 115, 116, 114, 105, 110, 103, 34, 125, 44,1542 34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 105, 100, 34, 58, 50, 44, 34, 114, 117,1543 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121,1544 112, 101, 34, 58, 34, 67, 111, 108, 111, 114, 34, 125, 44, 34, 83, 121, 109, 109, 101,1545 116, 114, 121, 32, 66, 114, 101, 97, 99, 104, 34, 58, 123, 34, 105, 100, 34, 58, 51,1546 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44,1547 34, 116, 121, 112, 101, 34, 58, 34, 83, 121, 109, 109, 101, 116, 114, 121, 32, 66, 114,1548 101, 97, 99, 104, 34, 125, 44, 34, 86, 101, 114, 116, 105, 99, 101, 34, 58, 123, 34,1549 105, 100, 34, 58, 52, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105,1550 114, 101, 100, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 86, 101, 114, 116, 105, 99,1551 101, 34, 125, 125, 125, 44, 34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 111, 112, 116,1552 105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92,1553 34, 101, 110, 92, 34, 58, 92, 34, 49, 32, 32, 32, 92, 34, 125, 34, 44, 34, 102, 105,1554 101, 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 50, 32, 92,1555 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 34, 123, 92, 34, 101, 110,1556 92, 34, 58, 92, 34, 51, 92, 34, 125, 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34,1557 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100,1558 50, 34, 58, 49, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 50, 125, 125, 44, 34, 83,1559 121, 109, 109, 101, 116, 114, 121, 32, 66, 114, 101, 97, 99, 104, 34, 58, 123, 34, 111,1560 112, 116, 105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34,1561 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 49, 92, 34, 125, 34, 44, 34, 102, 105, 101,1562 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 50, 92, 34, 125,1563 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100,1564 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 125, 125, 44, 34, 86,1565 101, 114, 116, 105, 99, 101, 34, 58, 123, 34, 111, 112, 116, 105, 111, 110, 115, 34,1566 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34,1567 58, 92, 34, 54, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 34, 123,1568 92, 34, 101, 110, 92, 34, 58, 92, 34, 55, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108,1569 100, 51, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 56, 92, 34, 125, 34,1570 44, 34, 102, 105, 101, 108, 100, 52, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92,1571 34, 57, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 53, 34, 58, 34, 123, 92, 34,1572 101, 110, 92, 34, 58, 92, 34, 49, 48, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100,1573 54, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 49, 49, 92, 34, 125, 34, 44,1574 34, 102, 105, 101, 108, 100, 55, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34,1575 49, 50, 92, 34, 125, 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34,1576 102, 105, 101, 108, 100, 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58,1577 49, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 50, 44, 34, 102, 105, 101, 108, 100,1578 52, 34, 58, 51, 44, 34, 102, 105, 101, 108, 100, 53, 34, 58, 52, 44, 34, 102, 105, 101,1579 108, 100, 54, 34, 58, 53, 44, 34, 102, 105, 101, 108, 100, 55, 34, 58, 54, 125, 125,1580 125, 125, 125, 125, 72, 95, 111, 108, 100, 95, 115, 99, 104, 101, 109, 97, 86, 101,1581 114, 115, 105, 111, 110, 24, 85, 110, 105, 113, 117, 101, 104, 95, 111, 108, 100, 95,1582 118, 97, 114, 105, 97, 98, 108, 101, 79, 110, 67, 104, 97, 105, 110, 83, 99, 104, 101,1583 109, 97, 17, 1, 123, 34, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 67, 111, 118,1584 101, 114, 34, 58, 34, 81, 109, 82, 67, 77, 84, 109, 57, 118, 81, 107, 76, 89, 86, 65,1585 54, 54, 87, 80, 49, 75, 72, 57, 55, 106, 84, 76, 76, 115, 56, 74, 78, 86, 65, 114, 80,1586 66, 52, 56, 98, 106, 87, 84, 75, 74, 110, 34, 125, 0, 0, 0,1587 ];1588 let mut bytes = IoReader(encoded_rpc_collection.as_slice());1589 RpcCollection::<[u8; 34]>::decode(&mut bytes).unwrap();1590 }15911592 #[test]1593 fn rpc_collection_supports_decoding_through_vec() {1594 let encoded_rpc_collection: [u8; 1576] = [1595 0, 1, 238, 236, 179, 149, 150, 47, 71, 194, 69, 174, 250, 116, 251, 148, 90, 15, 56,1596 220, 91, 79, 49, 79, 45, 197, 171, 98, 14, 171, 80, 23, 58, 92, 0, 96, 77, 0, 105, 0,1597 110, 0, 116, 0, 70, 0, 101, 0, 115, 0, 116, 0, 32, 0, 83, 0, 121, 0, 109, 0, 109, 0,1598 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 66, 0, 114, 0, 101, 0, 97, 0, 99, 0, 104, 0,1599 113, 3, 83, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 104, 0,1600 97, 0, 115, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101, 0, 116, 0, 104, 0, 105, 0, 110, 0,1601 103, 0, 32, 0, 105, 0, 110, 0, 116, 0, 111, 0, 120, 0, 105, 0, 99, 0, 97, 0, 116, 0,1602 105, 0, 110, 0, 103, 0, 32, 0, 116, 0, 104, 0, 97, 0, 116, 0, 32, 0, 100, 0, 114, 0,1603 97, 0, 119, 0, 115, 0, 32, 0, 121, 0, 111, 0, 117, 0, 32, 0, 105, 0, 110, 0, 46, 0, 10,1604 0, 73, 0, 110, 0, 115, 0, 112, 0, 105, 0, 114, 0, 101, 0, 100, 0, 32, 0, 98, 0, 121, 0,1605 32, 0, 116, 0, 104, 0, 101, 0, 32, 0, 112, 0, 101, 0, 114, 0, 102, 0, 101, 0, 99, 0,1606 116, 0, 105, 0, 111, 0, 110, 0, 32, 0, 111, 0, 102, 0, 32, 0, 116, 0, 104, 0, 101, 0,1607 32, 0, 115, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 44, 0, 32, 0,1608 73, 0, 32, 0, 104, 0, 97, 0, 118, 0, 101, 0, 32, 0, 99, 0, 114, 0, 101, 0, 97, 0, 116,1609 0, 101, 0, 100, 0, 32, 0, 115, 0, 121, 0, 109, 0, 109, 0, 101, 0, 116, 0, 114, 0, 105,1610 0, 99, 0, 97, 0, 108, 0, 32, 0, 105, 0, 109, 0, 97, 0, 103, 0, 101, 0, 115, 0, 32, 0,1611 111, 0, 102, 0, 32, 0, 115, 0, 101, 0, 118, 0, 101, 0, 114, 0, 97, 0, 108, 0, 32, 0,1612 118, 0, 101, 0, 114, 0, 116, 0, 105, 0, 99, 0, 101, 0, 115, 0, 44, 0, 32, 0, 98, 0,1613 117, 0, 116, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101, 0, 32, 0, 115, 0, 121, 0, 109, 0,1614 109, 0, 101, 0, 116, 0, 114, 0, 121, 0, 32, 0, 98, 0, 114, 0, 101, 0, 97, 0, 99, 0,1615 104, 0, 101, 0, 115, 0, 32, 0, 97, 0, 110, 0, 100, 0, 32, 0, 99, 0, 111, 0, 108, 0,1616 111, 0, 114, 0, 115, 0, 32, 0, 116, 0, 104, 0, 97, 0, 116, 0, 32, 0, 109, 0, 97, 0,1617 107, 0, 101, 0, 32, 0, 101, 0, 97, 0, 99, 0, 104, 0, 32, 0, 105, 0, 109, 0, 97, 0, 103,1618 0, 101, 0, 32, 0, 85, 0, 78, 0, 73, 0, 81, 0, 85, 0, 69, 0, 46, 0, 12, 83, 121, 66, 0,1619 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 4, 56, 95, 111, 108, 100, 95, 99,1620 111, 110, 115, 116, 68, 97, 116, 97, 0, 1, 0, 12, 92, 95, 111, 108, 100, 95, 99, 111,1621 110, 115, 116, 79, 110, 67, 104, 97, 105, 110, 83, 99, 104, 101, 109, 97, 97, 13, 123,1622 34, 110, 101, 115, 116, 101, 100, 34, 58, 123, 34, 111, 110, 67, 104, 97, 105, 110, 77,1623 101, 116, 97, 68, 97, 116, 97, 34, 58, 123, 34, 110, 101, 115, 116, 101, 100, 34, 58,1624 123, 34, 78, 70, 84, 77, 101, 116, 97, 34, 58, 123, 34, 102, 105, 101, 108, 100, 115,1625 34, 58, 123, 34, 105, 112, 102, 115, 74, 115, 111, 110, 34, 58, 123, 34, 105, 100, 34,1626 58, 49, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100,1627 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 115, 116, 114, 105, 110, 103, 34, 125, 44,1628 34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 105, 100, 34, 58, 50, 44, 34, 114, 117,1629 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44, 34, 116, 121,1630 112, 101, 34, 58, 34, 67, 111, 108, 111, 114, 34, 125, 44, 34, 83, 121, 109, 109, 101,1631 116, 114, 121, 32, 66, 114, 101, 97, 99, 104, 34, 58, 123, 34, 105, 100, 34, 58, 51,1632 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105, 114, 101, 100, 34, 44,1633 34, 116, 121, 112, 101, 34, 58, 34, 83, 121, 109, 109, 101, 116, 114, 121, 32, 66, 114,1634 101, 97, 99, 104, 34, 125, 44, 34, 86, 101, 114, 116, 105, 99, 101, 34, 58, 123, 34,1635 105, 100, 34, 58, 52, 44, 34, 114, 117, 108, 101, 34, 58, 34, 114, 101, 113, 117, 105,1636 114, 101, 100, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 86, 101, 114, 116, 105, 99,1637 101, 34, 125, 125, 125, 44, 34, 67, 111, 108, 111, 114, 34, 58, 123, 34, 111, 112, 116,1638 105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92,1639 34, 101, 110, 92, 34, 58, 92, 34, 49, 32, 32, 32, 92, 34, 125, 34, 44, 34, 102, 105,1640 101, 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 50, 32, 92,1641 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 34, 123, 92, 34, 101, 110,1642 92, 34, 58, 92, 34, 51, 92, 34, 125, 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34,1643 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100,1644 50, 34, 58, 49, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 50, 125, 125, 44, 34, 83,1645 121, 109, 109, 101, 116, 114, 121, 32, 66, 114, 101, 97, 99, 104, 34, 58, 123, 34, 111,1646 112, 116, 105, 111, 110, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34,1647 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 49, 92, 34, 125, 34, 44, 34, 102, 105, 101,1648 108, 100, 50, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 50, 92, 34, 125,1649 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34, 102, 105, 101, 108, 100,1650 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 49, 125, 125, 44, 34, 86,1651 101, 114, 116, 105, 99, 101, 34, 58, 123, 34, 111, 112, 116, 105, 111, 110, 115, 34,1652 58, 123, 34, 102, 105, 101, 108, 100, 49, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34,1653 58, 92, 34, 54, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58, 34, 123,1654 92, 34, 101, 110, 92, 34, 58, 92, 34, 55, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108,1655 100, 51, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 56, 92, 34, 125, 34,1656 44, 34, 102, 105, 101, 108, 100, 52, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92,1657 34, 57, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100, 53, 34, 58, 34, 123, 92, 34,1658 101, 110, 92, 34, 58, 92, 34, 49, 48, 92, 34, 125, 34, 44, 34, 102, 105, 101, 108, 100,1659 54, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34, 49, 49, 92, 34, 125, 34, 44,1660 34, 102, 105, 101, 108, 100, 55, 34, 58, 34, 123, 92, 34, 101, 110, 92, 34, 58, 92, 34,1661 49, 50, 92, 34, 125, 34, 125, 44, 34, 118, 97, 108, 117, 101, 115, 34, 58, 123, 34,1662 102, 105, 101, 108, 100, 49, 34, 58, 48, 44, 34, 102, 105, 101, 108, 100, 50, 34, 58,1663 49, 44, 34, 102, 105, 101, 108, 100, 51, 34, 58, 50, 44, 34, 102, 105, 101, 108, 100,1664 52, 34, 58, 51, 44, 34, 102, 105, 101, 108, 100, 53, 34, 58, 52, 44, 34, 102, 105, 101,1665 108, 100, 54, 34, 58, 53, 44, 34, 102, 105, 101, 108, 100, 55, 34, 58, 54, 125, 125,1666 125, 125, 125, 125, 72, 95, 111, 108, 100, 95, 115, 99, 104, 101, 109, 97, 86, 101,1667 114, 115, 105, 111, 110, 24, 85, 110, 105, 113, 117, 101, 104, 95, 111, 108, 100, 95,1668 118, 97, 114, 105, 97, 98, 108, 101, 79, 110, 67, 104, 97, 105, 110, 83, 99, 104, 101,1669 109, 97, 17, 1, 123, 34, 99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 67, 111, 118,1670 101, 114, 34, 58, 34, 81, 109, 82, 67, 77, 84, 109, 57, 118, 81, 107, 76, 89, 86, 65,1671 54, 54, 87, 80, 49, 75, 72, 57, 55, 106, 84, 76, 76, 115, 56, 74, 78, 86, 65, 114, 80,1672 66, 52, 56, 98, 106, 87, 84, 75, 74, 110, 34, 125, 0, 0, 0,1673 ];1674 let mut bytes = IoReader(encoded_rpc_collection.as_slice());1675 let vec = RawEncoded::decode(&mut bytes).unwrap();1676 let mut bytes = IoReader(vec.as_slice());1677 RpcCollection::<[u8; 34]>::decode(&mut bytes).unwrap();1678 }1679}