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

Created two cmd line utilities for converting between hex and json #16

Merged
merged 14 commits into from
Nov 14, 2024
Merged
13 changes: 13 additions & 0 deletions tools/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,18 @@ find_package(Threads)
add_executable(name name.cpp)
target_link_libraries(name abieos ${CMAKE_THREAD_LIBS_INIT})

add_library(abieos_util STATIC ../src/abieos.cpp ../src/abi.cpp ../src/crypto.cpp ../include/eosio/fpconv.c)
target_include_directories(abieos_util PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/../src"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/../include"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/../external/rapidjson/include"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")

add_executable(generate_hex_from_json util_generate_hex_from_json.cpp)
target_link_libraries(generate_hex_from_json abieos_util ${CMAKE_THREAD_LIBS_INIT})

add_executable(generate_json_from_hex util_generate_json_from_hex.cpp)
target_link_libraries(generate_json_from_hex abieos_util ${CMAKE_THREAD_LIBS_INIT})

add_custom_command( TARGET name POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink $<TARGET_FILE:name> ${CMAKE_CURRENT_BINARY_DIR}/name2num )
add_custom_command( TARGET name POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink $<TARGET_FILE:name> ${CMAKE_CURRENT_BINARY_DIR}/num2name )
96 changes: 96 additions & 0 deletions tools/test_utils.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/env bash

Transaction_ABI="../external/eosjs/src/transaction.abi.json"

######################################
PREFIX="Hex from JSON:"
if [ -f ../build/tools/generate_hex_from_json ]; then
# no args test ###############
if ../build/tools/generate_hex_from_json 2>>/dev/null ; then
echo "error: no arguments and still success ../build/tools/generate_hex_from_json"
exit 1
fi
echo "${PREFIX} Passed No Args Test"

# Bool test ###################
true_byte=$(../build/tools/generate_hex_from_json -f ${Transaction_ABI} -x bool -j true)
if [ "${true_byte}" != "01" ] ; then
echo "error: ${PREFIX} expected byte 01 from bool true but got ${true_byte}"
exit 1
fi
echo "${PREFIX} Passed Bool Test"

# Int test ####################
two_byte=$(../build/tools/generate_hex_from_json -f ${Transaction_ABI} -x int8 -j 2)
if [ "${two_byte}" != "02" ] ; then
echo "error: ${PREFIX} expected byte 02 from 2 int8 but got ${two_byte}"
exit 1
fi
echo "${PREFIX} Passed Int8 as 2 Test"
# Int test ####################
neg_two_byte=$(../build/tools/generate_hex_from_json -f ${Transaction_ABI} -x int8 -j -2)
if [ "${neg_two_byte}" != "FE" ] ; then
echo "error: ${PREFIX} expected byte FE from -2 int8 but got ${neg_two_byte}"
exit 1
fi
echo "${PREFIX} Passed Int8 as -2 Test"
# name test ###################
name_byte=$(../build/tools/generate_hex_from_json -f ${Transaction_ABI} -x name -j '"bigliontest1"')
if [ "${name_byte}" != "103256795217993B" ] ; then
echo "error: ${PREFIX} expected byte 103256795217993B from name but got ${neg_two_byte}"
exit 1
fi
echo "${PREFIX} Passed Name Test"
else
echo "Not Found ../build/tools/generate_hex_from_json"
exit 1
fi


###################################################


PREFIX="JSON from HEX:"
if [ -f ../build/tools/generate_json_from_hex ]; then
# no args test ###############
if ../build/tools/generate_json_from_hex 2>>/dev/null ; then
echo "error: no arguments and still success ../build/tools/generate_json_from_hex"
exit 1
fi
echo "${PREFIX} Passed No Args Test"

# Bool test #####################
true_byte=$(../build/tools/generate_json_from_hex -f ${Transaction_ABI} -x bool -h 01)
if [ "${true_byte}" != "true" ] ; then
echo "error: ${PREFIX} expected true from bool 01 but got ${true_byte}"
exit 1
fi
echo "${PREFIX} Passed Bool Test"

# Int test #####################
two_byte=$(../build/tools/generate_json_from_hex -f ${Transaction_ABI} -x int8 -h 02)
if [ "${two_byte}" != "2" ] ; then
echo "error: ${PREFIX} expected 2 from 02 int8 but got ${two_byte}"
exit 1
fi
echo "${PREFIX} Passed Int8 as 02 Test"
# Int test #####################
neg_two_byte=$(../build/tools/generate_json_from_hex -f ${Transaction_ABI} -x int8 -h FE)
if [ "${neg_two_byte}" != "-2" ] ; then
echo "error: ${PREFIX} expected -2 from FE int8 but got ${neg_two_byte}"
exit 1
fi
echo "${PREFIX} Passed Int8 as FE Test"
# name test #####################
name_byte=$(../build/tools/generate_json_from_hex -f ${Transaction_ABI} -x name -h 103256795217993B)
if [ "${name_byte}" != '"bigliontest1"' ] ; then
echo "error: ${PREFIX} expected \"bigliontest1\" from name but got ${neg_two_byte}"
exit 1
fi
echo "${PREFIX} Passed Name Test"
else
echo "Not Found ../build/tools/generate_json_from_hex"
exit 1
fi

