diff --git a/src/base64.cpp b/src/base64.cpp index 89b36842e..17978ff71 100644 --- a/src/base64.cpp +++ b/src/base64.cpp @@ -138,7 +138,7 @@ static size_t b64decode(uint8_t c, uint8_t *input, size_t size, std::ostringstre } } -std::string encode_base64(const std::string &input) { +std::string encode_base64(const std::string_view &input) { std::ostringstream sout; uint8_t ctx[4]{}; size_t ctxlen = 0; @@ -149,7 +149,7 @@ std::string encode_base64(const std::string &input) { return sout.str(); } -std::string decode_base64(const std::string &input) { +std::string decode_base64(const std::string_view &input) { std::ostringstream sout; uint8_t ctx[4]{}; size_t ctxlen = 0; diff --git a/src/base64.h b/src/base64.h index 69d0f9100..b2ebe8d20 100644 --- a/src/base64.h +++ b/src/base64.h @@ -18,12 +18,13 @@ #define BASE64_H #include +#include namespace cartesi { -std::string encode_base64(const std::string &input); +std::string encode_base64(const std::string_view &input); -std::string decode_base64(const std::string &input); +std::string decode_base64(const std::string_view &input); } // namespace cartesi diff --git a/src/clua-i-virtual-machine.cpp b/src/clua-i-virtual-machine.cpp index 74bbc59fd..ffc1ab136 100644 --- a/src/clua-i-virtual-machine.cpp +++ b/src/clua-i-virtual-machine.cpp @@ -30,12 +30,11 @@ static int machine_obj_index_get_proof(lua_State *L) { auto &m = clua_check>(L, 1); const uint64_t address = luaL_checkinteger(L, 2); const int log2_size = static_cast(luaL_checkinteger(L, 3)); - auto &managed_proof = clua_push_to(L, clua_managed_cm_ptr(nullptr)); - if (cm_get_proof(m.get(), address, log2_size, &managed_proof.get()) != 0) { + const char *proof = nullptr; + if (cm_get_proof(m.get(), address, log2_size, &proof) != 0) { return luaL_error(L, "%s", cm_get_last_error_message()); } - clua_push_cm_proof(L, managed_proof.get()); - managed_proof.reset(); + clua_push_json(L, nlohmann::json::parse(proof), true); return 1; } diff --git a/src/clua-jsonrpc-machine.cpp b/src/clua-jsonrpc-machine.cpp index 87db35b4d..6b5b91629 100644 --- a/src/clua-jsonrpc-machine.cpp +++ b/src/clua-jsonrpc-machine.cpp @@ -344,7 +344,6 @@ static const auto mod = cartesi::clua_make_luaL_Reg_array({ int clua_jsonrpc_machine_init(lua_State *L, int ctxidx) { clua_createnewtype>(L, ctxidx); - clua_createnewtype>(L, ctxidx); clua_createnewtype>(L, ctxidx); clua_createnewtype>(L, ctxidx); clua_createnewtype>(L, ctxidx); diff --git a/src/clua-machine-util.cpp b/src/clua-machine-util.cpp index c36b142b7..bba0f3c4a 100644 --- a/src/clua-machine-util.cpp +++ b/src/clua-machine-util.cpp @@ -19,6 +19,7 @@ #include #include +#include "base64.h" #include "clua.h" #include "riscv-constants.h" @@ -48,12 +49,6 @@ void cm_delete(cm_access_log *ptr) { cm_delete_access_log(ptr); } -/// \brief Deleter for C api merkle tree proof -template <> -void cm_delete(cm_merkle_tree_proof *ptr) { - cm_delete_merkle_tree_proof(ptr); -} - static char *copy_lua_str(lua_State *L, int idx) { const char *lua_str = lua_tostring(L, idx); auto size = strlen(lua_str) + 1; @@ -253,27 +248,6 @@ static void check_sibling_cm_hashes(lua_State *L, int idx, size_t log2_target_si } } -cm_merkle_tree_proof *clua_check_cm_merkle_tree_proof(lua_State *L, int tabidx, int ctxidx) { - tabidx = lua_absindex(L, tabidx); - luaL_checktype(L, tabidx, LUA_TTABLE); - auto &managed = clua_push_to(L, clua_managed_cm_ptr(new cm_merkle_tree_proof{}), ctxidx); - cm_merkle_tree_proof *proof = managed.get(); - proof->log2_target_size = check_uint_field(L, tabidx, "log2_target_size"); - proof->log2_root_size = check_uint_field(L, tabidx, "log2_root_size"); - proof->target_address = check_uint_field(L, tabidx, "target_address"); - lua_getfield(L, tabidx, "target_hash"); - clua_check_cm_hash(L, -1, &proof->target_hash); - lua_pop(L, 1); - lua_getfield(L, tabidx, "root_hash"); - clua_check_cm_hash(L, -1, &proof->root_hash); - lua_pop(L, 1); - lua_getfield(L, tabidx, "sibling_hashes"); - check_sibling_cm_hashes(L, -1, proof->log2_target_size, proof->log2_root_size, &proof->sibling_hashes); - managed.release(); - lua_pop(L, 2); - return proof; -} - /// \brief Returns an access data field indexed by string in a table /// \param L Lua state /// \param tabidx Table stack index @@ -693,23 +667,6 @@ void clua_push_cm_hash(lua_State *L, const cm_hash *hash) { lua_pushlstring(L, reinterpret_cast(hash), CM_MACHINE_HASH_BYTE_SIZE); } -void clua_push_cm_proof(lua_State *L, const cm_merkle_tree_proof *proof) { - lua_newtable(L); // proof - lua_newtable(L); // proof siblings - for (size_t log2_size = proof->log2_target_size; log2_size < proof->log2_root_size; ++log2_size) { - clua_push_cm_hash(L, &proof->sibling_hashes.entry[proof->log2_root_size - 1 - log2_size]); - lua_rawseti(L, -2, static_cast(proof->log2_root_size - log2_size)); - } - lua_setfield(L, -2, "sibling_hashes"); // proof - clua_setintegerfield(L, proof->target_address, "target_address", -1); // proof - clua_setintegerfield(L, proof->log2_target_size, "log2_target_size", -1); // proof - clua_setintegerfield(L, proof->log2_root_size, "log2_root_size", -1); // proof - clua_push_cm_hash(L, &proof->root_hash); - lua_setfield(L, -2, "root_hash"); // proof - clua_push_cm_hash(L, &proof->target_hash); - lua_setfield(L, -2, "target_hash"); // proof -} - cm_access_log_type clua_check_cm_log_type(lua_State *L, int tabidx) { luaL_checktype(L, tabidx, LUA_TTABLE); return cm_access_log_type{ @@ -743,14 +700,14 @@ static int64_t clua_get_array_table_len(lua_State *L, int tabidx) { return len; } -nlohmann::json clua_value_to_json(lua_State *L, int idx) { +nlohmann::json clua_value_to_json(lua_State *L, int idx, bool base64encode) { nlohmann::json j; const int64_t len = clua_get_array_table_len(L, idx); if (len >= 0) { // array j = nlohmann::json::array(); for (int64_t i = 1; i <= len; ++i) { lua_geti(L, idx, i); - j.push_back(clua_value_to_json(L, -1)); + j.push_back(clua_value_to_json(L, -1, base64encode)); lua_pop(L, 1); // pop value } } else if (lua_istable(L, idx)) { // object @@ -760,7 +717,7 @@ nlohmann::json clua_value_to_json(lua_State *L, int idx) { while (lua_next(L, -2)) { // update key, push value lua_pushvalue(L, -2); // push key again, because luaL_checkstring may overwrite it const char *key = luaL_checkstring(L, -1); - j[key] = clua_value_to_json(L, -2); + j[key] = clua_value_to_json(L, -2, base64encode); lua_pop(L, 2); // pop key, value } lua_pop(L, 1); // pop table @@ -769,7 +726,14 @@ nlohmann::json clua_value_to_json(lua_State *L, int idx) { } else if (lua_isnumber(L, idx)) { j = lua_tonumber(L, idx); } else if (lua_isstring(L, idx)) { - j = std::string(lua_tostring(L, idx)); + size_t len = 0; + const char *ptr = lua_tolstring(L, idx, &len); + const std::string_view data(ptr, len); + if (base64encode) { + j = cartesi::encode_base64(data); + } else { + j = data; + } } else if (lua_isboolean(L, idx)) { j = static_cast(lua_toboolean(L, idx)); } else if (lua_isnil(L, idx)) { @@ -780,22 +744,28 @@ nlohmann::json clua_value_to_json(lua_State *L, int idx) { return j; } -void clua_push_json(lua_State *L, const nlohmann::json &j) { +void clua_push_json(lua_State *L, const nlohmann::json &j, bool base64decode) { if (j.is_array()) { lua_createtable(L, static_cast(j.size()), 0); int64_t i = 1; for (auto it = j.begin(); it != j.end(); ++it, ++i) { - clua_push_json(L, *it); + clua_push_json(L, *it, base64decode); lua_rawseti(L, -2, i); } } else if (j.is_object()) { lua_createtable(L, 0, static_cast(j.size())); for (const auto &el : j.items()) { - clua_push_json(L, el.value()); + clua_push_json(L, el.value(), base64decode); lua_setfield(L, -2, el.key().c_str()); } } else if (j.is_string()) { - lua_pushstring(L, j.template get().c_str()); + const auto data = j.template get(); + if (base64decode) { + const auto base64data = cartesi::decode_base64(data); + lua_pushlstring(L, base64data.data(), base64data.length()); + } else { + lua_pushlstring(L, data.data(), data.length()); + } } else if (j.is_number_unsigned()) { lua_pushinteger(L, static_cast(j.template get())); } else if (j.is_number_integer()) { diff --git a/src/clua-machine-util.h b/src/clua-machine-util.h index c6b3f87a2..a7f14a997 100644 --- a/src/clua-machine-util.h +++ b/src/clua-machine-util.h @@ -52,10 +52,6 @@ void cm_delete(cm_machine *ptr); template <> void cm_delete(cm_access_log *ptr); -/// \brief Deleter for C api merkle tree proof -template <> -void cm_delete(cm_merkle_tree_proof *p); - // clua_managed_cm_ptr is a smart pointer, // however we don't use all its functionally, therefore we exclude it from code coverage. // LCOV_EXCL_START @@ -115,11 +111,6 @@ class clua_managed_cm_ptr final { }; // LCOV_EXCL_STOP -/// \brief Pushes a C api proof to the Lua stack -/// \param L Lua state -/// \param proof Proof to be pushed -void clua_push_cm_proof(lua_State *L, const cm_merkle_tree_proof *proof); - /// \brief Pushes a C api hash object to the Lua stack /// \param L Lua state /// \param hash Hash to be pushed @@ -148,12 +139,6 @@ cm_access_log_type clua_check_cm_log_type(lua_State *L, int tabidx); /// \param c_hash Receives hash void clua_check_cm_hash(lua_State *L, int idx, cm_hash *c_hash); -/// \brief Loads a cm_merkle_tree_proof from Lua -/// \param L Lua state -/// \param tabidx Proof stack index -/// \returns The allocated proof object -cm_merkle_tree_proof *clua_check_cm_merkle_tree_proof(lua_State *L, int tabidx); - /// \brief Loads an cm_access_log from Lua. /// \param L Lua state /// \param tabidx Access_log stack index. @@ -161,8 +146,8 @@ cm_merkle_tree_proof *clua_check_cm_merkle_tree_proof(lua_State *L, int tabidx); /// \returns The access log. Must be delete by the user with cm_delete_access_log cm_access_log *clua_check_cm_access_log(lua_State *L, int tabidx, int ctxidx = lua_upvalueindex(1)); -nlohmann::json clua_value_to_json(lua_State *L, int tabidx); -void clua_push_json(lua_State *L, const nlohmann::json &j); +nlohmann::json clua_value_to_json(lua_State *L, int tabidx, bool base64encode = false); +void clua_push_json(lua_State *L, const nlohmann::json &j, bool base64decode = false); } // namespace cartesi diff --git a/src/clua-machine.cpp b/src/clua-machine.cpp index e92b3ebc0..9d8b7501b 100644 --- a/src/clua-machine.cpp +++ b/src/clua-machine.cpp @@ -169,7 +169,6 @@ struct machine_class {}; int clua_machine_init(lua_State *L, int ctxidx) { clua_createnewtype>(L, ctxidx); - clua_createnewtype>(L, ctxidx); clua_createnewtype>(L, ctxidx); clua_createnewtype>(L, ctxidx); if (!clua_typeexists(L, ctxidx)) { diff --git a/src/json-util.cpp b/src/json-util.cpp index c5098b13d..58dd22a5b 100644 --- a/src/json-util.cpp +++ b/src/json-util.cpp @@ -876,10 +876,10 @@ void ju_get_opt_field(const nlohmann::json &j, const K &key, throw std::invalid_argument("field \""s + new_path + "sibling_hashes\" not an array"s); } const auto sibling_hashes_base = path + "sibling_hashes/"; - for (int log2_size = proof.get_log2_root_size() - 1; log2_size >= proof.get_log2_target_size(); --log2_size) { + for (int log2_size = proof.get_log2_target_size(), i = 0; log2_size < proof.get_log2_root_size(); + ++log2_size, ++i) { machine_merkle_tree::proof_type::hash_type sibling_hash; - ju_get_field(sh, static_cast(proof.get_log2_root_size() - 1 - log2_size), sibling_hash, - sibling_hashes_base); + ju_get_field(sh, i, sibling_hash, sibling_hashes_base); proof.set_sibling_hash(sibling_hash, log2_size); } } @@ -1608,7 +1608,7 @@ void to_json(nlohmann::json &j, const std::vector= p.get_log2_target_size(); --log2_size) { + for (int log2_size = p.get_log2_target_size(); log2_size < p.get_log2_root_size(); ++log2_size) { s.push_back(encode_base64(p.get_sibling_hash(log2_size))); } j = nlohmann::json{{"target_address", p.get_target_address()}, {"log2_target_size", p.get_log2_target_size()}, diff --git a/src/machine-c-api.cpp b/src/machine-c-api.cpp index a864efc44..85bccd186 100644 --- a/src/machine-c-api.cpp +++ b/src/machine-c-api.cpp @@ -184,50 +184,6 @@ static cm_hash_array *convert_to_c(const std::vectorlog2_root_size = proof.get_log2_root_size(); - new_merkle_tree_proof->log2_target_size = proof.get_log2_target_size(); - new_merkle_tree_proof->target_address = proof.get_target_address(); - - memcpy(&new_merkle_tree_proof->root_hash, static_cast(proof.get_root_hash().data()), - sizeof(cm_hash)); - memcpy(&new_merkle_tree_proof->target_hash, static_cast(proof.get_target_hash().data()), - sizeof(cm_hash)); - - new_merkle_tree_proof->sibling_hashes.count = - new_merkle_tree_proof->log2_root_size - new_merkle_tree_proof->log2_target_size; - new_merkle_tree_proof->sibling_hashes.entry = new cm_hash[new_merkle_tree_proof->sibling_hashes.count]; - memset(new_merkle_tree_proof->sibling_hashes.entry, 0, - sizeof(cm_hash) * new_merkle_tree_proof->sibling_hashes.count); - - for (size_t log2_size = new_merkle_tree_proof->log2_target_size; log2_size < new_merkle_tree_proof->log2_root_size; - ++log2_size) { - const int current_index = cm_log2_size_to_index(static_cast(log2_size), - static_cast(new_merkle_tree_proof->log2_target_size)); - const cartesi::machine_merkle_tree::hash_type sibling_hash = - proof.get_sibling_hash(static_cast(log2_size)); - memcpy(&(new_merkle_tree_proof->sibling_hashes.entry[current_index]), - static_cast(sibling_hash.data()), sizeof(cm_hash)); - } - - return new_merkle_tree_proof; -} - // ---------------------------------------------- // Access log conversion functions // ---------------------------------------------- @@ -614,26 +570,19 @@ int cm_verify_reset_uarch_state_transition(const cm_hash *root_hash_before, cons return cm_result_failure(); } -int cm_get_proof(const cm_machine *m, uint64_t address, int log2_size, cm_merkle_tree_proof **proof) try { +int cm_get_proof(const cm_machine *m, uint64_t address, int log2_size, const char **proof) try { if (proof == nullptr) { throw std::invalid_argument("invalid proof output"); } const auto *cpp_machine = convert_from_c(m); const cartesi::machine_merkle_tree::proof_type cpp_proof = cpp_machine->get_proof(address, log2_size); - *proof = convert_to_c(cpp_proof); + static THREAD_LOCAL char proof_buf[CM_MAX_CONFIG_LENGTH]; + *proof = string_to_buf(proof_buf, sizeof(proof_buf), cartesi::to_json(cpp_proof).dump()); return cm_result_success(); } catch (...) { return cm_result_failure(); } -void cm_delete_merkle_tree_proof(cm_merkle_tree_proof *proof) { - if (proof == nullptr) { - return; - } - delete[] proof->sibling_hashes.entry; - delete proof; -} - int cm_get_root_hash(const cm_machine *m, cm_hash *hash) try { if (hash == nullptr) { throw std::invalid_argument("invalid hash output"); diff --git a/src/machine-c-api.h b/src/machine-c-api.h index 64747a80a..d64bb21f5 100644 --- a/src/machine-c-api.h +++ b/src/machine-c-api.h @@ -273,19 +273,6 @@ typedef enum { // NOLINT(modernize-use-using) CM_UARCH_BREAK_REASON_UARCH_HALTED, } CM_UARCH_BREAK_REASON; -/// \brief Merkle tree proof structure -/// \details -/// This structure holds a proof that the node spanning a log2_target_size -/// at a given address in the tree has a certain hash. -typedef struct { // NOLINT(modernize-use-using) - uint64_t target_address; - size_t log2_target_size; - cm_hash target_hash; - size_t log2_root_size; - cm_hash root_hash; - cm_hash_array sibling_hashes; -} cm_merkle_tree_proof; - /// \brief Type of state access typedef enum { // NOLINT(modernize-use-using) CM_ACCESS_READ, ///< Read operation @@ -439,20 +426,17 @@ CM_API int cm_verify_reset_uarch_state_transition(const cm_hash *root_hash_befor /// \returns 0 for success, non zero code for error CM_API int cm_verify_reset_uarch_log(const cm_access_log *log, bool one_based); -/// \brief Obtains the proof for a node in the Merkle tree -/// \param m Pointer to valid machine instance -/// \param address Address of target node. Must be aligned to a 2log2_size boundary -/// \param log2_size log2 of size subintended by target node. -/// Must be between 3 (for a word) and 64 (for the entire address space), inclusive -/// \param proof Receives the proof -/// proof must be deleted with the function cm_delete_merkle_tree_proof -/// \returns 0 for success, non zero code for error -/// \details If the node is smaller than a page size, then it must lie entirely inside the same PMA range. -CM_API int cm_get_proof(const cm_machine *m, uint64_t address, int log2_size, cm_merkle_tree_proof **proof); - -/// \brief Deletes the instance of cm_merkle_tree_proof acquired from cm_get_proof -/// \param proof Valid pointer to cm_merkle_tree_proof object -CM_API void cm_delete_merkle_tree_proof(cm_merkle_tree_proof *proof); +/// \brief Obtains the proof for a node in the Merkle tree. +/// \param m Pointer to a valid machine instance. +/// \param address Address of target node. Must be aligned to a 2^log2_size boundary. +/// \param log2_size The log2 of size subtended by target node. +/// Must be between 3 (for a word) and 64 (for the entire address space), inclusive. +/// \param proof Receives the proof as a JSON string, +/// remains valid until the next time this same function is called on the same thread. +/// \returns 0 for success, non zero code for error. +/// \details If the node is smaller than a page size, +/// then it must lie entirely inside the same PMA range. +CM_API int cm_get_proof(const cm_machine *m, uint64_t address, int log2_size, const char **proof); /// \brief Obtains the root hash of the Merkle tree /// \param m Pointer to valid machine instance diff --git a/tests/misc/test-machine-c-api.cpp b/tests/misc/test-machine-c-api.cpp index d5feb85c5..f4cc7e8b4 100644 --- a/tests/misc/test-machine-c-api.cpp +++ b/tests/misc/test-machine-c-api.cpp @@ -62,10 +62,6 @@ BOOST_AUTO_TEST_CASE_NOLINT(delete_machine_null_test) { BOOST_CHECK_NO_THROW(cm_delete_machine(nullptr)); } -BOOST_AUTO_TEST_CASE_NOLINT(delete_proof_null_test) { - BOOST_CHECK_NO_THROW(cm_delete_merkle_tree_proof(nullptr)); -} - BOOST_AUTO_TEST_CASE_NOLINT(get_default_machine_config_basic_test) { const char *config = cm_get_default_config(); BOOST_TEST_CHECK(config != nullptr); @@ -370,7 +366,6 @@ BOOST_AUTO_TEST_CASE_NOLINT(get_root_hash_null_machine_test) { BOOST_AUTO_TEST_CASE_NOLINT(delete_null_test) { cm_delete_machine(nullptr); cm_delete_access_log(nullptr); - cm_delete_merkle_tree_proof(nullptr); } BOOST_FIXTURE_TEST_CASE_NOLINT(get_root_hash_null_hash_test, ordinary_machine_fixture) { @@ -389,13 +384,13 @@ BOOST_FIXTURE_TEST_CASE_NOLINT(get_root_hash_machine_hash_test, ordinary_machine } BOOST_AUTO_TEST_CASE_NOLINT(get_proof_null_machine_test) { - cm_merkle_tree_proof *proof{}; + const char *proof{}; int error_code = cm_get_proof(nullptr, 0, 12, &proof); BOOST_CHECK_EQUAL(error_code, CM_ERROR_INVALID_ARGUMENT); } BOOST_FIXTURE_TEST_CASE_NOLINT(get_proof_invalid_address_test, ordinary_machine_fixture) { - cm_merkle_tree_proof *proof{}; + const char *proof{}; int error_code = cm_get_proof(_machine, 1, 12, &proof); BOOST_CHECK_EQUAL(error_code, CM_ERROR_INVALID_ARGUMENT); @@ -405,7 +400,7 @@ BOOST_FIXTURE_TEST_CASE_NOLINT(get_proof_invalid_address_test, ordinary_machine_ } BOOST_FIXTURE_TEST_CASE_NOLINT(get_proof_invalid_log2_test, ordinary_machine_fixture) { - cm_merkle_tree_proof *proof{}; + const char *proof{}; // log2_root_size = 64 int error_code = cm_get_proof(_machine, 0, 65, &proof); @@ -422,16 +417,14 @@ BOOST_FIXTURE_TEST_CASE_NOLINT(get_proof_invalid_log2_test, ordinary_machine_fix } BOOST_FIXTURE_TEST_CASE_NOLINT(get_proof_inconsistent_tree_test, ordinary_machine_fixture) { - cm_merkle_tree_proof *proof{}; + const char *proof{}; int error_code = cm_get_proof(_machine, 0, 64, &proof); BOOST_CHECK_EQUAL(error_code, CM_ERROR_OK); - cm_delete_merkle_tree_proof(proof); // merkle tree is always consistent now as it updates on access error_code = cm_get_proof(_machine, 0, CM_TREE_LOG2_PAGE_SIZE, &proof); BOOST_CHECK_EQUAL(error_code, CM_ERROR_OK); - cm_delete_merkle_tree_proof(proof); } BOOST_FIXTURE_TEST_CASE_NOLINT(get_proof_null_proof_test, ordinary_machine_fixture) { @@ -440,22 +433,24 @@ BOOST_FIXTURE_TEST_CASE_NOLINT(get_proof_null_proof_test, ordinary_machine_fixtu } BOOST_FIXTURE_TEST_CASE_NOLINT(get_proof_machine_hash_test, ordinary_machine_fixture) { - - cm_merkle_tree_proof *p{}; - int error_code = cm_get_proof(_machine, 0, 12, &p); + const char *proof_str{}; + int error_code = cm_get_proof(_machine, 0, 12, &proof_str); BOOST_CHECK_EQUAL(error_code, CM_ERROR_OK); BOOST_CHECK_EQUAL(std::string(""), std::string(cm_get_last_error_message())); - auto verification = calculate_proof_root_hash(p); - BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), p->root_hash, - p->root_hash + sizeof(cm_hash)); + const auto proof = + cartesi::from_json>(proof_str) + .value(); + auto proof_root_hash = proof.get_root_hash(); + auto verification = calculate_proof_root_hash(proof); + BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), proof_root_hash.begin(), + proof_root_hash.end()); verification = calculate_emulator_hash(_machine); - BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), p->root_hash, - p->root_hash + sizeof(cm_hash)); - BOOST_CHECK_EQUAL(p->log2_root_size, static_cast(64)); - BOOST_CHECK_EQUAL(p->sibling_hashes.count, static_cast(52)); + BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), proof_root_hash.begin(), + proof_root_hash.end()); - cm_delete_merkle_tree_proof(p); + BOOST_REQUIRE(proof.get_log2_root_size() == 64); + BOOST_REQUIRE(proof.get_sibling_hashes().size() == 52); } BOOST_AUTO_TEST_CASE_NOLINT(read_word_null_machine_test) { @@ -1614,34 +1609,37 @@ BOOST_FIXTURE_TEST_CASE_NOLINT(machine_verify_merkle_tree_root_updates_test, ord } BOOST_FIXTURE_TEST_CASE_NOLINT(machine_verify_merkle_tree_proof_updates_test, ordinary_machine_fixture) { - - cm_merkle_tree_proof *start_proof{}; - int error_code = cm_get_proof(_machine, 0, 12, &start_proof); + const char *proof_str{}; + int error_code = cm_get_proof(_machine, 0, 12, &proof_str); BOOST_CHECK_EQUAL(error_code, CM_ERROR_OK); BOOST_CHECK_EQUAL(std::string(""), std::string(cm_get_last_error_message())); - auto verification = calculate_proof_root_hash(start_proof); - BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), start_proof->root_hash, - start_proof->root_hash + sizeof(cm_hash)); + auto proof = + cartesi::from_json>(proof_str) + .value(); + auto proof_root_hash = proof.get_root_hash(); + auto verification = calculate_proof_root_hash(proof); + BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), proof_root_hash.begin(), + proof_root_hash.end()); verification = calculate_emulator_hash(_machine); - BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), start_proof->root_hash, - start_proof->root_hash + sizeof(cm_hash)); - cm_delete_merkle_tree_proof(start_proof); + BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), proof_root_hash.begin(), + proof_root_hash.end()); error_code = cm_run(_machine, 1000, nullptr); BOOST_CHECK_EQUAL(error_code, CM_ERROR_OK); BOOST_CHECK_EQUAL(std::string(""), std::string(cm_get_last_error_message())); - cm_merkle_tree_proof *end_proof{}; - error_code = cm_get_proof(_machine, 0, 12, &end_proof); + error_code = cm_get_proof(_machine, 0, 12, &proof_str); BOOST_CHECK_EQUAL(error_code, CM_ERROR_OK); BOOST_CHECK_EQUAL(std::string(""), std::string(cm_get_last_error_message())); - verification = calculate_proof_root_hash(end_proof); - BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), end_proof->root_hash, - end_proof->root_hash + sizeof(cm_hash)); + proof = cartesi::from_json>(proof_str) + .value(); + proof_root_hash = proof.get_root_hash(); + verification = calculate_proof_root_hash(proof); + BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), proof_root_hash.begin(), + proof_root_hash.end()); verification = calculate_emulator_hash(_machine); - BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), end_proof->root_hash, - end_proof->root_hash + sizeof(cm_hash)); - cm_delete_merkle_tree_proof(end_proof); + BOOST_CHECK_EQUAL_COLLECTIONS(verification.begin(), verification.end(), proof_root_hash.begin(), + proof_root_hash.end()); } BOOST_AUTO_TEST_CASE_NOLINT(uarch_solidity_compatibility_layer) { diff --git a/tests/misc/test-utils.h b/tests/misc/test-utils.h index 33dd250f4..9fc017d64 100644 --- a/tests/misc/test-utils.h +++ b/tests/misc/test-utils.h @@ -20,6 +20,7 @@ #include #include #include +#include using hash_type = cartesi::keccak_256_hasher::hash_type; @@ -63,21 +64,23 @@ static hash_type merkle_hash(const std::string_view &data, int log2_size) { return detail::merkle_hash(h, data, log2_size); } -static hash_type calculate_proof_root_hash(const cm_merkle_tree_proof *proof) { +static hash_type calculate_proof_root_hash(const cartesi::machine_merkle_tree::proof_type &proof) { hash_type hash; - memcpy(hash.data(), proof->target_hash, sizeof(cm_hash)); - for (int log2_size = static_cast(proof->log2_target_size); log2_size < static_cast(proof->log2_root_size); - ++log2_size) { + memcpy(hash.data(), proof.get_target_hash().data(), sizeof(cm_hash)); + for (int log2_size = static_cast(proof.get_log2_target_size()); + log2_size < static_cast(proof.get_log2_root_size()); ++log2_size) { cartesi::keccak_256_hasher h; - auto bit = (proof->target_address & (UINT64_C(1) << log2_size)); + auto bit = (proof.get_target_address() & (UINT64_C(1) << log2_size)); hash_type first; hash_type second; if (bit) { - memcpy(first.data(), proof->sibling_hashes.entry[log2_size - proof->log2_target_size], sizeof(cm_hash)); + memcpy(first.data(), proof.get_sibling_hashes()[log2_size - proof.get_log2_target_size()].data(), + sizeof(cm_hash)); second = hash; } else { first = hash; - memcpy(second.data(), proof->sibling_hashes.entry[log2_size - proof->log2_target_size], sizeof(cm_hash)); + memcpy(second.data(), proof.get_sibling_hashes()[log2_size - proof.get_log2_target_size()].data(), + sizeof(cm_hash)); } get_concat_hash(h, first, second, hash); }