-
Notifications
You must be signed in to change notification settings - Fork 0
/
liboracle.go
130 lines (106 loc) · 2.92 KB
/
liboracle.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package liboracle
import (
"fmt"
"runtime"
"unsafe"
)
// #cgo CFLAGS: -std=gnu11 -pthread -fno-omit-frame-pointer
// #cgo pkg-config: libcurl libcjson
// #include "liboracle.h"
/*
void _add_address_to_query(rcl_query_t* query, _GoString_* strs) {
for (size_t i = 0; i < query->alen; ++i)
query->address[i].encoded = _GoStringPtr(strs[i]);
}
void _add_topics_to_query(rcl_query_t* query, size_t j, _GoString_* strs) {
for (size_t i = 0; i < query->tlen[j]; ++i)
query->topics[j][i].encoded = _GoStringPtr(strs[i]);
}
*/
import "C"
type Query struct { // see rcl_query_t
Limit *uint64
FromBlock uint64
ToBlock uint64
Addresses []string
Topics [][]string
}
type Conn struct {
db *C.rcl_t
}
func rcl_error(code C.rcl_result) error {
if code == C.RCLE_OK {
return nil
}
return fmt.Errorf("liboracle error: " + C.GoString(C.rcl_strerror(code)))
}
func NewDB(data_dir string, ram_limit uint64) (*Conn, error) {
data_dir_cstr := C.CString(data_dir)
defer C.free(unsafe.Pointer(data_dir_cstr))
var db *C.rcl_t
rc := C.rcl_open(data_dir_cstr, C.uint64_t(ram_limit), &db)
return &Conn{db: db}, rcl_error(rc)
}
func (conn *Conn) Close() {
C.rcl_free(conn.db)
}
func (conn *Conn) UpdateHeight(height uint64) error {
rc := C.rcl_update_height(conn.db, C.uint64_t(height))
return rcl_error(rc)
}
func (conn *Conn) SetUpstream(upstream string) error {
upstream_cstr := C.CString(upstream)
defer C.free(unsafe.Pointer(upstream_cstr))
rc := C.rcl_set_upstream(conn.db, upstream_cstr)
return rcl_error(rc)
}
func (conn *Conn) Query(query *Query) (uint64, error) {
var pinner runtime.Pinner
pinner.Pin(query)
defer pinner.Unpin()
if len(query.Topics) > len(query.Topics) {
return 0, fmt.Errorf("too many topics")
}
tlen := [C.TOPICS_LENGTH]C.size_t{0}
for i := 0; i < len(query.Topics); i++ {
tlen[i] = C.size_t(len(query.Topics[i]))
}
var cquery *C.rcl_query_t = nil
rc := C.rcl_query_alloc(
&cquery,
C.size_t(len(query.Addresses)),
&(tlen[0]),
)
if rc != C.RCLE_OK {
return 0, rcl_error(rc)
}
defer C.rcl_query_free(cquery)
cquery.from = C.uint64_t(query.FromBlock)
cquery.to = C.uint64_t(query.ToBlock)
if query.Limit != nil {
cquery.limit = C.uint64_t(*(query.Limit))
} else {
cquery.limit = C.uint64_t(0)
}
if len(query.Addresses) > 0 {
C._add_address_to_query(cquery, &(query.Addresses[0]))
}
for i := 0; i < len(query.Topics); i++ {
if len(query.Topics[i]) > 0 {
C._add_topics_to_query(cquery, C.size_t(i), &(query.Topics[0][i]))
}
}
var count C.uint64_t
rc = C.rcl_query(conn.db, (*C.rcl_query_t)(unsafe.Pointer(cquery)), &count)
return uint64(count), rcl_error(rc)
}
func (conn *Conn) GetLogsCount() (uint64, error) {
var result C.uint64_t
rc := C.rcl_logs_count(conn.db, &result)
return uint64(result), rcl_error(rc)
}
func (conn *Conn) GetBlocksCount() (uint64, error) {
var result C.uint64_t
rc := C.rcl_blocks_count(conn.db, &result)
return uint64(result), rcl_error(rc)
}