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!: add log_step and verify_step #297

Merged
merged 1 commit into from
Dec 20, 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
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_step inside 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
21 changes: 21 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-step=<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
mpernambuco marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -2168,6 +2182,13 @@ while math.ult(machine:read_mcycle(), max_mcycle) do
next_hash_mcycle = next_hash_mcycle + periodic_hashes_period
end
end
-- log step
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
-- Advance micro cycles
if max_uarch_cycle > 0 then
-- Save halt flag before micro cycles
Expand Down
29 changes: 29 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,23 @@ 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, 5);
auto &m = clua_check<clua_managed_cm_ptr<cm_machine>>(L, 1);
cm_hash root_hash_before{};
clua_check_cm_hash(L, 2, &root_hash_before);
cm_hash root_hash_after{};
clua_check_cm_hash(L, 5, &root_hash_after);
cm_break_reason break_reason{};
if (cm_verify_step(m.get(), &root_hash_before, luaL_checkstring(L, 3), luaL_checkinteger(L, 4), &root_hash_after,
&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: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 +1158,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 +1180,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.
interpreter_break_reason verify_step(const hash_type &root_hash_before, const std::string &log_filename,
uint64_t mcycle_count, const hash_type &root_hash_after) const {
return 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 interpreter_break_reason 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 file.",
"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
31 changes: 31 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,21 @@ 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)
auto reason =
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, interpreter_break_reason_name(reason));
}

/// \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 +1457,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 +1486,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
17 changes: 17 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,16 @@ machine_config jsonrpc_virtual_machine::do_get_default_config() const {
return result;
}

interpreter_break_reason 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 {
interpreter_break_reason result = interpreter_break_reason::failed;
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);
return result;
}

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;
interpreter_break_reason 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
Loading