Merge pull request #365 from AntelopeIO/merge_main_july_14
SC: [5.0 --> sync_call] Merge from main
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"antelope-spring-dev":{
|
||||
"target":"sync_call",
|
||||
"target":"release/2.0",
|
||||
"prerelease":false
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
cmake_minimum_required(VERSION 3.5...4.0)
|
||||
|
||||
# Sanity check our source directory to make sure that we are not trying to
|
||||
# generate an in-source build, and to make
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
#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
|
||||
@@ -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} -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} -Dspring_DIR=${spring_DIR} -Deosio_DIR=${eosio_DIR} -DLLVM_DIR=${LLVM_DIR} -DBOOST_ROOT=${BOOST_ROOT}
|
||||
UPDATE_COMMAND ""
|
||||
PATCH_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
#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()
|
||||
@@ -0,0 +1,47 @@
|
||||
#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()
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
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"); }
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#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,7 @@
|
||||
{
|
||||
"tests" : [
|
||||
{
|
||||
"compile_flags": ["--abi-version=1.2"],
|
||||
"compile_flags": [],
|
||||
"expected" : {
|
||||
"abi-file" : "action_results_test.abi"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"tests": [
|
||||
{
|
||||
"compile_flags": ["--abi-version=1.2"],
|
||||
"compile_flags": [],
|
||||
"expected": {
|
||||
"abi-file": "aliased_type_variant_template_arg.abi"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"tests" : [
|
||||
{
|
||||
"compile_flags": ["--abi-version=1.2"],
|
||||
"compile_flags": [],
|
||||
"expected" : {
|
||||
"abi-file" : "nested_container.abi"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"tests" : [
|
||||
{
|
||||
"compile_flags" : ["--abi-version=1.2", "-R={cwd}"],
|
||||
"compile_flags" : ["-R={cwd}"],
|
||||
"expected" : {
|
||||
"abi-file" : "ricardian_contract_test.abi"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"tests" : [
|
||||
{
|
||||
"compile_flags": ["--abi-version=1.2"],
|
||||
"compile_flags": [],
|
||||
"expected" : {
|
||||
"abi-file" : "singleton_contract.abi"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"tests": [
|
||||
{
|
||||
"compile_flags": ["--abi-version=1.2"],
|
||||
"compile_flags": [],
|
||||
"expected": {
|
||||
"abi-file": "struct_base_typedefd.abi"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"tests" : [
|
||||
{
|
||||
"compile_flags": ["--abi-version=1.2"],
|
||||
"compile_flags": [],
|
||||
"expected" : {
|
||||
"abi-file" : "tagged_number_test.abi"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"tests" : [
|
||||
{
|
||||
"compile_flags": ["--abi-version=1.2"],
|
||||
"compile_flags": [],
|
||||
"expected" : {
|
||||
"abi-file" : "using_std_array.abi"
|
||||
}
|
||||
|
||||
@@ -65,8 +65,7 @@ class [[eosio::contract]] array_tests : public contract {
|
||||
}
|
||||
}
|
||||
|
||||
// test parameter using std::array
|
||||
// not supported so far
|
||||
// test parameter using std::array
|
||||
[[eosio::action]]
|
||||
void testpa(std::array<int,4> input){
|
||||
std::array<int,4> arr = input;
|
||||
@@ -76,7 +75,7 @@ class [[eosio::contract]] array_tests : public contract {
|
||||
eosio::cout << "\n";
|
||||
}
|
||||
|
||||
// test return using std::array, not supported so far
|
||||
// test parameter and return value using std::array
|
||||
[[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){
|
||||
@@ -85,6 +84,15 @@ 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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <eosio/eosio.hpp>
|
||||
#include <eosio/transaction.hpp>
|
||||
#include <eosio/bitset.hpp>
|
||||
|
||||
#include "transfer.hpp"
|
||||
|
||||
@@ -61,6 +62,17 @@ 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");
|
||||
|
||||
@@ -64,7 +64,15 @@ 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);
|
||||
abigen::get().set_abi_version(std::get<0>(abi_version), std::get<1>(abi_version));
|
||||
|
||||
// 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_suppress_ricardian_warning(suppress_ricardian_warning);
|
||||
codegen::get().set_contract_name(contract_name);
|
||||
codegen::get().set_warn_action_read_only(warn_action_read_only);
|
||||
|
||||
@@ -69,16 +69,32 @@ struct abi_action_result {
|
||||
bool operator<(const abi_action_result& ar) const { return name < ar.name; }
|
||||
};
|
||||
|
||||
// The version when sync call was first introduced.
|
||||
constexpr int abi_call_version_major = 1;
|
||||
constexpr int abi_call_version_minor = 3;
|
||||
constexpr int abi_call_version = abi_call_version_major * 10 + abi_call_version_minor;
|
||||
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 {
|
||||
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); }
|
||||
version_t version{1,2}; // base version is 1.2, add features (bitset, sync calls) push to 1.3
|
||||
std::set<abi_struct> structs;
|
||||
std::set<abi_typedef> typedefs;
|
||||
std::set<abi_action> actions;
|
||||
@@ -88,6 +104,8 @@ struct abi {
|
||||
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 ) {
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <jsoncons/json.hpp>
|
||||
@@ -36,7 +37,11 @@ using namespace eosio::cdt;
|
||||
using jsoncons::json;
|
||||
using jsoncons::ojson;
|
||||
|
||||
namespace eosio { namespace cdt {
|
||||
namespace eosio::cdt {
|
||||
|
||||
const version_t bitset_min_version{1,3};
|
||||
const version_t sync_calls_min_version{1,3};
|
||||
|
||||
class abigen : public generation_utils {
|
||||
std::set<std::string> checked_actions;
|
||||
public:
|
||||
@@ -48,8 +53,7 @@ namespace eosio { namespace cdt {
|
||||
}
|
||||
|
||||
void set_abi_version(int major, int minor) {
|
||||
_abi.version_major = major;
|
||||
_abi.version_minor = minor;
|
||||
_abi.version = version_t{static_cast<uint8_t>(major), static_cast<uint8_t>(minor)};
|
||||
}
|
||||
|
||||
void add_typedef( const clang::QualType& t ) {
|
||||
@@ -146,6 +150,8 @@ namespace eosio { namespace cdt {
|
||||
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 ) {
|
||||
@@ -169,6 +175,8 @@ namespace eosio { namespace cdt {
|
||||
ret.result_type = result_type;
|
||||
}
|
||||
_abi.calls.insert(ret);
|
||||
|
||||
_abi.version.set_min(sync_calls_min_version);
|
||||
}
|
||||
|
||||
void add_tuple(const clang::QualType& type) {
|
||||
@@ -191,7 +199,6 @@ namespace eosio { namespace 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;
|
||||
@@ -521,7 +528,8 @@ namespace eosio { namespace cdt {
|
||||
add_explicit_nested_type(t.getNonReferenceType());
|
||||
return;
|
||||
}
|
||||
if (!is_builtin_type(translate_type(type))) {
|
||||
auto type_str = translate_type(type);
|
||||
if (!is_builtin_type(type_str)) {
|
||||
if (is_aliasing(type)) {
|
||||
add_typedef(type);
|
||||
}
|
||||
@@ -543,6 +551,13 @@ namespace eosio { namespace 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,7 +664,9 @@ namespace eosio { namespace cdt {
|
||||
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;
|
||||
@@ -776,8 +793,7 @@ namespace eosio { namespace cdt {
|
||||
for ( auto a : _abi.actions ) {
|
||||
o["actions"].push_back(action_to_json( a ));
|
||||
}
|
||||
if (_abi.version_major > abi_call_version_major ||
|
||||
_abi.version_major == abi_call_version_major && _abi.version_minor >= abi_call_version_minor) { // sync call
|
||||
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 ));
|
||||
@@ -791,16 +807,17 @@ namespace eosio { namespace 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();
|
||||
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 ));
|
||||
}
|
||||
|
||||
o["action_results"] = ojson::array();
|
||||
for ( auto ar : _abi.action_results ) {
|
||||
o["action_results"].push_back(action_result_to_json( ar ));
|
||||
}
|
||||
return o;
|
||||
}
|
||||
@@ -996,4 +1013,4 @@ namespace eosio { namespace cdt {
|
||||
return std::make_unique<eosio_abigen_consumer>(&CI, file);
|
||||
}
|
||||
};
|
||||
}} // ns eosio::cdt
|
||||
} // ns eosio::cdt
|
||||
|
||||
@@ -37,8 +37,9 @@ class ABIMerger {
|
||||
if (std::stod(vers.substr(vers.size()-3))*10 >= 12) {
|
||||
ret["action_results"] = merge_action_results(other);
|
||||
}
|
||||
if (std::stod(vers.substr(vers.size()-3))*10 >= abi_call_version) {
|
||||
ret["calls"] = merge_calls(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;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <regex>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
@@ -432,7 +433,7 @@ struct generation_utils {
|
||||
}
|
||||
|
||||
std::string _translate_type( const std::string& t ) {
|
||||
static std::map<std::string, std::string> translation_table =
|
||||
static std::unordered_map<std::string, std::string> translation_table =
|
||||
{
|
||||
{"unsigned __int128", "uint128"},
|
||||
{"__int128", "int128"},
|
||||
@@ -484,11 +485,10 @@ struct generation_utils {
|
||||
{"fixed_bytes_64", "checksum512"}
|
||||
};
|
||||
|
||||
auto ret = translation_table[t];
|
||||
if (auto it = translation_table.find(t); it != translation_table.end())
|
||||
return it->second;
|
||||
|
||||
if (ret == "")
|
||||
return t;
|
||||
return ret;
|
||||
return t;
|
||||
}
|
||||
|
||||
inline std::string replace_in_name( std::string name ) {
|
||||
@@ -776,7 +776,8 @@ struct generation_utils {
|
||||
"symbol",
|
||||
"symbol_code",
|
||||
"asset",
|
||||
"extended_asset"
|
||||
"extended_asset",
|
||||
"bitset"
|
||||
};
|
||||
return builtins.count(_translate_type(t)) >= 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user