你有没有发现合约中的参数类型明明是uint64,可是执行合约的时候明明传入的是字符串?明明合约参数类型是个结构体,执行合约的时候我传入的还是字符串?这到底是怎么回事?
EOSIO 针对数据流有两套机制,一套是针对客户端和 EOSIO 中的服务进行交互的时候,一套是 EOSIO 中的服务和智能合约进行交互的时候。
目前我知道的是,客户端和服务端交互的时候使用的是 JSON 格式的字符串!基于此我们修改源码增加自己的自定义的数据结构。
- 修改 ~/eos/libraries/chain/include/eosio/chain/asset.hpp, 增加 customdata 自定义数据结构,并且增加宏FC_REFLECT
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include
#include
#include
namespace eosio { namespace chain {
struct customdata {
int n;
static customdata from_string(const string& from);
string to_string()const ;
};
/**
asset includes amount and currency symbol
asset::from_string takes a string of the form "10.0000 CUR" and constructs an asset
with amount = 10 and symbol(4,"CUR")
*/
struct asset
{
static constexpr int64_t max_amount = (1LL << 62) - 1;
explicit asset(share_type a = 0, symbol id = symbol(CORE_SYMBOL)) :amount(a), sym(id) {
EOS_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" );
EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" );
}
bool is_amount_within_range()const { return -max_amount <= amount && amount <= max_amount; }
bool is_valid()const { return is_amount_within_range() && sym.valid(); }
double to_real()const { return static_cast(amount) / precision(); }
uint8_t decimals()const;
string symbol_name()const;
int64_t precision()const;
const symbol& get_symbol() const { return sym; }
share_type get_amount()const { return amount; }
static asset from_string(const string& from);
string to_string()const;
asset& operator += (const asset& o)
{
EOS_ASSERT(get_symbol() == o.get_symbol(), asset_type_exception, "addition between two different asset is not allowed");
amount += o.amount;
return *this;
}
asset& operator -= (const asset& o)
{
EOS_ASSERT(get_symbol() == o.get_symbol(), asset_type_exception, "subtraction between two different asset is not allowed");
amount -= o.amount;
return *this;
}
asset operator -()const { return asset(-amount, get_symbol()); }
friend bool operator == (const asset& a, const asset& b)
{
return std::tie(a.get_symbol(), a.amount) == std::tie(b.get_symbol(), b.amount);
}
friend bool operator < (const asset& a, const asset& b)
{
EOS_ASSERT(a.get_symbol() == b.get_symbol(), asset_type_exception, "logical operation between two different asset is not allowed");
return std::tie(a.amount,a.get_symbol()) < std::tie(b.amount,b.get_symbol());
}
friend bool operator <= (const asset& a, const asset& b) { return (a == b) || (a < b); }
friend bool operator != (const asset& a, const asset& b) { return !(a == b); }
friend bool operator > (const asset& a, const asset& b) { return !(a <= b); }
friend bool operator >= (const asset& a, const asset& b) { return !(a < b); }
friend asset operator - (const asset& a, const asset& b) {
EOS_ASSERT(a.get_symbol() == b.get_symbol(), asset_type_exception, "subtraction between two different asset is not allowed");
return asset(a.amount - b.amount, a.get_symbol());
}
friend asset operator + (const asset& a, const asset& b) {
EOS_ASSERT(a.get_symbol() == b.get_symbol(), asset_type_exception, "addition between two different asset is not allowed");
return asset(a.amount + b.amount, a.get_symbol());
}
friend std::ostream& operator << (std::ostream& out, const asset& a) { return out << a.to_string(); }
friend struct fc::reflector;
void reflector_verify()const {
EOS_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" );
EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" );
}
private:
share_type amount;
symbol sym;
};
struct extended_asset {
extended_asset(){}
extended_asset( asset a, name n ):quantity(a),contract(n){}
asset quantity;
name contract;
};
bool operator < (const asset& a, const asset& b);
bool operator <= (const asset& a, const asset& b);
}} // namespace eosio::chain
namespace fc {
inline void to_variant(const eosio::chain::asset& var, fc::variant& vo) { vo = var.to_string(); }
inline void from_variant(const fc::variant& var, eosio::chain::asset& vo) {
vo = eosio::chain::asset::from_string(var.get_string());
}
}
namespace fc {
inline void to_variant(const eosio::chain::customdata& var, fc::variant& vo) { vo = var.to_string(); }
inline void from_variant(const fc::variant& var, eosio::chain::customdata& vo) {
vo = eosio::chain::customdata::from_string(var.get_string());
}
}
FC_REFLECT(eosio::chain::asset, (amount)(sym))
FC_REFLECT(eosio::chain::extended_asset, (quantity)(contract) )
FC_REFLECT(eosio::chain::customdata, (n))
- 修改 /home/juzi/eos/libraries/chain/asset.cpp,实现 to_string 和 from_string,这里建议将 from_string 设置成静态的,因为 from_string 可能会失败
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include
#include
#include
#include
namespace eosio { namespace chain {
uint8_t asset::decimals()const {
return sym.decimals();
}
string asset::symbol_name()const {
return sym.name();
}
int64_t asset::precision()const {
return sym.precision();
}
string asset::to_string()const {
string sign = amount < 0 ? "-" : "";
int64_t abs_amount = std::abs(amount);
string result = fc::to_string( static_cast(abs_amount) / precision());
if( decimals() )
{
auto fract = static_cast(abs_amount) % precision();
result += "." + fc::to_string(precision() + fract).erase(0,1);
}
return sign + result + " " + symbol_name();
}
asset asset::from_string(const string& from)
{
try {
string s = fc::trim(from);
// Find space in order to split amount and symbol
auto space_pos = s.find(' ');
EOS_ASSERT((space_pos != string::npos), asset_type_exception, "Asset's amount and symbol should be separated with space");
auto symbol_str = fc::trim(s.substr(space_pos + 1));
auto amount_str = s.substr(0, space_pos);
// Ensure that if decimal point is used (.), decimal fraction is specified
auto dot_pos = amount_str.find('.');
if (dot_pos != string::npos) {
EOS_ASSERT((dot_pos != amount_str.size() - 1), asset_type_exception, "Missing decimal fraction after decimal point");
}
// Parse symbol
string precision_digit_str;
if (dot_pos != string::npos) {
precision_digit_str = eosio::chain::to_string(amount_str.size() - dot_pos - 1);
} else {
precision_digit_str = "0";
}
string symbol_part = precision_digit_str + ',' + symbol_str;
symbol sym = symbol::from_string(symbol_part);
// Parse amount
safe int_part, fract_part;
if (dot_pos != string::npos) {
int_part = fc::to_int64(amount_str.substr(0, dot_pos));
fract_part = fc::to_int64(amount_str.substr(dot_pos + 1));
if (amount_str[0] == '-') fract_part *= -1;
} else {
int_part = fc::to_int64(amount_str);
}
safe amount = int_part;
amount *= safe(sym.precision());
amount += fract_part;
return asset(amount.value, sym);
}
FC_CAPTURE_LOG_AND_RETHROW( (from) )
}
customdata customdata::from_string(const string& from)
{
customdata o;
std::stringstream ss(from);
ss >> o.n;
return o;
}
string customdata::to_string()const
{
std::stringstream ss;
ss << n;
return ss.str();
}
} } // eosio::types
- 修改 ~/eos/libraries/chain/abi_serializer.cpp,将 customdata 添加到 built_in_types,这个文件必须修改,原因是这个文件和生成 abi 文件有关的,具体怎么实现的暂时没有研究。
void abi_serializer::configure_built_in_types() {
built_in_types.emplace("bool", pack_unpack());
built_in_types.emplace("int8", pack_unpack());
built_in_types.emplace("uint8", pack_unpack());
built_in_types.emplace("int16", pack_unpack());
built_in_types.emplace("uint16", pack_unpack());
built_in_types.emplace("int32", pack_unpack());
built_in_types.emplace("uint32", pack_unpack());
built_in_types.emplace("int64", pack_unpack());
built_in_types.emplace("uint64", pack_unpack());
built_in_types.emplace("int128", pack_unpack());
built_in_types.emplace("uint128", pack_unpack());
built_in_types.emplace("varint32", pack_unpack());
built_in_types.emplace("varuint32", pack_unpack());
// TODO: Add proper support for floating point types. For now this is good enough.
built_in_types.emplace("float32", pack_unpack());
built_in_types.emplace("float64", pack_unpack());
built_in_types.emplace("float128", pack_unpack());
built_in_types.emplace("time_point", pack_unpack());
built_in_types.emplace("time_point_sec", pack_unpack());
built_in_types.emplace("block_timestamp_type", pack_unpack());
built_in_types.emplace("name", pack_unpack());
built_in_types.emplace("bytes", pack_unpack());
built_in_types.emplace("string", pack_unpack());
built_in_types.emplace("checksum160", pack_unpack());
built_in_types.emplace("checksum256", pack_unpack());
built_in_types.emplace("checksum512", pack_unpack());
built_in_types.emplace("public_key", pack_unpack());
built_in_types.emplace("signature", pack_unpack());
built_in_types.emplace("symbol", pack_unpack());
built_in_types.emplace("symbol_code", pack_unpack());
built_in_types.emplace("asset", pack_unpack());
built_in_types.emplace("extended_asset", pack_unpack());
built_in_types.emplace("customdata", pack_unpack());
}
- 在智能合约中增加一个测试:
#include
using namespace eosio;
struct customdata {
int n;
// template
// friend DataStream &operator<<(DataStream &ds, const customdata &t) { return ds << t.n; }
//
// template
// friend DataStream &operator>>(DataStream &ds, customdata &t) { return ds >> t.n; }
};
class hello : public eosio::contract {
public:
using contract::contract;
/// @abi action
void hi(account_name user) {
print("Hello, ", name{user});
}
/// @abi action
void hi2(account_permission per) {
require_auth2(per.account, per.permission);
print("Hello, ", name{per.account});
}
/// @abi action
void hi3(account_name user) {
require_auth(user);
print("Hello, ", name{user});
}
void hi4(customdata cd) {
print(cd.n);
}
};
EOSIO_ABI(hello, (hi)(hi2)(hi3)(hi4))
- 重新编译所有,然后安装,使用生成后的 eosiocpp 生成 hello.abi,然后搭建环境测试吧!!!