From 56494038823bf0d040d907ac983fa80ff4db8fa5 Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Tue, 8 Aug 2023 09:54:14 +0300 Subject: [PATCH 1/4] wip: refactor protocol to support external batches --- tezos_proto/src/context/batch.rs | 18 ++++++------ tezos_proto/src/lib.rs | 1 + tezos_proto/src/runner/batch.rs | 46 +++++++++++++++++++++++++++++++ tezos_proto/src/runner/mempool.rs | 0 tezos_proto/src/runner/mod.rs | 2 ++ 5 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 tezos_proto/src/runner/batch.rs create mode 100644 tezos_proto/src/runner/mempool.rs create mode 100644 tezos_proto/src/runner/mod.rs diff --git a/tezos_proto/src/context/batch.rs b/tezos_proto/src/context/batch.rs index 72e34ca..41ece49 100644 --- a/tezos_proto/src/context/batch.rs +++ b/tezos_proto/src/context/batch.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT use tezos_core::types::encoded::{ - BlockHash, BlockPayloadHash, ChainId, ContextHash, OperationListListHash, ProtocolHash, + BlockHash, BlockPayloadHash, ChainId, ContextHash, OperationListListHash, ProtocolHash, Signature, ImplicitAddress }; use tezos_operation::block_header; use tezos_rpc::models::{ @@ -36,7 +36,7 @@ pub struct BatchHeader { pub operations_hash: OperationListListHash, pub payload_hash: BlockPayloadHash, pub context: ContextHash, - // pub signature: Option + pub signature: Option } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -46,7 +46,7 @@ pub struct BatchReceipt { pub hash: BlockHash, pub header: BatchHeader, pub balance_updates: Option>, - // pub batcher: ImplicitAddress + pub batcher: Option } impl From for block_header::BlockHeader { @@ -67,9 +67,9 @@ impl From for block_header::BlockHeader { .expect("Failed to convert pow nonce"), proto: 0, seed_nonce_hash: None, - signature: ZERO_SIGNATURE - .try_into() - .expect("Failed to convert signature"), // TODO: sign with builtin key? + signature: header.signature.unwrap_or_else( + || ZERO_SIGNATURE.try_into().expect("Failed to convert signature") + ), timestamp: ts2dt!(header.timestamp), validation_pass: 4, } @@ -104,7 +104,8 @@ impl From for Metadata { fn from(receipt: BatchReceipt) -> Self { let config = Config::default(); Self { - baker: None, // TODO: + signature + baker: receipt.batcher, + proposer: receipt.batcher, balance_updates: receipt.balance_updates, // derived protocol: receipt.protocol.to_owned(), @@ -140,7 +141,7 @@ impl From for Metadata { }, ], max_block_header_length: config.max_block_header_length, - // null + // null / deprecated level: None, consumed_gas: None, deactivated: None, @@ -154,7 +155,6 @@ impl From for Metadata { protocol: None, expiration: None, }, - proposer: None, nonce_hash: None, liquidity_baking_toggle_ema: None, liquidity_baking_escape_ema: None, diff --git a/tezos_proto/src/lib.rs b/tezos_proto/src/lib.rs index 46b144f..d121564 100644 --- a/tezos_proto/src/lib.rs +++ b/tezos_proto/src/lib.rs @@ -8,5 +8,6 @@ pub mod context; pub mod error; pub mod executor; pub mod validator; +pub mod runner; pub use error::{Error, Result}; diff --git a/tezos_proto/src/runner/batch.rs b/tezos_proto/src/runner/batch.rs new file mode 100644 index 0000000..ef04daa --- /dev/null +++ b/tezos_proto/src/runner/batch.rs @@ -0,0 +1,46 @@ +use std::collections::HashMap; + +use tezos_core::types::encoded::{ImplicitAddress, ChainId, OperationHash}; +use tezos_operation::operations::{SignedOperation}; + +use crate::{context::{batch::BatchHeader, head::Head, TezosContext}, Result}; + +pub struct Batch { + pub header: BatchHeader, + pub source: ImplicitAddress, + pub operations: Vec +} + +pub struct TezosChain { + pub head: Head, + pub mempool: HashMap +} + +impl TezosChain { + pub fn load(context: &mut impl TezosContext, chain_id: ChainId) -> Result { + let mut head = context.get_head()?; + head.chain_id = chain_id; + Ok(Self { head, mempool: HashMap::new() }) + } + + pub fn add_pending_operation(&mut self, hash: OperationHash, operation: SignedOperation) -> Result<()> { + self.mempool.insert(hash, operation); + Ok(()) + } + + pub fn has_pending_operation(&self, hash: &OperationHash) -> bool { + self.mempool.contains_key(hash) + } + + pub fn remove_pending_operation(&mut self, hash: &OperationHash) -> Result { + self.mempool.remove(hash).ok_or(Error::) + } + + pub fn apply_batch(&mut self, context: &mut impl TezosContext, batch: Batch) -> Result<()> { + Ok(()) + } + + pub fn aggregate_batch(&mut self) -> Result { + todo!() + } +} \ No newline at end of file diff --git a/tezos_proto/src/runner/mempool.rs b/tezos_proto/src/runner/mempool.rs new file mode 100644 index 0000000..e69de29 diff --git a/tezos_proto/src/runner/mod.rs b/tezos_proto/src/runner/mod.rs new file mode 100644 index 0000000..72145e1 --- /dev/null +++ b/tezos_proto/src/runner/mod.rs @@ -0,0 +1,2 @@ +pub mod batch; +pub mod mempool; \ No newline at end of file From caadc8e7e21cceef89c78baf14a04123a9d590e4 Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Fri, 11 Aug 2023 12:30:04 +0300 Subject: [PATCH 2/4] wip: massive proto refactoring --- Cargo.lock | 2 + layered_store/Cargo.toml | 4 +- layered_store/src/store.rs | 4 + layered_store/src/types/tezos.rs | 18 +- tezos_node/src/rollup.rs | 2 +- tezos_node/src/services/blocks.rs | 2 +- tezos_node/src/services/context.rs | 4 +- tezos_proto/src/batch/executor.rs | 75 +++++++ tezos_proto/src/batch/header.rs | 117 +++++++++++ tezos_proto/src/batch/mod.rs | 9 + tezos_proto/src/batch/payload.rs | 29 +++ tezos_proto/src/batch/receipt.rs | 136 +++++++++++++ tezos_proto/src/batch/validator.rs | 133 ++++++++++++ tezos_proto/src/batcher.rs | 101 ---------- tezos_proto/src/config.rs | 50 ++--- tezos_proto/src/context/batch.rs | 189 ------------------ tezos_proto/src/context/head.rs | 11 + tezos_proto/src/context/mod.rs | 176 +++++++++++++++- tezos_proto/src/context/store.rs | 55 ----- tezos_proto/src/context/tezos.rs | 179 ----------------- .../contract.rs => contracts/michelson.rs} | 10 +- .../src/{validator => contracts}/mod.rs | 3 +- tezos_proto/src/contracts/system.rs | 3 + tezos_proto/src/error.rs | 2 + tezos_proto/src/lib.rs | 8 +- .../balance_updates.rs | 0 .../operation.rs => operations/executor.rs} | 23 ++- .../src/{executor => operations}/lazy_diff.rs | 0 .../src/{executor => operations}/mod.rs | 8 +- .../src/{executor => operations}/result.rs | 2 +- .../{executor => operations}/rpc_errors.rs | 0 tezos_proto/src/operations/types/mod.rs | 7 + .../types}/origination.rs | 20 +- .../{executor => operations/types}/reveal.rs | 3 +- .../types}/transaction.rs | 22 +- .../operation.rs => operations/validator.rs} | 2 +- .../{runner/mempool.rs => protocol/bridge.rs} | 0 tezos_proto/src/protocol/constants.rs | 50 +++++ tezos_proto/src/protocol/fees.rs | 0 tezos_proto/src/protocol/mempool.rs | 0 .../src/{context => protocol}/migrations.rs | 55 ++--- tezos_proto/src/protocol/mod.rs | 49 +++++ tezos_proto/src/runner/batch.rs | 46 ----- tezos_proto/src/runner/mod.rs | 2 - tezos_proto/src/validator/batch.rs | 55 ----- tezos_proto/tests/runner/client.rs | 5 +- tezos_proto/tests/runner/mock.rs | 4 +- 47 files changed, 923 insertions(+), 752 deletions(-) create mode 100644 tezos_proto/src/batch/executor.rs create mode 100644 tezos_proto/src/batch/header.rs create mode 100644 tezos_proto/src/batch/mod.rs create mode 100644 tezos_proto/src/batch/payload.rs create mode 100644 tezos_proto/src/batch/receipt.rs create mode 100644 tezos_proto/src/batch/validator.rs delete mode 100644 tezos_proto/src/batcher.rs delete mode 100644 tezos_proto/src/context/batch.rs delete mode 100644 tezos_proto/src/context/store.rs delete mode 100644 tezos_proto/src/context/tezos.rs rename tezos_proto/src/{executor/contract.rs => contracts/michelson.rs} (92%) rename tezos_proto/src/{validator => contracts}/mod.rs (74%) create mode 100644 tezos_proto/src/contracts/system.rs rename tezos_proto/src/{executor => operations}/balance_updates.rs (100%) rename tezos_proto/src/{executor/operation.rs => operations/executor.rs} (90%) rename tezos_proto/src/{executor => operations}/lazy_diff.rs (100%) rename tezos_proto/src/{executor => operations}/mod.rs (65%) rename tezos_proto/src/{executor => operations}/result.rs (99%) rename tezos_proto/src/{executor => operations}/rpc_errors.rs (100%) create mode 100644 tezos_proto/src/operations/types/mod.rs rename tezos_proto/src/{executor => operations/types}/origination.rs (90%) rename tezos_proto/src/{executor => operations/types}/reveal.rs (96%) rename tezos_proto/src/{executor => operations/types}/transaction.rs (89%) rename tezos_proto/src/{validator/operation.rs => operations/validator.rs} (99%) rename tezos_proto/src/{runner/mempool.rs => protocol/bridge.rs} (100%) create mode 100644 tezos_proto/src/protocol/constants.rs create mode 100644 tezos_proto/src/protocol/fees.rs create mode 100644 tezos_proto/src/protocol/mempool.rs rename tezos_proto/src/{context => protocol}/migrations.rs (58%) create mode 100644 tezos_proto/src/protocol/mod.rs delete mode 100644 tezos_proto/src/runner/batch.rs delete mode 100644 tezos_proto/src/runner/mod.rs delete mode 100644 tezos_proto/src/validator/batch.rs diff --git a/Cargo.lock b/Cargo.lock index f28fa52..20c8de5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1705,8 +1705,10 @@ name = "layered_store" version = "0.1.0" dependencies = [ "derive_more", + "serde-json-wasm", "tezos-core", "tezos-michelson", + "tezos-rpc", ] [[package]] diff --git a/layered_store/Cargo.toml b/layered_store/Cargo.toml index 2c5224a..419141c 100644 --- a/layered_store/Cargo.toml +++ b/layered_store/Cargo.toml @@ -14,8 +14,10 @@ crate-type = ["cdylib", "rlib"] derive_more = "0.99" tezos_core = { git = "https://github.com/baking-bad/tezos-rust-sdk", optional = true, branch = "develop", package = "tezos-core", default-features = false, features = ["ed25519"] } tezos_michelson = { git = "https://github.com/baking-bad/tezos-rust-sdk", optional = true, branch = "develop", package = "tezos-michelson", default-features = false } +tezos_rpc = { git = "https://github.com/baking-bad/tezos-rust-sdk", optional = true, branch = "develop", package = "tezos-rpc", default-features = false } +serde-json-wasm = { git = "https://github.com/CosmWasm/serde-json-wasm", optional = true, branch = "main" } [features] default = [] testing = ["tezos"] -tezos = ["dep:tezos_core", "dep:tezos_michelson"] \ No newline at end of file +tezos = ["dep:tezos_core", "dep:tezos_michelson", "dep:tezos_rpc", "dep:serde-json-wasm"] \ No newline at end of file diff --git a/layered_store/src/store.rs b/layered_store/src/store.rs index 25764b7..52a391e 100644 --- a/layered_store/src/store.rs +++ b/layered_store/src/store.rs @@ -106,6 +106,10 @@ impl LayeredStore { Ok(()) } + // TODO: implement state hash calculation + // state = blake2b(state, key, value) + // accept prev state as an optional argument + // if state is None skip hashing pub fn commit(&mut self) -> Result<()> { let modified_keys: Vec = self.modified_keys.drain().collect(); for key in modified_keys { diff --git a/layered_store/src/types/tezos.rs b/layered_store/src/types/tezos.rs index c5953bb..edf0fa9 100644 --- a/layered_store/src/types/tezos.rs +++ b/layered_store/src/types/tezos.rs @@ -8,8 +8,9 @@ use tezos_core::types::{ number::Nat, }; use tezos_michelson::micheline::Micheline; +use tezos_rpc::models::operation::Operation; -use crate::{internal_error, Result, StoreType}; +use crate::{error::err_into, internal_error, Result, StoreType}; macro_rules! impl_for_core { ($cls: ident, $ty: ty) => { @@ -31,3 +32,18 @@ impl_for_core!(Encoded, ContractAddress); impl_for_core!(Micheline, Micheline); impl_for_core!(Mutez, Mutez); impl_for_core!(Nat, Nat); + +impl StoreType for Operation { + fn from_bytes(_bytes: &[u8]) -> Result { + #[cfg(not(target_arch = "wasm32"))] + { + Ok(serde_json_wasm::de::from_slice(_bytes).map_err(err_into)?) + } + #[cfg(target_arch = "wasm32")] + unimplemented!() + } + + fn to_bytes(&self) -> Result> { + serde_json_wasm::ser::to_vec(&self).map_err(err_into) + } +} diff --git a/tezos_node/src/rollup.rs b/tezos_node/src/rollup.rs index a6b0d2d..24730be 100644 --- a/tezos_node/src/rollup.rs +++ b/tezos_node/src/rollup.rs @@ -19,7 +19,7 @@ use tezos_core::types::encoded::{ use tezos_core::types::{mutez::Mutez, number::Nat}; use tezos_michelson::micheline::Micheline; use tezos_operation::operations::SignedOperation; -use tezos_proto::context::{batch::BatchReceipt, head::Head, store::OperationReceipt}; +use tezos_proto::context::{batch_receipt::BatchReceipt, head::Head, store::OperationReceipt}; use tezos_rpc::models::{ block::{Block, FullHeader, Metadata}, contract::{ContractEntrypoints, ContractInfo, ContractScript}, diff --git a/tezos_node/src/services/blocks.rs b/tezos_node/src/services/blocks.rs index 4455771..f4c73ac 100644 --- a/tezos_node/src/services/blocks.rs +++ b/tezos_node/src/services/blocks.rs @@ -68,7 +68,7 @@ mod test { use actix_web::{test, web::Data, App}; use tezos_core::types::encoded::{BlockHash, Encoded}; use tezos_proto::context::{ - batch::{BatchHeader, BatchReceipt}, + batch_receipt::{BatchHeader, BatchReceipt}, head::Head, TezosContext, }; diff --git a/tezos_node/src/services/context.rs b/tezos_node/src/services/context.rs index 224bcc0..9a0ecdb 100644 --- a/tezos_node/src/services/context.rs +++ b/tezos_node/src/services/context.rs @@ -8,12 +8,12 @@ use actix_web::{ HttpResponse, Responder, Result, }; use tezos_core::types::encoded::ScriptExprHash; -use tezos_proto::config::Config; +use tezos_proto::constants::Constants; use crate::{json_response, rollup::TezosFacade, Error}; pub async fn constants() -> Result { - Ok(json_response!(Config::default())) + Ok(json_response!(Constants::default())) } pub async fn delegates() -> Result { diff --git a/tezos_proto/src/batch/executor.rs b/tezos_proto/src/batch/executor.rs new file mode 100644 index 0000000..0af2d6f --- /dev/null +++ b/tezos_proto/src/batch/executor.rs @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: 2023 Baking Bad +// +// SPDX-License-Identifier: MIT + +use michelson_vm::interpreter::InterpreterContext; +use tezos_core::types::encoded::{ContextHash, OperationHash}; +use tezos_rpc::models::operation::Operation as OperationReceipt; + +use crate::{ + batch::{header::BatchHeader, receipt::BatchReceipt}, + config::Config, + context::{head::Head, TezosContext}, + operations::{executor::execute_operation, validator::ValidOperation}, + protocol::{constants::Constants, migrations::Migrations}, + Result, +}; + +pub fn execute_batch( + context: &mut (impl TezosContext + InterpreterContext), + operations: Vec, + header: Option, +) -> Result<()> { + context.check_no_pending_changes()?; + + let head = context.get_head()?; + let balance_updates = C::Migrations::run(context, &head)?; + // TODO: implicit deployments C::System + // TODO: implicit ticket updates C::Bridge + + let mut operation_receipts: Vec = Vec::with_capacity(operations.len()); + let mut operation_hashes: Vec = Vec::with_capacity(operations.len()); + for opg in operations.iter() { + operation_receipts.push(execute_operation::(context, opg)?); + operation_hashes.push(opg.hash.clone()); + } + + let header = match header { + Some(h) => h, // TODO: verify context hash + None => { + // TODO: implement checksum or use durable storage root and store in the context + let context_hash: ContextHash = + "CoVhFUFQvxrbdDDemLCSXU4DLMfsVdvrbgCCXcCKBWqPAQ1gK8cL".try_into()?; + BatchHeader::implicit(&head, operation_hashes.clone(), context_hash)? + } + }; + + let hash = header.block_hash()?; + let receipt = BatchReceipt { + chain_id: head.chain_id.clone(), + protocol: C::Constants::protocol(), + hash: hash.clone(), + header: header.clone(), + balance_updates: Some(balance_updates), + batcher: None, // TODO: set + }; + context.set_batch_receipt(receipt)?; + + for opg_receipt in operation_receipts { + context.set_operation_receipt(opg_receipt)?; + } + + // TODO: do not store receipts in kernel storage (to save space), only on the sequencer side + + let head = Head::new( + head.chain_id, + header.level, + hash.clone(), + header.timestamp, + operation_hashes, + ); + context.set_head(head.clone())?; + context.commit()?; + + Ok(()) +} diff --git a/tezos_proto/src/batch/header.rs b/tezos_proto/src/batch/header.rs new file mode 100644 index 0000000..b9f56f5 --- /dev/null +++ b/tezos_proto/src/batch/header.rs @@ -0,0 +1,117 @@ +// SPDX-FileCopyrightText: 2023 Baking Bad +// +// SPDX-License-Identifier: MIT + +use tezos_core::{ + internal::coder::Encoder, + internal::crypto::blake2b, + types::encoded::{ + BlockHash, BlockPayloadHash, ContextHash, Encoded, OperationHash, OperationListListHash, + Signature, + }, +}; +use tezos_operation::{ + block_header, internal::coder::operation_content_bytes_coder::OperationContentBytesCoder, +}; +use tezos_rpc::models::block::{Header, LiquidityBakingToggleVote}; + +use chrono::NaiveDateTime; +use serde::{Deserialize, Serialize}; + +use crate::{context::head::Head, Result}; + +// TODO: make it meaningful so that TzKT can understand + embed git commit +pub const POW_NONCE: &str = "deadbeef"; +pub const ZERO_SIGNATURE: &str = + "sigMzJ4GVAvXEd2RjsKGfG2H9QvqTSKCZsuB2KiHbZRGFz72XgF6KaKADznh674fQgBatxw3xdHqTtMHUZAGRprxy64wg1aq"; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct BatchHeader { + pub predecessor: BlockHash, + pub level: i32, + pub timestamp: i64, + pub operations_hash: OperationListListHash, + pub payload_hash: BlockPayloadHash, + pub context: ContextHash, + pub signature: Option, +} + +impl BatchHeader { + pub fn block_hash(&self) -> Result { + let header = block_header::BlockHeader::from(self.clone()); + let payload = OperationContentBytesCoder::encode(&header)?; + let hash = blake2b(payload.as_slice(), 32)?; + Ok(BlockHash::from_bytes(&hash)?) + } + + pub fn implicit( + prev_head: &Head, + operation_hashes: Vec, + context_hash: ContextHash, + ) -> Result { + Ok(BatchHeader { + level: prev_head.level + 1, + predecessor: prev_head.hash.clone(), + payload_hash: BlockPayloadHash::from_parts( + prev_head.hash.clone(), + 0, + operation_hashes.clone(), + )?, + operations_hash: OperationListListHash::try_from(vec![ + vec![], + vec![], + vec![], + operation_hashes, + ])?, + context: context_hash, + timestamp: prev_head.timestamp + 1, // Minimal possible delta, cannot go faster :D + signature: None, + }) + } +} + +impl From for block_header::BlockHeader { + fn from(header: BatchHeader) -> Self { + Self { + context: header.context, + fitness: vec![], + level: header.level, + liquidity_baking_toggle_vote: block_header::LiquidityBakingToggleVote::Off, + operations_hash: header.operations_hash, + payload_hash: header.payload_hash, + payload_round: 0, + predecessor: header.predecessor, + proof_of_work_nonce: POW_NONCE.try_into().unwrap(), + proto: 0, + seed_nonce_hash: None, + signature: header + .signature + .unwrap_or_else(|| ZERO_SIGNATURE.try_into().unwrap()), + timestamp: NaiveDateTime::from_timestamp_opt(header.timestamp, 0).unwrap(), + validation_pass: 4, + } + } +} + +impl From for Header { + fn from(header: BatchHeader) -> Self { + Self { + context: header.context, + fitness: vec![], + level: header.level, + liquidity_baking_escape_vote: false, + liquidity_baking_toggle_vote: LiquidityBakingToggleVote::Off, + operations_hash: header.operations_hash, + payload_hash: Some(header.payload_hash), + payload_round: 0, + predecessor: header.predecessor, + priority: 0, + proof_of_work_nonce: POW_NONCE.into(), + proto: 0, + seed_nonce_hash: None, + signature: None, + timestamp: NaiveDateTime::from_timestamp_opt(header.timestamp, 0).unwrap(), + validation_pass: 4, + } + } +} diff --git a/tezos_proto/src/batch/mod.rs b/tezos_proto/src/batch/mod.rs new file mode 100644 index 0000000..a2ca10c --- /dev/null +++ b/tezos_proto/src/batch/mod.rs @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2023 Baking Bad +// +// SPDX-License-Identifier: MIT + +pub mod executor; +pub mod header; +pub mod payload; +pub mod receipt; +pub mod validator; diff --git a/tezos_proto/src/batch/payload.rs b/tezos_proto/src/batch/payload.rs new file mode 100644 index 0000000..fbee7cc --- /dev/null +++ b/tezos_proto/src/batch/payload.rs @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2023 Baking Bad +// +// SPDX-License-Identifier: MIT + +use std::collections::BTreeMap; + +use tezos_core::types::encoded::{OperationHash, OperationListListHash}; +use tezos_operation::operations::SignedOperation; + +use crate::Result; + +use super::header::BatchHeader; + +pub struct BatchPayload { + pub header: BatchHeader, + pub operations: BTreeMap, +} + +impl BatchPayload { + pub fn operation_list_list_hash(&self) -> Result { + let operation_hashes: Vec = self.operations.keys().cloned().collect(); + Ok(OperationListListHash::try_from(vec![ + vec![], + vec![], + vec![], + operation_hashes, + ])?) + } +} diff --git a/tezos_proto/src/batch/receipt.rs b/tezos_proto/src/batch/receipt.rs new file mode 100644 index 0000000..7d3e9f3 --- /dev/null +++ b/tezos_proto/src/batch/receipt.rs @@ -0,0 +1,136 @@ +// SPDX-FileCopyrightText: 2023 Baking Bad +// +// SPDX-License-Identifier: MIT + +use layered_store::{error::err_into, Result, StoreType}; +use tezos_core::types::encoded::{BlockHash, ChainId, ImplicitAddress, ProtocolHash}; +use tezos_rpc::models::{ + balance_update::BalanceUpdate, + block::{ + FullHeader, LevelInfo, Metadata, OperationListLength, TestChainStatus, TestChainStatusName, + }, +}; + +use chrono::NaiveDateTime; +use serde::{Deserialize, Serialize}; + +use crate::batch::header::{BatchHeader, POW_NONCE}; +use crate::protocol::constants::{Constants, ProtocolAlpha}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct BatchReceipt { + pub chain_id: ChainId, + pub protocol: ProtocolHash, + pub hash: BlockHash, + pub header: BatchHeader, + pub balance_updates: Option>, + pub batcher: Option, +} + +impl StoreType for BatchReceipt { + fn from_bytes(_bytes: &[u8]) -> Result { + #[cfg(not(target_arch = "wasm32"))] + { + // This is a workaround to avoid floating point operations introduced by serde. + // Since we do not need RPC models deserialization inside the kernel, + // we can only enable that for tests and binaries that are not compiled to wasm. + serde_json_wasm::de::from_slice(_bytes).map_err(err_into) + } + #[cfg(target_arch = "wasm32")] + unimplemented!() + } + + fn to_bytes(&self) -> Result> { + serde_json_wasm::ser::to_vec(self).map_err(err_into) + } +} + +impl From for Metadata { + fn from(receipt: BatchReceipt) -> Self { + // TODO: this code is only used in sequencer, need to move it there + // Constants should be retrieved separately and then merged with batch receipts + let constants = ProtocolAlpha::constants(); + Self { + baker: receipt.batcher.clone(), + proposer: receipt.batcher, + balance_updates: receipt.balance_updates, + // derived + protocol: receipt.protocol.clone(), + next_protocol: receipt.protocol, + level_info: Some(LevelInfo { + level: receipt.header.level, + level_position: receipt.header.level - 1, + cycle: receipt.header.level / constants.blocks_per_cycle, + cycle_position: receipt.header.level % constants.blocks_per_cycle, + expected_commitment: false, + }), + // default + max_operations_ttl: constants.max_operations_time_to_live, + max_operation_data_length: constants.max_operation_data_length, + max_operation_list_length: vec![ + OperationListLength { + max_size: 0, + max_op: None, + }, + OperationListLength { + max_size: 0, + max_op: None, + }, + OperationListLength { + max_size: 0, + max_op: None, + }, + OperationListLength { + max_size: constants.max_operations_list_length, + max_op: Some( + constants.max_operations_list_length * constants.max_operation_data_length, + ), + }, + ], + max_block_header_length: constants.max_block_header_length, + // null / deprecated + level: None, + consumed_gas: None, + deactivated: None, + implicit_operations_results: None, + voting_period_kind: None, + voting_period_info: None, + test_chain_status: TestChainStatus { + status: TestChainStatusName::NotRunning, + chain_id: None, + genesis: None, + protocol: None, + expiration: None, + }, + nonce_hash: None, + liquidity_baking_toggle_ema: None, + liquidity_baking_escape_ema: None, + } + } +} + +// TODO: move to sequencer +impl From for FullHeader { + fn from(receipt: BatchReceipt) -> Self { + Self { + chain_id: receipt.chain_id, + context: receipt.header.context, + fitness: vec![], + hash: receipt.hash, + level: receipt.header.level, + liquidity_baking_escape_vote: false, + operations_hash: receipt.header.operations_hash, + payload_hash: Some(receipt.header.payload_hash), + payload_round: 0, + predecessor: receipt.header.predecessor, + priority: 0, + proof_of_work_nonce: POW_NONCE.into(), + proto: 0, + protocol: receipt.protocol, + seed_nonce_hash: None, + signature: None, + timestamp: NaiveDateTime::from_timestamp_opt(receipt.header.timestamp, 0).unwrap(), + validation_pass: 4, + } + } +} diff --git a/tezos_proto/src/batch/validator.rs b/tezos_proto/src/batch/validator.rs new file mode 100644 index 0000000..f9898c0 --- /dev/null +++ b/tezos_proto/src/batch/validator.rs @@ -0,0 +1,133 @@ +// SPDX-FileCopyrightText: 2023 Baking Bad +// +// SPDX-License-Identifier: MIT + +use tezos_core::types::encoded::{Encoded, OperationHash}; +use tezos_operation::operations::SignedOperation; + +use crate::{ + context::TezosContext, + operations::validator::{validate_operation, ValidOperation, ValidatedOperation}, + Error, Result, +}; + +use super::payload::BatchPayload; + +macro_rules! assert_attr_eq { + ($expected: expr, $actual: expr) => { + if $actual != $expected { + return Err(Error::InvalidBatchHeader { + reason: format!( + "{}: expected {:?}, got {:?}", + stringify!($actual), + $expected, + $actual + ), + }); + } + }; +} + +pub fn validate_explicit_batch( + context: &mut impl TezosContext, + batch: BatchPayload, + dry_run: bool, +) -> Result> { + context.check_no_pending_changes()?; + + let prev_head = context.get_head()?; + + assert_attr_eq!(prev_head.level + 1, batch.header.level); + assert_attr_eq!(prev_head.hash, batch.header.predecessor); + + if batch.header.timestamp < prev_head.timestamp + 1 { + return Err(Error::InvalidBatchHeader { + reason: format!( + "batch.header.timestamp: expected at least {}, got {}", + prev_head.timestamp + 1, + batch.header.timestamp + ), + }); + } + + assert_attr_eq!( + batch.operation_list_list_hash()?, + batch.header.operations_hash + ); + + if !dry_run { + // TODO: check signature against whitelisted sequencer account + } + + let mut valid_operations: Vec = Vec::with_capacity(batch.operations.len()); + + for (hash, opg) in batch.operations.into_iter() { + match validate_operation(context, opg, hash.clone(), dry_run) { + Ok(ValidatedOperation::Valid(op)) => { + let balance = context.get_balance(&op.source.value())?.unwrap(); + context.set_balance(&op.source.value(), balance - op.total_spent)?; + context.set_counter(&op.source.value(), op.last_counter.clone())?; + valid_operations.push(op); + } + Ok(ValidatedOperation::Invalid(errors)) => { + context.log(format!( + "Invalid batch operation {}\n{:#?}", + hash.value(), + errors + )); + context.rollback(); + return Err(Error::InvalidBatchOperation { + reason: format!("{:#?}", errors), + }); + } + Err(err) => { + context.log(format!( + "Batch validator error at {}\n{}", + hash.value(), + err.format() + )); + context.rollback(); + return Err(err); + } + } + } + + context.rollback(); + + Ok(valid_operations) +} + +pub fn validate_implicit_batch( + context: &mut impl TezosContext, + operations: Vec<(OperationHash, SignedOperation)>, + dry_run: bool, +) -> Result> { + context.check_no_pending_changes()?; + + let mut valid_operations: Vec = Vec::with_capacity(operations.len()); + + for (hash, opg) in operations.into_iter() { + match validate_operation(context, opg, hash.clone(), dry_run) { + Ok(ValidatedOperation::Valid(op)) => { + let balance = context.get_balance(&op.source.value())?.unwrap(); + context.set_balance(&op.source.value(), balance - op.total_spent)?; + context.set_counter(&op.source.value(), op.last_counter.clone())?; + valid_operations.push(op); + } + Ok(ValidatedOperation::Invalid(errors)) => { + context.log(format!("Invalid operation: {:#?}", errors)); + } + Err(err) => { + context.log(format!( + "Validator error: {}\n{}", + hash.value(), + err.format() + )); + } + } + } + + context.rollback(); + + Ok(valid_operations) +} diff --git a/tezos_proto/src/batcher.rs b/tezos_proto/src/batcher.rs deleted file mode 100644 index e4993e9..0000000 --- a/tezos_proto/src/batcher.rs +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Baking Bad -// -// SPDX-License-Identifier: MIT - -use michelson_vm::interpreter::InterpreterContext; -use tezos_core::{ - internal::coder::Encoder, - internal::crypto::blake2b, - types::encoded::{BlockHash, BlockPayloadHash, Encoded, OperationHash, OperationListListHash}, -}; -use tezos_operation::{ - block_header, internal::coder::operation_content_bytes_coder::OperationContentBytesCoder, - operations::SignedOperation, -}; -use tezos_rpc::models::operation::Operation as OperationReceipt; - -use crate::{ - config::*, - context::{ - batch::{BatchHeader, BatchReceipt}, - head::Head, - migrations::run_migrations, - TezosContext, - }, - executor::operation::execute_operation, - validator::{batch::validate_batch, operation::ValidOperation}, - Result, -}; - -pub fn block_hash(header: BatchHeader) -> Result { - let header = block_header::BlockHeader::from(header); - let payload = OperationContentBytesCoder::encode(&header)?; - let hash = blake2b(payload.as_slice(), 32)?; - Ok(BlockHash::from_bytes(&hash)?) -} - -fn naive_header(prev_head: Head, operations: &Vec) -> Result { - let operation_hashes: Vec = operations.iter().map(|o| o.hash.clone()).collect(); - Ok(BatchHeader { - level: prev_head.level + 1, - predecessor: prev_head.hash.to_owned(), - payload_hash: BlockPayloadHash::from_parts(prev_head.hash, 0, operation_hashes.to_owned())?, - operations_hash: OperationListListHash::try_from(vec![ - vec![], - vec![], - vec![], - operation_hashes, - ])?, - context: "CoVhFUFQvxrbdDDemLCSXU4DLMfsVdvrbgCCXcCKBWqPAQ1gK8cL".try_into()?, // TODO - timestamp: prev_head.timestamp + BLOCK_TIME, - }) -} - -pub fn apply_batch( - context: &mut (impl TezosContext + InterpreterContext), - prev_head: Head, - batch_payload: Vec<(OperationHash, SignedOperation)>, - atomic: bool, -) -> Result { - context.check_no_pending_changes()?; - - let balance_updates = run_migrations(context, &prev_head)?; - let operations = validate_batch(context, batch_payload, atomic)?; - let chain_id = prev_head.chain_id.clone(); - - let mut operation_receipts: Vec = Vec::with_capacity(operations.len()); - for opg in operations.iter() { - operation_receipts.push(execute_operation(context, opg)?); - } - - // TODO: fees to batch producer (balance updates + update balance) - - let header = naive_header(prev_head, &operations)?; - let hash = block_hash(header.clone())?; - let receipt = BatchReceipt { - chain_id: chain_id.clone(), - protocol: PROTOCOL.try_into().unwrap(), - hash: hash.clone(), - header: header.clone(), - balance_updates, - }; - context.set_batch_receipt(receipt)?; - - let mut opg_hashes: Vec = Vec::with_capacity(operation_receipts.len()); - for opg_receipt in operation_receipts { - opg_hashes.push(opg_receipt.hash.clone().unwrap()); - context.set_operation_receipt(opg_receipt)?; - } - - let head = Head::new( - chain_id, - header.level, - hash.clone(), - header.timestamp, - opg_hashes, - ); - context.set_head(head.clone())?; - context.commit()?; - - Ok(head) -} diff --git a/tezos_proto/src/config.rs b/tezos_proto/src/config.rs index d889466..0392aa3 100644 --- a/tezos_proto/src/config.rs +++ b/tezos_proto/src/config.rs @@ -1,40 +1,18 @@ -// SPDX-FileCopyrightText: 2023 Baking Bad -// -// SPDX-License-Identifier: MIT +use crate::protocol::{constants::{Constants, ProtocolAlpha}, migrations::{Migrations, SandboxSeed}}; -use serde::{Deserialize, Serialize}; -use tezos_core::types::number::Nat; - -pub const PROTOCOL: &str = "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK"; -pub const BLOCK_TIME: i64 = 8; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Config { - pub blocks_per_cycle: i32, - pub max_operations_time_to_live: i32, - pub max_block_header_length: i32, - pub max_operation_data_length: i32, - pub max_operations_list_length: i32, - pub pow_nonce: String, - pub hard_gas_limit_per_operation: Nat, - pub hard_storage_limit_per_operation: Nat, - pub hard_gas_limit_per_block: Nat, - pub cost_per_byte: Nat, +pub trait Config { + type Constants: Constants; + type Migrations: Migrations; + // type Fees: Fees; + // type Bridge: Bridge; + // type Mempool: Mempool; + // type Producer: Producer; + // type Contracts: Contracts; } -impl Config { - pub fn default() -> Self { - Self { - blocks_per_cycle: 8096, - max_operations_time_to_live: 240, - max_block_header_length: 2048, - max_operation_data_length: 86400, - max_operations_list_length: 1024, - pow_nonce: "deadbeef".into(), - hard_gas_limit_per_operation: 1040000u64.into(), - hard_storage_limit_per_operation: 60000u64.into(), - hard_gas_limit_per_block: 5200000u64.into(), - cost_per_byte: 250u32.into(), - } - } +pub struct DefaultConfig {} + +impl Config for DefaultConfig { + type Constants = ProtocolAlpha; + type Migrations = SandboxSeed; } diff --git a/tezos_proto/src/context/batch.rs b/tezos_proto/src/context/batch.rs deleted file mode 100644 index 41ece49..0000000 --- a/tezos_proto/src/context/batch.rs +++ /dev/null @@ -1,189 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Baking Bad -// -// SPDX-License-Identifier: MIT - -use tezos_core::types::encoded::{ - BlockHash, BlockPayloadHash, ChainId, ContextHash, OperationListListHash, ProtocolHash, Signature, ImplicitAddress -}; -use tezos_operation::block_header; -use tezos_rpc::models::{ - balance_update::BalanceUpdate, - block::{ - FullHeader, Header, LevelInfo, LiquidityBakingToggleVote, Metadata, OperationListLength, - TestChainStatus, TestChainStatusName, - }, -}; - -use chrono::NaiveDateTime; -use serde::{Deserialize, Serialize}; - -use crate::config::Config; - -pub const ZERO_SIGNATURE: &str = - "sigMzJ4GVAvXEd2RjsKGfG2H9QvqTSKCZsuB2KiHbZRGFz72XgF6KaKADznh674fQgBatxw3xdHqTtMHUZAGRprxy64wg1aq"; - -macro_rules! ts2dt { - ($ts: expr) => { - NaiveDateTime::from_timestamp_opt($ts, 0).unwrap() - }; -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct BatchHeader { - pub predecessor: BlockHash, - pub level: i32, - pub timestamp: i64, - pub operations_hash: OperationListListHash, - pub payload_hash: BlockPayloadHash, - pub context: ContextHash, - pub signature: Option -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct BatchReceipt { - pub chain_id: ChainId, - pub protocol: ProtocolHash, - pub hash: BlockHash, - pub header: BatchHeader, - pub balance_updates: Option>, - pub batcher: Option -} - -impl From for block_header::BlockHeader { - fn from(header: BatchHeader) -> Self { - let config = Config::default(); - Self { - context: header.context, - fitness: vec![], - level: header.level, - liquidity_baking_toggle_vote: block_header::LiquidityBakingToggleVote::Off, - operations_hash: header.operations_hash, - payload_hash: header.payload_hash, - payload_round: 0, - predecessor: header.predecessor, - proof_of_work_nonce: config - .pow_nonce - .try_into() - .expect("Failed to convert pow nonce"), - proto: 0, - seed_nonce_hash: None, - signature: header.signature.unwrap_or_else( - || ZERO_SIGNATURE.try_into().expect("Failed to convert signature") - ), - timestamp: ts2dt!(header.timestamp), - validation_pass: 4, - } - } -} - -impl From for Header { - fn from(header: BatchHeader) -> Self { - let config = Config::default(); - Self { - context: header.context, - fitness: vec![], - level: header.level, - liquidity_baking_escape_vote: false, - liquidity_baking_toggle_vote: LiquidityBakingToggleVote::Off, - operations_hash: header.operations_hash, - payload_hash: Some(header.payload_hash), - payload_round: 0, - predecessor: header.predecessor, - priority: 0, - proof_of_work_nonce: config.pow_nonce, - proto: 0, - seed_nonce_hash: None, - signature: None, - timestamp: ts2dt!(header.timestamp), - validation_pass: 4, - } - } -} - -impl From for Metadata { - fn from(receipt: BatchReceipt) -> Self { - let config = Config::default(); - Self { - baker: receipt.batcher, - proposer: receipt.batcher, - balance_updates: receipt.balance_updates, - // derived - protocol: receipt.protocol.to_owned(), - next_protocol: receipt.protocol, - level_info: Some(LevelInfo { - level: receipt.header.level, - level_position: receipt.header.level - 1, - cycle: receipt.header.level / config.blocks_per_cycle, - cycle_position: receipt.header.level % config.blocks_per_cycle, - expected_commitment: false, - }), - // default - max_operations_ttl: config.max_operations_time_to_live, - max_operation_data_length: config.max_operation_data_length, - max_operation_list_length: vec![ - OperationListLength { - max_size: 0, - max_op: None, - }, - OperationListLength { - max_size: 0, - max_op: None, - }, - OperationListLength { - max_size: 0, - max_op: None, - }, - OperationListLength { - max_size: config.max_operations_list_length, - max_op: Some( - config.max_operations_list_length * config.max_operation_data_length, - ), - }, - ], - max_block_header_length: config.max_block_header_length, - // null / deprecated - level: None, - consumed_gas: None, - deactivated: None, - implicit_operations_results: None, - voting_period_kind: None, - voting_period_info: None, - test_chain_status: TestChainStatus { - status: TestChainStatusName::NotRunning, - chain_id: None, - genesis: None, - protocol: None, - expiration: None, - }, - nonce_hash: None, - liquidity_baking_toggle_ema: None, - liquidity_baking_escape_ema: None, - } - } -} - -impl From for FullHeader { - fn from(receipt: BatchReceipt) -> Self { - let config = Config::default(); - Self { - chain_id: receipt.chain_id, - context: receipt.header.context, - fitness: vec![], - hash: receipt.hash, - level: receipt.header.level, - liquidity_baking_escape_vote: false, - operations_hash: receipt.header.operations_hash, - payload_hash: Some(receipt.header.payload_hash), - payload_round: 0, - predecessor: receipt.header.predecessor, - priority: 0, - proof_of_work_nonce: config.pow_nonce, - proto: 0, - protocol: receipt.protocol, - seed_nonce_hash: None, - signature: None, - timestamp: ts2dt!(receipt.header.timestamp), - validation_pass: 4, - } - } -} diff --git a/tezos_proto/src/context/head.rs b/tezos_proto/src/context/head.rs index 49578b7..458c24a 100644 --- a/tezos_proto/src/context/head.rs +++ b/tezos_proto/src/context/head.rs @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: MIT +use layered_store::{error::err_into, Result, StoreType}; use serde::{Deserialize, Serialize}; use tezos_core::types::encoded::{BlockHash, ChainId, Encoded, OperationHash}; @@ -56,3 +57,13 @@ impl std::fmt::Display for Head { )) } } + +impl StoreType for Head { + fn from_bytes(bytes: &[u8]) -> Result { + serde_json_wasm::de::from_slice(bytes).map_err(err_into) + } + + fn to_bytes(&self) -> Result> { + serde_json_wasm::ser::to_vec(self).map_err(err_into) + } +} diff --git a/tezos_proto/src/context/mod.rs b/tezos_proto/src/context/mod.rs index 67e5b19..f7b4805 100644 --- a/tezos_proto/src/context/mod.rs +++ b/tezos_proto/src/context/mod.rs @@ -2,11 +2,177 @@ // // SPDX-License-Identifier: MIT -pub mod batch; pub mod head; -pub mod migrations; -pub mod store; -pub mod tezos; -pub use tezos::TezosContext; +use layered_store::{LayeredStore, StoreBackend}; +use tezos_core::types::{ + encoded::{Encoded, PublicKey}, + mutez::Mutez, + number::Nat, +}; +use tezos_michelson::micheline::Micheline; +use tezos_rpc::models::operation::Operation; + +use crate::{batch::receipt::BatchReceipt, context::head::Head, error::err_into, Error, Result}; + pub type TezosEphemeralContext = layered_store::EphemeralStore; + +pub trait TezosContext { + fn get_head(&mut self) -> Result; + fn set_head(&mut self, head: Head) -> Result<()>; + fn get_balance(&mut self, address: &str) -> Result>; + fn set_balance(&mut self, address: &str, balance: Mutez) -> Result<()>; + fn get_counter(&mut self, address: &str) -> Result; + fn set_counter(&mut self, address: &str, counter: Nat) -> Result<()>; + fn has_public_key(&self, address: &str) -> Result; + fn get_public_key(&mut self, address: &str) -> Result>; + fn set_public_key(&mut self, address: &str, public_key: PublicKey) -> Result<()>; + fn set_contract_code(&mut self, address: &str, code: Micheline) -> Result<()>; + fn get_contract_code(&mut self, address: &str) -> Result>; + fn get_contract_storage(&mut self, address: &str) -> Result>; + fn set_contract_storage(&mut self, address: &str, storage: Micheline) -> Result<()>; + fn set_batch_receipt(&mut self, receipt: BatchReceipt) -> Result<()>; + fn get_batch_receipt(&mut self, hash: &str) -> Result; + fn set_operation_receipt(&mut self, receipt: Operation) -> Result<()>; + fn get_operation_receipt(&mut self, hash: &str) -> Result; + fn check_no_pending_changes(&self) -> Result<()>; + fn commit(&mut self) -> Result<()>; + fn rollback(&mut self); + fn log(&self, msg: String); +} + +impl TezosContext for LayeredStore { + fn get_head(&mut self) -> Result { + match self.get("/head".into()) { + Ok(Some(head)) => Ok(head), + Ok(None) => Ok(Head::default()), + Err(err) => Err(err_into(err)), + } + } + + fn set_head(&mut self, head: Head) -> Result<()> { + self.set("/head".into(), Some(head)).map_err(err_into) + } + + fn get_balance(&mut self, address: &str) -> Result> { + self.get(format!("/context/contracts/{}/balance", address)) + .map_err(err_into) + } + + fn set_balance(&mut self, address: &str, balance: Mutez) -> Result<()> { + self.set( + format!("/context/contracts/{}/balance", address), + Some(balance), + ) + .map_err(err_into) + } + + fn get_counter(&mut self, address: &str) -> Result { + match self.get(format!("/context/contracts/{}/counter", address)) { + Ok(Some(value)) => Ok(value), + Ok(None) => Ok(Nat::from_integer(0)), + Err(err) => Err(err_into(err)), + } + } + + fn set_counter(&mut self, address: &str, counter: Nat) -> Result<()> { + self.set( + format!("/context/contracts/{}/counter", address), + Some(counter), + ) + .map_err(err_into) + } + + fn get_public_key(&mut self, address: &str) -> Result> { + self.get(format!("/context/contracts/{}/pubkey", address)) + .map_err(err_into) + } + + fn set_public_key(&mut self, address: &str, public_key: PublicKey) -> Result<()> { + // NOTE: Underscores are not allowed in path (host restriction) + self.set( + format!("/context/contracts/{}/pubkey", address), + Some(public_key), + ) + .map_err(err_into) + } + + fn has_public_key(&self, address: &str) -> Result { + self.has(format!("/context/contracts/{}/pubkey", address)) + .map_err(err_into) + } + + fn set_batch_receipt(&mut self, receipt: BatchReceipt) -> Result<()> { + self.set( + format!("/batches/{}", receipt.hash.value()).into(), + Some(receipt), + ) + .map_err(err_into) + } + + fn get_batch_receipt(&mut self, hash: &str) -> Result { + self.get(format!("/batches/{}", hash)) + .map_err(err_into)? + .ok_or(Error::BatchNotFound { hash: hash.into() }) + } + + fn set_operation_receipt(&mut self, receipt: Operation) -> Result<()> { + self.set( + format!( + "/operations/{}", + receipt.hash.as_ref().expect("Operation hash").value() + ), + Some(receipt), + ) + .map_err(err_into) + } + + fn get_operation_receipt(&mut self, hash: &str) -> Result { + self.get::(format!("/operations/{}", hash)) + .map_err(err_into)? + .ok_or(Error::OperationNotFound { hash: hash.into() }) + } + + fn get_contract_code(&mut self, address: &str) -> Result> { + self.get(format!("/context/contracts/{}/code", address)) + .map_err(err_into) + } + + fn set_contract_code(&mut self, address: &str, code: Micheline) -> Result<()> { + self.set(format!("/context/contracts/{}/code", address), Some(code)) + .map_err(err_into) + } + + fn get_contract_storage(&mut self, address: &str) -> Result> { + self.get(format!("/context/contracts/{}/storage", address)) + .map_err(err_into) + } + + fn set_contract_storage(&mut self, address: &str, storage: Micheline) -> Result<()> { + self.set( + format!("/context/contracts/{}/storage", address), + Some(storage), + ) + .map_err(err_into) + } + + fn check_no_pending_changes(&self) -> Result<()> { + if self.has_pending_changes() { + Err(layered_store::Error::ContextUnstagedError.into()) + } else { + Ok(()) + } + } + + fn commit(&mut self) -> Result<()> { + LayeredStore::commit(self).map_err(err_into) + } + + fn rollback(&mut self) { + LayeredStore::rollback(self) + } + + fn log(&self, msg: String) { + LayeredStore::log(&self, msg) + } +} diff --git a/tezos_proto/src/context/store.rs b/tezos_proto/src/context/store.rs deleted file mode 100644 index 2eeedf7..0000000 --- a/tezos_proto/src/context/store.rs +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Baking Bad -// -// SPDX-License-Identifier: MIT - -use layered_store::{error::err_into, Result, StoreType}; -use tezos_rpc::models::operation::Operation; - -use crate::{context::batch::BatchReceipt, context::head::Head}; - -impl StoreType for Head { - fn from_bytes(bytes: &[u8]) -> Result { - serde_json_wasm::de::from_slice(bytes).map_err(err_into) - } - - fn to_bytes(&self) -> Result> { - serde_json_wasm::ser::to_vec(self).map_err(err_into) - } -} - -impl StoreType for BatchReceipt { - fn from_bytes(_bytes: &[u8]) -> Result { - #[cfg(not(target_arch = "wasm32"))] - { - // This is a workaround to avoid floating point operations introduced by serde. - // Since we do not need RPC models deserialization inside the kernel, - // we can only enable that for tests and binaries that are not compiled to wasm. - serde_json_wasm::de::from_slice(_bytes).map_err(err_into) - } - #[cfg(target_arch = "wasm32")] - unimplemented!() - } - - fn to_bytes(&self) -> Result> { - serde_json_wasm::ser::to_vec(self).map_err(err_into) - } -} - -#[derive(Clone, Debug)] -pub struct OperationReceipt(pub Operation); - -impl StoreType for OperationReceipt { - fn from_bytes(_bytes: &[u8]) -> Result { - #[cfg(not(target_arch = "wasm32"))] - { - let operation: Operation = serde_json_wasm::de::from_slice(_bytes).map_err(err_into)?; - Ok(OperationReceipt(operation)) - } - #[cfg(target_arch = "wasm32")] - unimplemented!() - } - - fn to_bytes(&self) -> Result> { - serde_json_wasm::ser::to_vec(&self.0).map_err(err_into) - } -} diff --git a/tezos_proto/src/context/tezos.rs b/tezos_proto/src/context/tezos.rs deleted file mode 100644 index b875354..0000000 --- a/tezos_proto/src/context/tezos.rs +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Baking Bad -// -// SPDX-License-Identifier: MIT - -use layered_store::{LayeredStore, StoreBackend}; -use tezos_core::types::{ - encoded::{Encoded, PublicKey}, - mutez::Mutez, - number::Nat, -}; -use tezos_michelson::micheline::Micheline; -use tezos_rpc::models::operation::Operation; - -use crate::{ - context::{batch::BatchReceipt, head::Head, store::OperationReceipt}, - error::err_into, - Error, Result, -}; - -pub trait TezosContext { - fn get_head(&mut self) -> Result; - fn set_head(&mut self, head: Head) -> Result<()>; - fn get_balance(&mut self, address: &str) -> Result>; - fn set_balance(&mut self, address: &str, balance: Mutez) -> Result<()>; - fn get_counter(&mut self, address: &str) -> Result; - fn set_counter(&mut self, address: &str, counter: Nat) -> Result<()>; - fn has_public_key(&self, address: &str) -> Result; - fn get_public_key(&mut self, address: &str) -> Result>; - fn set_public_key(&mut self, address: &str, public_key: PublicKey) -> Result<()>; - fn set_contract_code(&mut self, address: &str, code: Micheline) -> Result<()>; - fn get_contract_code(&mut self, address: &str) -> Result>; - fn get_contract_storage(&mut self, address: &str) -> Result>; - fn set_contract_storage(&mut self, address: &str, storage: Micheline) -> Result<()>; - fn set_batch_receipt(&mut self, receipt: BatchReceipt) -> Result<()>; - fn get_batch_receipt(&mut self, hash: &str) -> Result; - fn set_operation_receipt(&mut self, receipt: Operation) -> Result<()>; - fn get_operation_receipt(&mut self, hash: &str) -> Result; - fn check_no_pending_changes(&self) -> Result<()>; - fn commit(&mut self) -> Result<()>; - fn rollback(&mut self); - fn log(&self, msg: String); -} - -impl TezosContext for LayeredStore { - fn get_head(&mut self) -> Result { - match self.get("/head".into()) { - Ok(Some(head)) => Ok(head), - Ok(None) => Ok(Head::default()), - Err(err) => Err(err_into(err)), - } - } - - fn set_head(&mut self, head: Head) -> Result<()> { - self.set("/head".into(), Some(head)).map_err(err_into) - } - - fn get_balance(&mut self, address: &str) -> Result> { - self.get(format!("/context/contracts/{}/balance", address)) - .map_err(err_into) - } - - fn set_balance(&mut self, address: &str, balance: Mutez) -> Result<()> { - self.set( - format!("/context/contracts/{}/balance", address), - Some(balance), - ) - .map_err(err_into) - } - - fn get_counter(&mut self, address: &str) -> Result { - match self.get(format!("/context/contracts/{}/counter", address)) { - Ok(Some(value)) => Ok(value), - Ok(None) => Ok(Nat::from_integer(0)), - Err(err) => Err(err_into(err)), - } - } - - fn set_counter(&mut self, address: &str, counter: Nat) -> Result<()> { - self.set( - format!("/context/contracts/{}/counter", address), - Some(counter), - ) - .map_err(err_into) - } - - fn get_public_key(&mut self, address: &str) -> Result> { - self.get(format!("/context/contracts/{}/pubkey", address)) - .map_err(err_into) - } - - fn set_public_key(&mut self, address: &str, public_key: PublicKey) -> Result<()> { - // NOTE: Underscores are not allowed in path (host restriction) - self.set( - format!("/context/contracts/{}/pubkey", address), - Some(public_key), - ) - .map_err(err_into) - } - - fn has_public_key(&self, address: &str) -> Result { - self.has(format!("/context/contracts/{}/pubkey", address)) - .map_err(err_into) - } - - fn set_batch_receipt(&mut self, receipt: BatchReceipt) -> Result<()> { - self.set( - format!("/batches/{}", receipt.hash.value()).into(), - Some(receipt), - ) - .map_err(err_into) - } - - fn get_batch_receipt(&mut self, hash: &str) -> Result { - self.get(format!("/batches/{}", hash)) - .map_err(err_into)? - .ok_or(Error::BatchNotFound { hash: hash.into() }) - } - - fn set_operation_receipt(&mut self, receipt: Operation) -> Result<()> { - self.set( - format!( - "/operations/{}", - receipt.hash.as_ref().expect("Operation hash").value() - ), - Some(OperationReceipt(receipt)), - ) - .map_err(err_into) - } - - fn get_operation_receipt(&mut self, hash: &str) -> Result { - self.get::(format!("/operations/{}", hash)) - .map_err(err_into)? - .ok_or(Error::OperationNotFound { hash: hash.into() }) - .map(|receipt| receipt.0) - } - - fn get_contract_code(&mut self, address: &str) -> Result> { - self.get(format!("/context/contracts/{}/code", address)) - .map_err(err_into) - } - - fn set_contract_code(&mut self, address: &str, code: Micheline) -> Result<()> { - self.set(format!("/context/contracts/{}/code", address), Some(code)) - .map_err(err_into) - } - - fn get_contract_storage(&mut self, address: &str) -> Result> { - self.get(format!("/context/contracts/{}/storage", address)) - .map_err(err_into) - } - - fn set_contract_storage(&mut self, address: &str, storage: Micheline) -> Result<()> { - self.set( - format!("/context/contracts/{}/storage", address), - Some(storage), - ) - .map_err(err_into) - } - - fn check_no_pending_changes(&self) -> Result<()> { - if self.has_pending_changes() { - Err(layered_store::Error::ContextUnstagedError.into()) - } else { - Ok(()) - } - } - - fn commit(&mut self) -> Result<()> { - LayeredStore::commit(self).map_err(err_into) - } - - fn rollback(&mut self) { - LayeredStore::rollback(self) - } - - fn log(&self, msg: String) { - LayeredStore::log(&self, msg) - } -} diff --git a/tezos_proto/src/executor/contract.rs b/tezos_proto/src/contracts/michelson.rs similarity index 92% rename from tezos_proto/src/executor/contract.rs rename to tezos_proto/src/contracts/michelson.rs index 12d91c0..fc6a4b6 100644 --- a/tezos_proto/src/executor/contract.rs +++ b/tezos_proto/src/contracts/michelson.rs @@ -16,7 +16,7 @@ use tezos_operation::operations::{ Entrypoint, OperationContent, Origination, Parameters, Transaction, }; -use crate::{config, context::TezosContext, Error, Result}; +use crate::{context::TezosContext, protocol::constants::Constants, Error, Result, config::Config}; #[derive(Debug, From)] pub enum ContractOutput { @@ -24,7 +24,7 @@ pub enum ContractOutput { Return(ScriptReturn), } -pub fn deploy_contract( +pub fn deploy_contract( context: &mut (impl TezosContext + InterpreterContext), origination: &Origination, self_address: ContractAddress, @@ -38,7 +38,7 @@ pub fn deploy_contract( balance, chain_id: head.chain_id, level: head.level + 1, - now: head.timestamp + config::BLOCK_TIME, + now: head.timestamp + C::Constants::constants().minimal_block_delay as i64, parameters: None, self_address, self_type: script.get_type(), @@ -57,7 +57,7 @@ pub fn deploy_contract( } } -pub fn execute_contract( +pub fn execute_contract( context: &mut (impl TezosContext + InterpreterContext), transaction: &Transaction, sender: Option
, @@ -84,7 +84,7 @@ pub fn execute_contract( balance, chain_id: head.chain_id, level: head.level + 1, - now: head.timestamp + config::BLOCK_TIME, + now: head.timestamp + C::Constants::constants().minimal_block_delay as i64, parameters: match &transaction.parameters { Some(params) => Some((params.entrypoint.to_str().into(), params.value.clone())), None => None, diff --git a/tezos_proto/src/validator/mod.rs b/tezos_proto/src/contracts/mod.rs similarity index 74% rename from tezos_proto/src/validator/mod.rs rename to tezos_proto/src/contracts/mod.rs index cd592b8..c7e466a 100644 --- a/tezos_proto/src/validator/mod.rs +++ b/tezos_proto/src/contracts/mod.rs @@ -2,5 +2,4 @@ // // SPDX-License-Identifier: MIT -pub mod batch; -pub mod operation; +pub mod michelson; diff --git a/tezos_proto/src/contracts/system.rs b/tezos_proto/src/contracts/system.rs new file mode 100644 index 0000000..78287d9 --- /dev/null +++ b/tezos_proto/src/contracts/system.rs @@ -0,0 +1,3 @@ +// SPDX-FileCopyrightText: 2023 Baking Bad +// +// SPDX-License-Identifier: MIT diff --git a/tezos_proto/src/error.rs b/tezos_proto/src/error.rs index 3d02338..e79612b 100644 --- a/tezos_proto/src/error.rs +++ b/tezos_proto/src/error.rs @@ -59,6 +59,8 @@ pub enum Error { CounterInThePast { counter: String }, BatchNotFound { hash: String }, OperationNotFound { hash: String }, + InvalidBatchOperation { reason: String }, + InvalidBatchHeader { reason: String }, } pub type Result = std::result::Result; diff --git a/tezos_proto/src/lib.rs b/tezos_proto/src/lib.rs index d121564..3dd55fb 100644 --- a/tezos_proto/src/lib.rs +++ b/tezos_proto/src/lib.rs @@ -2,12 +2,12 @@ // // SPDX-License-Identifier: MIT -pub mod batcher; +pub mod batch; pub mod config; pub mod context; +pub mod contracts; pub mod error; -pub mod executor; -pub mod validator; -pub mod runner; +pub mod operations; +pub mod protocol; pub use error::{Error, Result}; diff --git a/tezos_proto/src/executor/balance_updates.rs b/tezos_proto/src/operations/balance_updates.rs similarity index 100% rename from tezos_proto/src/executor/balance_updates.rs rename to tezos_proto/src/operations/balance_updates.rs diff --git a/tezos_proto/src/executor/operation.rs b/tezos_proto/src/operations/executor.rs similarity index 90% rename from tezos_proto/src/executor/operation.rs rename to tezos_proto/src/operations/executor.rs index a12bcfd..87e4e30 100644 --- a/tezos_proto/src/executor/operation.rs +++ b/tezos_proto/src/operations/executor.rs @@ -8,17 +8,20 @@ use tezos_operation::operations::OperationContent; use tezos_rpc::models::operation::Operation as OperationReceipt; use crate::{ - config::PROTOCOL, context::TezosContext, error::{Error, Result}, - executor::{ - balance_updates::BalanceUpdates, origination::execute_origination, reveal::execute_reveal, - transaction::execute_transaction, + operations::{ + balance_updates::BalanceUpdates, + types::{ + origination::execute_origination, reveal::execute_reveal, + transaction::execute_transaction, + }, + validator::ValidOperation, }, - validator::operation::ValidOperation, + protocol::constants::PROTOCOL, config::Config, }; -pub fn execute_operation( +pub fn execute_operation( context: &mut (impl TezosContext + InterpreterContext), opg: &ValidOperation, ) -> Result { @@ -34,7 +37,7 @@ pub fn execute_operation( let skip = failed_idx.is_some(); let result = match content { OperationContent::Reveal(reveal) => execute_reveal(context, reveal, skip)?, - OperationContent::Origination(origination) => execute_origination( + OperationContent::Origination(origination) => execute_origination::( context, origination, &opg.hash, @@ -42,7 +45,7 @@ pub fn execute_operation( skip, )?, OperationContent::Transaction(transaction) => { - execute_transaction(context, transaction, None, skip)? + execute_transaction::(context, transaction, None, skip)? } _ => return Err(Error::OperationKindUnsupported), }; @@ -87,7 +90,7 @@ mod test { use tezos_rpc::models::operation::{operation_result::OperationResultStatus, OperationContent}; use super::*; - use crate::{context::TezosEphemeralContext, validator::operation::ValidOperation, Result}; + use crate::{context::TezosEphemeralContext, operations::validator::ValidOperation, Result, config::DefaultConfig}; macro_rules! get_status { ($receipt: expr) => { @@ -152,7 +155,7 @@ mod test { total_spent: 0u32.into(), // <-- not true, fot the sake of the test }; - let receipt = execute_operation(&mut context, &opg)?; + let receipt = execute_operation::(&mut context, &opg)?; //println!("{:#?}", receipt); assert_eq!( get_status(&receipt.contents[0]).expect("Backtracked"), diff --git a/tezos_proto/src/executor/lazy_diff.rs b/tezos_proto/src/operations/lazy_diff.rs similarity index 100% rename from tezos_proto/src/executor/lazy_diff.rs rename to tezos_proto/src/operations/lazy_diff.rs diff --git a/tezos_proto/src/executor/mod.rs b/tezos_proto/src/operations/mod.rs similarity index 65% rename from tezos_proto/src/executor/mod.rs rename to tezos_proto/src/operations/mod.rs index 0228ad8..314a8eb 100644 --- a/tezos_proto/src/executor/mod.rs +++ b/tezos_proto/src/operations/mod.rs @@ -3,11 +3,9 @@ // SPDX-License-Identifier: MIT pub mod balance_updates; -pub mod contract; +pub mod executor; pub mod lazy_diff; -pub mod operation; -pub mod origination; pub mod result; -pub mod reveal; pub mod rpc_errors; -pub mod transaction; +pub mod types; +pub mod validator; diff --git a/tezos_proto/src/executor/result.rs b/tezos_proto/src/operations/result.rs similarity index 99% rename from tezos_proto/src/executor/result.rs rename to tezos_proto/src/operations/result.rs index 7023a70..1afe41a 100644 --- a/tezos_proto/src/executor/result.rs +++ b/tezos_proto/src/operations/result.rs @@ -21,7 +21,7 @@ use tezos_rpc::models::operation::{ OperationContent as OperationContentAndResult, }; -use crate::executor::balance_updates::BalanceUpdates; +use crate::operations::balance_updates::BalanceUpdates; #[derive(Debug, Clone, TryInto, From)] pub enum ExecutionResult { diff --git a/tezos_proto/src/executor/rpc_errors.rs b/tezos_proto/src/operations/rpc_errors.rs similarity index 100% rename from tezos_proto/src/executor/rpc_errors.rs rename to tezos_proto/src/operations/rpc_errors.rs diff --git a/tezos_proto/src/operations/types/mod.rs b/tezos_proto/src/operations/types/mod.rs new file mode 100644 index 0000000..e063a2d --- /dev/null +++ b/tezos_proto/src/operations/types/mod.rs @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: 2023 Baking Bad +// +// SPDX-License-Identifier: MIT + +pub mod origination; +pub mod reveal; +pub mod transaction; diff --git a/tezos_proto/src/executor/origination.rs b/tezos_proto/src/operations/types/origination.rs similarity index 90% rename from tezos_proto/src/executor/origination.rs rename to tezos_proto/src/operations/types/origination.rs index c48723c..e53340f 100644 --- a/tezos_proto/src/executor/origination.rs +++ b/tezos_proto/src/operations/types/origination.rs @@ -15,12 +15,12 @@ use tezos_rpc::models::operation::{ use crate::{ context::TezosContext, - executor::balance_updates::BalanceUpdates, - executor::contract::{deploy_contract, ContractOutput}, - executor::lazy_diff::LazyDiff, - executor::result::ExecutionResult, - executor::rpc_errors::RpcErrors, - Error, Result, + contracts::michelson::{deploy_contract, ContractOutput}, + operations::{ + balance_updates::BalanceUpdates, lazy_diff::LazyDiff, result::ExecutionResult, + rpc_errors::RpcErrors, + }, + Error, Result, config::Config, }; pub fn originated_address(opg_hash: &OperationHash, index: i32) -> Result { @@ -30,7 +30,7 @@ pub fn originated_address(opg_hash: &OperationHash, index: i32) -> Result( context: &mut (impl TezosContext + InterpreterContext), origination: &Origination, hash: &OperationHash, @@ -84,7 +84,7 @@ pub fn execute_origination( Err(err) => return Err(err), }; - match deploy_contract(context, origination, self_address.clone(), balance) { + match deploy_contract::(context, origination, self_address.clone(), balance) { Ok(ContractOutput::Return(ret)) => { lazy_diff.update(ret.big_map_diff)?; originated_contracts = Some(vec![self_address]); @@ -109,7 +109,7 @@ mod test { use tezos_operation::operations::Script; use super::*; - use crate::{context::TezosEphemeralContext, Result}; + use crate::{context::TezosEphemeralContext, Result, config::DefaultConfig}; #[test] fn test_origination_applied() -> Result<()> { @@ -133,7 +133,7 @@ mod test { }; let mut index = 1i32; - let result = execute_origination( + let result = execute_origination::( &mut context, &origination, &OperationHash::new("oneDGhZacw99EEFaYDTtWfz5QEhUW3PPVFsHa7GShnLPuDn7gSd".into())?, diff --git a/tezos_proto/src/executor/reveal.rs b/tezos_proto/src/operations/types/reveal.rs similarity index 96% rename from tezos_proto/src/executor/reveal.rs rename to tezos_proto/src/operations/types/reveal.rs index afc7f43..be2c2bd 100644 --- a/tezos_proto/src/executor/reveal.rs +++ b/tezos_proto/src/operations/types/reveal.rs @@ -9,7 +9,8 @@ use tezos_rpc::models::operation::operation_result::{ }; use crate::{ - context::TezosContext, executor::result::ExecutionResult, executor::rpc_errors::RpcErrors, + context::TezosContext, + operations::{result::ExecutionResult, rpc_errors::RpcErrors}, Result, }; diff --git a/tezos_proto/src/executor/transaction.rs b/tezos_proto/src/operations/types/transaction.rs similarity index 89% rename from tezos_proto/src/executor/transaction.rs rename to tezos_proto/src/operations/types/transaction.rs index 0f3e9e2..e1c34f2 100644 --- a/tezos_proto/src/executor/transaction.rs +++ b/tezos_proto/src/operations/types/transaction.rs @@ -13,15 +13,15 @@ use tezos_rpc::models::operation::{ use crate::{ context::TezosContext, - executor::balance_updates::BalanceUpdates, - executor::contract::{execute_contract, expand_content, ContractOutput}, - executor::lazy_diff::LazyDiff, - executor::result::ExecutionResult, - executor::rpc_errors::RpcErrors, - Error, Result, + contracts::michelson::{execute_contract, expand_content, ContractOutput}, + operations::{ + balance_updates::BalanceUpdates, lazy_diff::LazyDiff, result::ExecutionResult, + rpc_errors::RpcErrors, + }, + Error, Result, config::Config, }; -pub fn execute_transaction( +pub fn execute_transaction( context: &mut (impl TezosContext + InterpreterContext), transaction: &Transaction, sender: Option
, @@ -81,7 +81,7 @@ pub fn execute_transaction( } let internal_operations: Vec = - match execute_contract(context, transaction, sender.clone(), balance) { + match execute_contract::(context, transaction, sender.clone(), balance) { Ok(ContractOutput::Return(ret)) => { storage = Some(ret.storage); lazy_diff.update(ret.big_map_diff)?; @@ -97,7 +97,7 @@ pub fn execute_transaction( for operation in internal_operations { match operation { OperationContent::Transaction(tx) => { - match execute_transaction( + match execute_transaction::( context, &tx, Some(transaction.destination.clone()), @@ -127,7 +127,7 @@ mod test { use tezos_operation::operations::Transaction; use super::*; - use crate::{context::TezosEphemeralContext, Result}; + use crate::{context::TezosEphemeralContext, Result, config::DefaultConfig}; #[test] fn test_transaction_applied() -> Result<()> { @@ -149,7 +149,7 @@ mod test { parameters: None, }; - let res = execute_transaction(&mut context, &transaction, None, false); + let res = execute_transaction::(&mut context, &transaction, None, false); assert!(res.is_ok()); assert!(res.unwrap().ok()); diff --git a/tezos_proto/src/validator/operation.rs b/tezos_proto/src/operations/validator.rs similarity index 99% rename from tezos_proto/src/validator/operation.rs rename to tezos_proto/src/operations/validator.rs index 61616e6..c3314cd 100644 --- a/tezos_proto/src/validator/operation.rs +++ b/tezos_proto/src/operations/validator.rs @@ -12,7 +12,7 @@ use tezos_operation::operations::{OperationContent, SignedOperation}; use crate::{ context::TezosContext, - executor::rpc_errors::{RpcError, RpcErrors}, + operations::rpc_errors::{RpcError, RpcErrors}, Error, Result, }; diff --git a/tezos_proto/src/runner/mempool.rs b/tezos_proto/src/protocol/bridge.rs similarity index 100% rename from tezos_proto/src/runner/mempool.rs rename to tezos_proto/src/protocol/bridge.rs diff --git a/tezos_proto/src/protocol/constants.rs b/tezos_proto/src/protocol/constants.rs new file mode 100644 index 0000000..88cb8a4 --- /dev/null +++ b/tezos_proto/src/protocol/constants.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2023 Baking Bad +// +// SPDX-License-Identifier: MIT + +use serde::{Deserialize, Serialize}; +use tezos_core::types::{encoded::ProtocolHash, number::Nat}; + +pub const PROTOCOL: &str = "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK"; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ProtocolConstants { + pub minimal_block_delay: i32, + pub blocks_per_cycle: i32, + pub max_operations_time_to_live: i32, + pub max_block_header_length: i32, + pub max_operation_data_length: i32, + pub max_operations_list_length: i32, + pub hard_gas_limit_per_operation: Nat, + pub hard_storage_limit_per_operation: Nat, + pub hard_gas_limit_per_block: Nat, + pub cost_per_byte: Nat, +} + +pub trait Constants { + fn protocol() -> ProtocolHash; + fn constants() -> ProtocolConstants; +} + +pub struct ProtocolAlpha {} + +impl Constants for ProtocolAlpha { + fn protocol() -> ProtocolHash { + PROTOCOL.try_into().unwrap() + } + + fn constants() -> ProtocolConstants { + ProtocolConstants { + minimal_block_delay: 1, + blocks_per_cycle: 512, + max_operations_time_to_live: 240, + max_block_header_length: 2048, + max_operation_data_length: 86400, + max_operations_list_length: 1024, + hard_gas_limit_per_operation: 1040000u64.into(), + hard_storage_limit_per_operation: 60000u64.into(), + hard_gas_limit_per_block: 5200000u64.into(), + cost_per_byte: 250u32.into(), + } + } +} diff --git a/tezos_proto/src/protocol/fees.rs b/tezos_proto/src/protocol/fees.rs new file mode 100644 index 0000000..e69de29 diff --git a/tezos_proto/src/protocol/mempool.rs b/tezos_proto/src/protocol/mempool.rs new file mode 100644 index 0000000..e69de29 diff --git a/tezos_proto/src/context/migrations.rs b/tezos_proto/src/protocol/migrations.rs similarity index 58% rename from tezos_proto/src/context/migrations.rs rename to tezos_proto/src/protocol/migrations.rs index 87ea14d..427781d 100644 --- a/tezos_proto/src/context/migrations.rs +++ b/tezos_proto/src/protocol/migrations.rs @@ -22,32 +22,37 @@ const SEED_ACCOUNTS: [&str; 8] = [ ]; const SEED_BALANCE: u64 = 40_000_000_000_000u64; -pub fn genesis_migration(context: &mut impl TezosContext) -> Result> { - let mut updates: Vec = Vec::with_capacity(SEED_ACCOUNTS.len()); - let balance = Mutez::try_from(SEED_BALANCE).unwrap(); - - for account in SEED_ACCOUNTS.into_iter() { - context.set_balance(&account, balance)?; - updates.push(BalanceUpdate::Contract(Contract { - kind: Kind::Contract, - change: SEED_BALANCE.to_string(), - contract: account.to_string(), - origin: Some(Origin::Migration), - })); - } - - context.commit()?; - Ok(updates) +pub trait Migrations { + // TODO: migrations can potentially do more than just update balances + fn run(context: &mut impl TezosContext, head: &Head) -> Result>; } -pub fn run_migrations( - context: &mut impl TezosContext, - head: &Head, -) -> Result>> { - context.check_no_pending_changes()?; - match head.level { - -1 => Ok(Some(genesis_migration(context)?)), - _ => Ok(None), +pub struct SandboxSeed {} + +impl Migrations for SandboxSeed { + fn run(context: &mut impl TezosContext, head: &Head) -> Result> { + if head.level != -1 { + return Ok(vec![]); + } + + context.check_no_pending_changes()?; + + let mut updates: Vec = Vec::with_capacity(SEED_ACCOUNTS.len()); + let balance = Mutez::try_from(SEED_BALANCE).unwrap(); + + for account in SEED_ACCOUNTS.into_iter() { + context.set_balance(&account, balance)?; + updates.push(BalanceUpdate::Contract(Contract { + kind: Kind::Contract, + change: SEED_BALANCE.to_string(), + contract: account.to_string(), + origin: Some(Origin::Migration), + })); + } + + context.commit()?; + + Ok(updates) } } @@ -63,7 +68,7 @@ mod test { let head = context.get_head()?; assert_eq!(-1, head.level); - let updates = run_migrations(&mut context, &head)?.expect("Seed balance updates"); + let updates = SandboxSeed::run(&mut context, &head)?; assert_eq!(8, updates.len()); let balance = context diff --git a/tezos_proto/src/protocol/mod.rs b/tezos_proto/src/protocol/mod.rs new file mode 100644 index 0000000..ddd1544 --- /dev/null +++ b/tezos_proto/src/protocol/mod.rs @@ -0,0 +1,49 @@ +pub mod constants; +pub mod migrations; + +use tezos_core::types::encoded::ChainId; +use tezos_operation::operations::SignedOperation; + +use crate::{batch::payload::BatchPayload, config::Config, context::TezosContext, protocol::constants::Constants, Result}; + +pub fn initialize(context: &mut impl TezosContext, chain_id: ChainId) -> Result<()> { + let mut head = context.get_head()?; + + if head.chain_id != chain_id { + head.chain_id = chain_id; + context.set_head(head.clone())?; + context.commit()?; + } + + Ok(()) +} + +pub fn inject_operation(context: &mut impl TezosContext, operation: SignedOperation) -> Result<()> { + // TODO: validate and add operations to mempool + Ok(()) +} + +pub fn inject_batch(context: &mut impl TezosContext, batch: BatchPayload) -> Result<()> { + // remove included mempool operations + // validate and execute batch + Ok(()) +} + +pub fn finalize(context: &mut impl TezosContext, timestamp: i64) -> Result<()> { + let mut head = context.get_head()?; + + let constants = C::Constants::constants(); + if timestamp - head.timestamp > (constants.minimal_block_delay * constants.blocks_per_cycle) as i64 { + head.timestamp = timestamp; + context.set_head(head.clone())?; + context.commit()?; + } + + // Make an implicit batch in case: + // - there are mempool operations that about to expire + // - more than N seconds passed since the latest block + + // remove invalid mempool operations (due to balance/counter changes) + + Ok(()) +} diff --git a/tezos_proto/src/runner/batch.rs b/tezos_proto/src/runner/batch.rs deleted file mode 100644 index ef04daa..0000000 --- a/tezos_proto/src/runner/batch.rs +++ /dev/null @@ -1,46 +0,0 @@ -use std::collections::HashMap; - -use tezos_core::types::encoded::{ImplicitAddress, ChainId, OperationHash}; -use tezos_operation::operations::{SignedOperation}; - -use crate::{context::{batch::BatchHeader, head::Head, TezosContext}, Result}; - -pub struct Batch { - pub header: BatchHeader, - pub source: ImplicitAddress, - pub operations: Vec -} - -pub struct TezosChain { - pub head: Head, - pub mempool: HashMap -} - -impl TezosChain { - pub fn load(context: &mut impl TezosContext, chain_id: ChainId) -> Result { - let mut head = context.get_head()?; - head.chain_id = chain_id; - Ok(Self { head, mempool: HashMap::new() }) - } - - pub fn add_pending_operation(&mut self, hash: OperationHash, operation: SignedOperation) -> Result<()> { - self.mempool.insert(hash, operation); - Ok(()) - } - - pub fn has_pending_operation(&self, hash: &OperationHash) -> bool { - self.mempool.contains_key(hash) - } - - pub fn remove_pending_operation(&mut self, hash: &OperationHash) -> Result { - self.mempool.remove(hash).ok_or(Error::) - } - - pub fn apply_batch(&mut self, context: &mut impl TezosContext, batch: Batch) -> Result<()> { - Ok(()) - } - - pub fn aggregate_batch(&mut self) -> Result { - todo!() - } -} \ No newline at end of file diff --git a/tezos_proto/src/runner/mod.rs b/tezos_proto/src/runner/mod.rs deleted file mode 100644 index 72145e1..0000000 --- a/tezos_proto/src/runner/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod batch; -pub mod mempool; \ No newline at end of file diff --git a/tezos_proto/src/validator/batch.rs b/tezos_proto/src/validator/batch.rs deleted file mode 100644 index 9e73e9e..0000000 --- a/tezos_proto/src/validator/batch.rs +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Baking Bad -// -// SPDX-License-Identifier: MIT - -use tezos_core::types::encoded::{Encoded, OperationHash}; -use tezos_operation::operations::SignedOperation; - -use crate::{ - context::TezosContext, - validator::operation::{validate_operation, ValidOperation, ValidatedOperation}, - Result, -}; - -pub fn validate_batch( - context: &mut impl TezosContext, - batch_payload: Vec<(OperationHash, SignedOperation)>, - atomic: bool, -) -> Result> { - context.check_no_pending_changes()?; - - let mut operations: Vec = Vec::with_capacity(batch_payload.len()); - - for (hash, opg) in batch_payload.into_iter() { - match validate_operation(context, opg, hash.clone(), false) { - Ok(ValidatedOperation::Valid(op)) => { - let balance = context.get_balance(&op.source.value())?.unwrap(); - context.set_balance(&op.source.value(), balance - op.total_spent)?; - context.set_counter(&op.source.value(), op.last_counter.clone())?; - operations.push(op); - } - Ok(ValidatedOperation::Invalid(op)) => { - context.log(format!("Invalid operation: {:#?}", op)); - if atomic { - context.rollback(); - return Ok(vec![]); - } - } - Err(err) => { - context.log(format!( - "Validator error: {}\n{}", - hash.value(), - err.format() - )); - if atomic { - context.rollback(); - return Err(err); - } - } - } - } - - context.rollback(); - - Ok(operations) -} diff --git a/tezos_proto/tests/runner/client.rs b/tezos_proto/tests/runner/client.rs index f81d646..803f1e8 100644 --- a/tezos_proto/tests/runner/client.rs +++ b/tezos_proto/tests/runner/client.rs @@ -21,7 +21,8 @@ use tezos_rpc::models::operation::Operation; use tezos_proto::{ batcher::apply_batch, - context::{head::Head, migrations::run_migrations, TezosContext}, + context::{head::Head, TezosContext}, + protocol::migrations::{Migrations, Seed}, }; pub struct Wallet { @@ -91,7 +92,7 @@ impl Client { pub fn migrate(&mut self) -> &mut Self { let head = self.context.get_head().expect("Failed to get head"); - run_migrations(&mut self.context, &head).expect("Failed to run context migrations"); + Seed::run(&mut self.context, &head).expect("Failed to run context migrations"); self } diff --git a/tezos_proto/tests/runner/mock.rs b/tezos_proto/tests/runner/mock.rs index 4e6db82..d3bd267 100644 --- a/tezos_proto/tests/runner/mock.rs +++ b/tezos_proto/tests/runner/mock.rs @@ -9,7 +9,9 @@ use std::path::PathBuf; use tezos_core::types::encoded::Encoded; use tezos_michelson::micheline::Micheline; -use tezos_proto::{context::TezosEphemeralContext, executor::origination::originated_address}; +use tezos_proto::{ + context::TezosEphemeralContext, operations::types::origination::originated_address, +}; use crate::runner::client::Client; From b85d577a56db5ba4418daafec732a4495f60bda9 Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Wed, 16 Aug 2023 00:06:35 +0300 Subject: [PATCH 3/4] wip protocol trait --- Cargo.lock | 417 ++++++++---------- layered_store/Cargo.toml | 6 +- layered_store/src/types/tezos.rs | 11 + michelson_vm/src/instructions/stack.rs | 6 +- sapling_proto/src/codec.rs | 4 +- tezos_kernel/Cargo.toml | 1 + tezos_kernel/src/error.rs | 3 + tezos_kernel/src/kernel.rs | 128 +++--- tezos_kernel/src/lib.rs | 1 - tezos_kernel/src/payload.rs | 40 -- tezos_node/src/rollup/mock_client.rs | 4 +- tezos_node/src/rollup/rpc_helpers.rs | 4 +- tezos_node/tests/quickstart.rs | 2 +- tezos_proto/src/batch/executor.rs | 10 +- tezos_proto/src/batch/receipt.rs | 4 +- tezos_proto/src/batch/validator.rs | 32 +- tezos_proto/src/config.rs | 18 - tezos_proto/src/context/mod.rs | 16 + tezos_proto/src/contracts/michelson.rs | 12 +- tezos_proto/src/lib.rs | 1 - tezos_proto/src/operations/executor.rs | 12 +- .../src/operations/types/origination.rs | 10 +- .../src/operations/types/transaction.rs | 12 +- tezos_proto/src/protocol/constants.rs | 4 +- .../src/protocol/{mempool.rs => contracts.rs} | 0 tezos_proto/src/protocol/mod.rs | 47 +- 26 files changed, 388 insertions(+), 417 deletions(-) delete mode 100644 tezos_kernel/src/payload.rs delete mode 100644 tezos_proto/src/config.rs rename tezos_proto/src/protocol/{mempool.rs => contracts.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index 20c8de5..dca9aae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,12 +60,12 @@ dependencies = [ [[package]] name = "actix-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] @@ -104,7 +104,7 @@ dependencies = [ "futures-util", "mio", "num_cpus", - "socket2", + "socket2 0.4.9", "tokio", "tracing", ] @@ -166,7 +166,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2", + "socket2 0.4.9", "time", "url", ] @@ -244,9 +244,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" dependencies = [ "memchr", ] @@ -322,9 +322,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" dependencies = [ "anstyle", "windows-sys", @@ -332,9 +332,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "8c6f84b74db2535ebae81eede2f39b947dcbf01d093ae5f791e5dd414a1bf289" [[package]] name = "arrayref" @@ -350,13 +350,13 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "async-trait" -version = "0.1.71" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", ] [[package]] @@ -406,9 +406,9 @@ checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" [[package]] name = "basic-toml" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f838d03a705d72b12389b8930bd14cacf493be1380bfb15720d4d12db5ab03ac" +checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" dependencies = [ "serde", ] @@ -463,9 +463,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bitvec" @@ -543,14 +543,13 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a30d0edd9dd1c60ddb42b80341c7852f6f985279a5c1a83659dcb65899dec99" +checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" dependencies = [ "cc", "glob", "threadpool", - "which", "zeroize", ] @@ -632,11 +631,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -701,9 +701,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.11" +version = "4.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d" +checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd" dependencies = [ "clap_builder", "clap_derive", @@ -712,9 +712,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.11" +version = "4.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b" +checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa" dependencies = [ "anstream", "anstyle", @@ -724,14 +724,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.2" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", ] [[package]] @@ -862,9 +862,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.3" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7" +checksum = "f711ade317dd348950a9910f81c5947e3d8907ebd2b83f76203ff1807e6a2bc2" dependencies = [ "cfg-if", "cpufeatures", @@ -884,7 +884,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", ] [[package]] @@ -893,6 +893,12 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" +[[package]] +name = "deranged" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" + [[package]] name = "derive_more" version = "0.99.17" @@ -970,9 +976,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963" +checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" dependencies = [ "signature 2.1.0", ] @@ -993,20 +999,20 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.0.0-rc.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa8e9049d5d72bfc12acbc05914731b5322f79b5e2f195e9f2d705fca22ab4c" +checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ - "curve25519-dalek 4.0.0-rc.3", - "ed25519 2.2.1", + "curve25519-dalek 4.0.0", + "ed25519 2.2.2", "sha2 0.10.7", ] [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "elliptic-curve" @@ -1057,9 +1063,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", @@ -1087,12 +1093,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "ff" @@ -1132,9 +1135,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", "miniz_oxide", @@ -1469,9 +1472,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" @@ -1496,7 +1499,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -1598,17 +1601,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys", -] - [[package]] name = "ipnet" version = "2.8.0" @@ -1622,7 +1614,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.4", + "rustix", "windows-sys", ] @@ -1637,9 +1629,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" @@ -1708,6 +1700,7 @@ dependencies = [ "serde-json-wasm", "tezos-core", "tezos-michelson", + "tezos-operation", "tezos-rpc", ] @@ -1779,15 +1772,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "local-channel" @@ -1819,9 +1806,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "maybe-rayon" @@ -1857,7 +1844,7 @@ dependencies = [ "michelson_vm", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", "tezos-core", "tezos-michelson", "trybuild", @@ -2051,9 +2038,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] @@ -2091,9 +2078,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -2112,7 +2099,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", ] [[package]] @@ -2123,9 +2110,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" dependencies = [ "cc", "libc", @@ -2282,9 +2269,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pbkdf2" @@ -2304,9 +2291,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" [[package]] name = "pin-utils" @@ -2375,18 +2362,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.29" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -2470,9 +2457,9 @@ dependencies = [ [[package]] name = "reddsa" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b34d2c0df43159d2ff79d3cf929c9f11415529127344edb8160ad2be499fcd" +checksum = "78a5191930e84973293aa5f532b513404460cd2216c1cfb76d08748c15b40b02" dependencies = [ "blake2b_simd", "byteorder", @@ -2519,9 +2506,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" dependencies = [ "aho-corasick", "memchr", @@ -2531,9 +2518,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.2" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" dependencies = [ "aho-corasick", "memchr", @@ -2621,28 +2608,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys", -] - -[[package]] -name = "rustix" -version = "0.38.4" +version = "0.38.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys 0.4.3", + "linux-raw-sys", "windows-sys", ] @@ -2660,9 +2633,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "sapling_kernel" @@ -2711,9 +2684,9 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" @@ -2727,9 +2700,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -2740,9 +2713,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -2750,43 +2723,43 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.171" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" dependencies = [ "serde_derive", ] [[package]] name = "serde-json-wasm" -version = "0.5.1" -source = "git+https://github.com/CosmWasm/serde-json-wasm?branch=main#3a0b4a7bb93e051011f35aed971b914a998a2ac8" +version = "1.0.0" +source = "git+https://github.com/CosmWasm/serde-json-wasm?branch=main#05c08e6750ae7826b17b90bc0c7f52635cd4770a" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.171" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", ] [[package]] name = "serde_json" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", @@ -2890,6 +2863,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "spin" version = "0.5.2" @@ -2973,9 +2956,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.25" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -2990,15 +2973,14 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.6.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" dependencies = [ - "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.23", + "rustix", "windows-sys", ] @@ -3020,7 +3002,7 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "tezos-contract" version = "0.1.3" -source = "git+https://github.com/baking-bad/tezos-rust-sdk?branch=develop#ecb380b8887e94b01837da905f962aeb12dd904d" +source = "git+https://github.com/baking-bad/tezos-rust-sdk?branch=develop#2048dc8c59029f3f8d9c629cf4dca36282c11685" dependencies = [ "async-trait", "derive_more", @@ -3033,7 +3015,7 @@ dependencies = [ [[package]] name = "tezos-core" version = "0.1.3" -source = "git+https://github.com/baking-bad/tezos-rust-sdk?branch=develop#ecb380b8887e94b01837da905f962aeb12dd904d" +source = "git+https://github.com/baking-bad/tezos-rust-sdk?branch=develop#2048dc8c59029f3f8d9c629cf4dca36282c11685" dependencies = [ "blake2", "bs58 0.4.0", @@ -3052,7 +3034,7 @@ dependencies = [ [[package]] name = "tezos-michelson" version = "0.1.3" -source = "git+https://github.com/baking-bad/tezos-rust-sdk?branch=develop#ecb380b8887e94b01837da905f962aeb12dd904d" +source = "git+https://github.com/baking-bad/tezos-rust-sdk?branch=develop#2048dc8c59029f3f8d9c629cf4dca36282c11685" dependencies = [ "chrono", "derive_more", @@ -3068,7 +3050,7 @@ dependencies = [ [[package]] name = "tezos-operation" version = "0.1.3" -source = "git+https://github.com/baking-bad/tezos-rust-sdk?branch=develop#ecb380b8887e94b01837da905f962aeb12dd904d" +source = "git+https://github.com/baking-bad/tezos-rust-sdk?branch=develop#2048dc8c59029f3f8d9c629cf4dca36282c11685" dependencies = [ "chrono", "derive_more", @@ -3082,7 +3064,7 @@ dependencies = [ [[package]] name = "tezos-rpc" version = "0.1.3" -source = "git+https://github.com/baking-bad/tezos-rust-sdk?branch=develop#ecb380b8887e94b01837da905f962aeb12dd904d" +source = "git+https://github.com/baking-bad/tezos-rust-sdk?branch=develop#2048dc8c59029f3f8d9c629cf4dca36282c11685" dependencies = [ "async-trait", "chrono", @@ -3096,9 +3078,9 @@ dependencies = [ [[package]] name = "tezos-smart-rollup" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f497c89d8a143f20004142f9a0fa9232598ceaf438581b82a029cbc709decf9" +checksum = "fbc0d1ca723e4be76ae7f292068cc835e3cb2b74c0ec6e02c34f0474f7b65d4f" dependencies = [ "tezos-smart-rollup-core", "tezos-smart-rollup-debug", @@ -3113,15 +3095,15 @@ dependencies = [ [[package]] name = "tezos-smart-rollup-core" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b2d125ad921cde4c586427bdfd25350568e652f0b1b5050745fecb3f4f2a91" +checksum = "6982a67c936c315d8327c9d4bb0a29f53faa7fe24f02d5fb9d8d93f98553cbb1" [[package]] name = "tezos-smart-rollup-debug" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0108861f0710f4b10917917cfdc92fa320e991790fde5dd0a1851954bb01cec0" +checksum = "e84d8e72a764c57ed1fc8dccc7090cd76b1da187e19b588f3da3515bef0314b2" dependencies = [ "tezos-smart-rollup-core", "tezos-smart-rollup-host", @@ -3129,9 +3111,9 @@ dependencies = [ [[package]] name = "tezos-smart-rollup-encoding" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a23e2fc8261bb77a0bd0dec5350b0688dc4e45f6a2ad5227f24b8d17dd589cf" +checksum = "cae9ceec0ecf07b635420874723ddc4c578a29d2cd3bb50e7f14171f2f0906a2" dependencies = [ "hex", "nom", @@ -3148,9 +3130,9 @@ dependencies = [ [[package]] name = "tezos-smart-rollup-entrypoint" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07168b649bb867967cec5f14e942292af98b237b45c897a9aa57a86ff4c1d210" +checksum = "30022841b361845e0f7b9eabfdd065cf628b21f22214de3229675017fe25439a" dependencies = [ "dlmalloc", "tezos-smart-rollup-core", @@ -3161,9 +3143,9 @@ dependencies = [ [[package]] name = "tezos-smart-rollup-host" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ef490a027929034fda6e56d185d89ef70149c5818d5fa7a03f348d6ba985a1" +checksum = "8b7f04c22d0b0015563b53a0e67581a162cd358a55ba6d7c7da447ad0a6c2da5" dependencies = [ "tezos-smart-rollup-core", "tezos_crypto_rs", @@ -3173,9 +3155,9 @@ dependencies = [ [[package]] name = "tezos-smart-rollup-mock" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e09f8b60f4b8b3a126ad8f4e8b54c4045637a535fd2848e0d6c173736bb568c2" +checksum = "7c0a78d331bf3b80970c7e2b81472283f197aab77912e079e759c2e672d451cc" dependencies = [ "hex", "tezos-smart-rollup-core", @@ -3187,18 +3169,18 @@ dependencies = [ [[package]] name = "tezos-smart-rollup-panic-hook" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b878d9d2b185f01656efb5a313aa99abb334025adc146b09f21390fa523c1b30" +checksum = "7ed704d934d0295cc4f38b867c03641b4adcc218df007a9c237dad989e5eb4aa" dependencies = [ "tezos-smart-rollup-core", ] [[package]] name = "tezos-smart-rollup-storage" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1da8c5742aaad5aa439d25db85045f350b130b2309c8b3de762a221aba13af1" +checksum = "eeb101aa1167477304ed6cdecd3b357af627fdc8ba757caa0d64e4f182b9a1d7" dependencies = [ "tezos-smart-rollup-core", "tezos-smart-rollup-debug", @@ -3218,7 +3200,7 @@ dependencies = [ "blst", "byteorder", "cryptoxide", - "ed25519-dalek 2.0.0-rc.3", + "ed25519-dalek 2.0.0", "hex", "libsecp256k1", "num-bigint 0.3.3", @@ -3272,6 +3254,7 @@ dependencies = [ "derive_more", "hex", "kernel_io", + "layered_store", "tezos-core", "tezos-operation", "tezos-rpc", @@ -3333,22 +3316,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.43" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +checksum = "d9207952ae1a003f42d3d5e892dac3c6ba42aa6ac0c79a6a91a2b5cb4253e75c" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.43" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +checksum = "f1728216d3244de4f14f14f8c15c79be1a7c67867d28d69b719690e2a19fb445" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", ] [[package]] @@ -3362,10 +3345,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.23" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" +checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" dependencies = [ + "deranged", "itoa", "serde", "time-core", @@ -3380,9 +3364,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" dependencies = [ "time-core", ] @@ -3404,11 +3388,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", @@ -3417,7 +3400,7 @@ dependencies = [ "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.3", "tokio-macros", "windows-sys", ] @@ -3430,7 +3413,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", ] [[package]] @@ -3493,7 +3476,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", ] [[package]] @@ -3513,9 +3496,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "trybuild" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04366e99ff743345622cd00af2af01d711dc2d1ef59250d7347698d21b546729" +checksum = "a84e0202ea606ba5ebee8507ab2bfbe89b98551ed9b8f0be198109275cff284b" dependencies = [ "basic-toml", "glob", @@ -3552,9 +3535,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -3658,7 +3641,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -3692,7 +3675,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3732,17 +3715,6 @@ dependencies = [ "webpki", ] -[[package]] -name = "which" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" -dependencies = [ - "either", - "libc", - "once_cell", -] - [[package]] name = "winapi" version = "0.3.9" @@ -3794,9 +3766,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -3809,45 +3781,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9" [[package]] name = "winreg" @@ -3869,12 +3841,9 @@ dependencies = [ [[package]] name = "xdg" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688597db5a750e9cad4511cb94729a078e274308099a0382b5b8203bbc767fee" -dependencies = [ - "home", -] +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" [[package]] name = "zcash_address" @@ -3993,23 +3962,23 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.28", ] [[package]] name = "zstd" -version = "0.12.3+zstd.1.5.2" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "6.0.5+zstd.1.5.4" +version = "6.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" dependencies = [ "libc", "zstd-sys", diff --git a/layered_store/Cargo.toml b/layered_store/Cargo.toml index 419141c..9633905 100644 --- a/layered_store/Cargo.toml +++ b/layered_store/Cargo.toml @@ -15,9 +15,11 @@ derive_more = "0.99" tezos_core = { git = "https://github.com/baking-bad/tezos-rust-sdk", optional = true, branch = "develop", package = "tezos-core", default-features = false, features = ["ed25519"] } tezos_michelson = { git = "https://github.com/baking-bad/tezos-rust-sdk", optional = true, branch = "develop", package = "tezos-michelson", default-features = false } tezos_rpc = { git = "https://github.com/baking-bad/tezos-rust-sdk", optional = true, branch = "develop", package = "tezos-rpc", default-features = false } +tezos_operation = { git = "https://github.com/baking-bad/tezos-rust-sdk", optional = true, branch = "develop", package = "tezos-operation", default-features = false } + serde-json-wasm = { git = "https://github.com/CosmWasm/serde-json-wasm", optional = true, branch = "main" } [features] -default = [] +default = ["tezos"] testing = ["tezos"] -tezos = ["dep:tezos_core", "dep:tezos_michelson", "dep:tezos_rpc", "dep:serde-json-wasm"] \ No newline at end of file +tezos = ["dep:tezos_core", "dep:tezos_michelson", "dep:tezos_rpc", "dep:tezos_operation", "dep:serde-json-wasm"] \ No newline at end of file diff --git a/layered_store/src/types/tezos.rs b/layered_store/src/types/tezos.rs index edf0fa9..922b881 100644 --- a/layered_store/src/types/tezos.rs +++ b/layered_store/src/types/tezos.rs @@ -8,6 +8,7 @@ use tezos_core::types::{ number::Nat, }; use tezos_michelson::micheline::Micheline; +use tezos_operation::operations::SignedOperation; use tezos_rpc::models::operation::Operation; use crate::{error::err_into, internal_error, Result, StoreType}; @@ -47,3 +48,13 @@ impl StoreType for Operation { serde_json_wasm::ser::to_vec(&self).map_err(err_into) } } + +impl StoreType for SignedOperation { + fn from_bytes(bytes: &[u8]) -> Result { + SignedOperation::from_bytes(bytes).map_err(err_into) + } + + fn to_bytes(&self) -> Result> { + SignedOperation::to_bytes(&self).map_err(err_into) + } +} \ No newline at end of file diff --git a/michelson_vm/src/instructions/stack.rs b/michelson_vm/src/instructions/stack.rs index 51bb766..eac0955 100644 --- a/michelson_vm/src/instructions/stack.rs +++ b/michelson_vm/src/instructions/stack.rs @@ -2,8 +2,6 @@ // // SPDX-License-Identifier: MIT -use std::borrow::Borrow; - use tezos_michelson::michelson::data::instructions::{Dig, Drop, Dug, Dup, Push, Swap}; use crate::{ @@ -56,7 +54,7 @@ impl PureInterpreter for Swap { impl PureInterpreter for Dig { fn execute(&self, stack: &mut Stack) -> Result<()> { - let item = stack.pop_at(self.n.borrow().try_into()?)?; + let item = stack.pop_at(self.n.clone().try_into()?)?; stack.push(item) } } @@ -64,6 +62,6 @@ impl PureInterpreter for Dig { impl PureInterpreter for Dug { fn execute(&self, stack: &mut Stack) -> Result<()> { let item = stack.pop()?; - stack.push_at(self.n.borrow().try_into()?, item) + stack.push_at(self.n.clone().try_into()?, item) } } diff --git a/sapling_proto/src/codec.rs b/sapling_proto/src/codec.rs index b062544..a50fdcd 100644 --- a/sapling_proto/src/codec.rs +++ b/sapling_proto/src/codec.rs @@ -216,7 +216,7 @@ impl TryInto> for &Ciphertext { #[cfg(test)] mod test { - use std::{borrow::Borrow, io}; + use std::io; use crate::{storage::Ciphertext, types::SaplingTransaction}; @@ -238,7 +238,7 @@ mod test { .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.to_string()))?; let ciphertext = Ciphertext::try_from(payload.as_slice())?; - let res: Vec = ciphertext.borrow().try_into()?; + let res: Vec = (&ciphertext).try_into()?; assert_eq!(payload, res); Ok(()) diff --git a/tezos_kernel/Cargo.toml b/tezos_kernel/Cargo.toml index 4ea0ffe..d888610 100644 --- a/tezos_kernel/Cargo.toml +++ b/tezos_kernel/Cargo.toml @@ -14,6 +14,7 @@ crate-type = ["cdylib", "rlib"] derive_more = "0.99" kernel_io = { path = "../kernel_io" } tezos_proto = { path = "../tezos_proto" } +layered_store = { path = "../layered_store", features = ["tezos"], default-features = false } tezos_core = { git = "https://github.com/baking-bad/tezos-rust-sdk", branch = "develop", package = "tezos-core", default-features = false } tezos_operation = { git = "https://github.com/baking-bad/tezos-rust-sdk", branch = "develop", package = "tezos-operation", default-features = false } tezos-smart-rollup-host = { version = "0.2.0", features = ["proto-nairobi"], default-features = false } diff --git a/tezos_kernel/src/error.rs b/tezos_kernel/src/error.rs index 3959c99..ec49354 100644 --- a/tezos_kernel/src/error.rs +++ b/tezos_kernel/src/error.rs @@ -81,6 +81,9 @@ impl_from_error!(tezos_operation::Error); impl_from_error!(tezos_core::Error); impl_from_error!(tezos_smart_rollup_host::runtime::RuntimeError); impl_from_error!(tezos_smart_rollup_host::path::PathError); +impl_from_error!(kernel_io::Error); +impl_from_error!(layered_store::Error); + impl From for Error { fn from(error: tezos_proto::Error) -> Self { diff --git a/tezos_kernel/src/kernel.rs b/tezos_kernel/src/kernel.rs index 98cb786..e50dab4 100644 --- a/tezos_kernel/src/kernel.rs +++ b/tezos_kernel/src/kernel.rs @@ -6,76 +6,94 @@ use kernel_io::{ inbox::{read_inbox, InboxMessage}, KernelStore, KernelStoreAsHost, }; -use tezos_core::types::encoded::{ChainId, Encoded, OperationHash}; +use tezos_core::types::encoded::{ChainId, Encoded}; +use tezos_proto::{config::{DefaultConfig, Config}, protocol}; use tezos_operation::operations::SignedOperation; -use tezos_proto::{batcher::apply_batch, context::TezosContext}; use tezos_smart_rollup_core::SmartRollupCore; use tezos_smart_rollup_host::runtime::Runtime; -use crate::{payload::TezosPayload, Error, Result}; +use crate::{payload::TezosPayload, Result}; + +pub enum TezosPayload { + Operation(SignedOperation), + Batch(BatchPayload), +} + +impl PayloadType for TezosPayload { + fn from_external_message(message: &[u8]) -> kernel_io::Result { + let opg = SignedOperation::from_bytes(message).map_err(err_into)?; + Ok(TezosPayload::Operation(opg)) + } +} + +pub fn kernel_dispatch(context: &mut KernelStore, prefix: &[u8]) -> Result<(bool, bool)> { + match read_inbox(context.as_host(), prefix) { + Ok(InboxMessage::BeginBlock(_)) => { + let chain_id = ChainId::from_bytes(&prefix[..4]) + .expect("Failed to decode chain ID"); + let init = protocol::initialize::(context, chain_id)?; + Ok((init, init)) + }, + Ok(InboxMessage::LevelInfo(info)) => { + context.set("/time".into(), Some(info.predecessor_timestamp))?; + context.commit()?; + Ok((true, false)) + } + Ok(InboxMessage::Payload(TezosPayload::Operation(operation))) => { + protocol::inject_operation::(context, operation)?; + context.as_host().mark_for_reboot()?; + Ok((true, true)) + } + Ok(InboxMessage::Payload(TezosPayload::Batch(batch))) => { + protocol::inject_batch::(context, batch)?; + context.as_host().mark_for_reboot()?; + Ok((true, true)) + } + Ok(InboxMessage::EndBlock(_)) => { + let timestamp: i64 = context.get("/time".into())?.unwrap_or(0i64); + protocol::finalize::(context, timestamp)?; + Ok((true, true)) + } + Ok(InboxMessage::NoMoreData) => Ok((false, true)), + Ok(InboxMessage::Foreign(id)) => { + context.log(format!("Foreign message #{}", id)); + Ok((false, false)) + }, + Ok(InboxMessage::Unknown(id)) => { + context.log(format!("Unknown message #{}", id)); + Ok((false, false)) + }, + Err(err) => Err(err.into()) + } +} pub fn kernel_run(host: &mut Host) { let mut context = KernelStore::attach(host); + context.log(format!("Kernel boots")); + context.clear(); let metadata = Runtime::reveal_metadata(context.as_host()); - let mut head = context.get_head().expect("Failed to get head"); - head.chain_id = - ChainId::from_bytes(&metadata.raw_rollup_address[..4]).expect("Failed to decode chain ID"); - - context.log(format!("Kernel invoked, prev head: {}", head)); - - let mut batch_payload: Vec<(OperationHash, SignedOperation)> = Vec::new(); - let res: Result<()> = loop { - match read_inbox(context.as_host(), &metadata.raw_rollup_address[..4]) { - Ok(InboxMessage::BeginBlock(inbox_level)) => { - // Origination level is the one before kernel is first time invoked - // We assume single rollup block per inbox block here - // Note that head level is the one prior to the current block - let expected = inbox_level - metadata.origination_level as i32 - 2; - if head.level != expected { - break Err(Error::InconsistentHeadLevel { - expected, - found: head.level, - }); + loop { + match kernel_dispatch::(&mut context, &metadata.raw_rollup_address) { + Ok((save, exit)) => { + if save { + context + .as_mut() + .persist() + .expect("Failed to persist changes"); } - } - Ok(InboxMessage::LevelInfo(info)) => { - head.timestamp = info.predecessor_timestamp; - } - Ok(InboxMessage::Payload(TezosPayload::Operation { hash, opg })) => { - context.log(format!("Operation pending: {}", &hash.value())); - batch_payload.push((hash, opg)); - } - Ok(InboxMessage::EndBlock(_)) => { - match apply_batch(&mut context, head.clone(), batch_payload, false) { - Ok(new_head) => { - head = new_head; - context.log(format!("Batch applied: {}", head)); - break Ok(()); - } - Err(err) => break Err(err.into()), + if exit { + break; } + }, + Err(err) => { + context.clear(); + context.log(err.format()); } - Ok(InboxMessage::NoMoreData) => break Ok(()), - Ok(InboxMessage::Foreign(id)) => context.log(format!("Foreign message #{}", id)), - Ok(InboxMessage::Unknown(id)) => context.log(format!("Unknown message #{}", id)), - Err(err) => context.log(err.to_string()), } }; - match res { - Ok(_) => { - context - .as_mut() - .persist() - .expect("Failed to persist changes"); - context.log(format!("Kernel yields")); - } - Err(err) => { - context.log(err.format()); - context.clear(); - } - } + context.log(format!("Kernel yields")); } #[cfg(test)] diff --git a/tezos_kernel/src/lib.rs b/tezos_kernel/src/lib.rs index 71a84be..1324bca 100644 --- a/tezos_kernel/src/lib.rs +++ b/tezos_kernel/src/lib.rs @@ -4,7 +4,6 @@ pub mod error; pub mod kernel; -pub mod payload; pub use error::{Error, Result}; diff --git a/tezos_kernel/src/payload.rs b/tezos_kernel/src/payload.rs deleted file mode 100644 index 40ff25c..0000000 --- a/tezos_kernel/src/payload.rs +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Baking Bad -// -// SPDX-License-Identifier: MIT - -use kernel_io::{error::err_into, inbox::PayloadType}; -use tezos_core::types::encoded::{Encoded, OperationHash, Signature}; -use tezos_operation::operations::{SignedOperation, UnsignedOperation}; - -use crate::error::{Error, Result}; - -const SIGNATURE_SIZE: usize = 64; - -pub fn parse_l2_operation<'a>(bytes: &'a [u8]) -> Result<(OperationHash, SignedOperation)> { - if bytes.len() <= SIGNATURE_SIZE { - return Err(Error::UnexpectedL2OperationLength { - length: bytes.len(), - }); - } - - let unsigned_op = UnsignedOperation::from_forged_bytes(&bytes[..bytes.len() - SIGNATURE_SIZE])?; - let signature = Signature::from_bytes(&bytes[bytes.len() - SIGNATURE_SIZE..])?; - let hash = SignedOperation::operation_hash(bytes)?; - let opg = SignedOperation::from(unsigned_op, signature); - - Ok((hash, opg)) -} - -pub enum TezosPayload { - Operation { - hash: OperationHash, - opg: SignedOperation, - }, -} - -impl PayloadType for TezosPayload { - fn from_external_message(message: &[u8]) -> kernel_io::Result { - let (hash, opg) = parse_l2_operation(message).map_err(err_into)?; - Ok(TezosPayload::Operation { hash, opg }) - } -} diff --git a/tezos_node/src/rollup/mock_client.rs b/tezos_node/src/rollup/mock_client.rs index e33b4a8..dad21b4 100644 --- a/tezos_node/src/rollup/mock_client.rs +++ b/tezos_node/src/rollup/mock_client.rs @@ -12,8 +12,8 @@ use tezos_operation::operations::SignedOperation; use tezos_proto::{ batcher::apply_batch, context::{head::Head, migrations::run_migrations, TezosContext, TezosEphemeralContext}, - executor::operation::execute_operation, - validator::operation::{validate_operation, ValidatedOperation}, + operations::operation::execute_operation, + validator::validator::{validate_operation, ValidatedOperation}, }; use tezos_rpc::models::operation::Operation; use tezos_rpc::models::version::{ diff --git a/tezos_node/src/rollup/rpc_helpers.rs b/tezos_node/src/rollup/rpc_helpers.rs index 52257cd..d70dab1 100644 --- a/tezos_node/src/rollup/rpc_helpers.rs +++ b/tezos_node/src/rollup/rpc_helpers.rs @@ -8,8 +8,8 @@ use layered_store::LayeredStore; use tezos_core::types::encoded::{Encoded, OperationHash, Signature}; use tezos_operation::operations::{SignedOperation, UnsignedOperation}; use tezos_proto::{ - executor::operation::execute_operation, - validator::operation::{validate_operation, ValidatedOperation}, + operations::operation::execute_operation, + validator::validator::{validate_operation, ValidatedOperation}, }; use tezos_rpc::models::operation::Operation; diff --git a/tezos_node/tests/quickstart.rs b/tezos_node/tests/quickstart.rs index a0280a4..344c66d 100644 --- a/tezos_node/tests/quickstart.rs +++ b/tezos_node/tests/quickstart.rs @@ -14,7 +14,7 @@ use tezos_michelson::michelson::data; use tezos_operation::operations::{ OperationContent, Origination, Reveal, Script, Transaction, UnsignedOperation, }; -use tezos_proto::executor::origination::originated_address; +use tezos_proto::operations::origination::originated_address; use tezos_rpc::{client::TezosRpc, http::default::HttpClient, Result}; use tokio::time::sleep; diff --git a/tezos_proto/src/batch/executor.rs b/tezos_proto/src/batch/executor.rs index 0af2d6f..a6ba1cd 100644 --- a/tezos_proto/src/batch/executor.rs +++ b/tezos_proto/src/batch/executor.rs @@ -8,14 +8,14 @@ use tezos_rpc::models::operation::Operation as OperationReceipt; use crate::{ batch::{header::BatchHeader, receipt::BatchReceipt}, - config::Config, + protocol::Protocol, context::{head::Head, TezosContext}, operations::{executor::execute_operation, validator::ValidOperation}, protocol::{constants::Constants, migrations::Migrations}, Result, }; -pub fn execute_batch( +pub fn execute_batch( context: &mut (impl TezosContext + InterpreterContext), operations: Vec, header: Option, @@ -23,14 +23,14 @@ pub fn execute_batch( context.check_no_pending_changes()?; let head = context.get_head()?; - let balance_updates = C::Migrations::run(context, &head)?; + let balance_updates = Proto::Migrations::run(context, &head)?; // TODO: implicit deployments C::System // TODO: implicit ticket updates C::Bridge let mut operation_receipts: Vec = Vec::with_capacity(operations.len()); let mut operation_hashes: Vec = Vec::with_capacity(operations.len()); for opg in operations.iter() { - operation_receipts.push(execute_operation::(context, opg)?); + operation_receipts.push(execute_operation::(context, opg)?); operation_hashes.push(opg.hash.clone()); } @@ -47,7 +47,7 @@ pub fn execute_batch( let hash = header.block_hash()?; let receipt = BatchReceipt { chain_id: head.chain_id.clone(), - protocol: C::Constants::protocol(), + protocol: Proto::Constants::protocol(), hash: hash.clone(), header: header.clone(), balance_updates: Some(balance_updates), diff --git a/tezos_proto/src/batch/receipt.rs b/tezos_proto/src/batch/receipt.rs index 7d3e9f3..a82005d 100644 --- a/tezos_proto/src/batch/receipt.rs +++ b/tezos_proto/src/batch/receipt.rs @@ -15,7 +15,7 @@ use chrono::NaiveDateTime; use serde::{Deserialize, Serialize}; use crate::batch::header::{BatchHeader, POW_NONCE}; -use crate::protocol::constants::{Constants, ProtocolAlpha}; +use crate::protocol::constants::{Constants, ConstantsAlpha}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct BatchReceipt { @@ -49,7 +49,7 @@ impl From for Metadata { fn from(receipt: BatchReceipt) -> Self { // TODO: this code is only used in sequencer, need to move it there // Constants should be retrieved separately and then merged with batch receipts - let constants = ProtocolAlpha::constants(); + let constants = ConstantsAlpha::constants(); Self { baker: receipt.batcher.clone(), proposer: receipt.batcher, diff --git a/tezos_proto/src/batch/validator.rs b/tezos_proto/src/batch/validator.rs index f9898c0..eeab8b9 100644 --- a/tezos_proto/src/batch/validator.rs +++ b/tezos_proto/src/batch/validator.rs @@ -8,7 +8,7 @@ use tezos_operation::operations::SignedOperation; use crate::{ context::TezosContext, operations::validator::{validate_operation, ValidOperation, ValidatedOperation}, - Error, Result, + Result, Error }; use super::payload::BatchPayload; @@ -17,13 +17,8 @@ macro_rules! assert_attr_eq { ($expected: expr, $actual: expr) => { if $actual != $expected { return Err(Error::InvalidBatchHeader { - reason: format!( - "{}: expected {:?}, got {:?}", - stringify!($actual), - $expected, - $actual - ), - }); + reason: format!("{}: expected {:?}, got {:?}", stringify!($actual), $expected, $actual) + }) } }; } @@ -31,7 +26,7 @@ macro_rules! assert_attr_eq { pub fn validate_explicit_batch( context: &mut impl TezosContext, batch: BatchPayload, - dry_run: bool, + dry_run: bool ) -> Result> { context.check_no_pending_changes()?; @@ -46,14 +41,11 @@ pub fn validate_explicit_batch( "batch.header.timestamp: expected at least {}, got {}", prev_head.timestamp + 1, batch.header.timestamp - ), - }); + ) + }) } - assert_attr_eq!( - batch.operation_list_list_hash()?, - batch.header.operations_hash - ); + assert_attr_eq!(batch.operation_list_list_hash()?, batch.header.operations_hash); if !dry_run { // TODO: check signature against whitelisted sequencer account @@ -70,15 +62,9 @@ pub fn validate_explicit_batch( valid_operations.push(op); } Ok(ValidatedOperation::Invalid(errors)) => { - context.log(format!( - "Invalid batch operation {}\n{:#?}", - hash.value(), - errors - )); + context.log(format!("Invalid batch operation {}\n{:#?}", hash.value(), errors)); context.rollback(); - return Err(Error::InvalidBatchOperation { - reason: format!("{:#?}", errors), - }); + return Err(Error::InvalidBatchOperation { reason: format!("{:#?}", errors) }); } Err(err) => { context.log(format!( diff --git a/tezos_proto/src/config.rs b/tezos_proto/src/config.rs deleted file mode 100644 index 0392aa3..0000000 --- a/tezos_proto/src/config.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::protocol::{constants::{Constants, ProtocolAlpha}, migrations::{Migrations, SandboxSeed}}; - -pub trait Config { - type Constants: Constants; - type Migrations: Migrations; - // type Fees: Fees; - // type Bridge: Bridge; - // type Mempool: Mempool; - // type Producer: Producer; - // type Contracts: Contracts; -} - -pub struct DefaultConfig {} - -impl Config for DefaultConfig { - type Constants = ProtocolAlpha; - type Migrations = SandboxSeed; -} diff --git a/tezos_proto/src/context/mod.rs b/tezos_proto/src/context/mod.rs index f7b4805..c6ea9ec 100644 --- a/tezos_proto/src/context/mod.rs +++ b/tezos_proto/src/context/mod.rs @@ -11,6 +11,7 @@ use tezos_core::types::{ number::Nat, }; use tezos_michelson::micheline::Micheline; +use tezos_operation::operations::SignedOperation; use tezos_rpc::models::operation::Operation; use crate::{batch::receipt::BatchReceipt, context::head::Head, error::err_into, Error, Result}; @@ -35,6 +36,9 @@ pub trait TezosContext { fn get_batch_receipt(&mut self, hash: &str) -> Result; fn set_operation_receipt(&mut self, receipt: Operation) -> Result<()>; fn get_operation_receipt(&mut self, hash: &str) -> Result; + fn set_pending_operation(&mut self, level: i32, operation: SignedOperation) -> Result<()>; + fn del_pending_operation(&mut self, hash: &str) -> Result<()>; + fn agg_pending_operations(&mut self, level: i32) -> Result>; fn check_no_pending_changes(&self) -> Result<()>; fn commit(&mut self) -> Result<()>; fn rollback(&mut self); @@ -156,6 +160,18 @@ impl TezosContext for LayeredStore { .map_err(err_into) } + fn add_pending_operation(&mut self, level: i32, operation: SignedOperation) -> Result<()> { + let hash = operation.hash()?; + self.set( + format!( + "/mempool/{}", + receipt.hash.as_ref().expect("Operation hash").value() + ), + Some(receipt), + ) + .map_err(err_into) + } + fn check_no_pending_changes(&self) -> Result<()> { if self.has_pending_changes() { Err(layered_store::Error::ContextUnstagedError.into()) diff --git a/tezos_proto/src/contracts/michelson.rs b/tezos_proto/src/contracts/michelson.rs index fc6a4b6..2038c57 100644 --- a/tezos_proto/src/contracts/michelson.rs +++ b/tezos_proto/src/contracts/michelson.rs @@ -16,7 +16,7 @@ use tezos_operation::operations::{ Entrypoint, OperationContent, Origination, Parameters, Transaction, }; -use crate::{context::TezosContext, protocol::constants::Constants, Error, Result, config::Config}; +use crate::{context::TezosContext, protocol::constants::Constants, Error, Result, protocol::Protocol}; #[derive(Debug, From)] pub enum ContractOutput { @@ -24,7 +24,7 @@ pub enum ContractOutput { Return(ScriptReturn), } -pub fn deploy_contract( +pub fn deploy_contract( context: &mut (impl TezosContext + InterpreterContext), origination: &Origination, self_address: ContractAddress, @@ -32,13 +32,14 @@ pub fn deploy_contract( ) -> Result { let head = context.get_head()?; let script = MichelsonScript::try_from(origination.script.code.clone())?; + let minimal_block_delay = Proto::Constants::constants().minimal_block_delay as i64; let scope = OperationScope { amount: 0u32.into(), balance, chain_id: head.chain_id, level: head.level + 1, - now: head.timestamp + C::Constants::constants().minimal_block_delay as i64, + now: head.timestamp + minimal_block_delay, parameters: None, self_address, self_type: script.get_type(), @@ -57,7 +58,7 @@ pub fn deploy_contract( } } -pub fn execute_contract( +pub fn execute_contract( context: &mut (impl TezosContext + InterpreterContext), transaction: &Transaction, sender: Option
, @@ -78,13 +79,14 @@ pub fn execute_contract( let head = context.get_head()?; let script = MichelsonScript::try_from(code)?; + let minimal_block_delay = Proto::Constants::constants().minimal_block_delay as i64; let scope = OperationScope { amount: transaction.amount.clone(), balance, chain_id: head.chain_id, level: head.level + 1, - now: head.timestamp + C::Constants::constants().minimal_block_delay as i64, + now: head.timestamp + minimal_block_delay, parameters: match &transaction.parameters { Some(params) => Some((params.entrypoint.to_str().into(), params.value.clone())), None => None, diff --git a/tezos_proto/src/lib.rs b/tezos_proto/src/lib.rs index 3dd55fb..02a56c4 100644 --- a/tezos_proto/src/lib.rs +++ b/tezos_proto/src/lib.rs @@ -3,7 +3,6 @@ // SPDX-License-Identifier: MIT pub mod batch; -pub mod config; pub mod context; pub mod contracts; pub mod error; diff --git a/tezos_proto/src/operations/executor.rs b/tezos_proto/src/operations/executor.rs index 87e4e30..94d851c 100644 --- a/tezos_proto/src/operations/executor.rs +++ b/tezos_proto/src/operations/executor.rs @@ -18,10 +18,10 @@ use crate::{ }, validator::ValidOperation, }, - protocol::constants::PROTOCOL, config::Config, + protocol::constants::PROTOCOL, protocol::Protocol, }; -pub fn execute_operation( +pub fn execute_operation( context: &mut (impl TezosContext + InterpreterContext), opg: &ValidOperation, ) -> Result { @@ -37,7 +37,7 @@ pub fn execute_operation( let skip = failed_idx.is_some(); let result = match content { OperationContent::Reveal(reveal) => execute_reveal(context, reveal, skip)?, - OperationContent::Origination(origination) => execute_origination::( + OperationContent::Origination(origination) => execute_origination::( context, origination, &opg.hash, @@ -45,7 +45,7 @@ pub fn execute_operation( skip, )?, OperationContent::Transaction(transaction) => { - execute_transaction::(context, transaction, None, skip)? + execute_transaction::(context, transaction, None, skip)? } _ => return Err(Error::OperationKindUnsupported), }; @@ -90,7 +90,7 @@ mod test { use tezos_rpc::models::operation::{operation_result::OperationResultStatus, OperationContent}; use super::*; - use crate::{context::TezosEphemeralContext, operations::validator::ValidOperation, Result, config::DefaultConfig}; + use crate::{context::TezosEphemeralContext, operations::validator::ValidOperation, Result, protocol::ProtocolAlpha}; macro_rules! get_status { ($receipt: expr) => { @@ -155,7 +155,7 @@ mod test { total_spent: 0u32.into(), // <-- not true, fot the sake of the test }; - let receipt = execute_operation::(&mut context, &opg)?; + let receipt = execute_operation::(&mut context, &opg)?; //println!("{:#?}", receipt); assert_eq!( get_status(&receipt.contents[0]).expect("Backtracked"), diff --git a/tezos_proto/src/operations/types/origination.rs b/tezos_proto/src/operations/types/origination.rs index e53340f..a8b5430 100644 --- a/tezos_proto/src/operations/types/origination.rs +++ b/tezos_proto/src/operations/types/origination.rs @@ -20,7 +20,7 @@ use crate::{ balance_updates::BalanceUpdates, lazy_diff::LazyDiff, result::ExecutionResult, rpc_errors::RpcErrors, }, - Error, Result, config::Config, + Error, Result, protocol::Protocol, }; pub fn originated_address(opg_hash: &OperationHash, index: i32) -> Result { @@ -30,7 +30,7 @@ pub fn originated_address(opg_hash: &OperationHash, index: i32) -> Result( +pub fn execute_origination( context: &mut (impl TezosContext + InterpreterContext), origination: &Origination, hash: &OperationHash, @@ -84,7 +84,7 @@ pub fn execute_origination( Err(err) => return Err(err), }; - match deploy_contract::(context, origination, self_address.clone(), balance) { + match deploy_contract::(context, origination, self_address.clone(), balance) { Ok(ContractOutput::Return(ret)) => { lazy_diff.update(ret.big_map_diff)?; originated_contracts = Some(vec![self_address]); @@ -109,7 +109,7 @@ mod test { use tezos_operation::operations::Script; use super::*; - use crate::{context::TezosEphemeralContext, Result, config::DefaultConfig}; + use crate::{context::TezosEphemeralContext, Result, protocol::ProtocolAlpha}; #[test] fn test_origination_applied() -> Result<()> { @@ -133,7 +133,7 @@ mod test { }; let mut index = 1i32; - let result = execute_origination::( + let result = execute_origination::( &mut context, &origination, &OperationHash::new("oneDGhZacw99EEFaYDTtWfz5QEhUW3PPVFsHa7GShnLPuDn7gSd".into())?, diff --git a/tezos_proto/src/operations/types/transaction.rs b/tezos_proto/src/operations/types/transaction.rs index e1c34f2..6f50735 100644 --- a/tezos_proto/src/operations/types/transaction.rs +++ b/tezos_proto/src/operations/types/transaction.rs @@ -18,10 +18,10 @@ use crate::{ balance_updates::BalanceUpdates, lazy_diff::LazyDiff, result::ExecutionResult, rpc_errors::RpcErrors, }, - Error, Result, config::Config, + Error, Result, protocol::Protocol, }; -pub fn execute_transaction( +pub fn execute_transaction( context: &mut (impl TezosContext + InterpreterContext), transaction: &Transaction, sender: Option
, @@ -81,7 +81,7 @@ pub fn execute_transaction( } let internal_operations: Vec = - match execute_contract::(context, transaction, sender.clone(), balance) { + match execute_contract::(context, transaction, sender.clone(), balance) { Ok(ContractOutput::Return(ret)) => { storage = Some(ret.storage); lazy_diff.update(ret.big_map_diff)?; @@ -97,7 +97,7 @@ pub fn execute_transaction( for operation in internal_operations { match operation { OperationContent::Transaction(tx) => { - match execute_transaction::( + match execute_transaction::( context, &tx, Some(transaction.destination.clone()), @@ -127,7 +127,7 @@ mod test { use tezos_operation::operations::Transaction; use super::*; - use crate::{context::TezosEphemeralContext, Result, config::DefaultConfig}; + use crate::{context::TezosEphemeralContext, Result, protocol::ProtocolAlpha}; #[test] fn test_transaction_applied() -> Result<()> { @@ -149,7 +149,7 @@ mod test { parameters: None, }; - let res = execute_transaction::(&mut context, &transaction, None, false); + let res = execute_transaction::(&mut context, &transaction, None, false); assert!(res.is_ok()); assert!(res.unwrap().ok()); diff --git a/tezos_proto/src/protocol/constants.rs b/tezos_proto/src/protocol/constants.rs index 88cb8a4..01c8ce4 100644 --- a/tezos_proto/src/protocol/constants.rs +++ b/tezos_proto/src/protocol/constants.rs @@ -26,9 +26,9 @@ pub trait Constants { fn constants() -> ProtocolConstants; } -pub struct ProtocolAlpha {} +pub struct ConstantsAlpha {} -impl Constants for ProtocolAlpha { +impl Constants for ConstantsAlpha { fn protocol() -> ProtocolHash { PROTOCOL.try_into().unwrap() } diff --git a/tezos_proto/src/protocol/mempool.rs b/tezos_proto/src/protocol/contracts.rs similarity index 100% rename from tezos_proto/src/protocol/mempool.rs rename to tezos_proto/src/protocol/contracts.rs diff --git a/tezos_proto/src/protocol/mod.rs b/tezos_proto/src/protocol/mod.rs index ddd1544..5055ad7 100644 --- a/tezos_proto/src/protocol/mod.rs +++ b/tezos_proto/src/protocol/mod.rs @@ -1,13 +1,38 @@ pub mod constants; pub mod migrations; -use tezos_core::types::encoded::ChainId; +use tezos_core::types::encoded::{ChainId, OperationHash, BlockHash}; use tezos_operation::operations::SignedOperation; -use crate::{batch::payload::BatchPayload, config::Config, context::TezosContext, protocol::constants::Constants, Result}; +use crate::{ + protocol::{ + constants::{Constants, ConstantsAlpha}, + migrations::{Migrations, SandboxSeed} + }, + batch::payload::BatchPayload, + context::TezosContext, + Result +}; -pub fn initialize(context: &mut impl TezosContext, chain_id: ChainId) -> Result<()> { +pub trait Protocol { + type Constants: Constants; + type Migrations: Migrations; + // type Fees: Fees; + // type Bridge: Bridge; + // type Contracts: Contracts; +} + +pub struct ProtocolAlpha {} + +impl Protocol for ProtocolAlpha { + type Constants = ConstantsAlpha; + type Migrations = SandboxSeed; +} + + +pub fn initialize(context: &mut impl TezosContext, chain_id: ChainId) -> Result { let mut head = context.get_head()?; + context.log(format!("Protocol initialized: {}", head)); if head.chain_id != chain_id { head.chain_id = chain_id; @@ -15,24 +40,24 @@ pub fn initialize(context: &mut impl TezosContext, chain_id: ChainId) context.commit()?; } - Ok(()) + Ok(false) } -pub fn inject_operation(context: &mut impl TezosContext, operation: SignedOperation) -> Result<()> { +pub fn inject_operation(context: &mut impl TezosContext, operation: SignedOperation) -> Result { // TODO: validate and add operations to mempool - Ok(()) + todo!() } -pub fn inject_batch(context: &mut impl TezosContext, batch: BatchPayload) -> Result<()> { - // remove included mempool operations +pub fn inject_batch(context: &mut impl TezosContext, batch: BatchPayload) -> Result { // validate and execute batch - Ok(()) + // remove included mempool operations + todo!() } -pub fn finalize(context: &mut impl TezosContext, timestamp: i64) -> Result<()> { +pub fn finalize(context: &mut impl TezosContext, timestamp: i64) -> Result<()> { let mut head = context.get_head()?; - let constants = C::Constants::constants(); + let constants = Proto::Constants::constants(); if timestamp - head.timestamp > (constants.minimal_block_delay * constants.blocks_per_cycle) as i64 { head.timestamp = timestamp; context.set_head(head.clone())?; From 7ebeb872697782869202f06d84c16dfc7859e1db Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Tue, 26 Sep 2023 17:24:20 +0300 Subject: [PATCH 4/4] wip changes --- build/operator/Dockerfile.local | 1 + layered_store/Cargo.toml | 1 - layered_store/src/error.rs | 1 + tezos_kernel/src/kernel.rs | 16 +-- tezos_kernel/src/lib.rs | 2 + tezos_kernel/src/mempool.rs | 69 +++++++++++++ tezos_kernel/src/shell.rs | 127 ++++++++++++++++++++++++ tezos_proto/src/batch/payload.rs | 1 + tezos_proto/src/context/mod.rs | 42 ++++++-- tezos_proto/src/operations/executor.rs | 4 +- tezos_proto/src/operations/validator.rs | 3 + tezos_proto/src/protocol/constants.rs | 4 +- tezos_proto/src/protocol/mod.rs | 58 +---------- 13 files changed, 251 insertions(+), 78 deletions(-) create mode 100644 tezos_kernel/src/mempool.rs create mode 100644 tezos_kernel/src/shell.rs diff --git a/build/operator/Dockerfile.local b/build/operator/Dockerfile.local index bb5db34..a77d176 100644 --- a/build/operator/Dockerfile.local +++ b/build/operator/Dockerfile.local @@ -9,6 +9,7 @@ FROM alpine:3.15 AS rollup RUN apk --no-cache add binutils gcc gmp libgmpxx hidapi libc-dev libev libffi sudo ARG OCTEZ_PROTO COPY --from=octez /usr/local/bin/octez-smart-rollup-node-${OCTEZ_PROTO} /usr/bin/octez-smart-rollup-node +COPY --from=octez /usr/local/bin/octez-smart-rollup-client-${OCTEZ_PROTO} /usr/bin/octez-smart-rollup-client COPY --from=octez /usr/local/bin/octez-client /usr/bin/octez-client COPY ./bin/wasm_2_0_0/ /root/wasm_2_0_0/ ARG PACKAGE diff --git a/layered_store/Cargo.toml b/layered_store/Cargo.toml index 9633905..ee53117 100644 --- a/layered_store/Cargo.toml +++ b/layered_store/Cargo.toml @@ -16,7 +16,6 @@ tezos_core = { git = "https://github.com/baking-bad/tezos-rust-sdk", optional = tezos_michelson = { git = "https://github.com/baking-bad/tezos-rust-sdk", optional = true, branch = "develop", package = "tezos-michelson", default-features = false } tezos_rpc = { git = "https://github.com/baking-bad/tezos-rust-sdk", optional = true, branch = "develop", package = "tezos-rpc", default-features = false } tezos_operation = { git = "https://github.com/baking-bad/tezos-rust-sdk", optional = true, branch = "develop", package = "tezos-operation", default-features = false } - serde-json-wasm = { git = "https://github.com/CosmWasm/serde-json-wasm", optional = true, branch = "main" } [features] diff --git a/layered_store/src/error.rs b/layered_store/src/error.rs index 997d111..266ba31 100644 --- a/layered_store/src/error.rs +++ b/layered_store/src/error.rs @@ -47,6 +47,7 @@ pub enum Error { Internal(InternalError), ContextUnstagedError, DowncastingError, + InvalidBytes, } pub type Result = std::result::Result; diff --git a/tezos_kernel/src/kernel.rs b/tezos_kernel/src/kernel.rs index e50dab4..f89fe09 100644 --- a/tezos_kernel/src/kernel.rs +++ b/tezos_kernel/src/kernel.rs @@ -3,16 +3,16 @@ // SPDX-License-Identifier: MIT use kernel_io::{ - inbox::{read_inbox, InboxMessage}, + inbox::{read_inbox, InboxMessage, PayloadType}, KernelStore, KernelStoreAsHost, }; use tezos_core::types::encoded::{ChainId, Encoded}; -use tezos_proto::{config::{DefaultConfig, Config}, protocol}; +use tezos_proto::{batch::payload::BatchPayload, protocol::{self, Protocol}}; use tezos_operation::operations::SignedOperation; use tezos_smart_rollup_core::SmartRollupCore; use tezos_smart_rollup_host::runtime::Runtime; -use crate::{payload::TezosPayload, Result}; +use crate::Result; pub enum TezosPayload { Operation(SignedOperation), @@ -26,12 +26,12 @@ impl PayloadType for TezosPayload { } } -pub fn kernel_dispatch(context: &mut KernelStore, prefix: &[u8]) -> Result<(bool, bool)> { +pub fn kernel_dispatch(context: &mut KernelStore, prefix: &[u8]) -> Result<(bool, bool)> { match read_inbox(context.as_host(), prefix) { Ok(InboxMessage::BeginBlock(_)) => { let chain_id = ChainId::from_bytes(&prefix[..4]) .expect("Failed to decode chain ID"); - let init = protocol::initialize::(context, chain_id)?; + let init = protocol::initialize::(context, chain_id)?; Ok((init, init)) }, Ok(InboxMessage::LevelInfo(info)) => { @@ -40,18 +40,18 @@ pub fn kernel_dispatch(context: &mut KernelS Ok((true, false)) } Ok(InboxMessage::Payload(TezosPayload::Operation(operation))) => { - protocol::inject_operation::(context, operation)?; + protocol::inject_operation::(context, operation)?; context.as_host().mark_for_reboot()?; Ok((true, true)) } Ok(InboxMessage::Payload(TezosPayload::Batch(batch))) => { - protocol::inject_batch::(context, batch)?; + protocol::inject_batch::(context, batch)?; context.as_host().mark_for_reboot()?; Ok((true, true)) } Ok(InboxMessage::EndBlock(_)) => { let timestamp: i64 = context.get("/time".into())?.unwrap_or(0i64); - protocol::finalize::(context, timestamp)?; + protocol::finalize::(context, timestamp)?; Ok((true, true)) } Ok(InboxMessage::NoMoreData) => Ok((false, true)), diff --git a/tezos_kernel/src/lib.rs b/tezos_kernel/src/lib.rs index 1324bca..aaece05 100644 --- a/tezos_kernel/src/lib.rs +++ b/tezos_kernel/src/lib.rs @@ -4,6 +4,8 @@ pub mod error; pub mod kernel; +pub mod shell; +pub mod context; pub use error::{Error, Result}; diff --git a/tezos_kernel/src/mempool.rs b/tezos_kernel/src/mempool.rs new file mode 100644 index 0000000..55f1be5 --- /dev/null +++ b/tezos_kernel/src/mempool.rs @@ -0,0 +1,69 @@ +use std::mem::size_of; + +use layered_store::StoreType; +use tezos_core::types::encoded::OperationHash; +use tezos_operation::operations::SignedOperation; + +use crate::Result; + +#[derive(Debug, Clone, Default)] +pub struct MempoolState(Vec); + +impl StoreType for MempoolState { + fn to_bytes(&self) -> layered_store::Result> { + Ok(self.0.clone()) + } + + fn from_bytes(bytes: &[u8]) -> layered_store::Result { + Ok(Self(bytes.to_vec())) + } +} + +impl MempoolState { + const HASH_SIZE: usize = 32; + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn len(&self) -> usize { + self.0.len() / Self::HASH_SIZE + } + + fn find(&self, term: &[u8]) -> Option { + let mut ptr = 0; + while ptr + Self::HASH_SIZE <= self.0.len() { + if &self.0[ptr..ptr+Self::HASH_SIZE] == term { + return Some(ptr); + } + ptr += Self::HASH_SIZE; + } + None + } + + pub fn add(&mut self, hash: &OperationHash) -> Result { + let mut term = StoreType::to_bytes(hash)?; + if self.find(term.as_slice()).is_none() { + self.0.append(&mut term); + return Ok(true); + } + Ok(false) + } + + pub fn remove(&mut self, hash: &OperationHash) -> Result { + let term = StoreType::to_bytes(hash)?; + if let Some(ptr) = self.find(term.as_slice()) { + self.0.drain(ptr..ptr+Self::HASH_SIZE); + return Ok(true); + } + Ok(false) + } + + pub fn to_vec(&self) -> Result> { + let res = self.0 + .chunks_exact(Self::HASH_SIZE) + .map(|chunk| StoreType::from_bytes(chunk)) + .collect::>>(); + Ok(res?) + } +} diff --git a/tezos_kernel/src/shell.rs b/tezos_kernel/src/shell.rs new file mode 100644 index 0000000..f71b8c9 --- /dev/null +++ b/tezos_kernel/src/shell.rs @@ -0,0 +1,127 @@ +use tezos_core::types::encoded::{ChainId, Encoded, OperationHash}; +use tezos_operation::operations::SignedOperation; +use michelson_vm::InterpreterContext; + +use tezos_proto::{ + protocol::{ + constants::{Constants, ConstantsAlpha}, + migrations::{Migrations, SandboxSeed} + }, + batch::{payload::BatchPayload, validator::{validate_implicit_batch, validate_explicit_batch}, executor::execute_batch}, + context::{TezosContext, mempool::MempoolOperation}, + operations::validator::{validate_operation, ValidatedOperation} +}; + +pub trait Protocol { + type Constants: Constants; + type Migrations: Migrations; + // type Fees: Fees; + // type Bridge: Bridge; + // type Contracts: Contracts; +} + +pub struct ProtocolAlpha {} + +impl Protocol for ProtocolAlpha { + type Constants = ConstantsAlpha; + type Migrations = SandboxSeed; +} + +pub fn initialize(context: &mut impl TezosContext, chain_id: ChainId) -> Result { + let mut head = context.get_head()?; + if head.chain_id != chain_id { + head.chain_id = chain_id; + context.set_head(head.clone())?; + context.commit()?; + context.log(format!("Protocol initialized: {}", head)); + return Ok(true); + } + Ok(false) +} + +pub fn sync_clock(context: &mut impl TezosContext, timestamp: i64) -> Result<()> { + +} + +pub fn inject_operation(context: &mut impl TezosContext, operation: SignedOperation) -> Result<()> { + let hash = operation.hash()?; + match validate_operation(context, operation, hash.clone(), false)? { + ValidatedOperation::Valid(opg) => { + let head = context.get_head()?; + let mut mempool_state = context.get_mempool_state(head.level)?; + if mempool_state.add(&opg.hash)? { + let mempool_operation = MempoolOperation::new(head.level, opg.origin); + context.set_mempool_operation(opg.hash.value(), Some(mempool_operation))?; + context.set_mempool_state(head.level, Some(mempool_state))?; + context.log(format!("Operation added to the mempool ({})", opg.hash.value())); + } else { + context.log(format!("Operation already exists in the mempool ({})", opg.hash.value())); + } + }, + ValidatedOperation::Invalid(errors) => { + let description = errors + .into_iter() + .map(|e| format!("\t{}", e)) + .collect::>() + .join("\n"); + context.log(format!("Operation is invalid ({}):\n{}", hash.value(), description)); + }, + } + Ok(()) +} + +pub fn inject_batch(context: &mut (impl TezosContext + InterpreterContext), batch: BatchPayload) -> Result<()> { + // validate and execute batch + + let valid_operations = validate_explicit_batch(context, batch.clone(), false)?; + execute_batch::(context, valid_operations, Some(batch.header))?; + + for hash in batch.operations.keys() { + context.set_mempool_operation(hash.value(), None)?; + } + Ok(()) +} + +pub fn finalize(context: &mut (impl TezosContext + InterpreterContext), timestamp: i64) -> Result<()> { + let constants = Proto::Constants::constants(); + let mut head = context.get_head()?; + + let block_delay = constants.minimal_block_delay * constants.blocks_per_cycle; + let expire_level = head.level - block_delay; + let is_idle = timestamp - head.timestamp > constants.idle_time; + + if head.timestamp < timestamp { + head.timestamp = timestamp; + context.set_head(head.clone())?; + context.commit()?; + } + + let mempool_state = context.get_mempool_state(expire_level)?; + context.set_mempool_state(expire_level, None)?; + + if !mempool_state.is_empty() { + let mut pending_operations: Vec<(OperationHash, SignedOperation)> = Vec::with_capacity(mempool_state.len()); + for hash in mempool_state.to_vec()? { + match context.get_mempool_operation(hash.value())? { + Some(opg) => { + context.set_mempool_operation(hash.value(), None)?; + pending_operations.push((hash, opg.operation)); + }, + None => { + context.log(format!("Operation already included ({})", hash.value())); + } + } + } + + let valid_operations = validate_implicit_batch(context, pending_operations, false)?; + if !valid_operations.is_empty() { + return execute_batch::(context, valid_operations, None) + } + } + + if is_idle { + return execute_batch::(context, vec![], None) + } + + Ok(()) +} diff --git a/tezos_proto/src/batch/payload.rs b/tezos_proto/src/batch/payload.rs index fbee7cc..6ea5c39 100644 --- a/tezos_proto/src/batch/payload.rs +++ b/tezos_proto/src/batch/payload.rs @@ -11,6 +11,7 @@ use crate::Result; use super::header::BatchHeader; +#[derive(Clone, Debug)] pub struct BatchPayload { pub header: BatchHeader, pub operations: BTreeMap, diff --git a/tezos_proto/src/context/mod.rs b/tezos_proto/src/context/mod.rs index c6ea9ec..58300ca 100644 --- a/tezos_proto/src/context/mod.rs +++ b/tezos_proto/src/context/mod.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: MIT pub mod head; +pub mod mempool; use layered_store::{LayeredStore, StoreBackend}; use tezos_core::types::{ @@ -11,11 +12,12 @@ use tezos_core::types::{ number::Nat, }; use tezos_michelson::micheline::Micheline; -use tezos_operation::operations::SignedOperation; use tezos_rpc::models::operation::Operation; use crate::{batch::receipt::BatchReceipt, context::head::Head, error::err_into, Error, Result}; +use self::mempool::{MempoolOperation, MempoolState}; + pub type TezosEphemeralContext = layered_store::EphemeralStore; pub trait TezosContext { @@ -36,9 +38,10 @@ pub trait TezosContext { fn get_batch_receipt(&mut self, hash: &str) -> Result; fn set_operation_receipt(&mut self, receipt: Operation) -> Result<()>; fn get_operation_receipt(&mut self, hash: &str) -> Result; - fn set_pending_operation(&mut self, level: i32, operation: SignedOperation) -> Result<()>; - fn del_pending_operation(&mut self, hash: &str) -> Result<()>; - fn agg_pending_operations(&mut self, level: i32) -> Result>; + fn set_mempool_operation(&mut self, hash: &str, operation: Option) -> Result<()>; + fn get_mempool_operation(&mut self, hash: &str) -> Result>; + fn set_mempool_state(&mut self, level: i32, state: Option) -> Result<()>; + fn get_mempool_state(&mut self, level: i32) -> Result; fn check_no_pending_changes(&self) -> Result<()>; fn commit(&mut self) -> Result<()>; fn rollback(&mut self); @@ -160,18 +163,35 @@ impl TezosContext for LayeredStore { .map_err(err_into) } - fn add_pending_operation(&mut self, level: i32, operation: SignedOperation) -> Result<()> { - let hash = operation.hash()?; + fn set_mempool_operation(&mut self, hash: &str, operation: Option) -> Result<()> { self.set( - format!( - "/mempool/{}", - receipt.hash.as_ref().expect("Operation hash").value() - ), - Some(receipt), + format!("/mempool/index/{}", hash), + operation, + ) + .map_err(err_into) + } + + fn get_mempool_operation(&mut self, hash: &str) -> Result> { + self.get(format!("/mempool/index/{}", hash)) + .map_err(err_into) + } + + fn set_mempool_state(&mut self, level: i32, state: Option) -> Result<()> { + self.set( + format!("/mempool/state/{}", level), + state, ) .map_err(err_into) } + fn get_mempool_state(&mut self, level: i32) -> Result { + match self.get(format!("/mempool/state/{}", level)) { + Ok(Some(state)) => Ok(state), + Ok(None) => Ok(MempoolState::default()), + Err(err) => Err(err_into(err)) + } + } + fn check_no_pending_changes(&self) -> Result<()> { if self.has_pending_changes() { Err(layered_store::Error::ContextUnstagedError.into()) diff --git a/tezos_proto/src/operations/executor.rs b/tezos_proto/src/operations/executor.rs index 94d851c..a37c6a1 100644 --- a/tezos_proto/src/operations/executor.rs +++ b/tezos_proto/src/operations/executor.rs @@ -18,7 +18,7 @@ use crate::{ }, validator::ValidOperation, }, - protocol::constants::PROTOCOL, protocol::Protocol, + protocol::constants::Constants, protocol::Protocol, }; pub fn execute_operation( @@ -74,7 +74,7 @@ pub fn execute_operation( let head = context.get_head()?; Ok(OperationReceipt { - protocol: Some(PROTOCOL.try_into()?), + protocol: Some(Proto::Constants::protocol()), chain_id: Some(head.chain_id), hash: Some(opg.hash.to_owned()), branch: opg.origin.branch.clone(), diff --git a/tezos_proto/src/operations/validator.rs b/tezos_proto/src/operations/validator.rs index c3314cd..fbb989b 100644 --- a/tezos_proto/src/operations/validator.rs +++ b/tezos_proto/src/operations/validator.rs @@ -140,6 +140,9 @@ pub fn validate_operation( OperationContent::Origination(origination) => &origination.counter, _ => return Err(Error::OperationKindUnsupported), }; + // TODO: enforce incremental counter + // Because otherwise sequencer might choose not to include some of the operations from the mempool + // And it will be a valid behavior still if *next_counter <= counter { errors.counter_in_the_past(source.value(), &(counter + 1u32.into()), next_counter); return Ok(ValidatedOperation::Invalid(errors.unwrap())); diff --git a/tezos_proto/src/protocol/constants.rs b/tezos_proto/src/protocol/constants.rs index 01c8ce4..f69b8e9 100644 --- a/tezos_proto/src/protocol/constants.rs +++ b/tezos_proto/src/protocol/constants.rs @@ -5,10 +5,11 @@ use serde::{Deserialize, Serialize}; use tezos_core::types::{encoded::ProtocolHash, number::Nat}; -pub const PROTOCOL: &str = "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK"; +const PROTOCOL: &str = "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK"; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ProtocolConstants { + pub idle_time: i64, pub minimal_block_delay: i32, pub blocks_per_cycle: i32, pub max_operations_time_to_live: i32, @@ -35,6 +36,7 @@ impl Constants for ConstantsAlpha { fn constants() -> ProtocolConstants { ProtocolConstants { + idle_time: 1, minimal_block_delay: 1, blocks_per_cycle: 512, max_operations_time_to_live: 240, diff --git a/tezos_proto/src/protocol/mod.rs b/tezos_proto/src/protocol/mod.rs index 5055ad7..83c341d 100644 --- a/tezos_proto/src/protocol/mod.rs +++ b/tezos_proto/src/protocol/mod.rs @@ -1,17 +1,9 @@ pub mod constants; pub mod migrations; -use tezos_core::types::encoded::{ChainId, OperationHash, BlockHash}; -use tezos_operation::operations::SignedOperation; - -use crate::{ - protocol::{ - constants::{Constants, ConstantsAlpha}, - migrations::{Migrations, SandboxSeed} - }, - batch::payload::BatchPayload, - context::TezosContext, - Result +use crate::protocol::{ + constants::{Constants, ConstantsAlpha}, + migrations::{Migrations, SandboxSeed} }; pub trait Protocol { @@ -28,47 +20,3 @@ impl Protocol for ProtocolAlpha { type Constants = ConstantsAlpha; type Migrations = SandboxSeed; } - - -pub fn initialize(context: &mut impl TezosContext, chain_id: ChainId) -> Result { - let mut head = context.get_head()?; - context.log(format!("Protocol initialized: {}", head)); - - if head.chain_id != chain_id { - head.chain_id = chain_id; - context.set_head(head.clone())?; - context.commit()?; - } - - Ok(false) -} - -pub fn inject_operation(context: &mut impl TezosContext, operation: SignedOperation) -> Result { - // TODO: validate and add operations to mempool - todo!() -} - -pub fn inject_batch(context: &mut impl TezosContext, batch: BatchPayload) -> Result { - // validate and execute batch - // remove included mempool operations - todo!() -} - -pub fn finalize(context: &mut impl TezosContext, timestamp: i64) -> Result<()> { - let mut head = context.get_head()?; - - let constants = Proto::Constants::constants(); - if timestamp - head.timestamp > (constants.minimal_block_delay * constants.blocks_per_cycle) as i64 { - head.timestamp = timestamp; - context.set_head(head.clone())?; - context.commit()?; - } - - // Make an implicit batch in case: - // - there are mempool operations that about to expire - // - more than N seconds passed since the latest block - - // remove invalid mempool operations (due to balance/counter changes) - - Ok(()) -}