Files
pezkuwi-subxt/substrate/primitives/transaction-storage-proof/src/lib.rs
T
Andrew Jones 49b6dfd2e5 Enrich metadata with type information (#8615)
* Cargo.lock after merge

* Restore scale-info feature

* Fully qualify TypeInfo derive

* Skip PendingSwap T

* Add missing skip_type_params attr

* metadata docs features

* Reduce pallet event attribute to struct

* Cargo.lock

* Update frame/balances/src/tests_composite.rs

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>

* Line widths check

* Cargo.lock

* Add scale-info/std

* Update frame/system/src/lib.rs

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>

* Use `skip_type_params` to remove `TypeInfo` requirements on checks

* Revert "Remove unused Call metadata stuff"

This reverts commit 41311f85

* Skip BalanceSwapAction type parameter

* Remove unused event metadata macro

* Update frame-metadata

* Update primitives/npos-elections/compact/src/codec.rs

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>

* Manual TypeInfo for Header

* Remove TypeInfo requirement for consts in BoundedVec etc.

* Another TypeInfo bound removed

* review: fix indentation

* TypeInfo impls for Identity types

* Add some todos to add custom TypeInfo impls

* Update frame/support/procedural/src/pallet/expand/pallet_struct.rs

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>

* Add some todos to add custom TypeInfo impls

* Add a test for manual Data TypeInfo impl

* Add custom TypeInfo impl for Vote

* Era custom TypeInfo crimes

* Revert finality-grandpa version to 0.14.z

* review: renamed module to pallet_constants_metadata

* New line at end of file

* Add missing scale-info/std

* Update frame/support/src/storage/types/mod.rs

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>

* Remove StorageEntryType::Map unused flag

* Add missing scale-info dependency after merge

* SignedExtension::AdditionalSigned metadata

* Update frame-metadata, use abbreviated docs and args fields

* Update frame/example/Cargo.toml

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Add scale_info/std and remove unused scale-info dependency

* Remove scale-info dependency

* Remove treasury pallet::metadata

* Remove redundant Event test

* Add back scale-info as dev dependency

* fix error metadata when no error defined in decl_module

* Add Module3 to tests

* Fix metadata test

* Add docs feature to frame-support test

* WIP fixing pallet metadata test

* Remove redundant FunctionMetadata, FunctionArgumentMetadata as per https://github.com/paritytech/frame-metadata/pull/20

* Use main branch of frame-metadata

* Use patch of scale-info for latest changes

* Use latest patched scale-info

* Manual TypeInfo for DigestItem

* Manual TypeInfo for DigestItem

* Update scale-info

* Skip __Ignore variants for Error, depends on https://github.com/paritytech/scale-info/pull/117

* Named fields for FRAME v2 pallet Call variants

* Named fields for FRAME v1 pallet Call variants

* Add missing scale-info dependency

* WIP expand benchmark call variant

* fix benchmark with new function

create a new function for each variant of a pallet call.
This function is called by benchmarking macro in order not to break call
creation with unnamed argument

* fix tests

* more fix

* Fix staking tests

* Fix offchain workers calls

* Cherry pick rustfmt.toml from master

* cargo +nightly-2021-06-22 fmt --all

* Update to new call variant structs

* More call variant struct updates

* Remove unused import

* More call variant structs

* More call variant structs

* Even more call variant structs

* Mooar variant structs

* Evermore variant structs

* Call variant structs ad infinitum

* Fmt

* More call variants

* Last call variant

* Call variants all done?

* Fix SS58Prefix type

* Potential workaround for BitFlags<IdentityFields> TypeInfo

* Enable docs capturing for Call, Event, and Error types

* Fix IdentityFields TypeInfo

* Remove metadata-docs feature

* Add capture_docs = true for legacy Call, Event and Error types

* Fmt

* Fix metadata test type

* Update benchmarks with call struct variants

* Fmt

* More test fixes

* Fmt

* Fix benches

* Use latest capture_docs attr

* Latest scale_info

* Fmt

* review: change &Vec to &[]

* Remove pallet metadata attr

* review: remove commented out test code

* review: skip_type_params trailing comma suggestion

* Update to scale-info 0.10.0

* Update construct_runtime ui tests, different because of metadata TypeInfo impls

* Add some TypeInfo derives for UI tests

* Update storage ensure span ui stderrs

* Update call argument bound ui tests

Possibly changed because change from tuple to struct variants?

* Add scale-info dev dependency

* Update to latest finality-grandpa release

* review: missing newline

* review: missing scale-info/std

* review: remove duplicate scale-info/std

* review: remove fully qualified TypeInfo

* review: add missing scale-info/std

* review: remove unnecessary imports.

* Fmt

* Use crates.io RC version of frame-metadata

* Remove scale-info/std because it is a dev dependency

* Add missing scale_info dev-dependency for test

* Delete empty metadata folder

* Fix sp_std import

* review: improve manual UncheckedExtrinsic TypeInfo impl

* review: use full scale-info for dev-dependency

* Remove DefaultByteGetter impl

* review: derive TypeInfo for generic header

* Fmt

* Update primitives/runtime/src/generic/unchecked_extrinsic.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Update primitives/runtime/src/generic/unchecked_extrinsic.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

* Update bin/node/executor/Cargo.toml

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Update frame/identity/src/types.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Update frame/support/src/dispatch.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Remove redundant derive

* Simplify scale-info dependency

* Strip underscore prefix from call variant struct names

* Another underscore field

* More underscore fields

* Another underscore field

* Update to frame-metadata 14.0.0-rc.2 with combined StorageEntryType::Map

* Fmt

* Revert weights formatting

* Fix up some tests

* Fix up some tests for StorageEntryTypeMetadata

* scale-info dev dependency

* Fix test error

* Add missing TypeInfo derives

* Add back missing scale-info dependency

* Add back missing scale-info dependency

* Fix npos compact impls

* Cargo.lock

* Fmt

* Fix errors

* Fmt

* Fix renamed raw_solution field

* Fix error

* Fmt

* Fix some benchmarks

* Fmt

* Stray R

* Fix

* Add missing TypeInfos

* ui test fix

* Fix line widths

* Revert "ui test fix"

This reverts commit 2d15ec058a216e3f92d713f1174603a2bb1eac65.

* Upgrade to scale-info 0.11.0

* Revert "Upgrade to scale-info 0.11.0"

This reverts commit 047bb179085a0059c36cd20ab405f55cf0867e28.

* Add Runtime type

* Update to scale-info 0.12

* Update to scale-info 1.0

* Update frame-metadata to version 14.0.0

* Patch finality-grandpa until release available

* Fix metadata tests

* Fix metadata tests

* Fmt

* Remove patched finality-grandpa

* Fix tests, use scale_info imports

* Fix pallet tests

* Add BlockNumber TypeInfo bound

* ui test fix

* Cargo.lock

* Remove pallet metadata

* Cargo.lock

* Add missing scale-info dependency

* Remove pallet event metadata

* Fix error

* Fix collective errors

* Semicolol

* Fmt

* Remove another metadata attribute

* Add new variant to custom digest TypeInfo

* Fmt

* Cargo.lock from master

* Remove comma lol

* Fix example call error

* Fix example call error properly

Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
2021-09-15 11:40:41 +00:00

247 lines
7.4 KiB
Rust

// This file is part of Substrate.
// Copyright (C) 2019-2021 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.
//! Storage proof primitives. Constains types and basic code to extract storage
//! proofs for indexed transactions.
#![cfg_attr(not(feature = "std"), no_std)]
use sp_std::{prelude::*, result::Result};
use codec::{Decode, Encode};
use sp_inherents::{InherentData, InherentIdentifier, IsFatalError};
use sp_runtime::traits::{Block as BlockT, NumberFor};
pub use sp_inherents::Error;
/// The identifier for the proof inherent.
pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"tx_proof";
/// Storage period for data.
pub const DEFAULT_STORAGE_PERIOD: u32 = 100800;
/// Proof trie value size.
pub const CHUNK_SIZE: usize = 256;
/// Errors that can occur while checking the storage proof.
#[derive(Encode, sp_runtime::RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Decode))]
pub enum InherentError {
InvalidProof,
TrieError,
}
impl IsFatalError for InherentError {
fn is_fatal_error(&self) -> bool {
true
}
}
/// Holds a chunk of data retrieved from storage along with
/// a proof that the data was stored at that location in the trie.
#[derive(Encode, Decode, Clone, PartialEq, Debug, scale_info::TypeInfo)]
pub struct TransactionStorageProof {
/// Data chunk that is proved to exist.
pub chunk: Vec<u8>,
/// Trie nodes that compose the proof.
pub proof: Vec<Vec<u8>>,
}
/// Auxiliary trait to extract storage proof.
pub trait TransactionStorageProofInherentData {
/// Get the proof.
fn storage_proof(&self) -> Result<Option<TransactionStorageProof>, Error>;
}
impl TransactionStorageProofInherentData for InherentData {
fn storage_proof(&self) -> Result<Option<TransactionStorageProof>, Error> {
Ok(self.get_data(&INHERENT_IDENTIFIER)?)
}
}
/// Provider for inherent data.
#[cfg(feature = "std")]
pub struct InherentDataProvider {
proof: Option<TransactionStorageProof>,
}
#[cfg(feature = "std")]
impl InherentDataProvider {
pub fn new(proof: Option<TransactionStorageProof>) -> Self {
InherentDataProvider { proof }
}
}
#[cfg(feature = "std")]
#[async_trait::async_trait]
impl sp_inherents::InherentDataProvider for InherentDataProvider {
fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> {
if let Some(proof) = &self.proof {
inherent_data.put_data(INHERENT_IDENTIFIER, proof)
} else {
Ok(())
}
}
async fn try_handle_error(
&self,
identifier: &InherentIdentifier,
error: &[u8],
) -> Option<Result<(), Error>> {
if *identifier != INHERENT_IDENTIFIER {
return None
}
let error = InherentError::decode(&mut &error[..]).ok()?;
Some(Err(Error::Application(Box::from(format!("{:?}", error)))))
}
}
/// A utility function to extract a chunk index from the source of randomness.
pub fn random_chunk(random_hash: &[u8], total_chunks: u32) -> u32 {
let mut buf = [0u8; 8];
buf.copy_from_slice(&random_hash[0..8]);
let random_u64 = u64::from_be_bytes(buf);
(random_u64 % total_chunks as u64) as u32
}
/// A utility function to encode transaction index as trie key.
pub fn encode_index(input: u32) -> Vec<u8> {
codec::Encode::encode(&codec::Compact(input))
}
/// An interface to request indexed data from the client.
pub trait IndexedBody<B: BlockT> {
/// Get all indexed transactions for a block,
/// including renewed transactions.
///
/// Note that this will only fetch transactions
/// that are indexed by the runtime with `storage_index_transaction`.
fn block_indexed_body(&self, number: NumberFor<B>) -> Result<Option<Vec<Vec<u8>>>, Error>;
/// Get block number for a block hash.
fn number(&self, hash: B::Hash) -> Result<Option<NumberFor<B>>, Error>;
}
#[cfg(feature = "std")]
pub mod registration {
use super::*;
use sp_runtime::traits::{Block as BlockT, One, Saturating, Zero};
use sp_trie::TrieMut;
type Hasher = sp_core::Blake2Hasher;
type TrieLayout = sp_trie::Layout<Hasher>;
/// Create a new inherent data provider instance for a given parent block hash.
pub fn new_data_provider<B, C>(
client: &C,
parent: &B::Hash,
) -> Result<InherentDataProvider, Error>
where
B: BlockT,
C: IndexedBody<B>,
{
let parent_number = client.number(parent.clone())?.unwrap_or(Zero::zero());
let number = parent_number
.saturating_add(One::one())
.saturating_sub(DEFAULT_STORAGE_PERIOD.into());
if number.is_zero() {
// Too early to collect proofs.
return Ok(InherentDataProvider::new(None))
}
let proof = match client.block_indexed_body(number)? {
Some(transactions) if !transactions.is_empty() =>
Some(build_proof(parent.as_ref(), transactions)?),
Some(_) | None => {
// Nothing was indexed in that block.
None
},
};
Ok(InherentDataProvider::new(proof))
}
/// Build a proof for a given source of randomness and indexed transactions.
pub fn build_proof(
random_hash: &[u8],
transactions: Vec<Vec<u8>>,
) -> Result<TransactionStorageProof, Error> {
let mut db = sp_trie::MemoryDB::<Hasher>::default();
let mut target_chunk = None;
let mut target_root = Default::default();
let mut target_chunk_key = Default::default();
let mut chunk_proof = Default::default();
let total_chunks: u64 = transactions
.iter()
.map(|t| ((t.len() + CHUNK_SIZE - 1) / CHUNK_SIZE) as u64)
.sum();
let mut buf = [0u8; 8];
buf.copy_from_slice(&random_hash[0..8]);
let random_u64 = u64::from_be_bytes(buf);
let target_chunk_index = random_u64 % total_chunks;
// Generate tries for each transaction.
let mut chunk_index = 0;
for transaction in transactions {
let mut transaction_root = sp_trie::empty_trie_root::<TrieLayout>();
{
let mut trie =
sp_trie::TrieDBMut::<TrieLayout>::new(&mut db, &mut transaction_root);
let chunks = transaction.chunks(CHUNK_SIZE).map(|c| c.to_vec());
for (index, chunk) in chunks.enumerate() {
let index = encode_index(index as u32);
trie.insert(&index, &chunk).map_err(|e| Error::Application(Box::new(e)))?;
if chunk_index == target_chunk_index {
target_chunk = Some(chunk);
target_chunk_key = index;
}
chunk_index += 1;
}
trie.commit();
}
if target_chunk.is_some() && target_root == Default::default() {
target_root = transaction_root.clone();
chunk_proof = sp_trie::generate_trie_proof::<TrieLayout, _, _, _>(
&db,
transaction_root.clone(),
&[target_chunk_key.clone()],
)
.map_err(|e| Error::Application(Box::new(e)))?;
}
}
Ok(TransactionStorageProof { proof: chunk_proof, chunk: target_chunk.unwrap() })
}
#[test]
fn build_proof_check() {
use std::str::FromStr;
let random = [0u8; 32];
let proof = build_proof(&random, vec![vec![42]]).unwrap();
let root = sp_core::H256::from_str(
"0xff8611a4d212fc161dae19dd57f0f1ba9309f45d6207da13f2d3eab4c6839e91",
)
.unwrap();
sp_trie::verify_trie_proof::<TrieLayout, _, _, _>(
&root,
&proof.proof,
&[(encode_index(0), Some(proof.chunk))],
)
.unwrap();
}
}