Skip to content

Commit

Permalink
feat!: add value to voucher
Browse files Browse the repository at this point in the history
  • Loading branch information
mpolitzer committed Jan 31, 2024
1 parent d447123 commit b30e42b
Show file tree
Hide file tree
Showing 14 changed files with 494 additions and 786 deletions.
7 changes: 3 additions & 4 deletions sys-utils/ioctl-echo-loop/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,8 @@ RVCXX = $(TOOLCHAIN_PREFIX)g++
RVCOPY = $(TOOLCHAIN_PREFIX)objcopy
RVDUMP = $(TOOLCHAIN_PREFIX)objdump
STRIP = $(TOOLCHAIN_PREFIX)strip
CFLAGS :=-Wall -Wextra -pedantic -O2 \
`PKG_CONFIG_PATH=/usr/riscv64-linux-gnu/lib/pkgconfig pkg-config --cflags libcmt`
LDLIBS := \
`PKG_CONFIG_PATH=/usr/riscv64-linux-gnu/lib/pkgconfig pkg-config --libs libcmt`
CFLAGS +=-Wall -Wextra -pedantic -O2 `pkg-config --cflags libcmt`
LDLIBS += `pkg-config --libs libcmt`

CONTAINER_MAKE := /usr/bin/make
CONTAINER_BASE := /opt/cartesi/tools
Expand All @@ -45,6 +43,7 @@ ioctl-echo-loop.with-toolchain with-toolchain:
extra.ext2.with-toolchain:
$(MAKE) toolchain-exec CONTAINER_COMMAND="$(CONTAINER_MAKE) $@.toolchain"

