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 Oct 9, 2024
1 parent b56913d commit eb976ed
Show file tree
Hide file tree
Showing 32 changed files with 2,616 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,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: |
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 @@ -363,7 +363,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 @@ -434,6 +434,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-uarch-step
advance one micro step and print access log.
Expand Down Expand Up @@ -610,6 +613,8 @@ local load_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 @@ -1239,6 +1244,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%-uarch%-step$",
function(all)
Expand Down Expand Up @@ -2299,6 +2313,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_uarch_step then
assert(config.processor.iunrep == 0, "micro step proof is meaningless in unreproducible mode")
stderr("Gathering micro step log: please wait\n")
Expand Down
9 changes: 9 additions & 0 deletions src/clua-i-virtual-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,14 @@ 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;
TRY_EXECUTE(cm_log_step(m.get(), luaL_checkinteger(L, 2), luaL_checkstring(L, 3), &break_reason, err_msg));
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 @@ -718,6 +726,7 @@ static const auto machine_obj_index = cartesi::clua_make_luaL_Reg_array({
{"log_uarch_reset", machine_obj_index_log_uarch_reset},
{"send_cmio_response", machine_obj_index_send_cmio_response},
{"log_send_cmio_response", machine_obj_index_log_send_cmio_response},
{"log_step", machine_obj_index_log_step},
});

/// \brief This is the machine __close metamethod implementation.
Expand Down
19 changes: 19 additions & 0 deletions src/clua-jsonrpc-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,24 @@ static int jsonrpc_machine_class_verify_send_cmio_response_state_transition(lua_
return 1;
}

/// \brief This is the machine.verify_step() static method implementation.
static int jsonrpc_machine_class_verify_step(lua_State *L) {
const int stubidx = lua_upvalueindex(1);
const int ctxidx = lua_upvalueindex(2);
lua_settop(L, 5);
auto &managed_jsonrpc_mgr = clua_check<clua_managed_cm_ptr<cm_jsonrpc_mgr>>(L, stubidx, ctxidx);
cm_hash root_hash_before{};
clua_check_cm_hash(L, 1, &root_hash_before);
const auto *filename = luaL_checkstring(L, 2);
const uint64_t mcycle_count = luaL_optinteger(L, 3, UINT64_MAX);
cm_hash root_hash_after{};
clua_check_cm_hash(L, 4, &root_hash_after);
TRY_EXECUTE(cm_jsonrpc_verify_step(managed_jsonrpc_mgr.get(), &root_hash_before, filename, mcycle_count,
&root_hash_after, err_msg));
lua_pop(L, 2);
return 0;
}

/// \brief Contents of the machine class metatable __index table.
static const auto jsonrpc_machine_static_methods = cartesi::clua_make_luaL_Reg_array({
{"get_default_config", jsonrpc_machine_class_get_default_config},
Expand All @@ -237,6 +255,7 @@ static const auto jsonrpc_machine_static_methods = cartesi::clua_make_luaL_Reg_a
{"get_csr_address", jsonrpc_machine_class_get_csr_address},
{"verify_send_cmio_response_log", jsonrpc_machine_class_verify_send_cmio_response_log},
{"verify_send_cmio_response_state_transition", jsonrpc_machine_class_verify_send_cmio_response_state_transition},
{"verify_step", jsonrpc_machine_class_verify_step},
});

/// \brief Prints a JSONRPC machine class
Expand Down
14 changes: 14 additions & 0 deletions src/clua-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,19 @@ static int machine_class_index_verify_send_cmio_response_log(lua_State *L) {
return 1;
}

/// \brief This is the machine.verify_step() method implementation.
static int machine_class_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);

TRY_EXECUTE(
cm_verify_step(&root_hash_before, luaL_checkstring(L, 2), luaL_checkinteger(L, 3), &root_hash_after, err_msg));
return 1;
}

