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 #280

Closed
wants to merge 1 commit into from
Closed
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 @@ -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
Loading