Skip to content

Commit

Permalink
Variant hashing refactor + etc
Browse files Browse the repository at this point in the history
  • Loading branch information
madMAx43v3r committed Oct 26, 2024
1 parent 2c1c7c9 commit d7e4cc6
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 31 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ add_library(mmx_iface SHARED
src/VDF_Point.cpp
src/Partial.cpp
src/ChainParams.cpp
src/utils.cpp
)

add_library(mmx_vm SHARED
Expand Down
2 changes: 2 additions & 0 deletions include/mmx/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

namespace mmx {

bool is_json(const vnx::Variant& var);

inline
std::shared_ptr<const ChainParams> get_params()
{
Expand Down
66 changes: 41 additions & 25 deletions include/mmx/write_bytes.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,16 @@ void write_bytes(vnx::OutputBuffer& out, const std::set<T>& value);
template<typename K, typename V>
void write_bytes(vnx::OutputBuffer& out, const std::map<K, V>& value);

void write_bytes(vnx::OutputBuffer& out, const vnx::Object& value);

template<typename T>
void write_field(vnx::OutputBuffer& out, const std::string& name, const T& value);

inline void write_bytes(vnx::OutputBuffer& out, const bool& value) {
const uint8_t tmp = value ? 1 : 0;
out.write(&tmp, sizeof(tmp));
}

inline void write_bytes(vnx::OutputBuffer& out, const int64_t& value) {
out.write(&value, sizeof(value));
}
Expand Down Expand Up @@ -85,40 +92,51 @@ inline void write_bytes_cstr(vnx::OutputBuffer& out, const char* str) {
out.write(str, ::strlen(str));
}

template<size_t N>
void write_bytes(vnx::OutputBuffer& out, const bytes_t<N>& value)
inline void write_bytes(vnx::OutputBuffer& out, const std::string& value)
{
write_bytes_cstr(out, "bytes<>");
write_bytes(out, uint16_t(value.size()));
write_bytes_cstr(out, "string<>");
write_bytes(out, uint64_t(value.size()));
out.write(value.data(), value.size());
}

inline void write_bytes(vnx::OutputBuffer& out, const std::string& value)
template<size_t N>
void write_bytes(vnx::OutputBuffer& out, const bytes_t<N>& value)
{
write_bytes_cstr(out, "string<>");
write_bytes(out, uint32_t(value.size()));
write_bytes_cstr(out, "bytes<>");
write_bytes(out, uint64_t(value.size()));
out.write(value.data(), value.size());
}

inline void write_bytes(vnx::OutputBuffer& out, const std::vector<uint8_t>& value)
{
write_bytes_cstr(out, "vector<>");
write_bytes(out, uint32_t(value.size()));
write_bytes_cstr(out, "bytes<>");
write_bytes(out, uint64_t(value.size()));
out.write(value.data(), value.size());
}

inline void write_bytes(vnx::OutputBuffer& out, const vnx::Buffer& value)
{
write_bytes_cstr(out, "vector<>");
write_bytes(out, uint32_t(value.size()));
write_bytes_cstr(out, "bytes<>");
write_bytes(out, uint64_t(value.size()));
out.write(value.data(), value.size());
}

inline void write_bytes(vnx::OutputBuffer& out, const vnx::Variant& value)
{
write_bytes_cstr(out, "variant<>");
if(value.empty()) {
write_bytes(out, vnx::Variant(nullptr).data);
if(value.is_null()) {
write_bytes_cstr(out, "NULL");
} else if(value.is_bool()) {
write_bytes(out, value.to<bool>());
} else if(value.is_ulong()) {
write_bytes(out, value.to<uint64_t>());
} else if(value.is_long()) {
write_bytes(out, value.to<int64_t>());
} else if(value.is_string()) {
write_bytes(out, value.to<std::string>());
} else if(value.is_array()) {
write_bytes(out, value.to<std::vector<vnx::Variant>>());
} else if(value.is_object()) {
write_bytes(out, value.to_object());
} else {
write_bytes(out, value.data);
}
Expand Down Expand Up @@ -193,10 +211,10 @@ template<typename T>
void write_bytes(vnx::OutputBuffer& out, const vnx::optional<T>& value) {
write_bytes_cstr(out, "optional<>");
if(value) {
write_bytes(out, uint8_t(1));
write_bytes(out, true);
write_bytes(out, *value);
} else {
write_bytes(out, uint8_t(0));
write_bytes(out, false);
}
}

Expand All @@ -210,7 +228,7 @@ void write_bytes(vnx::OutputBuffer& out, const std::pair<T, S>& value) {
template<typename T, size_t N>
void write_bytes(vnx::OutputBuffer& out, const std::array<T, N>& value) {
write_bytes_cstr(out, "vector<>");
write_bytes(out, uint32_t(value.size()));
write_bytes(out, uint64_t(value.size()));
for(const auto& elem : value) {
write_bytes(out, elem);
}
Expand All @@ -219,7 +237,7 @@ void write_bytes(vnx::OutputBuffer& out, const std::array<T, N>& value) {
template<typename T>
void write_bytes(vnx::OutputBuffer& out, const std::vector<T>& value) {
write_bytes_cstr(out, "vector<>");
write_bytes(out, uint32_t(value.size()));
write_bytes(out, uint64_t(value.size()));
for(const auto& elem : value) {
write_bytes(out, elem);
}
Expand All @@ -228,7 +246,7 @@ void write_bytes(vnx::OutputBuffer& out, const std::vector<T>& value) {
template<typename T>
void write_bytes(vnx::OutputBuffer& out, const std::vector<T>& value, bool full_hash) {
write_bytes_cstr(out, "vector<>");
write_bytes(out, uint32_t(value.size()));
write_bytes(out, uint64_t(value.size()));
for(const auto& elem : value) {
write_bytes(out, elem, full_hash);
}
Expand All @@ -237,20 +255,18 @@ void write_bytes(vnx::OutputBuffer& out, const std::vector<T>& value, bool full_
template<typename T>
void write_bytes(vnx::OutputBuffer& out, const std::set<T>& value) {
write_bytes_cstr(out, "vector<>");
write_bytes(out, uint32_t(value.size()));
write_bytes(out, uint64_t(value.size()));
for(const auto& elem : value) {
write_bytes(out, elem);
}
}

template<typename K, typename V>
void write_bytes(vnx::OutputBuffer& out, const std::map<K, V>& value) {
write_bytes_cstr(out, "map<>");
write_bytes(out, uint32_t(value.size()));
write_bytes_cstr(out, "vector<>");
write_bytes(out, uint64_t(value.size()));
for(const auto& entry : value) {
write_bytes_cstr(out, "pair<>");
write_bytes(out, entry.first);
write_bytes(out, entry.second);
write_bytes(out, entry);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/contract/Data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace contract {

vnx::bool_t Data::is_valid() const
{
return Super::is_valid() && value.is_json_strict(100);
return Super::is_valid() && is_json(value);
}

hash_t Data::calc_hash(const vnx::bool_t& full_hash) const
Expand Down
2 changes: 1 addition & 1 deletion src/contract/Executable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace contract {
bool Executable::is_valid() const
{
for(const auto& arg : init_args) {
if(!arg.is_json_strict(100)) {
if(!is_json(arg)) {
return false;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/contract/TokenBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ vnx::bool_t TokenBase::is_valid() const
return Super::is_valid() && name.size() <= 64 && symbol.size() <= 6
&& symbol != "MMX" && symbol.find_first_of(" \n\t\r\b\f") == std::string::npos
&& decimals >= 0 && decimals <= 18
&& meta_data.is_json_strict(100);
&& is_json(meta_data);
}

hash_t TokenBase::calc_hash(const vnx::bool_t& full_hash) const
Expand Down
3 changes: 2 additions & 1 deletion src/operation/Execute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <mmx/operation/Execute.hxx>
#include <mmx/write_bytes.h>
#include <mmx/utils.h>


namespace mmx {
Expand All @@ -15,7 +16,7 @@ namespace operation {
vnx::bool_t Execute::is_valid() const
{
for(const auto& arg : args) {
if(!arg.is_json_strict(100)) {
if(!is_json(arg)) {
return false;
}
}
Expand Down
104 changes: 104 additions & 0 deletions src/utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* utils.cpp
*
* Created on: Oct 24, 2024
* Author: mad
*/

#include <mmx/utils.h>

#include <vnx/vnx.h>


namespace mmx {

static bool validate_json(vnx::TypeInput& in, const uint16_t* code, const size_t max_recursion, size_t call_depth)
{
if(++call_depth > max_recursion) {
return false;
}
switch(code[0]) {
case vnx::CODE_NULL:
case vnx::CODE_BOOL:
case vnx::CODE_UINT8:
case vnx::CODE_UINT16:
case vnx::CODE_UINT32:
case vnx::CODE_UINT64:
case vnx::CODE_INT8:
case vnx::CODE_INT16:
case vnx::CODE_INT32:
case vnx::CODE_INT64:
case vnx::CODE_STRING:
case vnx::CODE_ALT_BOOL:
case vnx::CODE_ALT_UINT8:
case vnx::CODE_ALT_UINT16:
case vnx::CODE_ALT_UINT32:
case vnx::CODE_ALT_UINT64:
case vnx::CODE_ALT_INT8:
case vnx::CODE_ALT_INT16:
case vnx::CODE_ALT_INT32:
case vnx::CODE_ALT_INT64:
case vnx::CODE_ALT_STRING:
vnx::skip(in, nullptr, code);
return true;
case vnx::CODE_LIST:
case vnx::CODE_ALT_LIST: {
switch(code[1]) {
case vnx::CODE_DYNAMIC:
case vnx::CODE_ALT_DYNAMIC:
break;
default:
return false;
}
uint32_t size;
read(in, size);
if(code[0] == vnx::CODE_ALT_LIST) {
size = vnx::flip_bytes(size);
}
for(uint32_t i = 0; i < size; ++i) {
if(!validate_json(in, code + 1, max_recursion, call_depth)) {
return false;
}
}
return true;
}
case vnx::CODE_OBJECT:
case vnx::CODE_ALT_OBJECT: {
uint32_t size;
read(in, size);
if(code[0] == vnx::CODE_ALT_OBJECT) {
size = vnx::flip_bytes(size);
}
for(uint32_t i = 0; i < size; ++i) {
const uint16_t key_code = (code[0] == vnx::CODE_OBJECT ? vnx::CODE_STRING : vnx::CODE_ALT_STRING);
const uint16_t value_code = (code[0] == vnx::CODE_OBJECT ? vnx::CODE_DYNAMIC : vnx::CODE_ALT_DYNAMIC);
vnx::skip(in, nullptr, &key_code);
if(!validate_json(in, &value_code, max_recursion, call_depth)) {
return false;
}
}
return true;
}
case vnx::CODE_DYNAMIC:
case vnx::CODE_ALT_DYNAMIC: {
uint16_t byte_code[VNX_MAX_BYTE_CODE_SIZE];
vnx::read_byte_code(in, byte_code);
return validate_json(in, byte_code, max_recursion, call_depth);
}
}
return false;
}

bool is_json(const vnx::Variant& var)
{
if(var.empty()) {
return true;
}
vnx::VectorInputStream stream(&var.data);
vnx::TypeInput in(&stream);
const uint16_t code = vnx::CODE_DYNAMIC;
return validate_json(in, &code, 100, 0);
}


} // mmx
27 changes: 27 additions & 0 deletions test/mmx_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,33 @@ int main(int argc, char** argv)
}
VNX_TEST_END()

VNX_TEST_BEGIN("is_json()")
{
vnx::test::expect(is_json(vnx::Variant()), true);
vnx::test::expect(is_json(vnx::Variant(nullptr)), true);
vnx::test::expect(is_json(vnx::Variant(false)), true);
vnx::test::expect(is_json(vnx::Variant(true)), true);
vnx::test::expect(is_json(vnx::Variant(1)), true);
vnx::test::expect(is_json(vnx::Variant(1 << 16)), true);
vnx::test::expect(is_json(vnx::Variant(uint64_t(1) << 32)), true);
vnx::test::expect(is_json(vnx::Variant(-1)), true);
vnx::test::expect(is_json(vnx::Variant(-256)), true);
vnx::test::expect(is_json(vnx::Variant(-65536)), true);
vnx::test::expect(is_json(vnx::Variant(-4294967296)), true);
vnx::test::expect(is_json(vnx::Variant("")), true);
vnx::test::expect(is_json(vnx::Variant("test")), true);
vnx::test::expect(is_json(vnx::Variant(std::vector<vnx::Variant>{})), true);
vnx::test::expect(is_json(vnx::Variant(std::vector<vnx::Variant>{vnx::Variant(1337), vnx::Variant("test")})), true);
vnx::test::expect(is_json(vnx::Variant(vnx::Object())), true);
vnx::test::expect(is_json(vnx::Variant(vnx::Object({{"test", vnx::Variant(1337)}, {"test1", vnx::Variant("test")}}))), true);

vnx::test::expect(is_json(vnx::Variant(std::array<int16_t, 10>())), false);
vnx::test::expect(is_json(vnx::Variant(std::vector<uint32_t>{1, 2, 3})), false);
vnx::test::expect(is_json(vnx::Variant(std::map<std::string, uint32_t>())), false);
vnx::test::expect(is_json(vnx::Variant(std::vector<vnx::Variant>{vnx::Variant(std::vector<uint32_t>{1, 2, 3})})), false);
}
VNX_TEST_END()

VNX_TEST_BEGIN("Contract::num_bytes()")
{
auto params = mmx::ChainParams::create();
Expand Down
3 changes: 2 additions & 1 deletion tools/mmx_compile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <mmx/pubkey_t.hpp>
#include <mmx/signature_t.hpp>
#include <mmx/secp256k1.hpp>
#include <mmx/utils.h>

#include <vnx/vnx.h>

Expand Down Expand Up @@ -195,7 +196,7 @@ int main(int argc, char** argv)
break;
}
}
if(engine == main_engine && !arg.is_json_strict(100)) {
if(engine == main_engine && !is_json(arg)) {
throw std::logic_error("argument not strict json: " + arg.to_string());
}
vm::copy(child, engine, vm::MEM_STACK + 1 + i, src);
Expand Down
2 changes: 1 addition & 1 deletion vnx-base

0 comments on commit d7e4cc6

Please sign in to comment.