Skip to content

Commit

Permalink
feat!: add log_step and verify_step
Browse files Browse the repository at this point in the history
  • Loading branch information
mpernambuco committed Dec 17, 2024
1 parent aa5e46c commit 17f016f
Show file tree
Hide file tree
Showing 28 changed files with 2,652 additions and 8 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ jobs:
- name: Run test suite inside the docker image
run: docker run --rm -t ${{ github.repository_owner }}/machine-emulator:tests /usr/bin/cartesi-machine-tests run

- name: Run test suite with log_stepinside the docker image
run: docker run --rm -t ${{ github.repository_owner }}/machine-emulator:tests /usr/bin/cartesi-machine-tests run_step

- name: Save and Load
run: |
docker run --rm -t ${{ github.repository_owner }}/machine-emulator:tests /usr/share/cartesi-machine/tests/scripts/test-save-and-load.sh
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]
### Added
- Added the "log_step" method
- Added the "verify_step" method
- Added the "--log-step" option to "cartesi-machine.lua"

### Changed
- Added a "--jobs" option to "uarch-riscv-tests.lua" test
Expand Down
3 changes: 2 additions & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,8 @@ LIBCARTESI_OBJS:= \
uarch-pristine-ram.o \
uarch-pristine-state-hash.o \
uarch-pristine-hash.o \
send-cmio-response.o
send-cmio-response.o \
replay-step-state-access-interop.o

CARTESI_CLUA_OBJS:= \
clua.o \
Expand Down
20 changes: 20 additions & 0 deletions src/cartesi-machine.lua
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,9 @@ where options are:
this option implies --initial-hash and --final-hash.
(default: none)
--log-steps=<mcycle-count>,<filename>
log and save a step of <mcycle-count> mcycles to <filename>.
--log-step-uarch
advance one micro step and print access log.
Expand Down Expand Up @@ -622,6 +625,8 @@ local load_json_config = false
local gdb_address
local exec_arguments = {}
local assert_rolling_template = false
local log_step_mcycle_count
local log_step_filename

