Skip to content

Commit

Permalink
refactor!: use JSON strings for cm_get_proof C API
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Sep 10, 2024
1 parent 9bf1fff commit 24bfd1e
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 210 deletions.
4 changes: 2 additions & 2 deletions src/base64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions src/base64.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@
#define BASE64_H

#include <string>
#include <string_view>

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

Expand Down
7 changes: 3 additions & 4 deletions src/clua-i-virtual-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,11 @@ static int machine_obj_index_get_proof(lua_State *L) {
auto &m = clua_check<clua_managed_cm_ptr<cm_machine>>(L, 1);
const uint64_t address = luaL_checkinteger(L, 2);
const int log2_size = static_cast<int>(luaL_checkinteger(L, 3));
auto &managed_proof = clua_push_to(L, clua_managed_cm_ptr<cm_merkle_tree_proof>(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;
}

Expand Down
1 change: 0 additions & 1 deletion src/clua-jsonrpc-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<clua_managed_cm_ptr<cm_access_log>>(L, ctxidx);
clua_createnewtype<clua_managed_cm_ptr<cm_merkle_tree_proof>>(L, ctxidx);
clua_createnewtype<clua_managed_cm_ptr<char>>(L, ctxidx);
clua_createnewtype<clua_managed_cm_ptr<unsigned char>>(L, ctxidx);
clua_createnewtype<clua_managed_cm_ptr<cm_jsonrpc_mgr>>(L, ctxidx);
Expand Down
74 changes: 22 additions & 52 deletions src/clua-machine-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <cstring>
#include <unordered_map>

#include "base64.h"
#include "clua.h"
#include "riscv-constants.h"

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<cm_merkle_tree_proof>(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
Expand Down Expand Up @@ -693,23 +667,6 @@ void clua_push_cm_hash(lua_State *L, const cm_hash *hash) {
lua_pushlstring(L, reinterpret_cast<const char *>(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<lua_Integer>(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{
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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<bool>(lua_toboolean(L, idx));
} else if (lua_isnil(L, idx)) {
Expand All @@ -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<int>(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<int>(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<std::string>().c_str());
const auto data = j.template get<std::string_view>();
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<int64_t>(j.template get<uint64_t>()));
} else if (j.is_number_integer()) {
Expand Down
19 changes: 2 additions & 17 deletions src/clua-machine-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@ void cm_delete<cm_machine>(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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -148,21 +139,15 @@ 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.
/// \param ctxidx Index of clua context
/// \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

Expand Down
1 change: 0 additions & 1 deletion src/clua-machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ struct machine_class {};

int clua_machine_init(lua_State *L, int ctxidx) {
clua_createnewtype<clua_managed_cm_ptr<cm_access_log>>(L, ctxidx);
clua_createnewtype<clua_managed_cm_ptr<cm_merkle_tree_proof>>(L, ctxidx);
clua_createnewtype<clua_managed_cm_ptr<char>>(L, ctxidx);
clua_createnewtype<clua_managed_cm_ptr<unsigned char>>(L, ctxidx);
if (!clua_typeexists<machine_class>(L, ctxidx)) {
Expand Down
8 changes: 4 additions & 4 deletions src/json-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint64_t>(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);
}
}
Expand Down Expand Up @@ -1608,7 +1608,7 @@ void to_json(nlohmann::json &j, const std::vector<machine_merkle_tree::hash_type

void to_json(nlohmann::json &j, const machine_merkle_tree::proof_type &p) {
nlohmann::json s = nlohmann::json::array();
for (int log2_size = p.get_log2_root_size() - 1; log2_size >= 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()},
Expand Down
57 changes: 3 additions & 54 deletions src/machine-c-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,50 +184,6 @@ static cm_hash_array *convert_to_c(const std::vector<cartesi::machine_merkle_tre
return new_array;
}

// ----------------------------------------------
// Merkle tree proof conversion functions
// ----------------------------------------------

/// \brief Converts log2_size to index into siblings array
static int cm_log2_size_to_index(int log2_size, int log2_target_size) {
const int index = log2_size - log2_target_size;
if (index < 0) {
throw std::invalid_argument("log2_size can't be smaller than log2_target_size");
}
return index;
}

static cm_merkle_tree_proof *convert_to_c(const cartesi::machine_merkle_tree::proof_type &proof) {
auto *new_merkle_tree_proof = new cm_merkle_tree_proof{};

new_merkle_tree_proof->log2_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<const uint8_t *>(proof.get_root_hash().data()),
sizeof(cm_hash));
memcpy(&new_merkle_tree_proof->target_hash, static_cast<const uint8_t *>(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<int>(log2_size),
static_cast<int>(new_merkle_tree_proof->log2_target_size));
const cartesi::machine_merkle_tree::hash_type sibling_hash =
proof.get_sibling_hash(static_cast<int>(log2_size));
memcpy(&(new_merkle_tree_proof->sibling_hashes.entry[current_index]),
static_cast<const uint8_t *>(sibling_hash.data()), sizeof(cm_hash));
}

return new_merkle_tree_proof;
}

// ----------------------------------------------
// Access log conversion functions
// ----------------------------------------------
Expand Down Expand Up @@ -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");
Expand Down
Loading

0 comments on commit 24bfd1e

Please sign in to comment.