-
Notifications
You must be signed in to change notification settings - Fork 71
/
Copy patheosio.system.cpp
318 lines (272 loc) · 11.9 KB
/
eosio.system.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
#include "eosio.system.hpp"
#include <eosio/dispatcher.hpp>
#include <eosio/crypto.hpp>
#include "producer_pay.cpp"
#include "delegate_bandwidth.cpp"
#include "voting.cpp"
#include "exchange_state.cpp"
#include "rex.cpp"
namespace eosiosystem {
system_contract::system_contract( name s, name code, datastream<const char*> ds )
:native(s,code,ds),
_voters(_self, _self.value),
_producers(_self, _self.value),
_producers2(_self, _self.value),
_global(_self, _self.value),
_global2(_self, _self.value),
_global3(_self, _self.value),
_rammarket(_self, _self.value),
_rexpool(_self, _self.value),
_rexfunds(_self, _self.value),
_rexbalance(_self, _self.value),
_rexorders(_self, _self.value)
{
//print( "construct system\n" );
_gstate = _global.exists() ? _global.get() : get_default_parameters();
_gstate2 = _global2.exists() ? _global2.get() : eosio_global_state2{};
_gstate3 = _global3.exists() ? _global3.get() : eosio_global_state3{};
}
eosio_global_state system_contract::get_default_parameters() {
eosio_global_state dp;
get_blockchain_parameters(dp);
return dp;
}
symbol system_contract::core_symbol()const {
const static auto sym = get_core_symbol( _rammarket );
return sym;
}
system_contract::~system_contract() {
_global.set( _gstate, _self );
_global2.set( _gstate2, _self );
_global3.set( _gstate3, _self );
}
void system_contract::setram( uint64_t max_ram_size ) {
require_auth( _self );
check( _gstate.max_ram_size < max_ram_size, "ram may only be increased" ); /// decreasing ram might result market maker issues
check( max_ram_size < 1024ll*1024*1024*1024*1024, "ram size is unrealistic" );
check( max_ram_size > _gstate.total_ram_bytes_reserved, "attempt to set max below reserved" );
auto delta = int64_t(max_ram_size) - int64_t(_gstate.max_ram_size);
auto itr = _rammarket.find(ramcore_symbol.raw());
/**
* Increase the amount of ram for sale based upon the change in max ram size.
*/
_rammarket.modify( itr, same_payer, [&]( auto& m ) {
m.base.balance.amount += delta;
});
_gstate.max_ram_size = max_ram_size;
}
void system_contract::update_ram_supply() {
auto cbt = current_block_time();
if( cbt <= _gstate2.last_ram_increase ) return;
auto itr = _rammarket.find(ramcore_symbol.raw());
auto new_ram = (cbt.slot - _gstate2.last_ram_increase.slot)*_gstate2.new_ram_per_block;
_gstate.max_ram_size += new_ram;
/**
* Increase the amount of ram for sale based upon the change in max ram size.
*/
_rammarket.modify( itr, same_payer, [&]( auto& m ) {
m.base.balance.amount += new_ram;
});
_gstate2.last_ram_increase = cbt;
}
/**
* Sets the rate of increase of RAM in bytes per block. It is capped by the uint16_t to
* a maximum rate of 3 TB per year.
*
* If update_ram_supply hasn't been called for the most recent block, then new ram will
* be allocated at the old rate up to the present block before switching the rate.
*/
void system_contract::setramrate( uint16_t bytes_per_block ) {
require_auth( _self );
update_ram_supply();
_gstate2.new_ram_per_block = bytes_per_block;
}
void system_contract::setparams( const eosio::blockchain_parameters& params ) {
require_auth( _self );
(eosio::blockchain_parameters&)(_gstate) = params;
check( 3 <= _gstate.max_authority_depth, "max_authority_depth should be at least 3" );
set_blockchain_parameters( params );
}
void system_contract::setpriv( name account, uint8_t ispriv ) {
require_auth( _self );
set_privileged( account, ispriv );
}
void system_contract::setalimits( name account, int64_t ram, int64_t net, int64_t cpu ) {
require_auth( _self );
user_resources_table userres( _self, account.value );
auto ritr = userres.find( account.value );
check( ritr == userres.end(), "only supports unlimited accounts" );
set_resource_limits( account, ram, net, cpu );
}
void system_contract::rmvproducer( name producer ) {
require_auth( _self );
auto prod = _producers.find( producer.value );
check( prod != _producers.end(), "producer not found" );
_producers.modify( prod, same_payer, [&](auto& p) {
p.deactivate();
});
}
void system_contract::updtrevision( uint8_t revision ) {
require_auth( _self );
check( _gstate2.revision < 255, "can not increment revision" ); // prevent wrap around
check( revision == _gstate2.revision + 1, "can only increment revision by one" );
check( revision <= 1, // set upper bound to greatest revision supported in the code
"specified revision is not yet supported by the code" );
_gstate2.revision = revision;
}
void system_contract::bidname( name bidder, name newname, asset bid ) {
require_auth( bidder );
check( newname.suffix() == newname, "you can only bid on top-level suffix" );
check( (bool)newname, "the empty name is not a valid account name to bid on" );
check( (newname.value & 0xFull) == 0, "13 character names are not valid account names to bid on" );
check( (newname.value & 0x1F0ull) == 0, "accounts with 12 character names and no dots can be created without bidding required" );
check( !is_account( newname ), "account already exists" );
check( bid.symbol == core_symbol(), "asset must be system token" );
check( bid.amount > 0, "insufficient bid" );
INLINE_ACTION_SENDER(eosio::token, transfer)(
token_account, { {bidder, active_permission} },
{ bidder, names_account, bid, std::string("bid name ")+ newname.to_string() }
);
name_bid_table bids(_self, _self.value);
print( name{bidder}, " bid ", bid, " on ", name{newname}, "\n" );
auto current = bids.find( newname.value );
if( current == bids.end() ) {
bids.emplace( bidder, [&]( auto& b ) {
b.newname = newname;
b.high_bidder = bidder;
b.high_bid = bid.amount;
b.last_bid_time = current_time_point();
});
} else {
check( current->high_bid > 0, "this auction has already closed" );
check( bid.amount - current->high_bid > (current->high_bid / 10), "must increase bid by 10%" );
check( current->high_bidder != bidder, "account is already highest bidder" );
bid_refund_table refunds_table(_self, newname.value);
auto it = refunds_table.find( current->high_bidder.value );
if ( it != refunds_table.end() ) {
refunds_table.modify( it, same_payer, [&](auto& r) {
r.amount += asset( current->high_bid, core_symbol() );
});
} else {
refunds_table.emplace( bidder, [&](auto& r) {
r.bidder = current->high_bidder;
r.amount = asset( current->high_bid, core_symbol() );
});
}
transaction t;
t.actions.emplace_back( permission_level{_self, active_permission},
_self, "bidrefund"_n,
std::make_tuple( current->high_bidder, newname )
);
t.delay_sec = 0;
uint128_t deferred_id = (uint128_t(newname.value) << 64) | current->high_bidder.value;
cancel_deferred( deferred_id );
t.send( deferred_id, bidder );
bids.modify( current, bidder, [&]( auto& b ) {
b.high_bidder = bidder;
b.high_bid = bid.amount;
b.last_bid_time = current_time_point();
});
}
}
void system_contract::bidrefund( name bidder, name newname ) {
bid_refund_table refunds_table(_self, newname.value);
auto it = refunds_table.find( bidder.value );
check( it != refunds_table.end(), "refund not found" );
INLINE_ACTION_SENDER(eosio::token, transfer)(
token_account, { {names_account, active_permission}, {bidder, active_permission} },
{ names_account, bidder, asset(it->amount), std::string("refund bid on name ")+(name{newname}).to_string() }
);
refunds_table.erase( it );
}
/**
* Called after a new account is created. This code enforces resource-limits rules
* for new accounts as well as new account naming conventions.
*
* Account names containing '.' symbols must have a suffix equal to the name of the creator.
* This allows users who buy a premium name (shorter than 12 characters with no dots) to be the only ones
* who can create accounts with the creator's name as a suffix.
*
*/
void native::newaccount( name creator,
name newact,
ignore<authority> owner,
ignore<authority> active ) {
if( creator != _self ) {
uint64_t tmp = newact.value >> 4;
bool has_dot = false;
for( uint32_t i = 0; i < 12; ++i ) {
has_dot |= !(tmp & 0x1f);
tmp >>= 5;
}
if( has_dot ) { // or is less than 12 characters
auto suffix = newact.suffix();
if( suffix == newact ) {
name_bid_table bids(_self, _self.value);
auto current = bids.find( newact.value );
check( current != bids.end(), "no active bid for name" );
check( current->high_bidder == creator, "only highest bidder can claim" );
check( current->high_bid < 0, "auction for name is not closed yet" );
bids.erase( current );
} else {
check( creator == suffix, "only suffix may create this account" );
}
}
}
user_resources_table userres( _self, newact.value);
userres.emplace( newact, [&]( auto& res ) {
res.owner = newact;
res.net_weight = asset( 0, system_contract::get_core_symbol() );
res.cpu_weight = asset( 0, system_contract::get_core_symbol() );
});
set_resource_limits( newact, 0, 0, 0 );
}
void native::setabi( name acnt, const std::vector<char>& abi ) {
eosio::multi_index< "abihash"_n, abi_hash > table(_self, _self.value);
auto itr = table.find( acnt.value );
if( itr == table.end() ) {
table.emplace( acnt, [&]( auto& row ) {
row.owner= acnt;
row.hash = eosio::sha256( const_cast<char*>(abi.data()), abi.size());
});
} else {
table.modify( itr, same_payer, [&]( auto& row ) {
row.hash = eosio::sha256( const_cast<char*>(abi.data()), abi.size() );
});
}
}
void system_contract::init( unsigned_int version, symbol core ) {
require_auth( _self );
check( version.value == 0, "unsupported version for init action" );
auto itr = _rammarket.find(ramcore_symbol.raw());
check( itr == _rammarket.end(), "system contract has already been initialized" );
auto system_token_supply = eosio::token::get_supply(token_account, core.code() );
check( system_token_supply.symbol == core, "specified core symbol does not exist (precision mismatch)" );
check( system_token_supply.amount > 0, "system token supply must be greater than 0" );
_rammarket.emplace( _self, [&]( auto& m ) {
m.supply.amount = 100000000000000ll;
m.supply.symbol = ramcore_symbol;
m.base.balance.amount = int64_t(_gstate.free_ram());
m.base.balance.symbol = ram_symbol;
m.quote.balance.amount = system_token_supply.amount / 1000;
m.quote.balance.symbol = core;
});
INLINE_ACTION_SENDER(eosio::token, open)( token_account, { _self, active_permission },
{ rex_account, core, _self } );
}
} /// eosio.system
EOSIO_DISPATCH( eosiosystem::system_contract,
// native.hpp (newaccount definition is actually in eosio.system.cpp)
(newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror)(setabi)
// eosio.system.cpp
(init)(setram)(setramrate)(setparams)(setpriv)(setalimits)(rmvproducer)(updtrevision)(bidname)(bidrefund)
// rex.cpp
(deposit)(withdraw)(buyrex)(unstaketorex)(sellrex)(cnclrexorder)(rentcpu)(rentnet)(fundcpuloan)(fundnetloan)
(defcpuloan)(defnetloan)(updaterex)(consolidate)(rexexec)(closerex)
// delegate_bandwidth.cpp
(buyrambytes)(buyram)(sellram)(delegatebw)(undelegatebw)(refund)
// voting.cpp
(regproducer)(unregprod)(voteproducer)(regproxy)
// producer_pay.cpp
(onblock)(claimrewards)
)