Skip to content

Commit

Permalink
api: sample cgo client to call silkworm_api lib (#1427)
Browse files Browse the repository at this point in the history
  • Loading branch information
mriccobene authored Aug 9, 2023
1 parent 7ee6896 commit 60106e1
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 16 deletions.
21 changes: 21 additions & 0 deletions cmd/api/sample-go-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# A sample go application that loads Silkworm API library

## Prerequisites
- c++ toolchain (required to compile cgo code)
- go toolchain

## Build & Run
1. build the silkworm library
2. go to the sample-go-client directory and build the go application specifying the path of the silkworm library:

```bash
CGO_LDFLAGS="-L/home/user/silkworm/build_debug/silkworm/api -lsilkworm_api -lstdc++ -ldl" go build
```

3. run the application with the environment variable LD_LIBRARY_PATH set to find the silkworm library:

```bash
export LD_LIBRARY_PATH=/home/user/silkworm/build_debug/silkworm/api
./sample-go-client
```

35 changes: 35 additions & 0 deletions cmd/api/sample-go-client/load.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

/*
#cgo LDFLAGS: -ldl
#include <dlfcn.h>
#include <stdlib.h>
*/
import "C"

import (
"fmt"
"unsafe"
)

func OpenDynLibrary(dllPath string) (unsafe.Pointer, error) {
cPath := C.CString(dllPath)
defer C.free(unsafe.Pointer(cPath))
dllHandle := C.dlopen(cPath, C.RTLD_LAZY)
if dllHandle == nil {
err := C.GoString(C.dlerror())
return nil, fmt.Errorf("failed to load dynamic library %s: %s", dllPath, err)
}
return dllHandle, nil
}

func LoadFunction(dllHandle unsafe.Pointer, funcName string) (unsafe.Pointer, error) {
cName := C.CString(funcName)
defer C.free(unsafe.Pointer(cName))
funcPtr := C.dlsym(dllHandle, cName)
if funcPtr == nil {
err := C.GoString(C.dlerror())
return nil, fmt.Errorf("failed to find the %s function: %s", funcName, err)
}
return funcPtr, nil
}
11 changes: 11 additions & 0 deletions cmd/api/sample-go-client/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

func main() {
var silkworm Silkworm

LoadSilkworm(&silkworm, "libsilkworm_api.so")

silkworm.Init()
//silkworm.AddSnapshot()
silkworm.Fini()
}
72 changes: 72 additions & 0 deletions cmd/api/sample-go-client/silkworm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package main

/*
// compiler flags:
//#cgo CXXFLAGS: -std=c++14
#cgo CFLAGS: -I${SRCDIR}/../../../silkworm/api
// linker flags: it is better to specify LDFLAGS at build time because the silkworm build dir is user specific
// #cgo LDFLAGS: -L${SRCDIR}/../../../build_debug/silkworm/api -lsilkworm_api -lstdc++ -ldl
#include "silkworm_api.h"
#include <stdlib.h>
typedef int (*silkworm_init_func)(SilkwormHandle** handle);
int call_silkworm_init_func(void* func_ptr, SilkwormHandle** handle) {
return ((silkworm_init_func)func_ptr)(handle);
}
typedef int (*silkworm_fini_func)(SilkwormHandle* handle);
int call_silkworm_fini_func(void* func_ptr, SilkwormHandle* handle) {
return ((silkworm_fini_func)func_ptr)(handle);
}
typedef int (*silkworm_add_snapshot_func)(SilkwormHandle* handle, struct SilkwormChainSnapshot* snapshot);
int call_silkworm_add_snapshot_func(void* func_ptr, SilkwormHandle* handle, struct SilkwormChainSnapshot* snapshot) {
return ((silkworm_add_snapshot_func)func_ptr)(handle, snapshot);
}
*/
import "C"
import (
"fmt"
"unsafe"
)

type Silkworm struct {
libHandle unsafe.Pointer
instance *C.SilkwormHandle
initFunc unsafe.Pointer
finiFunc unsafe.Pointer
addSnapshot unsafe.Pointer
}

func LoadSilkworm(silkworm *Silkworm, dllPath string) {
silkworm.libHandle, _ = OpenDynLibrary(dllPath)
if silkworm.libHandle == nil {
panic(fmt.Errorf("failed to load silkworm dynamic library"))
}

silkworm.initFunc, _ = LoadFunction(silkworm.libHandle, "silkworm_init")
silkworm.finiFunc, _ = LoadFunction(silkworm.libHandle, "silkworm_fini")
silkworm.addSnapshot, _ = LoadFunction(silkworm.libHandle, "silkworm_add_snapshot")

if silkworm.initFunc == nil || silkworm.finiFunc == nil {
panic(fmt.Errorf("failed to find all silkworm functions"))
}
}

func (silkworm *Silkworm) Init() {
C.call_silkworm_init_func(silkworm.initFunc, &silkworm.instance)
}

func (silkworm *Silkworm) Fini() {
C.call_silkworm_fini_func(silkworm.finiFunc, silkworm.instance)
}

func (silkworm *Silkworm) AddSnapshot(snapshot *C.struct_SilkwormChainSnapshot) {
C.call_silkworm_add_snapshot_func(silkworm.addSnapshot, silkworm.instance, snapshot)
}
30 changes: 14 additions & 16 deletions silkworm/api/silkworm_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,9 @@

// C API exported by Silkworm to be used in Erigon.

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#include <mdbx.h>
#pragma GCC diagnostic pop
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>

#if defined _MSC_VER
#define SILKWORM_EXPORT __declspec(dllexport)
Expand All @@ -43,6 +39,8 @@
extern "C" {
#endif

typedef struct MDBX_txn MDBX_txn;

#define SILKWORM_OK 0 /* Successful result */
#define SILKWORM_INTERNAL_ERROR 1
#define SILKWORM_UNKNOWN_ERROR 2
Expand All @@ -68,28 +66,28 @@ struct SilkwormMemoryMappedFile {
};

struct SilkwormHeadersSnapshot {
SilkwormMemoryMappedFile segment;
SilkwormMemoryMappedFile header_hash_index;
struct SilkwormMemoryMappedFile segment;
struct SilkwormMemoryMappedFile header_hash_index;
};

struct SilkwormBodiesSnapshot {
SilkwormMemoryMappedFile segment;
SilkwormMemoryMappedFile block_num_index;
struct SilkwormMemoryMappedFile segment;
struct SilkwormMemoryMappedFile block_num_index;
};

struct SilkwormTransactionsSnapshot {
SilkwormMemoryMappedFile segment;
SilkwormMemoryMappedFile tx_hash_index;
SilkwormMemoryMappedFile tx_hash_2_block_index;
struct SilkwormMemoryMappedFile segment;
struct SilkwormMemoryMappedFile tx_hash_index;
struct SilkwormMemoryMappedFile tx_hash_2_block_index;
};

struct SilkwormChainSnapshot {
SilkwormHeadersSnapshot headers;
SilkwormBodiesSnapshot bodies;
SilkwormTransactionsSnapshot transactions;
struct SilkwormHeadersSnapshot headers;
struct SilkwormBodiesSnapshot bodies;
struct SilkwormTransactionsSnapshot transactions;
};

SILKWORM_EXPORT int silkworm_add_snapshot(SilkwormHandle* handle, SilkwormChainSnapshot* snapshot) SILKWORM_NOEXCEPT;
SILKWORM_EXPORT int silkworm_add_snapshot(SilkwormHandle* handle, struct SilkwormChainSnapshot* snapshot) SILKWORM_NOEXCEPT;

/** \brief Execute a batch of blocks and write resulting changes into the database.
*
Expand Down

0 comments on commit 60106e1

Please sign in to comment.