Skip to content

Commit

Permalink
Use oxenc; replace rlpvalue; c++20 modernizations and various cleanups
Browse files Browse the repository at this point in the history
- Replace rlpvalue with oxenc (which now has an rlp serializer)
- Use oxenc for hex conversions and hex literals
- Switch compilation to C++20
- Switch to std::string_views or std::spans in various places instead of
  const lvalue strings or specific vector/array types.
- Change Provider::sendTransaction and similar to not use `std::async`
  because they were just waiting for the async to return (which blocks
  the current thread anyway, and so might as well just happen in the
  current thread), and abstracted the get-and-wait code into a single
  function.
- removed some unused utils functions
- external -- brought in `system_or_submodule` from other oxen packages
  to have cmake check for system libs before building/using submodules
  for nlohman, secp256k1, oxen-encoding.
- Turn off `-Wshadow` because, under GCC, it produces warnings for
  things it shouldn't, like constructor arguments that initialize
  members, and lambdas that capture a copy of the same name.  Clang's
  `-Wshadow` is less stupid about this, but as this also causes a metric
  ton of warnings for dependent code (like oxend) just turn it off for
  now.
  • Loading branch information
jagerman committed May 2, 2024
1 parent 1c12920 commit 814a1c9
Show file tree
Hide file tree
Showing 21 changed files with 349 additions and 480 deletions.
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
[submodule "external/cpr"]
path = external/cpr
url = https://github.com/libcpr/cpr.git
[submodule "external/rlpvalue"]
path = external/rlpvalue
url = https://github.com/bloq/rlpvalue.git
[submodule "external/secp256k1"]
path = external/secp256k1
url = https://github.com/bitcoin-core/secp256k1.git
[submodule "external/json"]
path = external/json
url = https://github.com/nlohmann/json.git
[submodule "external/oxen-encoding"]
path = external/oxen-encoding
url = https://github.com/oxen-io/oxen-encoding.git
14 changes: 3 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
#

project(
"ethyl"
ethyl
VERSION 0.1.0
LANGUAGES C CXX
)
Expand All @@ -21,12 +21,6 @@ endif()
#
# Set project options
#
if(${PROJECT_NAME}_IS_TOPLEVEL_PROJECT)
set(${PROJECT_NAME}_WARNINGS_AS_ERRORS ON CACHE BOOL "" FORCE)
else()
set(${PROJECT_NAME}_ENABLE_UNIT_TESTING FALSE CACHE BOOL "" FORCE)
endif()

include(cmake/StandardSettings.cmake)
include(cmake/StaticAnalyzers.cmake)
include(cmake/Utils.cmake)
Expand Down Expand Up @@ -61,7 +55,6 @@ add_subdirectory(external)

add_library(
${PROJECT_NAME}
STATIC
${headers}
${sources}
)
Expand Down Expand Up @@ -92,7 +85,7 @@ message(STATUS "Added all header and implementation files.\n")
include(cmake/CompilerWarnings.cmake)
set_project_warnings(${PROJECT_NAME})

verbose_message("Applied compiler warnings. Using standard ${CMAKE_CXX_STANDARD}.\n")
verbose_message("Applied compiler warnings.\n")

#
# Model project dependencies
Expand All @@ -105,9 +98,9 @@ target_link_libraries(
cpr::cpr
secp256k1
nlohmann_json::nlohmann_json
oxenc::oxenc
PRIVATE
cncrypto
rlpvalue
gmp
gmpxx
)
Expand All @@ -123,7 +116,6 @@ target_include_directories(
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
${CMAKE_CURRENT_SOURCE_DIR}/src
)
message(STATUS "Finished setting up include directories.")

