Compare commits

..

12 Commits

Author SHA1 Message Date
claude 4d0889dbc9 build: сабмодули с git.coopenomics.world — изоляция кодовой базы
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 06:37:26 +00:00
claude 4caf3ed614 merge: AntelopeIO cdt v4.1.1 into coopenomics cdt v4.2.0
Версия 4.3.0 — наша линейка (assert_recover_key_account,
get_account_ram_usage, Dockerfile) поверх upstream cdt 4.1.1,
штатной пары к spring/savanna 1.x.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 05:27:28 +00:00
Alex Ant 4d324084e8 bump version 2025-10-15 21:50:04 +05:00
Alex Ant eae8cd24f4 fix types 2025-10-15 10:50:05 +05:00
Alex Ant 0529c28563 Реализация вызова метода assert_recover_key_account 2025-10-15 01:45:39 +05:00
Matt Witherspoon b35ebffb22 Merge pull request #384 from AntelopeIO/411bump
[4.1.1] bump version to 4.1.1
2025-08-06 16:51:28 -04:00
Matt Witherspoon 9cd7fcb51e version bump to 4.1.1 2025-08-06 16:39:04 -04:00
Dark Sun 3e7f4e7254 update Dockerfile 2024-04-10 17:47:14 +03:00
Dark Sun 3be71635ac Dockerfile 2024-04-10 17:13:09 +03:00
Dark Sun e6c412e2c3 Dockerfile 2024-04-10 17:12:03 +03:00
Dark Sun 960076f4ce update version 2024-04-10 10:38:12 +03:00
Dark Sun 7d12b93e7e add get_account_ram_usage method 2024-04-09 18:45:15 +03:00
71 changed files with 655 additions and 2585 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
{
"antelope-spring-dev":{
"target":"release/2.0",
"target":"main",
"prerelease":false
}
}
}
+4 -4
View File
@@ -1,12 +1,12 @@
[submodule "cdt-llvm"]
path = cdt-llvm
url = https://github.com/AntelopeIO/cdt-llvm
url = https://git.coopenomics.world/C9S/cdt-llvm.git
[submodule "libraries/libc/cdt-musl"]
path = libraries/libc/cdt-musl
url = https://github.com/AntelopeIO/cdt-musl
url = https://git.coopenomics.world/C9S/cdt-musl.git
[submodule "libraries/libc++/cdt-libcxx"]
path = libraries/libc++/cdt-libcxx
url = https://github.com/AntelopeIO/cdt-libcxx
url = https://git.coopenomics.world/C9S/cdt-libcxx.git
[submodule "libraries/native/softfloat"]
path = libraries/native/softfloat
url = https://github.com/AntelopeIO/berkeley-softfloat-3
url = https://git.coopenomics.world/C9S/berkeley-softfloat-3.git
+4 -4
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5...4.0)
cmake_minimum_required(VERSION 3.5)
# Sanity check our source directory to make sure that we are not trying to
# generate an in-source build, and to make
@@ -13,10 +13,10 @@ endif()
project(cdt)
set(VERSION_MAJOR 5)
set(VERSION_MINOR 0)
set(VERSION_MAJOR 4)
set(VERSION_MINOR 3)
set(VERSION_PATCH 0)
set(VERSION_SUFFIX "dev1")
# set(VERSION_SUFFIX "rc1")
if (VERSION_SUFFIX)
set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}")
+9
View File
@@ -0,0 +1,9 @@
FROM ubuntu:latest
WORKDIR /workdir
COPY build/cdt_*.deb /workdir
RUN apt-get update && apt-get install -y wget cmake build-essential g++ libboost-all-dev libz3-dev && \
apt install ./cdt_*.deb -y && \
rm cdt_*.deb
-65
View File
@@ -1,65 +0,0 @@
#pragma once
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup call_c Call C API
* @ingroup c_api
* @brief Defines API for querying call object and making a sync call
*/
/**
* Make a sync call in the context of this call's parent action or parent call
*
* @param receiver - the name of the account that the sync call is made to
* @param flags - flags (bits) representing blockchain level requirements about
* the call. Currently LSB bit indicates read-only. All other bits
* are reserved to be 0
* @param data - the data of the sync call, which may include function name, arguments, and other information
* @return -1 if the receiver contract does not have sync call entry point or the entry point's signature is invalid, otherwise
* @return the number of bytes of the return value of the call. If the function is `void`, return `0`
*
*/
__attribute__((eosio_wasm_import))
int64_t call(capi_name receiver, uint64_t flags, const char* data, size_t data_size);
/**
* Copy up to `len` bytes of the return value of the most recent call to `mem`,
* in the context of this call's parent action or parent call
*
* @brief Copy the return value of the most recent call to the specified location
* @param mem - a pointer where up to `len` bytes of the return value will be copied
* @param len - length of the return value to be copied
* @return the number of bytes of the return value that can be retrieved (the number of total bytes of return value)
*/
__attribute__((eosio_wasm_import))
uint32_t get_call_return_value( void* mem, uint32_t len );
/**
* Copy up to `len` bytes of the current call data to `mem`
*
* @brief Copy current call data to the specified location
* @param mem - a pointer where up to `len` bytes of the current call data will be copied
* @param len - length of the current call data to be copied
* @return the number of bytes of the data that can be retrieved (the number of total bytes of the data)
*/
__attribute__((eosio_wasm_import))
uint32_t get_call_data( void* mem, uint32_t len );
/**
* Set the return value from `mem` with `len` bytes. This is to be retrieved by parent action
* or parent call using `get_call_return_value`
*
* @brief Copy the return value from the specified location
* @param mem - a pointer where `len` bytes of the return value will be copied from
*/
__attribute__((eosio_wasm_import))
void set_call_return_value( void* mem, uint32_t len );
#ifdef __cplusplus
}
#endif
/// @} call
+35
View File
@@ -232,6 +232,41 @@ int recover_key( const struct capi_checksum256* digest, const char* sig, size_t
__attribute__((eosio_wasm_import))
void assert_recover_key( const struct capi_checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen );
/**
* Tests a signature against a hash, verifies the recovered public key matches the expected one,
* and checks that this public key belongs to the specified account permission.
*
* @ingroup crypto
* @param digest - Pointer to the digest/hash of the message that was signed
* @param sig - Pointer to the signature
* @param siglen - Length of the signature
* @param pub - Pointer to the expected public key
* @param publen - Length of the expected public key
* @param account - The account name to verify key ownership
* @param permission - The permission name to check (e.g., active, owner)
*
* @pre `digest` is a valid pointer to a `capi_checksum256` struct
* @pre `sig` is a valid pointer to a buffer containing the signature
* @pre `pub` is a valid pointer to a buffer containing the expected public key
*
* @post Throws if signature is invalid, key doesn't match, or key doesn't belong to account permission
*
* Example:
* @code
* capi_checksum256 digest;
* char sig[65];
* size_t siglen = 65;
* char pub[34];
* size_t publen = 34;
* capi_name account = N(myaccount);
* capi_name permission = N(active);
* assert_recover_key_account( &digest, sig, siglen, pub, publen, account, permission );
* // If all checks pass, code continues here
* @endcode
*/
__attribute__((eosio_wasm_import))
void assert_recover_key_account( const struct capi_checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen, uint64_t account, uint64_t permission );
#ifdef __cplusplus
}
#endif
@@ -10,6 +10,16 @@ extern "C" {
* @brief Defines %C Privileged API
*/
/**
* Get the RAM usage an account
*
* @param account - name of the account whose resource limit to get
* @param used_ram_bytes - pointer to `int64_t` to hold retrieved ram usage in absolute bytes
*/
__attribute__((eosio_wasm_import))
void get_account_ram_usage( capi_name account, int64_t* used_ram_bytes );
/**
* Get the resource limits of an account
*
@@ -0,0 +1,56 @@
#pragma once
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Propose new participants to the security group.
*
* @param data - the buffer containing the packed participants.
* @param datalen - size of the packed participants
* @pre `data` is a valid pointer to a range of memory at least `datalen` bytes long that contains packed participants data
*
* @return -1 if proposing a new security group was unsuccessful, otherwise returns 0.
*/
__attribute__((eosio_wasm_import))
int64_t add_security_group_participants(const char* data, uint32_t datalen);
/**
* Propose to remove participants from the security group.
*
* @param data - the buffer containing the packed participants.
* @param datalen - size of the packed participants
* @pre `data` is a valid pointer to a range of memory at least `datalen` bytes long that contains packed participants data
*
* @return -1 if proposing a new security group was unsuccessful, otherwise returns 0.
*/
__attribute__((eosio_wasm_import))
int64_t remove_security_group_participants(const char* data, uint32_t datalen);
/**
* Check if the specified accounts are all in the active security group.
*
* @param data - the buffer containing the packed participants.
* @param datalen - size of the packed participants
*
* @return Returns true if the specified accounts are all in the active security group.
*/
__attribute__((eosio_wasm_import))
bool in_active_security_group(const char* data, uint32_t datalen);
/**
* Gets the active security group
*
* @param[out] data - the output buffer containing the packed security group.
* @param datalen - size of the `data` buffer
*
* @return Returns the size required in the buffer (if the buffer is too small, nothing is written).
*
*/
__attribute__((eosio_wasm_import))
uint32_t get_active_security_group(char* data, uint32_t datalen);
#ifdef __cplusplus
}
#endif
+84 -1
View File
@@ -6,11 +6,11 @@
#include <cstdlib>
#include <type_traits>
#include "detail.hpp"
#include "../../core/eosio/serialize.hpp"
#include "../../core/eosio/datastream.hpp"
#include "../../core/eosio/name.hpp"
#include "../../core/eosio/fixed_bytes.hpp"
#include "../../core/eosio/ignore.hpp"
#include "../../core/eosio/time.hpp"
namespace eosio {
@@ -409,6 +409,89 @@ namespace eosio {
};
namespace detail {
/// @cond INTERNAL
template <typename T>
struct unwrap { typedef T type; };
template <typename T>
struct unwrap<ignore<T>> { typedef T type; };
template <typename R, typename Act, typename... Args>
auto get_args(R(Act::*p)(Args...)) {
return std::tuple<std::decay_t<typename unwrap<Args>::type>...>{};
}
template <typename R, typename Act, typename... Args>
auto get_args_nounwrap(R(Act::*p)(Args...)) {
return std::tuple<std::decay_t<Args>...>{};
}
template <auto Action>
using deduced = decltype(get_args(Action));
template <auto Action>
using deduced_nounwrap = decltype(get_args_nounwrap(Action));
template <typename T>
struct convert { typedef T type; };
template <>
struct convert<const char*> { typedef std::string type; };
template <>
struct convert<char*> { typedef std::string type; };
template <typename T, typename U>
struct is_same { static constexpr bool value = std::is_convertible<T,U>::value; };
template <typename U>
struct is_same<bool,U> { static constexpr bool value = std::is_integral<U>::value; };
template <typename T>
struct is_same<T,bool> { static constexpr bool value = std::is_integral<T>::value; };
// Full specialization to resolve ambiguity introduced by partial specializations
// of is_same<bool,U> and is_same<T,bool>
template <>
struct is_same<bool, bool> { static constexpr bool value = true; };
template <size_t N, size_t I, auto Arg, auto... Args>
struct get_nth_impl { static constexpr auto value = get_nth_impl<N,I+1,Args...>::value; };
template <size_t N, auto Arg, auto... Args>
struct get_nth_impl<N, N, Arg, Args...> { static constexpr auto value = Arg; };
template <size_t N, auto... Args>
struct get_nth { static constexpr auto value = get_nth_impl<N,0,Args...>::value; };
template <auto Action, size_t I, typename T, typename... Rest>
struct check_types {
static_assert(detail::is_same<typename convert<T>::type, typename convert<typename std::tuple_element<I, deduced<Action>>::type>::type>::value);
using type = check_types<Action, I+1, Rest...>;
static constexpr bool value = true;
};
template <auto Action, size_t I, typename T>
struct check_types<Action, I, T> {
static_assert(detail::is_same<typename convert<T>::type, typename convert<typename std::tuple_element<I, deduced<Action>>::type>::type>::value);
static constexpr bool value = true;
};
template <auto Action, typename... Ts>
constexpr bool type_check() {
static_assert(sizeof...(Ts) == std::tuple_size<deduced<Action>>::value);
if constexpr (sizeof...(Ts) != 0)
return check_types<Action, 0, Ts...>::value;
return true;
}
/// @endcond
}
/**
* Wrapper for an action object.
*
-158
View File
@@ -1,158 +0,0 @@
/**
* @file
*/
#pragma once
#include <cstdlib>
#include <type_traits>
#include "detail.hpp"
#include "../../core/eosio/serialize.hpp"
#include "../../core/eosio/datastream.hpp"
#include "../../core/eosio/name.hpp"
#include "../../core/eosio/hash_id.hpp"
namespace eosio {
namespace internal_use_do_not_use {
extern "C" {
__attribute__((eosio_wasm_import))
int64_t call(uint64_t receiver, uint64_t flags, const char* data, size_t data_size);
__attribute__((eosio_wasm_import))
uint32_t get_call_return_value( void* mem, uint32_t len );
__attribute__((eosio_wasm_import))
uint32_t get_call_data( void* mem, uint32_t len );
__attribute__((eosio_wasm_import))
void set_call_return_value( void* mem, uint32_t len );
}
};
/**
* @defgroup call call
* @ingroup contracts
* @brief Defines type-safe C++ wrappers for querying call and sending call
* @note There are some methods from the @ref call that can be used directly from C++
*/
inline int64_t call(eosio::name receiver, uint64_t flags, const char* data, size_t data_size) {
return internal_use_do_not_use::call(receiver.value, flags, data, data_size);
}
inline uint32_t get_call_return_value( void* mem, uint32_t len ) {
return internal_use_do_not_use::get_call_return_value(mem, len);
}
inline uint32_t get_call_data( void* mem, uint32_t len ) {
return internal_use_do_not_use::get_call_data(mem, len);
}
inline void set_call_return_value( void* mem, uint32_t len ) {
internal_use_do_not_use::set_call_return_value(mem, len);
}
// Indicate whether a sync call is read_write or read_only. Default is read_write
enum class access_mode { read_write = 0, read_only = 1 };
// Indicate the action to take if the receiver does not support sync calls.
// Default is abort_op
enum class support_mode { abort_op = 0, no_op = 1 };
// For a void function, when support_mode is set to no_op, the call_wrapper.
// returns `std::optional<void_call>`. If the optional has no value, it indicates
// the call was op-op; if the optional has a value of `void_call`, the call
// executed successfully.
struct void_call {
};
struct call_data_header {
uint32_t version = 0;
uint64_t func_name = 0; // At WASM level, function name is a short ID of uint64_t.
EOSLIB_SERIALIZE(call_data_header, (version)(func_name))
};
/**
* Wrapper for simplifying making a sync call
*
* @brief Used to wrap a particular sync call to simplify the process of other contracts making sync calls to the "wrapped" call.
* Example:
* @code
* // defined by contract writer of the sync call functions
* using get_func = call_wrapper<"get"_i, &callee::get>;
* // usage by different contract writer
* get_func{"callee"_n}();
* // or
* get_func get{"callee"_n};
* get();
* @endcode
*/
template <eosio::hash_id::raw Func_Name, auto Func_Ref, access_mode Access_Mode=access_mode::read_write, support_mode Support_Mode = support_mode::abort_op>
struct call_wrapper {
template <typename Receiver>
constexpr call_wrapper(Receiver&& receiver)
: receiver(std::forward<Receiver>(receiver))
{}
static constexpr eosio::hash_id function_name = eosio::hash_id(Func_Name);
eosio::name receiver {};
using orig_ret_type = typename detail::function_traits<decltype(Func_Ref)>::return_type;
using return_type = std::conditional_t<
Support_Mode == support_mode::abort_op,// if Support_Mode is abort_op
orig_ret_type, // use the original return type
std::conditional_t< // else
std::is_void<orig_ret_type>::value, // original return type is void
std::optional<void_call>, // use optional of empty struct
std::optional<orig_ret_type> // use optional of original return type
>
>;
template <typename... Args>
return_type operator()(Args&&... args)const {
static_assert(detail::type_check<Func_Ref, Args...>());
uint64_t flags = 0x00;
if constexpr (Access_Mode == access_mode::read_only) {
flags = 0x01;
}
call_data_header header{ .version = 0,
.func_name = function_name.id };
const std::vector<char> data{ pack(std::forward_as_tuple(header, detail::deduced<Func_Ref>{std::forward<Args>(args)...})) };
auto ret_val_size = internal_use_do_not_use::call(receiver.value, flags, data.data(), data.size());
if (ret_val_size < 0) { // the receiver does not support sync calls
if constexpr (Support_Mode == support_mode::abort_op) {
check(false, "receiver does not support sync call but support_mode is set to abort_op");
} else {
return std::nullopt;
}
}
// The sync call has been executed by the receiver
if constexpr (std::is_void<return_type>::value) {
return;
} else {
if constexpr (Support_Mode == support_mode::no_op && std::is_void<orig_ret_type>::value) {
return void_call{};
} else {
constexpr size_t max_stack_buffer_size = 512;
char* buffer = (char*)(max_stack_buffer_size < ret_val_size ? malloc(ret_val_size) : alloca(ret_val_size)); // intentionally no `free()` is called. the memory will be freed at the end of callers wasm execution.
internal_use_do_not_use::get_call_return_value(buffer, ret_val_size);
orig_ret_type ret_val = unpack<orig_ret_type>(buffer, ret_val_size);
if constexpr (Support_Mode == support_mode::no_op) {
return std::make_optional(ret_val);
} else {
return ret_val;
}
}
}
}
};
} // namespace eosio
@@ -29,12 +29,6 @@ namespace eosio {
*/
class contract {
public:
enum class exec_type_t : uint8_t {
action,
call,
unknown
};
/**
* Construct a new contract given the contract name
*
@@ -81,27 +75,7 @@ class contract {
*/
inline const datastream<const char*>& get_datastream()const { return _ds; }
/**
* Whether this contract is for a sync call
*
* @return bool - Whether this contract is for a sync call
*/
inline bool is_sync_call()const {
check(_exec_type != exec_type_t::unknown, "too early to call is_sync_call(). _exec_type has not been set yet");
return (_exec_type == exec_type_t::call);
}
/**
* Set the exectution type.
*
* @param type - The exectution type to be set.
*/
inline void set_exec_type(exec_type_t type) {
_exec_type = type;
}
protected:
/**
* The name of the account this contract is deployed on.
*/
@@ -116,10 +90,5 @@ class contract {
* The datastream for this contract
*/
datastream<const char*> _ds = datastream<const char*>(nullptr, 0);
/**
* The execution type: action or sync call
*/
exec_type_t _exec_type = exec_type_t::unknown;
};
}
@@ -1,138 +0,0 @@
/**
* @file
* @copyright defined in eos/LICENSE
*/
#pragma once
#include "system.hpp"
#include "transaction.hpp"
#include "../../core/eosio/serialize.hpp"
#include <vector>
namespace eosio {
namespace internal_use_do_not_use {
extern "C" {
__attribute__((eosio_wasm_import))
void send_deferred(const uint128_t&, uint64_t, const char*, size_t, uint32_t);
__attribute__((eosio_wasm_import))
int cancel_deferred(const uint128_t&);
}
}
/**
* @defgroup deferred_transaction Transaction
* @ingroup contracts
* @brief Type-safe C++ wrappers for transaction C API
*
* deferred_transaction is no longer supported on Vaulta. This class is provided to
* support legacy test contracts that use deferred transactions.
*
* @details An inline message allows one contract to send another contract a message
* which is processed immediately after the current message's processing
* ends such that the success or failure of the parent transaction is
* dependent on the success of the message. If an inline message fails in
* processing then the whole tree of transactions and actions rooted in the
* block will me marked as failing and none of effects on the database will
* persist.
*
* Inline actions and Deferred transactions must adhere to the permissions
* available to the parent transaction or, in the future, delegated to the
* contract account for future use.
*
* @note There are some methods from the @ref transactioncapi that can be used directly from C++
*/
/**
* Class transaction contains the actions, context_free_actions and extensions type for a transaction
*
* @ingroup transaction
*/
class deferred_transaction : public transaction {
public:
/**
* Construct a new deferred_transaction with an expiration of now + 60 seconds.
*/
deferred_transaction(time_point_sec exp = time_point_sec(current_time_point()) + 60) : transaction( exp ) {}
/**
* Sends this transaction, packs the transaction then sends it as a deferred transaction
*
* @details Writes the symbol_code as a string to the provided char buffer
* @param sender_id - ID of sender
* @param payer - Account paying for RAM
* @param replace_existing - Defaults to false, if this is `0`/false then if the provided sender_id is already in use by an in-flight transaction from this contract, which will be a failing assert. If `1` then transaction will atomically cancel/replace the inflight transaction
*/
void send(const uint128_t& sender_id, name payer, bool replace_existing = false) const {
auto serialize = pack(*static_cast<const transaction*>(this));
internal_use_do_not_use::send_deferred(sender_id, payer.value, serialize.data(), serialize.size(), replace_existing);
}
};
/**
* Struct onerror contains and sender id and packed transaction
*
* @ingroup transaction
*/
struct onerror {
uint128_t sender_id;
std::vector<char> sent_trx;
/**
* from_current_action unpacks and returns a onerror struct
*
* @ingroup transaction
*/
static onerror from_current_action() {
return unpack_action_data<onerror>();
}
/**
* Unpacks and returns a transaction
*/
transaction unpack_sent_trx() const {
return unpack<transaction>(sent_trx);
}
EOSLIB_SERIALIZE( onerror, (sender_id)(sent_trx) )
};
/**
* Send a deferred transaction
*
* @ingroup transaction
* @param sender_id - Account name of the sender of this deferred transaction
* @param payer - Account name responsible for paying the RAM for this deferred transaction
* @param serialized_transaction - The packed transaction to be deferred
* @param size - The size of the packed transaction, required for persistence.
* @param replace - If true, will replace an existing transaction.
*/
inline void send_deferred(const uint128_t& sender_id, name payer, const char* serialized_transaction, size_t size, bool replace = false) {
internal_use_do_not_use::send_deferred(sender_id, payer.value, serialized_transaction, size, replace);
}
/**
* Cancels a deferred transaction.
*
* @ingroup transaction
* @param sender_id - The id of the sender
*
* @pre The deferred transaction ID exists.
* @pre The deferred transaction ID has not yet been published.
* @post Deferred transaction canceled.
*
* @return 1 if transaction was canceled, 0 if transaction was not found
*
* Example:
*
* @code
* id = 0xffffffffffffffff
* cancel_deferred( id );
* @endcode
*/
inline int cancel_deferred(const uint128_t& sender_id) {
return internal_use_do_not_use::cancel_deferred(sender_id);
}
}
@@ -1,99 +0,0 @@
#pragma once
#include "../../core/eosio/ignore.hpp"
namespace eosio { namespace detail {
/// @cond INTERNAL
template <typename T>
struct unwrap { typedef T type; };
template <typename T>
struct unwrap<ignore<T>> { typedef T type; };
template <typename R, typename Act, typename... Args>
auto get_args(R(Act::*p)(Args...)) {
return std::tuple<std::decay_t<typename unwrap<Args>::type>...>{};
}
template <typename R, typename Act, typename... Args>
auto get_args_nounwrap(R(Act::*p)(Args...)) {
return std::tuple<std::decay_t<Args>...>{};
}
template <auto Function>
using deduced = decltype(get_args(Function));
template <auto Function>
using deduced_nounwrap = decltype(get_args_nounwrap(Function));
template <typename T>
struct convert { typedef T type; };
template <>
struct convert<const char*> { typedef std::string type; };
template <>
struct convert<char*> { typedef std::string type; };
template <typename T, typename U>
struct is_same { static constexpr bool value = std::is_convertible<T,U>::value; };
template <typename U>
struct is_same<bool,U> { static constexpr bool value = std::is_integral<U>::value; };
template <typename T>
struct is_same<T,bool> { static constexpr bool value = std::is_integral<T>::value; };
// Full specialization to resolve ambiguity introduced by partial specializations
// of is_same<bool,U> and is_same<T,bool>
template <>
struct is_same<bool, bool> { static constexpr bool value = true; };
template <size_t N, size_t I, auto Arg, auto... Args>
struct get_nth_impl { static constexpr auto value = get_nth_impl<N,I+1,Args...>::value; };
template <size_t N, auto Arg, auto... Args>
struct get_nth_impl<N, N, Arg, Args...> { static constexpr auto value = Arg; };
template <size_t N, auto... Args>
struct get_nth { static constexpr auto value = get_nth_impl<N,0,Args...>::value; };
template <auto Function, size_t I, typename T, typename... Rest>
struct check_types {
static_assert(detail::is_same<typename convert<T>::type, typename convert<typename std::tuple_element<I, deduced<Function>>::type>::type>::value);
using type = check_types<Function, I+1, Rest...>;
static constexpr bool value = true;
};
template <auto Function, size_t I, typename T>
struct check_types<Function, I, T> {
static_assert(detail::is_same<typename convert<T>::type, typename convert<typename std::tuple_element<I, deduced<Function>>::type>::type>::value);
static constexpr bool value = true;
};
template <auto Function, typename... Ts>
constexpr bool type_check() {
static_assert(sizeof...(Ts) == std::tuple_size<deduced<Function>>::value);
if constexpr (sizeof...(Ts) != 0)
return check_types<Function, 0, Ts...>::value;
return true;
}
// For non-function-pointers (function_traits is undefined)
template <typename T>
struct function_traits;
// For non-const member function
template <typename Class, typename Ret, typename... Args>
struct function_traits<Ret (Class::*)(Args...)> {
using return_type = Ret;
};
// For const member function
template <typename Class, typename Ret, typename... Args>
struct function_traits<Ret (Class::*)(Args...) const> {
using return_type = Ret;
};
/// @endcond
}} // eosio detail
@@ -12,6 +12,9 @@ namespace eosio {
__attribute__((eosio_wasm_import))
bool is_privileged( uint64_t account );
__attribute__((eosio_wasm_import))
void get_account_ram_usage( uint64_t account, int64_t* used_ram_bytes );
__attribute__((eosio_wasm_import))
void get_resource_limits( uint64_t account, int64_t* ram_bytes, int64_t* net_weight, int64_t* cpu_weight );
@@ -182,6 +185,19 @@ namespace eosio {
*/
void get_blockchain_parameters(eosio::blockchain_parameters& params);
/**
* Get the ram usage of an account
*
* @ingroup privileged
* @param account - name of the account whose resource limit to get
* @param used_ram_bytes - output to hold retrieved ram usage in absolute bytes
*/
inline void get_account_ram_usage( name account, int64_t& used_ram_bytes ) {
internal_use_do_not_use::get_account_ram_usage( account.value, &used_ram_bytes);
}
/**
* Get the resource limits of an account
*
@@ -0,0 +1,86 @@
#pragma once
#include <set>
#include "../../core/eosio/name.hpp"
#include "../../core/eosio/serialize.hpp"
namespace eosio {
namespace internal_use_do_not_use {
extern "C" {
__attribute__((eosio_wasm_import)) int64_t add_security_group_participants(const char* data, uint32_t datalen);
__attribute__((eosio_wasm_import)) int64_t remove_security_group_participants(const char* data, uint32_t datalen);
__attribute__((eosio_wasm_import)) bool in_active_security_group(const char* data, uint32_t datalen);
__attribute__((eosio_wasm_import)) uint32_t get_active_security_group(char* data, uint32_t datalen);
}
} // namespace internal_use_do_not_use
/**
* @defgroup security_group Security Group
* @ingroup contracts
* @brief Defines C++ security group API
*/
struct security_group {
uint32_t version;
std::set<name> participants;
CDT_REFLECT(version, participants);
};
/**
* Propose new participants to the security group.
*
* @ingroup security_group
* @param participants - the participants.
*
* @return -1 if proposing a new security group was unsuccessful, otherwise returns 0.
*/
inline int64_t add_security_group_participants(const std::set<name>& participants) {
auto packed_participants = eosio::pack( participants );
return internal_use_do_not_use::add_security_group_participants( packed_participants.data(), packed_participants.size() );
}
/**
* Propose to remove participants from the security group.
* @ingroup security_group
* @param participants - the participants.
* @return -1 if proposing a new security group was unsuccessful, otherwise returns 0.
*/
inline int64_t remove_security_group_participants(const std::set<name>& participants){
auto packed_participants = eosio::pack( participants );
return internal_use_do_not_use::remove_security_group_participants( packed_participants.data(), packed_participants.size() );
}
/**
* Check if the specified accounts are all in the active security group.
*
* @ingroup security_group
* @param participants - the participants.
*
* @return Returns true if the specified accounts are all in the active security group.
*/
inline bool in_active_security_group(const std::set<name>& participants){
auto packed_participants = eosio::pack( participants );
return internal_use_do_not_use::in_active_security_group( packed_participants.data(), packed_participants.size() );
}
/**
* Gets the active security group
*
* @ingroup security_group
* @param[out] packed_security_group - the buffer containing the packed security_group.
*
* @return Returns the size required in the buffer (if the buffer is too small, nothing is written).
*
*/
inline security_group get_active_security_group() {
size_t buffer_size = internal_use_do_not_use::get_active_security_group(0, 0);
std::vector<char> buffer(buffer_size);
internal_use_do_not_use::get_active_security_group(buffer.data(), buffer_size);
return eosio::unpack<security_group>(buffer);
}
} // namespace eosio
@@ -62,7 +62,7 @@ namespace eosio {
* @return true - if exists
* @return false - otherwise
*/
bool exists() const {
bool exists() {
return _t.find( pk_value ) != _t.end();
}
@@ -72,7 +72,7 @@ namespace eosio {
* @brief Get the value stored inside the singleton table
* @return T - The value stored
*/
T get() const {
T get() {
auto itr = _t.find( pk_value );
eosio::check( itr != _t.end(), "singleton does not exist" );
return itr->value;
@@ -84,7 +84,7 @@ namespace eosio {
* @param def - The default value to be returned in case the data doesn't exist
* @return T - The value stored
*/
T get_or_default( const T& def = T() ) const {
T get_or_default( const T& def = T() ) {
auto itr = _t.find( pk_value );
return itr != _t.end() ? itr->value : def;
}
@@ -13,6 +13,12 @@
namespace eosio {
namespace internal_use_do_not_use {
extern "C" {
__attribute__((eosio_wasm_import))
void send_deferred(const uint128_t&, uint64_t, const char*, size_t, uint32_t);
__attribute__((eosio_wasm_import))
int cancel_deferred(const uint128_t&);
__attribute__((eosio_wasm_import))
size_t read_transaction(char*, size_t);
@@ -41,7 +47,17 @@ namespace eosio {
* @ingroup contracts
* @brief Type-safe C++ wrappers for transaction C API
*
* @details See action for the ability to send an inline action.
* @details An inline message allows one contract to send another contract a message
* which is processed immediately after the current message's processing
* ends such that the success or failure of the parent transaction is
* dependent on the success of the message. If an inline message fails in
* processing then the whole tree of transactions and actions rooted in the
* block will me marked as failing and none of effects on the database will
* persist.
*
* Inline actions and Deferred transactions must adhere to the permissions
* available to the parent transaction or, in the future, delegated to the
* contract account for future use.
*
* @note There are some methods from the @ref transactioncapi that can be used directly from C++
*/
@@ -67,17 +83,17 @@ namespace eosio {
public:
/**
* Construct a new transaction_header
* Construct a new transaction_header with an expiration of now + 60 seconds.
*
* @brief Construct a new transaction_header object
* @brief Construct a new transaction_header object initialising the transaction header expiration to now + 60 seconds
*/
transaction_header( time_point_sec exp = time_point_sec{} )
transaction_header( time_point_sec exp = time_point_sec(current_time_point()) + 60)
:expiration(exp)
{}
time_point_sec expiration;
uint16_t ref_block_num = 0UL;
uint32_t ref_block_prefix = 0UL;
uint16_t ref_block_num;
uint32_t ref_block_prefix;
unsigned_int max_net_usage_words = 0UL; /// number of 8 byte words this transaction can serialize into after compressions
uint8_t max_cpu_usage_ms = 0UL; /// number of CPU usage units to bill transaction for
unsigned_int delay_sec = 0UL; /// number of seconds to delay transaction, default: 0
@@ -94,9 +110,22 @@ namespace eosio {
public:
/**
* Construct a new transaction
* Construct a new transaction with an expiration of now + 60 seconds.
*/
transaction(time_point_sec exp = time_point_sec{}) : transaction_header( exp ) {}
transaction(time_point_sec exp = time_point_sec(current_time_point()) + 60) : transaction_header( exp ) {}
/**
* Sends this transaction, packs the transaction then sends it as a deferred transaction
*
* @details Writes the symbol_code as a string to the provided char buffer
* @param sender_id - ID of sender
* @param payer - Account paying for RAM
* @param replace_existing - Defaults to false, if this is `0`/false then if the provided sender_id is already in use by an in-flight transaction from this contract, which will be a failing assert. If `1` then transaction will atomically cancel/replace the inflight transaction
*/
void send(const uint128_t& sender_id, name payer, bool replace_existing = false) const {
auto serialize = pack(*this);
internal_use_do_not_use::send_deferred(sender_id, payer.value, serialize.data(), serialize.size(), replace_existing);
}
std::vector<action> context_free_actions;
std::vector<action> actions;
@@ -105,6 +134,47 @@ namespace eosio {
EOSLIB_SERIALIZE_DERIVED( transaction, transaction_header, (context_free_actions)(actions)(transaction_extensions) )
};
/**
* Struct onerror contains and sender id and packed transaction
*
* @ingroup transaction
*/
struct onerror {
uint128_t sender_id;
std::vector<char> sent_trx;
/**
* from_current_action unpacks and returns a onerror struct
*
* @ingroup transaction
*/
static onerror from_current_action() {
return unpack_action_data<onerror>();
}
/**
* Unpacks and returns a transaction
*/
transaction unpack_sent_trx() const {
return unpack<transaction>(sent_trx);
}
EOSLIB_SERIALIZE( onerror, (sender_id)(sent_trx) )
};
/**
* Send a deferred transaction
*
* @ingroup transaction
* @param sender_id - Account name of the sender of this deferred transaction
* @param payer - Account name responsible for paying the RAM for this deferred transaction
* @param serialized_transaction - The packed transaction to be deferred
* @param size - The size of the packed transaction, required for persistence.
* @param replace - If true, will replace an existing transaction.
*/
inline void send_deferred(const uint128_t& sender_id, name payer, const char* serialized_transaction, size_t size, bool replace = false) {
internal_use_do_not_use::send_deferred(sender_id, payer.value, serialized_transaction, size, replace);
}
/**
* Retrieve the indicated action from the active transaction.
*
@@ -134,6 +204,29 @@ namespace eosio {
return internal_use_do_not_use::read_transaction( ptr, sz );
}
/**
* Cancels a deferred transaction.
*
* @ingroup transaction
* @param sender_id - The id of the sender
*
* @pre The deferred transaction ID exists.
* @pre The deferred transaction ID has not yet been published.
* @post Deferred transaction canceled.
*
* @return 1 if transaction was canceled, 0 if transaction was not found
*
* Example:
*
* @code
* id = 0xffffffffffffffff
* cancel_deferred( id );
* @endcode
*/
inline int cancel_deferred(const uint128_t& sender_id) {
return internal_use_do_not_use::cancel_deferred(sender_id);
}
/**
* Gets the size of the currently executing transaction.
*
-225
View File
@@ -1,225 +0,0 @@
#pragma once
#include "serialize.hpp"
#include "print.hpp"
#include "check.hpp"
#include "varint.hpp"
#include <vector>
namespace eosio {
// -------------------------------------------------------------------------------
// see https://github.com/AntelopeIO/spring/wiki/ABI-1.3:-bitset-type
// -------------------------------------------------------------------------------
// stores a bitset in a std::vector<uint8_t>
//
// - bits 0-7 in first byte, 8-15 in second, ...
// - least significant bit of byte 0 is bit 0 of bitset.
// - unused bits must be zero.
// ---------------------------------------------------------------------------------
struct bitset {
using buffer_type = std::vector<uint8_t>;
using size_type = uint32_t;
static constexpr size_type bits_per_block = 8;
static constexpr size_type npos = static_cast<size_type>(-1);
static constexpr size_type calc_num_blocks(size_type num_bits) {
return (num_bits + bits_per_block - 1) / bits_per_block;
}
static size_type block_index(size_type pos) noexcept { return pos / bits_per_block; }
static uint8_t bit_index(size_type pos) noexcept { return static_cast<uint8_t>(pos % bits_per_block); }
static uint8_t bit_mask(size_type pos) noexcept { return uint8_t(1) << bit_index(pos); }
size_type size() const { return m_num_bits; }
size_type num_blocks() const {
assert(m_bits.size() == calc_num_blocks(m_num_bits));
return m_bits.size();
}
void resize(size_type num_bits) {
m_bits.resize(calc_num_blocks(num_bits), 0);
m_num_bits = num_bits;
zero_unused_bits();
}
void set(size_type pos) {
assert(pos < m_num_bits);
m_bits[block_index(pos)] |= bit_mask(pos);
}
void clear(size_type pos) {
assert(pos < m_num_bits);
m_bits[block_index(pos)] &= ~bit_mask(pos);
}
bool test(size_type pos) const {
return (*this)[pos];
}
bool operator[](size_type pos) const {
assert(pos < m_num_bits);
return !!(m_bits[block_index(pos)] & bit_mask(pos));
}
void flip(size_type pos) {
assert(pos < m_num_bits);
if (test(pos))
clear(pos);
else
set(pos);
}
void flip() {
for (auto& byte : m_bits)
byte = ~byte;
zero_unused_bits();
}
bool all() const {
auto sz = size();
for (size_t i=0; i<sz; ++i)
if (!test(i))
return false;
return true;
}
bool none() const {
for (auto& byte : m_bits)
if (byte)
return false;
return true;
}
void zero_all_bits() {
for (auto& byte : m_bits)
byte = 0;
}
bitset operator|=(const bitset& o) {
assert(size() == o.size());
for (size_t i=0; i<m_bits.size(); ++i)
m_bits[i] |= o.m_bits[i];
return *this;
}
void zero_unused_bits() {
assert (m_bits.size() == calc_num_blocks(m_num_bits));
// if != 0 this is the number of bits used in the last block
const size_type extra_bits = bit_index(size());
if (extra_bits != 0)
m_bits.back() &= (uint8_t(1) << extra_bits) - 1;
}
bool unused_bits_zeroed() const {
// if != 0 this is the number of bits used in the last block
const size_type extra_bits = bit_index(size());
return extra_bits == 0 || (m_bits.back() & ~((uint8_t(1) << extra_bits) - 1)) == 0;
}
friend auto operator<(const bitset& a, const bitset& b) {
return std::tuple(a.m_num_bits, a.m_bits) < std::tuple(b.m_num_bits, b.m_bits);
}
friend bool operator==(const bitset& a, const bitset& b) {
return std::tuple(a.m_num_bits, a.m_bits) == std::tuple(b.m_num_bits, b.m_bits);
}
uint8_t& byte(size_t i) {
assert(i < m_bits.size());
return m_bits[i];
}
const uint8_t& byte(size_t i) const {
assert(i < m_bits.size());
return m_bits[i];
}
std::string to_string() const {
std::string res;
res.resize(size());
size_t idx = 0;
for (auto i = size(); i-- > 0;)
res[idx++] = (*this)[i] ? '1' : '0';
return res;
}
static bitset from_string(std::string_view s) {
bitset bs;
auto num_bits = s.size();
bs.resize(num_bits);
for (size_t i = 0; i < num_bits; ++i) {
switch (s[i]) {
case '0':
break; // nothing to do, all bits initially 0
case '1':
bs.set(num_bits - i - 1); // high bitset indexes come first in the JSON representation
break;
default:
eosio::check(false, "unexpected character in bitset string representation");
break;
}
}
assert(bs.unused_bits_zeroed());
return bs;
}
void print() const {
auto s = to_string();
if (!s.empty())
printl(s.data(), s.size());
}
// binary representation
// ---------------------
// The bitset first encodes the number of bits it contains as a varint, then encodes
// (size+8-1)/8 bytes into the stream. The first byte represents bits 0-7, the next 8-15,
// and so on; i.e. LSB first.
// Within a byte, the least significant bit stores the smaller bitset index.
// Unused bits should be written as 0.
//
// This matches the storage scheme of bitset above
// ---------------------------------------------------------------------------------------
template <typename DataStream>
friend DataStream& operator>>(DataStream& stream, bitset& obj) {
unsigned_int num_bits(0);
stream >> num_bits;
obj.resize(num_bits.value);
if (obj.size() > 0) {
auto num_blocks = bitset::calc_num_blocks(obj.size());
for (size_t i = 0; i < num_blocks; ++i)
stream >> obj.byte(i);
obj.zero_unused_bits();
assert(obj.unused_bits_zeroed());
}
return stream;
}
template <typename DataStream>
friend DataStream& operator<<(DataStream& stream, const bitset& obj) {
unsigned_int num_bits(obj.size());
stream << num_bits;
if (obj.size() > 0) {
auto num_blocks = bitset::calc_num_blocks(obj.size());
assert(num_blocks >= 1);
for (size_t i = 0; i < num_blocks; ++i)
stream << obj.byte(i);
}
return stream;
}
private:
size_type m_num_bits{0}; // members order matters for comparison operators
buffer_type m_bits; // must be after `m_num_bits`
};
constexpr const char* get_type_name(bitset*) { return "bitset"; }
} // namespace eosio
+21
View File
@@ -7,6 +7,7 @@
#include "fixed_bytes.hpp"
#include "varint.hpp"
#include "serialize.hpp"
#include "name.hpp"
#include <array>
@@ -336,4 +337,24 @@ namespace eosio {
* @param pubkey - Public key
*/
void assert_recover_key( const eosio::checksum256& digest, const eosio::signature& sig, const eosio::public_key& pubkey );
/**
* Tests a signature against a hash, verifies the recovered public key matches the expected one,
* and checks that this public key belongs to the specified account permission.
*
* @ingroup crypto
* @param digest - Digest of the message that was signed
* @param sig - Signature
* @param pubkey - Expected public key
* @param account - The account name to verify key ownership
* @param permission - The permission name to check (e.g., "active"_n, "owner"_n)
*
* @throw eosio::check will fail if:
* - The signature is invalid
* - The recovered key doesn't match the expected public key
* - The account doesn't exist
* - The permission doesn't exist for the account
* - The public key doesn't belong to the specified account permission
*/
void assert_recover_key_account( const eosio::checksum256& digest, const eosio::signature& sig, const eosio::public_key& pubkey, eosio::name account, eosio::name permission );
}
+1 -1
View File
@@ -456,7 +456,7 @@ inline datastream<Stream>& operator>>(datastream<Stream>& ds, std::optional<T>&
T val;
ds >> val;
opt = val;
} else { opt.reset(); }
}
return ds;
}
-73
View File
@@ -1,73 +0,0 @@
#pragma once
#include "check.hpp"
#include "serialize.hpp"
#include "reflect.hpp"
#include <string_view>
namespace eosio {
struct hash_id {
public:
static constexpr uint32_t max_length = 128;
enum class raw : uint64_t {};
constexpr explicit hash_id( hash_id::raw r )
:id(static_cast<uint64_t>(r)) {}
constexpr hash_id() : id(0) {}
constexpr explicit hash_id( std::string_view s )
: id(djbh_hash(s))
{
validate(s);
}
constexpr void validate(std::string_view str) {
if (str.empty()) {
eosio::check(false, "string cannot be empty to be an hash_id");
}
if (str.length() > max_length) {
eosio::check(false, "string is too long be a valid hash_id. must be less than or equal to " + std::to_string(max_length));
}
// cannot use std::isalpha in constexpr function
if (! ((str[0] >= 'A' && str[0] <= 'Z') || (str[0] >= 'a' && str[0] <= 'z') || str[0] == '_') ) {
eosio::check(false, "string must start with a letter or _ to be a valid hash_id.");
}
for (char c : str.substr(1)) {
// cannot use std::isalnum in constexpr function
if (! ((str[0] >= 'A' && str[0] <= 'Z') || (str[0] >= 'a' && str[0] <= 'z') || (str[0] >= '0' && str[0] <= '9') || str[0] == '_') ) {
eosio::check(false, "string contains a character " + std::string{c} + " that is not a letter, number, or _");
}
}
}
static constexpr uint64_t djbh_hash(std::string_view s) {
uint64_t hash = 5381;
for (char c : s) {
hash = ((hash << 5) + hash) + static_cast<uint8_t>(c); // hash * 33 + c
}
return hash;
}
constexpr operator raw()const { return raw(id); }
uint64_t id = 0;
CDT_REFLECT(id);
EOSLIB_SERIALIZE( hash_id, (id) )
}; /// namespace hash_id
} /// namespace eosio
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template"
template <typename T, T... Str>
inline constexpr eosio::hash_id operator""_i() {
constexpr auto x = eosio::hash_id{std::string_view{eosio::detail::to_const_char_arr<Str...>::value, sizeof...(Str)}};
return x;
}
#pragma clang diagnostic pop
+17
View File
@@ -42,6 +42,11 @@ extern "C" {
__attribute__((eosio_wasm_import))
void assert_recover_key( const capi_checksum256* digest, const char* sig,
size_t siglen, const char* pub, size_t publen );
__attribute__((eosio_wasm_import))
void assert_recover_key_account( const capi_checksum256* digest, const char* sig,
size_t siglen, const char* pub, size_t publen,
uint64_t account, uint64_t permission );
}
namespace eosio {
@@ -131,4 +136,16 @@ namespace eosio {
sig_data.data(), sig_data.size(),
pubkey_data.data(), pubkey_data.size() );
}
void assert_recover_key_account( const eosio::checksum256& digest, const eosio::signature& sig, const eosio::public_key& pubkey, eosio::name account, eosio::name permission ) {
auto digest_data = digest.extract_as_byte_array();
auto sig_data = eosio::pack(sig);
auto pubkey_data = eosio::pack(pubkey);
::assert_recover_key_account( reinterpret_cast<const capi_checksum256*>(digest_data.data()),
sig_data.data(), sig_data.size(),
pubkey_data.data(), pubkey_data.size(),
account.value, permission.value );
}
}
+159 -149
View File
@@ -16,347 +16,341 @@
// Boilerplate
using namespace eosio::native;
extern "C" {
void get_account_ram_usage( capi_name account, int64_t* used_ram_bytes ) {
return intrinsics::get().call<intrinsics::get_account_ram_usage>(account, used_ram_bytes);
}
void get_resource_limits( capi_name account, int64_t* ram_bytes, int64_t* net_weight, int64_t* cpu_weight ) {
return intrinsics::get().exec<intrinsics::get_resource_limits>(account, ram_bytes, net_weight, cpu_weight);
return intrinsics::get().call<intrinsics::get_resource_limits>(account, ram_bytes, net_weight, cpu_weight);
}
void set_resource_limits( capi_name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ) {
return intrinsics::get().exec<intrinsics::set_resource_limits>(account, ram_bytes, net_weight, cpu_weight);
return intrinsics::get().call<intrinsics::set_resource_limits>(account, ram_bytes, net_weight, cpu_weight);
}
int64_t set_proposed_producers( char *producer_data, uint32_t producer_data_size ) {
return intrinsics::get().exec<intrinsics::set_proposed_producers>(producer_data, producer_data_size);
return intrinsics::get().call<intrinsics::set_proposed_producers>(producer_data, producer_data_size);
}
int64_t set_proposed_producers_ex( uint64_t producer_data_format, char *producer_data, uint32_t producer_data_size ) {
return intrinsics::get().exec<intrinsics::set_proposed_producers_ex>(producer_data_format, producer_data, producer_data_size);
return intrinsics::get().call<intrinsics::set_proposed_producers_ex>(producer_data_format, producer_data, producer_data_size);
}
uint32_t get_blockchain_parameters_packed( char* data, uint32_t datalen ) {
return intrinsics::get().exec<intrinsics::get_blockchain_parameters_packed>(data, datalen);
return intrinsics::get().call<intrinsics::get_blockchain_parameters_packed>(data, datalen);
}
void set_blockchain_parameters_packed( char* data, uint32_t datalen ) {
return intrinsics::get().exec<intrinsics::set_blockchain_parameters_packed>(data, datalen);
return intrinsics::get().call<intrinsics::set_blockchain_parameters_packed>(data, datalen);
}
bool is_privileged( capi_name account ) {
return intrinsics::get().exec<intrinsics::is_privileged>(account);
return intrinsics::get().call<intrinsics::is_privileged>(account);
}
void set_privileged( capi_name account, bool is_priv ) {
return intrinsics::get().exec<intrinsics::set_privileged>(account, is_priv);
return intrinsics::get().call<intrinsics::set_privileged>(account, is_priv);
}
bool is_feature_activated( const capi_checksum256* feature_digest ) {
return intrinsics::get().exec<intrinsics::is_feature_activated>(feature_digest);
return intrinsics::get().call<intrinsics::is_feature_activated>(feature_digest);
}
void preactivate_feature( const capi_checksum256* feature_digest ) {
return intrinsics::get().exec<intrinsics::preactivate_feature>(feature_digest);
return intrinsics::get().call<intrinsics::preactivate_feature>(feature_digest);
}
uint32_t get_active_producers( capi_name* producers, uint32_t datalen ) {
return intrinsics::get().exec<intrinsics::get_active_producers>(producers, datalen);
return intrinsics::get().call<intrinsics::get_active_producers>(producers, datalen);
}
int32_t db_idx64_store(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const uint64_t* secondary) {
return intrinsics::get().exec<intrinsics::db_idx64_store>(scope, table, payer, id, secondary);
return intrinsics::get().call<intrinsics::db_idx64_store>(scope, table, payer, id, secondary);
}
void db_idx64_remove(int32_t iterator) {
return intrinsics::get().exec<intrinsics::db_idx64_remove>(iterator);
return intrinsics::get().call<intrinsics::db_idx64_remove>(iterator);
}
void db_idx64_update(int32_t iterator, capi_name payer, const uint64_t* secondary) {
return intrinsics::get().exec<intrinsics::db_idx64_update>(iterator, payer, secondary);
return intrinsics::get().call<intrinsics::db_idx64_update>(iterator, payer, secondary);
}
int32_t db_idx64_find_primary(capi_name code, uint64_t scope, capi_name table, uint64_t* secondary, uint64_t primary) {
return intrinsics::get().exec<intrinsics::db_idx64_find_primary>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx64_find_primary>(code, scope, table, secondary, primary);
}
int32_t db_idx64_find_secondary(capi_name code, uint64_t scope, capi_name table, const uint64_t* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx64_find_secondary>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx64_find_secondary>(code, scope, table, secondary, primary);
}
int32_t db_idx64_lowerbound(capi_name code, uint64_t scope, capi_name table, uint64_t* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx64_lowerbound>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx64_lowerbound>(code, scope, table, secondary, primary);
}
int32_t db_idx64_upperbound(capi_name code, uint64_t scope, capi_name table, uint64_t* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx64_upperbound>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx64_upperbound>(code, scope, table, secondary, primary);
}
int32_t db_idx64_end(capi_name code, uint64_t scope, capi_name table) {
return intrinsics::get().exec<intrinsics::db_idx64_end>(code, scope, table);
return intrinsics::get().call<intrinsics::db_idx64_end>(code, scope, table);
}
int32_t db_idx64_next(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx64_next>(iterator, primary);
return intrinsics::get().call<intrinsics::db_idx64_next>(iterator, primary);
}
int32_t db_idx64_previous(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx64_previous>(iterator, primary);
return intrinsics::get().call<intrinsics::db_idx64_previous>(iterator, primary);
}
int32_t db_idx128_store(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const uint128_t* secondary) {
return intrinsics::get().exec<intrinsics::db_idx128_store>(scope, table, payer, id, secondary);
return intrinsics::get().call<intrinsics::db_idx128_store>(scope, table, payer, id, secondary);
}
void db_idx128_remove(int32_t iterator) {
return intrinsics::get().exec<intrinsics::db_idx128_remove>(iterator);
return intrinsics::get().call<intrinsics::db_idx128_remove>(iterator);
}
void db_idx128_update(int32_t iterator, capi_name payer, const uint128_t* secondary) {
return intrinsics::get().exec<intrinsics::db_idx128_update>(iterator, payer, secondary);
return intrinsics::get().call<intrinsics::db_idx128_update>(iterator, payer, secondary);
}
int32_t db_idx128_find_primary(capi_name code, uint64_t scope, capi_name table, uint128_t* secondary, uint64_t primary) {
return intrinsics::get().exec<intrinsics::db_idx128_find_primary>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx128_find_primary>(code, scope, table, secondary, primary);
}
int32_t db_idx128_find_secondary(capi_name code, uint64_t scope, capi_name table, const uint128_t* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx128_find_secondary>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx128_find_secondary>(code, scope, table, secondary, primary);
}
int32_t db_idx128_lowerbound(capi_name code, uint64_t scope, capi_name table, uint128_t* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx128_lowerbound>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx128_lowerbound>(code, scope, table, secondary, primary);
}
int32_t db_idx128_upperbound(capi_name code, uint64_t scope, capi_name table, uint128_t* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx128_upperbound>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx128_upperbound>(code, scope, table, secondary, primary);
}
int32_t db_idx128_end(capi_name code, uint64_t scope, capi_name table) {
return intrinsics::get().exec<intrinsics::db_idx128_end>(code, scope, table);
return intrinsics::get().call<intrinsics::db_idx128_end>(code, scope, table);
}
int32_t db_idx128_next(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx128_next>(iterator, primary);
return intrinsics::get().call<intrinsics::db_idx128_next>(iterator, primary);
}
int32_t db_idx128_previous(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx128_previous>(iterator, primary);
return intrinsics::get().call<intrinsics::db_idx128_previous>(iterator, primary);
}
int32_t db_idx256_store(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const uint128_t* data, uint32_t datalen) {
return intrinsics::get().exec<intrinsics::db_idx256_store>(scope, table, payer, id, data, datalen);
return intrinsics::get().call<intrinsics::db_idx256_store>(scope, table, payer, id, data, datalen);
}
void db_idx256_remove(int32_t iterator) {
return intrinsics::get().exec<intrinsics::db_idx256_remove>(iterator);
return intrinsics::get().call<intrinsics::db_idx256_remove>(iterator);
}
void db_idx256_update(int32_t iterator, capi_name payer, const uint128_t* data, uint32_t datalen) {
return intrinsics::get().exec<intrinsics::db_idx256_update>(iterator, payer, data, datalen);
return intrinsics::get().call<intrinsics::db_idx256_update>(iterator, payer, data, datalen);
}
int32_t db_idx256_find_primary(capi_name code, uint64_t scope, capi_name table, uint128_t* data, uint32_t datalen, uint64_t primary) {
return intrinsics::get().exec<intrinsics::db_idx256_find_primary>(code, scope, table, data, datalen, primary);
return intrinsics::get().call<intrinsics::db_idx256_find_primary>(code, scope, table, data, datalen, primary);
}
int32_t db_idx256_find_secondary(capi_name code, uint64_t scope, capi_name table, const uint128_t* data, uint32_t datalen, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx256_find_secondary>(code, scope, table, data, datalen, primary);
return intrinsics::get().call<intrinsics::db_idx256_find_secondary>(code, scope, table, data, datalen, primary);
}
int32_t db_idx256_lowerbound(capi_name code, uint64_t scope, capi_name table, uint128_t* data, uint32_t datalen, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx256_lowerbound>(code, scope, table, data, datalen, primary);
return intrinsics::get().call<intrinsics::db_idx256_lowerbound>(code, scope, table, data, datalen, primary);
}
int32_t db_idx256_upperbound(capi_name code, uint64_t scope, capi_name table, uint128_t* data, uint32_t datalen, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx256_upperbound>(code, scope, table, data, datalen, primary);
return intrinsics::get().call<intrinsics::db_idx256_upperbound>(code, scope, table, data, datalen, primary);
}
int32_t db_idx256_end(capi_name code, uint64_t scope, capi_name table) {
return intrinsics::get().exec<intrinsics::db_idx256_end>(code, scope, table);
return intrinsics::get().call<intrinsics::db_idx256_end>(code, scope, table);
}
int32_t db_idx256_next(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx256_next>(iterator, primary);
return intrinsics::get().call<intrinsics::db_idx256_next>(iterator, primary);
}
int32_t db_idx256_previous(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx256_previous>(iterator, primary);
return intrinsics::get().call<intrinsics::db_idx256_previous>(iterator, primary);
}
int32_t db_idx_double_store(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const double* secondary) {
return intrinsics::get().exec<intrinsics::db_idx_double_store>(scope, table, payer, id, secondary);
return intrinsics::get().call<intrinsics::db_idx_double_store>(scope, table, payer, id, secondary);
}
void db_idx_double_remove(int32_t iterator) {
return intrinsics::get().exec<intrinsics::db_idx_double_remove>(iterator);
return intrinsics::get().call<intrinsics::db_idx_double_remove>(iterator);
}
void db_idx_double_update(int32_t iterator, capi_name payer, const double* secondary) {
return intrinsics::get().exec<intrinsics::db_idx_double_update>(iterator, payer, secondary);
return intrinsics::get().call<intrinsics::db_idx_double_update>(iterator, payer, secondary);
}
int32_t db_idx_double_find_primary(capi_name code, uint64_t scope, capi_name table, double* secondary, uint64_t primary) {
return intrinsics::get().exec<intrinsics::db_idx_double_find_primary>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx_double_find_primary>(code, scope, table, secondary, primary);
}
int32_t db_idx_double_find_secondary(capi_name code, uint64_t scope, capi_name table, const double* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx_double_find_secondary>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx_double_find_secondary>(code, scope, table, secondary, primary);
}
int32_t db_idx_double_lowerbound(capi_name code, uint64_t scope, capi_name table, double* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx_double_lowerbound>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx_double_lowerbound>(code, scope, table, secondary, primary);
}
int32_t db_idx_double_upperbound(capi_name code, uint64_t scope, capi_name table, double* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx_double_upperbound>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx_double_upperbound>(code, scope, table, secondary, primary);
}
int32_t db_idx_double_end(capi_name code, uint64_t scope, capi_name table) {
return intrinsics::get().exec<intrinsics::db_idx_double_end>(code, scope, table);
return intrinsics::get().call<intrinsics::db_idx_double_end>(code, scope, table);
}
int32_t db_idx_double_next(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx_double_next>(iterator, primary);
return intrinsics::get().call<intrinsics::db_idx_double_next>(iterator, primary);
}
int32_t db_idx_double_previous(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx_double_previous>(iterator, primary);
return intrinsics::get().call<intrinsics::db_idx_double_previous>(iterator, primary);
}
int32_t db_idx_long_double_store(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const long double* secondary) {
return intrinsics::get().exec<intrinsics::db_idx_long_double_store>(scope, table, payer, id, secondary);
return intrinsics::get().call<intrinsics::db_idx_long_double_store>(scope, table, payer, id, secondary);
}
void db_idx_long_double_remove(int32_t iterator) {
return intrinsics::get().exec<intrinsics::db_idx_long_double_remove>(iterator);
return intrinsics::get().call<intrinsics::db_idx_long_double_remove>(iterator);
}
void db_idx_long_double_update(int32_t iterator, capi_name payer, const long double* secondary) {
return intrinsics::get().exec<intrinsics::db_idx_long_double_update>(iterator, payer, secondary);
return intrinsics::get().call<intrinsics::db_idx_long_double_update>(iterator, payer, secondary);
}
int32_t db_idx_long_double_find_primary(capi_name code, uint64_t scope, capi_name table, long double* secondary, uint64_t primary) {
return intrinsics::get().exec<intrinsics::db_idx_long_double_find_primary>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx_long_double_find_primary>(code, scope, table, secondary, primary);
}
int32_t db_idx_long_double_find_secondary(capi_name code, uint64_t scope, capi_name table, const long double* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx_long_double_find_secondary>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx_long_double_find_secondary>(code, scope, table, secondary, primary);
}
int32_t db_idx_long_double_lowerbound(capi_name code, uint64_t scope, capi_name table, long double* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx_long_double_lowerbound>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx_long_double_lowerbound>(code, scope, table, secondary, primary);
}
int32_t db_idx_long_double_upperbound(capi_name code, uint64_t scope, capi_name table, long double* secondary, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx_long_double_upperbound>(code, scope, table, secondary, primary);
return intrinsics::get().call<intrinsics::db_idx_long_double_upperbound>(code, scope, table, secondary, primary);
}
int32_t db_idx_long_double_end(capi_name code, uint64_t scope, capi_name table) {
return intrinsics::get().exec<intrinsics::db_idx_long_double_end>(code, scope, table);
return intrinsics::get().call<intrinsics::db_idx_long_double_end>(code, scope, table);
}
int32_t db_idx_long_double_next(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx_long_double_next>(iterator, primary);
return intrinsics::get().call<intrinsics::db_idx_long_double_next>(iterator, primary);
}
int32_t db_idx_long_double_previous(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_idx_long_double_previous>(iterator, primary);
return intrinsics::get().call<intrinsics::db_idx_long_double_previous>(iterator, primary);
}
int32_t db_store_i64(uint64_t scope, capi_name table, capi_name payer, uint64_t id, const void* data, uint32_t len) {
return intrinsics::get().exec<intrinsics::db_store_i64>(scope, table, payer, id, data, len);
return intrinsics::get().call<intrinsics::db_store_i64>(scope, table, payer, id, data, len);
}
void db_update_i64(int32_t iterator, capi_name payer, const void* data, uint32_t len) {
return intrinsics::get().exec<intrinsics::db_update_i64>(iterator, payer, data, len);
return intrinsics::get().call<intrinsics::db_update_i64>(iterator, payer, data, len);
}
void db_remove_i64(int32_t iterator) {
return intrinsics::get().exec<intrinsics::db_remove_i64>(iterator);
return intrinsics::get().call<intrinsics::db_remove_i64>(iterator);
}
int32_t db_get_i64(int32_t iterator, const void* data, uint32_t len) {
return intrinsics::get().exec<intrinsics::db_get_i64>(iterator, data, len);
return intrinsics::get().call<intrinsics::db_get_i64>(iterator, data, len);
}
int32_t db_next_i64(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_next_i64>(iterator, primary);
return intrinsics::get().call<intrinsics::db_next_i64>(iterator, primary);
}
int32_t db_previous_i64(int32_t iterator, uint64_t* primary) {
return intrinsics::get().exec<intrinsics::db_previous_i64>(iterator, primary);
return intrinsics::get().call<intrinsics::db_previous_i64>(iterator, primary);
}
int32_t db_find_i64(capi_name code, uint64_t scope, capi_name table, uint64_t id) {
return intrinsics::get().exec<intrinsics::db_find_i64>(code, scope, table, id);
return intrinsics::get().call<intrinsics::db_find_i64>(code, scope, table, id);
}
int32_t db_lowerbound_i64(capi_name code, uint64_t scope, capi_name table, uint64_t id) {
return intrinsics::get().exec<intrinsics::db_lowerbound_i64>(code, scope, table, id);
return intrinsics::get().call<intrinsics::db_lowerbound_i64>(code, scope, table, id);
}
int32_t db_upperbound_i64(capi_name code, uint64_t scope, capi_name table, uint64_t id) {
return intrinsics::get().exec<intrinsics::db_upperbound_i64>(code, scope, table, id);
return intrinsics::get().call<intrinsics::db_upperbound_i64>(code, scope, table, id);
}
int32_t db_end_i64(capi_name code, uint64_t scope, capi_name table) {
return intrinsics::get().exec<intrinsics::db_end_i64>(code, scope, table);
return intrinsics::get().call<intrinsics::db_end_i64>(code, scope, table);
}
void assert_recover_key( const capi_checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen ) {
return intrinsics::get().exec<intrinsics::assert_recover_key>(digest, sig, siglen, pub, publen);
return intrinsics::get().call<intrinsics::assert_recover_key>(digest, sig, siglen, pub, publen);
}
int recover_key( const capi_checksum256* digest, const char* sig, size_t siglen, char* pub, size_t publen ) {
return intrinsics::get().exec<intrinsics::recover_key>(digest, sig, siglen, pub, publen);
return intrinsics::get().call<intrinsics::recover_key>(digest, sig, siglen, pub, publen);
}
void assert_recover_key_account( const capi_checksum256* digest, const char* sig, size_t siglen, const char* pub, size_t publen, uint64_t account, uint64_t permission ) {
return intrinsics::get().call<intrinsics::assert_recover_key_account>(digest, sig, siglen, pub, publen, account, permission);
}
void assert_sha256( const char* data, uint32_t length, const capi_checksum256* hash ) {
return intrinsics::get().exec<intrinsics::assert_sha256>(data, length, hash);
return intrinsics::get().call<intrinsics::assert_sha256>(data, length, hash);
}
void assert_sha1( const char* data, uint32_t length, const capi_checksum160* hash ) {
return intrinsics::get().exec<intrinsics::assert_sha1>(data, length, hash);
return intrinsics::get().call<intrinsics::assert_sha1>(data, length, hash);
}
void assert_sha512( const char* data, uint32_t length, const capi_checksum512* hash ) {
return intrinsics::get().exec<intrinsics::assert_sha512>(data, length, hash);
return intrinsics::get().call<intrinsics::assert_sha512>(data, length, hash);
}
void assert_ripemd160( const char* data, uint32_t length, const capi_checksum160* hash ) {
return intrinsics::get().exec<intrinsics::assert_ripemd160>(data, length, hash);
return intrinsics::get().call<intrinsics::assert_ripemd160>(data, length, hash);
}
void sha256( const char* data, uint32_t length, capi_checksum256* hash ) {
return intrinsics::get().exec<intrinsics::sha256>(data, length, hash);
return intrinsics::get().call<intrinsics::sha256>(data, length, hash);
}
void sha1( const char* data, uint32_t length, capi_checksum160* hash ) {
return intrinsics::get().exec<intrinsics::sha1>(data, length, hash);
return intrinsics::get().call<intrinsics::sha1>(data, length, hash);
}
void sha512( const char* data, uint32_t length, capi_checksum512* hash ) {
return intrinsics::get().exec<intrinsics::sha512>(data, length, hash);
return intrinsics::get().call<intrinsics::sha512>(data, length, hash);
}
void ripemd160( const char* data, uint32_t length, capi_checksum160* hash ) {
return intrinsics::get().exec<intrinsics::ripemd160>(data, length, hash);
return intrinsics::get().call<intrinsics::ripemd160>(data, length, hash);
}
int32_t check_transaction_authorization( const char* trx_data, uint32_t trx_size,
const char* pubkeys_data, uint32_t pubkeys_size,
const char* perms_data, uint32_t perms_size
) {
return intrinsics::get().exec<intrinsics::check_transaction_authorization>(trx_data, trx_size, pubkeys_data, pubkeys_size, perms_data, perms_size);
return intrinsics::get().call<intrinsics::check_transaction_authorization>(trx_data, trx_size, pubkeys_data, pubkeys_size, perms_data, perms_size);
}
int32_t check_permission_authorization( capi_name account, capi_name permission,
const char* pubkeys_data, uint32_t pubkeys_size,
const char* perms_data, uint32_t perms_size, uint64_t delay_us
) {
return intrinsics::get().exec<intrinsics::check_permission_authorization>(account, permission, pubkeys_data, pubkeys_size, perms_data, perms_size, delay_us);
return intrinsics::get().call<intrinsics::check_permission_authorization>(account, permission, pubkeys_data, pubkeys_size, perms_data, perms_size, delay_us);
}
int64_t get_permission_last_used( capi_name account, capi_name permission ) {
return intrinsics::get().exec<intrinsics::get_permission_last_used>(account, permission);
return intrinsics::get().call<intrinsics::get_permission_last_used>(account, permission);
}
int64_t get_account_creation_time( capi_name account ) {
return intrinsics::get().exec<intrinsics::get_account_creation_time>(account);
return intrinsics::get().call<intrinsics::get_account_creation_time>(account);
}
uint64_t current_time() {
return intrinsics::get().exec<intrinsics::current_time>();
return intrinsics::get().call<intrinsics::current_time>();
}
uint64_t publication_time() {
return intrinsics::get().exec<intrinsics::publication_time>();
return intrinsics::get().call<intrinsics::publication_time>();
}
uint32_t read_action_data( void* msg, uint32_t len ) {
return intrinsics::get().exec<intrinsics::read_action_data>(msg, len);
return intrinsics::get().call<intrinsics::read_action_data>(msg, len);
}
uint32_t action_data_size() {
return intrinsics::get().exec<intrinsics::action_data_size>();
return intrinsics::get().call<intrinsics::action_data_size>();
}
capi_name current_receiver() {
return intrinsics::get().exec<intrinsics::current_receiver>();
return intrinsics::get().call<intrinsics::current_receiver>();
}
void set_action_return_value( void* rv, size_t len ) {
intrinsics::get().exec<intrinsics::set_action_return_value>(rv, len);
intrinsics::get().call<intrinsics::set_action_return_value>(rv, len);
}
void require_recipient( capi_name name ) {
return intrinsics::get().exec<intrinsics::require_recipient>(name);
return intrinsics::get().call<intrinsics::require_recipient>(name);
}
void require_auth( capi_name name ) {
return intrinsics::get().exec<intrinsics::require_auth>(name);
return intrinsics::get().call<intrinsics::require_auth>(name);
}
void require_auth2( capi_name name, capi_name permission ) {
return intrinsics::get().exec<intrinsics::require_auth2>(name, permission);
return intrinsics::get().call<intrinsics::require_auth2>(name, permission);
}
bool has_auth( capi_name name ) {
return intrinsics::get().exec<intrinsics::has_auth>(name);
return intrinsics::get().call<intrinsics::has_auth>(name);
}
bool is_account( capi_name name ) {
return intrinsics::get().exec<intrinsics::is_account>(name);
return intrinsics::get().call<intrinsics::is_account>(name);
}
size_t read_transaction(char *buffer, size_t size) {
return intrinsics::get().exec<intrinsics::read_transaction>(buffer, size);
return intrinsics::get().call<intrinsics::read_transaction>(buffer, size);
}
size_t transaction_size() {
return intrinsics::get().exec<intrinsics::transaction_size>();
return intrinsics::get().call<intrinsics::transaction_size>();
}
uint32_t expiration() {
return intrinsics::get().exec<intrinsics::expiration>();
return intrinsics::get().call<intrinsics::expiration>();
}
int tapos_block_prefix() {
return intrinsics::get().exec<intrinsics::tapos_block_prefix>();
return intrinsics::get().call<intrinsics::tapos_block_prefix>();
}
int tapos_block_num() {
return intrinsics::get().exec<intrinsics::tapos_block_num>();
return intrinsics::get().call<intrinsics::tapos_block_num>();
}
int get_action( uint32_t type, uint32_t index, char* buff, size_t size ) {
return intrinsics::get().exec<intrinsics::get_action>(type, index, buff, size);
return intrinsics::get().call<intrinsics::get_action>(type, index, buff, size);
}
void send_inline(char *serialized_action, size_t size) {
return intrinsics::get().exec<intrinsics::send_inline>(serialized_action, size);
return intrinsics::get().call<intrinsics::send_inline>(serialized_action, size);
}
void send_context_free_inline(char *serialized_action, size_t size) {
return intrinsics::get().exec<intrinsics::send_context_free_inline>(serialized_action, size);
return intrinsics::get().call<intrinsics::send_context_free_inline>(serialized_action, size);
}
void send_deferred(const uint128_t* sender_id, capi_name payer, const char *serialized_transaction, size_t size, uint32_t replace_existing) {
return intrinsics::get().exec<intrinsics::send_deferred>(sender_id, payer, serialized_transaction, size, replace_existing);
return intrinsics::get().call<intrinsics::send_deferred>(sender_id, payer, serialized_transaction, size, replace_existing);
}
int cancel_deferred(const uint128_t* sender_id) {
return intrinsics::get().exec<intrinsics::cancel_deferred>(sender_id);
return intrinsics::get().call<intrinsics::cancel_deferred>(sender_id);
}
int get_context_free_data( uint32_t index, char* buff, size_t size ) {
return intrinsics::get().exec<intrinsics::get_context_free_data>(index, buff, size);
return intrinsics::get().call<intrinsics::get_context_free_data>(index, buff, size);
}
capi_name get_sender() {
return intrinsics::get().exec<intrinsics::get_sender>();
}
int64_t call(capi_name receiver, uint64_t flags, const char* data, size_t data_size) {
return intrinsics::get().exec<intrinsics::call>(receiver, flags, data, data_size);
}
uint32_t get_call_return_value(void* mem, uint32_t len) {
return intrinsics::get().exec<intrinsics::get_call_return_value>(mem, len);
}
uint32_t get_call_data(void* mem, uint32_t len) {
return intrinsics::get().exec<intrinsics::get_call_data>(mem, len);
}
void set_call_return_value(void* mem, uint32_t len) {
return intrinsics::get().exec<intrinsics::set_call_return_value>(mem, len);
return intrinsics::get().call<intrinsics::get_sender>();
}
// softfloat
@@ -798,47 +792,47 @@ extern "C" {
}
void prints_l(const char* cstr, uint32_t len) {
return intrinsics::get().exec<intrinsics::prints_l>(cstr, len);
return intrinsics::get().call<intrinsics::prints_l>(cstr, len);
}
void prints(const char* cstr) {
return intrinsics::get().exec<intrinsics::prints>(cstr);
return intrinsics::get().call<intrinsics::prints>(cstr);
}
void printi(int64_t value) {
return intrinsics::get().exec<intrinsics::printi>(value);
return intrinsics::get().call<intrinsics::printi>(value);
}
void printui(uint64_t value) {
return intrinsics::get().exec<intrinsics::printui>(value);
return intrinsics::get().call<intrinsics::printui>(value);
}
void printi128(const int128_t* value) {
return intrinsics::get().exec<intrinsics::printi128>(value);
return intrinsics::get().call<intrinsics::printi128>(value);
}
void printui128(const uint128_t* value) {
return intrinsics::get().exec<intrinsics::printui128>(value);
return intrinsics::get().call<intrinsics::printui128>(value);
}
void printsf(float value) {
return intrinsics::get().exec<intrinsics::printsf>(value);
return intrinsics::get().call<intrinsics::printsf>(value);
}
void printdf(double value) {
return intrinsics::get().exec<intrinsics::printdf>(value);
return intrinsics::get().call<intrinsics::printdf>(value);
}
void printqf(const long double* value) {
return intrinsics::get().exec<intrinsics::printqf>(value);
return intrinsics::get().call<intrinsics::printqf>(value);
}
void printn(uint64_t nm) {
return intrinsics::get().exec<intrinsics::printn>(nm);
return intrinsics::get().call<intrinsics::printn>(nm);
}
void printhex(const void* data, uint32_t len) {
return intrinsics::get().exec<intrinsics::printhex>(data, len);
return intrinsics::get().call<intrinsics::printhex>(data, len);
}
void* memset ( void* ptr, int value, size_t num ) {
@@ -902,87 +896,103 @@ extern "C" {
}
#pragma clang diagnostic pop
int64_t add_security_group_participants(const char* data, uint32_t datalen) {
return intrinsics::get().call<intrinsics::add_security_group_participants>(data, datalen);
}
int64_t remove_security_group_participants(const char* data, uint32_t datalen){
return intrinsics::get().call<intrinsics::remove_security_group_participants>(data, datalen);
}
bool in_active_security_group(const char* data, uint32_t datalen){
return intrinsics::get().call<intrinsics::in_active_security_group>(data, datalen);
}
uint32_t get_active_security_group(char* data, uint32_t datalen){
return intrinsics::get().call<intrinsics::get_active_security_group>(data, datalen);
}
void set_finalizers(uint64_t packed_finalizer_format, const char* data, uint32_t len) {
intrinsics::get().exec<intrinsics::set_finalizers>(packed_finalizer_format, data, len);
intrinsics::get().call<intrinsics::set_finalizers>(packed_finalizer_format, data, len);
}
} // extern "C"
int32_t blake2_f( uint32_t rounds, const char* state, uint32_t state_len, const char* msg, uint32_t msg_len,
const char* t0_offset, uint32_t t0_len, const char* t1_offset, uint32_t t1_len, int32_t final, char* result, uint32_t result_len) {
return intrinsics::get().exec<intrinsics::blake2_f>(rounds, state, state_len, msg, msg_len, t0_offset, t0_len, t1_offset, t1_len, final, result, result_len);
return intrinsics::get().call<intrinsics::blake2_f>(rounds, state, state_len, msg, msg_len, t0_offset, t0_len, t1_offset, t1_len, final, result, result_len);
}
int32_t k1_recover( const char* sig, uint32_t sig_len, const char* dig, uint32_t dig_len, char* pub, uint32_t pub_len) {
return intrinsics::get().exec<intrinsics::k1_recover>(sig, sig_len, dig, dig_len, pub, pub_len);
return intrinsics::get().call<intrinsics::k1_recover>(sig, sig_len, dig, dig_len, pub, pub_len);
}
int32_t alt_bn128_add( const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* result, uint32_t result_len) {
return intrinsics::get().exec<intrinsics::alt_bn128_add>(op1, op1_len, op2, op2_len, result, result_len);
return intrinsics::get().call<intrinsics::alt_bn128_add>(op1, op1_len, op2, op2_len, result, result_len);
}
int32_t alt_bn128_mul( const char* g1, uint32_t g1_len, const char* scalar, uint32_t scalar_len, char* result, uint32_t result_len) {
return intrinsics::get().exec<intrinsics::alt_bn128_mul>(g1, g1_len, scalar, scalar_len, result, result_len);
return intrinsics::get().call<intrinsics::alt_bn128_mul>(g1, g1_len, scalar, scalar_len, result, result_len);
}
int32_t alt_bn128_pair( const char* pairs, uint32_t pairs_len) {
return intrinsics::get().exec<intrinsics::alt_bn128_pair>(pairs, pairs_len);
return intrinsics::get().call<intrinsics::alt_bn128_pair>(pairs, pairs_len);
}
int32_t mod_exp( const char* base, uint32_t base_len, const char* exp, uint32_t exp_len, const char* mod, uint32_t mod_len, char* result, uint32_t result_len) {
return intrinsics::get().exec<intrinsics::mod_exp>(base, base_len, exp, exp_len, mod, mod_len, result, result_len);
return intrinsics::get().call<intrinsics::mod_exp>(base, base_len, exp, exp_len, mod, mod_len, result, result_len);
}
void sha3( const char* data, uint32_t data_len, char* hash, uint32_t hash_len, int32_t keccak ) {
intrinsics::get().exec<intrinsics::sha3>(data, data_len, hash, hash_len, keccak);
intrinsics::get().call<intrinsics::sha3>(data, data_len, hash, hash_len, keccak);
}
int32_t bls_g1_add(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len)
{
return intrinsics::get().exec<intrinsics::bls_g1_add>(op1, op1_len, op2, op2_len, res, res_len);
return intrinsics::get().call<intrinsics::bls_g1_add>(op1, op1_len, op2, op2_len, res, res_len);
}
int32_t bls_g2_add(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len)
{
return intrinsics::get().exec<intrinsics::bls_g2_add>(op1, op1_len, op2, op2_len, res, res_len);
return intrinsics::get().call<intrinsics::bls_g2_add>(op1, op1_len, op2, op2_len, res, res_len);
}
int32_t bls_g1_weighted_sum(const char* points, uint32_t points_len, const char* scalars, uint32_t scalars_len, uint32_t n, char* res, uint32_t res_len)
{
return intrinsics::get().exec<intrinsics::bls_g1_weighted_sum>(points, points_len, scalars, scalars_len, n, res, res_len);
return intrinsics::get().call<intrinsics::bls_g1_weighted_sum>(points, points_len, scalars, scalars_len, n, res, res_len);
}
int32_t bls_g2_weighted_sum(const char* points, uint32_t points_len, const char* scalars, uint32_t scalars_len, uint32_t n, char* res, uint32_t res_len)
{
return intrinsics::get().exec<intrinsics::bls_g2_weighted_sum>(points, points_len, scalars, scalars_len, n, res, res_len);
return intrinsics::get().call<intrinsics::bls_g2_weighted_sum>(points, points_len, scalars, scalars_len, n, res, res_len);
}
int32_t bls_pairing(const char* g1_points, uint32_t g1_points_len, const char* g2_points, uint32_t g2_points_len, uint32_t n, char* res, uint32_t res_len)
{
return intrinsics::get().exec<intrinsics::bls_pairing>(g1_points, g1_points_len, g1_points, g1_points_len, n, res, res_len);
return intrinsics::get().call<intrinsics::bls_pairing>(g1_points, g1_points_len, g1_points, g1_points_len, n, res, res_len);
}
int32_t bls_g1_map(const char* e, uint32_t e_len, char* res, uint32_t res_len)
{
return intrinsics::get().exec<intrinsics::bls_g1_map>(e, e_len, res, res_len);
return intrinsics::get().call<intrinsics::bls_g1_map>(e, e_len, res, res_len);
}
int32_t bls_g2_map(const char* e, uint32_t e_len, char* res, uint32_t res_len)
{
return intrinsics::get().exec<intrinsics::bls_g2_map>(e, e_len, res, res_len);
return intrinsics::get().call<intrinsics::bls_g2_map>(e, e_len, res, res_len);
}
int32_t bls_fp_mod(const char* s, uint32_t s_len, char* res, uint32_t res_len)
{
return intrinsics::get().exec<intrinsics::bls_fp_mod>(s, s_len, res, res_len);
return intrinsics::get().call<intrinsics::bls_fp_mod>(s, s_len, res, res_len);
}
int32_t bls_fp_mul(const char* op1, uint32_t op1_len, const char* op2, uint32_t op2_len, char* res, uint32_t res_len)
{
return intrinsics::get().exec<intrinsics::bls_fp_mul>(op1, op1_len, op2, op2_len, res, res_len);
return intrinsics::get().call<intrinsics::bls_fp_mul>(op1, op1_len, op2, op2_len, res, res_len);
}
int32_t bls_fp_exp(const char* base, uint32_t base_len, const char* exp, uint32_t exp_len, char* res, uint32_t res_len)
{
return intrinsics::get().exec<intrinsics::bls_fp_exp>(base, base_len, exp, exp_len, res, res_len);
return intrinsics::get().call<intrinsics::bls_fp_exp>(base, base_len, exp, exp_len, res, res_len);
}
+1 -1
View File
@@ -24,7 +24,7 @@ namespace eosio { namespace native {
};
template <intrinsic_name IN, typename... Args>
auto exec(Args... args) -> decltype(std::get<IN>(intrinsics::get().funcs)(args...)) {
auto call(Args... args) -> decltype(std::get<IN>(intrinsics::get().funcs)(args...)) {
return std::get<IN>(intrinsics::get().funcs)(args...);
}
@@ -7,13 +7,13 @@
#include <eosio/crypto_bls_ext.h>
#include <eosio/db.h>
#include <eosio/instant_finality.h>
#include <eosio/call.h>
#include <eosio/permission.h>
#include <eosio/print.h>
#include <eosio/privileged.h>
#include <eosio/system.h>
#include <eosio/transaction.h>
#include <eosio/types.h>
#include <eosio/security_group.h>
#include <type_traits>
#include <functional>
@@ -45,6 +45,7 @@ namespace eosio { namespace native {
}
#define INTRINSICS(intrinsic_macro) \
intrinsic_macro(get_account_ram_usage) \
intrinsic_macro(get_resource_limits) \
intrinsic_macro(set_resource_limits) \
intrinsic_macro(set_proposed_producers) \
@@ -118,6 +119,7 @@ intrinsic_macro(db_upperbound_i64) \
intrinsic_macro(db_end_i64) \
intrinsic_macro(assert_recover_key) \
intrinsic_macro(recover_key) \
intrinsic_macro(assert_recover_key_account) \
intrinsic_macro(assert_sha256) \
intrinsic_macro(assert_sha1) \
intrinsic_macro(assert_sha512) \
@@ -164,6 +166,10 @@ intrinsic_macro(cancel_deferred) \
intrinsic_macro(get_context_free_data) \
intrinsic_macro(get_sender) \
intrinsic_macro(set_action_return_value) \
intrinsic_macro(add_security_group_participants) \
intrinsic_macro(remove_security_group_participants) \
intrinsic_macro(in_active_security_group) \
intrinsic_macro(get_active_security_group) \
intrinsic_macro(blake2_f) \
intrinsic_macro(sha3) \
intrinsic_macro(k1_recover) \
@@ -181,11 +187,7 @@ intrinsic_macro(bls_g2_map) \
intrinsic_macro(bls_fp_mod) \
intrinsic_macro(bls_fp_mul) \
intrinsic_macro(bls_fp_exp) \
intrinsic_macro(set_finalizers) \
intrinsic_macro(call) \
intrinsic_macro(get_call_return_value) \
intrinsic_macro(get_call_data) \
intrinsic_macro(set_call_return_value)
intrinsic_macro(set_finalizers)
#define CREATE_ENUM(name) \
name,
+1 -1
View File
@@ -32,7 +32,7 @@ if (spring_FOUND)
CDTIntegrationTests
SOURCE_DIR "${CMAKE_SOURCE_DIR}/tests/integration"
BINARY_DIR "${CMAKE_BINARY_DIR}/tests/integration"
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${TEST_BUILD_TYPE} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_FRAMEWORK_PATH=${TEST_FRAMEWORK_PATH} -DCMAKE_MODULE_PATH=${TEST_MODULE_PATH} -Dspring_DIR=${spring_DIR} -Deosio_DIR=${eosio_DIR} -DLLVM_DIR=${LLVM_DIR} -DBOOST_ROOT=${BOOST_ROOT}
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${TEST_BUILD_TYPE} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_FRAMEWORK_PATH=${TEST_FRAMEWORK_PATH} -DCMAKE_MODULE_PATH=${TEST_MODULE_PATH} -Deosio_DIR=${eosio_DIR} -DLLVM_DIR=${LLVM_DIR} -DBOOST_ROOT=${BOOST_ROOT}
UPDATE_COMMAND ""
PATCH_COMMAND ""
TEST_COMMAND ""
-97
View File
@@ -1,97 +0,0 @@
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <fc/variant_object.hpp>
#include <contracts.hpp>
using namespace eosio;
using namespace eosio::testing;
using namespace eosio::chain;
using namespace eosio::testing;
using namespace fc;
using mvo = fc::mutable_variant_object;
BOOST_AUTO_TEST_SUITE(array_tests)
BOOST_FIXTURE_TEST_CASE( std_array_param, tester ) try {
/* ----------- testpa action tests --------------------------------------------------
[[eosio::action]]
void testpa(std::array<int,4> input){
std::array<int,4> arr = input;
for(int i = 0; i < 4; ++i){
eosio::cout << arr[i] << " ";
}
eosio::cout << "\n";
}
-------------------------------------------------------------------------------------- */
create_accounts( { "test"_n } );
produce_block();
set_code( "test"_n, contracts::array_tests_wasm() );
set_abi( "test"_n, contracts::array_tests_abi().data() );
produce_blocks();
auto trace = push_action("test"_n, "testpa"_n, "test"_n, mvo()("input", {1,2,3,4}));
auto& con = trace->action_traces[0].console;
BOOST_REQUIRE_EQUAL(con, std::string("1 2 3 4 \n"));
produce_block();
// size should be correct
// ----------------------
BOOST_CHECK_EXCEPTION( push_action("test"_n, "testpa"_n, "test"_n, mvo()("input", {1,2,3})),
pack_exception,
fc_exception_message_starts_with("Incorrect number of values provided (4) for fixed-size (3) array type"));
produce_block();
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE( std_array_return_value, tester ) try {
/* ----------- testre action tests --------------------------------------------------
[[eosio::action]]
std::array<int,4> testre(std::array<int,4> input){
std::array<int,4> arr = input;
for(auto & v : arr) v += 1;
return arr;
}
-------------------------------------------------------------------------------------- */
create_accounts( { "test"_n } );
produce_block();
set_code( "test"_n, contracts::array_tests_wasm() );
set_abi( "test"_n, contracts::array_tests_abi().data() );
produce_blocks();
auto trace = push_action("test"_n, "testre"_n, "test"_n, mvo()("input", {1, 2, 3, 4}));
auto& rv = trace->action_traces[0].return_value;
auto actual = fc::raw::unpack<std::array<int, 4>>(rv);
auto expected = std::array<int, 4>{2, 3, 4, 5};
BOOST_REQUIRE(actual == expected);
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE( std_vector_return_value, tester ) try {
/* ----------- testrev action tests --------------------------------------------------
[[eosio::action]]
std::vector<int> testrev(std::vector<int> input){
std::vector<int> vec = input;
for(auto & v : vec) v += 1;
return vec;
}
-------------------------------------------------------------------------------------- */
create_accounts( { "test"_n } );
produce_block();
set_code( "test"_n, contracts::array_tests_wasm() );
set_abi( "test"_n, contracts::array_tests_abi().data() );
produce_blocks();
auto trace = push_action("test"_n, "testrev"_n, "test"_n, mvo()("input", {1, 2, 3, 4}));
auto& rv = trace->action_traces[0].return_value;
auto actual = fc::raw::unpack<std::vector<int>>(rv);
auto expected = std::vector<int>{2, 3, 4, 5};
BOOST_REQUIRE(actual == expected);
} FC_LOG_AND_RETHROW()
BOOST_AUTO_TEST_SUITE_END()
-47
View File
@@ -1,47 +0,0 @@
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <fc/variant_object.hpp>
#include <contracts.hpp>
#include "test_utils.hpp"
using namespace eosio;
using namespace eosio::testing;
using namespace eosio::chain;
using namespace eosio::testing;
using namespace fc;
using mvo = fc::mutable_variant_object;
BOOST_AUTO_TEST_SUITE(bitset_tests)
BOOST_FIXTURE_TEST_CASE( bitset_test, tester ) try {
create_accounts( { "test"_n } );
produce_block();
set_code( "test"_n, contracts::simple_wasm() );
set_abi( "test"_n, contracts::simple_abi().data() );
produce_blocks();
auto trx_trace = push_action("test"_n, "testbs"_n, "test"_n, mvo()("b", "0010"));
auto& act_trace = trx_trace->action_traces[0];
BOOST_REQUIRE_EQUAL(fc::raw::unpack<fc::bitset>(act_trace.return_value), fc::bitset{"1101"});
{
// because contract `simple_tests.cpp` uses the `bitset` type, the abi version should be 1.3 or greater
auto abi_version = extract_version_from_json_abi(contracts::simple_abi());
BOOST_REQUIRE(abi_version.is_valid());
BOOST_REQUIRE_LT(version_t(1,2), abi_version);
}
{
// check that abi version of minimal contract is still 1.2.
auto abi_version = extract_version_from_json_abi(contracts::malloc_tests_abi());
BOOST_REQUIRE(abi_version.is_valid());
BOOST_REQUIRE_EQUAL(version_t(1,2), abi_version);
}
} FC_LOG_AND_RETHROW()
BOOST_AUTO_TEST_SUITE_END()
-275
View File
@@ -1,275 +0,0 @@
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <fc/variant_object.hpp>
#include <contracts.hpp>
using namespace eosio;
using namespace eosio::testing;
using namespace fc;
using mvo = fc::mutable_variant_object;
struct acct_and_code {
account_name acct;
std::vector<uint8_t> wasm;
char* abi = nullptr;
};
// The first account in the accounts vector is the action initiating the
// first sync call
struct call_tester: tester {
call_tester(const std::vector<acct_and_code>& accounts) {
for (auto i = 0u; i < accounts.size(); ++i) {
create_account(accounts[i].acct);
set_code(accounts[i].acct, accounts[i].wasm);
set_abi(accounts[i].acct, accounts[i].abi);
}
produce_block();
}
};
BOOST_AUTO_TEST_SUITE(sync_call_tests)
// Verify a sync call returns value correctly
BOOST_AUTO_TEST_CASE(return_value_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::callee_wasm(), contracts::callee_abi().data()}
});
// Using host function directly
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "hstretvaltst"_n, "caller"_n, {}));
// Using call_wrapper
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "wrpretvaltst"_n, "caller"_n, {}));
} FC_LOG_AND_RETHROW() }
// Verify one parameter passing works correctly
BOOST_AUTO_TEST_CASE(param_basic_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::callee_wasm(), contracts::callee_abi().data()}
});
// Using host function directly
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "hstoneprmtst"_n, "caller"_n, {}));
// Using call_wrapper
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "wrponeprmtst"_n, "caller"_n, {}));
} FC_LOG_AND_RETHROW() }
// Verify multiple parameters passing works correctly
BOOST_AUTO_TEST_CASE(multiple_params_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::callee_wasm(), contracts::callee_abi().data()}
});
// Using host function directly
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "hstmulprmtst"_n, "caller"_n, {}));
// Using call_wrapper
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "wrpmulprmtst"_n, "caller"_n, {}));
} FC_LOG_AND_RETHROW() }
// Verify passing a struct parameter works correctly
BOOST_AUTO_TEST_CASE(struct_param_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::callee_wasm(), contracts::callee_abi().data()}
});
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "structtest"_n, "caller"_n, {}));
} FC_LOG_AND_RETHROW() }
// Verify passing a mix of structs and integer works correctly
BOOST_AUTO_TEST_CASE(mix_struct_int_params_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::callee_wasm(), contracts::callee_abi().data()}
});
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "structinttst"_n, "caller"_n, {}));
} FC_LOG_AND_RETHROW() }
// Verify a sync call to a void function works properly.
BOOST_AUTO_TEST_CASE(void_func_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::callee_wasm(), contracts::callee_abi().data()}
});
auto check = [] (const transaction_trace_ptr& trx_trace) {
auto& atrace = trx_trace->action_traces;
auto& call_traces = atrace[0].call_traces;
BOOST_REQUIRE_EQUAL(call_traces.size(), 1u);
// Verify the print from the void function is correct.
// The test contract checks the return value size is 0.
auto& call_trace = call_traces[0];
BOOST_REQUIRE_EQUAL(call_trace.call_ordinal, 1u);
BOOST_REQUIRE_EQUAL(call_trace.sender_ordinal, 0u);
BOOST_REQUIRE_EQUAL(call_trace.console, "I am a void function");
};
// Using host function directly
auto trx_trace = t.push_action("caller"_n, "hstvodfuntst"_n, "caller"_n, {});
check(trx_trace);
// Using call_wrapper
trx_trace = t.push_action("caller"_n, "wrpvodfuntst"_n, "caller"_n, {});
check(trx_trace);
} FC_LOG_AND_RETHROW() }
// Verify a function tagged as both `action` and `call` works
BOOST_AUTO_TEST_CASE(mixed_action_call_tags_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::callee_wasm(), contracts::callee_abi().data()}
});
// `sum` in `callee` contract is tagged as `action` and `call`
// Make sure we can make a sync call to `sum` (`mulparamtest` in `caller` does
// a sync call to `sum`)
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "hstmulprmtst"_n, "caller"_n, {}));
// Make sure we can push an action using `sum`.
BOOST_REQUIRE_NO_THROW(t.push_action("callee"_n, "sum"_n, "callee"_n,
mvo()
("a", 1)
("b", 2)
("c", 3)));
} FC_LOG_AND_RETHROW() }
// Verify the receiver contract with only one sync call function works
// (for testing the sync_call entry point dispatcher)
BOOST_AUTO_TEST_CASE(single_function_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::single_func_wasm(), contracts::single_func_abi().data()}
});
// The single_func_wasm contains only one function and the caller contract
// hooks up with it
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "hstretvaltst"_n, "caller"_n, {}));
} FC_LOG_AND_RETHROW() }
// Verify support_mode for void and non-void sync calls if calls are a failure
BOOST_AUTO_TEST_CASE(sync_call_support_mode_failure_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::not_supported_wasm(), contracts::not_supported_abi().data()}
});
// voidfncnoop uses support_mode::no_op
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "voidfncnoop"_n, "caller"_n, {}));
// voidfncabort uses default support_mode::abort
BOOST_CHECK_EXCEPTION(t.push_action("caller"_n, "voidfncabort"_n, "caller"_n, {}),
eosio_assert_message_exception,
fc_exception_message_contains("receiver does not support sync call but support_mode is set to abort"));
// intfuncnoop uses support_mode::no_op
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "intfuncnoop"_n, "caller"_n, {}));
// intfuncabort uses default support_mode::abort
BOOST_CHECK_EXCEPTION(t.push_action("caller"_n, "intfuncabort"_n, "caller"_n, {}),
eosio_assert_message_exception,
fc_exception_message_contains("receiver does not support sync call but support_mode is set to abort"));
} FC_LOG_AND_RETHROW() }
// Verify support_mode for void and non-void sync calls if call is successful
BOOST_AUTO_TEST_CASE(sync_call_support_mode_success_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::callee_wasm(), contracts::callee_abi().data()}
});
// voidnoopsucc uses support_mode::no_op
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "voidnoopsucc"_n, "caller"_n, {}));
// sumnoopsucc uses support_mode::no_op
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "sumnoopsucc"_n, "caller"_n, {}));
} FC_LOG_AND_RETHROW() }
// Verify header validation
BOOST_AUTO_TEST_CASE(unknown_function_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::callee_wasm(), contracts::callee_abi().data()}
});
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "hdrvaltest"_n, "caller"_n, {}));
} FC_LOG_AND_RETHROW() }
// Verify adding/reading entries to/from a table, and read-only enforcement work
BOOST_AUTO_TEST_CASE(addr_book_tests) { try {
call_tester t({
{"caller"_n, contracts::addr_book_caller_wasm(), contracts::addr_book_caller_abi().data()},
{"callee"_n, contracts::addr_book_callee_wasm(), contracts::addr_book_callee_abi().data()}
});
// Try to add an entry using a read-only sync call
BOOST_CHECK_EXCEPTION(t.push_action("caller"_n, "upsertrdonly"_n, "caller"_n, mvo()
("user", "alice")
("first_name", "alice")
("street", "123 Main St.")),
unaccessible_api,
fc_exception_message_contains("this API is not allowed in read only action/call"));
// Add an entry using a read-write sync call
t.push_action("caller"_n, "upsert"_n, "caller"_n, mvo()
("user", "alice")
("first_name", "alice")
("street", "123 Main St."));
// Read the inserted entry. "get"_n action will check the return value from the sync call
BOOST_REQUIRE_NO_THROW(t.push_action("caller"_n, "get"_n, "caller"_n, mvo() ("user", "alice")));
} FC_LOG_AND_RETHROW() }
// For a function tagged as both `action` and `call`, verify is_sync_call()
// returns true if tagged as `call` and false if tagged as `action`.
BOOST_AUTO_TEST_CASE(is_sync_call_test) { try {
call_tester t({
{"caller"_n, contracts::caller_wasm(), contracts::caller_abi().data()},
{"callee"_n, contracts::callee_wasm(), contracts::callee_abi().data()}
});
// issynccall() is tagged as both `action` and `call`, and returns
// is_sync_call(). makesynccall() calls issynccall() as a sync call
// and returns its result. So the current action return value must be
// true.
auto trx_trace = t.push_action("caller"_n, "makesynccall"_n, "caller"_n, {});
auto& action_trace = trx_trace->action_traces[0];
bool return_value = fc::raw::unpack<bool>(action_trace.return_value);
BOOST_REQUIRE(return_value == true);
// Call issynccall() directly as an action. Since issynccall()
// returns is_sync_call(), the current action return value must be false.
trx_trace = t.push_action("callee"_n, "issynccall"_n, "callee"_n, {});
auto& action_trace1 = trx_trace->action_traces[0];
return_value = fc::raw::unpack<bool>(action_trace1.return_value);
BOOST_REQUIRE(return_value == false);
} FC_LOG_AND_RETHROW() }
// Verify customized sync call entry function, without sync call tag
BOOST_AUTO_TEST_CASE(customized_call_entry_func_test1) { try {
call_tester t({{"receiver"_n, contracts::cust_entry_wasm(), contracts::cust_entry_abi().data()}});
BOOST_REQUIRE_NO_THROW(t.push_action("receiver"_n, "cusentrytst1"_n, "receiver"_n, {}));
} FC_LOG_AND_RETHROW() }
// Verify customized sync call entry function, with sync call tag
BOOST_AUTO_TEST_CASE(customized_call_entry_func_test2) { try {
call_tester t({{"receiver"_n, contracts::cust_entry_wasm(), contracts::cust_entry_abi().data()}});
BOOST_REQUIRE_NO_THROW(t.push_action("receiver"_n, "cusentrytst2"_n, "receiver"_n, {}));
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_SUITE_END()
-17
View File
@@ -3,8 +3,6 @@
namespace eosio::testing {
struct contracts {
static std::vector<uint8_t> array_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/array_tests.wasm"); }
static std::vector<char> array_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/array_tests.abi"); }
static std::vector<uint8_t> malloc_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/malloc_tests.wasm"); }
static std::vector<char> malloc_tests_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/malloc_tests.abi"); }
static std::vector<uint8_t> old_malloc_tests_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/old_malloc_tests.wasm"); }
@@ -41,20 +39,5 @@ namespace eosio::testing {
static std::vector<uint8_t> test_multi_index_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/test_multi_index.wasm"); }
static std::vector<char> test_multi_index_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/test_multi_index.abi"); }
static std::vector<uint8_t> caller_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_caller.wasm"); }
static std::vector<char> caller_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_caller.abi"); }
static std::vector<uint8_t> callee_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_callee.wasm"); }
static std::vector<char> callee_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_callee.abi"); }
static std::vector<uint8_t> not_supported_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_not_supported.wasm"); }
static std::vector<char> not_supported_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_not_supported.abi"); }
static std::vector<uint8_t> single_func_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_single_func.wasm"); }
static std::vector<char> single_func_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_single_func.abi"); }
static std::vector<uint8_t> addr_book_callee_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_addr_book_callee.wasm"); }
static std::vector<char> addr_book_callee_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_addr_book_callee.abi"); }
static std::vector<uint8_t> addr_book_caller_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_addr_book_caller.wasm"); }
static std::vector<char> addr_book_caller_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_addr_book_caller.abi"); }
static std::vector<uint8_t> cust_entry_wasm() { return read_wasm("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_cust_entry.wasm"); }
static std::vector<char> cust_entry_abi() { return read_abi("${CMAKE_BINARY_DIR}/../unit/test_contracts/sync_call_cust_entry.abi"); }
};
} //ns eosio::testing
-19
View File
@@ -1,19 +0,0 @@
#pragma once
#include <cstdint>
#include <string>
#include <cstring>
#include <string_view>
#include <vector>
#include <optional>
#include <charconv>
inline eosio::chain::version_t extract_version_from_json_abi(std::vector<char> abi) {
std::string_view sv(abi.data(), abi.size());
constexpr const char* pattern = R"("version": "eosio::abi/)";
if (auto pos = sv.find(pattern); pos != std::string_view::npos) {
return eosio::chain::version_t{sv.substr(pos + strlen(pattern))};
}
return {};
}
@@ -1,7 +1,6 @@
{
"tests" : [
{
"compile_flags": [],
"expected" : {
"abi-file" : "action_results_test.abi"
}
@@ -1,7 +1,6 @@
{
"tests": [
{
"compile_flags": [],
"expected": {
"abi-file": "aliased_type_variant_template_arg.abi"
}
@@ -1,7 +1,6 @@
{
"tests" : [
{
"compile_flags": [],
"expected" : {
"abi-file" : "nested_container.abi"
}
@@ -1,10 +1,10 @@
{
"tests" : [
{
"compile_flags": [],
"expected" : {
"abi-file" : "singleton_contract.abi"
}
}
]
}
@@ -1,7 +1,6 @@
{
"tests": [
{
"compile_flags": [],
"expected": {
"abi-file": "struct_base_typedefd.abi"
}
@@ -1,76 +0,0 @@
{
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT ",
"version": "eosio::abi/1.3",
"types": [],
"structs": [
{
"name": "noparam",
"base": "",
"fields": []
},
{
"name": "sum",
"base": "",
"fields": [
{
"name": "a",
"type": "uint32"
},
{
"name": "b",
"type": "uint32"
},
{
"name": "c",
"type": "uint32"
}
]
},
{
"name": "voidfunc",
"base": "",
"fields": []
},
{
"name": "withparam",
"base": "",
"fields": [
{
"name": "in",
"type": "uint32"
}
]
}
],
"actions": [],
"tables": [],
"ricardian_clauses": [],
"variants": [],
"action_results": [],
"calls": [
{
"name": "noparam",
"type": "noparam",
"id": 229476383600947,
"result_type": "uint32"
},
{
"name": "sum",
"type": "sum",
"id": 193506202,
"result_type": "uint32"
},
{
"name": "voidfunc",
"type": "voidfunc",
"id": 7573061335575747,
"result_type": ""
},
{
"name": "withparam",
"type": "withparam",
"id": 249912189145794130,
"result_type": "uint32"
}
]
}
@@ -1,27 +0,0 @@
#include <eosio/call.hpp>
#include <eosio/eosio.hpp>
class [[eosio::contract]] sync_call_test : public eosio::contract {
public:
using contract::contract;
[[eosio::call]]
uint32_t noparam() {
return 10;
}
[[eosio::call]]
uint32_t withparam(uint32_t in) {
return in;
}
[[eosio::call]]
void voidfunc() {
int i = 10;
}
[[eosio::call]]
uint32_t sum(uint32_t a, uint32_t b, uint32_t c) {
return a + b + c;
}
};
@@ -1,9 +0,0 @@
{
"tests" : [
{
"expected" : {
"abi-file" : "sync_call_test.abi"
}
}
]
}
@@ -1,7 +1,6 @@
{
"tests" : [
{
"compile_flags": [],
"expected" : {
"abi-file" : "tagged_number_test.abi"
}
@@ -1,7 +1,6 @@
{
"tests" : [
{
"compile_flags": [],
"expected" : {
"abi-file" : "using_std_array.abi"
}
@@ -1,6 +1,6 @@
#include <eosio/eosio.hpp>
class [[eosio::contract]] separate_cpp_hpp : public eosio::contract {
class [[eosio::contract]] separate_cpp_hpp : eosio::contract {
public:
using contract::contract;
@@ -1,31 +0,0 @@
#include <eosio/call.hpp>
#include <eosio/eosio.hpp>
// Test the validation of the number of arguments passed in call_wrapper.
// Expected error:
// .../build/bin/../include/eosiolib/contracts/eosio/detail.hpp:72:7: error: static_assert failed due to requirement 'sizeof...(Ts) == std::tuple_size<std::__1::tuple<unsigned int, unsigned int, unsigned int>>::value'
// static_assert(sizeof...(Ts) == std::tuple_size<deduced<Function>>::value);
class [[eosio::contract]] sync_call_invalid_arg_nums : public eosio::contract{
public:
using contract::contract;
[[eosio::call]]
uint32_t sum(uint32_t a, uint32_t b, uint32_t c) {
return a + b + c;
}
using sum_func = eosio::call_wrapper<"sum"_i, &sync_call_invalid_arg_nums::sum>;
// Fewer number of arguments
[[eosio::action]]
void fewerargs() {
sum_func{"callee"_n}(1, 2);
}
// More number of arguments
[[eosio::action]]
void moreargs() {
sum_func{"callee"_n}(1, 2, 3, 4);
}
};
@@ -1,11 +0,0 @@
{
"tests" : [
{
"compile_flags": [],
"expected" : {
"exit-code": 255,
"stderr": "error: static_assert failed due to requirement 'sizeof"
}
}
]
}
@@ -1,28 +0,0 @@
#include <eosio/call.hpp>
#include <eosio/eosio.hpp>
// Test the validation of the types of arguments passed in call_wrapper.
// Expected error:
// build/bin/../include/eosiolib/contracts/eosio/detail.hpp:60:7: error: static_assert failed due to requirement 'detail::is_same<sync_call_invalid_arg_nums::empty &, unsigned int>::value'
// static_assert(detail::is_same<typename convert<T>::type, typename convert<typename std::tuple_element<I, deduced<Function>>::type>::type>::value);
class [[eosio::contract]] sync_call_invalid_arg_nums : public eosio::contract{
public:
using contract::contract;
[[eosio::call]]
uint32_t sum(uint32_t a, uint32_t b, uint32_t c) {
return a + b + c;
}
using sum_func = eosio::call_wrapper<"sum"_i, &sync_call_invalid_arg_nums::sum>;
struct empty {
};
// Invalid first argument
[[eosio::action]]
void wrongrettype() {
empty bad;
sum_func{"callee"_n}(bad, 2, 3);
}
};
@@ -1,11 +0,0 @@
{
"tests" : [
{
"compile_flags": [],
"expected" : {
"exit-code": 255,
"stderr": "error: static_assert failed due to requirement 'detail::is_same"
}
}
]
}
-7
View File
@@ -351,13 +351,6 @@ EOSIO_TEST_BEGIN(datastream_stream_test)
ds.seekp(0);
ds >> o;
CHECK_EQUAL( co, o )
// test upacking an empty std::optional to a non-empty works
static const optional<char> co1{}; // empty
ds.seekp(0);
ds << co1;
ds.seekp(0);
ds >> o; // o had value
CHECK_EQUAL( co1, o )
// ---------
// std::pair
+1 -8
View File
@@ -13,15 +13,8 @@ add_contract(get_code_hash_tests get_code_hash_write get_code_hash_write.cpp)
add_contract(get_code_hash_tests get_code_hash_read get_code_hash_read.cpp)
add_contract(name_pk_tests name_pk_tests name_pk_tests.cpp)
add_contract(test_multi_index test_multi_index multi_index_tests.cpp)
add_contract(sync_call_caller sync_call_caller sync_call_caller.cpp)
add_contract(sync_call_callee sync_call_callee sync_call_callee.cpp)
add_contract(sync_call_not_supported sync_call_not_supported sync_call_not_supported.cpp)
add_contract(sync_call_single_func sync_call_single_func sync_call_single_func.cpp)
add_contract(sync_call_addr_book_callee sync_call_addr_book_callee sync_call_addr_book_callee.cpp)
add_contract(sync_call_addr_book_caller sync_call_addr_book_caller sync_call_addr_book_caller.cpp)
add_contract(sync_call_cust_entry sync_call_cust_entry sync_call_cust_entry.cpp)
add_contract(capi_tests capi_tests capi/capi.c capi/action.c capi/chain.c capi/crypto.c capi/db.c capi/permission.c
capi/print.c capi/privileged.c capi/system.c capi/transaction.c capi/call.c)
capi/print.c capi/privileged.c capi/system.c capi/transaction.c)
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/simple_wrong.abi ${CMAKE_CURRENT_BINARY_DIR}/simple_wrong.abi COPYONLY )
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/capi/capi_tests.abi ${CMAKE_CURRENT_BINARY_DIR}/capi_tests.abi COPYONLY )
+3 -11
View File
@@ -65,7 +65,8 @@ class [[eosio::contract]] array_tests : public contract {
}
}
// test parameter using std::array
// test parameter using std::array
// not supported so far
[[eosio::action]]
void testpa(std::array<int,4> input){
std::array<int,4> arr = input;
@@ -75,7 +76,7 @@ class [[eosio::contract]] array_tests : public contract {
eosio::cout << "\n";
}
// test parameter and return value using std::array
// test return using std::array, not supported so far
[[eosio::action]]
// cleos -v push action eosio testre '[[1,2,3,4]]' -p eosio@active
std::array<int,4> testre(std::array<int,4> input){
@@ -84,15 +85,6 @@ class [[eosio::contract]] array_tests : public contract {
return arr;
}
// test return value using std::array
[[eosio::action]]
// cleos -v push action eosio testre2 '[[1,2,3,4]]' -p eosio@active
std::array<int,4> testre2(std::vector<int> input){
std::array<int,4> arr;
for(size_t i=0; i<4; ++i) arr[i] = input[i+1];
return arr;
}
// test return using std::vector
[[eosio::action]]
// cleos -v push action eosio testrev '[[1,2,3,4]]' -p eosio@active
-9
View File
@@ -1,9 +0,0 @@
#include <eosio/call.h>
#include <stddef.h>
void test_call( void ) {
call(0, 0, NULL, 0);
get_call_return_value(NULL, 0);
get_call_data(NULL, 0);
set_call_return_value(NULL, 0);
}
-2
View File
@@ -9,7 +9,6 @@ void test_print( void );
void test_privileged( void );
void test_system( void );
void test_transaction( void );
void test_call( void );
void apply( uint64_t a, uint64_t b, uint64_t c ) {
if(a != 0xed234054a367196eull) return; // random value that should not be used
@@ -22,5 +21,4 @@ void apply( uint64_t a, uint64_t b, uint64_t c ) {
test_privileged();
test_system();
test_transaction();
test_call();
}
+2 -14
View File
@@ -1,6 +1,5 @@
#include <eosio/eosio.hpp>
#include <eosio/deferred_transaction.hpp>
#include <eosio/bitset.hpp>
#include <eosio/transaction.hpp>
#include "transfer.hpp"
@@ -52,7 +51,7 @@ class [[eosio::contract]] simple_tests : public contract {
[[eosio::action]]
void testd(name nm) {
deferred_transaction t;
transaction t;
action act;
act.account = "other"_n;
act.name = "testc"_n;
@@ -62,17 +61,6 @@ class [[eosio::contract]] simple_tests : public contract {
t.send(nm.value, get_self());
}
[[eosio::action]]
eosio::bitset testbs(eosio::bitset b) {
for (size_t i=0; i<b.size(); ++i) {
if (b[i])
b.clear(i);
else
b.set(i);
}
return b;
}
[[eosio::on_notify("eosio.token::transfer")]]
void on_transfer(name from, name to, asset quant, std::string memo) {
check(get_first_receiver() == "eosio.token"_n, "should be eosio.token");
@@ -1,37 +0,0 @@
#include "sync_call_addr_book_callee.hpp"
#include <eosio/eosio.hpp>
using namespace eosio;
void sync_call_addr_book_callee::upsert(name user, std::string first_name, std::string street) {
// Intentionally leave out require_auth(user) to test upsert cannot be called as a read_only
// sync call
address_index addresses(get_first_receiver(), get_first_receiver().value);
auto iterator = addresses.find(user.value);
if( iterator == addresses.end() )
{
addresses.emplace(user, [&]( auto& row ) {
row.key = user;
row.first_name = first_name;
row.street = street;
});
}
else {
addresses.modify(iterator, user, [&]( auto& row ) {
row.key = user;
row.first_name = first_name;
row.street = street;
});
}
}
person_info sync_call_addr_book_callee::get(name user) {
address_index addresses(get_first_receiver(), get_first_receiver().value);
auto iterator = addresses.find(user.value);
check(iterator != addresses.end(), "Record does not exist");
return person_info{ .first_name = iterator->first_name,
.street = iterator->street };
}
@@ -1,33 +0,0 @@
#include <eosio/call.hpp>
#include <eosio/eosio.hpp>
struct person_info {
std::string first_name;
std::string street;
};
class [[eosio::contract]] sync_call_addr_book_callee : public eosio::contract {
public:
sync_call_addr_book_callee(eosio::name receiver, eosio::name code, eosio::datastream<const char*> ds): contract(receiver, code, ds) {}
[[eosio::call]]
void upsert(eosio::name user, std::string first_name, std::string street);
[[eosio::call]]
person_info get(eosio::name user);
using upsert_read_only_func = eosio::call_wrapper<"upsert"_i, &sync_call_addr_book_callee::upsert, eosio::access_mode::read_only>;
using upsert_func = eosio::call_wrapper<"upsert"_i, &sync_call_addr_book_callee::upsert>;
using get_func = eosio::call_wrapper<"get"_i, &sync_call_addr_book_callee::get>;
private:
struct [[eosio::table]] person {
eosio::name key;
std::string first_name;
std::string street;
uint64_t primary_key() const { return key.value; }
};
using address_index = eosio::multi_index<"people"_n, person>;
};
@@ -1,30 +0,0 @@
#include "sync_call_addr_book_callee.hpp"
#include <eosio/eosio.hpp>
#include <eosio/call.hpp>
class [[eosio::contract]] sync_call_addr_book_caller : public eosio::contract{
public:
using contract::contract;
// Insert an entry using read_only, which will fail
[[eosio::action]]
void upsertrdonly(eosio::name user, std::string first_name, std::string street) {
sync_call_addr_book_callee::upsert_read_only_func{"callee"_n}(user, first_name, street);
}
// Insert an entry
[[eosio::action]]
void upsert(eosio::name user, std::string first_name, std::string street) {
sync_call_addr_book_callee::upsert_func{"callee"_n}(user, first_name, street);
}
// Read an entry
[[eosio::action]]
person_info get(eosio::name user) {
auto user_info = sync_call_addr_book_callee::get_func{"callee"_n}(user);
eosio::check(user_info.first_name == "alice", "first name not alice");
eosio::check(user_info.street == "123 Main St.", "street not 123 Main St.");
return user_info;
}
};
@@ -1,36 +0,0 @@
#include "sync_call_callee.hpp"
#include <eosio/print.hpp>
[[eosio::call]]
uint32_t sync_call_callee::return_ten() {
return 10;
}
[[eosio::call]]
uint32_t sync_call_callee::echo_input(uint32_t in) {
return in;
}
[[eosio::call]]
void sync_call_callee::void_func() {
eosio::print("I am a void function");
}
[[eosio::action, eosio::call]]
uint32_t sync_call_callee::sum(uint32_t a, uint32_t b, uint32_t c) {
return a + b + c;
}
[[eosio::call]]
struct1_t sync_call_callee::pass_single_struct(struct1_t s) {
return s;
}
[[eosio::call]]
struct1_t sync_call_callee::pass_multi_structs(struct1_t s1, int32_t m, struct2_t s2) {
return { .a = s1.a * m + s2.c, .b = s1.b * m + s2.d };
}
bool sync_call_callee::issynccall() {
return is_sync_call();
}
@@ -1,55 +0,0 @@
#include <eosio/call.hpp>
#include <eosio/eosio.hpp>
struct struct1_t {
int64_t a;
uint64_t b;
};
struct struct2_t {
char a;
bool b;
int64_t c;
uint64_t d;
};
class [[eosio::contract]] sync_call_callee : public eosio::contract{
public:
using contract::contract;
[[eosio::call]]
uint32_t return_ten();
[[eosio::call]]
uint32_t echo_input(uint32_t in);
[[eosio::call]]
void void_func();
[[eosio::action, eosio::call]]
uint32_t sum(uint32_t a, uint32_t b, uint32_t c);
// pass in a struct and return it
[[eosio::call]]
struct1_t pass_single_struct(struct1_t s);
// pass in two structs and an integer, multiply each field in the struct by
// the integer, add last two fields of the second struct, and return the result
[[eosio::call]]
struct1_t pass_multi_structs(struct1_t s1, int32_t m, struct2_t s2);
// return is_sync_call()
[[eosio::action, eosio::call]]
bool issynccall();
using issynccall_func = eosio::call_wrapper<"issynccall"_i, &sync_call_callee::issynccall>;
using return_ten_func = eosio::call_wrapper<"return_ten"_i, &sync_call_callee::return_ten>;
using echo_input_func = eosio::call_wrapper<"echo_input"_i, &sync_call_callee::echo_input>;
using void_func_func = eosio::call_wrapper<"void_func"_i, &sync_call_callee::void_func>;
using sum_func = eosio::call_wrapper<"sum"_i, &sync_call_callee::sum>;
using pass_single_struct_func = eosio::call_wrapper<"pass_single_struct"_i, &sync_call_callee::pass_single_struct>;
using pass_multi_structs_func = eosio::call_wrapper<"pass_multi_structs"_i, &sync_call_callee::pass_multi_structs>;
using void_no_op_success_func = eosio::call_wrapper<"void_func"_i, &sync_call_callee::void_func, eosio::access_mode::read_write, eosio::support_mode::no_op>;
using sum_no_op_success_func = eosio::call_wrapper<"sum"_i, &sync_call_callee::sum, eosio::access_mode::read_write, eosio::support_mode::no_op>;
};
@@ -1,182 +0,0 @@
#include "sync_call_callee.hpp"
#include "sync_call_not_supported.hpp"
#include <eosio/eosio.hpp>
#include <eosio/call.hpp>
using namespace eosio;
class [[eosio::contract]] sync_call_caller : public eosio::contract{
public:
using contract::contract;
// Using host function directly
[[eosio::action]]
void hstretvaltst() {
call_data_header header{ .version = 0, .func_name = "return_ten"_i.id };
const std::vector<char> data{ eosio::pack(header) };
auto expected_size = eosio::call("callee"_n, 0, data.data(), data.size());
eosio::check(expected_size >= 0, "call did not return a positive value");
std::vector<char> return_value;
return_value.resize(expected_size);
auto actual_size = eosio::get_call_return_value(return_value.data(), return_value.size());
eosio::check(actual_size == expected_size, "actual_size not equal to expected_size");
eosio::check(eosio::unpack<uint32_t>(return_value) == 10u, "return value not 10"); // return_ten always returns 10
}
// Using call_wrapper
[[eosio::action]]
void wrpretvaltst() {
sync_call_callee::return_ten_func return_ten{ "callee"_n };
eosio::check(return_ten() == 10u, "return value not 10");
}
// Using host function directly, testing one parameter passing
[[eosio::action]]
void hstoneprmtst() {
// `echo_input(uint32_t p)` returns p
call_data_header header{ .version = 0, .func_name = "echo_input"_i.id };
const std::vector<char> data{ eosio::pack(std::make_tuple(header, 5)) };
auto expected_size = eosio::call("callee"_n, 0, data.data(), data.size());
eosio::check(expected_size >= 0, "call did not return a positive value");
std::vector<char> return_value;
return_value.resize(expected_size);
auto actual_size = eosio::get_call_return_value(return_value.data(), return_value.size());
eosio::check(actual_size == expected_size, "actual_size not equal to expected_size");
eosio::check(eosio::unpack<uint32_t>(return_value) == 5u, "return value not 5"); // echo_input returns back the same value of parameter
}
// Using call_wrapper, testing one parameter passing
[[eosio::action]]
void wrponeprmtst() {
sync_call_callee::echo_input_func echo_input{ "callee"_n };
eosio::check(echo_input(5) == 5u, "return value not 5");
}
// Using host function directly, testing multiple parameters passing
[[eosio::action]]
void hstmulprmtst() {
call_data_header header{ .version = 0, .func_name = "sum"_i.id };
const std::vector<char> data{ eosio::pack(std::make_tuple(header, 10, 20, 30)) };
auto expected_size = eosio::call("callee"_n, 0, data.data(), data.size());
eosio::check(expected_size >= 0, "call did not return a positive value");
std::vector<char> return_value;
return_value.resize(expected_size);
auto actual_size = eosio::get_call_return_value(return_value.data(), return_value.size());
eosio::check(actual_size == expected_size, "actual_size not equal to expected_size");
eosio::check(eosio::unpack<uint32_t>(return_value) == 60u, "sum of 10, 20, and 30 not 60"); // sum returns the sum of the 3 arguments
}
// Using call_wrapper, testing multiple parameters passing
[[eosio::action]]
void wrpmulprmtst() {
sync_call_callee::sum_func sum{ "callee"_n };
eosio::check(sum(10, 20, 30) == 60u, "sum of 10, 20, and 30 not 60");
}
// Verify single struct parameter passing
[[eosio::action]]
void structtest() {
sync_call_callee::pass_single_struct_func func{ "callee"_n };
struct1_t input = { 10, 20 };
auto output = func(input); // pass_single_struct_func returns the input as is
eosio::check(output.a == input.a, "field a in output is not equal to a in input");
eosio::check(output.b == input.b, "field b in output is not equal to b in input");
}
// Verify mix of struct and integer parameters passing
[[eosio::action]]
void structinttst() {
sync_call_callee::pass_multi_structs_func func{ "callee"_n };
struct1_t input1 = { 10, 20 };
struct2_t input2 = { 'a', true, 50, 100 };
int32_t m = 2;
// pass_multi_structs_func multiply each field of input1 by m,
// add last two fields of input2, and return a struct1_t
auto output = func(input1, m, input2);
eosio::check(output.a == m * input1.a + input2.c, "field a of output is not correct");
eosio::check(output.b == m * input1.b + input2.d, "field b of output is not correct");
}
[[eosio::action]]
void hstvodfuntst() {
call_data_header header{ .version = 0, .func_name = "void_func"_i.id };
const std::vector<char> data{ eosio::pack(header) };
auto expected_size = eosio::call("callee"_n, 0, data.data(), data.size());
eosio::check(expected_size == 0, "call did not return 0"); // void function. return value size should be 0
}
[[eosio::action]]
void wrpvodfuntst() {
sync_call_callee::void_func_func void_func{ "callee"_n };
void_func();
}
// Verify void call. void_func uses default support_mode::abort
[[eosio::action]]
void voidfncabort() {
sync_call_not_supported::void_func void_func_abort{ "callee"_n };
void_func_abort(); // Will throw. Tester will verify that.
}
// void_func uses support_mode::no_op
[[eosio::action]]
void voidfncnoop() {
sync_call_not_supported::void_no_op_func void_func_no_op{ "callee"_n };
check(void_func_no_op() == std::nullopt, "void_func_io_op did not return std::nullopt");
}
// verify non-void call. int_func uses default support_mode::abort
[[eosio::action]]
void intfuncabort() {
sync_call_not_supported::int_func int_func_abort{ "callee"_n };
int_func_abort(); // Will throw. Tester will verify that.
}
// int_func uses support_mode::no_opabort
[[eosio::action]]
void intfuncnoop() {
sync_call_not_supported::int_no_op_func int_func_no_op{ "callee"_n };
check(int_func_no_op() == std::nullopt, "void_func_io_op did not return std::nullopt");
}
// void_io_op_success_func uses support_mode::no_op
[[eosio::action]]
void voidnoopsucc() {
sync_call_callee::void_no_op_success_func f{ "callee"_n };
check(f().has_value(), "void_io_op_success_func did not return a value");
}
// void_io_op_success_func uses support_mode::no_op
[[eosio::action]]
void sumnoopsucc() {
sync_call_callee::sum_no_op_success_func f{ "callee"_n };
check(*f(7, 8, 9) == 24, "sum_io_op_success_func did not return a value");
}
[[eosio::action]]
void hdrvaltest() {
// Verify function name validation works
call_data_header unkwn_func_header{ .version = 0, .func_name = "unknwnfunc"_i.id };
const std::vector<char> unkwn_func_data{ eosio::pack(unkwn_func_header) }; // unknwnfunc is not in "callee"_i contract
auto status = eosio::call("callee"_n, 0, unkwn_func_data.data(), unkwn_func_data.size());
eosio::check(status == -10001, "call did not return -10001 for unknown function");
// Verify version validation works
call_data_header bad_version_header{ .version = 1, .func_name = "sum"_i.id }; // version 1 is not supported
const std::vector<char> bad_version_data{ eosio::pack(bad_version_header) };
status = eosio::call("callee"_n, 0, bad_version_data.data(), bad_version_data.size());
eosio::check(status == -10000, "call did not return -10000 for invalid version");
}
// Call issynccall as a sync call and return its return value
[[eosio::action]]
bool makesynccall() {
sync_call_callee::issynccall_func is_sync_call_func{ "callee"_n };
return is_sync_call_func();
}
};
@@ -1,83 +0,0 @@
/*
* This contract is used to verify customized sync_call entry function works.
* It verifies customized sync_call entry is exported, and `call()` host function
* can reach it.
*/
#include <eosio/eosio.hpp>
#include <eosio/call.hpp>
namespace eosio {
class [[eosio::contract]] sync_call_cust_entry : public contract {
public:
using contract::contract;
[[eosio::action]]
void cusentrytst1() {
// Make a sync call to "receiver"_n account, pass function ID in `data`,
// go to `sync_call()` entry function, and dispatch the call to `get_10()`
// based on the function ID.
const std::vector<char> data{ eosio::pack(1) }; // function ID 1
eosio::call("receiver"_n, 0, data.data(), data.size());
// Retrieve return value and unpack it
std::vector<char> return_value(sizeof(uint32_t));
eosio::get_call_return_value(return_value.data(), return_value.size());
// Verify it
eosio::check(eosio::unpack<uint32_t>(return_value) == 10, "return value is not 10");
}
[[eosio::action]]
void cusentrytst2() {
// Make a sync call to "receiver"_n account, pass function ID in `data`,
// go to `sync_call()` entry function, and dispatch the call to `get_20()`
// based on the function ID.
const std::vector<char> data{ eosio::pack(2) }; // function ID 2
eosio::call("receiver"_n, 0, data.data(), data.size());
// Retrieve return value and unpack it
std::vector<char> return_value(sizeof(uint32_t));
eosio::get_call_return_value(return_value.data(), return_value.size());
// Verify it
eosio::check(eosio::unpack<uint32_t>(return_value) == 20, "return value is not 20");
}
// `eosio::call` tag is optional
uint32_t get_10() {
return 10;
}
[[eosio::call]]
uint32_t get_20() {
return 20;
}
};
} /// namespace eosio
extern "C" {
[[eosio::wasm_entry]]
int64_t sync_call(uint64_t sender, uint64_t receiver, uint32_t data_size) {
eosio::datastream<const char*> ds(nullptr, 0); // for testing, not used
eosio::sync_call_cust_entry obj(eosio::name{receiver}, eosio::name{receiver}, ds);
std::vector<char> data(sizeof(uint32_t));
eosio::get_call_data(data.data(), data.size());
auto func_id = eosio::unpack<uint32_t>(data);
// Dispatch sync calls
uint32_t rv = 0;
switch (func_id) {
case 1: rv = obj.get_10(); break;
case 2: rv = obj.get_20(); break;
default: eosio::check(false, "wrong function ID");
}
// set return value
eosio::set_call_return_value(&rv, sizeof(uint32_t));
return 0; // return 0 to indicate success
}
}
@@ -1,10 +0,0 @@
#include "sync_call_not_supported.hpp"
[[eosio::action]]
void sync_call_not_supported::voidfunc() {
}
[[eosio::action]]
int sync_call_not_supported::intfunc() {
return 1;
}
@@ -1,23 +0,0 @@
#include <eosio/eosio.hpp>
#include <eosio/call.hpp>
// Because this contract does not tag any functions by `call` attribute,
// `sync_call` entry point is not generated.
// Any sync calls to this contract will return a status indicating
// sync calls are not supported by the receiver.
class [[eosio::contract]] sync_call_not_supported : public eosio::contract{
public:
using contract::contract;
[[eosio::action]]
void voidfunc();
[[eosio::action]]
int intfunc();
using void_func = eosio::call_wrapper<"voidfunc"_i, &sync_call_not_supported::voidfunc>; // default behavior: abort when called
using void_no_op_func = eosio::call_wrapper<"voidfunc"_i, &sync_call_not_supported::voidfunc, eosio::access_mode::read_write, eosio::support_mode::no_op>; // no op when called
using int_func = eosio::call_wrapper<"intfunc"_i, &sync_call_not_supported::intfunc>; // default behavior: abort when called
using int_no_op_func = eosio::call_wrapper<"intfunc"_i, &sync_call_not_supported::intfunc, eosio::access_mode::read_write, eosio::support_mode::no_op>; // no op when called
};
@@ -1,16 +0,0 @@
#include <eosio/call.hpp>
#include <eosio/print.hpp>
#include <eosio/eosio.hpp>
class [[eosio::contract]] sync_call_single_func : public eosio::contract{
public:
using contract::contract;
[[eosio::call]]
uint32_t return_ten() {
return 10;
}
// Do NOT add any more functions tagged as `eosio::call` in this contract.
// It is used to test a contract having only one function tagged as `eosio::call`.
};
+1 -9
View File
@@ -64,15 +64,7 @@ void generate(const std::vector<std::string>& base_options, std::string input, s
abigen::get().set_contract_name(contract_name);
abigen::get().set_resource_dirs(resource_paths);
// We used to accept a command line option `--abi-version` which allowed a user to force an abi version
// to be generated.
// Since https://github.com/AntelopeIO/cdt/pull/360, this command line flag is ignored, and the abi
// version is generated according to the features used in the contract being compiled, starting from a
// base `1.2` version and up.
// ----------------------------------------------------------------------------------------------------
// abigen::get().set_abi_version(std::get<0>(abi_version), std::get<1>(abi_version));
abigen::get().set_abi_version(std::get<0>(abi_version), std::get<1>(abi_version));
abigen::get().set_suppress_ricardian_warning(suppress_ricardian_warning);
codegen::get().set_contract_name(contract_name);
codegen::get().set_warn_action_read_only(warn_action_read_only);
+1 -6
View File
@@ -509,7 +509,6 @@ static void GetLdDefaults(std::vector<std::string>& ldopts) {
ldopts.insert(ldopts.end(), { "-e", "apply" });
ldopts.insert(ldopts.end(), { "--only-export", "apply:function" });
ldopts.insert(ldopts.end(), { "--only-export", "*:memory" });
ldopts.insert(ldopts.end(), { "--only-export", "sync_call:function" });
}
ldopts.emplace_back("-lc++");
ldopts.emplace_back("-lc");
@@ -948,13 +947,9 @@ static Options CreateOptions(bool add_defaults=true) {
#endif
// 1.2 -- action results
// 1.3 -- sync calls, bitset type, action and sync call names in C++
// identifier format
/* TODO add some way of defaulting these to the current highest version */
int abi_version_major = 1;
int abi_version_minor = 3;
int abi_version_minor = 2;
if (!abi_version_opt.empty()) {
abi_version_major = std::stoi(abi_version_opt);
+3 -35
View File
@@ -30,14 +30,6 @@ struct abi_action {
bool operator<(const abi_action& s) const { return name < s.name; }
};
struct abi_call {
std::string name;
std::string type;
uint64_t id = 0; // internal short ID of `name`
std::string result_type;
bool operator<(const abi_call& s) const { return name < s.name; }
};
struct abi_table {
std::string name;
std::string type;
@@ -69,43 +61,19 @@ struct abi_action_result {
bool operator<(const abi_action_result& ar) const { return name < ar.name; }
};
struct version_t {
uint8_t major = 0;
uint8_t minor = 0;
version_t(uint8_t major, uint8_t minor)
: major(major)
, minor(minor) {}
friend bool operator<(const version_t& a, const version_t& b) {
return std::tie(a.major, a.minor) < std::tie(b.major, b.minor);
}
friend bool operator==(const version_t& a, const version_t& b) {
return std::tie(a.major, a.minor) == std::tie(b.major, b.minor);
}
void set_min(version_t o) {
if (*this < o)
*this = o;
}
std::string str() const { return std::to_string(major) + "." + std::to_string(minor); }
};
/// From eosio libraries/chain/include/eosio/chain/abi_def.hpp
struct abi {
version_t version{1,2}; // base version is 1.2, add features (bitset, sync calls) push to 1.3
int version_major = 1;
int version_minor = 1;
std::string version_string()const { return std::string("eosio::abi/")+std::to_string(version_major)+"."+std::to_string(version_minor); }
std::set<abi_struct> structs;
std::set<abi_typedef> typedefs;
std::set<abi_action> actions;
std::set<abi_call> calls;
std::set<abi_table> tables;
std::set<abi_variant> variants;
std::vector<abi_ricardian_clause_pair> ricardian_clauses;
std::vector<abi_error_message> error_messages;
std::set<abi_action_result> action_results;
std::string version_string() const { return std::string("eosio::abi/")+version.str(); }
};
inline void dump( const abi& abi ) {
+13 -104
View File
@@ -26,7 +26,6 @@
#include <sstream>
#include <memory>
#include <set>
#include <tuple>
#include <map>
#include <array>
#include <jsoncons/json.hpp>
@@ -37,11 +36,7 @@ using namespace eosio::cdt;
using jsoncons::json;
using jsoncons::ojson;
namespace eosio::cdt {
const version_t bitset_min_version{1,3};
const version_t sync_calls_min_version{1,3};
namespace eosio { namespace cdt {
class abigen : public generation_utils {
std::set<std::string> checked_actions;
public:
@@ -53,7 +48,8 @@ namespace eosio::cdt {
}
void set_abi_version(int major, int minor) {
_abi.version = version_t{static_cast<uint8_t>(major), static_cast<uint8_t>(minor)};
_abi.version_major = major;
_abi.version_minor = minor;
}
void add_typedef( const clang::QualType& t ) {
@@ -135,50 +131,6 @@ namespace eosio::cdt {
}
}
void add_call( const clang::CXXRecordDecl* decl ) {
abi_call ret;
auto call_name = decl->getEosioCallAttr()->getName();
if (call_name.empty()) {
validate_name(decl->getName().str(), [&](auto s) { CDT_ERROR("abigen_error", decl->getLocation(), s); });
ret.name = decl->getName().str();
}
else {
validate_name( call_name.str(), [&](auto s) { CDT_ERROR("abigen_error", decl->getLocation(), s); });
ret.name = call_name.str();
}
ret.type = decl->getName().str();
ret.id = to_hash_id(ret.name);
_abi.calls.insert(ret);
_abi.version.set_min(sync_calls_min_version);
}
void add_call( const clang::CXXMethodDecl* decl ) {
abi_call ret;
auto call_name = decl->getEosioCallAttr()->getName();
if (call_name.empty()) {
validate_hash_id( decl->getNameAsString(), [&](auto s) { CDT_ERROR("abigen_error", decl->getLocation(), s); } );
ret.name = decl->getNameAsString();
}
else {
validate_hash_id( call_name.str(), [&](auto s) { CDT_ERROR("abigen_error", decl->getLocation(), s); } );
ret.name = call_name.str();
}
ret.type = decl->getNameAsString();
ret.id = to_hash_id(ret.name);
auto result_type = translate_type(decl->getReturnType());
if (result_type != "void") {
add_type(decl->getReturnType());
ret.result_type = result_type;
}
_abi.calls.insert(ret);
_abi.version.set_min(sync_calls_min_version);
}
void add_tuple(const clang::QualType& type) {
auto pt = llvm::dyn_cast<clang::ElaboratedType>(type.getTypePtr());
auto tst = llvm::dyn_cast<clang::TemplateSpecializationType>((pt) ? pt->desugar().getTypePtr() : type.getTypePtr());
@@ -199,6 +151,7 @@ namespace eosio::cdt {
void add_pair(const clang::QualType& type) {
for (int i = 0; i < 2; ++i) {
clang::QualType ftype = std::get<clang::QualType>(get_template_argument(type, i));
std::string ty = translate_type(ftype);
add_type(ftype);
}
abi_struct pair;
@@ -263,7 +216,6 @@ namespace eosio::cdt {
void add_struct( const clang::CXXMethodDecl* decl ) {
abi_struct new_struct;
new_struct.name = decl->getNameAsString();
for (auto param : decl->parameters() ) {
auto param_type = param->getType().getNonReferenceType().getUnqualifiedType();
new_struct.fields.push_back({param->getNameAsString(), get_type(param_type)});
@@ -528,8 +480,7 @@ namespace eosio::cdt {
add_explicit_nested_type(t.getNonReferenceType());
return;
}
auto type_str = translate_type(type);
if (!is_builtin_type(type_str)) {
if (!is_builtin_type(translate_type(type))) {
if (is_aliasing(type)) {
add_typedef(type);
}
@@ -551,13 +502,6 @@ namespace eosio::cdt {
}
else if (type.getTypePtr()->isRecordType())
add_struct(type.getTypePtr()->getAsCXXRecordDecl());
} else {
static std::unordered_map<std::string, version_t> versioned_types {
{ "bitset", bitset_min_version }
};
if (auto it = versioned_types.find(type_str); it != versioned_types.end())
_abi.version.set_min(it->second);
}
}
@@ -607,15 +551,6 @@ namespace eosio::cdt {
return o;
}
ojson call_to_json( const abi_call& c ) {
ojson o;
o["name"] = c.name;
o["type"] = c.type;
o["id"] = c.id;
o["result_type"] = c.result_type;
return o;
}
ojson clause_to_json( const abi_ricardian_clause_pair& clause ) {
ojson o;
o["id"] = clause.id;
@@ -658,15 +593,13 @@ namespace eosio::cdt {
set_of_tables.insert(t);
}
return _abi.structs.empty() && _abi.typedefs.empty() && _abi.actions.empty() && _abi.calls.empty() && set_of_tables.empty() && _abi.ricardian_clauses.empty() && _abi.variants.empty();
return _abi.structs.empty() && _abi.typedefs.empty() && _abi.actions.empty() && set_of_tables.empty() && _abi.ricardian_clauses.empty() && _abi.variants.empty();
}
ojson to_json() {
ojson o;
o["____comment"] = generate_json_comment();
o["version"] = _abi.version_string();
o["structs"] = ojson::array();
auto remove_suffix = [&]( std::string name ) {
int i = name.length()-1;
@@ -725,10 +658,6 @@ namespace eosio::cdt {
if (as.name == _translate_type(a.type))
return true;
}
for ( auto a : _abi.calls ) {
if (as.name == _translate_type(a.type))
return true;
}
for( auto t : set_of_tables ) {
if (as.name == _translate_type(t.type))
return true;
@@ -766,9 +695,6 @@ namespace eosio::cdt {
for ( auto a : _abi.actions )
if ( a.type == td.new_type_name )
return true;
for ( auto a : _abi.calls )
if ( a.type == td.new_type_name )
return true;
for ( auto _td : _abi.typedefs )
if ( remove_suffix(_td.type) == td.new_type_name )
return true;
@@ -793,12 +719,6 @@ namespace eosio::cdt {
for ( auto a : _abi.actions ) {
o["actions"].push_back(action_to_json( a ));
}
if (!_abi.calls.empty()) { // add calls section only when sync calls are used
o["calls"] = ojson::array();
for ( auto a : _abi.calls ) {
o["calls"].push_back(call_to_json( a ));
}
}
o["tables"] = ojson::array();
for ( auto t : set_of_tables ) {
o["tables"].push_back(table_to_json( t ));
@@ -807,17 +727,16 @@ namespace eosio::cdt {
for ( auto rc : _abi.ricardian_clauses ) {
o["ricardian_clauses"].push_back(clause_to_json( rc ));
}
o["variants"] = ojson::array();
for ( auto v : _abi.variants ) {
o["variants"].push_back(variant_to_json( v ));
}
o["abi_extensions"] = ojson::array();
o["action_results"] = ojson::array();
for ( auto ar : _abi.action_results ) {
o["action_results"].push_back(action_result_to_json( ar ));
if (_abi.version_major == 1 && _abi.version_minor >= 2) {
o["action_results"] = ojson::array();
for ( auto ar : _abi.action_results ) {
o["action_results"].push_back(action_result_to_json( ar ));
}
}
return o;
}
@@ -859,14 +778,6 @@ namespace eosio::cdt {
ag.add_type( param->getType() );
}
}
if (decl->isEosioCall() && ag.is_eosio_contract(decl, ag.get_contract_name())) {
ag.add_struct(decl);
ag.add_call(decl);
for (auto param : decl->parameters()) {
ag.add_type( param->getType() );
}
}
return true;
}
virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl* decl) {
@@ -875,12 +786,10 @@ namespace eosio::cdt {
ag.add_contracts(ag.parse_contracts());
has_added_clauses = true;
}
if ((decl->isEosioAction() || decl->isEosioCall() || decl->isEosioTable()) && ag.is_eosio_contract(decl, ag.get_contract_name())) {
if ((decl->isEosioAction() || decl->isEosioTable()) && ag.is_eosio_contract(decl, ag.get_contract_name())) {
ag.add_struct(decl);
if (decl->isEosioAction())
ag.add_action(decl);
if (decl->isEosioCall())
ag.add_call(decl);
if (decl->isEosioTable())
ag.add_table(decl);
for (auto field : decl->fields()) {
@@ -1013,4 +922,4 @@ namespace eosio::cdt {
return std::make_unique<eosio_abigen_consumer>(&CI, file);
}
};
} // ns eosio::cdt
}} // ns eosio::cdt
-14
View File
@@ -37,10 +37,6 @@ class ABIMerger {
if (std::stod(vers.substr(vers.size()-3))*10 >= 12) {
ret["action_results"] = merge_action_results(other);
}
auto it = abi.find("calls");
if (it != abi.object_range().end()) { // merge `calls` section only when it exists
ret["calls"] = merge_calls(other);
}
return ret;
}
private:
@@ -86,10 +82,6 @@ class ABIMerger {
a["type"] == b["type"];
}
static bool call_is_same(ojson a, ojson b) {
return a["name"] == b["name"] &&
a["type"] == b["type"];
}
static bool variant_is_same(ojson a, ojson b) {
for (auto tya : a["types"].array_range()) {
@@ -189,12 +181,6 @@ class ABIMerger {
return acts;
}
ojson merge_calls(ojson b) {
ojson calls = ojson::array();
add_object_to_array(calls, abi, b, "calls", "name", call_is_same);
return calls;
}
ojson merge_tables(ojson b) {
ojson tabs = ojson::array();
add_object_to_array(tabs, abi, b, "tables", "name", table_is_same);
+4 -183
View File
@@ -53,7 +53,6 @@ namespace eosio { namespace cdt {
std::set<std::string> datastream_uses;
std::set<std::string> actions;
std::set<std::string> notify_handlers;
std::set<std::string> calls;
ASTContext *ast_context;
std::map<std::string, CXXMethodDecl*> cxx_methods;
std::map<std::string, CXXRecordDecl*> cxx_records;
@@ -146,28 +145,11 @@ namespace eosio { namespace cdt {
return "";
}
// Return `true` if the method `decl`'s base class if `eosio::contract`
bool base_is_eosio_contract_class(const clang::CXXMethodDecl* decl) {
auto cxx_decl = decl->getParent();
// on this point it could be just an attribute so let's check base classes
for (const auto& base : cxx_decl->bases()) {
if (const clang::Type *base_type = base.getType().getTypePtrOrNull()) {
if (const auto* cur_cxx_decl = base_type->getAsCXXRecordDecl()) {
if (cur_cxx_decl->getQualifiedNameAsString() == "eosio::contract") {
return true;;
}
}
}
}
return false;
}
template <typename F>
void create_dispatch(const std::string& attr, const std::string& func_name, F&& get_str, CXXMethodDecl* decl) {
constexpr static uint32_t max_stack_size = 512;
codegen& cg = codegen::get();
std::string nm = decl->getNameAsString()+"_"+decl->getParent()->getNameAsString();
if (cg.is_eosio_contract(decl, cg.contract_name)) {
ss << "\n\n#include <eosio/datastream.hpp>\n";
ss << "#include <eosio/name.hpp>\n";
@@ -207,22 +189,8 @@ namespace eosio { namespace cdt {
ss << tn << " arg" << i << "; ds >> arg" << i << ";\n";
i++;
}
// Create contract object
ss << decl->getParent()->getQualifiedNameAsString()
<< " obj {eosio::name{r},eosio::name{c},ds};\n";
// Call `set_exec_type()` only for contracts dervied from `eosio::contract`.
// A contract class can have only `eosio::contract` attribute
// but does not inherit from the `eosio::contract` class;
// it may not have `set_exec_type()`. We need to make sure the class derives
// from `eosio::contract` before calling set_exec_type().
if (base_is_eosio_contract_class(decl)) {
ss << "obj.set_exec_type(eosio::contract::exec_type_t::action);\n";
}
const auto& call_action = [&]() {
ss << "obj." << decl->getNameAsString() << "(";
ss << decl->getParent()->getQualifiedNameAsString() << "{eosio::name{r},eosio::name{c},ds}." << decl->getNameAsString() << "(";
for (int i=0; i < decl->parameters().size(); i++) {
ss << "arg" << i;
if (i < decl->parameters().size()-1)
@@ -253,116 +221,10 @@ namespace eosio { namespace cdt {
create_dispatch("eosio_wasm_notify", "__eosio_notify_", func, decl);
}
// Generate sync call dispatcher
void create_call_dispatch(CXXMethodDecl* decl) {
const std::string attr = "eosio_wasm_call";
const std::string func_name = "__eosio_call_";
const std::string call_name = generation_utils::get_call_name(decl);
constexpr static uint32_t max_stack_size = 512;
codegen& cg = codegen::get();
std::string nm = decl->getNameAsString()+"_"+decl->getParent()->getNameAsString();
if (cg.is_eosio_contract(decl, cg.contract_name)) {
ss << "\n\n#include <eosio/datastream.hpp>\n";
ss << "#include <eosio/call.hpp>\n";
ss << "extern \"C\" {\n";
const auto& return_ty = decl->getReturnType().getAsString();
if (return_ty != "void") {
ss << "__attribute__((eosio_wasm_import))\n";
ss << "void set_call_return_value(void*, size_t);\n";
}
ss << "__attribute__((weak, " << attr << "(\"";
ss << call_name;
ss << ":";
ss << func_name << nm;
ss << "\"))) void " << func_name << nm << "(unsigned long long sender, unsigned long long receiver, size_t data_size, void* data) {\n";
ss << "eosio::datastream<const char*> ds{(char*)data, data_size};\n";
ss << "eosio::call_data_header header; ds >> header;\n"; // skip header
int i=0;
for (auto param : decl->parameters()) {
clang::LangOptions lang_opts;
lang_opts.CPlusPlus = true;
lang_opts.Bool = true;
clang::PrintingPolicy policy(lang_opts);
auto qt = param->getOriginalType().getNonReferenceType();
qt.removeLocalConst();
qt.removeLocalVolatile();
qt.removeLocalRestrict();
std::string tn = clang::TypeName::getFullyQualifiedName(qt, *(cg.ast_context), policy);
ss << tn << " arg" << i << "; ds >> arg" << i << ";\n";
i++;
}
// Create contract object
ss << decl->getParent()->getQualifiedNameAsString()
<< " obj {eosio::name{receiver},eosio::name{receiver},ds};\n";
// Call `set_exec_type()` only for contracts dervied from `eosio::contract`.
// A contract class can have only `eosio::contract` attribute
// but does not inherit from the `eosio::contract` class;
// it may not have `set_exec_type()`. We need to make sure the class derives
// from `eosio::contract` before calling set_exec_type().
if (base_is_eosio_contract_class(decl)) {
ss << "obj.set_exec_type(eosio::contract::exec_type_t::call);\n";
}
const auto& call_function = [&]() {
ss << "obj." << decl->getNameAsString() << "(";
for (int i=0; i < decl->parameters().size(); i++) {
ss << "arg" << i;
if (i < decl->parameters().size()-1)
ss << ", ";
}
ss << ");\n";
};
if (return_ty != "void") {
ss << "const auto& result = ";
}
call_function();
if (return_ty != "void") {
ss << "const auto& packed_result = eosio::pack(result);\n";
ss << "::set_call_return_value((void*)packed_result.data(), packed_result.size());\n";
}
ss << "}}\n";
}
}
// Generate get_sync_call_data_version which returns the version of call data.
// In version 0, call data is packed as header + arguments, where
// header is `struct header { uint32_t version; uint64_t func_name }`
static void create_get_sync_call_data_header(std::stringstream& ss) {
ss << "\n\n#include <eosio/datastream.hpp>\n";
ss << "#include <eosio/call.hpp>\n";
ss << "extern \"C\" {\n";
ss << "__attribute__((weak)) void* __eos_get_sync_call_data_header_(void* data) {\n";
ss << "size_t size = sizeof(eosio::call_data_header);\n";
ss << "eosio::datastream<const char*> ds{(char*)data, size};\n";
ss << "eosio::call_data_header header; ds >> header;\n";
ss << "void* ptr = malloc(size);\n";
ss << "memcpy(ptr, &header, size);\n";
ss << "return ptr;\n";
ss << "}}\n";
}
// Generate get_sync_call_data which returns call data which consists of
// header and arguments
static void create_get_sync_call_data(std::stringstream& ss) {
ss << "\n\n#include <eosio/datastream.hpp>\n";
ss << "#include <eosio/name.hpp>\n";
ss << "extern \"C\" {\n";
ss << "__attribute__((eosio_wasm_import)) uint32_t get_call_data(void*, uint32_t);\n";
ss << "__attribute__((weak)) void* __eos_get_sync_call_data_(unsigned long size) {\n";
ss << "void* data = malloc(size);\n"; // store data in linear memory
ss << "::get_call_data(data, size);\n";
ss << "return data;\n";
ss << "}}\n";
}
virtual bool VisitCXXMethodDecl(CXXMethodDecl* decl) {
std::string name = decl->getNameAsString();
static std::set<std::string> _action_set; //used for validations
static std::set<std::string> _notify_set; //used for validations
static std::set<std::string> _call_set; //used for validations
if (decl->isEosioAction()) {
name = generation_utils::get_action_name(decl);
validate_name(name, [&](auto s) {
@@ -378,8 +240,8 @@ namespace eosio { namespace cdt {
std::string full_action_name = decl->getNameAsString() + ((decl->getParent()) ? decl->getParent()->getNameAsString() : "");
if (cg.actions.count(full_action_name) == 0) {
create_action_dispatch(decl);
cg.actions.insert(full_action_name); // insert the method action, so we don't create the dispatcher twice
}
cg.actions.insert(full_action_name); // insert the method action, so we don't create the dispatcher twice
if (decl->isEosioReadOnly()) {
read_only_actions.insert(decl);
@@ -407,49 +269,8 @@ namespace eosio { namespace cdt {
std::string full_notify_name = decl->getNameAsString() + ((decl->getParent()) ? decl->getParent()->getNameAsString() : "");
if (cg.notify_handlers.count(full_notify_name) == 0) {
create_notify_dispatch(decl);
cg.notify_handlers.insert(full_notify_name); // insert the method action, so we don't create the dispatcher twice
}
}
// We allow a method to be tagged as both `action` and `call`
if (decl->isEosioCall()) {
static std::unordered_map<uint64_t, std::string> _call_id_map;
name = generation_utils::get_call_name(decl);
validate_hash_id(name, [&](auto s) {
CDT_ERROR("codegen_error", decl->getLocation(), std::string("call name (")+s+") is not a valid C++ identifier");
});
// Make sure there are no conflicts of IDs
auto id = to_hash_id(name);
auto it = _call_id_map.find(id);
if (it != _call_id_map.end()) {
if (name != it->second) {
CDT_ERROR("codegen_error",
decl->getLocation(),
std::string("call name (") + name + ")'s ID " + std::to_string(id) + " conflicts with a previous call name: " + it->second + ". Please choose another name");
}
} else {
_call_id_map.insert({id, name});
}
// Genereate create_get_sync_call_data and create_get_sync_call_data_header only once
if (_call_set.empty()) {
create_get_sync_call_data(ss);
create_get_sync_call_data_header(ss);
}
if (!_call_set.count(name))
_call_set.insert(name);
else {
auto itr = _call_set.find(name);
CDT_CHECK_ERROR(*itr == name, "codegen_error", decl->getLocation(), "call declaration doesn't match previous declaration");
}
std::string full_call_name = decl->getNameAsString() + ((decl->getParent()) ? decl->getParent()->getNameAsString() : "");
if (cg.calls.count(full_call_name) == 0) {
create_call_dispatch(decl);
cg.calls.insert(full_call_name); // insert the sync call method name, so we don't create the dispatcher twice
}
cg.notify_handlers.insert(full_notify_name); // insert the method action, so we don't create the dispatcher twice
}
return true;
@@ -644,7 +465,7 @@ namespace eosio { namespace cdt {
for (auto nd : visitor->notify_decls)
visitor->create_notify_dispatch(nd);
if (cg.actions.size() < 1 && cg.notify_handlers.size() < 1 && cg.calls.size() < 1) {
if (cg.actions.size() < 1 && cg.notify_handlers.size() < 1) {
return;
}
+6 -19
View File
@@ -13,7 +13,6 @@
#include <vector>
#include <string>
#include <map>
#include <unordered_map>
#include <regex>
#include <utility>
#include <variant>
@@ -192,18 +191,6 @@ struct generation_utils {
return tmp;
return decl->getNameAsString();
}
static inline std::string get_call_name( const clang::CXXMethodDecl* decl ) {
auto tmp = decl->getEosioCallAttr()->getName();
if (!tmp.empty())
return tmp;
return decl->getNameAsString();
}
static inline std::string get_call_name( const clang::CXXRecordDecl* decl ) {
auto tmp = decl->getEosioCallAttr()->getName();
if (!tmp.empty())
return tmp;
return decl->getName();
}
static inline std::string get_notify_pair( const clang::CXXMethodDecl* decl ) {
std::string notify_pair = "";
auto tmp = decl->getEosioNotifyAttr()->getName();
@@ -433,7 +420,7 @@ struct generation_utils {
}
std::string _translate_type( const std::string& t ) {
static std::unordered_map<std::string, std::string> translation_table =
static std::map<std::string, std::string> translation_table =
{
{"unsigned __int128", "uint128"},
{"__int128", "int128"},
@@ -485,10 +472,11 @@ struct generation_utils {
{"fixed_bytes_64", "checksum512"}
};
if (auto it = translation_table.find(t); it != translation_table.end())
return it->second;
auto ret = translation_table[t];
return t;
if (ret == "")
return t;
return ret;
}
inline std::string replace_in_name( std::string name ) {
@@ -776,8 +764,7 @@ struct generation_utils {
"symbol",
"symbol_code",
"asset",
"extended_asset",
"bitset"
"extended_asset"
};
return builtins.count(_translate_type(t)) >= 1;
}
-33
View File
@@ -97,39 +97,6 @@ std::string name_to_string( uint64_t nm ) {
return str;
}
static constexpr uint32_t max_string_length_for_hash_id = 128;
// Validate the input `str` is a valid C/C++ identifier
template <typename Lambda>
void validate_hash_id( const std::string& str, Lambda&& error_handler ) {
if (str.empty()) {
return error_handler("string is empty");
}
const auto len = str.length();
if ( len > max_string_length_for_hash_id ) {
return error_handler(std::string("string {") + str + "} is more than " + std::to_string(max_string_length_for_hash_id) + " characters long");
}
if (!(std::isalpha(str[0]) || str[0] == '_')) {
return error_handler(std::string("string {") + str + "} does not start with letter or underscore");
}
for (char ch : str.substr(1)) {
if (!(std::isalnum(static_cast<unsigned char>(ch)) || ch == '_')) {
return error_handler(std::string("string {") + str + "} has a character {" + ch + "} which is not a number, letter, or _");
}
}
}
uint64_t to_hash_id(std::string str) {
uint64_t hash = 5381;
for (char c : str) {
hash = ((hash << 5) + hash) + static_cast<uint8_t>(c); // hash * 33 + c
}
return hash;
}
struct environment {
static llvm::ArrayRef<llvm::StringRef> get() {
static std::vector<llvm::StringRef> env_table;