Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Remark storage #10698

Merged
merged 6 commits into from
Apr 18, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ members = [
"frame/randomness-collective-flip",
"frame/recovery",
"frame/referenda",
"frame/remark",
"frame/scheduler",
"frame/scored-pool",
"frame/session",
Expand Down
3 changes: 3 additions & 0 deletions bin/node/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ pallet-proxy = { version = "4.0.0-dev", default-features = false, path = "../../
pallet-randomness-collective-flip = { version = "4.0.0-dev", default-features = false, path = "../../../frame/randomness-collective-flip" }
pallet-recovery = { version = "4.0.0-dev", default-features = false, path = "../../../frame/recovery" }
pallet-referenda = { version = "4.0.0-dev", default-features = false, path = "../../../frame/referenda" }
pallet-remark = { version = "4.0.0-dev", default-features = false, path = "../../../frame/remark" }
pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = "../../../frame/session", default-features = false }
pallet-session-benchmarking = { version = "4.0.0-dev", path = "../../../frame/session/benchmarking", default-features = false, optional = true }
pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/staking" }
Expand Down Expand Up @@ -173,6 +174,7 @@ std = [
"sp-version/std",
"pallet-society/std",
"pallet-referenda/std",
"pallet-remark/std",
"pallet-recovery/std",
"pallet-uniques/std",
"pallet-vesting/std",
Expand Down Expand Up @@ -213,6 +215,7 @@ runtime-benchmarks = [
"pallet-proxy/runtime-benchmarks",
"pallet-scheduler/runtime-benchmarks",
"pallet-referenda/runtime-benchmarks",
"pallet-remark/runtime-benchmarks",
"pallet-session-benchmarking",
"pallet-society/runtime-benchmarks",
"pallet-staking/runtime-benchmarks",
Expand Down
8 changes: 8 additions & 0 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,12 @@ impl pallet_referenda::Config for Runtime {
type Tracks = TracksInfo;
}

impl pallet_remark::Config for Runtime {
type WeightInfo = pallet_remark::weights::SubstrateWeight<Self>;
type Call = Call;
type Event = Event;
}

parameter_types! {
pub const LaunchPeriod: BlockNumber = 28 * 24 * 60 * MINUTES;
pub const VotingPeriod: BlockNumber = 28 * 24 * 60 * MINUTES;
Expand Down Expand Up @@ -1446,6 +1452,7 @@ construct_runtime!(
StateTrieMigration: pallet_state_trie_migration,
ChildBounties: pallet_child_bounties,
Referenda: pallet_referenda,
Remark: pallet_remark,
ConvictionVoting: pallet_conviction_voting,
Whitelist: pallet_whitelist,
}
Expand Down Expand Up @@ -1535,6 +1542,7 @@ mod benches {
[pallet_preimage, Preimage]
[pallet_proxy, Proxy]
[pallet_referenda, Referenda]
[pallet_remark, Remark]
[pallet_scheduler, Scheduler]
[pallet_session, SessionBench::<Runtime>]
[pallet_staking, Staking]
Expand Down
42 changes: 42 additions & 0 deletions frame/remark/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[package]
name = "pallet-remark"
version = "4.0.0-dev"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
license = "Apache-2.0"
homepage = "https://substrate.io"
repository = "https://github.com/paritytech/substrate/"
description = "Remark storage pallet"
readme = "README.md"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
serde = { version = "1.0.136", optional = true }
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" }
frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" }
sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" }
sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" }
sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" }
sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" }
frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true }

[dev-dependencies]
sp-core = { version = "6.0.0", path = "../../primitives/core", default-features = false }

[features]
default = ["std"]
runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
std = [
"serde",
"codec/std",
"scale-info/std",
"sp-runtime/std",
"frame-support/std",
"frame-system/std",
"sp-io/std",
"sp-std/std",
]
6 changes: 6 additions & 0 deletions frame/remark/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Remark Storage Pallet

Allows storing arbitrary data off chain.


License: Apache-2.0
47 changes: 47 additions & 0 deletions frame/remark/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// This file is part of Substrate.

// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Benchmarks for remarks pallet

#![cfg(feature = "runtime-benchmarks")]

use super::*;
use frame_benchmarking::{benchmarks, whitelisted_caller};
use frame_system::{EventRecord, Pallet as System, RawOrigin};
use sp_std::*;

#[cfg(test)]
use crate::Pallet as Remark;

fn assert_last_event<T: Config>(generic_event: <T as Config>::Event) {
let events = System::<T>::events();
let system_event: <T as frame_system::Config>::Event = generic_event.into();
let EventRecord { event, .. } = &events[events.len() - 1];
assert_eq!(event, &system_event);
}

benchmarks! {
store {
let l in 1 .. 1024*1024;
let caller: T::AccountId = whitelisted_caller();
}: _(RawOrigin::Signed(caller.clone()), vec![0u8; l as usize])
verify {
assert_last_event::<T>(Event::Stored { sender: caller, content_hash: sp_io::hashing::blake2_256(&vec![0u8; l as usize]).into() }.into());
}

impl_benchmark_test_suite!(Remark, crate::mock::new_test_ext(), crate::mock::Test);
}
91 changes: 91 additions & 0 deletions frame/remark/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// This file is part of Substrate.

// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Remark storage pallet. Indexes remarks and stores them off chain.

// Ensure we're `no_std` when compiling for Wasm.
#![cfg_attr(not(feature = "std"), no_std)]

mod benchmarking;
pub mod weights;

#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;

use frame_support::dispatch::{Dispatchable, GetDispatchInfo};
use sp_std::prelude::*;

// Re-export pallet items so that they can be accessed from the crate namespace.
pub use pallet::*;
pub use weights::WeightInfo;

#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;

#[pallet::config]
pub trait Config: frame_system::Config {
/// The overarching event type.
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
/// A dispatchable call.
type Call: Parameter
+ Dispatchable<Origin = Self::Origin>
+ GetDispatchInfo
+ From<frame_system::Call<Self>>;
arkpar marked this conversation as resolved.
Show resolved Hide resolved
/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also have a

// Origin that control the ability to index a remark.
type ControlOrigin: frame_support::traits::EnsureOrigin<Self::Origin>;

but I don't think it is necessary at this point.

}

#[pallet::error]
pub enum Error<T> {
/// Attempting to store empty data.
Empty,
/// Attempted to call `store` outside of block execution.
BadContext,
}

#[pallet::pallet]
#[pallet::without_storage_info]
pub struct Pallet<T>(_);

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Index and store data off chain.
#[pallet::weight(T::WeightInfo::store(remark.len() as u32))]
pub fn store(origin: OriginFor<T>, remark: Vec<u8>) -> DispatchResultWithPostInfo {
ensure!(!remark.is_empty(), Error::<T>::Empty);
let sender = ensure_signed(origin)?;
let content_hash = sp_io::hashing::blake2_256(&remark);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we use the T::Hashing for this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I have now seen it is because of the transaction indexing. But that should have maybe been generic as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hashing scheme has to match the scheme supported by the IPFS bitswap server. The generic parameter would need to be propagated to sc-network module somehow. For not it is hardcoded to blake2

let extrinsic_index = <frame_system::Pallet<T>>::extrinsic_index()
.ok_or_else(|| Error::<T>::BadContext)?;
sp_io::transaction_index::index(extrinsic_index, remark.len() as u32, content_hash);
Self::deposit_event(Event::Stored { sender, content_hash: content_hash.into() });
Ok(().into())
}
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// Stored data off chain.
Stored { sender: T::AccountId, content_hash: sp_core::H256 },
}
}
80 changes: 80 additions & 0 deletions frame/remark/src/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// This file is part of Substrate.

// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Test environment for remarks pallet.

use crate as pallet_remark;
use frame_support::traits::{ConstU16, ConstU32, ConstU64};
use sp_core::H256;
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
};

type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
pub type Block = frame_system::mocking::MockBlock<Test>;

// Configure a mock runtime to test the pallet.
frame_support::construct_runtime!(
pub enum Test where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
Remark: pallet_remark::{ Pallet, Call, Event<T> },
}
);

impl frame_system::Config for Test {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = ();
type BlockLength = ();
type Origin = Origin;
type Call = Call;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = Event;
type BlockHashCount = ConstU64<250>;
type DbWeight = ();
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = ();
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = ConstU16<42>;
type OnSetCode = ();
type MaxConsumers = ConstU32<16>;
}

impl pallet_remark::Config for Test {
type Event = Event;
type Call = Call;
type WeightInfo = ();
}

pub fn new_test_ext() -> sp_io::TestExternalities {
let t = GenesisConfig { system: Default::default() }.build_storage().unwrap();
t.into()
}
Loading