提交 794033f5 编写于 作者: A arhag

Merge branch 'slim' into slim-resource-limits-fix2

......@@ -113,6 +113,26 @@ namespace eosiosystem {
// r->cpu_weight.amount );
}
/**
* This action will buy an exact amount of ram and bill the payer the current market price.
*/
void system_contract::buyrambytes( account_name payer, account_name receiver, uint32_t bytes ) {
const double system_token_supply = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount;
const double unstaked_token_supply = system_token_supply - _gstate.total_storage_stake.amount;
const double R = unstaked_token_supply;
const double C = _gstate.free_ram() + bytes;
const double F = _gstate.storage_reserve_ratio / 10000.0;
const double T = bytes;
const double ONE(1.0);
double E = -R * (ONE - std::pow( ONE + T/C, F ) );
int64_t tokens_out = int64_t(E*1.0105);
print( "desired ram: ", bytes, "\n" );
buyram( payer, receiver, asset(tokens_out) );
}
/**
......@@ -176,7 +196,7 @@ namespace eosiosystem {
* refunds the purchase price to the account. In this way there is no profit to be made through buying
* and selling ram.
*/
void system_contract::sellram( account_name account, uint64_t bytes ) {
void system_contract::sellram( account_name account, uint32_t bytes ) {
user_resources_table userres( _self, account );
auto res_itr = userres.find( account );
eosio_assert( res_itr != userres.end(), "no resource row" );
......
......@@ -6,6 +6,21 @@
"fields": [
{"name":"value", "type":"string"}
]
},{
"name": "buyrambytes",
"base": "",
"fields": [
{"name":"payer", "type":"account_name"},
{"name":"receiver", "type":"account_name"},
{"name":"bytes", "type":"uint32"}
]
},{
"name": "sellram",
"base": "",
"fields": [
{"name":"account", "type":"account_name"},
{"name":"bytes", "type":"uint32"}
]
},{
"name": "buyram",
"base": "",
......@@ -181,9 +196,17 @@
],
"actions": [
{
"name": "buyrambytes",
"type": "buyrambytes",
"ricardian_contract": ""
},{
"name": "buyram",
"type": "buyram",
"ricardian_contract": ""
},{
"name": "sellram",
"type": "sellram",
"ricardian_contract": ""
},{
"name": "delegatebw",
"type": "delegatebw",
......
......@@ -38,7 +38,7 @@ EOSIO_ABI( eosiosystem::system_contract,
(setparams)
// delegate_bandwith.cpp
(delegatebw)(undelegatebw)(refund)
(buyram)(sellram)
(buyram)(buyrambytes)(sellram)
// voting.cpp
(regproxy)(regproducer)(unregprod)(voteproducer)
// producer_pay.cpp
......
......@@ -156,12 +156,13 @@ namespace eosiosystem {
* tokens will be executed.
*/
void buyram( account_name buyer, account_name receiver, asset tokens );
void buyrambytes( account_name buyer, account_name receiver, uint32_t bytes );
/**
* Reduces quota my bytes and then performs an inline transfer of tokens
* to receiver based upon the average purchase price of the original quota.
*/
void sellram( account_name receiver, uint64_t bytes );
void sellram( account_name receiver, uint32_t bytes );
/**
* This action is called after the delegation-period to claim all pending
......
......@@ -78,6 +78,9 @@ void token::transfer( account_name from,
eosio_assert( quantity.is_valid(), "invalid quantity" );
eosio_assert( quantity.amount > 0, "must transfer positive quantity" );
if ( quantity.symbol.precision() != st.supply.symbol.precision() )
quantity.adjust_precision( st.supply.symbol );
sub_balance( from, quantity, st );
add_balance( to, quantity, st, from );
}
......
......@@ -251,6 +251,18 @@ namespace eosio {
symbol.print(false);
}
void adjust_precision(const symbol_type& ref_sym) {
eosio_assert(this->symbol.name() == ref_sym.name(), "comparison of symbols with different names is not allowed");
if (this->symbol.precision() == ref_sym.precision())
return;
eosio_assert(ref_sym.precision() >= this->symbol.precision(), "asset symbol has higher precision than expected");
for (uint8_t i = 0; i < ref_sym.precision() - this->symbol.precision(); ++i) {
printi(amount);
this->amount *= 10;
}
this->symbol.value = ref_sym.value;
}
EOSLIB_SERIALIZE( asset, (amount)(symbol) )
};
......
......@@ -41,7 +41,8 @@ extern "C" {
}
WASM_TEST_HANDLER(test_action, assert_true_cf);
require_auth(code);
if (action != WASM_TEST_ACTION("test_transaction", "stateful_api") && action != WASM_TEST_ACTION("test_transaction", "context_free_api"))
require_auth(code);
//test_types
WASM_TEST_HANDLER(test_types, types_size);
......@@ -139,6 +140,8 @@ extern "C" {
WASM_TEST_HANDLER(test_transaction, cancel_deferred_transaction);
WASM_TEST_HANDLER(test_transaction, send_cf_action);
WASM_TEST_HANDLER(test_transaction, send_cf_action_fail);
WASM_TEST_HANDLER(test_transaction, stateful_api);
WASM_TEST_HANDLER(test_transaction, context_free_api);
//test chain
WASM_TEST_HANDLER(test_chain, test_activeprods);
......
......@@ -170,6 +170,8 @@ struct test_transaction {
static void cancel_deferred_transaction();
static void send_cf_action();
static void send_cf_action_fail();
static void stateful_api();
static void context_free_api();
};
struct test_chain {
......
......@@ -287,3 +287,13 @@ void test_transaction::send_cf_action_fail() {
act.send_context_free();
eosio_assert(false, "send_cfa_action_fail() should've thrown an error");
}
void test_transaction::stateful_api() {
char buf[4] = {1};
db_store_i64(N(test_transaction), N(table), N(test_transaction), 0, buf, 4);
}
void test_transaction::context_free_api() {
char buf[128] = {0};
get_context_free_data(0, buf, sizeof(buf));
}
......@@ -63,10 +63,10 @@ namespace eosio {
static constexpr uint8_t max_precision = 18;
explicit symbol(uint8_t p, const char* s): m_value(string_to_symbol(p, s)) {
FC_ASSERT(valid(), "invalid symbol");
FC_ASSERT(valid(), "invalid symbol", ("s",s));
}
explicit symbol(uint64_t v = SY(4, EOS)): m_value(v) {
FC_ASSERT(valid(), "invalid symbol");
FC_ASSERT(valid(), "invalid symbol", ("name",name()));
}
static symbol from_string(const string& from)
{
......
......@@ -518,6 +518,113 @@ BOOST_FIXTURE_TEST_CASE(cfa_tx_signature, TESTER) try {
BOOST_REQUIRE_EQUAL( validate(), true );
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE(cfa_stateful_api, TESTER) try {
create_account( N(testapi) );
produce_blocks(1);
set_code( N(testapi), test_api_wast );
account_name a = N(testapi2);
account_name creator = N(eosio);
signed_transaction trx;
trx.actions.emplace_back( vector<permission_level>{{creator,config::active_name}},
newaccount{
.creator = creator,
.name = a,
.owner = authority( get_public_key( a, "owner" ) ),
.active = authority( get_public_key( a, "active" ) ),
.recovery = authority( get_public_key( a, "recovery" ) ),
});
action act({}, test_api_action<TEST_METHOD("test_transaction", "stateful_api")>{});
trx.context_free_actions.push_back(act);
set_transaction_headers(trx);
trx.sign( get_private_key( creator, "active" ), chain_id_type() );
BOOST_CHECK_EXCEPTION(push_transaction( trx ), fc::exception,
[&](const fc::exception &e) {
return expect_assert_message(e, "only context free api's can be used in this context");
});
BOOST_REQUIRE_EQUAL( validate(), true );
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE(deferred_cfa_failed, TESTER) try {
create_account( N(testapi) );
produce_blocks(1);
set_code( N(testapi), test_api_wast );
account_name a = N(testapi2);
account_name creator = N(eosio);
signed_transaction trx;
trx.actions.emplace_back( vector<permission_level>{{creator,config::active_name}},
newaccount{
.creator = creator,
.name = a,
.owner = authority( get_public_key( a, "owner" ) ),
.active = authority( get_public_key( a, "active" ) ),
.recovery = authority( get_public_key( a, "recovery" ) ),
});
action act({}, test_api_action<TEST_METHOD("test_transaction", "stateful_api")>{});
trx.context_free_actions.push_back(act);
set_transaction_headers(trx, 10, 2);
trx.sign( get_private_key( creator, "active" ), chain_id_type() );
BOOST_CHECK_EXCEPTION(push_transaction( trx ), fc::exception,
[&](const fc::exception &e) {
return expect_assert_message(e, "only context free api's can be used in this context");
});
produce_blocks(10);
// CFA failed, testapi2 not created
create_account( N(testapi2) );
BOOST_REQUIRE_EQUAL( validate(), true );
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE(deferred_cfa_success, TESTER) try {
create_account( N(testapi) );
produce_blocks(1);
set_code( N(testapi), test_api_wast );
account_name a = N(testapi2);
account_name creator = N(eosio);
signed_transaction trx;
trx.actions.emplace_back( vector<permission_level>{{creator,config::active_name}},
newaccount{
.creator = creator,
.name = a,
.owner = authority( get_public_key( a, "owner" ) ),
.active = authority( get_public_key( a, "active" ) ),
.recovery = authority( get_public_key( a, "recovery" ) ),
});
action act({}, test_api_action<TEST_METHOD("test_transaction", "context_free_api")>{});
trx.context_free_actions.push_back(act);
set_transaction_headers(trx, 10, 2);
trx.sign( get_private_key( creator, "active" ), chain_id_type() );
auto trace = push_transaction( trx );
BOOST_REQUIRE(trace != nullptr);
if (trace) {
BOOST_REQUIRE_EQUAL(transaction_receipt_header::status_enum::delayed, trace->receipt.status);
BOOST_REQUIRE_EQUAL(1, trace->action_traces.size());
}
produce_blocks(10);
// CFA success, testapi2 created
BOOST_CHECK_EXCEPTION(create_account( N(testapi2) ), fc::exception,
[&](const fc::exception &e) {
return expect_assert_message(e, "Cannot create account named testapi2, as that name is already taken");
});
BOOST_REQUIRE_EQUAL( validate(), true );
} FC_LOG_AND_RETHROW()
/*************************************************************************************
* checktime_tests test case
*************************************************************************************/
......
......@@ -52,6 +52,16 @@ class currency_tester : public TESTER {
return get_currency_balance(N(eosio.token), symbol(SY(4,CUR)), account);
}
auto transfer(const account_name& from, const account_name& to, const std::string& quantity, const std::string& memo = "") {
auto trace = push_action(from, N(transfer), mutable_variant_object()
("from", from)
("to", to)
("quantity", quantity)
("memo", memo)
);
produce_block();
return trace;
}
currency_tester()
:TESTER(),abi_ser(json::from_string(eosio_token_abi).as<abi_def>())
......@@ -295,10 +305,8 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, TESTER) try {
// invalid - contains lower case characters, no validation
{
symbol malformed(SY(6,EoS));
BOOST_REQUIRE_EQUAL(false, malformed.valid());
BOOST_REQUIRE_EQUAL("EoS", malformed.name());
BOOST_REQUIRE_EQUAL(6, malformed.decimals());
BOOST_CHECK_EXCEPTION(symbol malformed(SY(6,EoS)),
fc::assert_exception, fc_assert_exception_message_is("invalid symbol"));
}
// invalid - contains lower case characters, exception thrown
......@@ -524,4 +532,50 @@ BOOST_FIXTURE_TEST_CASE( test_deferred_failure, currency_tester ) try {
} FC_LOG_AND_RETHROW() /// test_currency
BOOST_FIXTURE_TEST_CASE( test_input_quantity, currency_tester ) try {
produce_blocks(2);
create_accounts( {N(alice), N(bob), N(carl)} );
// transfer to alice using right precision
{
auto trace = transfer(eosio_token, N(alice), "100.0000 CUR");
BOOST_CHECK_EQUAL(true, chain_has_transaction(trace->id));
BOOST_CHECK_EQUAL(asset::from_string( "100.0000 CUR"), get_balance(N(alice)));
BOOST_CHECK_EQUAL(1000000, get_balance(N(alice)).amount);
}
// transfer from alice to bob using no decimal point
{
auto trace = transfer(N(alice), N(bob), "13 CUR");
BOOST_CHECK_EQUAL(true, chain_has_transaction(trace->id));
BOOST_CHECK_EQUAL(asset::from_string("13.0000 CUR"), get_balance(N(bob)));
BOOST_CHECK_EQUAL(asset::from_string("87.0000 CUR"), get_balance(N(alice)));
}
// transfer from bob to carl using lower precision
{
auto trace = transfer(N(bob), N(carl), "2.01 CUR");
BOOST_CHECK_EQUAL(true, chain_has_transaction(trace->id));
BOOST_CHECK_EQUAL(asset::from_string("2.0100 CUR"), get_balance(N(carl)));
BOOST_CHECK_EQUAL(asset::from_string("10.9900 CUR"), get_balance(N(bob)));
}
// transfer using higher precision fails
{
BOOST_REQUIRE_EXCEPTION( transfer(N(alice), N(carl), "5.34567 CUR"), fc::assert_exception,
eosio_assert_message_is("asset symbol has higher precision than expected") );
}
// transfer using different symbol name fails
{
BOOST_REQUIRE_THROW(transfer(N(alice), N(carl), "20.50 USD"), fc::assert_exception);
}
} FC_LOG_AND_RETHROW() /// test_currency
BOOST_AUTO_TEST_SUITE_END()
......@@ -102,6 +102,17 @@ public:
return push_transaction( trx );
}
action_result buyram( const account_name& payer, account_name receiver, string eosin ) {
return push_action( payer, N(buyram), mvo()( "payer",payer)("receiver",receiver)("quant",eosin) );
}
action_result buyrambytes( const account_name& payer, account_name receiver, uint32_t numbytes ) {
return push_action( payer, N(buyrambytes), mvo()( "payer",payer)("receiver",receiver)("bytes",numbytes) );
}
action_result sellram( const account_name& account, uint32_t numbytes ) {
return push_action( account, N(sellram), mvo()( "account", account)("bytes",numbytes) );
}
action_result push_action( const account_name& signer, const action_name &name, const variant_object &data, bool auth = true ) {
string action_type_name = abi_ser.get_action_type(name);
......@@ -299,6 +310,9 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake, eosio_system_tester ) try {
BOOST_REQUIRE_EQUAL( asset::from_string("1000.0000 EOS"), get_balance( "alice" ) );
BOOST_REQUIRE_EQUAL( success(), stake( "alice", "bob", "200.0000 EOS", "100.0000 EOS" ) );
BOOST_REQUIRE_EQUAL( asset::from_string("700.0000 EOS"), get_balance( "alice" ) );
BOOST_REQUIRE_EQUAL( success(), buyram( "alice", "bob", "200.0000 EOS" ) );
BOOST_REQUIRE_EQUAL( success(), buyrambytes( "alice", "bob", 100 ) );
BOOST_REQUIRE_EQUAL( success(), sellram( "bob", 100 ) );
......
......@@ -131,6 +131,28 @@ BOOST_FIXTURE_TEST_CASE( create_negative_max_supply, eosio_token_tester ) try {
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE( symbol_already_exists, eosio_token_tester ) try {
auto token = create( N(alice), asset::from_string("100 TKN"), true, false, false);
auto stats = get_stats("0,TKN");
REQUIRE_MATCHING_OBJECT( stats, mvo()
("supply", "0 TKN")
("max_supply", "100 TKN")
("issuer", "alice")
("can_freeze",1)
("can_recall",0)
("can_whitelist",0)
("is_frozen",false)
("enforce_whitelist",false)
);
produce_blocks(1);
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: token with symbol already exists" ),
create( N(alice), asset::from_string("100 TKN"), true, false, false)
);
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE( create_max_supply, eosio_token_tester ) try {
auto token = create( N(alice), asset::from_string("4611686018427387903 TKN"), true, false, false);
......@@ -147,9 +169,13 @@ BOOST_FIXTURE_TEST_CASE( create_max_supply, eosio_token_tester ) try {
);
produce_blocks(1);
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: invalid supply" ),
create( N(alice), asset::from_string("4611686018427387904 TKN"), true, false, false)
);
asset max(10, symbol(SY(0, NKT)));
max.amount = 4611686018427387904;
BOOST_CHECK_EXCEPTION( create( N(alice), max, true, false, false) , asset_type_exception, [](const asset_type_exception& e) {
return expect_assert_message(e, "magnitude of asset amount must be less than 2^62");
});
} FC_LOG_AND_RETHROW()
......@@ -169,15 +195,13 @@ BOOST_FIXTURE_TEST_CASE( create_max_decimals, eosio_token_tester ) try {
);
produce_blocks(1);
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: invalid supply" ),
create( N(alice), asset::from_string("4.611686018427387904 TKN"), true, false, false)
);
asset max(10, symbol(SY(0, NKT)));
//1.0000000000000000000 => 0x8ac7230489e80000L
//TODO: Better error message
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: max-supply must be positive" ),
create( N(alice), asset::from_string("1.0000000000000000000 TKN"), true, false, false)
);
max.amount = 0x8ac7230489e80000L;
BOOST_CHECK_EXCEPTION( create( N(alice), max, true, false, false) , asset_type_exception, [](const asset_type_exception& e) {
return expect_assert_message(e, "magnitude of asset amount must be less than 2^62");
});
} FC_LOG_AND_RETHROW()
......@@ -211,10 +235,6 @@ BOOST_FIXTURE_TEST_CASE( issue_tests, eosio_token_tester ) try {
issue( N(alice), N(alice), asset::from_string("500.001 TKN"), "hola" )
);
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: invalid quantity" ),
issue( N(alice), N(alice), asset::from_string("4611686018427387.904 TKN"), "hola" )
);
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: must issue positive quantity" ),
issue( N(alice), N(alice), asset::from_string("-1.000 TKN"), "hola" )
);
......@@ -275,10 +295,6 @@ BOOST_FIXTURE_TEST_CASE( transfer_tests, eosio_token_tester ) try {
transfer( N(alice), N(bob), asset::from_string("701 CERO"), "hola" )
);
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: invalid quantity" ),
transfer( N(alice), N(bob), asset::from_string("4611686018427387904 CERO"), "hola" )
);
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: must transfer positive quantity" ),
transfer( N(alice), N(bob), asset::from_string("-1000 CERO"), "hola" )
);
......
......@@ -64,6 +64,12 @@ BOOST_AUTO_TEST_CASE(asset_from_string_overflow)
BOOST_CHECK_EXCEPTION( asset::from_string("-0.1000000000000000000 CUR") , assert_exception, [](const assert_exception& e) {
return expect_assert_message(e, "precision should be <= 18");
});
BOOST_CHECK_EXCEPTION( asset::from_string("1.0000000000000000000 CUR") , assert_exception, [](const assert_exception& e) {
return expect_assert_message(e, "precision should be <= 18");
});
BOOST_CHECK_EXCEPTION( asset::from_string("-1.0000000000000000000 CUR") , assert_exception, [](const assert_exception& e) {
return expect_assert_message(e, "precision should be <= 18");
});
// precision = 18, magnitude < 2^58
a = asset::from_string("0.100000000000000000 CUR");
......@@ -78,6 +84,12 @@ BOOST_AUTO_TEST_CASE(asset_from_string_overflow)
BOOST_CHECK_EXCEPTION( asset::from_string("-4.611686018427387904 CUR") , asset_type_exception, [](const asset_type_exception& e) {
return expect_assert_message(e, "magnitude of asset amount must be less than 2^62");
});
BOOST_CHECK_EXCEPTION( asset::from_string("4611686018427387.904 CUR") , asset_type_exception, [](const asset_type_exception& e) {
return expect_assert_message(e, "magnitude of asset amount must be less than 2^62");
});
BOOST_CHECK_EXCEPTION( asset::from_string("-4611686018427387.904 CUR") , asset_type_exception, [](const asset_type_exception& e) {
return expect_assert_message(e, "magnitude of asset amount must be less than 2^62");
});
// precision = 18, magnitude = 2^62-1
a = asset::from_string("4.611686018427387903 CUR");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册