Skip to content

Commit

Permalink
refactor: move README contents to a wiki
Browse files Browse the repository at this point in the history
  • Loading branch information
mpolitzer committed Jun 4, 2024
1 parent 194a7df commit cd65bce
Showing 1 changed file with 0 additions and 205 deletions.
205 changes: 0 additions & 205 deletions sys-utils/libcmt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,208 +128,3 @@ cast calldata-decode "Notice(bytes)" 0x`xxd -p -c0 "$1"` | (
# sh decode-notice.sh $1 | jq '.bytes' | xxd -r
```

# binds

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

## Python

Python has multiple Foreign Function Interface (FFI) options for interoperability with C.
This example uses CFFI and the `libcmt` mock. Which is assumed to be installed at `./libcmt-0.1.0`.

This document uses the [main mode](https://cffi.readthedocs.io/en/latest/overview.html#main-mode-of-usage) of CFFI and works in two steps: `build`, then `use`.

### Build

The `build` step has the objective of creating a python module for libcmt.
To achieve this we'll use `libcmt/ffi.h` and the script below.
Paths may need adjustments.

```
import os
from cffi import FFI
ffi = FFI()
with open(os.path.join(os.path.dirname(__file__), "../libcmt-0.1.0/usr/include/libcmt/ffi.h")) as f:
ffi.cdef(f.read())
ffi.set_source("pycmt",
"""
#include "libcmt/rollup.h"
""",
include_dirs=["libcmt-0.1.0/usr/include"],
library_dirs=["libcmt-0.1.0/usr/lib"],
libraries=['cmt'])
if __name__ == "__main__":
ffi.compile(verbose=True)
```

### Use

With the module built, we can import it with python and use its functions.
This example uses the raw bindings and just serves to illustrate the process.
Better yet would be to wrap these functions into a more "pythonic" API.

`LD_LIBRARY_PATH=libcmt-0.1.0/lib/ python`

```
#!/usr/bin/env python
# run this file only after building pycmt!
import os
from pycmt.lib import ffi, lib
r = ffi.new("cmt_rollup_t[1]")
assert(lib.cmt_rollup_init(r) == 0)
address = ffi.new("uint8_t[20]", b"1000000000000")
value = ffi.new("uint8_t[32]", b"0000000000001")
data = b"hello world"
index = ffi.new("uint64_t *")
print(os.strerror(-lib.cmt_rollup_emit_voucher(r,
20, address,
32, value,
len(data), data, index)))
ffi.gc(r, lib.cmt_rollup_fini)
```

Common errors such as the one below indicate that python couldn't find libcmt,
make sure `LD_LIBRARY_PATH` points to the correct directory, or better yet, link
against the static library.

```
>>> import pycmt
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: libcmt.so: cannot open shared object file: No such file or directory
```

## Go

Go is able to include C headers directly with cgo.

The application can be compiled with: `go build main.go`.
Assuming that the mock was installed at `./libcmt-0.1.0`.
For the actual risc-v binaries, use:
```
CC=riscv64-linux-gnu-gcc-12 CGO_ENABLED=1 GOOS=linux GOARCH=riscv64 go build
```

In Debian, the cross compiler can be obtained with:
```
apt-get install crossbuild-essential-riscv64 gcc-12-riscv64-linux-gnu g++-12-riscv64-linux-gnu
```

(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, NULL)
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'
```

0 comments on commit cd65bce

Please sign in to comment.