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 tooling for creating snapshots programmatically #498

Merged
merged 1 commit 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
54 changes: 1 addition & 53 deletions build/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -103,58 +103,6 @@ RUN <<EOF
rm -rf /var/lib/apt/lists/*
EOF

# =============================================================================
# STAGE: emulator-devel
#
# - Install libarchive13 (setup -- required by xgenext2fs).
# - Install libcmt.
# - Install xgenext2fs.
# =============================================================================

FROM emulator AS emulator-devel

ARG MACHINE_TOOLS_VERSION
ARG MACHINE_XGENEXT2FS_VERSION
ARG DEBIAN_FRONTEND=noninteractive

# Install libarchive13 (setup -- required by xgenext2fs).
RUN <<EOF
set -e
apt-get update
apt-get install -y --no-install-recommends libarchive13
EOF

# Install libcmt (cartesi/machine-emulator-tools).
RUN <<EOF
set -e
URL=https://github.com/cartesi/machine-emulator-tools/releases/download
VERSION=v${MACHINE_TOOLS_VERSION}
ARTIFACT=libcmt-${VERSION}-dev.deb
curl -fsSL ${URL}/${VERSION}/${ARTIFACT} -o ./libcmt.deb
apt-get install -y ./libcmt.deb
rm ./libcmt.deb
mv /usr/riscv64-linux-gnu/include/libcmt /usr/include/
mv /usr/riscv64-linux-gnu/lib/libcmt.a /usr/lib/
rm -rf /usr/riscv64-linux-gnu
EOF

# Install xgenext2fs (cartesi/genext2fs).
RUN <<EOF
set -e
URL=https://github.com/cartesi/genext2fs/releases/download
VERSION=v${MACHINE_XGENEXT2FS_VERSION}
ARCH=$(dpkg --print-architecture)
ARTIFACT=xgenext2fs_${ARCH}.deb
curl -fsSL ${URL}/${VERSION}/${ARTIFACT} -o ./xgenext2fs.deb
apt-get install -y ./xgenext2fs.deb
rm ./xgenext2fs.deb
EOF

# Clean up.
RUN <<EOF
rm -rf /var/lib/apt/lists/*
EOF

# =============================================================================
# STAGE: rollups-node-ci
#
Expand All @@ -165,7 +113,7 @@ EOF
# - Install docker.
# =============================================================================

FROM emulator-devel AS rollups-node-ci
FROM emulator AS rollups-node-ci

# Install git and build-essential (setup).
RUN <<EOF
Expand Down
114 changes: 114 additions & 0 deletions test/snapshot/snapshot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

marcelstanley marked this conversation as resolved.
Show resolved Hide resolved
// Package snapshot implements dynamic snapshot instantiation.
// It defines the Snapshot type, which manages the lifecycle of a snapshot.
package snapshot

import (
"errors"
"fmt"
"math"
"math/rand"
"os"
"strings"

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

const ramLength = 64 << 20

// ImagesPath is the path to the folder containing the linux.bin and rootfs.ext2 files.
// It can be redefined in case the files are not in the default folder.
var ImagesPath = "/usr/share/cartesi-machine/images/"
marcelstanley marked this conversation as resolved.
Show resolved Hide resolved

type Snapshot struct {
id string // an unique id used to avoid name clashing
temp string // path to the temporary directory containing snapshot relevant files
path string // path to the snapshot directory

// Reason why the snapshot stopped running before being stored.
BreakReason emulator.BreakReason
}

// FromScript creates a snapshot given an script command.
func FromScript(command string, cycles uint64) (*Snapshot, error) {
snapshot := &Snapshot{id: fmt.Sprintf("fromscript%d", rand.Int())}

err := snapshot.createTempDir()
if err != nil {
return nil, err
}

config := defaultMachineConfig()
config.Dtb.Entrypoint = command

err = snapshot.createRunAndStore(config, cycles)
return snapshot, err
}

// Path returns the path to the directory where the snapshot is stored.
func (snapshot *Snapshot) Path() string {
return snapshot.path
}

// Close deletes the temporary directory created to hold the snapshot files.
func (snapshot *Snapshot) Close() error {
return os.RemoveAll(snapshot.temp)
}

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

func defaultMachineConfig() *emulator.MachineConfig {
config := emulator.NewDefaultMachineConfig()
config.Ram.Length = ramLength
config.Ram.ImageFilename = ImagesPath + "linux.bin"
config.Dtb.Bootargs = strings.Join([]string{"quiet",
"no4lvl",
"quiet",
"earlycon=sbi",
"console=hvc0",
"rootfstype=ext2",
"root=/dev/pmem0",
"rw",
"init=/usr/sbin/cartesi-init"}, " ")
config.FlashDrive = []emulator.MemoryRangeConfig{{
Start: 0x80000000000000, //nolint:mnd
Length: math.MaxUint64,
ImageFilename: ImagesPath + "rootfs.ext2",
}}
return config
}

func (snapshot *Snapshot) createTempDir() error {
temp, err := os.MkdirTemp("", snapshot.id+"-*")
if err != nil {
return err
}
snapshot.temp = temp
snapshot.path = snapshot.temp + "/snapshot"
return nil
}

func (snapshot *Snapshot) createRunAndStore(config *emulator.MachineConfig, cycles uint64) error {
// Creates the (local) machine.
machine, err := emulator.NewMachine(config, &emulator.MachineRuntimeConfig{})
if err != nil {
return errors.Join(err, snapshot.Close())
}
defer machine.Delete()

// Runs the machine.
snapshot.BreakReason, err = machine.Run(cycles)
if err != nil {
return errors.Join(err, snapshot.Close())
}

// Stores the machine.
err = machine.Store(snapshot.path)
if err != nil {
return errors.Join(err, snapshot.Close())
}

return nil
}
Loading