Skip to content

Commit

Permalink
Backport Append optimization to 1.13.0 (#4771)
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Co-authored-by: cheme <emericchevalier.pro@gmail.com>
Co-authored-by: EgorPopelyaev <egor@parity.io>
Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com>
Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: Branislav Kontur <bkontur@gmail.com>
Co-authored-by: Sebastian Kunert <skunert49@gmail.com>
  • Loading branch information
10 people authored Jun 12, 2024
1 parent 47ef2a0 commit 958792b
Show file tree
Hide file tree
Showing 20 changed files with 1,352 additions and 230 deletions.
15 changes: 15 additions & 0 deletions Cargo.lock

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

12 changes: 6 additions & 6 deletions polkadot/node/core/pvf/common/src/executor_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,19 +215,19 @@ type HostFunctions = (
struct ValidationExternalities(sp_externalities::Extensions);

impl sp_externalities::Externalities for ValidationExternalities {
fn storage(&self, _: &[u8]) -> Option<Vec<u8>> {
fn storage(&mut self, _: &[u8]) -> Option<Vec<u8>> {
panic!("storage: unsupported feature for parachain validation")
}

fn storage_hash(&self, _: &[u8]) -> Option<Vec<u8>> {
fn storage_hash(&mut self, _: &[u8]) -> Option<Vec<u8>> {
panic!("storage_hash: unsupported feature for parachain validation")
}

fn child_storage_hash(&self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
fn child_storage_hash(&mut self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
panic!("child_storage_hash: unsupported feature for parachain validation")
}

fn child_storage(&self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
fn child_storage(&mut self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
panic!("child_storage: unsupported feature for parachain validation")
}

Expand Down Expand Up @@ -275,11 +275,11 @@ impl sp_externalities::Externalities for ValidationExternalities {
panic!("child_storage_root: unsupported feature for parachain validation")
}

fn next_child_storage_key(&self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
fn next_child_storage_key(&mut self, _: &ChildInfo, _: &[u8]) -> Option<Vec<u8>> {
panic!("next_child_storage_key: unsupported feature for parachain validation")
}

fn next_storage_key(&self, _: &[u8]) -> Option<Vec<u8>> {
fn next_storage_key(&mut self, _: &[u8]) -> Option<Vec<u8>> {
panic!("next_storage_key: unsupported feature for parachain validation")
}

Expand Down
13 changes: 13 additions & 0 deletions prdoc/pr_1223.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
title: Optimize storage append operation

doc:
- audience: [Node Dev, Runtime Dev]
description: |
This pull request optimizes the storage append operation in the `OverlayedChanges`.
Before the internal buffer was cloned every time a new transaction was created. Cloning
the internal buffer is now only done when there is no other possibility. This should
improve the performance in situations like when depositing events from batched calls.

crates:
- name: sp-state-machine
bump: major
8 changes: 4 additions & 4 deletions substrate/client/executor/src/integration_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,15 @@ fn storage_should_work(wasm_method: WasmExecutionMethod) {
assert_eq!(output, b"all ok!".to_vec().encode());
}

let expected = TestExternalities::new(sp_core::storage::Storage {
let mut expected = TestExternalities::new(sp_core::storage::Storage {
top: map![
b"input".to_vec() => value,
b"foo".to_vec() => b"bar".to_vec(),
b"baz".to_vec() => b"bar".to_vec()
],
children_default: map![],
});
assert_eq!(ext, expected);
assert!(ext.eq(&mut expected));
}

test_wasm_execution!(clear_prefix_should_work);
Expand All @@ -208,15 +208,15 @@ fn clear_prefix_should_work(wasm_method: WasmExecutionMethod) {
assert_eq!(output, b"all ok!".to_vec().encode());
}

let expected = TestExternalities::new(sp_core::storage::Storage {
let mut expected = TestExternalities::new(sp_core::storage::Storage {
top: map![
b"aaa".to_vec() => b"1".to_vec(),
b"aab".to_vec() => b"2".to_vec(),
b"bbb".to_vec() => b"5".to_vec()
],
children_default: map![],
});
assert_eq!(expected, ext);
assert!(expected.eq(&mut ext));
}

test_wasm_execution!(blake2_256_should_work);
Expand Down
16 changes: 8 additions & 8 deletions substrate/primitives/externalities/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,24 +83,24 @@ pub trait Externalities: ExtensionStore {
fn set_offchain_storage(&mut self, key: &[u8], value: Option<&[u8]>);

/// Read runtime storage.
fn storage(&self, key: &[u8]) -> Option<Vec<u8>>;
fn storage(&mut self, key: &[u8]) -> Option<Vec<u8>>;

/// Get storage value hash.
///
/// This may be optimized for large values.
fn storage_hash(&self, key: &[u8]) -> Option<Vec<u8>>;
fn storage_hash(&mut self, key: &[u8]) -> Option<Vec<u8>>;

/// Get child storage value hash.
///
/// This may be optimized for large values.
///
/// Returns an `Option` that holds the SCALE encoded hash.
fn child_storage_hash(&self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>>;
fn child_storage_hash(&mut self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>>;

/// Read child runtime storage.
///
/// Returns an `Option` that holds the SCALE encoded hash.
fn child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>>;
fn child_storage(&mut self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>>;

/// Set storage entry `key` of current contract being called (effective immediately).
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
Expand All @@ -124,20 +124,20 @@ pub trait Externalities: ExtensionStore {
}

/// Whether a storage entry exists.
fn exists_storage(&self, key: &[u8]) -> bool {
fn exists_storage(&mut self, key: &[u8]) -> bool {
self.storage(key).is_some()
}

/// Whether a child storage entry exists.
fn exists_child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> bool {
fn exists_child_storage(&mut self, child_info: &ChildInfo, key: &[u8]) -> bool {
self.child_storage(child_info, key).is_some()
}

/// Returns the key immediately following the given key, if it exists.
fn next_storage_key(&self, key: &[u8]) -> Option<Vec<u8>>;
fn next_storage_key(&mut self, key: &[u8]) -> Option<Vec<u8>>;

/// Returns the key immediately following the given key, if it exists, in child storage.
fn next_child_storage_key(&self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>>;
fn next_child_storage_key(&mut self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>>;

/// Clear an entire child storage.
///
Expand Down
12 changes: 6 additions & 6 deletions substrate/primitives/io/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ impl From<MultiRemovalResults> for KillStorageResult {
#[runtime_interface]
pub trait Storage {
/// Returns the data for `key` in the storage or `None` if the key can not be found.
fn get(&self, key: &[u8]) -> Option<bytes::Bytes> {
fn get(&mut self, key: &[u8]) -> Option<bytes::Bytes> {
self.storage(key).map(bytes::Bytes::from)
}

Expand All @@ -190,7 +190,7 @@ pub trait Storage {
/// doesn't exist at all.
/// If `value_out` length is smaller than the returned length, only `value_out` length bytes
/// are copied into `value_out`.
fn read(&self, key: &[u8], value_out: &mut [u8], value_offset: u32) -> Option<u32> {
fn read(&mut self, key: &[u8], value_out: &mut [u8], value_offset: u32) -> Option<u32> {
self.storage(key).map(|value| {
let value_offset = value_offset as usize;
let data = &value[value_offset.min(value.len())..];
Expand All @@ -211,7 +211,7 @@ pub trait Storage {
}

/// Check whether the given `key` exists in storage.
fn exists(&self, key: &[u8]) -> bool {
fn exists(&mut self, key: &[u8]) -> bool {
self.exists_storage(key)
}

Expand Down Expand Up @@ -387,7 +387,7 @@ pub trait DefaultChildStorage {
///
/// Parameter `storage_key` is the unprefixed location of the root of the child trie in the
/// parent trie. Result is `None` if the value for `key` in the child storage can not be found.
fn get(&self, storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
fn get(&mut self, storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
let child_info = ChildInfo::new_default(storage_key);
self.child_storage(&child_info, key).map(|s| s.to_vec())
}
Expand All @@ -400,7 +400,7 @@ pub trait DefaultChildStorage {
/// If `value_out` length is smaller than the returned length, only `value_out` length bytes
/// are copied into `value_out`.
fn read(
&self,
&mut self,
storage_key: &[u8],
key: &[u8],
value_out: &mut [u8],
Expand Down Expand Up @@ -478,7 +478,7 @@ pub trait DefaultChildStorage {
/// Check a child storage key.
///
/// Check whether the given `key` exists in default child defined at `storage_key`.
fn exists(&self, storage_key: &[u8], key: &[u8]) -> bool {
fn exists(&mut self, storage_key: &[u8], key: &[u8]) -> bool {
let child_info = ChildInfo::new_default(storage_key);
self.exists_child_storage(&child_info, key)
}
Expand Down
3 changes: 3 additions & 0 deletions substrate/primitives/state-machine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,19 @@ sp-externalities = { path = "../externalities", default-features = false }
sp-panic-handler = { path = "../panic-handler", optional = true }
sp-trie = { path = "../trie", default-features = false }
trie-db = { version = "0.29.0", default-features = false }
arbitrary = { version = "1", features = ["derive"], optional = true }

[dev-dependencies]
array-bytes = "6.2.2"
pretty_assertions = "1.2.1"
rand = "0.8.5"
sp-runtime = { path = "../runtime" }
assert_matches = "1.5"
arbitrary = { version = "1", features = ["derive"] }

[features]
default = ["std"]
fuzzing = ["arbitrary"]
std = [
"codec/std",
"hash-db/std",
Expand Down
30 changes: 30 additions & 0 deletions substrate/primitives/state-machine/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "sp-state-machine-fuzz"
version = "0.0.0"
publish = false
license = "Apache-2.0"
edition = "2021"

[package.metadata]
cargo-fuzz = true

[dependencies]
libfuzzer-sys = "0.4"
sp-runtime = { path = "../../runtime" }

[dependencies.sp-state-machine]
path = ".."
features = ["fuzzing"]

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[profile.release]
debug = 1

[[bin]]
name = "fuzz_append"
path = "fuzz_targets/fuzz_append.rs"
test = false
doc = false
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// This file is part of Substrate.

// Copyright (C) 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.

#![no_main]

use libfuzzer_sys::fuzz_target;
use sp_state_machine::fuzzing::{fuzz_append, FuzzAppendPayload};
use sp_runtime::traits::BlakeTwo256;

fuzz_target!(|data: FuzzAppendPayload| {
fuzz_append::<BlakeTwo256>(data);
});
Loading

0 comments on commit 958792b

Please sign in to comment.