提交 79b73d97 编写于 作者: M Matias Romeo 提交者: GitHub

Merge pull request #101 from elmato/extend-abi-serializer

Extend abi serializer
{
"types": [{
"newTypeName": "AccountName",
"type": "Name"
}
],
"structs": [{
"name": "OrderID",
"fields": {
"name" : "AccountName",
"id" : "UInt64"
}
},{
"name" : "Bid",
"fields" : {
"buyer" : "OrderID",
"price" : "UInt128",
"quantity" : "UInt64",
"expiration" : "Time"
}
},{
"name" : "Ask",
"fields" : {
"seller" : "OrderID",
"price" : "UInt128",
"quantity" : "UInt64",
"expiration" : "Time"
}
},{
"name" : "Account",
"fields" : {
"owner" : "AccountName",
"eos_balance" : "UInt64",
"currency_balance" : "UInt64",
"open_orders" : "UInt32"
}
},{
"name" : "BuyOrder",
"base" : "Bid",
"fields" : {
"fill_or_kill" : "UInt8"
}
},{
"name" : "SellOrder",
"base" : "Ask",
"fields" : {
"fill_or_kill" : "UInt8"
}
}
],
"actions": [{
"action": "buy",
"type": "BuyOrder"
},{
"action": "sell",
"type": "SellOrder"
},{
"action": "cancel_buy",
"type": "OrderID"
},{
"action": "cancel_sell",
"type": "OrderID"
}
],
"tables": [
{"table":"bids","type":"Bid"},
{"table":"asks","type":"Ask"},
{"table":"account","type":"Account"}
]
}
......@@ -148,6 +148,7 @@ void apply_exchange_buy( BuyOrder order ) {
print( "\n No asks found, saving buyer account and storing bid\n" );
assert( !order.fill_or_kill, "order not completely filled" );
Bids::store( bid );
buyer_account.open_orders++;
save( buyer_account );
return;
}
......@@ -162,6 +163,7 @@ void apply_exchange_buy( BuyOrder order ) {
match( bid, buyer_account, lowest_ask, seller_account );
if( lowest_ask.quantity == CurrencyTokens(0) ) {
seller_account.open_orders--;
save( seller_account );
save( buyer_account );
Asks::remove( lowest_ask );
......@@ -175,6 +177,7 @@ void apply_exchange_buy( BuyOrder order ) {
}
print( "lowest_ask >= bid.price or buyer's bid has been filled\n" );
if( bid.quantity && !order.fill_or_kill ) buyer_account.open_orders++;
save( buyer_account );
print( "saving buyer's account\n" );
if( bid.quantity ) {
......@@ -209,6 +212,7 @@ void apply_exchange_sell( SellOrder order ) {
assert( !order.fill_or_kill, "order not completely filled" );
print( "\n No bids found, saving seller account and storing ask\n" );
Asks::store( ask );
seller_account.open_orders++;
save( seller_account );
return;
}
......@@ -220,6 +224,7 @@ void apply_exchange_sell( SellOrder order ) {
match( highest_bid, buyer_account, ask, seller_account );
if( highest_bid.quantity == EosTokens(0) ) {
buyer_account.open_orders--;
save( seller_account );
save( buyer_account );
Bids::remove( highest_bid );
......@@ -231,13 +236,49 @@ void apply_exchange_sell( SellOrder order ) {
break; // buyer's bid should be filled
}
}
if( ask.quantity && !order.fill_or_kill ) seller_account.open_orders++;
save( seller_account );
if( ask.quantity ) {
assert( !order.fill_or_kill, "order not completely filled" );
print( "saving ask\n" );
Asks::store( ask );
return;
}
print( "ask filled\n" );
}
void apply_exchange_cancel_buy( OrderID order ) {
requireAuth( order.name );
Bid bid_to_cancel;
assert( BidsById::get( order, bid_to_cancel ), "bid with this id does not exists" );
auto buyer_account = getAccount( order.name );
buyer_account.eos_balance += bid_to_cancel.quantity;
buyer_account.open_orders--;
Bids::remove( bid_to_cancel );
save( buyer_account );
print( "bid removed\n" );
}
void apply_exchange_cancel_sell( OrderID order ) {
requireAuth( order.name );
Ask ask_to_cancel;
assert( AsksById::get( order, ask_to_cancel ), "ask with this id does not exists" );
auto seller_account = getAccount( order.name );
seller_account.currency_balance += ask_to_cancel.quantity;
seller_account.open_orders--;
Asks::remove( ask_to_cancel );
save( seller_account );
print( "ask removed\n" );
}
} // namespace exchange
......@@ -266,6 +307,12 @@ extern "C" {
case N(sell):
apply_exchange_sell( currentMessage<exchange::SellOrder>() );
break;
case N(cancel_buy):
apply_exchange_cancel_buy( currentMessage<exchange::OrderID>() );
break;
case N(cancel_sell):
apply_exchange_cancel_sell( currentMessage<exchange::OrderID>() );
break;
default:
assert( false, "unknown action" );
}
......
......@@ -50,7 +50,7 @@ namespace exchange {
using Accounts = Table<N(exchange),N(exchange),N(account),Account,uint64_t>;
TABLE2(Bids,exchange,exchange,bids,Bid,BidsById,OrderID,BidsByPrice,Price);
TABLE2(Asks,exchange,exchange,bids,Ask,AsksById,OrderID,AsksByPrice,Price);
TABLE2(Asks,exchange,exchange,asks,Ask,AsksById,OrderID,AsksByPrice,Price);
struct BuyOrder : public Bid { uint8_t fill_or_kill = false; };
......
......@@ -14,87 +14,108 @@
"initial_accounts": [{
"name": "inita",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initb",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initc",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initd",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "inite",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initf",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initg",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "inith",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initi",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initj",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initk",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initl",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initm",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initn",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "inito",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initp",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initq",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initr",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "inits",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initt",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
},{
"name": "initu",
"owner_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
"active_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"liquid_balance": "1000000.00000000 EOS"
}],
"initial_producers": [{
"owner_name": "inita",
......
......@@ -390,7 +390,7 @@ DEFINE_INTRINSIC_FUNCTION1(env,free,free,none,i32,ptr) {
FC_ASSERT( getFunctionType(call)->parameters.size() == 2 );
// idump((current_validate_context->msg.code)(current_validate_context->msg.type)(current_validate_context->code));
std::vector<Value> args = { Value(uint64_t(current_validate_context->code)),
std::vector<Value> args = { Value(uint64_t(current_validate_context->msg.code)),
Value(uint64_t(current_validate_context->msg.type)) };
auto& state = *current_state;
......
......@@ -22,6 +22,7 @@ namespace eos { namespace types {
for( const auto& a : abi.actions )
actions[a.action] = a.type;
for( const auto& t : abi.tables )
tables[t.table] = t.type;
......@@ -36,7 +37,7 @@ namespace eos { namespace types {
}
bool AbiSerializer::isType( const TypeName& type )const {
static const std::set<TypeName> native = {"Name","UInt64"};
static const std::set<TypeName> native = {"Name", "UInt8", "UInt32", "UInt64", "UInt128", "Time", "String"};
if( native.find(type) != native.end() ) return true;
if( typedefs.find(type) != typedefs.end() ) return isType( typedefs.find(type)->second );
if( structs.find(type) != structs.end() ) return true;
......@@ -87,6 +88,7 @@ namespace eos { namespace types {
obj( field.name, binaryToVariant( resolveType(field.type), stream ) );
}
}
fc::variant AbiSerializer::binaryToVariant(const TypeName& type, fc::datastream<const char*>& stream )const
{
TypeName rtype = resolveType( type );
......@@ -95,11 +97,36 @@ namespace eos { namespace types {
fc::raw::unpack( stream, temp );
return fc::variant(temp);
}
else if( rtype == "UInt8" ) {
unsigned char temp;
fc::raw::unpack( stream, temp );
return fc::variant(temp);
}
else if( rtype == "UInt32" ) {
uint32_t temp;
fc::raw::unpack( stream, temp );
return fc::variant(temp);
}
else if( rtype == "UInt64" ) {
uint64_t temp;
fc::raw::unpack( stream, temp );
return fc::variant(temp);
}
else if( rtype == "UInt128" ) {
UInt128 temp;
fc::raw::unpack( stream, temp );
return fc::variant(temp);
}
else if( rtype == "Time" ) {
Time temp;
fc::raw::unpack( stream, temp );
return fc::variant(temp);
}
else if( rtype == "String" ) {
String temp;
fc::raw::unpack( stream, temp );
return fc::variant(temp);
}
fc::mutable_variant_object mvo;
binaryToVariant( rtype, stream, mvo );
return fc::variant( std::move(mvo) );
......@@ -118,10 +145,26 @@ namespace eos { namespace types {
fc::raw::pack( ds, var.as<Name>() );
return;
}
else if( rtype == "UInt8" ) {
fc::raw::pack( ds, var.as<unsigned char>() );
return;
}
else if( rtype == "UInt32" ) {
fc::raw::pack( ds, var.as<uint32_t>() );
return;
}
else if( rtype == "UInt64" ) {
fc::raw::pack( ds, var.as<uint64_t>() );
return;
}
else if( rtype == "UInt128" ) {
fc::raw::pack( ds, var.as<UInt128>() );
return;
}
else if( rtype == "Time" ) {
fc::raw::pack( ds, var.as<uint32_t>() );
return;
}
else if( rtype == "String" ) {
fc::raw::pack( ds, var.as<String>() );
return;
......@@ -144,9 +187,7 @@ namespace eos { namespace types {
}
}
Bytes AbiSerializer::variantToBinary(const TypeName& type, const fc::variant& var)const {
Bytes AbiSerializer::variantToBinary(const TypeName& type, const fc::variant& var)const {
if( !isType(type) )
return var.as<Bytes>();
......
......@@ -52,6 +52,7 @@ void chain_api_plugin::plugin_startup() {
CHAIN_RO_CALL(get_block),
CHAIN_RO_CALL(get_account),
CHAIN_RO_CALL(get_table_rows_i64),
CHAIN_RO_CALL(get_table_rows_i128i128_primary),
CHAIN_RO_CALL(abi_json_to_bin),
CHAIN_RW_CALL(push_block),
CHAIN_RW_CALL(push_transaction)
......
......@@ -4,6 +4,7 @@
#include <eos/chain/exceptions.hpp>
#include <eos/chain/producer_object.hpp>
#include <eos/chain/config.hpp>
#include <eos/chain/types.hpp>
#include <eos/native_contract/native_contract_chain_initializer.hpp>
#include <eos/native_contract/native_contract_chain_administrator.hpp>
......@@ -27,6 +28,7 @@ using chain::account_object;
using chain::key_value_object;
using chain::by_name;
using chain::by_scope_key;
using chain::uint128_t;
class chain_plugin_impl {
......@@ -237,6 +239,48 @@ read_only::get_table_rows_i64_result read_only::get_table_rows_i64( const read_o
return result;
}
read_only::get_table_rows_i128i128_primary_result read_only::get_table_rows_i128i128_primary( const read_only::get_table_rows_i128i128_primary_params& p )const {
read_only::get_table_rows_i128i128_primary_result result;
const auto& d = db.get_database();
const auto& code_account = d.get<account_object,by_name>( p.code );
types::AbiSerializer abis;
if( code_account.abi.size() > 4 ) { /// 4 == packsize of empty Abi
eos::types::Abi abi;
fc::datastream<const char*> ds( code_account.abi.data(), code_account.abi.size() );
fc::raw::unpack( ds, abi );
abis.setAbi( abi );
}
const auto& idx = d.get_index<chain::key128x128_value_index,chain::by_scope_primary>();
auto lower = idx.lower_bound( boost::make_tuple( p.scope, p.code, p.table, p.lower_bound ) );
auto upper = idx.upper_bound( boost::make_tuple( p.scope, p.code, p.table, p.upper_bound ) );
vector<char> data;
auto start = fc::time_point::now();
auto end = fc::time_point::now() + fc::microseconds( 1000*10 ); /// 10ms max time
int count = 0;
auto itr = lower;
for( itr = lower; itr != upper; ++itr ) {
data.resize( sizeof(uint128_t)*2 + itr->value.size() );
memcpy( data.data(), &itr->primary_key, sizeof(itr->primary_key) );
memcpy( data.data()+sizeof(uint128_t), &itr->secondary_key, sizeof(itr->secondary_key) );
memcpy( data.data()+sizeof(uint128_t)*2, itr->value.data(), itr->value.size() );
if( p.json )
result.rows.emplace_back( abis.binaryToVariant( abis.getTableType(p.table), data ) );
else
result.rows.emplace_back( fc::variant(data) );
if( ++count == p.limit || fc::time_point::now() > end )
break;
}
if( itr != upper )
result.more = true;
return result;
}
read_only::get_block_results read_only::get_block(const read_only::get_block_params& params) const {
try {
if (auto block = db.fetch_block_by_id(fc::json::from_string(params.block_num_or_id).as<chain::block_id_type>()))
......
......@@ -14,6 +14,7 @@ namespace eos {
using namespace appbase;
using chain::Name;
using fc::optional;
using chain::uint128_t;
namespace chain_apis {
struct empty{};
......@@ -106,6 +107,23 @@ public:
};
get_table_rows_i64_result get_table_rows_i64( const get_table_rows_i64_params& params )const;
struct get_table_rows_i128i128_primary_params {
bool json = false;
Name scope;
Name code;
Name table;
uint128_t lower_bound = 0;
uint128_t upper_bound = uint128_t(-1);
uint32_t limit = 10;
};
struct get_table_rows_i128i128_primary_result {
vector<fc::variant> rows; ///< one row per item, either encoded as hex String or JSON object
bool more; ///< true if last element in data is not the end and sizeof data() < limit
};
get_table_rows_i128i128_primary_result get_table_rows_i128i128_primary( const get_table_rows_i128i128_primary_params& params )const;
};
class read_write {
......@@ -172,6 +190,10 @@ FC_REFLECT( eos::chain_apis::read_only::get_table_rows_i64_params,
(json)(scope)(code)(table)(lower_bound)(upper_bound)(limit) );
FC_REFLECT( eos::chain_apis::read_only::get_table_rows_i64_result,
(rows)(more) );
FC_REFLECT( eos::chain_apis::read_only::get_table_rows_i128i128_primary_params,
(json)(scope)(code)(table)(lower_bound)(upper_bound)(limit) );
FC_REFLECT( eos::chain_apis::read_only::get_table_rows_i128i128_primary_result,
(rows)(more) );
FC_REFLECT( eos::chain_apis::read_only::get_account_results, (name)(eos_balance)(staked_balance)(unstaking_balance)(last_unstaking_time)(producer)(abi) )
FC_REFLECT( eos::chain_apis::read_only::get_account_params, (name) )
FC_REFLECT( eos::chain_apis::read_only::producer_info, (name) )
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册