Bladeren bron

wasm: fix most of the warnings

x 3 jaren geleden
bovenliggende
commit
695f86f7c6

+ 7 - 40
example/smart-contract/src/lib.rs

@@ -37,8 +37,8 @@ pub struct FooCallData {
 impl FooCallData {
     //fn zk_public_values(&self) -> Vec<(String, Vec<DrkCircuitField>)>;
 
-    fn get_metadata(&self) {
-    }
+    //fn get_metadata(&self) {
+    //}
 }
 
 #[derive(SerialEncodable, SerialDecodable)]
@@ -75,13 +75,13 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
     Ok(())
 }
 
-fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
+fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
     match Function::from(ix[0]) {
         Function::Foo => {
             let tx_data = &ix[1..];
             // ...
             let (func_call_index, func_calls): (u32, Vec<FuncCall>) = deserialize(tx_data)?;
-            let call_data: FooCallData =
+            let _call_data: FooCallData =
                 deserialize(&func_calls[func_call_index as usize].call_data)?;
 
             // Convert call_data to halo2 public inputs
@@ -97,7 +97,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
 // This is the main entrypoint function where the payload is fed.
 // Through here, you can branch out into different functions inside
 // this library.
-fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
+fn process_instruction(_cid: ContractId, ix: &[u8]) -> ContractResult {
     match Function::from(ix[0]) {
         Function::Foo => {
             let tx_data = &ix[1..];
@@ -123,40 +123,14 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
         Function::Bar => {
             let tx_data = &ix[1..];
             // ...
-            let args: BarArgs = deserialize(tx_data)?;
+            let _args: BarArgs = deserialize(tx_data)?;
         }
     }
-    /*
-    msg!("Hello from the VM runtime!");
-    // Deserialize the payload into `Args`.
-    let args: Args = deserialize(ix)?;
-    msg!("deserializing payload worked");
-
-    if args.a < args.b {
-        // Returning custom errors
-        return Err(ContractError::Custom(69))
-    }
-
-    let sum = args.a + args.b;
-    // Publicly logged messages
-    msg!("Hello from the VM runtime!");
-    msg!("Sum: {:?}", sum);
-
-    // Querying of ledger state available from the VM host
-    let nf = Nullifier::from(pallas::Base::from(0x10));
-    msg!("Contract Nullifier: {:?}", nf);
-
-    if nullifier_exists(&nf)? {
-        msg!("Nullifier exists");
-    } else {
-        msg!("Nullifier doesn't exist");
-    }
-    */
 
     Ok(())
 }
 
-fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
+fn process_update(_cid: ContractId, update_data: &[u8]) -> ContractResult {
     msg!("Make update!");
 
     match Function::from(update_data[0]) {
@@ -175,10 +149,3 @@ fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
     Ok(())
 }
 
-//fn state_transition() -> Result<StateUpdate> {
-//    // read only
-//}
-//
-//fn apply(update) {
-//    // writes happen here
-//}

+ 0 - 97
src/runtime/import/chain_state.rs

@@ -1,97 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2022 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use log::debug;
-use wasmer::{FunctionEnvMut, WasmPtr};
-
-use crate::runtime::vm_runtime::{ContractSection, Env};
-
-/// Try to read a `Nullifier` from the given pointer and check if it's
-/// an existing nullifier in the blockchain state machine.
-pub(crate) fn nullifier_exists(mut ctx: FunctionEnvMut<Env>, ptr: u32, len: u32) -> i32 {
-    let env = ctx.data();
-    match env.contract_section {
-        ContractSection::Null => {
-            unreachable!();
-        }
-        ContractSection::Deploy => {
-            debug!(target: "nullifier_exists", "deploy!!!");
-        }
-        ContractSection::Exec => {
-            debug!(target: "nullifier_exists", "exec!!!");
-        }
-        ContractSection::Update => {
-            debug!(target: "nullifier_exists", "apply!!!");
-        }
-    }
-    /*
-    if let Some(bytes) = env.memory.get_ref().unwrap().read(ptr, len as usize) {
-        debug!(target: "wasm_runtime::nullifier_exists", "Read bytes: {:?}", bytes);
-
-        let nullifier = match Nullifier::from_bytes(bytes.try_into().unwrap()) {
-            Some(nf) => {
-                debug!(target: "wasm_runtime::nullifier_exists", "Nullifier: {:?}", nf);
-                nf
-            }
-            None => {
-                error!(target: "wasm_runtime::nullifier_exists", "Could not convert bytes to Nullifier");
-                return -1
-            }
-        };
-
-        match env.state_machine.nullifier_exists(&nullifier) {
-            true => return 1,
-            false => return 0,
-        }
-    }
-    */
-
-    //error!(target: "wasm_runtime::nullifier_exists", "Failed to read bytes from VM memory");
-    //-2
-    0
-}
-
-/// Try to read a `MerkleNode` from the given pointer and check if it's
-/// a valid Merkle root in the chain's Merkle tree.
-pub(crate) fn is_valid_merkle(mut ctx: FunctionEnvMut<Env>, ptr: u32, len: u32) -> i32 {
-    /*
-    if let Some(bytes) = env.memory.get_ref().unwrap().read(ptr, len as usize) {
-        debug!(target: "wasm_runtime::is_valid_merkle", "Read bytes: {:?}", bytes);
-
-        let merkle_node = match MerkleNode::from_bytes(bytes.try_into().unwrap()) {
-            Some(mn) => {
-                debug!(target: "wasm_runtime::is_valid_merkle", "MerkleNode: {:?}", mn);
-                mn
-            }
-            None => {
-                error!(target: "wasm_runtime::is_valid_merkle", "Could not convert bytes to MerkleNode");
-                return -1
-            }
-        };
-
-        match env.state_machine.is_valid_merkle(&merkle_node) {
-            true => return 1,
-            false => return 0,
-        }
-    }
-    */
-
-    //error!(target: "wasm_runtime::is_valid_merkle", "Failed to read bytes from VM memory");
-    //-2
-    0
-}

+ 6 - 6
src/runtime/import/db.rs

@@ -40,7 +40,7 @@ impl DbHandle {
 ///     type DbHandle = u32;
 ///     db_init(db_name) -> DbHandle
 /// ```
-pub(crate) fn db_init(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i32 {
+pub(crate) fn db_init(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i32 {
     let env = ctx.data();
     match env.contract_section {
         ContractSection::Deploy => {
@@ -99,7 +99,7 @@ pub(crate) fn db_init(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32)
 ///     type DbHandle = u32;
 ///     db_lookup(db_name) -> DbHandle
 /// ```
-pub(crate) fn db_lookup(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i32 {
+pub(crate) fn db_lookup(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i32 {
     let env = ctx.data();
     match env.contract_section {
         ContractSection::Deploy | ContractSection::Exec | ContractSection::Update => {
@@ -126,7 +126,7 @@ pub(crate) fn db_lookup(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32
 /// ```
 ///     value = db_get(db_handle, key);
 /// ```
-pub(crate) fn db_get(mut ctx: FunctionEnvMut<Env>) -> i32 {
+pub(crate) fn db_get(ctx: FunctionEnvMut<Env>) -> i32 {
     let env = ctx.data();
     match env.contract_section {
         ContractSection::Exec => 0,
@@ -139,7 +139,7 @@ pub(crate) fn db_get(mut ctx: FunctionEnvMut<Env>) -> i32 {
 /// ```
 ///     tx_handle = db_begin_tx();
 /// ```
-pub(crate) fn db_begin_tx(mut ctx: FunctionEnvMut<Env>) -> i32 {
+pub(crate) fn db_begin_tx(ctx: FunctionEnvMut<Env>) -> i32 {
     let env = ctx.data();
     match env.contract_section {
         ContractSection::Deploy | ContractSection::Update => 0,
@@ -152,7 +152,7 @@ pub(crate) fn db_begin_tx(mut ctx: FunctionEnvMut<Env>) -> i32 {
 /// ```
 ///     db_set(tx_handle, key, value);
 /// ```
-pub(crate) fn db_set(mut ctx: FunctionEnvMut<Env>) -> i32 {
+pub(crate) fn db_set(ctx: FunctionEnvMut<Env>) -> i32 {
     let env = ctx.data();
     match env.contract_section {
         ContractSection::Deploy | ContractSection::Update => 0,
@@ -165,7 +165,7 @@ pub(crate) fn db_set(mut ctx: FunctionEnvMut<Env>) -> i32 {
 /// ```
 ///     db_end_tx(db_handle, tx_handle);
 /// ```
-pub(crate) fn db_end_tx(mut ctx: FunctionEnvMut<Env>) -> i32 {
+pub(crate) fn db_end_tx(ctx: FunctionEnvMut<Env>) -> i32 {
     let env = ctx.data();
     match env.contract_section {
         ContractSection::Deploy | ContractSection::Update => 0,

+ 0 - 3
src/runtime/import/mod.rs

@@ -19,8 +19,5 @@
 /// Host functions for interacting with db backend
 pub(crate) mod db;
 
-/// Host functions for querying blockchain state through `MemoryState`
-pub(crate) mod chain_state;
-
 /// Host functions for utilities
 pub(crate) mod util;

+ 2 - 2
src/runtime/import/util.rs

@@ -23,7 +23,7 @@ use crate::runtime::vm_runtime::{ContractSection, Env};
 
 /// Host function for logging strings.
 /// This is injected into the runtime with wasmer's `imports!` macro.
-pub(crate) fn drk_log(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) {
+pub(crate) fn drk_log(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) {
     let env = ctx.data();
     let memory_view = env.memory_view(&ctx);
 
@@ -39,7 +39,7 @@ pub(crate) fn drk_log(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32)
     }
 }
 
-pub(crate) fn set_return_data(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i32 {
+pub(crate) fn set_return_data(ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32) -> i32 {
     let env = ctx.data();
     match env.contract_section {
         ContractSection::Exec => {

+ 1 - 1
src/runtime/memory.rs

@@ -36,7 +36,7 @@ impl<'a> MemoryManipulation for MemoryView<'a> {
         Ok(slice.write_slice(value_slice)?)
     }
 
-    fn read_slice(&self, value_len: usize, mem_offset: u32) -> Option<&[u8]> {
+    fn read_slice(&self, _value_len: usize, _mem_offset: u32) -> Option<&[u8]> {
         // TODO: use data_size() ?
         // DISABLED
         /*

+ 3 - 167
src/runtime/vm_runtime.rs

@@ -39,20 +39,16 @@ use crate::{blockchain::Blockchain, Error, Result};
 /// Name of the wasm linear memory in our guest module
 const MEMORY: &str = "memory";
 
-/// Hardcoded setup function of a contract
-const INITIALIZE: &str = "__initialize";
-/// Hardcoded entrypoint function of a contract
-const ENTRYPOINT: &str = "__entrypoint";
-/// Hardcoded apply function of a contract
-const UPDATE: &str = "__update";
-
 /// Gas limit for a contract
 const GAS_LIMIT: u64 = 200000;
 
 #[derive(Clone, Copy)]
 pub enum ContractSection {
+    /// Setup function of a contract
     Deploy,
+    /// Entrypoint function of a contract
     Exec,
+    /// Apply function of a contract
     Update,
     Null,
 }
@@ -167,18 +163,6 @@ impl Runtime {
                     import::util::drk_log,
                 ),
 
-                "nullifier_exists_" => Function::new_typed_with_env(
-                    &mut store,
-                    &ctx,
-                    import::chain_state::nullifier_exists,
-                ),
-
-                "is_valid_merkle_" => Function::new_typed_with_env(
-                    &mut store,
-                    &ctx,
-                    import::chain_state::is_valid_merkle,
-                ),
-
                 "set_return_data_" => Function::new_typed_with_env(
                     &mut store,
                     &ctx,
@@ -300,57 +284,6 @@ impl Runtime {
     pub fn deploy(&mut self, payload: &[u8]) -> Result<()> {
         let _ = self.call(ContractSection::Deploy, payload)?;
         Ok(())
-        /*
-        let mut env_mut = self.ctx.as_mut(&mut self.store);
-        env_mut.contract_section = ContractSection::Deploy;
-        assert!(env_mut.contract_return_data.take().is_none());
-        env_mut.contract_return_data.set(None);
-
-        // Serialize the payload for the format the wasm runtime is expecting.
-        let payload = Self::serialize_payload(&env_mut.contract_id, payload);
-
-        // Allocate enough memory for the payload and copy it into the memory.
-        let pages_required = payload.len() / WASM_PAGE_SIZE + 1;
-        self.set_memory_page_size(pages_required as u32)?;
-        self.copy_to_memory(&payload)?;
-
-        debug!(target: "wasm_runtime::deploy", "Getting initialize function");
-        let entrypoint = self.instance.exports.get_function(INITIALIZE)?;
-
-        debug!(target: "wasm_runtime::deploy", "Executing wasm");
-        let ret = match entrypoint.call(&mut self.store, &[Value::I32(0 as i32)]) {
-            Ok(retvals) => {
-                self.print_logs();
-                debug!(target: "wasm_runtime::deploy", "{}", self.gas_info());
-                retvals
-            }
-            Err(e) => {
-                self.print_logs();
-                debug!(target: "wasm_runtime::deploy", "{}", self.gas_info());
-                // WasmerRuntimeError panics are handled here. Return from run() immediately.
-                return Err(e.into())
-            }
-        };
-
-        debug!(target: "wasm_runtime::deploy", "wasm executed successfully");
-        debug!(target: "wasm_runtime::deploy", "Contract returned: {:?}", ret[0]);
-
-        let mut env_mut = self.ctx.as_mut(&mut self.store);
-        env_mut.contract_section = ContractSection::Null;
-        let retdata = env_mut.contract_return_data.take();
-
-        let retval = match ret[0] {
-            Value::I64(v) => v as u64,
-            _ => unreachable!(),
-        };
-
-        match retval {
-            entrypoint::SUCCESS => Ok(()),
-            // FIXME: we should be able to see the error returned from the contract
-            // We can put sdk::Error inside of this.
-            _ => Err(Error::ContractInitError(retval)),
-        }
-        */
     }
 
     /// This funcion runs when someone wants to execute a smart contract.
@@ -359,52 +292,6 @@ impl Runtime {
     /// be used inside the vm by the runtime.
     pub fn exec(&mut self, payload: &[u8]) -> Result<Vec<u8>> {
         self.call(ContractSection::Exec, payload)
-        /*
-        let mut env_mut = self.ctx.as_mut(&mut self.store);
-        env_mut.contract_section = ContractSection::Exec;
-        assert!(env_mut.contract_return_data.take().is_none());
-        env_mut.contract_return_data.set(None);
-
-        // Serialize the payload for the format the wasm runtime is expecting.
-        let payload = Self::serialize_payload(&env_mut.contract_id, payload);
-
-        // Allocate enough memory for the payload and copy it into the memory.
-        let pages_required = payload.len() / WASM_PAGE_SIZE + 1;
-        self.set_memory_page_size(pages_required as u32)?;
-        self.copy_to_memory(&payload)?;
-
-        debug!(target: "wasm_runtime::exec", "Getting entrypoint function");
-        let entrypoint = self.instance.exports.get_function(ENTRYPOINT)?;
-
-        debug!(target: "wasm_runtime::exec", "Executing wasm");
-        // We pass 0 to entrypoint() which is the location of the payload data in the memory
-        let ret = match entrypoint.call(&mut self.store, &[Value::I32(0 as i32)]) {
-            Ok(retvals) => {
-                self.print_logs();
-                debug!(target: "wasm_runtime::exec", "{}", self.gas_info());
-                retvals
-            }
-            Err(e) => {
-                self.print_logs();
-                debug!(target: "wasm_runtime::exec", "{}", self.gas_info());
-                // WasmerRuntimeError panics are handled here. Return from run() immediately.
-                return Err(e.into())
-            }
-        };
-
-        debug!(target: "wasm_runtime::exec", "wasm executed successfully");
-        debug!(target: "wasm_runtime::exec", "Contract returned: {:?}", ret[0]);
-
-        let retval = match ret[0] {
-            Value::I64(v) => v as u64,
-            _ => unreachable!(),
-        };
-
-        match retval {
-            entrypoint::SUCCESS => Ok(()),
-            _ => Err(Error::ContractExecError(retval)),
-        }
-        */
     }
 
     /// This function runs after successful execution of [`exec`] and tries to
@@ -415,57 +302,6 @@ impl Runtime {
     pub fn apply(&mut self, update: &[u8]) -> Result<()> {
         let _ = self.call(ContractSection::Update, update)?;
         Ok(())
-        /*
-        let mut env_mut = self.ctx.as_mut(&mut self.store);
-        env_mut.contract_section = ContractSection::Update;
-        assert!(env_mut.contract_return_data.take().is_none());
-        env_mut.contract_return_data.set(None);
-
-        // Take the update data from env, and serialize it for the format the wasm
-        // runtime is expecting.
-        // FIXME: Can panic
-        let update_data = env_mut.contract_update.take().unwrap();
-        let mut payload = Vec::with_capacity(1 + update_data.1.len());
-        payload.extend_from_slice(&[update_data.0]);
-        payload.extend_from_slice(&update_data.1);
-        let payload = Self::serialize_payload(&env_mut.contract_id, &payload);
-
-        // Allocate enough memory for the payload and copy it into the memory.
-        let pages_required = payload.len() / WASM_PAGE_SIZE + 1;
-        self.set_memory_page_size(pages_required as u32)?;
-        self.copy_to_memory(&payload)?;
-
-        debug!(target: "wasm_runtime::apply", "Getting update function");
-        let entrypoint = self.instance.exports.get_function(UPDATE)?;
-
-        debug!(target: "wasm_runtime::apply", "Executing wasm");
-        let ret = match entrypoint.call(&mut self.store, &[Value::I32(0 as i32)]) {
-            Ok(retvals) => {
-                self.print_logs();
-                debug!(target: "wasm_runtime::apply", "{}", self.gas_info());
-                retvals
-            }
-            Err(e) => {
-                self.print_logs();
-                debug!(target: "wasm_runtime::apply", "{}", self.gas_info());
-                // WasmerRuntimeError panics are handled here. Return from run() immediately.
-                return Err(e.into())
-            }
-        };
-
-        debug!(target: "wasm_runtime::apply", "wasm executed successfully");
-        debug!(target: "wasm_runtime::apply", "Contract returned: {:?}", ret[0]);
-
-        let retval = match ret[0] {
-            Value::I64(v) => v as u64,
-            _ => unreachable!(),
-        };
-
-        match retval {
-            entrypoint::SUCCESS => Ok(()),
-            _ => Err(Error::ContractInitError(retval)),
-        }
-        */
     }
 
     fn print_logs(&self) {

+ 0 - 5
src/sdk/src/db.rs

@@ -137,11 +137,6 @@ pub fn db_end_tx(db_handle: DbHandle, tx_handle: TxHandle) -> GenericResult<()>
 
 #[cfg(target_arch = "wasm32")]
 extern "C" {
-    fn get_update_() -> i32;
-    fn set_update_(ptr: *const u8, len: u32) -> i32;
-    fn nullifier_exists_(ptr: *const u8, len: u32) -> i32;
-    fn is_valid_merkle_(ptr: *const u8, len: u32) -> i32;
-
     fn db_init_(ptr: *const u8, len: u32) -> i32;
     fn db_lookup_(ptr: *const u8, len: u32) -> i32;
     fn db_get_() -> i32;

+ 0 - 3
src/sdk/src/lib.rs

@@ -34,9 +34,6 @@ pub mod log;
 /// Crypto-related definitions
 pub mod crypto;
 
-/// Functions for state queries
-pub mod state;
-
 /// Transaction structure
 pub mod tx;
 

+ 0 - 64
src/sdk/src/state.rs

@@ -1,64 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2022 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use super::{
-    crypto::{MerkleNode, Nullifier},
-    error::ContractError,
-};
-
-pub fn nullifier_exists(nullifier: &Nullifier) -> Result<bool, ContractError> {
-    #[cfg(target_arch = "wasm32")]
-    unsafe {
-        // Convert to bytes, and pass pointer to first byte in slice to the function.
-        let nf = nullifier.to_bytes();
-        return match nullifier_exists_(&nf as *const u8, 32) {
-            0 => Ok(false),
-            1 => Ok(true),
-            -1 => Err(ContractError::NullifierExistCheck),
-            -2 => Err(ContractError::Internal),
-            _ => unreachable!(),
-        }
-    }
-
-    #[cfg(not(target_arch = "wasm32"))]
-    todo!("nullifier_exists({:?}", nullifier);
-}
-
-pub fn is_valid_merkle(merkle_root: &MerkleNode) -> Result<bool, ContractError> {
-    #[cfg(target_arch = "wasm32")]
-    unsafe {
-        // Convert to bytes, and pass pointer to first byte in slice to the function.
-        let mr = merkle_root.to_bytes();
-        return match is_valid_merkle_(&mr as *const u8, 32) {
-            0 => Ok(false),
-            1 => Ok(true),
-            -1 => Err(ContractError::ValidMerkleCheck),
-            -2 => Err(ContractError::Internal),
-            _ => unreachable!(),
-        }
-    }
-
-    #[cfg(not(target_arch = "wasm32"))]
-    todo!("is_valid_merkle({:?}", merkle_root);
-}
-
-#[cfg(target_arch = "wasm32")]
-extern "C" {
-    fn nullifier_exists_(ptr: *const u8, len: u32) -> i32;
-    fn is_valid_merkle_(ptr: *const u8, len: u32) -> i32;
-}

+ 1 - 1
src/serial/src/async_serial.rs

@@ -103,7 +103,7 @@ impl VarInt {
 
             _ => {
                 AsyncWriteExt::write_u8(stream, 0xFF).await?;
-                AsyncWriteExt::write_u64(stream, self.0 as u64).await?;
+                AsyncWriteExt::write_u64(stream, self.0).await?;
                 Ok(9)
             }
         }