local function parse_memory_range(opts, what, all)
local f = util.parse_options(opts, {
Expand Down Expand Up @@ -1251,6 +1256,15 @@ local options = {
return true
end,
},
{
"^%-%-log%-step%=(.*),(.*)$",
function(count, filename)
if (not count) or not filename then return false end
log_step_mcycle_count = assert(util.parse_number(count), "invalid steps " .. count)
log_step_filename = filename
return true
end,
},
{
"^%-%-log%-step%-uarch$",
function(all)
Expand Down Expand Up @@ -2185,6 +2199,12 @@ if max_uarch_cycle > 0 then
end
end
if gdb_stub then gdb_stub:close() end
if log_step_mcycle_count then
stderr(string.format("Logging step of %d cycles to %s\n", log_step_mcycle_count, log_step_filename))
print_root_hash(machine, stderr_unsilenceable)
machine:log_step(log_step_mcycle_count, log_step_filename)
print_root_hash(machine, stderr_unsilenceable)
end
if log_step_uarch then
assert(config.processor.iunrep == 0, "micro step proof is meaningless in unreproducible mode")
stderr("Gathering micro step log: please wait\n")
Expand Down
25 changes: 25 additions & 0 deletions src/clua-i-virtual-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,16 @@ static int machine_obj_index_run(lua_State *L) {
return 1;
}

static int machine_obj_index_log_step(lua_State *L) {
auto &m = clua_check<clua_managed_cm_ptr<cm_machine>>(L, 1);
cm_break_reason break_reason = CM_BREAK_REASON_FAILED;
if (cm_log_step(m.get(), luaL_checkinteger(L, 2), luaL_checkstring(L, 3), &break_reason) != 0) {
return luaL_error(L, "%s", cm_get_last_error_message());
}
lua_pushinteger(L, static_cast<lua_Integer>(break_reason));
return 1;
}

/// \brief This is the machine:read_uarch_halt_flag() method implementation.
/// \param L Lua state.
static int machine_obj_index_read_uarch_halt_flag(lua_State *L) {
Expand Down Expand Up @@ -1048,6 +1058,19 @@ static int machine_obj_index_get_reg_address(lua_State *L) {
return 1;
}

/// \brief This is the machine.verify_step() method implementation.
static int machine_obj_index_verify_step(lua_State *L) {
lua_settop(L, 4);
cm_hash root_hash_before{};
clua_check_cm_hash(L, 1, &root_hash_before);
cm_hash root_hash_after{};
clua_check_cm_hash(L, 4, &root_hash_after);
if (cm_verify_step(&root_hash_before, luaL_checkstring(L, 2), luaL_checkinteger(L, 3), &root_hash_after) != 0) {
return luaL_error(L, "%s", cm_get_last_error_message());
}
return 1;
}

/// \brief This is the machine:verify_step_uarch() method implementation.
/// \param L Lua state.
static int machine_obj_index_verify_step_uarch(lua_State *L) {
Expand Down Expand Up @@ -1131,6 +1154,7 @@ static const auto machine_obj_index = cartesi::clua_make_luaL_Reg_array({
{"read_virtual_memory", machine_obj_index_read_virtual_memory},
{"read_word", machine_obj_index_read_word},
{"run", machine_obj_index_run},
{"log_step", machine_obj_index_log_step},
{"run_uarch", machine_obj_index_run_uarch},
{"log_step_uarch", machine_obj_index_log_step_uarch},
{"store", machine_obj_index_store},
Expand All @@ -1152,6 +1176,7 @@ static const auto machine_obj_index = cartesi::clua_make_luaL_Reg_array({
{"log_send_cmio_response", machine_obj_index_log_send_cmio_response},
{"get_default_config", machine_obj_index_get_default_config},
{"get_reg_address", machine_obj_index_get_reg_address},
{"verify_step", machine_obj_index_verify_step},
{"verify_step_uarch", machine_obj_index_verify_step_uarch},
{"verify_reset_uarch", machine_obj_index_verify_reset_uarch},
{"verify_send_cmio_response", machine_obj_index_verify_send_cmio_response},
Expand Down
14 changes: 14 additions & 0 deletions src/i-virtual-machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ class i_virtual_machine {
do_store(dir);
}

/// \brief Runs the machine for the given mcycle count and generates a log file of accessed pages and proof data.
interpreter_break_reason log_step(uint64_t mcycle_count, const std::string &filename) {
return do_log_step(mcycle_count, filename);
}

/// \brief Runs the machine for one micro cycle logging all accesses to the state.
access_log log_step_uarch(const access_log::type &log_type) {
return do_log_step_uarch(log_type);
Expand Down Expand Up @@ -220,6 +225,12 @@ class i_virtual_machine {
return do_get_default_config();
}

/// \brief Checks the validity of a state transition caused by log_step.
void verify_step(const hash_type &root_hash_before, const std::string &log_filename, uint64_t mcycle_count,
const hash_type &root_hash_after) const {
do_verify_step(root_hash_before, log_filename, mcycle_count, root_hash_after);
}

/// \brief Checks the validity of a state transition caused by log_step_uarch.
void verify_step_uarch(const hash_type &root_hash_before, const access_log &log,
const hash_type &root_hash_after) const {
Expand Down Expand Up @@ -250,6 +261,7 @@ class i_virtual_machine {
virtual void do_load(const std::string &directory, const machine_runtime_config &runtime) = 0;
virtual interpreter_break_reason do_run(uint64_t mcycle_end) = 0;
virtual void do_store(const std::string &dir) const = 0;
virtual interpreter_break_reason do_log_step(uint64_t mcycle_count, const std::string &filename) = 0;
virtual access_log do_log_step_uarch(const access_log::type &log_type) = 0;
virtual machine_merkle_tree::proof_type do_get_proof(uint64_t address, int log2_size) const = 0;
virtual void do_get_root_hash(hash_type &hash) const = 0;
Expand Down Expand Up @@ -277,6 +289,8 @@ class i_virtual_machine {
const access_log::type &log_type) = 0;
virtual uint64_t do_get_reg_address(reg r) const = 0;
virtual machine_config do_get_default_config() const = 0;
virtual void do_verify_step(const hash_type &root_hash_before, const std::string &log_filename,
uint64_t mcycle_count, const hash_type &root_hash_after) const = 0;
virtual void do_verify_step_uarch(const hash_type &root_hash_before, const access_log &log,
const hash_type &root_hash_after) const = 0;
virtual void do_verify_reset_uarch(const hash_type &root_hash_before, const access_log &log,
Expand Down
6 changes: 6 additions & 0 deletions src/interpret.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include "uarch-machine-state-access.h"
#include "uarch-runtime.h"
#else
#include "record-step-state-access.h"
#include "replay-step-state-access.h"
#include "state-access.h"
#include <cassert>
#endif // MICROARCHITECTURE
Expand Down Expand Up @@ -5647,6 +5649,10 @@ template interpreter_break_reason interpret(uarch_machine_state_access &a, uint6
#else
// Explicit instantiation for state_access
template interpreter_break_reason interpret(state_access &a, uint64_t mcycle_end);
// Explicit instantiation for record_step_state_access
template interpreter_break_reason interpret(record_step_state_access &a, uint64_t mcycle_end);
// Explicit instantiation for replay_step_state_access
template interpreter_break_reason interpret(replay_step_state_access &a, uint64_t mcycle_end);
#endif // MICROARCHITECTURE

} // namespace cartesi
74 changes: 74 additions & 0 deletions src/jsonrpc-discover.json
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,80 @@
"type": "boolean"
}
}
},
{
"name": "machine.log_step",
"summary": "Logs a step of a given number of cycles",
"params": [
{
"name": "mcycle_count",
"description": "Number of cycles to log",
"required": true,
"schema": {
"$ref": "#/components/schemas/UnsignedInteger"
}
},
{
"name": "filename",
"description": "Filename to store the log",
"required": true,
"schema": {
"type": "string"
}
}
],
"result": {
"name": "reason",
"description": "Reason call returned",
"schema": {
"$ref": "#/components/schemas/InterpreterBreakReason"
}
}
},
{
"name": "machine.verify_step",
"summary": "Checks the validity of a step log fil.",
"params": [
{
"name": "root_hash_before",
"description": "State hash before step",
"required": true,
"schema": {
"$ref": "#/components/schemas/Base64Hash"
}
},
{
"name": "filename",
"description": "Filename containing the log of the step",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "mcycle_count",
"description": "Number of cycles in step",
"required": true,
"schema": {
"$ref": "#/components/schemas/UnsignedInteger"
}
},
{
"name": "root_hash_after",
"description": "State hash after step",
"required": true,
"schema": {
"$ref": "#/components/schemas/Base64Hash"
}
}
],
"result": {
"name": "status",
"description": "True when operation succeeded",
"schema": {
"type": "boolean"
}
}
}
],
"components": {
Expand Down
30 changes: 30 additions & 0 deletions src/jsonrpc-remote-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,20 @@ static json jsonrpc_machine_run_handler(const json &j, const std::shared_ptr<htt
return jsonrpc_response_ok(j, interpreter_break_reason_name(reason));
}

/// \brief JSONRPC handler for the machine.log_step method
/// \param j JSON request object
/// \param session HTTP session
/// \returns JSON response object
static json jsonrpc_machine_log_step_handler(const json &j, const std::shared_ptr<http_session> &session) {
if (!session->handler->machine) {
return jsonrpc_response_invalid_request(j, "no machine");
}
static const char *param_name[] = {"mcycle_count", "filename"};
auto args = parse_args<uint64_t, std::string>(j, param_name);
auto reason = session->handler->machine->log_step(std::get<0>(args), std::get<1>(args));
return jsonrpc_response_ok(j, interpreter_break_reason_name(reason));
}

/// \brief Translate an uarch_interpret_break_reason value to string
/// \param reason uarch_interpret_break_reason value to translate
/// \returns String representation of value
Expand Down Expand Up @@ -1009,6 +1023,20 @@ static json jsonrpc_machine_log_reset_uarch_handler(const json &j, const std::sh
return jsonrpc_response_ok(j, session->handler->machine->log_reset_uarch(std::get<0>(args).value()));
}

/// \brief JSONRPC handler for the machine.verify_send_cmio_response method
/// \param j JSON request object
/// \param session HTTP session
/// \returns JSON response object
static json jsonrpc_machine_verify_step_handler(const json &j, const std::shared_ptr<http_session> &session) {
(void) session;
static const char *param_name[] = {"root_hash_before", "filename", "mcycle_count", "root_hash_after"};
auto args = parse_args<cartesi::machine_merkle_tree::hash_type, std::string, uint64_t,
cartesi::machine_merkle_tree::hash_type>(j, param_name);
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
cartesi::machine::verify_step(std::get<0>(args), std::get<1>(args), std::get<2>(args), std::get<3>(args));
return jsonrpc_response_ok(j);
}

/// \brief JSONRPC handler for the machine.verify_step_uarch method
/// \param j JSON request object
/// \param session HTTP session
Expand Down Expand Up @@ -1428,6 +1456,7 @@ static json jsonrpc_dispatch_method(const json &j, const std::shared_ptr<http_se
{"machine.destroy", jsonrpc_machine_destroy_handler},
{"machine.store", jsonrpc_machine_store_handler},
{"machine.run", jsonrpc_machine_run_handler},
{"machine.log_step", jsonrpc_machine_log_step_handler},
{"machine.run_uarch", jsonrpc_machine_run_uarch_handler},
{"machine.log_step_uarch", jsonrpc_machine_log_step_uarch_handler},
{"machine.reset_uarch", jsonrpc_machine_reset_uarch_handler},
Expand Down Expand Up @@ -1456,6 +1485,7 @@ static json jsonrpc_dispatch_method(const json &j, const std::shared_ptr<http_se
{"machine.send_cmio_response", jsonrpc_machine_send_cmio_response_handler},
{"machine.log_send_cmio_response", jsonrpc_machine_log_send_cmio_response_handler},
{"machine.verify_send_cmio_response", jsonrpc_machine_verify_send_cmio_response_handler},
{"machine.verify_step", jsonrpc_machine_verify_step_handler},
};
auto method = j["method"].get<std::string>();
SLOG(debug) << session->handler->local_endpoint << " handling \"" << method << "\" method";
Expand Down
16 changes: 16 additions & 0 deletions src/jsonrpc-virtual-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,13 @@ interpreter_break_reason jsonrpc_virtual_machine::do_run(uint64_t mcycle_end) {
return result;
}

interpreter_break_reason jsonrpc_virtual_machine::do_log_step(uint64_t mcycle_count, const std::string &filename) {
interpreter_break_reason result = interpreter_break_reason::failed;
jsonrpc_request(m_ioc, m_stream, m_address, "machine.log_step", std::tie(mcycle_count, filename), result,
m_timeout);
return result;
}

void jsonrpc_virtual_machine::do_store(const std::string &directory) const {
bool result = false;
jsonrpc_request(m_ioc, m_stream, m_address, "machine.store", std::tie(directory), result, m_timeout);
Expand Down Expand Up @@ -782,6 +789,15 @@ machine_config jsonrpc_virtual_machine::do_get_default_config() const {
return result;
}

void jsonrpc_virtual_machine::do_verify_step(const hash_type &root_hash_before, const std::string &log_filename,
uint64_t mcycle_count, const hash_type &root_hash_after) const {
bool result = false;
auto b64_root_hash_before = encode_base64(root_hash_before);
auto b64_root_hash_after = encode_base64(root_hash_after);
jsonrpc_request(m_ioc, m_stream, m_address, "machine.verify_step",
std::tie(b64_root_hash_before, log_filename, mcycle_count, b64_root_hash_after), result, m_timeout);
}

void jsonrpc_virtual_machine::do_verify_step_uarch(const hash_type &root_hash_before, const access_log &log,
const hash_type &root_hash_after) const {
bool result = false;
Expand Down
3 changes: 3 additions & 0 deletions src/jsonrpc-virtual-machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class jsonrpc_virtual_machine final : public i_virtual_machine {
void do_create(const machine_config &config, const machine_runtime_config &runtime) override;
void do_load(const std::string &directory, const machine_runtime_config &runtime) override;
interpreter_break_reason do_run(uint64_t mcycle_end) override;
interpreter_break_reason do_log_step(uint64_t mcycle_count, const std::string &filename) override;
void do_store(const std::string &dir) const override;
uint64_t do_read_reg(reg r) const override;
void do_write_reg(reg w, uint64_t val) override;
Expand Down Expand Up @@ -128,6 +129,8 @@ class jsonrpc_virtual_machine final : public i_virtual_machine {
const access_log::type &log_type) override;
uint64_t do_get_reg_address(reg r) const override;
machine_config do_get_default_config() const override;
void do_verify_step(const hash_type &root_hash_before, const std::string &log_filename, uint64_t mcycle_count,
const hash_type &root_hash_after) const override;
void do_verify_step_uarch(const hash_type &root_hash_before, const access_log &log,
const hash_type &root_hash_after) const override;
void do_verify_reset_uarch(const hash_type &root_hash_before, const access_log &log,
Expand Down
Loading

0 comments on commit 17f016f

Please sign in to comment.