From 7b005c41be4d614ca2e48824f50a4deab00ccf63 Mon Sep 17 00:00:00 2001 From: martoon Date: Tue, 12 Sep 2023 02:49:43 +0300 Subject: [PATCH 1/2] MIR: Add dummy fibonacci logic to rollup Prepare a rollup that executes fibonacci contract, but instead of contract call yet have a dummy Rust computation. Parameter is obtained from the processed message, and storage persists in the durable storage. --- contrib/mir/Cargo.lock | 15 ++++++ contrib/mir/Cargo.toml | 1 + contrib/mir/src/rollup.rs | 1 + contrib/mir/src/rollup/demo.rs | 82 ++++++++++++++++++++++++++++++++ contrib/mir/src/rollup/kernel.rs | 8 +++- contrib/mir/src/rollup/types.rs | 4 +- 6 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 contrib/mir/src/rollup/demo.rs diff --git a/contrib/mir/Cargo.lock b/contrib/mir/Cargo.lock index 2f96f32f9eef..2729f05ea3da 100644 --- a/contrib/mir/Cargo.lock +++ b/contrib/mir/Cargo.lock @@ -649,6 +649,7 @@ dependencies = [ "lalrpop", "lalrpop-util", "tezos-smart-rollup", + "tezos-smart-rollup-mock", ] [[package]] @@ -1225,6 +1226,20 @@ dependencies = [ "thiserror", ] +[[package]] +name = "tezos-smart-rollup-mock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c0a78d331bf3b80970c7e2b81472283f197aab77912e079e759c2e672d451cc" +dependencies = [ + "hex", + "tezos-smart-rollup-core", + "tezos-smart-rollup-encoding", + "tezos-smart-rollup-host", + "tezos_crypto_rs", + "tezos_data_encoding", +] + [[package]] name = "tezos-smart-rollup-panic-hook" version = "0.2.1" diff --git a/contrib/mir/Cargo.toml b/contrib/mir/Cargo.toml index df797ce3204c..059c26d739c3 100644 --- a/contrib/mir/Cargo.toml +++ b/contrib/mir/Cargo.toml @@ -16,3 +16,4 @@ lalrpop = "0.20.0" [dependencies] lalrpop-util = { version = "0.20.0", features = ["lexer"] } tezos-smart-rollup = "0.2.1" +tezos-smart-rollup-mock = "0.2.1" diff --git a/contrib/mir/src/rollup.rs b/contrib/mir/src/rollup.rs index bbb1dc551f66..f941925887c7 100644 --- a/contrib/mir/src/rollup.rs +++ b/contrib/mir/src/rollup.rs @@ -5,5 +5,6 @@ /* */ /******************************************************************************/ +pub mod demo; pub mod kernel; pub mod types; diff --git a/contrib/mir/src/rollup/demo.rs b/contrib/mir/src/rollup/demo.rs new file mode 100644 index 000000000000..a6fde599875a --- /dev/null +++ b/contrib/mir/src/rollup/demo.rs @@ -0,0 +1,82 @@ +/******************************************************************************/ +/* */ +/* SPDX-License-Identifier: MIT */ +/* Copyright (c) [2023] Serokell */ +/* */ +/******************************************************************************/ + +//! This is a logic for demo rollup that eventually should be thrown away. + +use std::mem::size_of; +use tezos_smart_rollup::{ + inbox::Transfer, + prelude::{debug_msg, Runtime}, + storage::path::RefPath, +}; +use tezos_smart_rollup_encoding::michelson::MichelsonInt; + +use super::types::IncomingTransferParam; + +pub type Error = String; + +const STORAGE_PATH: &RefPath = &RefPath::assert_from(b"/storage"); + +pub fn process_external_message(host: &mut impl Runtime, payload: &[u8]) -> Result<(), Error> { + let param = free_form_bytes_to_number(payload); + call_fibonacci(host, param) +} + +pub fn process_internal_message( + host: &mut impl Runtime, + transfer: &Transfer, +) -> Result<(), Error> { + let payload: &MichelsonInt = &transfer.payload; + let param = (payload.0 .0) + .clone() + .try_into() + .map_err(|_| String::from("Too large input"))?; + call_fibonacci(host, param) +} + +pub fn call_fibonacci(host: &mut impl Runtime, param: usize) -> Result<(), Error> { + let is_storage_empty = host + .store_has(STORAGE_PATH) + .map_err(|err| err.to_string())? + .is_none(); + let storage = if is_storage_empty { + 0 + } else { + free_form_bytes_to_number( + host.store_read_all(STORAGE_PATH) + .map_err(|err| err.to_string())? + .as_ref(), + ) + }; + // ↑ That's pretty painful, MR with a higher-level API is on the way + + let new_storage = run_fibonacci(param, storage)?; + + host.store_write_all(STORAGE_PATH, &new_storage.to_le_bytes()) + .map_err(|err| err.to_string())?; + debug_msg!(host, "Computation successful, storage updated"); + Ok(()) +} + +fn run_fibonacci(param: usize, _storage: usize) -> Result { + // TODO: replace with contract interpretation + let answers: Vec = vec![ + 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, + ]; + answers + .get(param) + .copied() + .ok_or(String::from("Cannot answer for such large number :shrug:")) +} + +/// Accepts both undersized and oversized byte arrays to convert to number. +fn free_form_bytes_to_number(bs: &[u8]) -> usize { + let mut bs_sized = [0; size_of::()]; + let bs_len = std::cmp::min(bs_sized.len(), bs.len()); + bs_sized[..bs_len].copy_from_slice(&bs[..bs_len]); + usize::from_le_bytes(bs_sized) +} diff --git a/contrib/mir/src/rollup/kernel.rs b/contrib/mir/src/rollup/kernel.rs index b56c6360a634..07340ad42136 100644 --- a/contrib/mir/src/rollup/kernel.rs +++ b/contrib/mir/src/rollup/kernel.rs @@ -11,6 +11,8 @@ use tezos_smart_rollup::{ types::Message, }; +use crate::rollup::demo::{process_external_message, process_internal_message}; + use super::types::*; // This module follows the reference examples: https://gitlab.com/tezos/kernel-gallery @@ -58,7 +60,8 @@ pub fn process_message(host: &mut impl Runtime, msg: &Message) -> Result<(), Err debug_assert!(rest.is_empty()); match msg { InboxMessage::External(payload) => { - debug_msg!(host, "Message #{msg_id} - external: {payload:#x?}") + debug_msg!(host, "Message #{msg_id} - external: {payload:#x?}"); + process_external_message(host, &payload)? } // [optimization] If payload is bytes, it should not be hard // to avoid copying payload when parsing if we use our own structures. @@ -72,7 +75,8 @@ pub fn process_message(host: &mut impl Runtime, msg: &Message) -> Result<(), Err "Message #{msg_id} - internal transfer to {} with payload: {:#x?}", transfer.destination, &transfer.payload.0 - ) + ); + process_internal_message(host, &transfer)? } InternalInboxMessage::StartOfLevel => {} InternalInboxMessage::InfoPerLevel(_) => {} diff --git a/contrib/mir/src/rollup/types.rs b/contrib/mir/src/rollup/types.rs index d8193a779154..2916b5512924 100644 --- a/contrib/mir/src/rollup/types.rs +++ b/contrib/mir/src/rollup/types.rs @@ -5,11 +5,11 @@ /* */ /******************************************************************************/ -use tezos_smart_rollup::michelson::MichelsonBytes; +use tezos_smart_rollup::michelson::MichelsonInt; /// What we accept in internal messages as payload (i.e. what is our parameter /// type). /// /// If you change this, then in the rollup origination command you should also /// change the `type` CLI argument respectively. -pub type IncomingTransferParam = MichelsonBytes; +pub type IncomingTransferParam = MichelsonInt; -- GitLab From 5bc4a0e87fe58d6f8bc6b5b86ee7800a8394c9ac Mon Sep 17 00:00:00 2001 From: martoon Date: Tue, 12 Sep 2023 02:51:16 +0300 Subject: [PATCH 2/2] MIR: Add tests on new logic --- contrib/mir/Cargo.lock | 144 ++++++++++++++++++++++++++++++++- contrib/mir/Cargo.toml | 4 + contrib/mir/src/rollup/demo.rs | 49 +++++++++++ 3 files changed, 194 insertions(+), 3 deletions(-) diff --git a/contrib/mir/Cargo.lock b/contrib/mir/Cargo.lock index 2729f05ea3da..10321e67916e 100644 --- a/contrib/mir/Cargo.lock +++ b/contrib/mir/Cargo.lock @@ -371,6 +371,12 @@ dependencies = [ "libc", ] +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "ff" version = "0.10.1" @@ -393,6 +399,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "funty" version = "2.0.0" @@ -409,6 +421,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -417,7 +440,7 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -563,6 +586,12 @@ version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + [[package]] name = "libsecp256k1" version = "0.7.1" @@ -577,6 +606,7 @@ dependencies = [ "libsecp256k1-gen-genmult", "rand 0.8.5", "serde", + "sha2 0.9.9", ] [[package]] @@ -648,8 +678,12 @@ version = "0.1.0" dependencies = [ "lalrpop", "lalrpop-util", + "num-bigint", "tezos-smart-rollup", + "tezos-smart-rollup-encoding", "tezos-smart-rollup-mock", + "tezos_crypto_rs", + "tezos_data_encoding", ] [[package]] @@ -677,6 +711,7 @@ dependencies = [ "autocfg", "num-integer", "num-traits", + "rand 0.7.3", "serde", ] @@ -697,6 +732,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -832,6 +868,32 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" +dependencies = [ + "bit-set", + "bitflags 1.3.2", + "byteorder", + "lazy_static", + "num-traits", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_xorshift", + "regex-syntax 0.6.29", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.33" @@ -853,7 +915,9 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "rand_chacha", + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", ] @@ -864,6 +928,8 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", + "rand_chacha 0.3.1", "rand_core 0.6.4", ] @@ -877,17 +943,33 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.10", +] [[package]] name = "rand_hc" @@ -898,6 +980,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -922,7 +1013,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom", + "getrandom 0.2.10", "redox_syscall 0.2.16", "thiserror", ] @@ -990,6 +1081,18 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1139,6 +1242,19 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tempfile" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys", +] + [[package]] name = "term" version = "0.7.0" @@ -1279,6 +1395,7 @@ dependencies = [ "num-bigint", "num-traits", "p256", + "proptest", "rand 0.7.3", "serde", "strum", @@ -1391,6 +1508,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -1415,6 +1538,21 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/contrib/mir/Cargo.toml b/contrib/mir/Cargo.toml index 059c26d739c3..612ae85ee3b6 100644 --- a/contrib/mir/Cargo.toml +++ b/contrib/mir/Cargo.toml @@ -15,5 +15,9 @@ lalrpop = "0.20.0" [dependencies] lalrpop-util = { version = "0.20.0", features = ["lexer"] } +num-bigint = "0.3.3" +tezos_data_encoding = "0.5.1" +tezos_crypto_rs = "0.5.1" tezos-smart-rollup = "0.2.1" +tezos-smart-rollup-encoding = "0.2.1" tezos-smart-rollup-mock = "0.2.1" diff --git a/contrib/mir/src/rollup/demo.rs b/contrib/mir/src/rollup/demo.rs index a6fde599875a..aced606eda1f 100644 --- a/contrib/mir/src/rollup/demo.rs +++ b/contrib/mir/src/rollup/demo.rs @@ -80,3 +80,52 @@ fn free_form_bytes_to_number(bs: &[u8]) -> usize { bs_sized[..bs_len].copy_from_slice(&bs[..bs_len]); usize::from_le_bytes(bs_sized) } + +#[cfg(test)] +mod test_message_processing { + use num_bigint::BigInt; + use tezos_crypto_rs::hash::ContractKt1Hash; + use tezos_smart_rollup_encoding::{ + public_key_hash::PublicKeyHash, smart_rollup::SmartRollupAddress, + }; + use tezos_smart_rollup_mock::MockHost; + + use super::*; + + fn test_on_sample(param: &[u8], expected_res: &[u8]) { + let mut host = MockHost::default(); + process_external_message(&mut host, param).unwrap(); + assert_eq!(host.store_read_all(STORAGE_PATH).unwrap(), expected_res); + } + + #[test] + fn test_external_message_processing_on_samples() { + // 0th value of the Fibonacci sequence is 0. + test_on_sample(b"\x00", b"\0\0\0\0\0\0\0\0"); + // 1st value of the Fibonacci sequence is 1. + test_on_sample(b"\x01", b"\x01\0\0\0\0\0\0\0"); + // 10th value of the Fibonacci sequence is 55. + test_on_sample(&[10], &[55, 0, 0, 0, 0, 0, 0, 0]); + // 15th value of the Fibonacci sequence is 610 = 98 + 2*256. + test_on_sample(&[15], &[98, 2, 0, 0, 0, 0, 0, 0]); + } + + #[test] + fn test_internal_message_processing_on_samples() { + let mut host = MockHost::default(); + let payload = MichelsonInt(BigInt::from(10).into()); + let transfer = Transfer { + payload, + // Just arbitrary constants, they don't matter for test + sender: ContractKt1Hash::from_base58_check("KT1ThEdxfUcWUwqsdergy3QnbCWGHSUHeHJq") + .unwrap(), + source: PublicKeyHash::from_b58check("tz1RjtZUVeLhADFHDL8UwDZA6vjWWhojpu5w").unwrap(), + destination: SmartRollupAddress::new(host.reveal_metadata().address()), + }; + process_internal_message(&mut host, &transfer).unwrap(); + assert_eq!( + host.store_read_all(STORAGE_PATH).unwrap(), + &[55, 0, 0, 0, 0, 0, 0, 0] + ); + } +} -- GitLab