From 12c938f27f748942ff3efeda3f9af83c29b67bc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Bilge=20Yal=C3=A7=C4=B1nkaya?= Date: Tue, 4 Feb 2025 13:01:58 +0300 Subject: [PATCH] Add host functions for `Bytes` operations (#61) * implement `bytes_copy_from_linear_memory` * implement `bytes_new` * implement `bytes_put` * implement `bytes_get` * refactor `bytes_copy_from_linear_memory` * implement `bytes_del` * refactor hostcall implementations to use `hostCallAux` * implement `bytes_push` * implement `bytes_pop` * implement `bytes_front` `bytes_back` * implement `bytes_insert` * implement `bytes_append` * implement `bytes_slice` * allow 0 length in `bytes_insert` * add property tests * Set Version: 0.1.51 * update soroban sdk * implement `symbol_len` * Set Version: 0.1.52 --------- Co-authored-by: devops Co-authored-by: automergerpr-permission-manager[bot] <190534181+automergerpr-permission-manager[bot]@users.noreply.github.com> --- package/version | 2 +- pyproject.toml | 2 +- .../kdist/soroban-semantics/host/buffer.md | 246 +++++++++++- .../kdist/soroban-semantics/host/symbol.md | 11 + src/tests/integration/data/buffer.wast | 369 ++++++++++++++++++ .../soroban/contracts/test_bytes/Cargo.toml | 15 + .../soroban/contracts/test_bytes/src/lib.rs | 85 ++++ .../soroban/contracts/test_bytes/src/test.rs | 32 ++ 8 files changed, 739 insertions(+), 23 deletions(-) create mode 100644 src/tests/integration/data/buffer.wast create mode 100644 src/tests/integration/data/soroban/contracts/test_bytes/Cargo.toml create mode 100644 src/tests/integration/data/soroban/contracts/test_bytes/src/lib.rs create mode 100644 src/tests/integration/data/soroban/contracts/test_bytes/src/test.rs diff --git a/package/version b/package/version index c892edde..9c4d21fb 100644 --- a/package/version +++ b/package/version @@ -1 +1 @@ -0.1.51 +0.1.52 diff --git a/pyproject.toml b/pyproject.toml index 3f614a6f..dc7394c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "komet" -version = "0.1.51" +version = "0.1.52" description = "K tooling for the Soroban platform" authors = [ "Runtime Verification, Inc. ", diff --git a/src/komet/kdist/soroban-semantics/host/buffer.md b/src/komet/kdist/soroban-semantics/host/buffer.md index a8e1323e..af7479a7 100644 --- a/src/komet/kdist/soroban-semantics/host/buffer.md +++ b/src/komet/kdist/soroban-semantics/host/buffer.md @@ -30,21 +30,52 @@ module HOST-BUFFER andBool B_POS +Int LEN <=Int lengthBytes(BYTES) ``` +## bytes_copy_from_linear_memory + +Reads a slice from linear memory and writes into a `Bytes` object, returning a new object. +The `Bytes` object expands if needed, and any gap between the starting position and its current size is filled with zeros. + +```k + rule [hostCallAux-bytes-copy-from-linear-memory]: + hostCallAux ( "b" , "2" ) + => #memLoad(LM_POS, LEN) + ~> bytesCopyFromLinearMemory + ... + + ScBytes(_) : U32(B_POS) : U32(LM_POS) : U32(LEN) : _ + requires 0 <=Int B_POS + andBool 0 <=Int LEN + + syntax InternalInstr ::= "bytesCopyFromLinearMemory" [symbol(bytesCopyFromLinearMemory)] + // ------------------------------------------------------------------------------------------ + rule [bytesCopyFromLinearMemory]: + bytesCopyFromLinearMemory + => allocObject( + ScBytes( + replaceAtBytes( + padRightBytes(BYTES, B_POS +Int LEN, 0), + B_POS, + BS + ) + ) + ) + ~> returnHostVal + ... + + BS:Bytes : ScBytes(BYTES) : U32(B_POS) : U32(_) : U32(LEN) : S => S + +``` + ## bytes_new_from_linear_memory ```k - rule [hostfun-bytes-new-from-linear-memory]: - hostCall ( "b" , "3" , [ i64 i64 .ValTypes ] -> [ i64 .ValTypes ] ) - => #memLoad(getMajor(HostVal(LM_POS)), getMajor(HostVal(LEN))) + rule [hostCallAux-bytes-new-from-linear-memory]: + hostCallAux ( "b" , "3" ) + => #memLoad(LM_POS, LEN) ~> bytesNewFromLinearMemory ... - - 0 |-> < i64 > LM_POS // U32 - 1 |-> < i64 > LEN // U32 - - requires fromSmallValid(HostVal(LM_POS)) - andBool fromSmallValid(HostVal(LEN)) + U32(LM_POS) : U32(LEN) : S => S syntax InternalInstr ::= "bytesNewFromLinearMemory" [symbol(bytesNewFromLinearMemory)] // --------------------------------------------------------------------------------- @@ -58,28 +89,201 @@ module HOST-BUFFER ``` -## bytes_len +## bytes_new + +Creates an empty `Bytes` object. ```k + rule [hostfun-bytes-new]: + hostCall ( "b" , "4" , [ .ValTypes ] -> [ i64 .ValTypes ] ) + => allocObject(ScBytes(.Bytes)) + ~> returnHostVal + ... + + .Map +``` - rule [hostfun-bytes-len]: - hostCall ( "b" , "8" , [ i64 .ValTypes ] -> [ i64 .ValTypes ] ) - => loadObject(HostVal(BYTES)) - ~> bytesLen +## bytes_put + +Updates the byte at given index. + +```k + rule [hostCallAux-bytes-put]: + hostCallAux ( "b" , "5" ) + => allocObject(ScBytes( BYTES [ I <- V ] )) + ~> returnHostVal ... - - 0 |-> < i64 > BYTES // Bytes HostVal - + ScBytes(BYTES) : U32(I) : U32(V) : S => S + requires 0 <=Int I + andBool I bytesLen +## bytes_get + +Gets the byte at given index. + +```k + rule [hostCallAux-bytes-get]: + hostCallAux ( "b" , "6" ) + => toSmall( U32( BYTES [I] ) ) + ... + + ScBytes(BYTES) : U32(I) : S => S + requires 0 <=Int I + andBool I hostCallAux ( "b" , "7" ) + => allocObject( + ScBytes( substrBytes(BYTES, 0, I) + +Bytes substrBytes(BYTES, I +Int 1, lengthBytes(BYTES)) + ) + ) + ~> returnHostVal + ... + + ScBytes(BYTES) : U32(I) : S => S + requires 0 <=Int I + andBool I hostCallAux ( "b" , "8" ) => toSmall(U32(lengthBytes(BS))) ... ScBytes(BS) : S => S +``` + +## bytes_push + +Add an element to the back of the `Bytes` object + +```k + rule [hostCallAux-bytes-push]: + hostCallAux ( "b" , "9" ) + => allocObject(ScBytes( BYTES +Bytes Int2Bytes(1, V, LE) )) + ~> returnHostVal + ... + + ScBytes(BYTES) : U32(V) : S => S + requires 0 <=Int V + andBool V hostCallAux ( "b" , "a" ) + => allocObject(ScBytes( substrBytes(BYTES, 0, lengthBytes(BYTES) -Int 1) )) + ~> returnHostVal + ... + + ScBytes(BYTES) : S => S + requires 0 hostCallAux ( "b" , "b" ) + => toSmall(U32( BYTES[0] )) + ... + + ScBytes(BYTES) : S => S + requires 0 hostCallAux ( "b" , "c" ) + => toSmall(U32( BYTES[lengthBytes(BYTES) -Int 1] )) + ... + + ScBytes(BYTES) : S => S + requires 0 hostCallAux ( "b" , "d" ) + => allocObject( + ScBytes( substrBytes(BYTES, 0, I) + +Bytes Int2Bytes(1, V, LE) + +Bytes substrBytes(BYTES, I, lengthBytes(BYTES)) + ) + ) + ~> returnHostVal + ... + + ScBytes(BYTES) : U32(I) : U32(V) : S => S + requires 0 <=Int I + andBool I <=Int lengthBytes(BYTES) + andBool 0 <=Int V + andBool V hostCallAux ( "b" , "e" ) + => allocObject( + ScBytes( BYTES1 +Bytes BYTES2 ) + ) + ~> returnHostVal + ... + + ScBytes(BYTES1) : ScBytes(BYTES2) : S => S + requires lengthBytes(BYTES1) +Int lengthBytes(BYTES2) hostCallAux ( "b" , "f" ) + => allocObject( ScBytes( substrBytes(BYTES, START, END) ) ) + ~> returnHostVal + ... + + ScBytes(BYTES) : U32(START) : U32(END) : S => S + requires 0 <=Int START + andBool START <=Int END + andBool END <=Int lengthBytes(BYTES) +``` + +```k endmodule ``` \ No newline at end of file diff --git a/src/komet/kdist/soroban-semantics/host/symbol.md b/src/komet/kdist/soroban-semantics/host/symbol.md index 1ea94b99..ebb39768 100644 --- a/src/komet/kdist/soroban-semantics/host/symbol.md +++ b/src/komet/kdist/soroban-semantics/host/symbol.md @@ -49,6 +49,17 @@ module HOST-SYMBOL (BS => Symbol(Bytes2String(BS))) : _ ``` +## symbol_len + +```k + rule [hostCallAux-symbol-len]: + hostCallAux ( "b" , "l" ) + => toSmall(U32(lengthString(SYM))) + ... + + Symbol(SYM) : S => S +``` + ## symbol_index_in_linear_memory Linear search a `Symbol` in an array of byte slices. Return the index of the element or trap if not found. diff --git a/src/tests/integration/data/buffer.wast b/src/tests/integration/data/buffer.wast new file mode 100644 index 00000000..aca3f250 --- /dev/null +++ b/src/tests/integration/data/buffer.wast @@ -0,0 +1,369 @@ + +setExitCode(1) + +uploadWasm( b"test-wasm", +(module + (import "b" "1" (func $bytes_copy_to_linear_memory (param i64 i64 i64 i64) (result i64))) + (import "b" "2" (func $bytes_copy_from_linear_memory (param i64 i64 i64 i64) (result i64))) + (import "b" "4" (func $bytes_new (result i64))) + (import "b" "5" (func $bytes_put (param i64 i64 i64) (result i64))) + (import "b" "6" (func $bytes_get (param i64 i64) (result i64))) + (import "b" "7" (func $bytes_del (param i64 i64) (result i64))) + (import "b" "8" (func $bytes_len (param i64) (result i64))) + (import "b" "9" (func $bytes_push (param i64 i64) (result i64))) + (import "b" "a" (func $bytes_pop (param i64) (result i64))) + (import "b" "b" (func $bytes_front (param i64) (result i64))) + (import "b" "c" (func $bytes_back (param i64) (result i64))) + (import "b" "d" (func $bytes_insert (param i64 i64 i64) (result i64))) + (import "b" "e" (func $bytes_append (param i64 i64) (result i64))) + (import "b" "f" (func $bytes_slice (param i64 i64 i64) (result i64))) + (import "b" "l" (func $symbol_len (param i64) (result i64))) + (func $u32 (param i32) (result i64) + local.get 0 + i64.extend_i32_u + i64.const 32 + i64.shl + i64.const 4 + i64.or + ) + (func $to_and_from (param (; SRC ;) i64 (; DEST ;) i64 (; POS ;) i64) (result i64) + (call $bytes_copy_to_linear_memory + (local.get 0) (call $u32 (i32.const 0)) (call $u32 (i32.const 0)) (call $bytes_len (local.get 0)) + ) + drop + (call $bytes_copy_from_linear_memory + (local.get 1) (local.get 2) (call $u32 (i32.const 0)) (call $bytes_len (local.get 0)) + ) + ) + (func $push_first (param (; SRC ;) i64 (; DEST ;) i64) (result i64) + ;; get the first byte of SRC and push to DEST + (call $bytes_push + (local.get 1) + (call $bytes_front (local.get 0)) + ) + ) + (func $u32_to_bytes (param i64) (result i64) + (call $bytes_push (call $bytes_new) (local.get 0)) + ) + (func $bytes_front_as_bytes (param i64) (result i64) + (call $u32_to_bytes (call $bytes_front (local.get 0))) + ) + (func $bytes_back_as_bytes (param i64) (result i64) + (call $u32_to_bytes (call $bytes_back (local.get 0))) + ) + (memory (;0;) 16) + (export "to_and_from" (func $to_and_from)) + (export "bytes_new" (func $bytes_new)) + (export "bytes_put" (func $bytes_put)) + (export "bytes_get" (func $bytes_get)) + (export "bytes_del" (func $bytes_del)) + (export "push_first" (func $push_first)) + (export "bytes_pop" (func $bytes_pop)) + (export "bytes_front" (func $bytes_front_as_bytes)) + (export "bytes_back" (func $bytes_back_as_bytes)) + (export "bytes_insert" (func $bytes_insert)) + (export "bytes_append" (func $bytes_append)) + (export "bytes_slice" (func $bytes_slice)) + (export "symbol_len" (func $symbol_len)) +) +) + +setAccount(Account(b"test-account"), 9876543210) + +deployContract( + Account(b"test-account"), + Contract(b"test-sc"), + b"test-wasm" +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "to_and_from", + ListItem(ScBytes(b"abc")) ListItem(ScBytes(b"def")) ListItem(U32(0)), + ScBytes(b"abc") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "to_and_from", + ListItem(ScBytes(b"abc")) ListItem(ScBytes(b"def")) ListItem(U32(1)), + ScBytes(b"dabc") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "to_and_from", + ListItem(ScBytes(b"abc")) ListItem(ScBytes(b"def")) ListItem(U32(3)), + ScBytes(b"defabc") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "to_and_from", + ListItem(ScBytes(b"abc")) ListItem(ScBytes(b"def")) ListItem(U32(5)), + ScBytes(b"def\x00\x00abc") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_new", + .List, + ScBytes(b"") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_put", + ListItem(ScBytes(b"abc")) ListItem(U32(0)) ListItem(U32(0)), + ScBytes(b"\x00bc") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_put", + ListItem(ScBytes(b"abc")) ListItem(U32(1)) ListItem(U32(0)), + ScBytes(b"a\x00c") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_put", + ListItem(ScBytes(b"abc")) ListItem(U32(2)) ListItem(U32(0)), + ScBytes(b"ab\x00") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_get", + ListItem(ScBytes(b"\x00\x01\x02")) ListItem(U32(0)), + U32(0) +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_get", + ListItem(ScBytes(b"\x00\x01\x02")) ListItem(U32(1)), + U32(1) +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_get", + ListItem(ScBytes(b"\x00\x01\x02")) ListItem(U32(2)), + U32(2) +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_del", + ListItem(ScBytes(b"abc")) ListItem(U32(0)), + ScBytes(b"bc") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_del", + ListItem(ScBytes(b"abc")) ListItem(U32(1)), + ScBytes(b"ac") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_del", + ListItem(ScBytes(b"abc")) ListItem(U32(2)), + ScBytes(b"ab") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "push_first", + ListItem(ScBytes(b"komet")) ListItem(ScBytes(b"bura")), + ScBytes(b"burak") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "push_first", + ListItem(ScBytes(b"komet")) ListItem(ScBytes(b"")), + ScBytes(b"k") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_pop", + ListItem(ScBytes(b"komet")), + ScBytes(b"kome") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_front", + ListItem(ScBytes(b"komet")), + ScBytes(b"k") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_back", + ListItem(ScBytes(b"komet")), + ScBytes(b"t") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_insert", + ListItem(ScBytes(b"komet")) ListItem(U32(0)) ListItem(U32(0)), + ScBytes(b"\x00komet") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_insert", + ListItem(ScBytes(b"komet")) ListItem(U32(1)) ListItem(U32(7)), + ScBytes(b"k\x07omet") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_insert", + ListItem(ScBytes(b"komet")) ListItem(U32(4)) ListItem(U32(7)), + ScBytes(b"kome\x07t") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_insert", + ListItem(ScBytes(b"")) ListItem(U32(0)) ListItem(U32(7)), + ScBytes(b"\x07") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_append", + ListItem(ScBytes(b"abc")) ListItem(ScBytes(b"def")), + ScBytes(b"abcdef") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_append", + ListItem(ScBytes(b"")) ListItem(ScBytes(b"def")), + ScBytes(b"def") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_append", + ListItem(ScBytes(b"abc")) ListItem(ScBytes(b"")), + ScBytes(b"abc") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_append", + ListItem(ScBytes(b"")) ListItem(ScBytes(b"")), + ScBytes(b"") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_slice", + ListItem(ScBytes(b"abc")) ListItem(U32(0)) ListItem(U32(0)), + ScBytes(b"") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_slice", + ListItem(ScBytes(b"abc")) ListItem(U32(0)) ListItem(U32(1)), + ScBytes(b"a") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_slice", + ListItem(ScBytes(b"abc")) ListItem(U32(0)) ListItem(U32(2)), + ScBytes(b"ab") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_slice", + ListItem(ScBytes(b"abc")) ListItem(U32(0)) ListItem(U32(3)), + ScBytes(b"abc") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_slice", + ListItem(ScBytes(b"abc")) ListItem(U32(1)) ListItem(U32(2)), + ScBytes(b"b") +) + +;; empty slice from the middle +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_slice", + ListItem(ScBytes(b"abc")) ListItem(U32(1)) ListItem(U32(1)), + ScBytes(b"") +) + +;; empty slice from the end +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "bytes_slice", + ListItem(ScBytes(b"abc")) ListItem(U32(3)) ListItem(U32(3)), + ScBytes(b"") +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "symbol_len", + ListItem(Symbol(str("abc"))), + U32(3) +) + +callTx( + Account(b"test-caller"), + Contract(b"test-sc"), + "symbol_len", + ListItem(Symbol(str("1234567890"))), + U32(10) +) + +setExitCode(0) \ No newline at end of file diff --git a/src/tests/integration/data/soroban/contracts/test_bytes/Cargo.toml b/src/tests/integration/data/soroban/contracts/test_bytes/Cargo.toml new file mode 100644 index 00000000..d0bb815a --- /dev/null +++ b/src/tests/integration/data/soroban/contracts/test_bytes/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "test_bytes" +version = "0.0.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] +doctest = false + +[dependencies] +soroban-sdk = { workspace = true } + +[dev-dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } diff --git a/src/tests/integration/data/soroban/contracts/test_bytes/src/lib.rs b/src/tests/integration/data/soroban/contracts/test_bytes/src/lib.rs new file mode 100644 index 00000000..68f14a47 --- /dev/null +++ b/src/tests/integration/data/soroban/contracts/test_bytes/src/lib.rs @@ -0,0 +1,85 @@ +#![no_std] +use soroban_sdk::{contract, contractimpl, Env, Bytes}; + +#[contract] +pub struct BytesContract; + +#[contractimpl] +impl BytesContract { + + pub fn test_put_get(_env: Env, mut bs: Bytes, i: u32, v: u32) -> bool { + if bs.len() < 1 || i >= bs.len() || v > 255 { + return true; + } + + let v = v as u8; + + bs.set(i, v); + + bs.get_unchecked(i) == v + } + + pub fn test_push_and_pop(_env: Env, mut bs: Bytes, v: u32) -> bool { + if v > 255 { + return true; + } + + let init_len = bs.len(); + let v = v as u8; + + bs.push_back(v); + + assert_eq!(init_len + 1, bs.len()); + assert_eq!(v, bs.last_unchecked()); + assert_eq!(v, bs.get_unchecked(bs.len()-1)); + + let v_popped = bs.pop_back_unchecked(); + + assert_eq!(init_len, bs.len()); + assert_eq!(v, v_popped); + + true + } + + pub fn test_insert_is_append_slices(_env: Env, mut bs: Bytes, i: u32, v: u32) -> bool { + if i >= bs.len() || v > 255 { + return true; + } + let v = v as u8; + + let mut res = bs.slice(0..i); + res.push_back(v); + res.append(&bs.slice(i..)); + + bs.insert(i, v); + + res == bs && res.get_unchecked(i) == v + } + + pub fn test_insert_delete_is_id(_env: Env, mut bs: Bytes, i: u32, v: u32) -> bool { + if i >= bs.len() || v > 255 { + return true; + } + let v = v as u8; + let bs_init = bs.clone(); + + bs.insert(i, v); + + assert_eq!(bs.get_unchecked(i), v); + + bs.remove_unchecked(i); + + bs_init == bs + } + + pub fn test_front_and_back(_env: Env, bs: Bytes) -> bool { + if bs.len() < 1 { + return true; + } + + bs.get_unchecked(0) == bs.first_unchecked() + && bs.get_unchecked(bs.len()-1) == bs.last_unchecked() + } +} + +mod test; diff --git a/src/tests/integration/data/soroban/contracts/test_bytes/src/test.rs b/src/tests/integration/data/soroban/contracts/test_bytes/src/test.rs new file mode 100644 index 00000000..5423e128 --- /dev/null +++ b/src/tests/integration/data/soroban/contracts/test_bytes/src/test.rs @@ -0,0 +1,32 @@ +#![cfg(test)] + +use super::*; +use soroban_sdk::Env; + +#[test] +fn test() { + let env = Env::default(); + let contract_id = env.register_contract(None, BytesContract); + let client = BytesContractClient::new(&env, &contract_id); + + let bss = [ + Bytes::from_array(&env, b"asd"), + Bytes::from_array(&env, b"asdqwezzzzzzzzzzzzzzzzzzzxxxxxxxxxxxxxxxxxccccccccccccccc"), + Bytes::from_array(&env, b"") + ]; + + for bs in &bss { + assert!( + client.test_push_and_pop(bs, &0) + ); + } + + for bs in &bss { + for i in 0..bs.len() { + assert!( + client.test_insert_is_append_slices(bs, &i, &0) + ); + } + } + +}