Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
YottaChain
YTBP
提交
8880865f
Y
YTBP
项目概览
YottaChain
/
YTBP
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Y
YTBP
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
8880865f
编写于
5月 24, 2019
作者:
W
Wang Zhi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add temp dev folder for eosio.system contract
上级
540fe08b
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
2263 addition
and
0 deletion
+2263
-0
contracts/CMakeLists.txt
contracts/CMakeLists.txt
+2
-0
contracts/eosio.system_dev/CMakeLists.txt
contracts/eosio.system_dev/CMakeLists.txt
+8
-0
contracts/eosio.system_dev/README.md
contracts/eosio.system_dev/README.md
+84
-0
contracts/eosio.system_dev/delegate_bandwidth.cpp
contracts/eosio.system_dev/delegate_bandwidth.cpp
+426
-0
contracts/eosio.system_dev/eosio.system.abi
contracts/eosio.system_dev/eosio.system.abi
+590
-0
contracts/eosio.system_dev/eosio.system.hpp
contracts/eosio.system_dev/eosio.system.hpp
+248
-0
contracts/eosio.system_dev/eosio.system_dev.cpp
contracts/eosio.system_dev/eosio.system_dev.cpp
+209
-0
contracts/eosio.system_dev/exchange_state.cpp
contracts/eosio.system_dev/exchange_state.cpp
+85
-0
contracts/eosio.system_dev/exchange_state.hpp
contracts/eosio.system_dev/exchange_state.hpp
+40
-0
contracts/eosio.system_dev/native.hpp
contracts/eosio.system_dev/native.hpp
+112
-0
contracts/eosio.system_dev/producer_pay.cpp
contracts/eosio.system_dev/producer_pay.cpp
+171
-0
contracts/eosio.system_dev/voting.cpp
contracts/eosio.system_dev/voting.cpp
+288
-0
未找到文件。
contracts/CMakeLists.txt
浏览文件 @
8880865f
...
...
@@ -33,6 +33,8 @@ add_subdirectory(integration_test)
add_subdirectory
(
hddpool
)
add_subdirectory
(
hdddeposit
)
add_subdirectory
(
eosio.system_dev
)
file
(
GLOB SKELETONS RELATIVE
${
CMAKE_SOURCE_DIR
}
/contracts
"skeleton/*"
)
...
...
contracts/eosio.system_dev/CMakeLists.txt
0 → 100644
浏览文件 @
8880865f
file
(
GLOB ABI_FILES
"*.abi"
)
configure_file
(
"
${
ABI_FILES
}
"
"
${
CMAKE_CURRENT_BINARY_DIR
}
"
COPYONLY
)
add_wast_executable
(
TARGET eosio.system_dev
INCLUDE_FOLDERS
${
STANDARD_INCLUDE_FOLDERS
}
LIBRARIES libc++ libc eosiolib eosio.token
DESTINATION_FOLDER
${
CMAKE_CURRENT_BINARY_DIR
}
)
contracts/eosio.system_dev/README.md
0 → 100644
浏览文件 @
8880865f
eosio.system
----------
This contract enables users to stake tokens, and then configure and vote on producers and worker proposals.
Users can also proxy their voting influence to other users.
The state of this contract is read to determine the 21 active block producers.
Actions:
The naming convention is codeaccount::actionname followed by a list of paramters.
Indicates that a particular account wishes to become a producer
## eosio.system::cfgproducer account config
-
**account**
the producer account to update
-
updates the configuration settings for a particular producer, these
Storage changes are billed to 'account'
## eosio.system::okproducer account producer vote
-
**account**
the account which is doing the voting
-
**producer**
the producer which is being voted for (or unvoted for)
-
**vote**
true if the producer should be voted for, false if not
Each account has a maximum number of votes it can maintain. Storage changes will be billed to 'account'
## eosio.system::setproxy account proxy
-
**account**
the account which is updating it's proxy
-
**proxy**
the account which will have the power to vote account's stake
All current votes are removed and a new proxy link is created. The votes for every producer the proxy
has voted for are updated immediately.
Storage changes will be billed to 'account'
## eosio.system::unstake account quantity
-
**account**
- the account which is requesting their balance be unstaked
-
**quantity**
- the quantity which will be unstaked, unstaked tokens lose voting influence immediately
-
in order to unstake tokens, an account must request them. The user will receive them over
time via weekly withdraws. The length of time will be configured by the median time as set by
the active producers.
-
If this is called while in the process of unstaking, the currently pending unstake is canceled as if
quantity were 0, then it is applied as if a new unstake request was made.
-
all producers this 'from' has voted for will have their votes updated immediately.
-
bandwidth and storage for the deferred transaction will be billed to 'from'
## eosio.system::withdraw account
-
this action can only be triggered by eosio.system via a deferred transaction generated by unstake
-
this will generate an inline eosio.token::transfer call from=eosio.system to=account and amount equal to the next withdraw increment
-
this will generate another deferred withdraw to continue the process if there are still withdraws to be made
## eosio.system::transfer from to amount memo
-
decrements balance of from if amount <= balance
-
increments balance of to by amount
-
memo is ignored
## eosio.system::stakevote account amount
-
the primary currency of eosio is controlled by the token contract which enables users to transfer
balances from one user to another. The receiver is notified on incoming balances and the vote contract
will stake the tokens on receipt.
-
all producers this 'from' has voted for will have their votes updated immediately.
## eosio.system::onblock account blocktime blocknum
-
this special action is triggered when a block is applied by the given producer and cannot be generated from
any other source. It is used to pay producers and calculate missed blocks of other producers.
-
producer pay is deposited into the producer's stake balance and can be withdrawn over time.
-
if blocknum is the start of a new round this may update the active producer config from the producer votes.
## eosio.system::freeze producer accounts true|false
-
requires permission of the @producers account
-
if an account is frozen, all authorizations of that account are rejected and the code for that account will not be run
## eosio.system::paystandby producer
-
every block some amount of tokens is paid
-
at most once per day a producer may claim a percentage of the standby pay equal to their totalvotes / allvotes
contracts/eosio.system_dev/delegate_bandwidth.cpp
0 → 100644
浏览文件 @
8880865f
/**
* @file
* @copyright defined in eos/LICENSE
*/
#include "eosio.system.hpp"
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
#include <eosiolib/datastream.hpp>
#include <eosiolib/serialize.hpp>
#include <eosiolib/multi_index.hpp>
#include <eosiolib/privileged.h>
#include <eosiolib/transaction.hpp>
#include <eosio.token/eosio.token.hpp>
#include <cmath>
#include <map>
namespace
eosiosystem
{
using
eosio
::
asset
;
using
eosio
::
indexed_by
;
using
eosio
::
const_mem_fun
;
using
eosio
::
bytes
;
using
eosio
::
print
;
using
eosio
::
permission_level
;
using
std
::
map
;
using
std
::
pair
;
static
constexpr
time
refund_delay
=
3
*
24
*
3600
;
static
constexpr
time
refund_expiration_time
=
3600
;
struct
user_resources
{
account_name
owner
;
asset
net_weight
;
asset
cpu_weight
;
int64_t
ram_bytes
=
0
;
uint64_t
primary_key
()
const
{
return
owner
;
}
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE
(
user_resources
,
(
owner
)(
net_weight
)(
cpu_weight
)(
ram_bytes
)
)
};
/**
* Every user 'from' has a scope/table that uses every receipient 'to' as the primary key.
*/
struct
delegated_bandwidth
{
account_name
from
;
account_name
to
;
asset
net_weight
;
asset
cpu_weight
;
uint64_t
primary_key
()
const
{
return
to
;
}
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE
(
delegated_bandwidth
,
(
from
)(
to
)(
net_weight
)(
cpu_weight
)
)
};
struct
refund_request
{
account_name
owner
;
time
request_time
;
eosio
::
asset
net_amount
;
eosio
::
asset
cpu_amount
;
uint64_t
primary_key
()
const
{
return
owner
;
}
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE
(
refund_request
,
(
owner
)(
request_time
)(
net_amount
)(
cpu_amount
)
)
};
/**
* These tables are designed to be constructed in the scope of the relevant user, this
* facilitates simpler API for per-user queries
*/
typedef
eosio
::
multi_index
<
N
(
userres
),
user_resources
>
user_resources_table
;
typedef
eosio
::
multi_index
<
N
(
delband
),
delegated_bandwidth
>
del_bandwidth_table
;
typedef
eosio
::
multi_index
<
N
(
refunds
),
refund_request
>
refunds_table
;
/**
* 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
)
{
auto
itr
=
_rammarket
.
find
(
S
(
4
,
RAMCORE
));
auto
tmp
=
*
itr
;
auto
eosout
=
tmp
.
convert
(
asset
(
bytes
,
S
(
0
,
RAM
)),
CORE_SYMBOL
);
buyram
(
payer
,
receiver
,
eosout
);
}
/**
* When buying ram the payer irreversiblly transfers quant to system contract and only
* the receiver may reclaim the tokens via the sellram action. The receiver pays for the
* storage of all database records associated with this action.
*
* RAM is a scarce resource whose supply is defined by global properties max_ram_size. RAM is
* priced using the bancor algorithm such that price-per-byte with a constant reserve ratio of 100:1.
*/
void
system_contract
::
buyram
(
account_name
payer
,
account_name
receiver
,
asset
quant
)
{
require_auth
(
payer
);
eosio_assert
(
quant
.
amount
>
0
,
"must purchase a positive amount"
);
auto
fee
=
quant
;
fee
.
amount
=
(
fee
.
amount
+
199
)
/
200
;
/// .5% fee (round up)
// fee.amount cannot be 0 since that is only possible if quant.amount is 0 which is not allowed by the assert above.
// If quant.amount == 1, then fee.amount == 1,
// otherwise if quant.amount > 1, then 0 < fee.amount < quant.amount.
auto
quant_after_fee
=
quant
;
quant_after_fee
.
amount
-=
fee
.
amount
;
// quant_after_fee.amount should be > 0 if quant.amount > 1.
// If quant.amount == 1, then quant_after_fee.amount == 0 and the next inline transfer will fail causing the buyram action to fail.
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
payer
,
N
(
active
)},
{
payer
,
N
(
eosio
.
ram
),
quant_after_fee
,
std
::
string
(
"buy ram"
)
}
);
if
(
fee
.
amount
>
0
)
{
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
payer
,
N
(
active
)},
{
payer
,
N
(
eosio
.
ramfee
),
fee
,
std
::
string
(
"ram fee"
)
}
);
}
int64_t
bytes_out
;
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
;
});
eosio_assert
(
bytes_out
>
0
,
"must reserve a positive amount"
);
_gstate
.
total_ram_bytes_reserved
+=
uint64_t
(
bytes_out
);
_gstate
.
total_ram_stake
+=
quant_after_fee
.
amount
;
user_resources_table
userres
(
_self
,
receiver
);
auto
res_itr
=
userres
.
find
(
receiver
);
if
(
res_itr
==
userres
.
end
()
)
{
res_itr
=
userres
.
emplace
(
receiver
,
[
&
](
auto
&
res
)
{
res
.
owner
=
receiver
;
res
.
ram_bytes
=
bytes_out
;
});
}
else
{
userres
.
modify
(
res_itr
,
receiver
,
[
&
](
auto
&
res
)
{
res
.
ram_bytes
+=
bytes_out
;
});
}
set_resource_limits
(
res_itr
->
owner
,
res_itr
->
ram_bytes
,
res_itr
->
net_weight
.
amount
,
res_itr
->
cpu_weight
.
amount
);
}
/**
* The system contract now buys and sells RAM allocations at prevailing market prices.
* This may result in traders buying RAM today in anticipation of potential shortages
* tomorrow. Overall this will result in the market balancing the supply and demand
* for RAM over time.
*/
void
system_contract
::
sellram
(
account_name
account
,
int64_t
bytes
)
{
require_auth
(
account
);
eosio_assert
(
bytes
>
0
,
"cannot sell negative byte"
);
user_resources_table
userres
(
_self
,
account
);
auto
res_itr
=
userres
.
find
(
account
);
eosio_assert
(
res_itr
!=
userres
.
end
(),
"no resource row"
);
eosio_assert
(
res_itr
->
ram_bytes
>=
bytes
,
"insufficient quota"
);
asset
tokens_out
;
auto
itr
=
_rammarket
.
find
(
S
(
4
,
RAMCORE
));
_rammarket
.
modify
(
itr
,
0
,
[
&
](
auto
&
es
)
{
/// the cast to int64_t of bytes is safe because we certify bytes is <= quota which is limited by prior purchases
tokens_out
=
es
.
convert
(
asset
(
bytes
,
S
(
0
,
RAM
)),
CORE_SYMBOL
);
});
eosio_assert
(
tokens_out
.
amount
>
1
,
"token amount received from selling ram is too low"
);
_gstate
.
total_ram_bytes_reserved
-=
static_cast
<
decltype
(
_gstate
.
total_ram_bytes_reserved
)
>
(
bytes
);
// bytes > 0 is asserted above
_gstate
.
total_ram_stake
-=
tokens_out
.
amount
;
//// this shouldn't happen, but just in case it does we should prevent it
eosio_assert
(
_gstate
.
total_ram_stake
>=
0
,
"error, attempt to unstake more tokens than previously staked"
);
userres
.
modify
(
res_itr
,
account
,
[
&
](
auto
&
res
)
{
res
.
ram_bytes
-=
bytes
;
});
set_resource_limits
(
res_itr
->
owner
,
res_itr
->
ram_bytes
,
res_itr
->
net_weight
.
amount
,
res_itr
->
cpu_weight
.
amount
);
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
N
(
eosio
.
ram
),
N
(
active
)},
{
N
(
eosio
.
ram
),
account
,
asset
(
tokens_out
),
std
::
string
(
"sell ram"
)
}
);
auto
fee
=
(
tokens_out
.
amount
+
199
)
/
200
;
/// .5% fee (round up)
// since tokens_out.amount was asserted to be at least 2 earlier, fee.amount < tokens_out.amount
if
(
fee
>
0
)
{
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
account
,
N
(
active
)},
{
account
,
N
(
eosio
.
ramfee
),
asset
(
fee
),
std
::
string
(
"sell ram fee"
)
}
);
}
}
void
validate_b1_vesting
(
int64_t
stake
)
{
const
int64_t
base_time
=
1527811200
;
/// 2018-06-01
const
int64_t
max_claimable
=
100'000'000'0000ll
;
const
int64_t
claimable
=
int64_t
(
max_claimable
*
double
(
now
()
-
base_time
)
/
(
10
*
seconds_per_year
)
);
eosio_assert
(
max_claimable
-
claimable
<=
stake
,
"b1 can only claim their tokens over 10 years"
);
}
void
system_contract
::
changebw
(
account_name
from
,
account_name
receiver
,
const
asset
stake_net_delta
,
const
asset
stake_cpu_delta
,
bool
transfer
)
{
require_auth
(
from
);
eosio_assert
(
stake_net_delta
!=
asset
(
0
)
||
stake_cpu_delta
!=
asset
(
0
),
"should stake non-zero amount"
);
eosio_assert
(
std
::
abs
(
(
stake_net_delta
+
stake_cpu_delta
).
amount
)
>=
std
::
max
(
std
::
abs
(
stake_net_delta
.
amount
),
std
::
abs
(
stake_cpu_delta
.
amount
)
),
"net and cpu deltas cannot be opposite signs"
);
account_name
source_stake_from
=
from
;
if
(
transfer
)
{
from
=
receiver
;
}
// update stake delegated from "from" to "receiver"
{
del_bandwidth_table
del_tbl
(
_self
,
from
);
auto
itr
=
del_tbl
.
find
(
receiver
);
if
(
itr
==
del_tbl
.
end
()
)
{
itr
=
del_tbl
.
emplace
(
from
,
[
&
](
auto
&
dbo
){
dbo
.
from
=
from
;
dbo
.
to
=
receiver
;
dbo
.
net_weight
=
stake_net_delta
;
dbo
.
cpu_weight
=
stake_cpu_delta
;
});
}
else
{
del_tbl
.
modify
(
itr
,
0
,
[
&
](
auto
&
dbo
){
dbo
.
net_weight
+=
stake_net_delta
;
dbo
.
cpu_weight
+=
stake_cpu_delta
;
});
}
eosio_assert
(
asset
(
0
)
<=
itr
->
net_weight
,
"insufficient staked net bandwidth"
);
eosio_assert
(
asset
(
0
)
<=
itr
->
cpu_weight
,
"insufficient staked cpu bandwidth"
);
if
(
itr
->
net_weight
==
asset
(
0
)
&&
itr
->
cpu_weight
==
asset
(
0
)
)
{
del_tbl
.
erase
(
itr
);
}
}
// itr can be invalid, should go out of scope
// update totals of "receiver"
{
user_resources_table
totals_tbl
(
_self
,
receiver
);
auto
tot_itr
=
totals_tbl
.
find
(
receiver
);
if
(
tot_itr
==
totals_tbl
.
end
()
)
{
tot_itr
=
totals_tbl
.
emplace
(
from
,
[
&
](
auto
&
tot
)
{
tot
.
owner
=
receiver
;
tot
.
net_weight
=
stake_net_delta
;
tot
.
cpu_weight
=
stake_cpu_delta
;
});
}
else
{
totals_tbl
.
modify
(
tot_itr
,
from
==
receiver
?
from
:
0
,
[
&
](
auto
&
tot
)
{
tot
.
net_weight
+=
stake_net_delta
;
tot
.
cpu_weight
+=
stake_cpu_delta
;
});
}
eosio_assert
(
asset
(
0
)
<=
tot_itr
->
net_weight
,
"insufficient staked total net bandwidth"
);
eosio_assert
(
asset
(
0
)
<=
tot_itr
->
cpu_weight
,
"insufficient staked total cpu bandwidth"
);
set_resource_limits
(
receiver
,
tot_itr
->
ram_bytes
,
tot_itr
->
net_weight
.
amount
,
tot_itr
->
cpu_weight
.
amount
);
if
(
tot_itr
->
net_weight
==
asset
(
0
)
&&
tot_itr
->
cpu_weight
==
asset
(
0
)
&&
tot_itr
->
ram_bytes
==
0
)
{
totals_tbl
.
erase
(
tot_itr
);
}
}
// tot_itr can be invalid, should go out of scope
// create refund or update from existing refund
if
(
N
(
eosio
.
stake
)
!=
source_stake_from
)
{
//for eosio both transfer and refund make no sense
refunds_table
refunds_tbl
(
_self
,
from
);
auto
req
=
refunds_tbl
.
find
(
from
);
//create/update/delete refund
auto
net_balance
=
stake_net_delta
;
auto
cpu_balance
=
stake_cpu_delta
;
bool
need_deferred_trx
=
false
;
// net and cpu are same sign by assertions in delegatebw and undelegatebw
// redundant assertion also at start of changebw to protect against misuse of changebw
bool
is_undelegating
=
(
net_balance
.
amount
+
cpu_balance
.
amount
)
<
0
;
bool
is_delegating_to_self
=
(
!
transfer
&&
from
==
receiver
);
if
(
is_delegating_to_self
||
is_undelegating
)
{
if
(
req
!=
refunds_tbl
.
end
()
)
{
//need to update refund
refunds_tbl
.
modify
(
req
,
0
,
[
&
](
refund_request
&
r
)
{
if
(
net_balance
<
asset
(
0
)
||
cpu_balance
<
asset
(
0
)
)
{
r
.
request_time
=
now
();
}
r
.
net_amount
-=
net_balance
;
if
(
r
.
net_amount
<
asset
(
0
)
)
{
net_balance
=
-
r
.
net_amount
;
r
.
net_amount
=
asset
(
0
);
}
else
{
net_balance
=
asset
(
0
);
}
r
.
cpu_amount
-=
cpu_balance
;
if
(
r
.
cpu_amount
<
asset
(
0
)
){
cpu_balance
=
-
r
.
cpu_amount
;
r
.
cpu_amount
=
asset
(
0
);
}
else
{
cpu_balance
=
asset
(
0
);
}
});
eosio_assert
(
asset
(
0
)
<=
req
->
net_amount
,
"negative net refund amount"
);
//should never happen
eosio_assert
(
asset
(
0
)
<=
req
->
cpu_amount
,
"negative cpu refund amount"
);
//should never happen
if
(
req
->
net_amount
==
asset
(
0
)
&&
req
->
cpu_amount
==
asset
(
0
)
)
{
refunds_tbl
.
erase
(
req
);
need_deferred_trx
=
false
;
}
else
{
need_deferred_trx
=
true
;
}
}
else
if
(
net_balance
<
asset
(
0
)
||
cpu_balance
<
asset
(
0
)
)
{
//need to create refund
refunds_tbl
.
emplace
(
from
,
[
&
](
refund_request
&
r
)
{
r
.
owner
=
from
;
if
(
net_balance
<
asset
(
0
)
)
{
r
.
net_amount
=
-
net_balance
;
net_balance
=
asset
(
0
);
}
// else r.net_amount = 0 by default constructor
if
(
cpu_balance
<
asset
(
0
)
)
{
r
.
cpu_amount
=
-
cpu_balance
;
cpu_balance
=
asset
(
0
);
}
// else r.cpu_amount = 0 by default constructor
r
.
request_time
=
now
();
});
need_deferred_trx
=
true
;
}
// else stake increase requested with no existing row in refunds_tbl -> nothing to do with refunds_tbl
}
/// end if is_delegating_to_self || is_undelegating
if
(
need_deferred_trx
)
{
eosio
::
transaction
out
;
out
.
actions
.
emplace_back
(
permission_level
{
from
,
N
(
active
)
},
_self
,
N
(
refund
),
from
);
out
.
delay_sec
=
refund_delay
;
cancel_deferred
(
from
);
// TODO: Remove this line when replacing deferred trxs is fixed
out
.
send
(
from
,
from
,
true
);
}
else
{
cancel_deferred
(
from
);
}
auto
transfer_amount
=
net_balance
+
cpu_balance
;
if
(
asset
(
0
)
<
transfer_amount
)
{
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
source_stake_from
,
N
(
active
)},
{
source_stake_from
,
N
(
eosio
.
stake
),
asset
(
transfer_amount
),
std
::
string
(
"stake bandwidth"
)
}
);
}
}
// update voting power
{
asset
total_update
=
stake_net_delta
+
stake_cpu_delta
;
auto
from_voter
=
_voters
.
find
(
from
);
if
(
from_voter
==
_voters
.
end
()
)
{
from_voter
=
_voters
.
emplace
(
from
,
[
&
](
auto
&
v
)
{
v
.
owner
=
from
;
v
.
staked
=
total_update
.
amount
;
});
}
else
{
_voters
.
modify
(
from_voter
,
0
,
[
&
](
auto
&
v
)
{
v
.
staked
+=
total_update
.
amount
;
});
}
eosio_assert
(
0
<=
from_voter
->
staked
,
"stake for voting cannot be negative"
);
if
(
from
==
N
(
b1
)
)
{
validate_b1_vesting
(
from_voter
->
staked
);
}
if
(
from_voter
->
producers
.
size
()
||
from_voter
->
proxy
)
{
update_votes
(
from
,
from_voter
->
proxy
,
from_voter
->
producers
,
false
);
}
}
}
void
system_contract
::
delegatebw
(
account_name
from
,
account_name
receiver
,
asset
stake_net_quantity
,
asset
stake_cpu_quantity
,
bool
transfer
)
{
eosio_assert
(
stake_cpu_quantity
>=
asset
(
0
),
"must stake a positive amount"
);
eosio_assert
(
stake_net_quantity
>=
asset
(
0
),
"must stake a positive amount"
);
eosio_assert
(
stake_net_quantity
+
stake_cpu_quantity
>
asset
(
0
),
"must stake a positive amount"
);
eosio_assert
(
!
transfer
||
from
!=
receiver
,
"cannot use transfer flag if delegating to self"
);
changebw
(
from
,
receiver
,
stake_net_quantity
,
stake_cpu_quantity
,
transfer
);
}
// delegatebw
void
system_contract
::
undelegatebw
(
account_name
from
,
account_name
receiver
,
asset
unstake_net_quantity
,
asset
unstake_cpu_quantity
)
{
eosio_assert
(
asset
()
<=
unstake_cpu_quantity
,
"must unstake a positive amount"
);
eosio_assert
(
asset
()
<=
unstake_net_quantity
,
"must unstake a positive amount"
);
eosio_assert
(
asset
()
<
unstake_cpu_quantity
+
unstake_net_quantity
,
"must unstake a positive amount"
);
eosio_assert
(
_gstate
.
total_activated_stake
>=
min_activated_stake
,
"cannot undelegate bandwidth until the chain is activated (at least 15% of all tokens participate in voting)"
);
changebw
(
from
,
receiver
,
-
unstake_net_quantity
,
-
unstake_cpu_quantity
,
false
);
}
// undelegatebw
void
system_contract
::
refund
(
const
account_name
owner
)
{
require_auth
(
owner
);
refunds_table
refunds_tbl
(
_self
,
owner
);
auto
req
=
refunds_tbl
.
find
(
owner
);
eosio_assert
(
req
!=
refunds_tbl
.
end
(),
"refund request not found"
);
eosio_assert
(
req
->
request_time
+
refund_delay
<=
now
(),
"refund is not available yet"
);
// Until now() becomes NOW, the fact that now() is the timestamp of the previous block could in theory
// allow people to get their tokens earlier than the 3 day delay if the unstake happened immediately after many
// consecutive missed blocks.
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
N
(
eosio
.
stake
),
N
(
active
)},
{
N
(
eosio
.
stake
),
req
->
owner
,
req
->
net_amount
+
req
->
cpu_amount
,
std
::
string
(
"unstake"
)
}
);
refunds_tbl
.
erase
(
req
);
}
}
//namespace eosiosystem
contracts/eosio.system_dev/eosio.system.abi
0 → 100644
浏览文件 @
8880865f
{
"version": "eosio::abi/1.0",
"types": [{
"new_type_name": "account_name",
"type": "name"
},{
"new_type_name": "permission_name",
"type": "name"
},{
"new_type_name": "action_name",
"type": "name"
},{
"new_type_name": "transaction_id_type",
"type": "checksum256"
},{
"new_type_name": "weight_type",
"type": "uint16"
}],
"____comment": "eosio.bios structs: set_account_limits, setpriv, set_global_limits, producer_key, set_producers, require_auth are provided so abi available for deserialization in future.",
"structs": [{
"name": "permission_level",
"base": "",
"fields": [
{"name":"actor", "type":"account_name"},
{"name":"permission", "type":"permission_name"}
]
},{
"name": "key_weight",
"base": "",
"fields": [
{"name":"key", "type":"public_key"},
{"name":"weight", "type":"weight_type"}
]
},{
"name": "bidname",
"base": "",
"fields": [
{"name":"bidder", "type":"account_name"},
{"name":"newname", "type":"account_name"},
{"name":"bid", "type":"asset"}
]
},{
"name": "permission_level_weight",
"base": "",
"fields": [
{"name":"permission", "type":"permission_level"},
{"name":"weight", "type":"weight_type"}
]
},{
"name": "wait_weight",
"base": "",
"fields": [
{"name":"wait_sec", "type":"uint32"},
{"name":"weight", "type":"weight_type"}
]
},{
"name": "authority",
"base": "",
"fields": [
{"name":"threshold", "type":"uint32"},
{"name":"keys", "type":"key_weight[]"},
{"name":"accounts", "type":"permission_level_weight[]"},
{"name":"waits", "type":"wait_weight[]"}
]
},{
"name": "newaccount",
"base": "",
"fields": [
{"name":"creator", "type":"account_name"},
{"name":"name", "type":"account_name"},
{"name":"owner", "type":"authority"},
{"name":"active", "type":"authority"}
]
},{
"name": "setcode",
"base": "",
"fields": [
{"name":"account", "type":"account_name"},
{"name":"vmtype", "type":"uint8"},
{"name":"vmversion", "type":"uint8"},
{"name":"code", "type":"bytes"}
]
},{
"name": "setabi",
"base": "",
"fields": [
{"name":"account", "type":"account_name"},
{"name":"abi", "type":"bytes"}
]
},{
"name": "updateauth",
"base": "",
"fields": [
{"name":"account", "type":"account_name"},
{"name":"permission", "type":"permission_name"},
{"name":"parent", "type":"permission_name"},
{"name":"auth", "type":"authority"}
]
},{
"name": "deleteauth",
"base": "",
"fields": [
{"name":"account", "type":"account_name"},
{"name":"permission", "type":"permission_name"}
]
},{
"name": "linkauth",
"base": "",
"fields": [
{"name":"account", "type":"account_name"},
{"name":"code", "type":"account_name"},
{"name":"type", "type":"action_name"},
{"name":"requirement", "type":"permission_name"}
]
},{
"name": "unlinkauth",
"base": "",
"fields": [
{"name":"account", "type":"account_name"},
{"name":"code", "type":"account_name"},
{"name":"type", "type":"action_name"}
]
},{
"name": "canceldelay",
"base": "",
"fields": [
{"name":"canceling_auth", "type":"permission_level"},
{"name":"trx_id", "type":"transaction_id_type"}
]
},{
"name": "onerror",
"base": "",
"fields": [
{"name":"sender_id", "type":"uint128"},
{"name":"sent_trx", "type":"bytes"}
]
},{
"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":"uint64"}
]
},{
"name": "buyram",
"base": "",
"fields": [
{"name":"payer", "type":"account_name"},
{"name":"receiver", "type":"account_name"},
{"name":"quant", "type":"asset"}
]
},{
"name": "delegatebw",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"receiver", "type":"account_name"},
{"name":"stake_net_quantity", "type":"asset"},
{"name":"stake_cpu_quantity", "type":"asset"},
{"name":"transfer", "type":"bool"}
]
},{
"name": "undelegatebw",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"receiver", "type":"account_name"},
{"name":"unstake_net_quantity", "type":"asset"},
{"name":"unstake_cpu_quantity", "type":"asset"}
]
},{
"name": "refund",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"}
]
},{
"name": "delegated_bandwidth",
"base": "",
"fields": [
{"name":"from", "type":"account_name"},
{"name":"to", "type":"account_name"},
{"name":"net_weight", "type":"asset"},
{"name":"cpu_weight", "type":"asset"}
]
},{
"name": "user_resources",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"},
{"name":"net_weight", "type":"asset"},
{"name":"cpu_weight", "type":"asset"},
{"name":"ram_bytes", "type":"uint64"}
]
},{
"name": "total_resources",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"},
{"name":"net_weight", "type":"asset"},
{"name":"cpu_weight", "type":"asset"},
{"name":"ram_bytes", "type":"uint64"}
]
},{
"name": "refund_request",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"},
{"name":"request_time", "type":"time_point_sec"},
{"name":"net_amount", "type":"asset"},
{"name":"cpu_amount", "type":"asset"}
]
},{
"name": "blockchain_parameters",
"base": "",
"fields": [
{"name":"max_block_net_usage", "type":"uint64"},
{"name":"target_block_net_usage_pct", "type":"uint32"},
{"name":"max_transaction_net_usage", "type":"uint32"},
{"name":"base_per_transaction_net_usage", "type":"uint32"},
{"name":"net_usage_leeway", "type":"uint32"},
{"name":"context_free_discount_net_usage_num", "type":"uint32"},
{"name":"context_free_discount_net_usage_den", "type":"uint32"},
{"name":"max_block_cpu_usage", "type":"uint32"},
{"name":"target_block_cpu_usage_pct", "type":"uint32"},
{"name":"max_transaction_cpu_usage", "type":"uint32"},
{"name":"min_transaction_cpu_usage", "type":"uint32"},
{"name":"max_transaction_lifetime", "type":"uint32"},
{"name":"deferred_trx_expiration_window", "type":"uint32"},
{"name":"max_transaction_delay", "type":"uint32"},
{"name":"max_inline_action_size", "type":"uint32"},
{"name":"max_inline_action_depth", "type":"uint16"},
{"name":"max_authority_depth", "type":"uint16"}
]
},{
"name": "eosio_global_state",
"base": "blockchain_parameters",
"fields": [
{"name":"max_ram_size", "type":"uint64"},
{"name":"total_ram_bytes_reserved", "type":"uint64"},
{"name":"total_ram_stake", "type":"int64"},
{"name":"last_producer_schedule_update", "type":"block_timestamp_type"},
{"name":"last_pervote_bucket_fill", "type":"uint64"},
{"name":"pervote_bucket", "type":"int64"},
{"name":"perblock_bucket", "type":"int64"},
{"name":"total_unpaid_blocks", "type":"uint32"},
{"name":"total_activated_stake", "type":"int64"},
{"name":"thresh_activated_stake_time", "type":"uint64"},
{"name":"last_producer_schedule_size", "type":"uint16"},
{"name":"total_producer_vote_weight", "type":"float64"},
{"name":"last_name_close", "type":"block_timestamp_type"}
]
},{
"name": "eosio_global_count",
"base": "",
"fields": [
{"name":"total_accounts", "type":"uint64"}
]
},{
"name": "producer_info",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"},
{"name":"total_votes", "type":"float64"},
{"name":"producer_key", "type":"public_key"},
{"name":"is_active", "type":"bool"},
{"name":"url", "type":"string"},
{"name":"unpaid_blocks", "type":"uint32"},
{"name":"last_claim_time", "type":"uint64"},
{"name":"location", "type":"uint16"}
]
},{
"name": "regproducer",
"base": "",
"fields": [
{"name":"producer", "type":"account_name"},
{"name":"producer_key", "type":"public_key"},
{"name":"url", "type":"string"},
{"name":"location", "type":"uint16"}
]
},{
"name": "unregprod",
"base": "",
"fields": [
{"name":"producer", "type":"account_name"}
]
},{
"name": "setram",
"base": "",
"fields": [
{"name":"max_ram_size", "type":"uint64"}
]
},{
"name": "regproxy",
"base": "",
"fields": [
{"name":"proxy", "type":"account_name"},
{"name":"isproxy", "type":"bool"}
]
},{
"name": "voteproducer",
"base": "",
"fields": [
{"name":"voter", "type":"account_name"},
{"name":"proxy", "type":"account_name"},
{"name":"producers", "type":"account_name[]"}
]
},{
"name": "voter_info",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"},
{"name":"proxy", "type":"account_name"},
{"name":"producers", "type":"account_name[]"},
{"name":"staked", "type":"int64"},
{"name":"last_vote_weight", "type":"float64"},
{"name":"proxied_vote_weight", "type":"float64"},
{"name":"is_proxy", "type":"bool"}
]
},{
"name": "claimrewards",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"}
]
},{
"name": "setpriv",
"base": "",
"fields": [
{"name":"account", "type":"account_name"},
{"name":"is_priv", "type":"int8"}
]
},{
"name": "rmvproducer",
"base": "",
"fields": [
{"name":"producer", "type":"account_name"}
]
},{
"name": "set_account_limits",
"base": "",
"fields": [
{"name":"account", "type":"account_name"},
{"name":"ram_bytes", "type":"int64"},
{"name":"net_weight", "type":"int64"},
{"name":"cpu_weight", "type":"int64"}
]
},{
"name": "set_global_limits",
"base": "",
"fields": [
{"name":"cpu_usec_per_period", "type":"int64"}
]
},{
"name": "producer_key",
"base": "",
"fields": [
{"name":"producer_name", "type":"account_name"},
{"name":"block_signing_key", "type":"public_key"}
]
},{
"name": "set_producers",
"base": "",
"fields": [
{"name":"schedule", "type":"producer_key[]"}
]
},{
"name": "require_auth",
"base": "",
"fields": [
{"name":"from", "type":"account_name"}
]
},{
"name": "setparams",
"base": "",
"fields": [
{"name":"params", "type":"blockchain_parameters"}
]
},{
"name": "connector",
"base": "",
"fields": [
{"name":"balance", "type":"asset"},
{"name":"weight", "type":"float64"}
]
},{
"name": "exchange_state",
"base": "",
"fields": [
{"name":"supply", "type":"asset"},
{"name":"base", "type":"connector"},
{"name":"quote", "type":"connector"}
]
}, {
"name": "namebid_info",
"base": "",
"fields": [
{"name":"newname", "type":"account_name"},
{"name":"high_bidder", "type":"account_name"},
{"name":"high_bid", "type":"int64"},
{"name":"last_bid_time", "type":"uint64"}
]
}
],
"actions": [{
"name": "newaccount",
"type": "newaccount",
"ricardian_contract": ""
},{
"name": "setcode",
"type": "setcode",
"ricardian_contract": ""
},{
"name": "setabi",
"type": "setabi",
"ricardian_contract": ""
},{
"name": "updateauth",
"type": "updateauth",
"ricardian_contract": ""
},{
"name": "deleteauth",
"type": "deleteauth",
"ricardian_contract": ""
},{
"name": "linkauth",
"type": "linkauth",
"ricardian_contract": ""
},{
"name": "unlinkauth",
"type": "unlinkauth",
"ricardian_contract": ""
},{
"name": "canceldelay",
"type": "canceldelay",
"ricardian_contract": ""
},{
"name": "onerror",
"type": "onerror",
"ricardian_contract": ""
},{
"name": "buyrambytes",
"type": "buyrambytes",
"ricardian_contract": ""
},{
"name": "buyram",
"type": "buyram",
"ricardian_contract": ""
},{
"name": "sellram",
"type": "sellram",
"ricardian_contract": ""
},{
"name": "delegatebw",
"type": "delegatebw",
"ricardian_contract": ""
},{
"name": "undelegatebw",
"type": "undelegatebw",
"ricardian_contract": ""
},{
"name": "refund",
"type": "refund",
"ricardian_contract": ""
},{
"name": "regproducer",
"type": "regproducer",
"ricardian_contract": ""
},{
"name": "setram",
"type": "setram",
"ricardian_contract": ""
},{
"name": "bidname",
"type": "bidname",
"ricardian_contract": ""
},{
"name": "unregprod",
"type": "unregprod",
"ricardian_contract": ""
},{
"name": "regproxy",
"type": "regproxy",
"ricardian_contract": ""
},{
"name": "voteproducer",
"type": "voteproducer",
"ricardian_contract": ""
},{
"name": "claimrewards",
"type": "claimrewards",
"ricardian_contract": ""
},{
"name": "setpriv",
"type": "setpriv",
"ricardian_contract": ""
},{
"name": "rmvproducer",
"type": "rmvproducer",
"ricardian_contract": ""
},{
"name": "setalimits",
"type": "set_account_limits",
"ricardian_contract": ""
},{
"name": "setglimits",
"type": "set_global_limits",
"ricardian_contract": ""
},{
"name": "setprods",
"type": "set_producers",
"ricardian_contract": ""
},{
"name": "reqauth",
"type": "require_auth",
"ricardian_contract": ""
},{
"name": "setparams",
"type": "setparams",
"ricardian_contract": ""
}],
"tables": [{
"name": "producers",
"type": "producer_info",
"index_type": "i64",
"key_names" : ["owner"],
"key_types" : ["uint64"]
},{
"name": "global",
"type": "eosio_global_state",
"index_type": "i64",
"key_names" : [],
"key_types" : []
},{
"name": "gcount",
"type": "eosio_global_count",
"index_type": "i64",
"key_names" : [],
"key_types" : []
},{
"name": "voters",
"type": "voter_info",
"index_type": "i64",
"key_names" : ["owner"],
"key_types" : ["account_name"]
},{
"name": "userres",
"type": "user_resources",
"index_type": "i64",
"key_names" : ["owner"],
"key_types" : ["uint64"]
},{
"name": "delband",
"type": "delegated_bandwidth",
"index_type": "i64",
"key_names" : ["to"],
"key_types" : ["uint64"]
},{
"name": "rammarket",
"type": "exchange_state",
"index_type": "i64",
"key_names" : ["supply"],
"key_types" : ["uint64"]
},{
"name": "refunds",
"type": "refund_request",
"index_type": "i64",
"key_names" : ["owner"],
"key_types" : ["uint64"]
},{
"name": "namebids",
"type": "namebid_info",
"index_type": "i64",
"key_names" : ["newname"],
"key_types" : ["account_name"]
}
],
"ricardian_clauses": [],
"abi_extensions": []
}
contracts/eosio.system_dev/eosio.system.hpp
0 → 100644
浏览文件 @
8880865f
/**
* @file
* @copyright defined in eos/LICENSE
*/
#pragma once
#include <eosio.system/native.hpp>
#include <eosiolib/asset.hpp>
#include <eosiolib/time.hpp>
#include <eosiolib/privileged.hpp>
#include <eosiolib/singleton.hpp>
#include <eosio.system/exchange_state.hpp>
#include <string>
namespace
eosiosystem
{
using
eosio
::
asset
;
using
eosio
::
indexed_by
;
using
eosio
::
const_mem_fun
;
using
eosio
::
block_timestamp
;
struct
name_bid
{
account_name
newname
;
account_name
high_bidder
;
int64_t
high_bid
=
0
;
///< negative high_bid == closed auction waiting to be claimed
uint64_t
last_bid_time
=
0
;
auto
primary_key
()
const
{
return
newname
;
}
uint64_t
by_high_bid
()
const
{
return
static_cast
<
uint64_t
>
(
-
high_bid
);
}
};
typedef
eosio
::
multi_index
<
N
(
namebids
),
name_bid
,
indexed_by
<
N
(
highbid
),
const_mem_fun
<
name_bid
,
uint64_t
,
&
name_bid
::
by_high_bid
>
>
>
name_bid_table
;
struct
eosio_global_state
:
eosio
::
blockchain_parameters
{
uint64_t
free_ram
()
const
{
return
max_ram_size
-
total_ram_bytes_reserved
;
}
uint64_t
max_ram_size
=
64ll
*
1024
*
1024
*
1024
;
uint64_t
total_ram_bytes_reserved
=
0
;
int64_t
total_ram_stake
=
0
;
block_timestamp
last_producer_schedule_update
;
uint64_t
last_pervote_bucket_fill
=
0
;
int64_t
pervote_bucket
=
0
;
int64_t
perblock_bucket
=
0
;
uint32_t
total_unpaid_blocks
=
0
;
/// all blocks which have been produced but not paid
int64_t
total_activated_stake
=
0
;
uint64_t
thresh_activated_stake_time
=
0
;
uint16_t
last_producer_schedule_size
=
0
;
double
total_producer_vote_weight
=
0
;
/// the sum of all producer votes
block_timestamp
last_name_close
;
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE_DERIVED
(
eosio_global_state
,
eosio
::
blockchain_parameters
,
(
max_ram_size
)(
total_ram_bytes_reserved
)(
total_ram_stake
)
(
last_producer_schedule_update
)(
last_pervote_bucket_fill
)
(
pervote_bucket
)(
perblock_bucket
)(
total_unpaid_blocks
)(
total_activated_stake
)(
thresh_activated_stake_time
)
(
last_producer_schedule_size
)(
total_producer_vote_weight
)(
last_name_close
)
)
};
//##YTA-Change start:
struct
eosio_global_count
{
uint64_t
total_accounts
=
1
;
EOSLIB_SERIALIZE
(
eosio_global_count
,
(
total_accounts
)
)
};
//##YTA-Change end:
struct
producer_info
{
account_name
owner
;
double
total_votes
=
0
;
eosio
::
public_key
producer_key
;
/// a packed public key object
bool
is_active
=
true
;
std
::
string
url
;
uint32_t
unpaid_blocks
=
0
;
uint64_t
last_claim_time
=
0
;
uint16_t
location
=
0
;
uint64_t
primary_key
()
const
{
return
owner
;
}
double
by_votes
()
const
{
return
is_active
?
-
total_votes
:
total_votes
;
}
bool
active
()
const
{
return
is_active
;
}
void
deactivate
()
{
producer_key
=
public_key
();
is_active
=
false
;
}
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE
(
producer_info
,
(
owner
)(
total_votes
)(
producer_key
)(
is_active
)(
url
)
(
unpaid_blocks
)(
last_claim_time
)(
location
)
)
};
struct
voter_info
{
account_name
owner
=
0
;
/// the voter
account_name
proxy
=
0
;
/// the proxy set by the voter, if any
std
::
vector
<
account_name
>
producers
;
/// the producers approved by this voter if no proxy set
int64_t
staked
=
0
;
/**
* Every time a vote is cast we must first "undo" the last vote weight, before casting the
* new vote weight. Vote weight is calculated as:
*
* stated.amount * 2 ^ ( weeks_since_launch/weeks_per_year)
*/
double
last_vote_weight
=
0
;
/// the vote weight cast the last time the vote was updated
/**
* Total vote weight delegated to this voter.
*/
double
proxied_vote_weight
=
0
;
/// the total vote weight delegated to this voter as a proxy
bool
is_proxy
=
0
;
/// whether the voter is a proxy for others
uint32_t
reserved1
=
0
;
time
reserved2
=
0
;
eosio
::
asset
reserved3
;
uint64_t
primary_key
()
const
{
return
owner
;
}
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE
(
voter_info
,
(
owner
)(
proxy
)(
producers
)(
staked
)(
last_vote_weight
)(
proxied_vote_weight
)(
is_proxy
)(
reserved1
)(
reserved2
)(
reserved3
)
)
};
typedef
eosio
::
multi_index
<
N
(
voters
),
voter_info
>
voters_table
;
typedef
eosio
::
multi_index
<
N
(
producers
),
producer_info
,
indexed_by
<
N
(
prototalvote
),
const_mem_fun
<
producer_info
,
double
,
&
producer_info
::
by_votes
>
>
>
producers_table
;
typedef
eosio
::
singleton
<
N
(
global
),
eosio_global_state
>
global_state_singleton
;
//##YTA-Change start:
typedef
eosio
::
singleton
<
N
(
gcount
),
eosio_global_count
>
global_count_singleton
;
//##YTA-Change end:
// static constexpr uint32_t max_inflation_rate = 5; // 5% annual inflation
static
constexpr
uint32_t
seconds_per_day
=
24
*
3600
;
static
constexpr
uint64_t
system_token_symbol
=
CORE_SYMBOL
;
class
system_contract
:
public
native
{
private:
voters_table
_voters
;
producers_table
_producers
;
global_state_singleton
_global
;
eosio_global_state
_gstate
;
rammarket
_rammarket
;
public:
system_contract
(
account_name
s
);
~
system_contract
();
// Actions:
void
onblock
(
block_timestamp
timestamp
,
account_name
producer
);
// const block_header& header ); /// only parse first 3 fields of block header
// functions defined in delegate_bandwidth.cpp
/**
* Stakes SYS from the balance of 'from' for the benfit of 'receiver'.
* If transfer == true, then 'receiver' can unstake to their account
* Else 'from' can unstake at any time.
*/
void
delegatebw
(
account_name
from
,
account_name
receiver
,
asset
stake_net_quantity
,
asset
stake_cpu_quantity
,
bool
transfer
);
/**
* Decreases the total tokens delegated by from to receiver and/or
* frees the memory associated with the delegation if there is nothing
* left to delegate.
*
* This will cause an immediate reduction in net/cpu bandwidth of the
* receiver.
*
* A transaction is scheduled to send the tokens back to 'from' after
* the staking period has passed. If existing transaction is scheduled, it
* will be canceled and a new transaction issued that has the combined
* undelegated amount.
*
* The 'from' account loses voting power as a result of this call and
* all producer tallies are updated.
*/
void
undelegatebw
(
account_name
from
,
account_name
receiver
,
asset
unstake_net_quantity
,
asset
unstake_cpu_quantity
);
/**
* Increases receiver's ram quota based upon current price and quantity of
* tokens provided. An inline transfer from receiver to system contract of
* 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
,
int64_t
bytes
);
/**
* This action is called after the delegation-period to claim all pending
* unstaked tokens belonging to owner
*/
void
refund
(
account_name
owner
);
// functions defined in voting.cpp
void
regproducer
(
const
account_name
producer
,
const
public_key
&
producer_key
,
const
std
::
string
&
url
,
uint16_t
location
);
void
unregprod
(
const
account_name
producer
);
void
setram
(
uint64_t
max_ram_size
);
void
voteproducer
(
const
account_name
voter
,
const
account_name
proxy
,
const
std
::
vector
<
account_name
>&
producers
);
void
regproxy
(
const
account_name
proxy
,
bool
isproxy
);
void
setparams
(
const
eosio
::
blockchain_parameters
&
params
);
// functions defined in producer_pay.cpp
void
claimrewards
(
const
account_name
&
owner
);
void
setpriv
(
account_name
account
,
uint8_t
ispriv
);
void
rmvproducer
(
account_name
producer
);
void
bidname
(
account_name
bidder
,
account_name
newname
,
asset
bid
);
private:
void
update_elected_producers
(
block_timestamp
timestamp
);
// Implementation details:
//defind in delegate_bandwidth.cpp
void
changebw
(
account_name
from
,
account_name
receiver
,
asset
stake_net_quantity
,
asset
stake_cpu_quantity
,
bool
transfer
);
//defined in voting.hpp
static
eosio_global_state
get_default_parameters
();
void
update_votes
(
const
account_name
voter
,
const
account_name
proxy
,
const
std
::
vector
<
account_name
>&
producers
,
bool
voting
);
// defined in voting.cpp
void
propagate_weight_change
(
const
voter_info
&
voter
);
};
}
/// eosiosystem
contracts/eosio.system_dev/eosio.system_dev.cpp
0 → 100644
浏览文件 @
8880865f
#include "eosio.system.hpp"
#include <eosiolib/dispatcher.hpp>
#include "producer_pay.cpp"
#include "delegate_bandwidth.cpp"
#include "voting.cpp"
#include "exchange_state.cpp"
namespace
eosiosystem
{
system_contract
::
system_contract
(
account_name
s
)
:
native
(
s
),
_voters
(
_self
,
_self
),
_producers
(
_self
,
_self
),
_global
(
_self
,
_self
),
_rammarket
(
_self
,
_self
)
{
//print( "construct system\n" );
_gstate
=
_global
.
exists
()
?
_global
.
get
()
:
get_default_parameters
();
auto
itr
=
_rammarket
.
find
(
S
(
4
,
RAMCORE
));
if
(
itr
==
_rammarket
.
end
()
)
{
auto
system_token_supply
=
eosio
::
token
(
N
(
eosio
.
token
)).
get_supply
(
eosio
::
symbol_type
(
system_token_symbol
).
name
()).
amount
;
if
(
system_token_supply
>
0
)
{
itr
=
_rammarket
.
emplace
(
_self
,
[
&
](
auto
&
m
)
{
m
.
supply
.
amount
=
100000000000000ll
;
m
.
supply
.
symbol
=
S
(
4
,
RAMCORE
);
m
.
base
.
balance
.
amount
=
int64_t
(
_gstate
.
free_ram
());
m
.
base
.
balance
.
symbol
=
S
(
0
,
RAM
);
m
.
quote
.
balance
.
amount
=
system_token_supply
/
1000
;
m
.
quote
.
balance
.
symbol
=
CORE_SYMBOL
;
});
}
}
else
{
//print( "ram market already created" );
}
}
eosio_global_state
system_contract
::
get_default_parameters
()
{
eosio_global_state
dp
;
get_blockchain_parameters
(
dp
);
return
dp
;
}
system_contract
::~
system_contract
()
{
//print( "destruct system\n" );
_global
.
set
(
_gstate
,
_self
);
//eosio_exit(0);
}
void
system_contract
::
setram
(
uint64_t
max_ram_size
)
{
require_auth
(
_self
);
eosio_assert
(
_gstate
.
max_ram_size
<
max_ram_size
,
"ram may only be increased"
);
/// decreasing ram might result market maker issues
eosio_assert
(
max_ram_size
<
1024ll
*
1024
*
1024
*
1024
*
1024
,
"ram size is unrealistic"
);
eosio_assert
(
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
(
S
(
4
,
RAMCORE
));
/**
* Increase or decrease the amount of ram for sale based upon the change in max
* ram size.
*/
_rammarket
.
modify
(
itr
,
0
,
[
&
](
auto
&
m
)
{
m
.
base
.
balance
.
amount
+=
delta
;
});
_gstate
.
max_ram_size
=
max_ram_size
;
_global
.
set
(
_gstate
,
_self
);
}
void
system_contract
::
setparams
(
const
eosio
::
blockchain_parameters
&
params
)
{
require_auth
(
N
(
eosio
)
);
(
eosio
::
blockchain_parameters
&
)(
_gstate
)
=
params
;
eosio_assert
(
3
<=
_gstate
.
max_authority_depth
,
"max_authority_depth should be at least 3"
);
set_blockchain_parameters
(
params
);
}
void
system_contract
::
setpriv
(
account_name
account
,
uint8_t
ispriv
)
{
require_auth
(
_self
);
set_privileged
(
account
,
ispriv
);
}
void
system_contract
::
rmvproducer
(
account_name
producer
)
{
require_auth
(
_self
);
auto
prod
=
_producers
.
find
(
producer
);
eosio_assert
(
prod
!=
_producers
.
end
(),
"producer not found"
);
_producers
.
modify
(
prod
,
0
,
[
&
](
auto
&
p
)
{
p
.
deactivate
();
});
}
void
system_contract
::
bidname
(
account_name
bidder
,
account_name
newname
,
asset
bid
)
{
require_auth
(
bidder
);
eosio_assert
(
eosio
::
name_suffix
(
newname
)
==
newname
,
"you can only bid on top-level suffix"
);
eosio_assert
(
newname
!=
0
,
"the empty name is not a valid account name to bid on"
);
eosio_assert
(
(
newname
&
0xFull
)
==
0
,
"13 character names are not valid account names to bid on"
);
eosio_assert
(
(
newname
&
0x1F0ull
)
==
0
,
"accounts with 12 character names and no dots can be created without bidding required"
);
eosio_assert
(
!
is_account
(
newname
),
"account already exists"
);
eosio_assert
(
bid
.
symbol
==
asset
().
symbol
,
"asset must be system token"
);
eosio_assert
(
bid
.
amount
>
0
,
"insufficient bid"
);
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
bidder
,
N
(
active
)},
{
bidder
,
N
(
eosio
.
names
),
bid
,
std
::
string
(
"bid name "
)
+
(
name
{
newname
}).
to_string
()
}
);
name_bid_table
bids
(
_self
,
_self
);
print
(
name
{
bidder
},
" bid "
,
bid
,
" on "
,
name
{
newname
},
"
\n
"
);
auto
current
=
bids
.
find
(
newname
);
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
();
});
}
else
{
eosio_assert
(
current
->
high_bid
>
0
,
"this auction has already closed"
);
eosio_assert
(
bid
.
amount
-
current
->
high_bid
>
(
current
->
high_bid
/
10
),
"must increase bid by 10%"
);
eosio_assert
(
current
->
high_bidder
!=
bidder
,
"account is already highest bidder"
);
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
N
(
eosio
.
names
),
N
(
active
)},
{
N
(
eosio
.
names
),
current
->
high_bidder
,
asset
(
current
->
high_bid
),
std
::
string
(
"refund bid on name "
)
+
(
name
{
newname
}).
to_string
()
}
);
bids
.
modify
(
current
,
bidder
,
[
&
](
auto
&
b
)
{
b
.
high_bidder
=
bidder
;
b
.
high_bid
=
bid
.
amount
;
b
.
last_bid_time
=
current_time
();
});
}
}
/**
* 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
(
account_name
creator
,
account_name
newact
/* no need to parse authorities
const authority& owner,
const authority& active*/
)
{
if
(
creator
!=
_self
)
{
auto
tmp
=
newact
>>
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
=
eosio
::
name_suffix
(
newact
);
if
(
suffix
==
newact
)
{
name_bid_table
bids
(
_self
,
_self
);
auto
current
=
bids
.
find
(
newact
);
eosio_assert
(
current
!=
bids
.
end
(),
"no active bid for name"
);
eosio_assert
(
current
->
high_bidder
==
creator
,
"only highest bidder can claim"
);
eosio_assert
(
current
->
high_bid
<
0
,
"auction for name is not closed yet"
);
bids
.
erase
(
current
);
}
else
{
eosio_assert
(
creator
==
suffix
,
"only suffix may create this account"
);
}
}
}
user_resources_table
userres
(
_self
,
newact
);
userres
.
emplace
(
newact
,
[
&
](
auto
&
res
)
{
res
.
owner
=
newact
;
});
set_resource_limits
(
newact
,
0
,
0
,
0
);
//##YTA-Change start:
global_count_singleton
global
(
_self
,
_self
);
eosio_global_count
gstate
;
if
(
global
.
exists
())
{
gstate
=
global
.
get
();
}
gstate
.
total_accounts
+=
1
;
global
.
set
(
gstate
,
_self
);
//##YTA-Change end:
}
}
/// eosio.system
EOSIO_ABI
(
eosiosystem
::
system_contract
,
// native.hpp (newaccount definition is actually in eosio.system.cpp)
(
newaccount
)(
updateauth
)(
deleteauth
)(
linkauth
)(
unlinkauth
)(
canceldelay
)(
onerror
)
// eosio.system.cpp
(
setram
)(
setparams
)(
setpriv
)(
rmvproducer
)(
bidname
)
// delegate_bandwidth.cpp
(
buyrambytes
)(
buyram
)(
sellram
)(
delegatebw
)(
undelegatebw
)(
refund
)
// voting.cpp
(
regproducer
)(
unregprod
)(
voteproducer
)(
regproxy
)
// producer_pay.cpp
(
onblock
)(
claimrewards
)
)
contracts/eosio.system_dev/exchange_state.cpp
0 → 100644
浏览文件 @
8880865f
#include <eosio.system/exchange_state.hpp>
namespace
eosiosystem
{
asset
exchange_state
::
convert_to_exchange
(
connector
&
c
,
asset
in
)
{
real_type
R
(
supply
.
amount
);
real_type
C
(
c
.
balance
.
amount
+
in
.
amount
);
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
)
);
//print( "E: ", E, "\n");
int64_t
issued
=
int64_t
(
E
);
supply
.
amount
+=
issued
;
c
.
balance
.
amount
+=
in
.
amount
;
return
asset
(
issued
,
supply
.
symbol
);
}
asset
exchange_state
::
convert_from_exchange
(
connector
&
c
,
asset
in
)
{
eosio_assert
(
in
.
symbol
==
supply
.
symbol
,
"unexpected asset symbol input"
);
real_type
R
(
supply
.
amount
-
in
.
amount
);
real_type
C
(
c
.
balance
.
amount
);
real_type
F
(
1000.0
/
c
.
weight
);
real_type
E
(
in
.
amount
);
real_type
ONE
(
1.0
);
// potentially more accurate:
// The functions std::expm1 and std::log1p are useful for financial calculations, for example,
// when calculating small daily interest rates: (1+x)n
// -1 can be expressed as std::expm1(n * std::log1p(x)).
// real_type T = C * std::expm1( F * std::log1p(E/R) );
real_type
T
=
C
*
(
std
::
pow
(
ONE
+
E
/
R
,
F
)
-
ONE
);
//print( "T: ", T, "\n");
int64_t
out
=
int64_t
(
T
);
supply
.
amount
-=
in
.
amount
;
c
.
balance
.
amount
-=
out
;
return
asset
(
out
,
c
.
balance
.
symbol
);
}
asset
exchange_state
::
convert
(
asset
from
,
symbol_type
to
)
{
auto
sell_symbol
=
from
.
symbol
;
auto
ex_symbol
=
supply
.
symbol
;
auto
base_symbol
=
base
.
balance
.
symbol
;
auto
quote_symbol
=
quote
.
balance
.
symbol
;
//print( "From: ", from, " TO ", asset( 0,to), "\n" );
//print( "base: ", base_symbol, "\n" );
//print( "quote: ", quote_symbol, "\n" );
//print( "ex: ", supply.symbol, "\n" );
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
);
}
else
{
eosio_assert
(
false
,
"invalid sell"
);
}
}
else
{
if
(
to
==
base_symbol
)
{
from
=
convert_from_exchange
(
base
,
from
);
}
else
if
(
to
==
quote_symbol
)
{
from
=
convert_from_exchange
(
quote
,
from
);
}
else
{
eosio_assert
(
false
,
"invalid conversion"
);
}
}
if
(
to
!=
from
.
symbol
)
return
convert
(
from
,
to
);
return
from
;
}
}
/// namespace eosiosystem
contracts/eosio.system_dev/exchange_state.hpp
0 → 100644
浏览文件 @
8880865f
#pragma once
#include <eosiolib/asset.hpp>
namespace
eosiosystem
{
using
eosio
::
asset
;
using
eosio
::
symbol_type
;
typedef
double
real_type
;
/**
* Uses Bancor math to create a 50/50 relay between two asset types. The state of the
* bancor exchange is entirely contained within this struct. There are no external
* side effects associated with using this API.
*/
struct
exchange_state
{
asset
supply
;
struct
connector
{
asset
balance
;
double
weight
=
.5
;
EOSLIB_SERIALIZE
(
connector
,
(
balance
)(
weight
)
)
};
connector
base
;
connector
quote
;
uint64_t
primary_key
()
const
{
return
supply
.
symbol
;
}
asset
convert_to_exchange
(
connector
&
c
,
asset
in
);
asset
convert_from_exchange
(
connector
&
c
,
asset
in
);
asset
convert
(
asset
from
,
symbol_type
to
);
EOSLIB_SERIALIZE
(
exchange_state
,
(
supply
)(
base
)(
quote
)
)
};
typedef
eosio
::
multi_index
<
N
(
rammarket
),
exchange_state
>
rammarket
;
}
/// namespace eosiosystem
contracts/eosio.system_dev/native.hpp
0 → 100644
浏览文件 @
8880865f
/**
* @file
* @copyright defined in eos/LICENSE
*/
#pragma once
#include <eosiolib/action.hpp>
#include <eosiolib/public_key.hpp>
#include <eosiolib/types.hpp>
#include <eosiolib/print.hpp>
#include <eosiolib/privileged.h>
#include <eosiolib/optional.hpp>
#include <eosiolib/producer_schedule.hpp>
#include <eosiolib/contract.hpp>
namespace
eosiosystem
{
using
eosio
::
permission_level
;
using
eosio
::
public_key
;
typedef
std
::
vector
<
char
>
bytes
;
struct
permission_level_weight
{
permission_level
permission
;
weight_type
weight
;
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE
(
permission_level_weight
,
(
permission
)(
weight
)
)
};
struct
key_weight
{
public_key
key
;
weight_type
weight
;
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE
(
key_weight
,
(
key
)(
weight
)
)
};
struct
authority
{
uint32_t
threshold
;
uint32_t
delay_sec
;
std
::
vector
<
key_weight
>
keys
;
std
::
vector
<
permission_level_weight
>
accounts
;
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE
(
authority
,
(
threshold
)(
delay_sec
)(
keys
)(
accounts
)
)
};
struct
block_header
{
uint32_t
timestamp
;
account_name
producer
;
uint16_t
confirmed
=
0
;
block_id_type
previous
;
checksum256
transaction_mroot
;
checksum256
action_mroot
;
uint32_t
schedule_version
=
0
;
eosio
::
optional
<
eosio
::
producer_schedule
>
new_producers
;
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE
(
block_header
,
(
timestamp
)(
producer
)(
confirmed
)(
previous
)(
transaction_mroot
)(
action_mroot
)
(
schedule_version
)(
new_producers
))
};
/*
* Method parameters commented out to prevent generation of code that parses input data.
*/
class
native
:
public
eosio
::
contract
{
public:
using
eosio
::
contract
::
contract
;
/**
* Called after a new account is created. This code enforces resource-limits rules
* for new accounts as well as new account naming conventions.
*
* 1. accounts cannot contain '.' symbols which forces all acccounts to be 12
* characters long without '.' until a future account auction process is implemented
* which prevents name squatting.
*
* 2. new accounts must stake a minimal number of tokens (as set in system parameters)
* therefore, this method will execute an inline buyram from receiver for newacnt in
* an amount equal to the current new account creation fee.
*/
void
newaccount
(
account_name
creator
,
account_name
newact
/* no need to parse authorites
const authority& owner,
const authority& active*/
);
void
updateauth
(
/*account_name account,
permission_name permission,
permission_name parent,
const authority& data*/
)
{}
void
deleteauth
(
/*account_name account, permission_name permission*/
)
{}
void
linkauth
(
/*account_name account,
account_name code,
action_name type,
permission_name requirement*/
)
{}
void
unlinkauth
(
/*account_name account,
account_name code,
action_name type*/
)
{}
void
canceldelay
(
/*permission_level canceling_auth, transaction_id_type trx_id*/
)
{}
void
onerror
(
/*const bytes&*/
)
{}
};
}
contracts/eosio.system_dev/producer_pay.cpp
0 → 100644
浏览文件 @
8880865f
#include "eosio.system.hpp"
#include <eosiolib/print.hpp>
#include <eosio.token/eosio.token.hpp>
namespace
eosiosystem
{
const
int64_t
min_pervote_daily_pay
=
100'0000
;
//##YTA-Change start:
//Change total vote rate from 15% to 1% for test network
//const int64_t min_activated_stake = 150'000'000'0000;
const
int64_t
min_activated_stake
=
10'000'000'0000
;
//##YTA-Change end:
const
uint32_t
blocks_per_year
=
52
*
7
*
24
*
2
*
3600
;
// half seconds per year
const
uint32_t
seconds_per_year
=
52
*
7
*
24
*
3600
;
const
uint32_t
blocks_per_day
=
2
*
24
*
3600
;
const
uint32_t
blocks_per_hour
=
2
*
3600
;
const
uint64_t
useconds_per_day
=
24
*
3600
*
uint64_t
(
1000000
);
const
uint64_t
useconds_per_year
=
seconds_per_year
*
1000000ll
;
const
int64_t
block_initial_timestamp
=
1551369600ll
;
// epoch year 2019.03.01 unix timestamp 1551369600s
//yta seo total= yta_seo_year[i] * YTA_SEO_BASE
const
uint32_t
YTA_SEO_BASE
=
10'0000
;
const
double
YTA_PRECISION
=
10000.0000
;
const
uint32_t
yta_seo_year
[
62
]
=
{
1000
,
900
,
800
,
700
,
600
,
600
,
500
,
500
,
400
,
400
,
300
,
300
,
200
,
200
,
200
,
100
,
100
,
100
,
90
,
90
,
90
,
80
,
80
,
80
,
70
,
70
,
70
,
70
,
60
,
60
,
60
,
60
,
50
,
50
,
50
,
50
,
50
,
40
,
40
,
40
,
40
,
40
,
30
,
30
,
30
,
30
,
30
,
20
,
20
,
20
,
20
,
20
,
10
,
10
,
10
,
10
,
10
,
9
,
9
,
9
,
9
,
9
};
void
system_contract
::
onblock
(
block_timestamp
timestamp
,
account_name
producer
)
{
using
namespace
eosio
;
require_auth
(
N
(
eosio
));
/** until activated stake crosses this threshold no new rewards are paid */
if
(
_gstate
.
total_activated_stake
<
min_activated_stake
)
return
;
if
(
_gstate
.
last_pervote_bucket_fill
==
0
)
/// start the presses
_gstate
.
last_pervote_bucket_fill
=
current_time
();
/**
* At startup the initial producer may not be one that is registered / elected
* and therefore there may be no producer object for them.
*/
auto
prod
=
_producers
.
find
(
producer
);
if
(
prod
!=
_producers
.
end
()
)
{
_gstate
.
total_unpaid_blocks
++
;
_producers
.
modify
(
prod
,
0
,
[
&
](
auto
&
p
)
{
p
.
unpaid_blocks
++
;
});
}
/// only update block producers once every minute, block_timestamp is in half seconds
if
(
timestamp
.
slot
-
_gstate
.
last_producer_schedule_update
.
slot
>
120
)
{
update_elected_producers
(
timestamp
);
if
(
(
timestamp
.
slot
-
_gstate
.
last_name_close
.
slot
)
>
blocks_per_day
)
{
name_bid_table
bids
(
_self
,
_self
);
auto
idx
=
bids
.
get_index
<
N
(
highbid
)
>
();
auto
highest
=
idx
.
begin
();
if
(
highest
!=
idx
.
end
()
&&
highest
->
high_bid
>
0
&&
highest
->
last_bid_time
<
(
current_time
()
-
useconds_per_day
)
&&
_gstate
.
thresh_activated_stake_time
>
0
&&
(
current_time
()
-
_gstate
.
thresh_activated_stake_time
)
>
14
*
useconds_per_day
)
{
_gstate
.
last_name_close
=
timestamp
;
idx
.
modify
(
highest
,
0
,
[
&
](
auto
&
b
){
b
.
high_bid
=
-
b
.
high_bid
;
});
}
}
}
}
using
namespace
eosio
;
void
system_contract
::
claimrewards
(
const
account_name
&
owner
)
{
require_auth
(
owner
);
const
auto
&
prod
=
_producers
.
get
(
owner
);
eosio_assert
(
prod
.
active
(),
"producer does not have an active key"
);
eosio_assert
(
_gstate
.
total_activated_stake
>=
min_activated_stake
,
"cannot claim rewards until the chain is activated (at least 15% of all tokens participate in voting)"
);
auto
ct
=
current_time
();
//eosio_assert( ct - prod.last_claim_time > useconds_per_day, "already claimed rewards within past day" );
const
asset
token_supply
=
token
(
N
(
eosio
.
token
)).
get_supply
(
symbol_type
(
system_token_symbol
).
name
()
);
const
auto
usecs_since_last_fill
=
ct
-
_gstate
.
last_pervote_bucket_fill
;
print
(
"usecs_since_last_fill: "
,
usecs_since_last_fill
,
"
\n
"
);
print
(
"_gstate.last_pervote_bucket_fill: "
,
_gstate
.
last_pervote_bucket_fill
,
"
\n
"
);
print
(
"now(): "
,
now
(),
"
\n
"
);
int
idx_year
=
(
int
)((
now
()
-
block_initial_timestamp
)
/
seconds_per_year
);
auto
seo_token
=
yta_seo_year
[
idx_year
]
*
YTA_SEO_BASE
;
print
(
"idx_year: "
,
idx_year
,
"
\n
"
);
print
(
"yta_seo_year[idx_year]: "
,
yta_seo_year
[
idx_year
],
"
\n
"
);
print
(
"token_supply: "
,
token_supply
,
"
\n
"
);
print
(
"seo_token: "
,
seo_token
,
"
\n
"
);
if
(
usecs_since_last_fill
>
0
&&
_gstate
.
last_pervote_bucket_fill
>
0
)
{
auto
new_tokens
=
static_cast
<
int64_t
>
(
seo_token
*
YTA_PRECISION
*
double
(
usecs_since_last_fill
)
/
double
(
useconds_per_year
));
print
(
"new_token: "
,
new_tokens
,
"
\n
"
);
auto
to_producers
=
new_tokens
;
auto
to_per_block_pay
=
to_producers
/
4
;
auto
to_per_vote_pay
=
to_producers
-
to_per_block_pay
;
INLINE_ACTION_SENDER
(
eosio
::
token
,
issue
)(
N
(
eosio
.
token
),
{{
N
(
eosio
),
N
(
active
)}},
{
N
(
eosio
),
asset
(
new_tokens
),
std
::
string
(
"issue tokens for producer pay and savings"
)}
);
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
N
(
eosio
),
N
(
active
)},
{
N
(
eosio
),
N
(
eosio
.
bpay
),
asset
(
to_per_block_pay
),
"fund per-block bucket"
}
);
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
N
(
eosio
),
N
(
active
)},
{
N
(
eosio
),
N
(
eosio
.
vpay
),
asset
(
to_per_vote_pay
),
"fund per-vote bucket"
}
);
_gstate
.
pervote_bucket
+=
to_per_vote_pay
;
_gstate
.
perblock_bucket
+=
to_per_block_pay
;
_gstate
.
last_pervote_bucket_fill
=
ct
;
}
int64_t
producer_per_block_pay
=
0
;
if
(
_gstate
.
total_unpaid_blocks
>
0
)
{
producer_per_block_pay
=
(
_gstate
.
perblock_bucket
*
prod
.
unpaid_blocks
)
/
_gstate
.
total_unpaid_blocks
;
}
int64_t
producer_per_vote_pay
=
0
;
if
(
_gstate
.
total_producer_vote_weight
>
0
)
{
producer_per_vote_pay
=
int64_t
((
_gstate
.
pervote_bucket
*
prod
.
total_votes
)
/
_gstate
.
total_producer_vote_weight
);
}
if
(
producer_per_vote_pay
<
min_pervote_daily_pay
)
{
producer_per_vote_pay
=
0
;
}
_gstate
.
pervote_bucket
-=
producer_per_vote_pay
;
_gstate
.
perblock_bucket
-=
producer_per_block_pay
;
_gstate
.
total_unpaid_blocks
-=
prod
.
unpaid_blocks
;
_producers
.
modify
(
prod
,
0
,
[
&
](
auto
&
p
)
{
p
.
last_claim_time
=
ct
;
p
.
unpaid_blocks
=
0
;
});
if
(
producer_per_block_pay
>
0
)
{
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
N
(
eosio
.
bpay
),
N
(
active
)},
{
N
(
eosio
.
bpay
),
owner
,
asset
(
producer_per_block_pay
),
std
::
string
(
"producer block pay"
)
}
);
}
if
(
producer_per_vote_pay
>
0
)
{
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
N
(
eosio
.
vpay
),
N
(
active
)},
{
N
(
eosio
.
vpay
),
owner
,
asset
(
producer_per_vote_pay
),
std
::
string
(
"producer vote pay"
)
}
);
}
}
}
//namespace eosiosystem
contracts/eosio.system_dev/voting.cpp
0 → 100644
浏览文件 @
8880865f
/**
* @file
* @copyright defined in eos/LICENSE
*/
#include "eosio.system.hpp"
#include <eosiolib/eosio.hpp>
#include <eosiolib/crypto.h>
#include <eosiolib/print.hpp>
#include <eosiolib/datastream.hpp>
#include <eosiolib/serialize.hpp>
#include <eosiolib/multi_index.hpp>
#include <eosiolib/privileged.hpp>
#include <eosiolib/singleton.hpp>
#include <eosiolib/transaction.hpp>
#include <eosio.token/eosio.token.hpp>
#include <algorithm>
#include <cmath>
namespace
eosiosystem
{
using
eosio
::
indexed_by
;
using
eosio
::
const_mem_fun
;
using
eosio
::
bytes
;
using
eosio
::
print
;
using
eosio
::
singleton
;
using
eosio
::
transaction
;
/**
* This method will create a producer_config and producer_info object for 'producer'
*
* @pre producer is not already registered
* @pre producer to register is an account
* @pre authority of producer to register
*
*/
void
system_contract
::
regproducer
(
const
account_name
producer
,
const
eosio
::
public_key
&
producer_key
,
const
std
::
string
&
url
,
uint16_t
location
)
{
eosio_assert
(
url
.
size
()
<
512
,
"url too long"
);
eosio_assert
(
producer_key
!=
eosio
::
public_key
(),
"public key should not be the default value"
);
require_auth
(
producer
);
auto
prod
=
_producers
.
find
(
producer
);
if
(
prod
!=
_producers
.
end
()
)
{
_producers
.
modify
(
prod
,
producer
,
[
&
](
producer_info
&
info
){
info
.
producer_key
=
producer_key
;
info
.
is_active
=
true
;
info
.
url
=
url
;
info
.
location
=
location
;
});
}
else
{
_producers
.
emplace
(
producer
,
[
&
](
producer_info
&
info
){
info
.
owner
=
producer
;
info
.
total_votes
=
0
;
info
.
producer_key
=
producer_key
;
info
.
is_active
=
true
;
info
.
url
=
url
;
info
.
location
=
location
;
});
}
}
void
system_contract
::
unregprod
(
const
account_name
producer
)
{
require_auth
(
producer
);
const
auto
&
prod
=
_producers
.
get
(
producer
,
"producer not found"
);
_producers
.
modify
(
prod
,
0
,
[
&
](
producer_info
&
info
){
info
.
deactivate
();
});
}
void
system_contract
::
update_elected_producers
(
block_timestamp
block_time
)
{
_gstate
.
last_producer_schedule_update
=
block_time
;
auto
idx
=
_producers
.
get_index
<
N
(
prototalvote
)
>
();
std
::
vector
<
std
::
pair
<
eosio
::
producer_key
,
uint16_t
>
>
top_producers
;
top_producers
.
reserve
(
21
);
for
(
auto
it
=
idx
.
cbegin
();
it
!=
idx
.
cend
()
&&
top_producers
.
size
()
<
21
&&
0
<
it
->
total_votes
&&
it
->
active
();
++
it
)
{
top_producers
.
emplace_back
(
std
::
pair
<
eosio
::
producer_key
,
uint16_t
>
({{
it
->
owner
,
it
->
producer_key
},
it
->
location
})
);
}
if
(
top_producers
.
size
()
<
_gstate
.
last_producer_schedule_size
)
{
return
;
}
/// sort by producer name
std
::
sort
(
top_producers
.
begin
(),
top_producers
.
end
()
);
std
::
vector
<
eosio
::
producer_key
>
producers
;
producers
.
reserve
(
top_producers
.
size
());
for
(
const
auto
&
item
:
top_producers
)
producers
.
push_back
(
item
.
first
);
bytes
packed_schedule
=
pack
(
producers
);
if
(
set_proposed_producers
(
packed_schedule
.
data
(),
packed_schedule
.
size
()
)
>=
0
)
{
_gstate
.
last_producer_schedule_size
=
static_cast
<
decltype
(
_gstate
.
last_producer_schedule_size
)
>
(
top_producers
.
size
()
);
}
}
double
stake2vote
(
int64_t
staked
)
{
/// TODO subtract 2080 brings the large numbers closer to this decade
double
weight
=
int64_t
(
(
now
()
-
(
block_timestamp
::
block_timestamp_epoch
/
1000
))
/
(
seconds_per_day
*
7
)
)
/
double
(
52
);
return
double
(
staked
)
*
std
::
pow
(
2
,
weight
);
}
/**
* @pre producers must be sorted from lowest to highest and must be registered and active
* @pre if proxy is set then no producers can be voted for
* @pre if proxy is set then proxy account must exist and be registered as a proxy
* @pre every listed producer or proxy must have been previously registered
* @pre voter must authorize this action
* @pre voter must have previously staked some EOS for voting
* @pre voter->staked must be up to date
*
* @post every producer previously voted for will have vote reduced by previous vote weight
* @post every producer newly voted for will have vote increased by new vote amount
* @post prior proxy will proxied_vote_weight decremented by previous vote weight
* @post new proxy will proxied_vote_weight incremented by new vote weight
*
* If voting for a proxy, the producer votes will not change until the proxy updates their own vote.
*/
void
system_contract
::
voteproducer
(
const
account_name
voter_name
,
const
account_name
proxy
,
const
std
::
vector
<
account_name
>&
producers
)
{
require_auth
(
voter_name
);
update_votes
(
voter_name
,
proxy
,
producers
,
true
);
}
void
system_contract
::
update_votes
(
const
account_name
voter_name
,
const
account_name
proxy
,
const
std
::
vector
<
account_name
>&
producers
,
bool
voting
)
{
//validate input
if
(
proxy
)
{
eosio_assert
(
producers
.
size
()
==
0
,
"cannot vote for producers and proxy at same time"
);
eosio_assert
(
voter_name
!=
proxy
,
"cannot proxy to self"
);
require_recipient
(
proxy
);
}
else
{
eosio_assert
(
producers
.
size
()
<=
30
,
"attempt to vote for too many producers"
);
for
(
size_t
i
=
1
;
i
<
producers
.
size
();
++
i
)
{
eosio_assert
(
producers
[
i
-
1
]
<
producers
[
i
],
"producer votes must be unique and sorted"
);
}
}
auto
voter
=
_voters
.
find
(
voter_name
);
eosio_assert
(
voter
!=
_voters
.
end
(),
"user must stake before they can vote"
);
/// staking creates voter object
eosio_assert
(
!
proxy
||
!
voter
->
is_proxy
,
"account registered as a proxy is not allowed to use a proxy"
);
/**
* The first time someone votes we calculate and set last_vote_weight, since they cannot unstake until
* after total_activated_stake hits threshold, we can use last_vote_weight to determine that this is
* their first vote and should consider their stake activated.
*/
if
(
voter
->
last_vote_weight
<=
0.0
)
{
_gstate
.
total_activated_stake
+=
voter
->
staked
;
if
(
_gstate
.
total_activated_stake
>=
min_activated_stake
&&
_gstate
.
thresh_activated_stake_time
==
0
)
{
_gstate
.
thresh_activated_stake_time
=
current_time
();
}
}
auto
new_vote_weight
=
stake2vote
(
voter
->
staked
);
if
(
voter
->
is_proxy
)
{
new_vote_weight
+=
voter
->
proxied_vote_weight
;
}
boost
::
container
::
flat_map
<
account_name
,
pair
<
double
,
bool
/*new*/
>
>
producer_deltas
;
if
(
voter
->
last_vote_weight
>
0
)
{
if
(
voter
->
proxy
)
{
auto
old_proxy
=
_voters
.
find
(
voter
->
proxy
);
eosio_assert
(
old_proxy
!=
_voters
.
end
(),
"old proxy not found"
);
//data corruption
_voters
.
modify
(
old_proxy
,
0
,
[
&
](
auto
&
vp
)
{
vp
.
proxied_vote_weight
-=
voter
->
last_vote_weight
;
});
propagate_weight_change
(
*
old_proxy
);
}
else
{
for
(
const
auto
&
p
:
voter
->
producers
)
{
auto
&
d
=
producer_deltas
[
p
];
d
.
first
-=
voter
->
last_vote_weight
;
d
.
second
=
false
;
}
}
}
if
(
proxy
)
{
auto
new_proxy
=
_voters
.
find
(
proxy
);
eosio_assert
(
new_proxy
!=
_voters
.
end
(),
"invalid proxy specified"
);
//if ( !voting ) { data corruption } else { wrong vote }
eosio_assert
(
!
voting
||
new_proxy
->
is_proxy
,
"proxy not found"
);
if
(
new_vote_weight
>=
0
)
{
_voters
.
modify
(
new_proxy
,
0
,
[
&
](
auto
&
vp
)
{
vp
.
proxied_vote_weight
+=
new_vote_weight
;
});
propagate_weight_change
(
*
new_proxy
);
}
}
else
{
if
(
new_vote_weight
>=
0
)
{
for
(
const
auto
&
p
:
producers
)
{
auto
&
d
=
producer_deltas
[
p
];
d
.
first
+=
new_vote_weight
;
d
.
second
=
true
;
}
}
}
for
(
const
auto
&
pd
:
producer_deltas
)
{
auto
pitr
=
_producers
.
find
(
pd
.
first
);
if
(
pitr
!=
_producers
.
end
()
)
{
eosio_assert
(
!
voting
||
pitr
->
active
()
||
!
pd
.
second
.
second
/* not from new set */
,
"producer is not currently registered"
);
_producers
.
modify
(
pitr
,
0
,
[
&
](
auto
&
p
)
{
p
.
total_votes
+=
pd
.
second
.
first
;
if
(
p
.
total_votes
<
0
)
{
// floating point arithmetics can give small negative numbers
p
.
total_votes
=
0
;
}
_gstate
.
total_producer_vote_weight
+=
pd
.
second
.
first
;
//eosio_assert( p.total_votes >= 0, "something bad happened" );
});
}
else
{
eosio_assert
(
!
pd
.
second
.
second
/* not from new set */
,
"producer is not registered"
);
//data corruption
}
}
_voters
.
modify
(
voter
,
0
,
[
&
](
auto
&
av
)
{
av
.
last_vote_weight
=
new_vote_weight
;
av
.
producers
=
producers
;
av
.
proxy
=
proxy
;
});
}
/**
* An account marked as a proxy can vote with the weight of other accounts which
* have selected it as a proxy. Other accounts must refresh their voteproducer to
* update the proxy's weight.
*
* @param isproxy - true if proxy wishes to vote on behalf of others, false otherwise
* @pre proxy must have something staked (existing row in voters table)
* @pre new state must be different than current state
*/
void
system_contract
::
regproxy
(
const
account_name
proxy
,
bool
isproxy
)
{
require_auth
(
proxy
);
auto
pitr
=
_voters
.
find
(
proxy
);
if
(
pitr
!=
_voters
.
end
()
)
{
eosio_assert
(
isproxy
!=
pitr
->
is_proxy
,
"action has no effect"
);
eosio_assert
(
!
isproxy
||
!
pitr
->
proxy
,
"account that uses a proxy is not allowed to become a proxy"
);
_voters
.
modify
(
pitr
,
0
,
[
&
](
auto
&
p
)
{
p
.
is_proxy
=
isproxy
;
});
propagate_weight_change
(
*
pitr
);
}
else
{
_voters
.
emplace
(
proxy
,
[
&
](
auto
&
p
)
{
p
.
owner
=
proxy
;
p
.
is_proxy
=
isproxy
;
});
}
}
void
system_contract
::
propagate_weight_change
(
const
voter_info
&
voter
)
{
eosio_assert
(
voter
.
proxy
==
0
||
!
voter
.
is_proxy
,
"account registered as a proxy is not allowed to use a proxy"
);
double
new_weight
=
stake2vote
(
voter
.
staked
);
if
(
voter
.
is_proxy
)
{
new_weight
+=
voter
.
proxied_vote_weight
;
}
/// don't propagate small changes (1 ~= epsilon)
if
(
fabs
(
new_weight
-
voter
.
last_vote_weight
)
>
1
)
{
if
(
voter
.
proxy
)
{
auto
&
proxy
=
_voters
.
get
(
voter
.
proxy
,
"proxy not found"
);
//data corruption
_voters
.
modify
(
proxy
,
0
,
[
&
](
auto
&
p
)
{
p
.
proxied_vote_weight
+=
new_weight
-
voter
.
last_vote_weight
;
}
);
propagate_weight_change
(
proxy
);
}
else
{
auto
delta
=
new_weight
-
voter
.
last_vote_weight
;
for
(
auto
acnt
:
voter
.
producers
)
{
auto
&
pitr
=
_producers
.
get
(
acnt
,
"producer not found"
);
//data corruption
_producers
.
modify
(
pitr
,
0
,
[
&
](
auto
&
p
)
{
p
.
total_votes
+=
delta
;
_gstate
.
total_producer_vote_weight
+=
delta
;
});
}
}
}
_voters
.
modify
(
voter
,
0
,
[
&
](
auto
&
v
)
{
v
.
last_vote_weight
=
new_weight
;
}
);
}
}
/// namespace eosiosystem
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录