-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add libcmt and gollup packages
- Loading branch information
Showing
2 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// (c) Cartesi and individual authors (see AUTHORS) | ||
// SPDX-License-Identifier: Apache-2.0 (see LICENSE) | ||
|
||
package gollup | ||
|
||
import "github.com/cartesi/rollups-node/pkg/libcmt" | ||
|
||
type OutputEmitter interface { | ||
SendVoucher(address [20]byte, value []byte, data []byte) (uint64, error) | ||
SendNotice(data []byte) (uint64, error) | ||
SendReport(data []byte) error | ||
RaiseException(data []byte) error | ||
} | ||
|
||
type ReportEmitter interface { | ||
SendReport(data []byte) error | ||
RaiseException(data []byte) error | ||
} | ||
|
||
// ------------------------------------------------------------------------------------------------ | ||
|
||
type AdvanceHandler func(OutputEmitter, *libcmt.Input) bool | ||
|
||
type InspectHandler func(ReportEmitter, *libcmt.Query) bool | ||
|
||
type Gollup struct { | ||
rollup *libcmt.Rollup | ||
advanceHandler AdvanceHandler | ||
inspectHandler InspectHandler | ||
} | ||
|
||
func New(advanceHandler AdvanceHandler, inspectHandler InspectHandler) (*Gollup, error) { | ||
rollup, err := libcmt.NewRollup() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &Gollup{rollup, advanceHandler, inspectHandler}, nil | ||
} | ||
|
||
func (gollup *Gollup) Destroy() { | ||
gollup.rollup.Destroy() | ||
} | ||
|
||
func (gollup *Gollup) Run() error { | ||
accept := true | ||
for { | ||
finish, err := gollup.rollup.Finish(accept) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
switch finish.NextRequestType { | ||
case libcmt.AdvanceStateRequest: | ||
input, err := gollup.rollup.ReadAdvanceState() | ||
if err != nil { | ||
return err | ||
} | ||
accept = gollup.advanceHandler(gollup, input) | ||
case libcmt.InspectStateRequest: | ||
query, err := gollup.rollup.ReadInspectState() | ||
if err != nil { | ||
return err | ||
} | ||
accept = gollup.inspectHandler(gollup, query) | ||
default: | ||
panic("unreachable") | ||
} | ||
} | ||
} | ||
|
||
// ------------------------------------------------------------------------------------------------ | ||
|
||
func (gollup *Gollup) SendVoucher(address [20]byte, value []byte, data []byte) (uint64, error) { | ||
return gollup.rollup.EmitVoucher(address, value, data) | ||
} | ||
|
||
func (gollup *Gollup) SendNotice(data []byte) (uint64, error) { | ||
return gollup.rollup.EmitNotice(data) | ||
} | ||
|
||
func (gollup *Gollup) SendReport(data []byte) error { | ||
return gollup.rollup.EmitReport(data) | ||
} | ||
|
||
func (gollup *Gollup) RaiseException(data []byte) error { | ||
return gollup.rollup.EmitException(data) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
// (c) Cartesi and individual authors (see AUTHORS) | ||
// SPDX-License-Identifier: Apache-2.0 (see LICENSE) | ||
|
||
package libcmt | ||
|
||
// #cgo LDFLAGS: -lcmt | ||
// #include <stdlib.h> | ||
// #include <string.h> | ||
// #include "libcmt/rollup.h" | ||
// #include "libcmt/io.h" | ||
import "C" | ||
import ( | ||
"fmt" | ||
"unsafe" | ||
) | ||
|
||
type RequestType = uint8 | ||
|
||
const ( | ||
AdvanceStateRequest RequestType = C.HTIF_YIELD_REASON_ADVANCE | ||
InspectStateRequest RequestType = C.HTIF_YIELD_REASON_INSPECT | ||
) | ||
|
||
type Finish struct { | ||
AcceptPreviousRequest bool | ||
NextRequestType RequestType | ||
NextRequestPayloadLength uint32 | ||
} | ||
|
||
type Input struct { | ||
ChainId uint64 | ||
AppContract [20]byte | ||
Sender [20]byte | ||
BlockNumber uint64 | ||
BlockTimestamp uint64 | ||
Index uint64 | ||
Data []byte | ||
} | ||
|
||
type Query struct { | ||
Data []byte | ||
} | ||
|
||
// ------------------------------------------------------------------------------------------------ | ||
|
||
type Rollup struct { | ||
inner *C.cmt_rollup_t | ||
} | ||
|
||
func NewRollup() (*Rollup, error) { | ||
var rollup C.cmt_rollup_t | ||
errno := C.cmt_rollup_init(&rollup) | ||
return &Rollup{inner: &rollup}, toError(errno) | ||
} | ||
|
||
func (rollup *Rollup) Destroy() { | ||
C.cmt_rollup_fini(rollup.inner) | ||
} | ||
|
||
func (rollup *Rollup) Finish(accept bool) (*Finish, error) { | ||
finish := C.cmt_rollup_finish_t{accept_previous_request: C.bool(accept)} | ||
errno := C.cmt_rollup_finish(rollup.inner, &finish) | ||
if err := toError(errno); err != nil { | ||
return nil, err | ||
} | ||
|
||
return &Finish{ | ||
AcceptPreviousRequest: bool(finish.accept_previous_request), | ||
NextRequestType: RequestType(finish.next_request_type), | ||
NextRequestPayloadLength: uint32(finish.next_request_payload_length), | ||
}, nil | ||
} | ||
|
||
// Returns the index. | ||
func (rollup *Rollup) EmitVoucher(address [20]byte, value []byte, voucher []byte) (uint64, error) { | ||
addressLength, addressData := C.uint(20), C.CBytes(address[:]) | ||
defer C.free(addressData) | ||
|
||
valueLength, valueData := C.uint(len(value)), C.CBytes(value) | ||
defer C.free(valueData) | ||
|
||
voucherLength, voucherData := C.uint(len(voucher)), C.CBytes(voucher) | ||
defer C.free(voucherData) | ||
|
||
var index C.uint64_t | ||
err := toError(C.cmt_rollup_emit_voucher(rollup.inner, | ||
addressLength, addressData, | ||
valueLength, valueData, | ||
voucherLength, voucherData, | ||
&index, | ||
)) | ||
|
||
return uint64(index), err | ||
} | ||
|
||
func (rollup *Rollup) EmitNotice(notice []byte) (uint64, error) { | ||
length, data := C.uint(len(notice)), C.CBytes(notice) | ||
defer C.free(data) | ||
var index C.uint64_t | ||
err := toError(C.cmt_rollup_emit_notice(rollup.inner, length, data, &index)) | ||
return uint64(index), err | ||
} | ||
|
||
func (rollup *Rollup) EmitReport(report []byte) error { | ||
length, data := C.uint(len(report)), C.CBytes(report) | ||
defer C.free(data) | ||
return toError(C.cmt_rollup_emit_report(rollup.inner, length, data)) | ||
} | ||
|
||
func (rollup *Rollup) EmitException(exception []byte) error { | ||
length, data := C.uint(len(exception)), C.CBytes(exception) | ||
defer C.free(data) | ||
return toError(C.cmt_rollup_emit_exception(rollup.inner, length, data)) | ||
} | ||
|
||
func (rollup *Rollup) ReadAdvanceState() (*Input, error) { | ||
var advance C.cmt_rollup_advance_t | ||
errno := C.cmt_rollup_read_advance_state(rollup.inner, &advance) | ||
if err := toError(errno); err != nil { | ||
return nil, err | ||
} | ||
// TODO: should I free inner.data? | ||
|
||
var appContract [20]byte | ||
for i, v := range advance.app_contract { | ||
appContract[i] = byte(v) | ||
} | ||
|
||
var sender [20]byte | ||
for i, v := range advance.msg_sender { | ||
sender[i] = byte(v) | ||
} | ||
|
||
return &Input{ | ||
ChainId: uint64(advance.chain_id), | ||
AppContract: [20]byte{}, // TODO | ||
Sender: sender, | ||
BlockNumber: uint64(advance.block_number), | ||
BlockTimestamp: uint64(advance.block_timestamp), | ||
Index: uint64(advance.index), | ||
Data: C.GoBytes(advance.payload, C.int(advance.payload_length)), | ||
}, nil | ||
} | ||
|
||
func (rollup *Rollup) ReadInspectState() (*Query, error) { | ||
var query C.cmt_rollup_inspect_t | ||
errno := C.cmt_rollup_read_inspect_state(rollup.inner, &query) | ||
if err := toError(errno); err != nil { | ||
return nil, err | ||
} | ||
// TODO: should I free query.data? | ||
|
||
return &Query{Data: C.GoBytes(query.payload, C.int(query.payload_length))}, nil | ||
} | ||
|
||
func (rollup *Rollup) LoadMerkle(path string) error { | ||
s := C.CString(path) | ||
defer C.free(unsafe.Pointer(s)) | ||
return toError(C.cmt_rollup_load_merkle(rollup.inner, s)) | ||
} | ||
|
||
func (rollup *Rollup) SaveMerkle(path string) error { | ||
s := C.CString(path) | ||
defer C.free(unsafe.Pointer(s)) | ||
return toError(C.cmt_rollup_save_merkle(rollup.inner, s)) | ||
} | ||
|
||
// ------------------------------------------------------------------------------------------------ | ||
|
||
func toError(errno C.int) error { | ||
if errno < 0 { | ||
s := C.strerror(-errno) | ||
defer C.free(unsafe.Pointer(s)) | ||
return fmt.Errorf("%s (%d)", C.GoString(s), errno) | ||
} else { | ||
return nil | ||
} | ||
} |