提交 b6553c8d 编写于 作者: D Daniel Larimer

Added support for uploading and calling contracts to eosc

- added account fetching in CLI
- added currency.abi file describing currency contract's ABI
上级 a39b4340
{
"types": [{
"newTypeName": "AccountName",
"type": "Name"
}
],
"structs": [{
"name": "transfer",
"base": "",
"fields": {
"from": "AccountName",
"to": "AccountName",
"amount": "UInt64"
}
},{
"name" : "account",
"fields" : {
"key" : "UInt64",
"balance" : "UInt64"
}
}
],
"actions": [{
"action": "transfer",
"type": "transfer"
}
],
"tables": [{"table":"account","type":"account"}]
}
......@@ -1083,6 +1083,8 @@ ProcessedTransaction chain_controller::transaction_from_variant( const fc::varia
if( data.is_string() ) {
GET_FIELD( vo, data, result.messages[i] );
} else if ( data.is_object() ) {
result.messages[i].data = message_to_binary( result.messages[i].code, result.messages[i].type, data );
/*
const auto& code_account = _db.get<account_object,by_name>( result.messages[i].code );
if( code_account.abi.size() > 4 ) { /// 4 == packsize of empty Abi
fc::datastream<const char*> ds( code_account.abi.data(), code_account.abi.size() );
......@@ -1091,6 +1093,7 @@ ProcessedTransaction chain_controller::transaction_from_variant( const fc::varia
types::AbiSerializer abis( abi );
result.messages[i].data = abis.variantToBinary( abis.getActionType( result.messages[i].type ), data );
}
*/
}
}
}
......@@ -1102,6 +1105,19 @@ ProcessedTransaction chain_controller::transaction_from_variant( const fc::varia
#undef GET_FIELD
}
vector<char> chain_controller::message_to_binary( Name code, Name type, const fc::variant& obj )const {
wdump((obj));
const auto& code_account = _db.get<account_object,by_name>( code );
if( code_account.abi.size() > 4 ) { /// 4 == packsize of empty Abi
fc::datastream<const char*> ds( code_account.abi.data(), code_account.abi.size() );
eos::types::Abi abi;
fc::raw::unpack( ds, abi );
types::AbiSerializer abis( abi );
return abis.variantToBinary( abis.getActionType( type ), obj );
}
return vector<char>();
}
fc::variant chain_controller::transaction_to_variant( const ProcessedTransaction& trx )const {
#define SET_FIELD( MVO, OBJ, FIELD ) MVO(#FIELD, OBJ.FIELD)
......
......@@ -122,6 +122,11 @@ namespace eos { namespace chain {
*/
fc::variant transaction_to_variant( const ProcessedTransaction& trx )const;
/**
* Usees the ABI for code::type to convert a JSON object (variant) into hex
*/
vector<char> message_to_binary( Name code, Name type, const fc::variant& obj )const;
/**
* Calculate the percent of block production slots that were missed in the
......
#include <eos/types/AbiSerializer.hpp>
#include <fc/io/raw.hpp>
#include <boost/algorithm/string/predicate.hpp>
namespace eos { namespace types {
......@@ -35,6 +36,8 @@ namespace eos { namespace types {
}
bool AbiSerializer::isType( const TypeName& type )const {
static const std::set<TypeName> native = {"Name","UInt64"};
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;
return false;
......@@ -49,7 +52,7 @@ namespace eos { namespace types {
void AbiSerializer::validate()const {
for( const auto& t : typedefs ) { try {
FC_ASSERT( isType( t.second ) );
FC_ASSERT( isType( t.second ), "", ("type",t.second) );
} FC_CAPTURE_AND_RETHROW( (t) ) }
for( const auto& s : structs ) { try {
if( s.second.base != TypeName() )
......@@ -59,11 +62,11 @@ namespace eos { namespace types {
} FC_CAPTURE_AND_RETHROW( (field) ) }
} FC_CAPTURE_AND_RETHROW( (s) ) }
for( const auto& a : actions ) { try {
FC_ASSERT( isType( a.second ) );
FC_ASSERT( isType( a.second ), "", ("type",a.second) );
} FC_CAPTURE_AND_RETHROW( (a) ) }
for( const auto& t : tables ) { try {
FC_ASSERT( isType( t.second ) );
FC_ASSERT( isType( t.second ), "", ("type",t.second) );
} FC_CAPTURE_AND_RETHROW( (t) ) }
}
......
......@@ -50,7 +50,9 @@ void chain_api_plugin::plugin_startup() {
app().get_plugin<http_plugin>().add_api({
CHAIN_RO_CALL(get_info),
CHAIN_RO_CALL(get_block),
CHAIN_RO_CALL(get_account),
CHAIN_RO_CALL(get_table_rows_i64),
CHAIN_RO_CALL(abi_json_to_bin),
CHAIN_RW_CALL(push_block),
CHAIN_RW_CALL(push_transaction)
});
......
......@@ -7,6 +7,8 @@
#include <eos/native_contract/native_contract_chain_initializer.hpp>
#include <eos/native_contract/native_contract_chain_administrator.hpp>
#include <eos/native_contract/staked_balance_objects.hpp>
#include <eos/native_contract/balance_object.hpp>
#include <eos/native_contract/genesis_state.hpp>
#include <eos/types/AbiSerializer.hpp>
......@@ -260,5 +262,38 @@ read_write::push_transaction_results read_write::push_transaction(const read_wri
return read_write::push_transaction_results{ params.id(), pretty_trx };
}
read_only::get_account_results read_only::get_account( const get_account_params& params )const {
using namespace native::eos;
get_account_results result;
result.name = params.name;
const auto& d = db.get_database();
const auto& accnt = d.get<account_object,by_name>( params.name );
const auto& balance = d.get<BalanceObject,byOwnerName>( params.name );
const auto& staked_balance = d.get<StakedBalanceObject,byOwnerName>( params.name );
if( accnt.abi.size() > 4 ) {
eos::types::Abi abi;
fc::datastream<const char*> ds( accnt.abi.data(), accnt.abi.size() );
fc::raw::unpack( ds, abi );
result.abi = std::move(abi);
}
result.eos_balance = balance.balance;
result.staked_balance = staked_balance.stakedBalance;
result.unstaking_balance = staked_balance.unstakingBalance;
result.last_unstaking_time = staked_balance.lastUnstakingTime;
return result;
}
read_only::abi_json_to_bin_result read_only::abi_json_to_bin( const read_only::abi_json_to_bin_params& params )const {
abi_json_to_bin_result result;
idump((params));
result.binargs = db.message_to_binary( params.code, params.action, params.args );
return result;
}
} // namespace chain_apis
} // namespace eos
......@@ -13,6 +13,7 @@ namespace eos {
using std::unique_ptr;
using namespace appbase;
using chain::Name;
using fc::optional;
namespace chain_apis {
struct empty{};
......@@ -27,16 +28,49 @@ public:
using get_info_params = empty;
struct get_info_results {
uint32_t head_block_num;
uint32_t last_irreversible_block_num;
chain::block_id_type head_block_id;
fc::time_point_sec head_block_time;
types::AccountName head_block_producer;
string recent_slots;
double participation_rate;
uint32_t head_block_num = 0;
uint32_t last_irreversible_block_num = 0;
chain::block_id_type head_block_id;
fc::time_point_sec head_block_time;
types::AccountName head_block_producer;
string recent_slots;
double participation_rate = 0;
};
get_info_results get_info(const get_info_params&) const;
struct producer_info {
Name name;
};
struct get_account_results {
Name name;
uint64_t eos_balance = 0;
uint64_t staked_balance = 0;
uint64_t unstaking_balance = 0;
fc::time_point_sec last_unstaking_time;
optional<producer_info> producer;
optional<types::Abi> abi;
};
struct get_account_params {
Name name;
};
get_account_results get_account( const get_account_params& params )const;
struct abi_json_to_bin_params {
Name code;
Name action;
fc::variant args;
};
struct abi_json_to_bin_result {
vector<char> binargs;
vector<Name> required_scope;
vector<Name> required_auth;
};
abi_json_to_bin_result abi_json_to_bin( const abi_json_to_bin_params& params )const;
struct get_block_params {
string block_num_or_id;
};
......@@ -138,3 +172,8 @@ 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_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) )
FC_REFLECT( eos::chain_apis::read_only::abi_json_to_bin_params, (code)(action)(args) )
FC_REFLECT( eos::chain_apis::read_only::abi_json_to_bin_result, (binargs)(required_scope)(required_auth) )
......@@ -129,21 +129,34 @@ namespace eos {
my->server.set_http_handler([&](connection_hdl hdl) {
auto con = my->server.get_con_from_hdl(hdl);
ilog("handle http request: ${url}", ("url",con->get_uri()->str()));
ilog("${body}", ("body", con->get_request_body()));
auto body = con->get_request_body();
auto resource = con->get_uri()->get_resource();
auto handler_itr = my->url_handlers.find(resource);
if(handler_itr != my->url_handlers.end()) {
handler_itr->second(resource, body, [con,this](int code, string body) {
con->set_body(body);
con->set_status(websocketpp::http::status_code::value(code));
});
} else {
wlog("404 - not found: ${ep}", ("ep",resource));
con->set_body("Unknown Endpoint");
con->set_status(websocketpp::http::status_code::not_found);
try {
ilog("handle http request: ${url}", ("url",con->get_uri()->str()));
ilog("${body}", ("body", con->get_request_body()));
auto body = con->get_request_body();
auto resource = con->get_uri()->get_resource();
auto handler_itr = my->url_handlers.find(resource);
if(handler_itr != my->url_handlers.end()) {
handler_itr->second(resource, body, [con,this](int code, string body) {
con->set_body(body);
con->set_status(websocketpp::http::status_code::value(code));
});
} else {
wlog("404 - not found: ${ep}", ("ep",resource));
con->set_body("Unknown Endpoint");
con->set_status(websocketpp::http::status_code::not_found);
}
} catch( const fc::exception& e ) {
elog( "http: ${e}", ("e",e.to_detail_string()));
con->set_body(e.to_detail_string());
con->set_status(websocketpp::http::status_code::internal_server_error);
} catch( const std::exception& e ) {
elog( "http: ${e}", ("e",e.what()));
con->set_body(e.what());
con->set_status(websocketpp::http::status_code::internal_server_error);
} catch( ... ) {
con->set_body("unknown exception");
con->set_status(websocketpp::http::status_code::internal_server_error);
}
});
......@@ -153,6 +166,10 @@ namespace eos {
my->http_ios.run();
ilog("http io service exit");
} catch ( const fc::exception& e ){
elog( "http: ${e}", ("e",e.to_detail_string()));
} catch ( const std::exception& e ){
elog( "http: ${e}", ("e",e.what()));
} catch (...) {
elog("error thrown from http io service");
}
......
......@@ -23,6 +23,7 @@ fc::variant call( const std::string& server, uint16_t port,
const std::string& path,
const fc::variant& postdata )
{ try {
idump((postdata));
std::string postjson;
if( !postdata.is_null() )
......
......@@ -11,6 +11,15 @@
#include <eos/utilities/key_conversion.hpp>
#include <boost/range/algorithm/sort.hpp>
#include <Inline/BasicTypes.h>
#include <IR/Module.h>
#include <IR/Validate.h>
#include <WAST/WAST.h>
#include <WASM/WASM.h>
#include <Runtime/Runtime.h>
#include <fc/io/fstream.hpp>
using namespace std;
using namespace eos;
......@@ -24,6 +33,41 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
return names;
}
vector<uint8_t> assemble_wast( const std::string& wast ) {
// std::cout << "\n" << wast << "\n";
IR::Module module;
std::vector<WAST::Error> parseErrors;
WAST::parseModule(wast.c_str(),wast.size(),module,parseErrors);
if(parseErrors.size())
{
// Print any parse errors;
std::cerr << "Error parsing WebAssembly text file:" << std::endl;
for(auto& error : parseErrors)
{
std::cerr << ":" << error.locus.describe() << ": " << error.message.c_str() << std::endl;
std::cerr << error.locus.sourceLine << std::endl;
std::cerr << std::setw(error.locus.column(8)) << "^" << std::endl;
}
FC_ASSERT( !"error parsing wast" );
}
try
{
// Serialize the WebAssembly module.
Serialization::ArrayOutputStream stream;
WASM::serialize(stream,module);
return stream.getBytes();
}
catch(Serialization::FatalSerializationException exception)
{
std::cerr << "Error serializing WebAssembly binary file:" << std::endl;
std::cerr << exception.message << std::endl;
throw;
}
}
fc::variant call( const std::string& server, uint16_t port,
const std::string& path,
const fc::variant& postdata = fc::variant() );
......@@ -105,10 +149,70 @@ int main( int argc, char** argv ) {
FC_ASSERT( args.size() == 3 );
std::cout << fc::json::to_pretty_string( call( "localhost", 8888, "/v1/chain/get_block", fc::mutable_variant_object( "block_num_or_id", args[2]) ) );
}
else if( command == "exec" ) {
FC_ASSERT( args.size() >= 7 );
Name code = args[2];
Name action = args[3];
auto& json = args[4];
auto result = call( "localhost", 8888, "/v1/chain/abi_json_to_bin", fc::mutable_variant_object( "code", code )("action",action)("args", fc::json::from_string(json)) );
std::cout << fc::json::to_pretty_string(result) << "\n";
SignedTransaction trx;
//trx.scope = { config::EosContractName, code };
trx.messages.resize(1);
auto& msg = trx.messages.back();
msg.code = code;
msg.type = action;
msg.authorization = fc::json::from_string( args[6] ).as<vector<types::AccountPermission>>();
msg.data = result.get_object()["binargs"].as<Bytes>();
trx.scope = fc::json::from_string( args[5] ).as<vector<Name>>();
auto trx_result = push_transaction( trx );
std::cout << fc::json::to_pretty_string( trx_result ) <<"\n";
} else if( command == "account" ) {
FC_ASSERT( args.size() == 3 );
std::cout << fc::json::to_pretty_string( call( "localhost", 8888, "/v1/chain/get_account", fc::mutable_variant_object( "name", args[2] ) ) );
}
else if( command == "push-trx" ) {
std::cout << fc::json::to_pretty_string( call( "localhost", 8888, "/v1/chain/push_transaction",
fc::json::from_string(args[2])) );
} else if( command == "transfer" ) {
} else if ( command == "setcode" ) {
if( args.size() == 2 ) {
std::cout << "usage: "<<args[0] << " " << args[1] <<" ACCOUNT FILE.WAST FILE.ABI\n";
return -1;
}
Name account(args[2]);
const auto& wast_file = args[3];
std::string wast;
FC_ASSERT( fc::exists(wast_file) );
fc::read_file_contents( wast_file, wast );
auto wasm = assemble_wast( wast );
types::setcode handler;
handler.account = account;
handler.code.resize(wasm.size());
memcpy( handler.code.data(), wasm.data(), wasm.size() );
if( args.size() == 5 ) {
handler.abi = fc::json::from_file( args[4] ).as<types::Abi>();
}
SignedTransaction trx;
trx.scope = { config::EosContractName, account };
trx.emplaceMessage( config::EosContractName,
vector<types::AccountPermission>{ {account,"active"} },
"setcode", handler );
std::cout << fc::json::to_pretty_string( push_transaction(trx) );
}else if( command == "transfer" ) {
FC_ASSERT( args.size() == 5 );
Name sender(args[2]);
Name recipient(args[3]);
uint64_t amount = fc::variant(argv[4]).as_uint64();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册