RAM购买机制结合多种合约详解
945坏男人
发表于 2022-11-12 16:42:51
204
0
0
// native.hpp (newaccount definition is actually in eosio.system.cpp)
(newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror)' c5 h1 d/ }' h" h" g/ Y
// eosio.system.cpp) X: p: b; t+ P9 L7 w. [. `
(setram)(setparams)(setpriv)(rmvproducer)(bidname)' Z' i. @5 c0 V! H, Y, h
// delegate_bandwidth.cpp
(buyrambytes)(buyram)(sellram)(delegatebw)(undelegatebw)(refund)
// voting.cpp
(regproducer)(unregprod)(voteproducer)(regproxy)
// producer_pay.cpp
(onblock)(claimrewards)9 [+ T% f4 i) t( d6 i
ram,cpu和net操作相关方法的都定义在delegate_bandwidth.cpp,其中和RAM相关的是buyrambytes(通过指定字节数购买ram),buyram(通过指定货币购买ram)。
delegate_bandwidth.cpp
//根据当前市场的份额,将需要购买的字节数转化为指定的EOS进行购买
void system_contract::buyrambytes( account_name payer, account_name receiver, uint32_t bytes ) {" I4 v" O, S! }! |" K/ P9 t
//在数据库中查询RAMCORE发行量,默认为100000000000000- A# |/ x+ K7 b1 |
auto itr = _rammarket.find(S(4,RAMCORE));; S0 |" H5 q; q
auto tmp = *itr;$ l# R ?' F8 h- }# h! m
auto eosout = tmp.convert( asset(bytes,S(0,RAM)), CORE_SYMBOL );
//通过转化后,调用buyram使用EOS购买
buyram( payer, receiver, eosout );
}) I2 r) k* K2 o' g3 w/ I; |
解析
RAM的交易机制采用Bancor算法,使每字节的价格保持不变,通过中间代币(RAMCORE)来保证EOS和RAM之间的交易流通性。从上源码看首先获得RAMCORE的发行量,再通过tmp.convert方法RAM->RAMCORE,RAMCORE->EOS(CORE_SYMBOL)再调用buyram进行购买。这里的CORE_SYMBOL不一定是指EOS,查看core_symbol.hpp,发现源码内定义为SYS,也就是说在没有修改的前提下,需要提前发行SYS代币,才能进行RAM购买。
core_symbol.hpp K; w2 j2 V7 W0 }: m% Y9 l
#define CORE_SYMBOL S(4,SYS)
delegate_bandwidth.cpp
void system_contract::buyram(account_name payer, account_name receiver, asset quant)* K' T; \0 W, J# M7 ~ H
{
//验证权限' L* m9 H) f7 `1 J
require_auth(payer);" I" j; M6 S- j1 [! \& `
//不能为0+ q' W. S" F( f! @9 m
eosio_assert(quant.amount > 0, "must purchase a positive amount");3 f4 t7 r0 J/ Z
auto fee = quant;1 T, d B+ m: Z$ Z" d$ w J9 S6 x
//手续费为0.5%,如果amoun为1则手续费为1,如果小于1,则手续费在amoun 0)
{
INLINE_ACTION_SENDER(eosio::token, transfer)
(N(eosio.token), {payer, N(active)},8 [! |3 }- B5 I
{payer, N(eosio.ramfee), fee, std::string("ram fee")});. q6 d; Y+ v1 o* y. d
}
int64_t bytes_out;3 J- q% V/ T' x8 Y
//根据ram市场里的EOS和RAM实时汇率计算出能够购买的RAM总量* b- r1 k* r1 e, P2 _- @
const auto &market = _rammarket.get(S(4, RAMCORE), "ram market does not exist");
_rammarket.modify(market, 0, [&](auto &es) {
//转化方法请参考下半部分
bytes_out = es.convert(quant_after_fee, S(0, RAM)).amount;4 B* W$ K+ i. i" g
});
//剩余总量大于0判断
eosio_assert(bytes_out > 0, "must reserve a positive amount");: a7 D7 j. R' ~* e3 R
//更新全局变量,总共可以使用的内存大小* I% U; ]0 T3 W: u
_gstate.total_ram_bytes_reserved += uint64_t(bytes_out);9 J8 K Q8 ]3 w" l+ S: W# S
//更新全局变量,购买RAM冻结总金额3 s: T& J" P. b9 a& ?& @) T
_gstate.total_ram_stake += quant_after_fee.amount;' \% A2 R, ~7 J+ E& N
user_resources_table userres(_self, receiver);
auto res_itr = userres.find(receiver);
if (res_itr == userres.end())' P# D7 _# N- H" Z+ v
{. Q- R6 N6 N, T5 {9 V
//在userres表中添加ram相关记录 ~. T2 r5 R' F% Z: P
res_itr = userres.emplace(receiver, [&](auto &res) {; t* _* ^2 d$ ?, p
res.owner = receiver;7 R, L; ]4 ]. Y4 W( w' ^, x
res.ram_bytes = bytes_out;
});
}
else
{- Q# _; p/ r5 T3 ]
//在userres表中修改ram相关记录% d" c& g2 ?+ B) P7 A
userres.modify(res_itr, receiver, [&](auto &res) {2 B. h7 z- u% H y. H3 u; v
res.ram_bytes += bytes_out;- v( v( C; H, z( k5 s
});$ o5 F4 m0 S, C% \
}+ ^4 z. D, @. l* ^
//更新账号的RAM拥有量5 o1 i1 s' ~. `: Z/ O
set_resource_limits(res_itr->owner, res_itr->ram_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount);
}( R# E, t. w9 p! [! ?
相关注释已经在代码中,这里还会用到一个比较重要的内容,那就是代币转化为RAM的公式,此方法请参考下面, 这方面还未深入研究会在接下来补充。- _+ v8 ~( e4 [1 }
exchange_state.cpp: j7 o+ G* f' i! ?
asset exchange_state::convert_to_exchange( connector& c, asset in ) {( T' I/ h; {1 A m9 x8 Q* q5 l
real_type R(supply.amount); //RAM已经售出的总量
real_type C(c.balance.amount+in.amount); //RAM总购买金额+本次购买的量
real_type F(c.weight/1000.0);
real_type T(in.amount);
real_type ONE(1.0);
real_type E = -R * (ONE - std::pow( ONE + T / C, F) );//换算出EOS对应的RAM量
//print( "E: ", E, "\n");5 l. p7 w# o2 j" h0 ?0 D
int64_t issued = int64_t(E);
supply.amount += issued;//更新RAM已经售出的总量/ D% d0 m* k; z& H# D! ^, f
c.balance.amount += in.amount;//更新RAM总购买金额
return asset( issued, supply.symbol );( W8 B* t) y! [$ ]( R5 s% N9 G
}
9 g. |: n+ m9 g) q- t+ y
asset exchange_state::convert( asset from, symbol_type to ) {* u, }5 S# y, Z5 ~* f' w# o
auto sell_symbol = from.symbol; * l! A3 q9 O6 H$ `+ l
auto ex_symbol = supply.symbol; 9 y6 y$ {. N! E0 y1 S' k
auto base_symbol = base.balance.symbol;
auto quote_symbol = quote.balance.symbol;
3 K ^/ c3 k: d& r, B
//根据币种转化可以购买的RAM量
if( sell_symbol != ex_symbol ) {
if( sell_symbol == base_symbol ) {
from = convert_to_exchange( base, from );
} else if( sell_symbol == quote_symbol ) {
from = convert_to_exchange( quote, from );" h5 s, G0 b K' U2 c
} else { ' E7 i% @% r9 K4 K4 E: W
eosio_assert( false, "invalid sell" );
}
} else {$ F! ] M& T/ r) y0 B
if( to == base_symbol ) {
from = convert_from_exchange( base, from ); 7 O, V3 p( K6 G8 U S
} else if( to == quote_symbol ) {
from = convert_from_exchange( quote, from );
} else {5 X% Z& x6 ]( s: ]2 U% ^- C: c
eosio_assert( false, "invalid conversion" );' _! d) A' B- o% ^
}
}
if( to != from.symbol )
return convert( from, to );
return from;% R/ q ]9 ^" D4 C4 e
}: z$ Z: [' W0 a' P: o6 t. c5 i. T4 w6 l
convert_to_exchange的转化公式如下。: w4 o$ P) U9 H" D9 J9 Y6 @5 g
; E% Y3 @+ c W0 F
ram购买的量是一个绝对值,是根据购买EOS的金额和当前市场内ram的数量计算出来的。一般来说在ram总量不增加的情况下,一样金额的EOS,所能获得的ram会越来越少。所以如果早期你购买了ram,然后过段时间后通过sellram卖掉ram可能还能挣钱。
成为第一个吐槽的人