Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(advancer): add rollupsmachine package #520

Merged
merged 3 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/compose-devnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ services:
CARTESI_BLOCKCHAIN_WS_ENDPOINT: "ws://devnet:8545"
CARTESI_LEGACY_BLOCKCHAIN_ENABLED: "false"
CARTESI_BLOCKCHAIN_FINALITY_OFFSET: "1"
CARTESI_CONTRACTS_APPLICATION_ADDRESS: "0x00D13Ee2EB6D14eD8A2CA9DAD09D3345F95bE731"
CARTESI_CONTRACTS_APPLICATION_ADDRESS: "0x1b0FAD42f016a9EBa358c7491A67fa1fAE82912A"
CARTESI_CONTRACTS_ICONSENSUS_ADDRESS: "0x3fd5dc9dCf5Df3c7002C0628Eb9AD3bb5e2ce257"
CARTESI_CONTRACTS_INPUT_BOX_ADDRESS: "0x593E5BCf894D6829Dd26D0810DA7F064406aebB6"
CARTESI_CONTRACTS_INPUT_BOX_DEPLOYMENT_BLOCK_NUMBER: "10"
Expand Down
4 changes: 2 additions & 2 deletions build/docker-bake.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ target "common" {
RUST_VERSION = "1.78.0"
GO_VERSION = "1.22.1"
FOUNDRY_NIGHTLY_VERSION = "293fad73670b7b59ca901c7f2105bf7a29165a90"
MACHINE_EMULATOR_VERSION = "0.17.0"
MACHINE_TOOLS_VERSION = "0.15.0"
MACHINE_EMULATOR_VERSION = "0.18.1"
MACHINE_TOOLS_VERSION = "0.16.1"
MACHINE_IMAGE_KERNEL_VERSION = "0.20.0"
MACHINE_KERNEL_VERSION = "6.5.13"
MACHINE_XGENEXT2FS_VERSION = "1.5.6"
Expand Down
2 changes: 2 additions & 0 deletions internal/node/model/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
)

const HashLength = common.HashLength