ioctl-echo-loop: export PKG_CONFIG_PATH ?= /usr/riscv64-linux-gnu/lib/pkgconfig
ioctl-echo-loop: ioctl-echo-loop.c
$(RVCC) $(CFLAGS) -o ioctl-echo-loop ioctl-echo-loop.c $(LDLIBS)
$(STRIP) ioctl-echo-loop
Expand Down
2 changes: 1 addition & 1 deletion sys-utils/ioctl-echo-loop/ioctl-echo-loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ static int write_notices(cmt_rollup_t *me, unsigned count, uint32_t length, cons
static int write_vouchers(cmt_rollup_t *me, unsigned count, uint8_t destination[CMT_ADDRESS_LENGTH]
,uint32_t length, const void *data) {
for (unsigned i = 0; i < count; i++) {
int rc = cmt_rollup_emit_voucher(me, destination, length, data);
int rc = cmt_rollup_emit_voucher(me, CMT_ADDRESS_LENGTH, destination, 0, NULL, length, data);
if (rc) return rc;
}
return 0;
Expand Down
231 changes: 231 additions & 0 deletions sys-utils/libcmt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,234 @@ And finally, a couple of utility modules used by the high level API are also exp

The header files and a compiled RISC-V version of this library can be found [here](https://github.com/cartesi/machine-emulator-tools/).
We also provide `.pc` (pkg-config) files to facilitate linking.

# mock and testing

This library provides a mock implementation of @ref libcmt\_io\_driver that is
able to simulate requests and replies on the host machine.

- Build it with: `make mock.build`.
- Install it with: `make mock.install`, use `PREFIX` to specify the installation path:
(The command below will install the library and headers on `$PWD/_install` directory)
```
make mock.install PREFIX=_install
```

## testing

Use the environment variable @p CMT\_INPUTS to inject inputs into the application compiled with the mock.
Outputs will be written to files with names derived from the input name.

example:
```
CMT_INPUTS="0:advance.bin" ./application
```

The first output will generate the file:
```
advance.output-0.bin
```

The first report will generate the file:
```
advance.report-0.bin
```

The first exception will generate the file:
```
advance.exception-0.bin
```

The (verifiable) outputs root hash:
```
advance.outputs_root_hash.bin
```

inputs must follow this syntax, a comma separated list of reason number followed by a filepath:
```
CMT_INPUTS="<reason-number> ':' <filepath> ( ',' <reason-number> ':' <filepath> ) *"
```

In addition to @p CMT\_INPUTS, there is also the @p CMT\_DEBUG variable. Enable it
for a verbose version of the low level calls.

```
CMT_DEBUG=yes ./application
```

## generating inputs

Inputs and Outputs are expected to be EVM-ABI encoded. Encoding and decoding
can be acheived multiple ways, including writing tools with this library. A
simple way for testing is to use the @p cast tool from
[foundry](http://book.getfoundry.sh/reference/cast/cast.html) and `xxd`.

Encoding an @p EvmAdvance:
```
cast calldata "EvmAdvance(address,uint256,uint256,uint256,bytes)" \
0x0000000000000000000000000000000000000000 \
0x0000000000000000000000000000000000000000 \
0x0000000000000000000000000000000000000000 \
0x0000000000000000000000000000000000000000 \
0x`echo "advance-0" | xxd -p -c0` | xxd -r -p > 0.bin
```

Encoding an @p EvmInspect:
```
cast calldata "EvmInspect(bytes)" \
0x`echo "inspect-0" | xxd -p -c0` | xxd -r -p > 1.bin
```

## parsing outputs

Decoding a @p Voucher:
```
cast calldata-decode "Voucher(address,uint256,bytes)" 0x`xxd -p -c0 "$1"` | (
read address
read value
read bytes
echo "{"
printf '\t"address" : "%s",\n' $address
printf '\t"value" : "%s",\n' $value
printf '\t"bytes" : "%s"\n' $bytes
echo "}"
)
# sh decode-voucher.sh $1 | jq '.bytes' | xxd -r
```

Decoding a @p Notice:
```
cast calldata-decode "Notice(bytes)" 0x`xxd -p -c0 "$1"` | (
read bytes
echo "{"
printf '\t"bytes" : "%s"\n' $bytes
echo "}"
)
# sh decode-notice.sh $1 | jq '.bytes' | xxd -r
```

# binds

This library is intented to be used with programming languages other than C.
They acheive this by different means.

## Go

Go is able to include C headers directly.

The application can be compiled with: `go build main.go`. Assuming that the
mock was installed at `./libcmt-0.1.0`.
(Code below is for demonstration purposes and not intended for production)

```
package main
/*
#cgo CFLAGS: -Ilibcmt-0.1.0/include/
#cgo LDFLAGS: -Llibcmt-0.1.0/lib/ -lcmt
#include "libcmt/rollup.h"
*/
import "C"
import (
"math/big"
"fmt"
"unsafe"
)
func main() {
var rollup C.cmt_rollup_t
err := C.cmt_rollup_init(&rollup)
if err != 0 {
fmt.Printf("initialization failed\n")
}
bytes_s := []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
}
wei := new(big.Int).SetBytes(bytes_s)
finish := C.cmt_rollup_finish_t{
accept_previous_request: true,
}
for {
var advance C.cmt_rollup_advance_t
err = C.cmt_rollup_finish(&rollup, &finish)
if err != 0 { return; }
err = C.cmt_rollup_read_advance_state(&rollup, &advance);
if err != 0 { return; }
bytes:= wei.Bytes()
size := len(bytes)
C.cmt_rollup_emit_voucher(&rollup,
C.CMT_ADDRESS_LENGTH, &advance.sender[0],
C.uint(size), unsafe.Pointer(&bytes[0]),
advance.length, advance.data)
C.cmt_rollup_emit_report(&rollup, advance.length, advance.data)
}
}
```

## Rust

Rust interop with C requires bindings to be generated, we'll use bindgen to
accomplish this.

Create the initial directory layout with `cargo`, then add the library to it:
```
cargo init --bin cmt
# download the library and extract it into cmt/libcmt-0.1.0
cd cmt
```

Generate the bindings, execute:
```
# join all header files into one.
cat libcmt-0.1.0/include/libcmt/*.h > src/libcmt.h
# generate the bindings
bindgen src/libcmt.h -o src/bindings.rs --allowlist-function '^cmt_.*' --allowlist-type '^cmt_.*' --no-doc-comments -- -I libcmt-0.1.0/include/libcmt
```

Include the bindings to the project, add the following to: `src/lib.rs`
```
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!("bindings.rs");
```

Tell cargo to link with the C library, add the following to: `build.rs`
```
fn main() {
println!("cargo:rustc-link-search=libcmt-0.1.0/lib");
println!("cargo:rustc-link-lib=cmt");
}
```

An example of the raw calls to C, add the following to: `src/main.rs`
```
use std::mem;
fn main() {
let mut rollup: cmt::cmt_rollup_t = unsafe { mem::zeroed() };
let rc = unsafe { cmt::cmt_rollup_init(&mut rollup) };
println!("got return value: {}!", rc);
}
```

Messages like the one below most likely mean that cargo didn't find the library
`libcmt.a` or `build.rs` is incomplete:
```
undefined reference to `cmt_rollup_emit_voucher'
```
2 changes: 1 addition & 1 deletion sys-utils/libcmt/doc/examples/rollup.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ int main(void) {
break;
}

rc = cmt_rollup_emit_voucher(&rollup, advance.sender, advance.length, advance.data);
rc = cmt_rollup_emit_voucher(&rollup, sizeof advance.sender, advance.sender, 0, NULL, advance.length, advance.data);
if (rc < 0) {
fprintf(stderr, "%s:%d Error on voucher %s (%d)\n", __FILE__, __LINE__, strerror(-rc), (-rc));
break;
Expand Down
45 changes: 45 additions & 0 deletions sys-utils/libcmt/include/libcmt/abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,39 @@ int cmt_abi_put_funsel(cmt_buf_t *me, uint32_t funsel);
* @note This function takes care of endianess conversions */
int cmt_abi_put_uint(cmt_buf_t *me, size_t n, const void *data);

/** Encode a big-endian value of up to 32bytes of data into the buffer
*
* @param [in,out] me a initialized buffer working as iterator
* @param [in] length size of @p data in bytes
* @param [in] data poiter to a integer
*
* @return
* - 0 success
* - ENOBUFS no space left in @p me
* - EDOM requested @p n is too large
*
* @code
* ...
* cmt_buf_t it = ...;
* uint8_t small[] = {
* 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
* 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
* 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
* 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
* };
* cmt_abi_put_uint(&it, sizeof small, &small);
* ...
* uint8_t big[] = {
* 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
* 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
* 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
* 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
* };
* cmt_abi_put_uint(&it, sizeof big, &big);
* @endcode
* @note This function takes care of endianess conversions */
int cmt_abi_put_uint_be(cmt_buf_t *me, size_t n, const void *data);

/** Encode a bool into the buffer
*
* @param [in,out] me a initialized buffer working as iterator
Expand Down Expand Up @@ -282,6 +315,18 @@ int cmt_abi_check_funsel(cmt_buf_t *me, uint32_t expected);
* - EDOM value won't fit into @p n bytes. */
int cmt_abi_get_uint(cmt_buf_t *me, size_t n, void *data);

/** Decode @p length big-endian bytes, up to 32, from the buffer into @p data
*
* @param [in,out] me initialized buffer
* @param [in] length size of @p data in bytes
* @param [out] data pointer to a integer
*
* @return
* - 0 success
* - ENOBUFS no space left in @p me
* - EDOM value won't fit into @p n bytes. */
int cmt_abi_get_uint_be(cmt_buf_t *me, size_t n, void *data);

/** Consume and decode @b address from the buffer
*
* @param [in,out] me initialized buffer
Expand Down
13 changes: 8 additions & 5 deletions sys-utils/libcmt/include/libcmt/rollup.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* Rollup abstraction layer
*
* Takes care of @ref libcmt_io_driver interactions, @ref libcmt_abi
* encoding/decoding and @ref libcmt_merkle tree interactions.
* encoding/decoding and @ref libcmt_merkle tree handling.
*
* Mocked version has support for simulating I/O via environment variables:
* @p CMT_INPUTS="0:input.bin,..." and verbose ouput with @p CMT_DEBUG=yes.
Expand Down Expand Up @@ -89,7 +89,10 @@ void cmt_rollup_fini(cmt_rollup_t *me);
* @return
* - 0 success
* - -ENOBUFS no space left in @p me */
int cmt_rollup_emit_voucher(cmt_rollup_t *me, uint8_t address[CMT_ADDRESS_LENGTH], size_t n, const void *data);
int cmt_rollup_emit_voucher(cmt_rollup_t *me,
uint32_t address_length, const void *address_data,
uint32_t value_length, const void *value_data,
uint32_t length, const void *data);

/** Emit a notice
*
Expand All @@ -99,7 +102,7 @@ int cmt_rollup_emit_voucher(cmt_rollup_t *me, uint8_t address[CMT_ADDRESS_LENGTH
* @return
* - 0 success
* - -ENOBUFS no space left in @p me */
int cmt_rollup_emit_notice(cmt_rollup_t *me, size_t n, const void *data);
int cmt_rollup_emit_notice(cmt_rollup_t *me, uint32_t length, const void *data);

/** Emit a report
* @param [in,out] me initialized cmt_rollup_t instance
Expand All @@ -108,7 +111,7 @@ int cmt_rollup_emit_notice(cmt_rollup_t *me, size_t n, const void *data);
* @return
* - 0 success
* - -ENOBUFS no space left in @p me */
int cmt_rollup_emit_report(cmt_rollup_t *me, size_t n, const void *data);
int cmt_rollup_emit_report(cmt_rollup_t *me, uint32_t length, const void *data);

/** Emit a exception
* @param [in,out] me initialized cmt_rollup_t instance
Expand All @@ -117,7 +120,7 @@ int cmt_rollup_emit_report(cmt_rollup_t *me, size_t n, const void *data);
* @return
* - 0 success
* - -ENOBUFS no space left in @p me */
int cmt_rollup_emit_exception(cmt_rollup_t *me, size_t n, const void *data);
int cmt_rollup_emit_exception(cmt_rollup_t *me, uint32_t length, const void *data);

/** Read advance state
*
Expand Down
Loading

0 comments on commit b30e42b

Please sign in to comment.