Expand Down
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ cmake --build build --parallel --verbose
pacman -Syuu # Terminal may prompt to restart before proceeding
pacman -S git base-devel libargp-devel cmake gcc libcurl-devel gmp-devel autoconf automake libtool
# MSYS packages libargp with a .dll suffix which breaks rlpvalue's autotool
# script so we patch it up
ln -s /usr/lib/libargp.dll.a /usr/lib/libargp.a
# Build
cmake -B build -S .
cmake --build build --parallel --verbose
Expand Down
2 changes: 0 additions & 2 deletions cmake/CompilerWarnings.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ function(set_project_warnings project_name)
set(CLANG_WARNINGS
-Wall
-Wextra # reasonable and standard
-Wshadow # warn the user if a variable declaration shadows one from a
# parent context
-Wnon-virtual-dtor # warn the user if a class with virtual functions has a
# non-virtual destructor. This helps catch hard to
# track down memory errors
Expand Down
20 changes: 10 additions & 10 deletions cmake/StandardSettings.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
# Compiler options
#

option(${PROJECT_NAME}_WARNINGS_AS_ERRORS "Treat compiler warnings as errors." OFF)
option(${PROJECT_NAME}_WARNINGS_AS_ERRORS "Treat compiler warnings as errors." ${${PROJECT_NAME}_IS_TOPLEVEL_PROJECT})

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

option(BUILD_SHARED_LIBS "Build libraries as shared libraries" ON)

Include(FetchContent)

Expand All @@ -11,7 +18,7 @@ Include(FetchContent)
#
# Currently supporting: Catch2.

option(${PROJECT_NAME}_ENABLE_UNIT_TESTING "Enable unit tests for the projects (from the `test` subfolder)." ON)
option(${PROJECT_NAME}_ENABLE_UNIT_TESTING "Enable unit tests for the projects (from the `test` subfolder)." ${${PROJECT_NAME}_IS_TOPLEVEL_PROJECT})

#
# Crypto Library
Expand All @@ -32,14 +39,7 @@ option(${PROJECT_NAME}_ENABLE_CPPCHECK "Enable static analysis with Cppcheck." O

option(${PROJECT_NAME}_VERBOSE_OUTPUT "Enable verbose output, allowing for a better understanding of each step taken." ON)

# Export all symbols when building a shared library
if(BUILD_SHARED_LIBS)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
endif()

option(${PROJECT_NAME}_ENABLE_LTO "Enable Interprocedural Optimization, aka Link Time Optimization (LTO)." OFF)
option(${PROJECT_NAME}_ENABLE_LTO "Enable Interprocedural Optimization, aka Link Time Optimization (LTO)." ON)
if(${PROJECT_NAME}_ENABLE_LTO)
include(CheckIPOSupported)
check_ipo_supported(RESULT result OUTPUT output)
Expand Down
21 changes: 21 additions & 0 deletions cmake/system_or_submodule.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
macro(system_or_submodule BIGNAME smallname pkgconf subdir)
option(FORCE_${BIGNAME}_SUBMODULE "force using ${smallname} submodule" OFF)
if(NOT BUILD_STATIC_DEPS AND NOT FORCE_${BIGNAME}_SUBMODULE AND NOT FORCE_ALL_SUBMODULES)
pkg_check_modules(${BIGNAME} ${pkgconf} IMPORTED_TARGET)
endif()
if(${BIGNAME}_FOUND)
add_library(${smallname} INTERFACE)
if(NOT TARGET PkgConfig::${BIGNAME} AND CMAKE_VERSION VERSION_LESS "3.21")
# Work around cmake bug 22180 (PkgConfig::THING not set if no flags needed)
else()
target_link_libraries(${smallname} INTERFACE PkgConfig::${BIGNAME})
endif()
message(STATUS "Found system ${smallname} ${${BIGNAME}_VERSION}")
else()
message(STATUS "using ${smallname} submodule")
add_subdirectory(${subdir} EXCLUDE_FROM_ALL)
endif()
if(NOT TARGET ${smallname}::${smallname})
add_library(${smallname}::${smallname} ALIAS ${smallname})
endif()
endmacro()
81 changes: 29 additions & 52 deletions external/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@

include(../cmake/system_or_submodule.cmake)
find_package(PkgConfig REQUIRED)


# Force shared libs off for any libraries we build inside here so that if we build a shared lib we
# don't end up with a libspdlog.so or whatever that would need to be distributed alongside the
# libquic.so
set(BUILD_SHARED_LIBS OFF)


#
# CPR
#
if(NOT TARGET cpr)
if(NOT TARGET cpr::cpr)
set(CPR_USE_SYSTEM_CURL ON CACHE BOOL "")
add_subdirectory(cpr)
endif()

#
# SECP256k1
#
if(NOT TARGET secp256k1)
set(SECP256K1_ENABLE_MODULE_RECOVERY ON CACHE BOOL "" FORCE)
set(SECP256K1_VALGRIND OFF CACHE BOOL "" FORCE)
set(SECP256K1_BUILD_BENCHMARK OFF CACHE BOOL "" FORCE)
set(SECP256K1_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(SECP256K1_BUILD_EXHAUSTIVE_TESTS OFF CACHE BOOL "" FORCE)
set(SECP256K1_BUILD_CTIME_TESTS OFF CACHE BOOL "" FORCE)
set(SECP256K1_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
add_subdirectory(secp256k1)
endif()
set(SECP256K1_ENABLE_MODULE_RECOVERY ON CACHE BOOL "" FORCE)
set(SECP256K1_VALGRIND OFF CACHE BOOL "" FORCE)
set(SECP256K1_BUILD_BENCHMARK OFF CACHE BOOL "" FORCE)
set(SECP256K1_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(SECP256K1_BUILD_EXHAUSTIVE_TESTS OFF CACHE BOOL "" FORCE)
set(SECP256K1_BUILD_CTIME_TESTS OFF CACHE BOOL "" FORCE)
set(SECP256K1_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
system_or_submodule(SECP256K1 secp256k1 libsecp256k1 secp256k1)

#
# Catch2
Expand All @@ -28,53 +37,21 @@ if(NOT TARGET Catch2)
endif()

#
# rlpvalue is built using autotools
# oxen-encoding
#
include(ExternalProject)
set(RLP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/rlpvalue)
set(RLP_BIN ${CMAKE_CURRENT_BINARY_DIR}/librlpvalue)
set(RLP_STATIC_LIB ${RLP_BIN}/lib/librlpvalue.a)
set(RLP_INCLUDES ${RLP_BIN}/include)
file(MAKE_DIRECTORY ${RLP_INCLUDES})

# NOTE: rlpvalue includes a sub-project, univalue which it configures from the
# top level script. Passing in the `--prefix` at the top-level does not
# propagate down to the bottom level causing `make install` to install to the
# system level prefix.
#
# We override this by specifying prefix at the last step ensuring that both
# `rlpvalue` and `univalue` are installed to the same prefix.
ExternalProject_Add(
librlpvalue
PREFIX ${RLP_BIN}
SOURCE_DIR ${RLP_DIR}
DOWNLOAD_COMMAND cd ${RLP_DIR} && git clean -dfX
CONFIGURE_COMMAND bash -c "CFLAGS='-fPIC' CXXFLAGS='-fPIC' ${RLP_DIR}/autogen.sh" &&
bash -c "CFLAGS='-fPIC' CXXFLAGS='-fPIC' ${RLP_DIR}/configure --srcdir=${RLP_DIR} --disable-shared --enable-static=yes"
PATCH_COMMAND git checkout -- src/InfInt.h &&
git apply --ignore-whitespace ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/rlpvalue-001-infint-missing-limits-h.patch
BUILD_COMMAND make
INSTALL_COMMAND make install prefix=${RLP_BIN}
BUILD_BYPRODUCTS ${RLP_STATIC_LIB} ${RLP_BIN}/lib/libunivalue.a
)
add_library (rlpvalue STATIC IMPORTED GLOBAL)
add_dependencies (rlpvalue librlpvalue)
set_target_properties(rlpvalue PROPERTIES IMPORTED_LOCATION ${RLP_STATIC_LIB})
set_target_properties(rlpvalue PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${RLP_INCLUDES})
system_or_submodule(OXENC oxenc liboxenc>=1.1.0 oxen-encoding)

#
# nlohmann_json
#
if(NOT TARGET nlohmann_json)
set(JSON_BuildTests OFF CACHE INTERNAL "")
set(JSON_MultipleHeaders ON CACHE BOOL "") # Allows multi-header nlohmann use
add_subdirectory(json EXCLUDE_FROM_ALL)
endif()
set(JSON_MultipleHeaders ON CACHE BOOL "") # Allows multi-header nlohmann use
system_or_submodule(NLOHMANN nlohmann_json nlohmann_json>=3.7.0 nlohmann_json)

#
# GMP
#
find_library(gmp gmp)
if(NOT gmp)
message(FATAL_ERROR "gmp not found")
endif()

pkg_check_modules(GMP gmp IMPORTED_TARGET REQUIRED)
add_library(gmp INTERFACE)
target_link_libraries(gmp INTERFACE PkgConfig::GMP)
message(STATUS "Found gmp ${GMP_VERSION}")
2 changes: 1 addition & 1 deletion external/cpr
Submodule cpr updated 67 files
+2 −2 .github/workflows/build-deb.yml
+461 −169 .github/workflows/ci.yml
+1 −1 .github/workflows/clang-format.yml
+1 −1 .github/workflows/clang-tidy.yml
+71 −0 .github/workflows/codeql-analysis.yml
+1 −1 .github/workflows/cppcheck.yml
+24 −30 CMakeLists.txt
+0 −1 README.md
+2 −2 cmake/zlib_external.cmake
+1 −1 cpr/CMakeLists.txt
+1 −1 cpr/callback.cpp
+1 −1 cpr/curl_container.cpp
+1 −1 cpr/curlmultiholder.cpp
+1 −1 cpr/interceptor.cpp
+0 −2 cpr/multipart.cpp
+9 −1 cpr/multiperform.cpp
+6 −0 cpr/parameters.cpp
+6 −0 cpr/payload.cpp
+5 −14 cpr/proxyauth.cpp
+1 −1 cpr/response.cpp
+15 −14 cpr/session.cpp
+1 −1 cpr/ssl_ctx.cpp
+0 −10 cpr/util.cpp
+1 −1 include/CMakeLists.txt
+1 −1 include/cpr/api.h
+1 −1 include/cpr/buffer.h
+1 −3 include/cpr/cert_info.h
+4 −4 include/cpr/cookies.h
+1 −1 include/cpr/curlmultiholder.h
+4 −4 include/cpr/file.h
+1 −1 include/cpr/interceptor.h
+1 −1 include/cpr/limit_rate.h
+1 −1 include/cpr/local_port.h
+1 −1 include/cpr/local_port_range.h
+0 −2 include/cpr/multipart.h
+1 −1 include/cpr/multiperform.h
+1 −1 include/cpr/parameters.h
+1 −1 include/cpr/payload.h
+8 −16 include/cpr/proxyauth.h
+5 −5 include/cpr/redirect.h
+1 −1 include/cpr/ssl_ctx.h
+24 −21 include/cpr/ssl_options.h
+2 −2 include/cpr/status_codes.h
+1 −1 test/alternating_tests.cpp
+2 −2 test/async_tests.cpp
+9 −12 test/callback_tests.cpp
+1 −1 test/delete_tests.cpp
+1 −1 test/download_tests.cpp
+3 −3 test/encoded_auth_tests.cpp
+2 −2 test/error_tests.cpp
+1 −1 test/get_tests.cpp
+2 −2 test/head_tests.cpp
+1 −1 test/httpsServer.hpp
+1 −1 test/multiasync_tests.cpp
+2 −2 test/multiperform_tests.cpp
+1 −1 test/options_tests.cpp
+1 −1 test/patch_tests.cpp
+2 −2 test/post_tests.cpp
+1 −1 test/prepare_tests.cpp
+1 −1 test/proxy_tests.cpp
+1 −1 test/put_tests.cpp
+2 −2 test/raw_body_tests.cpp
+24 −68 test/session_tests.cpp
+3 −3 test/ssl_tests.cpp
+2 −2 test/structures_tests.cpp
+2 −2 test/util_tests.cpp
+1 −1 test/version_tests.cpp
1 change: 1 addition & 0 deletions external/oxen-encoding
Submodule oxen-encoding added at 201c4c
1 change: 0 additions & 1 deletion external/rlpvalue
Submodule rlpvalue deleted from 1e58dc
30 changes: 16 additions & 14 deletions include/ethyl/provider.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "transaction.hpp"
#include "logs.hpp"

using namespace std::literals;

struct ReadCallData {
std::string contractAddress;
std::string data;
Expand All @@ -32,43 +34,43 @@ class Provider {
cpr::Url url;
cpr::Session session;
public:
Provider(const std::string& name, const std::string& _url);
Provider(std::string name, std::string url);
~Provider();

void connectToNetwork();
void disconnectFromNetwork();

uint64_t getTransactionCount(const std::string& address, const std::string& blockTag);
uint64_t getTransactionCount(std::string_view address, std::string_view blockTag);
nlohmann::json callReadFunctionJSON(const ReadCallData& callData, std::string_view blockNumber = "latest");
std::string callReadFunction(const ReadCallData& callData, std::string_view blockNumber = "latest");
std::string callReadFunction(const ReadCallData& callData, uint64_t blockNumberInt);

uint32_t getNetworkChainId();
std::string evm_snapshot();
bool evm_revert(const std::string& snapshotId);
bool evm_revert(std::string_view snapshotId);

uint64_t evm_increaseTime(std::chrono::seconds seconds);

std::optional<nlohmann::json> getTransactionByHash(const std::string& transactionHash);
std::optional<nlohmann::json> getTransactionReceipt(const std::string& transactionHash);
std::vector<LogEntry> getLogs(uint64_t fromBlock, uint64_t toBlock, const std::string& address);
std::vector<LogEntry> getLogs(uint64_t block, const std::string& address);
std::string getContractStorageRoot(const std::string& address, uint64_t blockNumberInt);
std::string getContractStorageRoot(const std::string& address, const std::string& blockNumber = "latest");
std::optional<nlohmann::json> getTransactionByHash(std::string_view transactionHash);
std::optional<nlohmann::json> getTransactionReceipt(std::string_view transactionHash);
std::vector<LogEntry> getLogs(uint64_t fromBlock, uint64_t toBlock, std::string_view address);
std::vector<LogEntry> getLogs(uint64_t block, std::string_view address);
std::string getContractStorageRoot(std::string_view address, uint64_t blockNumberInt);
std::string getContractStorageRoot(std::string_view address, std::string_view blockNumber = "latest");

std::string sendTransaction(const Transaction& signedTx);
std::string sendUncheckedTransaction(const Transaction& signedTx);

uint64_t waitForTransaction(const std::string& txHash, int64_t timeout = 320000);
bool transactionSuccessful(const std::string& txHash, int64_t timeout = 320000);
uint64_t gasUsed(const std::string& txHash, int64_t timeout = 320000);
std::string getBalance(const std::string& address);
uint64_t waitForTransaction(std::string_view txHash, std::chrono::milliseconds timeout = 320s);
bool transactionSuccessful(std::string_view txHash, std::chrono::milliseconds timeout = 320s);
uint64_t gasUsed(std::string_view txHash, std::chrono::milliseconds timeout = 320s);
std::string getBalance(std::string_view address);
std::string getContractDeployedInLatestBlock();

uint64_t getLatestHeight();
FeeData getFeeData();

private:
cpr::Response makeJsonRpcRequest(const std::string& method, const nlohmann::json& params);
cpr::Response makeJsonRpcRequest(std::string_view method, const nlohmann::json& params);
};

27 changes: 15 additions & 12 deletions include/ethyl/signer.hpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#pragma once

#include <assert.h>
#include <secp256k1.h>
#include <vector>
#include <string>
#include <array>
#include <memory>
#include <span>
#include <string>
#include <string_view>
#include <vector>

#include "provider.hpp"

#include "ethyl/provider.hpp"
typedef struct secp256k1_context_struct secp256k1_context; // forward decl

class Signer {
private:
Expand All @@ -24,22 +27,22 @@ class Signer {

// Returns <Pubkey, Seckey>
std::pair<std::vector<unsigned char>, std::vector<unsigned char>> generate_key_pair();
std::array<unsigned char, 20> secretKeyToAddress(const std::vector<unsigned char>& seckey);
std::string secretKeyToAddressString(const std::vector<unsigned char>& seckey);
std::array<unsigned char, 20> secretKeyToAddress(std::span<const unsigned char> seckey);
std::string secretKeyToAddressString(std::span<const unsigned char> seckey);

std::vector<unsigned char> sign(const std::array<unsigned char, 32>& hash, const std::vector<unsigned char>& seckey);
std::vector<unsigned char> sign(const std::string& hash, const std::vector<unsigned char>& seckey);
std::vector<unsigned char> sign(const std::array<unsigned char, 32>& hash, std::span<const unsigned char> seckey);
std::vector<unsigned char> sign(std::string_view hash, std::span<const unsigned char> seckey);

// Client usage methods
bool hasProvider() const { return static_cast<bool>(provider); }
std::shared_ptr<Provider> getProvider() { return provider; }


std::vector<unsigned char> signMessage(const std::string& message, const std::vector<unsigned char>& seckey);
std::string signTransaction(Transaction& tx, const std::vector<unsigned char>& seckey);
std::vector<unsigned char> signMessage(std::string_view message, std::span<const unsigned char> seckey);
std::string signTransaction(Transaction& tx, std::span<const unsigned char> seckey);

void populateTransaction(Transaction& tx, std::string sender_address);
std::string sendTransaction(Transaction& tx, const std::vector<unsigned char>& seckey);
std::string sendTransaction(Transaction& tx, std::span<const unsigned char> seckey);


private:
Expand Down
Loading

0 comments on commit 814a1c9

Please sign in to comment.