rlp仍然是上次写的rlp代码
我们利用下面的命令行创建c-shared dll与python对接.
go build -buildmode=c-shared -o verifyproof.dll .\verifyproof.go
注意cgo采用了magic comment的方法.所有需要export的函数需要在前面注释上:
//export yourfunctionname
func yourfunctionname ...
本次任务的难点是如何传[]string
参数
显然如果在C语言中这是一个**char
变量.
转化逻辑如下:
func stringPtrToStringSlice(stringPtr **C.char, slicelen C.size_t) []string {
strslice := make([]string, 0, slicelen)
var unblock unsafe.Pointer
for idx := C.size_t(0); idx < slicelen; idx++ {
unblock = unsafe.Pointer(uintptr(unsafe.Pointer(stringPtr)) + uintptr(idx * CHAR_P_SIZE))
strslice = append(strslice, C.GoString(*((**C.char)(unblock))))
}
return strslice;
}
因为go的内存管理和C-DLL的内存管理独立,所以设计下面的方法控制eth-db.
var dbPacket = make([]*leveldb.DB, 0, 64)
var dbpi = 0
//export openDB
func openDB(dbpath *C.char) C.int {
db, err := leveldb.OpenFile(C.GoString(dbpath), nil)
if err != nil {
fmt.Println("link error")
fmt.Println(err)
return C.int(0)
}else {
dbPacket = append(dbPacket, db)
dbpi++
return C.int(dbpi - 1);
}
}
//export closeDB
func closeDB(dbpi C.int) {
db := dbPacket[dbpi]
db.Close();
}
剩下的逻辑与之前没有差异
简单地写出python内的实现代码:
from ctypes import *
from hexbytes import HexBytes
PROVER_PATH = "./scripts/verifyproof.dll"
EDB_PATH = "D:/Go Ethereum/data/geth/chaindata"
ENC = "utf-8"
StorageHash = b"0x11e91152ab237ceff29728c03999ef2debadd7db0fc45b280657c6f7cc4c1ffa"
StoragePath = ["f8918080a06d032ff808e3a2b585df339916901d7b7d04c5bd18a088607093d3178172b7ee8080808080a0071b011fdbd4ad7d1e6f9762be4d1a88dffde614a6bd399bf3b5bad8f41249b5808080a01b56cc0a5b9b1ce34e9a14e896ea000c830bd64387573d238cbe3fa24ddfa2c3a0f5c2efa606e3a5be341f22bf1d5c8f4bce679719870c097a24abb38aec0a4855808080", "f8518080808080a06f643b8fd2176a403e2ccfae43808c4543289e1082078e91d821d1c7886d6f51808080a03822ab26403807d175522401e184b20b5aa8c7fcd802f4793970a70e810f4ce980808080808080", "e2a0200decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56333"]
key = b"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"
val = b"0x33"
GoInt8 = c_int8
GoInt16 = c_int16
GoInt32 = c_int32
GoInt64 = c_int64
GoUint8 = c_uint8
GoUint16 = c_uint16
GoUint32 = c_uint32
GoUint64 = c_uint64
GoInt = GoUint64
GoUInt = GoUint64
GoBytes = c_char_p
GoString = POINTER(c_char)
GoStringSlice = POINTER(GoString)
dbptr = GoInt32
funcs = CDLL(PROVER_PATH)
funcs.openDB.restype = dbptr
funcs.openDB.argtype = GoString
funcs.closeDB.argtype = dbptr
funcs.VerifyProof.restype = GoInt32
funcs.VerifyProof.argtypes = (dbptr, GoString, GoString, GoString, GoStringSlice, GoInt32)
class Prover:
def __init__(self, path):
self.ethdb = funcs