Skip to content

Commit

Permalink
feat: add libcmt and gollup packages
Browse files Browse the repository at this point in the history
  • Loading branch information
renan061 committed Jun 7, 2024
1 parent 2f773ff commit cdc8e5c
Show file tree
Hide file tree
Showing 2 changed files with 265 additions and 0 deletions.
87 changes: 87 additions & 0 deletions pkg/gollup/gollup.go
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)
}
178 changes: 178 additions & 0 deletions pkg/libcmt/libcmt.go
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
}
}

0 comments on commit cdc8e5c

Please sign in to comment.