/// \brief This is the machine.verify_send_cmio_response_state_transition() method implementation.
static int machine_class_index_verify_send_cmio_response_state_transition(lua_State *L) {
lua_settop(L, 6);
Expand Down Expand Up @@ -183,6 +196,7 @@ static const auto machine_class_index = cartesi::clua_make_luaL_Reg_array({
{"get_csr_address", machine_class_index_get_csr_address},
{"verify_send_cmio_response_log", machine_class_index_verify_send_cmio_response_log},
{"verify_send_cmio_response_state_transition", machine_class_index_verify_send_cmio_response_state_transition},
{"verify_step", machine_class_index_verify_step},
});

/// \brief This is the cartesi.machine() constructor implementation.
Expand Down
6 changes: 6 additions & 0 deletions src/i-virtual-machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ class i_virtual_machine {
return do_run(mcycle_end);
}

/// \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 Serialize entire state to directory
void store(const std::string &dir) {
do_store(dir);
Expand Down Expand Up @@ -698,6 +703,7 @@ class i_virtual_machine {

private:
virtual interpreter_break_reason do_run(uint64_t mcycle_end) = 0;
virtual interpreter_break_reason do_log_step(uint64_t mcycle_count, const std::string &filename) = 0;
virtual void do_store(const std::string &dir) = 0;
virtual access_log do_log_uarch_step(const access_log::type &log_type, bool one_based = false) = 0;
virtual machine_merkle_tree::proof_type do_get_proof(uint64_t address, int log2_size) const = 0;
Expand Down
9 changes: 9 additions & 0 deletions src/interpret.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,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"
#endif
#include "machine-statistics.h"
Expand Down Expand Up @@ -5677,6 +5679,13 @@ 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_access32
template interpreter_break_reason interpret(replay_step_state_access &a, uint64_t mcycle_end);

#endif // MICROARCHITECTURE

} // namespace cartesi
8 changes: 8 additions & 0 deletions src/interpret.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,19 @@ extern template interpreter_break_reason interpret(uarch_machine_state_access &a
#else
// Forward declarations
class state_access;
class record_step_state_access;
class replay_step_state_access;
class machine;

// Declaration of explicit instantiation in module interpret.cpp
extern template interpreter_break_reason interpret(state_access &a, uint64_t mcycle_end);

// Declaration of explicit instantiation
extern template interpreter_break_reason interpret(record_step_state_access &a, uint64_t mcycle_end);

// Declaration of explicit instantiation
extern template interpreter_break_reason interpret(replay_step_state_access &a, uint64_t mcycle_end);

#endif // MICROARCHITECTURE
} // namespace cartesi

Expand Down
12 changes: 12 additions & 0 deletions src/jsonrpc-machine-c-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,18 @@ int cm_jsonrpc_verify_send_cmio_response_log(const cm_jsonrpc_mgr *mgr, uint16_t
return cm_result_failure(err_msg);
}

int cm_jsonrpc_verify_step(const cm_jsonrpc_mgr *mgr, const cm_hash *root_hash_before, const char *filename,
uint16_t mcycle_count, const cm_hash *root_hash_after, char **err_msg) try {
const auto *cpp_mgr = convert_from_c(mgr);
const cartesi::machine::hash_type cpp_root_hash_before = convert_from_c(root_hash_before);
const cartesi::machine::hash_type cpp_root_hash_after = convert_from_c(root_hash_after);
cartesi::jsonrpc_virtual_machine::verify_step(*cpp_mgr, cpp_root_hash_before, filename, mcycle_count,
cpp_root_hash_after);
return cm_result_success(err_msg);
} catch (...) {
return cm_result_failure(err_msg);
}

int cm_jsonrpc_verify_send_cmio_response_state_transition(const cm_jsonrpc_mgr *mgr, uint16_t reason,
const unsigned char *data, size_t length, const cm_hash *root_hash_before, const cm_access_log *log,
const cm_hash *root_hash_after, const cm_machine_runtime_config *runtime_config, bool one_based,
Expand Down
10 changes: 10 additions & 0 deletions src/jsonrpc-machine-c-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,16 @@ CM_API int cm_jsonrpc_verify_send_cmio_response_log(const cm_jsonrpc_mgr *mgr, u
const unsigned char *data, size_t length, const cm_access_log *log, const cm_machine_runtime_config *runtime_config,
bool one_based, char **err_msg);

/// \brief Checks the validity of a step log file.
/// \param mgr Cartesi jsonrpc connection manager. Must be pointer to valid object
/// \param root_hash_before Machine root hash before step
/// \param filename Path to the step log file
/// \param mcycle_count Number of mcycles in the step
/// \param root_hash_after Machine root hash after step
/// \param err_msg Receives the error message if function execution fails
CM_API int cm_jsonrpc_verify_step(const cm_jsonrpc_mgr *mgr, const cm_hash *root_hash_before, const char *filename,
uint16_t mcycle_count, const cm_hash *root_hash_after, char **err_msg);

/// \brief Checks the validity of a state transition caused by send_cmio_response
/// \param mgr Cartesi jsonrpc connection manager. Must be pointer to valid object
/// \param reason Reason for sending response.
Expand Down
35 changes: 35 additions & 0 deletions src/jsonrpc-remote-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,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 @@ -1698,6 +1712,25 @@ static json jsonrpc_machine_send_cmio_response_handler(const json &j, const std:
return jsonrpc_response_ok(j);
}

/// \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);
switch (count_args(args)) {
case 4:
cartesi::machine::verify_step(std::get<0>(args), std::get<1>(args), std::get<2>(args), std::get<3>(args));
break;
default:
throw std::runtime_error{"error detecting number of arguments"};
}
return jsonrpc_response_ok(j);
}

static json jsonrpc_machine_log_send_cmio_response_handler(const json &j,
const std::shared_ptr<http_session> &session) {
if (!session->handler->machine) {
Expand Down Expand Up @@ -1911,6 +1944,8 @@ static json jsonrpc_dispatch_method(const json &j, const std::shared_ptr<http_se
{"machine.verify_send_cmio_response_log", jsonrpc_machine_verify_send_cmio_response_log_handler},
{"machine.verify_send_cmio_response_state_transition",
jsonrpc_machine_verify_send_cmio_response_state_transition_handler},
{"machine.log_step", jsonrpc_machine_log_step_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 @@ -440,6 +440,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_mgr->get_stream(), m_mgr->get_remote_address(), "machine.log_step",
std::tie(mcycle_count, filename), result);
return result;
}

void jsonrpc_virtual_machine::do_store(const std::string &directory) {
bool result = false;
jsonrpc_request(m_mgr->get_stream(), m_mgr->get_remote_address(), "machine.store", std::tie(directory), result);
Expand Down Expand Up @@ -1057,6 +1064,15 @@ void jsonrpc_virtual_machine::do_send_cmio_response(uint16_t reason, const unsig
std::tie(reason, b64), result);
}

void jsonrpc_virtual_machine::verify_step(const jsonrpc_mgr_ptr &mgr, const hash_type &root_hash_before,
const char *filename, uint16_t mcycle_count, const hash_type &root_hash_after) {
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(mgr->get_stream(), mgr->get_remote_address(), "machine.verify_step",
std::tie(b64_root_hash_before, filename, mcycle_count, b64_root_hash_after), result);
}

access_log jsonrpc_virtual_machine::do_log_send_cmio_response(uint16_t reason, const unsigned char *data, size_t length,
const access_log::type &log_type, bool one_based) {
not_default_constructible<access_log> result;
Expand Down
4 changes: 4 additions & 0 deletions src/jsonrpc-virtual-machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ class jsonrpc_virtual_machine final : public i_virtual_machine {
const unsigned char *data, size_t length, const hash_type &root_hash_before, const access_log &log,
const hash_type &root_hash_after, const machine_runtime_config &r = {}, bool one_based = false);

static void verify_step(const jsonrpc_mgr_ptr &mgr, const hash_type &root_hash_before, const char *filename,
uint16_t mcycle_count, const hash_type &root_hash_after);

static std::string fork(const jsonrpc_mgr_ptr &mgr);
static void rebind(const jsonrpc_mgr_ptr &mgr, const std::string &address);
static uint64_t get_x_address(const jsonrpc_mgr_ptr &mgr, int i);
Expand All @@ -84,6 +87,7 @@ class jsonrpc_virtual_machine final : public i_virtual_machine {
machine_config do_get_initial_config(void) const 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) override;
uint64_t do_read_csr(csr r) const override;
void do_write_csr(csr w, uint64_t val) override;
Expand Down
22 changes: 22 additions & 0 deletions src/machine-c-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,28 @@ int cm_machine_run(cm_machine *m, uint64_t mcycle_end, CM_BREAK_REASON *break_re
return cm_result_failure(err_msg);
}

int cm_log_step(cm_machine *m, uint64_t mcycle_count, const char *log_filename, CM_BREAK_REASON *break_reason_result,
char **err_msg) try {
auto *cpp_machine = convert_from_c(m);
cartesi::interpreter_break_reason break_reason = cpp_machine->log_step(mcycle_count, null_to_empty(log_filename));
if (break_reason_result) {
*break_reason_result = static_cast<CM_BREAK_REASON>(break_reason);
}
return cm_result_success(err_msg);
} catch (...) {
return cm_result_failure(err_msg);
}

int cm_verify_step(const cm_hash *root_hash_before, const char *log_filename, uint64_t mcycle_count,
const cm_hash *root_hash_after, char **err_msg) try {
const cartesi::machine::hash_type cpp_root_hash_before = convert_from_c(root_hash_before);
const cartesi::machine::hash_type cpp_root_hash_after = convert_from_c(root_hash_after);
cartesi::machine::verify_step(cpp_root_hash_before, null_to_empty(log_filename), mcycle_count, cpp_root_hash_after);
return cm_result_success(err_msg);
} catch (...) {
return cm_result_failure(err_msg);
}

int cm_read_uarch_x(const cm_machine *m, int i, uint64_t *val, char **err_msg) try {
if (val == nullptr) {
throw std::invalid_argument("invalid val output");
Expand Down
Loading

0 comments on commit eb976ed

Please sign in to comment.