echo "Success all tests passed"
147 changes: 147 additions & 0 deletions tools/util_generate_hex_from_json.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
//
// Purpose: command line option to generate hex code from JSON
// may be used to generate serialization tests cases in other languages and external packages
//

#include "abieos.h"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <unistd.h>
#include <vector>

// Main work done here four steps
// 1) create empty context
// 2) set the context
// 3) parse json to binary
// 4) create hex from bin
// abiContractName: enum with contract names
// schema: the name of the data type or reference to schema in the ABI contract
// json: the name and values
// verbose: flag to print out step by step messages
std::string generate_hex_from_json(const char* abi_definition, const char* contract_name, const char* schema, const char* json, bool verbose) {
if (verbose) std::cerr << "Schema is: " << schema << " and json is " << json << std::endl << std::endl;

// create empty context
using unique_abieos = std::unique_ptr<abieos_context, decltype( &abieos_destroy )>;
unique_abieos context( abieos_create(), &abieos_destroy );
if (! context) throw std::runtime_error("unable to create context");
if (verbose) std::cerr << "step 1 of 4: created empty ABI context" << std::endl;

// set the transaction context.
// first get the contract_id
uint64_t contract_id = abieos_string_to_name(context.get(), contract_name);
if (contract_id == 0) {
std::cerr << "Error: abieos_string_to_name " << abieos_get_error(context.get()) << std::endl;
throw std::runtime_error("unable to set context");
}
// use our id and set the ABI
bool successSettingAbi = abieos_set_abi(context.get(), contract_id, abi_definition);
if (! successSettingAbi) {
std::cerr << "Error: abieos_set_abi " << abieos_get_error(context.get()) << std::endl;
throw std::runtime_error("unable to set context");
}
if (verbose) std::cerr << "step 2 of 4: established context for transactions, packed transactions, and state history" << std::endl;

// convert from json to binary. binary stored with context
// get contract id returns integer for the ABI contract we passed in by name
bool successJsonToBin = abieos_json_to_bin_reorderable(
context.get(),
contract_id,
schema,
json
);
if (!successJsonToBin) {
std::cerr << "failed in step 3: using context " << contract_name << std::endl;
throw std::runtime_error(abieos_get_error(context.get()));
}
if (verbose) std::cerr << "step 3 of 4: completed parsing json to binary" << std::endl;

// now time to return the hex string
std::string hex = abieos_get_bin_hex(context.get());
if (verbose) std::cerr << "step 4 of 4: converted binary to hex" << std::endl << std::endl;
return hex;
}

// prints usage
void help(const char* exec_name) {
std::cerr << "Usage " << exec_name << ": -f -j JSON -x type [-v]\n";
std::cerr << "\t-f file with ABI definition\n";
std::cerr << "\t-v verbose, print out steps\n";
std::cerr << "\t-j json: string to convert to hex\n";
std::cerr << "\t-x type: a specific data type or schema section (example uint16, action, name, uint8[])\n";
std::cerr << "\texample: generate_hex_from_json -f ./transaction.abi -x bool -j true\n" << std::endl;
}

// reads file returning string of contents
std::string retrieveFileContents(const std::string &filename ) {
try {
std::ifstream ifs(filename, std::ios::in);
std::string string_of_file_contents((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
return string_of_file_contents;
} catch(std::filesystem::filesystem_error const& ex) {
std::cerr << "unable to read ABI file at path: " << filename << std::endl;
exit(EXIT_FAILURE);
}
}

int main(int argc, char* argv[]) {
// static string for our contract id
static const char* contract_name = "eosio";
// input string to transform to hex code
std::string json;
// schema name ex: bool
std::string type;
// hex value returned ex: 01
std::string hex;
// file containing ABI definition
std::string abiFileName;
// string with contents of ABI file
std::string abiDefinition;
// default verbose setting
bool verbose = false;
int opt;

try {
while ((opt = getopt(argc, argv, "vf:j:x:")) != -1) {
switch (opt) {
case 'f': abiFileName = optarg; break;
case 'v': verbose = true; break;
case 'j': json = optarg; break;
case 'x': type = optarg; break;
case '?':
exit(EXIT_FAILURE);
default:
exit(EXIT_FAILURE);
}
}

// check for required params
if (json.empty() || type.empty() || abiFileName.empty()) {
help(*argv);
exit(EXIT_FAILURE);
}

// this is an important step
// here we grab the ABI definition and stuff it in a string
abiDefinition = retrieveFileContents(abiFileName);

hex = generate_hex_from_json(
abiDefinition.c_str(),
contract_name,
type.c_str(),
json.c_str(),
verbose
);
if (hex.length() > 0) {
std::cout << hex << std::endl;
} else {
std::cerr << "returned empty" << std::endl;
}
return 0;
} catch (std::exception& e) {
std::cerr << "Could not compute hex value: " << e.what() << std::endl;
return 1;
}
}
Loading