Skip to content

Commit

Permalink
refactor: add cffi instructions for python bindings and and ffi to th…
Browse files Browse the repository at this point in the history
…e distribution
  • Loading branch information
mpolitzer committed May 10, 2024
1 parent dcee7bc commit 63da59f
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 6 deletions.
12 changes: 8 additions & 4 deletions sys-utils/libcmt/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,12 @@ $(libcmt_SO): $(libcmt_OBJ)
$(TARGET_CC) -shared -o $@ $^

libcmt: $(libcmt_LIB) $(libcmt_SO)
install: $(libcmt_LIB) $(libcmt_SO)
install: $(libcmt_LIB) $(libcmt_SO) build/ffi.h
mkdir -p $(TARGET_DESTDIR)$(TARGET_PREFIX)/lib
cp -f $^ $(TARGET_DESTDIR)$(TARGET_PREFIX)/lib
cp -f $(libcmt_LIB) $(libcmt_SO) $(TARGET_DESTDIR)$(TARGET_PREFIX)/lib
mkdir -p $(TARGET_DESTDIR)$(TARGET_PREFIX)/include/libcmt/
cp -f src/*.h $(TARGET_DESTDIR)$(TARGET_PREFIX)/include/libcmt/
cp -f build/ffi.h $(TARGET_DESTDIR)$(TARGET_PREFIX)/include/libcmt/
mkdir -p $(TARGET_DESTDIR)$(TARGET_PREFIX)/lib/pkgconfig
sed -e 's|@ARG_PREFIX@|$(TARGET_PREFIX)|g' src/libcmt.pc > $(TARGET_DESTDIR)$(TARGET_PREFIX)/lib/pkgconfig/libcmt.pc

Expand Down Expand Up @@ -121,11 +122,12 @@ $(mock_SO): $(mock_OBJ)

mock: $(mock_LIB) $(mock_SO)

install-mock: $(mock_LIB) $(mock_SO)
install-mock: $(mock_LIB) $(mock_SO) build/ffi.h
mkdir -p $(DESTDIR)$(PREFIX)/lib
cp -f $^ $(DESTDIR)$(PREFIX)/lib
cp -f $(mock_LIB) $(mock_SO) $(DESTDIR)$(PREFIX)/lib
mkdir -p $(DESTDIR)$(PREFIX)/include/libcmt/
cp -f src/*.h $(DESTDIR)$(PREFIX)/include/libcmt/
cp -f build/ffi.h $(DESTDIR)$(PREFIX)/include/libcmt/
mkdir -p $(DESTDIR)$(PREFIX)/lib/pkgconfig
sed -e 's|@ARG_PREFIX@|$(PREFIX)|g' src/libcmt_mock.pc > $(DESTDIR)$(PREFIX)/lib/pkgconfig/libcmt.pc

Expand Down Expand Up @@ -181,6 +183,8 @@ $(tools_OBJDIR)/funsel: tools/funsel.c $(mock_LIB)

tools: $(tools_BINS)

build/ffi.h: src/buf.h src/abi.h src/keccak.h src/merkle.h src/io.h src/rollup.h
cat $^ | sh tools/prepare-ffi.sh > $@
#-------------------------------------------------------------------------------
LINTER_IGNORE_SOURCES=src/io.c
LINTER_IGNORE_HEADERS=
Expand Down
77 changes: 75 additions & 2 deletions sys-utils/libcmt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ 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
can be achieved multiple ways, including writing tools with this library. A
simple way to generate testing data is to use the @p cast tool from
[foundry](http://book.getfoundry.sh/reference/cast/cast.html) and `xxd`.

Expand Down Expand Up @@ -132,7 +132,80 @@ cast calldata-decode "Notice(bytes)" 0x`xxd -p -c0 "$1"` | (
# binds

This library is intented to be used with programming languages other than C.
They acheive this by different means.
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 ilustrate 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

Expand Down
9 changes: 9 additions & 0 deletions sys-utils/libcmt/tools/prepare-ffi.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh

sed \
-e '/\/\*/,/\*\//d' \
-e '/#if\s/,/#endif/d' \
-e '/#define/d' \
-e '/#endif/d' \
-e '/#ifndef/d' \
-e '/#include/d' \

0 comments on commit 63da59f

Please sign in to comment.