Consolidate all sync call related fields into a single call section in ABI and allow a function to be tagged both as an action and a call

This commit is contained in:
Lin Huang
2025-07-13 23:14:20 -04:00
parent 3793b76ac5
commit ecb339bb64
10 changed files with 10 additions and 146 deletions
@@ -1,19 +0,0 @@
#include <eosio/call.hpp>
#include <eosio/eosio.hpp>
// Test the validation that action and call tags cannot be mixed.
class [[eosio::contract]] invalid_call_tags : public eosio::contract{
public:
using contract::contract;
[[eosio::action, eosio::call]]
uint32_t act1() {
return 0;
}
[[eosio::call, eosio::action]]
uint32_t act2() {
return 0;
}
};
@@ -1,11 +0,0 @@
{
"tests" : [
{
"compile_flags": [],
"expected" : {
"exit-code": 255,
"stderr": "codegen error (cannot be tagged as both action and call)"
}
}
]
}
@@ -1,17 +0,0 @@
#include <eosio/call.hpp>
#include <eosio/eosio.hpp>
// Test the validation that action and call tags cannot be mixed.
class [[eosio::contract]] invalid_call_tags : public eosio::contract{
public:
using contract::contract;
[[eosio::action]]
uint32_t act();
};
[[eosio::call]]
uint32_t invalid_call_tags::act() {
return 0;
}
@@ -1,11 +0,0 @@
{
"tests" : [
{
"compile_flags": [],
"expected" : {
"exit-code": 255,
"stderr": "codegen error (cannot be tagged as both action and call)"
}
}
]
}
@@ -1,17 +0,0 @@
#include <eosio/call.hpp>
#include <eosio/eosio.hpp>
// Test the validation that action and call tags cannot be mixed.
class [[eosio::contract]] invalid_call_tags : public eosio::contract{
public:
using contract::contract;
[[eosio::call]]
uint32_t act();
};
[[eosio::action]]
uint32_t invalid_call_tags::act() {
return 0;
}
@@ -1,11 +0,0 @@
{
"tests" : [
{
"compile_flags": [],
"expected" : {
"exit-code": 255,
"stderr": "codegen error (cannot be tagged as both action and call)"
}
}
]
}
+1 -7
View File
@@ -34,6 +34,7 @@ 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; }
};
@@ -68,12 +69,6 @@ struct abi_action_result {
bool operator<(const abi_action_result& ar) const { return name < ar.name; }
};
struct abi_call_result {
std::string name;
std::string type;
bool operator<(const abi_call_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;
@@ -93,7 +88,6 @@ 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::set<abi_call_result> call_results;
};
inline void dump( const abi& abi ) {
+5 -36
View File
@@ -163,11 +163,12 @@ namespace eosio { namespace cdt {
}
ret.type = decl->getNameAsString();
ret.id = to_hash_id(ret.name);
_abi.calls.insert(ret);
if (translate_type(decl->getReturnType()) != "void") {
auto result_type = translate_type(decl->getReturnType());
if (result_type != "void") {
add_type(decl->getReturnType());
_abi.call_results.insert({get_call_name(decl), translate_type(decl->getReturnType())});
ret.result_type = result_type;
}
_abi.calls.insert(ret);
}
void add_tuple(const clang::QualType& type) {
@@ -256,20 +257,6 @@ namespace eosio { namespace cdt {
abi_struct new_struct;
new_struct.name = decl->getNameAsString();
if (decl->isEosioCall()) {
// Add call_data_header definition to structs set
abi_struct data_header;
data_header.name = "call_data_header";
if (_abi.structs.count(data_header) == 0) {
data_header.fields.push_back({"version", "uint32"});
data_header.fields.push_back({"func_name", "uint64"});
_abi.structs.insert(data_header);
}
// Add header field as the first field to the method struct
new_struct.fields.push_back({"header", "call_data_header"});
}
for (auto param : decl->parameters() ) {
auto param_type = param->getType().getNonReferenceType().getUnqualifiedType();
new_struct.fields.push_back({param->getNameAsString(), get_type(param_type)});
@@ -610,6 +597,7 @@ namespace eosio { namespace cdt {
o["name"] = c.name;
o["type"] = c.type;
o["id"] = c.id;
o["result_type"] = c.result_type;
return o;
}
@@ -637,13 +625,6 @@ namespace eosio { namespace cdt {
return o;
}
ojson call_result_to_json( const abi_call_result& result ) {
ojson o;
o["name"] = result.name;
o["result_type"] = result.type;
return o;
}
bool is_empty() {
std::set<abi_table> set_of_tables;
for ( auto t : ctables ) {
@@ -743,10 +724,6 @@ namespace eosio { namespace cdt {
if (as.name == _translate_type(ar.type))
return true;
}
for( auto ar : _abi.call_results ) {
if (as.name == _translate_type(ar.type))
return true;
}
return false;
};
@@ -782,9 +759,6 @@ namespace eosio { namespace cdt {
if ( ar.type == td.new_type_name )
return true;
}
for ( auto ar : _abi.call_results )
if ( ar.type == td.new_type_name )
return true;
return false;
};
@@ -808,11 +782,6 @@ namespace eosio { namespace cdt {
for ( auto a : _abi.calls ) {
o["calls"].push_back(call_to_json( a ));
}
o["call_results"] = ojson::array();
for ( auto ar : _abi.call_results ) {
o["call_results"].push_back(call_result_to_json( ar ));
}
}
o["tables"] = ojson::array();
for ( auto t : set_of_tables ) {
-12
View File
@@ -39,7 +39,6 @@ class ABIMerger {
}
if (std::stod(vers.substr(vers.size()-3))*10 >= abi_call_version) {
ret["calls"] = merge_calls(other);
ret["call_results"] = merge_call_results(other);
}
return ret;
}
@@ -122,11 +121,6 @@ class ABIMerger {
a["result_type"] == b["result_type"];
}
static bool call_result_is_same(ojson a, ojson b) {
return a["name"] == b["name"] &&
a["result_type"] == b["result_type"];
}
template <typename F>
void add_object_to_array(ojson& ret, ojson a, ojson b, std::string type, std::string id, F&& is_same_func) {
for (auto obj_a : a[type].array_range()) {
@@ -218,12 +212,6 @@ class ABIMerger {
return res;
}
ojson merge_call_results(ojson b) {
ojson res = ojson::array();
add_object_to_array(res, abi, b, "call_results", "name", call_result_is_same);
return res;
}
ojson abi;
};
#pragma GCC diagnostic pop
+4 -5
View File
@@ -318,10 +318,6 @@ namespace eosio { namespace cdt {
static std::set<std::string> _notify_set; //used for validations
static std::set<std::string> _call_set; //used for validations
if (decl->isEosioAction() && decl->isEosioCall()) {
CDT_ERROR("codegen_error", decl->getLocation(), "cannot be tagged as both action and call");
}
if (decl->isEosioAction()) {
name = generation_utils::get_action_name(decl);
validate_name(name, [&](auto s) {
@@ -368,7 +364,10 @@ namespace eosio { namespace cdt {
create_notify_dispatch(decl);
cg.notify_handlers.insert(full_notify_name); // insert the method action, so we don't create the dispatcher twice
}
} else if (decl->isEosioCall()) {
}
// 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);