Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ethexe): impl basis for runtime related RPC calls; impl calculate_reply_for_handle v1 #4238

Merged
merged 15 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from 13 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
4 changes: 4 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 @@ -143,6 +143,7 @@ hashbrown = "0.14.5"
hex = { version = "0.4.3", default-features = false }
hex-literal = "0.4.1"
impl-trait-for-tuples = "0.2.2"
impl-serde = "0.4.0"
jsonrpsee = { version = "^0.16" }
libc = { version = "0.2", default-features = false }
log = { version = "0.4.22", default-features = false }
Expand Down
3 changes: 2 additions & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ primitive-types = { workspace = true, features = ["scale-info"] }

# Optional dependencies
serde = { workspace = true, features = ["derive"], optional = true }
impl-serde = { workspace = true, optional = true }

[dev-dependencies]
wabt.workspace = true
Expand All @@ -49,4 +50,4 @@ numerated = { workspace = true, features = ["mock"] }
[features]
default = []
strict = []
std = ["serde/std", "wasmparser/std", "gear-core-errors/serde"]
std = ["serde/std", "dep:impl-serde", "wasmparser/std", "gear-core-errors/serde"]
1 change: 1 addition & 0 deletions core/src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ pub trait Packet {
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct ReplyInfo {
/// Payload of the reply.
#[cfg_attr(feature = "std", serde(with = "impl_serde::serialize"))]
pub payload: Vec<u8>,
/// Value sent with reply.
pub value: u128,
Expand Down
2 changes: 1 addition & 1 deletion ethexe/cli/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ impl Service {
db.set_block_end_state_is_valid(block_hash, true);

let header = db.block_header(block_hash).expect("must be set; qed");
db.set_latest_valid_block_height(header.height);
db.set_latest_valid_block(block_hash, header);

Ok(transition_outcomes)
}
Expand Down
4 changes: 2 additions & 2 deletions ethexe/common/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ pub trait BlockMetaStorage: Send + Sync {
fn block_outcome(&self, block_hash: H256) -> Option<Vec<StateTransition>>;
fn set_block_outcome(&self, block_hash: H256, outcome: Vec<StateTransition>);

fn latest_valid_block_height(&self) -> Option<u32>;
fn set_latest_valid_block_height(&self, block_height: u32);
fn latest_valid_block(&self) -> Option<(H256, BlockHeader)>;
fn set_latest_valid_block(&self, block_hash: H256, header: BlockHeader);
}

pub trait CodesStorage: Send + Sync {
Expand Down
26 changes: 20 additions & 6 deletions ethexe/db/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@

use std::collections::{BTreeMap, BTreeSet, VecDeque};

use crate::{CASDatabase, KVDatabase};
use crate::{
overlay::{CASOverlay, KVOverlay},
CASDatabase, KVDatabase,
};
use ethexe_common::{
db::{BlockHeader, BlockMetaStorage, CodesStorage},
router::StateTransition,
Expand Down Expand Up @@ -253,18 +256,19 @@ impl BlockMetaStorage for Database {
);
}

fn latest_valid_block_height(&self) -> Option<u32> {
fn latest_valid_block(&self) -> Option<(H256, BlockHeader)> {
self.kv
.get(&KeyPrefix::LatestValidBlock.one(self.router_address))
.map(|block_height| {
u32::from_le_bytes(block_height.try_into().expect("must be correct; qed"))
.map(|data| {
<(H256, BlockHeader)>::decode(&mut data.as_slice())
.expect("Failed to decode data into `(H256, BlockHeader)`")
})
}

fn set_latest_valid_block_height(&self, block_height: u32) {
fn set_latest_valid_block(&self, block_hash: H256, header: BlockHeader) {
self.kv.put(
&KeyPrefix::LatestValidBlock.one(self.router_address),
block_height.to_le_bytes().to_vec(),
(block_hash, header).encode(),
);
}
}
Expand Down Expand Up @@ -383,6 +387,16 @@ impl Database {
}
}

/// # Safety
/// Not ready for using in prod. Intended to be for rpc calls only.
pub unsafe fn overlaid(self) -> Self {
Self {
cas: Box::new(CASOverlay::new(self.cas)),
kv: Box::new(KVOverlay::new(self.kv)),
router_address: self.router_address,
}
}

// TODO: temporary solution for MVP runtime-interfaces db access.
pub fn read_by_hash(&self, hash: H256) -> Option<Vec<u8>> {
self.cas.read(&hash)
Expand Down
1 change: 1 addition & 0 deletions ethexe/db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use gprimitives::H256;

mod database;
mod mem;
mod overlay;
mod rocks;

pub use database::Database;
Expand Down
105 changes: 105 additions & 0 deletions ethexe/db/src/overlay.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// This file is part of Gear.
//
// Copyright (C) 2024 Gear Technologies Inc.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use crate::{CASDatabase, KVDatabase, MemDb};
use gear_core::ids::hash;
use gprimitives::H256;
use std::collections::HashSet;

pub struct CASOverlay {
db: Box<dyn CASDatabase>,
mem: MemDb,
}

impl CASOverlay {
pub fn new(db: Box<dyn CASDatabase>) -> Self {
Self {
db,
mem: MemDb::default(),
}
}
}

impl CASDatabase for CASOverlay {
fn clone_boxed(&self) -> Box<dyn CASDatabase> {
Box::new(Self {
db: self.db.clone_boxed(),
mem: self.mem.clone(),
})
}

fn read(&self, hash: &H256) -> Option<Vec<u8>> {
self.mem.read(hash).or_else(|| self.db.read(hash))
}

fn write_by_hash(&self, hash: &H256, data: &[u8]) {
self.mem.write_by_hash(hash, data)
}
}

pub struct KVOverlay {
db: Box<dyn KVDatabase>,
mem: MemDb,
}

impl KVOverlay {
pub fn new(db: Box<dyn KVDatabase>) -> Self {
Self {
db,
mem: MemDb::default(),
}
}
}

impl KVDatabase for KVOverlay {
fn clone_boxed_kv(&self) -> Box<dyn KVDatabase> {
Box::new(Self {
db: self.db.clone_boxed_kv(),
mem: self.mem.clone(),
})
}

fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
self.mem.get(key).or_else(|| self.db.get(key))
}

fn take(&self, _key: &[u8]) -> Option<Vec<u8>> {
unimplemented!()
}

fn put(&self, key: &[u8], value: Vec<u8>) {
self.mem.put(key, value)
}

fn iter_prefix<'a>(
&'a self,
prefix: &'a [u8],
) -> Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + '_> {
let mem_iter = self.mem.iter_prefix(prefix);
let db_iter = self.db.iter_prefix(prefix);

let full_iter = mem_iter.chain(db_iter);

let mut known_keys = HashSet::new();

let filtered_iter =
full_iter.filter_map(move |(k, v)| known_keys.insert(hash(&k)).then_some((k, v)));

Box::new(filtered_iter)
}
}
19 changes: 12 additions & 7 deletions ethexe/observer/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,9 @@ impl Query {
.set_block_end_program_states(hash, Default::default());

// set latest valid if empty.
if self.database.latest_valid_block_height().is_none() {
if self.database.latest_valid_block().is_none() {
let genesis_header = self.get_block_header_meta(hash).await?;
self.database
.set_latest_valid_block_height(genesis_header.height);
self.database.set_latest_valid_block(hash, genesis_header);
}

Ok(())
Expand Down Expand Up @@ -160,7 +159,8 @@ impl Query {
let current_block = self.get_block_header_meta(block_hash).await?;
let latest_valid_block_height = self
.database
.latest_valid_block_height()
.latest_valid_block()
.map(|(_, header)| header.height)
.expect("genesis by default; qed");

if current_block.height >= latest_valid_block_height
Expand Down Expand Up @@ -196,15 +196,21 @@ impl Query {

// Continue loading chain by parent hashes from the current block to the latest valid block.
let mut hash = block_hash;
let mut height = current_block.height;

while hash != self.genesis_block_hash {
// If the block's end state is valid, set it as the latest valid block
if self
.database
.block_end_state_is_valid(hash)
.unwrap_or(false)
{
self.database.set_latest_valid_block_height(height);
let header = match headers_map.get(&hash) {
Some(header) => header.clone(),
None => self.get_block_header_meta(hash).await?,
};

self.database.set_latest_valid_block(hash, header);

log::trace!("Nearest valid in db block found: {hash}");
break;
}
Expand All @@ -218,7 +224,6 @@ impl Query {
Some(header) => header.parent_hash,
None => self.get_block_parent_hash(hash).await?,
};
height -= 1;
}

let mut actual_commitment_queue: VecDeque<H256> = self
Expand Down
26 changes: 10 additions & 16 deletions ethexe/processor/src/host/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ pub type Store = wasmtime::Store<StoreData>;

#[derive(Clone)]
pub(crate) struct InstanceCreator {
db: Database,
engine: wasmtime::Engine,
instance_pre: Arc<wasmtime::InstancePre<StoreData>>,

Expand All @@ -54,7 +53,7 @@ pub(crate) struct InstanceCreator {
}

impl InstanceCreator {
pub fn new(db: Database, runtime: Vec<u8>) -> Result<Self> {
pub fn new(runtime: Vec<u8>) -> Result<Self> {
gear_runtime_interface::sandbox_init();

let engine = wasmtime::Engine::default();
Expand All @@ -72,7 +71,6 @@ impl InstanceCreator {
let instance_pre = Arc::new(instance_pre);

Ok(Self {
db,
engine,
instance_pre,
chain_head: None,
Expand All @@ -87,7 +85,6 @@ impl InstanceCreator {
let mut instance_wrapper = InstanceWrapper {
instance,
store,
db: self.db().clone(),
chain_head: self.chain_head,
};

Expand All @@ -100,10 +97,6 @@ impl InstanceCreator {
Ok(instance_wrapper)
}

pub fn db(&self) -> &Database {
&self.db
}

pub fn set_chain_head(&mut self, chain_head: H256) {
self.chain_head = Some(chain_head);
}
Expand All @@ -112,15 +105,10 @@ impl InstanceCreator {
pub(crate) struct InstanceWrapper {
instance: wasmtime::Instance,
store: Store,
db: Database,
chain_head: Option<H256>,
}

impl InstanceWrapper {
pub fn db(&self) -> &Database {
&self.db
}

#[allow(unused)]
pub fn data(&self) -> &StoreData {
self.store.data()
Expand All @@ -139,13 +127,14 @@ impl InstanceWrapper {

pub fn run(
&mut self,
db: Database,
program_id: ProgramId,
original_code_id: CodeId,
state_hash: H256,
maybe_instrumented_code: Option<InstrumentedCode>,
) -> Result<Vec<JournalNote>> {
let chain_head = self.chain_head.expect("chain head must be set before run");
threads::set(self.db.clone(), chain_head, state_hash);
threads::set(db, chain_head, state_hash);

let arg = (
program_id,
Expand All @@ -157,9 +146,14 @@ impl InstanceWrapper {
self.call("run", arg.encode())
}

pub fn wake_messages(&mut self, program_id: ProgramId, state_hash: H256) -> Result<H256> {
pub fn wake_messages(
&mut self,
db: Database,
program_id: ProgramId,
state_hash: H256,
) -> Result<H256> {
let chain_head = self.chain_head.expect("chain head must be set before wake");
threads::set(self.db.clone(), chain_head, state_hash);
threads::set(db, chain_head, state_hash);

self.call("wake_messages", (program_id, state_hash).encode())
}
Expand Down
Loading
Loading