type (
Hash = common.Hash
Address = common.Address
Expand Down
2 changes: 1 addition & 1 deletion pkg/addresses/addresses.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type Book struct {
func GetTestBook() *Book {
return &Book{
Application: common.HexToAddress(
"0x00D13Ee2EB6D14eD8A2CA9DAD09D3345F95bE731"),
"0x1b0FAD42f016a9EBa358c7491A67fa1fAE82912A"),
ApplicationFactory: common.HexToAddress(
"0xA1DA32BF664109D62208a1cb0d69aACc6a484873"),
Authority: common.HexToAddress(
Expand Down
2 changes: 1 addition & 1 deletion pkg/emulator/emulator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

var (
imagesPath = "/usr/share/cartesi-machine/images/"
address = "localhost:8081"
address = "127.0.0.1:8081"
)

func init() {
Expand Down
3 changes: 3 additions & 0 deletions pkg/emulator/pma.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ import "C"
const (
CmioRxBufferStart uint64 = C.PMA_CMIO_RX_BUFFER_START_DEF
CmioTxBufferStart uint64 = C.PMA_CMIO_TX_BUFFER_START_DEF

CmioRxBufferLog2Size uint64 = C.PMA_CMIO_RX_BUFFER_LOG2_SIZE_DEF
CmioTxBufferLog2Size uint64 = C.PMA_CMIO_TX_BUFFER_LOG2_SIZE_DEF
)
6 changes: 3 additions & 3 deletions pkg/emulator/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// A connection to the remote jsonrpc machine manager.
type RemoteMachineManager struct {
c *C.cm_jsonrpc_mg_mgr
c *C.cm_jsonrpc_mgr

Address string
}
Expand All @@ -22,13 +22,13 @@ func NewRemoteMachineManager(address string) (*RemoteMachineManager, error) {
cRemoteAddress := C.CString(address)
defer C.free(unsafe.Pointer(cRemoteAddress))
var msg *C.char
code := C.cm_create_jsonrpc_mg_mgr(cRemoteAddress, &manager.c, &msg)
code := C.cm_create_jsonrpc_mgr(cRemoteAddress, &manager.c, &msg)
return manager, newError(code, msg)
}

func (remote *RemoteMachineManager) Delete() {
if remote.c != nil {
C.cm_delete_jsonrpc_mg_mgr(remote.c)
C.cm_delete_jsonrpc_mgr(remote.c)
remote.c = nil
}
}
Expand Down
28 changes: 28 additions & 0 deletions pkg/rollupsmachine/abi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[{
"type" : "function",
"name" : "EvmAdvance",
"inputs" : [
{ "type" : "uint256" },
{ "type" : "address" },
{ "type" : "address" },
{ "type" : "uint256" },
{ "type" : "uint256" },
{ "type" : "uint256" },
{ "type" : "uint256" },
{ "type" : "bytes" }
]
}, {
"type" : "function",
"name" : "Voucher",
"inputs" : [
{ "type" : "address" },
{ "type" : "uint256" },
{ "type" : "bytes" }
]
}, {
"type" : "function",
"name" : "Notice",
"inputs" : [
{ "type" : "bytes" }
]
}]
30 changes: 30 additions & 0 deletions pkg/rollupsmachine/cartesimachine/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

// Package cartesimachine abstracts into an interface the functionalities expected from a machine
// library. It provides an implementation for that interface using the emulator package.
package cartesimachine

import "github.com/cartesi/rollups-node/pkg/emulator"

type (
RequestType uint8
YieldReason uint8
)

type CartesiMachine interface {
Fork() (CartesiMachine, error)
Continue() error
Run(until uint64) (emulator.BreakReason, error)
Close() error

IsAtManualYield() (bool, error)
ReadYieldReason() (emulator.HtifYieldReason, error)
ReadHash() ([32]byte, error)
ReadCycle() (uint64, error)
ReadMemory() ([]byte, error)
WriteRequest([]byte, RequestType) error

PayloadLengthLimit() uint
Address() string
}
235 changes: 235 additions & 0 deletions pkg/rollupsmachine/cartesimachine/machine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

package cartesimachine

import (
"errors"
"fmt"
"math"

"github.com/cartesi/rollups-node/pkg/emulator"
)

const (
AdvanceStateRequest RequestType = 0
InspectStateRequest RequestType = 1
)

var (
ErrCartesiMachine = errors.New("cartesi machine internal error")

ErrOrphanServer = errors.New("cartesi machine server was left orphan")
)

type cartesiMachine struct {
inner *emulator.Machine
server *emulator.RemoteMachineManager

address string // address of the JSON RPC remote cartesi machine server
}

// Load loads the machine stored at path into the remote server from address.
func Load(path, address string, config *emulator.MachineRuntimeConfig) (CartesiMachine, error) {
machine := &cartesiMachine{address: address}

// Creates the server machine manager (the server's manager).
server, err := emulator.NewRemoteMachineManager(address)
if err != nil {
err = fmt.Errorf("could not create the remote machine manager: %w", err)
return nil, errCartesiMachine(err)
}
machine.server = server

// Loads the machine stored at path into the server.
inner, err := server.LoadMachine(path, config)
if err != nil {
defer machine.server.Delete()
err = fmt.Errorf("could not load the machine: %w", err)
return nil, errCartesiMachine(err)
}
machine.inner = inner

return machine, nil
}

// Fork forks the machine.
//
// When Fork returns with the ErrOrphanServer error, it also returns with a non-nil CartesiMachine
// the can be used to retrieve the orphan server's address.
func (machine *cartesiMachine) Fork() (CartesiMachine, error) {
newMachine := new(cartesiMachine)

// Forks the server.
address, err := machine.server.Fork()
if err != nil {
err = fmt.Errorf("could not fork the machine: %w", err)
return nil, errCartesiMachine(err)
}
newMachine.address = address

// Instantiates the new remote machine manager.
server, err := emulator.NewRemoteMachineManager(address)
if err != nil {
err = fmt.Errorf("could not create the new remote machine manager: %w", err)
errOrphanServer := errOrphanServerWithAddress(address)
return newMachine, errors.Join(ErrCartesiMachine, err, errOrphanServer)
}
newMachine.server = server

// Gets the inner machine reference from the server.
inner, err := newMachine.server.GetMachine()
if err != nil {
err = fmt.Errorf("could not get the machine from the server: %w", err)
return newMachine, errors.Join(ErrCartesiMachine, err, newMachine.closeServer())
}
newMachine.inner = inner

return newMachine, nil
}

func (machine *cartesiMachine) Run(until uint64) (emulator.BreakReason, error) {
breakReason, err := machine.inner.Run(until)
if err != nil {
assert(breakReason == emulator.BreakReasonFailed, breakReason.String())
err = fmt.Errorf("machine run failed: %w", err)
return breakReason, errCartesiMachine(err)
}
return breakReason, nil
}

func (machine *cartesiMachine) IsAtManualYield() (bool, error) {
iflagsY, err := machine.inner.ReadIFlagsY()
if err != nil {
err = fmt.Errorf("could not read iflagsY: %w", err)
return iflagsY, errCartesiMachine(err)
}
return iflagsY, nil
}

func (machine *cartesiMachine) ReadYieldReason() (emulator.HtifYieldReason, error) {
tohost, err := machine.readHtifToHostData()
if err != nil {
return emulator.HtifYieldReason(0), err
}
yieldReason := tohost >> 32 //nolint:mnd
return emulator.HtifYieldReason(yieldReason), nil
}

func (machine *cartesiMachine) ReadHash() ([32]byte, error) {
hash, err := machine.inner.GetRootHash()
if err != nil {
err := fmt.Errorf("could not get the machine's root hash: %w", err)
return hash, errCartesiMachine(err)
}
return hash, nil
}

func (machine *cartesiMachine) ReadMemory() ([]byte, error) {
tohost, err := machine.readHtifToHostData()
if err != nil {
return nil, err
}
length := tohost & 0x00000000ffffffff //nolint:mnd

read, err := machine.inner.ReadMemory(emulator.CmioTxBufferStart, length)
if err != nil {
err := fmt.Errorf("could not read from the memory: %w", err)
return nil, errCartesiMachine(err)
}

return read, nil
}

func (machine *cartesiMachine) WriteRequest(data []byte, type_ RequestType) error {
// Writes the request's data.
err := machine.inner.WriteMemory(emulator.CmioRxBufferStart, data)
if err != nil {
err := fmt.Errorf("could not write to the memory: %w", err)
return errCartesiMachine(err)
}

// Writes the request's type and length.
fromhost := ((uint64(type_) << 32) | (uint64(len(data)) & 0xffffffff)) //nolint:mnd
err = machine.inner.WriteHtifFromHostData(fromhost)
if err != nil {
err := fmt.Errorf("could not write HTIF fromhost data: %w", err)
return errCartesiMachine(err)
}

return nil
}

func (machine *cartesiMachine) Continue() error {
err := machine.inner.ResetIFlagsY()
if err != nil {
err = fmt.Errorf("could not reset iflagsY: %w", err)
return errCartesiMachine(err)
}
return nil
}

func (machine *cartesiMachine) ReadCycle() (uint64, error) {
cycle, err := machine.inner.ReadMCycle()
if err != nil {
err = fmt.Errorf("could not read the machine's current cycle: %w", err)
return cycle, errCartesiMachine(err)
}
return cycle, nil
}

func (machine cartesiMachine) PayloadLengthLimit() uint {
expo := float64(emulator.CmioRxBufferLog2Size)
var payloadLengthLimit = uint(math.Pow(2, expo)) //nolint:mnd
return payloadLengthLimit
}

func (machine cartesiMachine) Address() string {
return machine.address
}

// Close closes the cartesi machine. It also shuts down the remote cartesi machine server.
func (machine *cartesiMachine) Close() error {
machine.inner.Delete()
machine.inner = nil
return machine.closeServer()
}

// ------------------------------------------------------------------------------------------------

// closeServer shuts down the server and deletes its reference.
func (machine *cartesiMachine) closeServer() error {
err := machine.server.Shutdown()
if err != nil {
err = fmt.Errorf("could not shut down the server: %w", err)
err = errors.Join(errCartesiMachine(err), errOrphanServerWithAddress(machine.address))
}
machine.server.Delete()
machine.server = nil
return err
}

func (machine *cartesiMachine) readHtifToHostData() (uint64, error) {
tohost, err := machine.inner.ReadHtifToHostData()
if err != nil {
err = fmt.Errorf("could not read HTIF tohost data: %w", err)
return tohost, errCartesiMachine(err)
}
return tohost, nil
}

// ------------------------------------------------------------------------------------------------

func errCartesiMachine(err error) error {
return errors.Join(ErrCartesiMachine, err)
}

func errOrphanServerWithAddress(address string) error {
return fmt.Errorf("%w at address %s", ErrOrphanServer, address)
}

func assert(condition bool, s string) {
if !condition {
panic("assertion error: " + s)
}
}
Loading
Loading