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

initial work to general purpose binary to json and json to binary via abi

上级 6359b180
......@@ -36,6 +36,7 @@
#include <eos/types/native.hpp>
#include <eos/types/generated.hpp>
#include <eos/types/AbiSerializer.hpp>
#include <eos/utilities/rand.hpp>
......@@ -1076,5 +1077,88 @@ void chain_controller::set_apply_handler( const AccountName& contract, const Acc
chain_initializer_interface::~chain_initializer_interface() {}
SignedTransaction chain_controller::transaction_from_variant( const fc::variant& v )const {
const variant_object& vo = v.get_object();
#define GET_FIELD( VO, FIELD, RESULT ) \
if( VO.contains(#FIELD) ) fc::from_variant( VO[#FIELD], RESULT.FIELD )
SignedTransaction result;
GET_FIELD( vo, refBlockNum, result );
GET_FIELD( vo, refBlockPrefix, result );
GET_FIELD( vo, expiration, result );
GET_FIELD( vo, scope, result );
GET_FIELD( vo, signatures, result );
if( vo.contains( "messages" ) ) {
const vector<variant>& msgs = vo["messages"].get_array();
result.messages.resize( msgs.size() );
for( uint32_t i = 0; i < msgs.size(); ++i ) {
const auto& vo = msgs[i].get_object();
GET_FIELD( vo, code, result.messages[i] );
GET_FIELD( vo, type, result.messages[i] );
GET_FIELD( vo, recipients, result.messages[i] );
GET_FIELD( vo, authorization, result.messages[i] );
if( vo.contains( "data" ) ) {
const auto& data = vo["data"];
if( data.is_string() ) {
GET_FIELD( vo, data, result.messages[i] );
} else if ( data.is_object() ) {
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() );
eos::types::Abi abi;
fc::raw::unpack( ds, abi );
types::AbiSerializer abis( abi );
result.messages[i].data = abis.variantToBinary( abis.getActionType( result.messages[i].type ), data );
}
}
}
}
}
return result;
#undef GET_FIELD
}
fc::variant chain_controller::transaction_to_variant( const SignedTransaction& trx )const {
#define SET_FIELD( MVO, OBJ, FIELD ) MVO(#FIELD, OBJ.FIELD)
fc::mutable_variant_object trx_mvo;
SET_FIELD( trx_mvo, trx, refBlockNum );
SET_FIELD( trx_mvo, trx, refBlockPrefix );
SET_FIELD( trx_mvo, trx, expiration );
SET_FIELD( trx_mvo, trx, scope );
SET_FIELD( trx_mvo, trx, signatures );
vector<fc::mutable_variant_object> msgs( trx.messages.size() );
vector<fc::variant> msgsv(msgs.size());
for( uint32_t i = 0; i < trx.messages.size(); ++i ) {
auto& msg_mvo = msgs[i];
auto& msg = trx.messages[i];
SET_FIELD( msg_mvo, msg, code );
SET_FIELD( msg_mvo, msg, type );
SET_FIELD( msg_mvo, msg, recipients );
SET_FIELD( msg_mvo, msg, authorization );
const auto& code_account = _db.get<account_object,by_name>( msg.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 );
msg_mvo( "data", abis.binaryToVariant( abis.getActionType( msg.type ), msg.data ) );
}
else {
SET_FIELD( msg_mvo, msg, data );
}
msgsv[i] = std::move( msgs[i] );
}
trx_mvo( "messages", std::move(msgsv) );
return fc::variant( std::move( trx_mvo ) );
#undef SET_FIELD
}
} }
......@@ -30,15 +30,22 @@
namespace eos { namespace chain {
class account_object : public chainbase::object<account_object_type, account_object> {
OBJECT_CTOR(account_object,(code))
OBJECT_CTOR(account_object,(code)(abi))
id_type id;
AccountName name;
uint8_t vm_type = 0;
uint8_t vm_version = 0;
fc::sha256 code_version;
shared_vector<char> code;
Time creation_date;
shared_vector<char> code;
shared_vector<char> abi;
void set_abi( const eos::types::Abi& _abi ) {
abi.resize( fc::raw::pack_size( _abi ) );
fc::datastream<char*> ds( abi.data(), abi.size() );
fc::raw::pack( ds, _abi );
}
};
using account_id_type = account_object::id_type;
......
......@@ -109,7 +109,20 @@ namespace eos { namespace chain {
optional<signed_block> fetch_block_by_id( const block_id_type& id )const;
optional<signed_block> fetch_block_by_number( uint32_t num )const;
const SignedTransaction& get_recent_transaction( const transaction_id_type& trx_id )const;
std::vector<block_id_type> get_block_ids_on_fork(block_id_type head_of_fork) const;
std::vector<block_id_type> get_block_ids_on_fork(block_id_type head_of_fork)const;
/**
* This method will convert a variant to a SignedTransaction using a contract's ABI to
* interpret the message types.
*/
SignedTransaction transaction_from_variant( const fc::variant& v )const;
/**
* This method will convert a signed transaction into a human-friendly variant that can be
* converted to JSON.
*/
fc::variant transaction_to_variant( const SignedTransaction& trx )const;
/**
* Calculate the percent of block production slots that were missed in the
......
......@@ -76,7 +76,7 @@ void validate_eos_transfer(message_validate_context& context) {
#warning TODO: should transfer validate that the sender is in the provided authorites
auto transfer = context.msg.as<types::transfer>();
try {
EOS_ASSERT(transfer.amount > Asset(0), message_validate_exception, "Must transfer a positive amount");
EOS_ASSERT(transfer.amount > 0, message_validate_exception, "Must transfer a positive amount");
context.require_recipient(transfer.to);
context.require_recipient(transfer.from);
......@@ -93,7 +93,7 @@ void precondition_eos_transfer(precondition_validate_context& context) {
try {
db.get<account_object,by_name>(transfer.to); ///< make sure this exists
const auto& from = db.get<BalanceObject, byOwnerName>(transfer.from);
EOS_ASSERT(from.balance >= transfer.amount.amount, message_precondition_exception, "Insufficient Funds",
EOS_ASSERT(from.balance >= transfer.amount, message_precondition_exception, "Insufficient Funds",
("from.balance",from.balance)("transfer.amount",transfer.amount));
} FC_CAPTURE_AND_RETHROW((transfer))
}
......@@ -105,10 +105,10 @@ void apply_eos_transfer(apply_context& context) {
const auto& from = db.get<BalanceObject, byOwnerName>(transfer.from);
const auto& to = db.get<BalanceObject, byOwnerName>(transfer.to);
db.modify(from, [&](BalanceObject& a) {
a.balance -= transfer.amount.amount;
a.balance -= ShareType(transfer.amount);
});
db.modify(to, [&](BalanceObject& a) {
a.balance += transfer.amount.amount;
a.balance += ShareType(transfer.amount);
});
} FC_CAPTURE_AND_RETHROW( (transfer) )
}
......
......@@ -102,6 +102,14 @@ std::vector<chain::Message> native_contract_chain_initializer::prepare_database(
db.create<account_object>([this, &name](account_object& a) {
a.name = name;
a.creation_date = genesis.initial_timestamp;
if( name == config::EosContractName ) {
types::Abi eos_abi;
eos_abi.types.push_back( types::TypeDef{"AccountName","Name"} );
eos_abi.actions.push_back( types::Action{Name("transfer"), "transfer"} );
eos_abi.structs.push_back( eos::types::GetStruct<eos::types::transfer>::type() );
a.set_abi(eos_abi);
}
});
db.create<native::eos::BalanceObject>([&name, liquidBalance]( auto& b) {
b.ownerName = name;
......@@ -131,7 +139,7 @@ std::vector<chain::Message> native_contract_chain_initializer::prepare_database(
message = chain::Message(config::EosContractName, vector<AccountName>{config::SystemContractName, acct.name},
vector<types::AccountPermission>{},
"transfer", types::transfer(config::SystemContractName, acct.name,
acct.liquid_balance, "Genesis Allocation"));
acct.liquid_balance.amount/*, "Genesis Allocation"*/));
messages_to_process.emplace_back(std::move(message));
}
}
......
......@@ -7,16 +7,24 @@
#include <eos/chain/global_property_object.hpp>
#include <eos/chain/wasm_interface.hpp>
#include <eos/types/AbiSerializer.hpp>
namespace native {
namespace system {
using namespace chain;
using eos::types::AbiSerializer;
namespace config = ::eos::config;
void validate_system_setcode(message_validate_context& context) {
auto msg = context.msg.as<types::setcode>();
FC_ASSERT( msg.vmtype == 0 );
FC_ASSERT( msg.vmversion == 0 );
/// if an ABI is specified make sure it is well formed and doesn't
/// reference any undefined types
AbiSerializer( msg.abi ).validate();
#warning TODO: verify code compiles and is properly sanitized
}
......@@ -37,6 +45,8 @@ void apply_system_setcode(apply_context& context) {
a.code_version = fc::sha256::hash( msg.code.data(), msg.code.size() );
a.code.resize( msg.code.size() );
memcpy( a.code.data(), msg.code.data(), msg.code.size() );
a.set_abi( msg.abi );
});
apply_context init_context( context.mutable_controller, context.mutable_db, context.trx, context.msg, msg.account );
......
......@@ -4,6 +4,7 @@ add_library( eos_types
Asset.cpp
PublicKey.cpp
TypeParser.cpp
AbiSerializer.cpp
native.cpp
${HEADERS}
"${CMAKE_CURRENT_SOURCE_DIR}/include/eos/types/generated.hpp"
......
......@@ -34,8 +34,6 @@ public:
*/
void parse(std::istream& in);
string binaryToJson(const TypeName& type, const Bytes& binary);
Bytes jsonToBinary(const TypeName& type, const string& json);
};
......@@ -56,14 +54,15 @@ public:
virtual Struct getType(TypeName name) const override;
virtual TypeName resolveTypedef(TypeName name) const override;
// private:
set<TypeName> known;
const set<TypeName> known;
vector<TypeName> order;
map<TypeName, TypeName> typedefs;
map<TypeName, Struct> structs;
};
}} // namespace eos::types
FC_REFLECT(eos::types::SimpleSymbolTable, (typedefs)(structs))
......@@ -51,11 +51,28 @@ struct BlockchainConfiguration
minEosBalance ShareType
maxTrxLifetime UInt32
struct TypeDef
newTypeName TypeName
type TypeName
struct Action
action Name
type TypeName
struct Table
table Name
type TypeName
struct Abi
types TypeDef[]
structs Struct[]
actions Action[]
tables Table[]
struct transfer
from AccountName # may not be the message.sender if message.sender has delegated authority by from
to AccountName
amount Asset
memo String
amount UInt64
struct lock
from AccountName
......@@ -83,6 +100,7 @@ struct setcode
vmtype UInt8 # the virtual machine type
vmversion UInt8 # the virtual machine version
code Bytes # the apply
abi Abi # the interface description of the code
struct setproducer
......
......@@ -209,7 +209,7 @@ read_write::push_block_results read_write::push_block(const read_write::push_blo
read_write::push_transaction_results read_write::push_transaction(const read_write::push_transaction_params& params) {
db.push_transaction(params);
return read_write::push_transaction_results();
return read_write::push_transaction_results{ params.id() };
}
} // namespace chain_apis
......
......@@ -64,7 +64,9 @@ public:
push_block_results push_block(const push_block_params& params);
using push_transaction_params = chain::SignedTransaction;
using push_transaction_results = empty;
struct push_transaction_results {
chain::transaction_id_type transaction_id;
};
push_transaction_results push_transaction(const push_transaction_params& params);
};
} // namespace chain_apis
......@@ -110,3 +112,4 @@ FC_REFLECT(eos::chain_apis::read_only::get_info_results,
FC_REFLECT(eos::chain_apis::read_only::get_block_params, (block_num_or_id))
FC_REFLECT_DERIVED( eos::chain_apis::read_only::get_block_results, (eos::chain::signed_block), (id)(block_num)(refBlockPrefix) );
FC_REFLECT( eos::chain_apis::read_write::push_transaction_results, (transaction_id) )
......@@ -62,18 +62,18 @@ inline std::vector<Name> sort_names( std::vector<Name>&& names ) {
#define MKACCT7(chain, name, creator, deposit, owner, active, recovery) \
MKACCT_IMPL(chain, name, creator, owner, active, recovery, deposit)
#define XFER5(chain, sender, recipient, amount, memo) \
#define XFER5(chain, sender, recipient, Amount, memo) \
{ \
eos::chain::SignedTransaction trx; \
trx.scope = sort_names({#sender,#recipient}); \
trx.emplaceMessage(config::EosContractName, vector<AccountName>{#sender, #recipient}, \
vector<types::AccountPermission>{}, \
"transfer", types::transfer{#sender, #recipient, amount, memo}); \
"transfer", types::transfer{#sender, #recipient, Amount.amount/*, memo*/}); \
boost::sort(trx.messages.back().recipients); \
trx.expiration = chain.head_block_time() + 100; \
trx.set_reference_block(chain.head_block_id()); \
chain.push_transaction(trx); \
BOOST_TEST_CHECKPOINT("Transfered " << amount << " from " << #sender << " to " << #recipient); \
BOOST_TEST_CHECKPOINT("Transfered " << Amount << " from " << #sender << " to " << #recipient); \
}
#define XFER4(chain, sender, recipient, amount) XFER5(chain, sender, recipient, amount, "")
......
......@@ -47,93 +47,6 @@ using namespace eos;
using namespace chain;
/*
* This code is saved because it provides an alternative implementation of string to int conversion.
struct Tame {
uint64_t value = 0;
bool valid()const { return 0 == (value >> 60); }
bool empty()const { return 0 == value; }
bool good()const { return !empty() && valid(); }
Tame( const char* str ) { set(str); }
Tame( const String& str ) { set( str.c_str() ); }
void set( const char* str ) {
try {
idump((std::string(str)));
const auto len = strnlen(str,14);
value = 0;
FC_ASSERT( len <= 13 );
for( uint32_t i = 0; i < len && i < 12; ++i )
value |= uint64_t(char_to_symbol( str[i] )) << (59-(i*5));
if( len == 13 )
value |= (0x0f & char_to_symbol( str[ 12 ] ));
}FC_CAPTURE_AND_RETHROW( (str) ) }
uint8_t char_to_symbol( char c ) const {
static const char* charmap = ".abcdefghijklmnopqrstuvwxyz12345";
if( c >= 'a' && c <= 'z' ) {
idump((int(((c-'a') + 1)))(string()+c));
// FC_ASSERT( charmap[((c-'a') + 1)] == c );
return uint8_t(c - 'a') + 1;
}
if( c >= '1' && c <= '5' ) {
idump((int(((c-'1') + 26)))(string()+c));
// FC_ASSERT( charmap[((c-'1') + 26)] == c );
return uint8_t(c - '1') + 27;
}
FC_ASSERT( c == '.', "invalid character '${c}' (${i}) in Tame string", ("c", String(&c,1))("i",int(c)) );
return 0;
}
Tame( uint64_t v = 0 ):value(v){
// FC_ASSERT( !(v>>(5*12)), "invalid name id" );
}
explicit operator String()const {
static const char* charmap = ".abcdefghijklmnopqrstuvwxyz12345";
String str;
uint64_t tmp = value;
for( uint32_t i = 0; i < 12; ++i ) {
str += charmap[ 0x1f & (tmp >> (59-i*5)) ];
}
str += charmap[0x0f & tmp];
boost::algorithm::trim_right_if( str, []( char c ){ return c == '.'; } );
return str;
}
String toString() const { return String(*this); }
Tame& operator=( uint64_t v ) {
value = v;
return *this;
}
Tame& operator=( const String& n ) {
value = Tame(n).value;
return *this;
}
Tame& operator=( const char* n ) {
value = Tame(n).value;
return *this;
}
template<typename Stream>
friend Stream& operator << ( Stream& out, const Tame& n ) {
return out << String(n);
}
friend bool operator < ( const Tame& a, const Tame& b ) { return a.value < b.value; }
friend bool operator > ( const Tame& a, const Tame& b ) { return a.value > b.value; }
friend bool operator == ( const Tame& a, const Tame& b ) { return a.value == b.value; }
friend bool operator != ( const Tame& a, const Tame& b ) { return a.value != b.value; }
operator bool()const { return value; }
operator uint64_t()const { return value; }
};
*/
BOOST_AUTO_TEST_SUITE(block_tests)
......@@ -222,6 +135,41 @@ BOOST_AUTO_TEST_CASE(schedule_test) {
}
///@} end of schedule test
BOOST_FIXTURE_TEST_CASE(trx_variant, testing_fixture) {
try {
Make_Blockchain(chain)
Name from("from"), to("to");
uint64_t amount = 10;
eos::chain::SignedTransaction trx;
trx.scope = sort_names({from,to});
trx.emplaceMessage("eos", sort_names( {from,to} ),
vector<types::AccountPermission>{ {from,"active"} },
"transfer", types::transfer{from, to, amount/*, ""*/});
trx.expiration = chain.head_block_time() + 100;
trx.set_reference_block(chain.head_block_id());
auto original = fc::raw::pack( trx );
auto var = chain.transaction_to_variant( trx );
auto from_var = chain.transaction_from_variant( var );
auto _process = fc::raw::pack( from_var );
/*
idump((trx));
idump((var));
idump((from_var));
idump((original));
idump((_process));
*/
FC_ASSERT( original == _process, "Transaction seralization not reversible" );
} catch ( const fc::exception& e ) {
edump((e.to_detail_string()));
throw;
}
}
BOOST_AUTO_TEST_CASE(name_test) {
using eos::types::Name;
Name temp;
......
......@@ -93,7 +93,7 @@ BOOST_FIXTURE_TEST_CASE(transfer, testing_fixture)
trx.scope = sort_names( {"inita", "initb"} );
trx.messages[0].recipients = {"inita", config::EosContractName};
types::transfer trans = { "inita", "initb", Asset(100), "transfer 100" };
types::transfer trans = { "inita", "initb", (100)/*, "transfer 100"*/ };
UInt64 value(5);
auto packed = fc::raw::pack(value);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册