Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
YottaChain
YTBP
提交
208a6016
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,发现更多精彩内容 >>
提交
208a6016
编写于
5月 09, 2018
作者:
A
Anton Perkov
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'slim' into system-contract-tests-fix
上级
111599bf
69b571ad
变更
28
隐藏空白更改
内联
并排
Showing
28 changed file
with
1189 addition
and
477 deletion
+1189
-477
contracts/eosio.system/eosio.system.abi
contracts/eosio.system/eosio.system.abi
+2
-3
contracts/eosio.system/eosio.system.hpp
contracts/eosio.system/eosio.system.hpp
+3
-3
contracts/eosio.system/producer_pay.cpp
contracts/eosio.system/producer_pay.cpp
+23
-17
contracts/eosio.token/eosio.token.cpp
contracts/eosio.token/eosio.token.cpp
+9
-5
contracts/eosiolib/account.h
contracts/eosiolib/account.h
+0
-46
contracts/eosiolib/account.hpp
contracts/eosiolib/account.hpp
+0
-81
contracts/eosiolib/permission.h
contracts/eosiolib/permission.h
+22
-1
contracts/test_api/test_api.cpp
contracts/test_api/test_api.cpp
+2
-0
contracts/test_api/test_api.hpp
contracts/test_api/test_api.hpp
+2
-0
contracts/test_api/test_permission.cpp
contracts/test_api/test_permission.cpp
+28
-0
libraries/chain/apply_context.cpp
libraries/chain/apply_context.cpp
+2
-0
libraries/chain/authorization_manager.cpp
libraries/chain/authorization_manager.cpp
+58
-16
libraries/chain/block_header_state.cpp
libraries/chain/block_header_state.cpp
+1
-1
libraries/chain/controller.cpp
libraries/chain/controller.cpp
+133
-143
libraries/chain/eosio_contract.cpp
libraries/chain/eosio_contract.cpp
+8
-18
libraries/chain/include/eosio/chain/authority.hpp
libraries/chain/include/eosio/chain/authority.hpp
+7
-0
libraries/chain/include/eosio/chain/authorization_manager.hpp
...aries/chain/include/eosio/chain/authorization_manager.hpp
+8
-0
libraries/chain/include/eosio/chain/config.hpp
libraries/chain/include/eosio/chain/config.hpp
+1
-0
libraries/chain/include/eosio/chain/controller.hpp
libraries/chain/include/eosio/chain/controller.hpp
+22
-16
libraries/chain/include/eosio/chain/permission_object.hpp
libraries/chain/include/eosio/chain/permission_object.hpp
+29
-35
libraries/chain/transaction_context.cpp
libraries/chain/transaction_context.cpp
+10
-0
libraries/chain/wasm_interface.cpp
libraries/chain/wasm_interface.cpp
+9
-6
libraries/testing/tester.cpp
libraries/testing/tester.cpp
+17
-6
plugins/producer_plugin/producer_plugin.cpp
plugins/producer_plugin/producer_plugin.cpp
+139
-28
unittests/api_tests.cpp
unittests/api_tests.cpp
+125
-15
unittests/delay_tests.cpp
unittests/delay_tests.cpp
+7
-1
unittests/eosio.system_tests.cpp
unittests/eosio.system_tests.cpp
+427
-36
unittests/forked_tests.cpp
unittests/forked_tests.cpp
+95
-0
未找到文件。
contracts/eosio.system/eosio.system.abi
浏览文件 @
208a6016
...
...
@@ -116,8 +116,7 @@
"name": "eosio_parameters",
"base": "blockchain_parameters",
"fields": [
{"name":"max_ram_size", "type":"uint64"},
{"name":"percent_of_max_inflation_rate", "type":"uint32"}
{"name":"max_ram_size", "type":"uint64"}
]
},{
"name": "eosio_global_state",
...
...
@@ -127,7 +126,7 @@
{"name":"total_ram_stake", "type":"asset"},
{"name":"last_producer_schedule_update", "type":"time"},
{"name":"last_pervote_bucket_fill", "type":"uint64"},
{"name":"
eos_bucket",
"type":"asset"},
{"name":"
pervote_bucket",
"type":"asset"},
{"name":"savings", "type":"asset"},
{"name":"last_producer_schedule_id", "type":"checksum160"},
{"name":"total_activatied_stake", "type":"int64"}
...
...
contracts/eosio.system/eosio.system.hpp
浏览文件 @
208a6016
...
...
@@ -33,7 +33,7 @@ namespace eosiosystem {
block_timestamp
last_producer_schedule_update
=
0
;
uint64_t
last_pervote_bucket_fill
=
0
;
eosio
::
asset
eos
_bucket
;
eosio
::
asset
pervote
_bucket
;
eosio
::
asset
savings
;
checksum160
last_producer_schedule_id
;
...
...
@@ -43,7 +43,7 @@ namespace eosiosystem {
EOSLIB_SERIALIZE_DERIVED
(
eosio_global_state
,
eosio_parameters
,
(
total_ram_bytes_reserved
)(
total_ram_stake
)
(
last_producer_schedule_update
)
(
last_pervote_bucket_fill
)
(
eos
_bucket
)(
savings
)(
last_producer_schedule_id
)(
total_activated_stake
)
)
(
pervote
_bucket
)(
savings
)(
last_producer_schedule_id
)(
total_activated_stake
)
)
};
struct
producer_info
{
...
...
@@ -191,7 +191,7 @@ namespace eosiosystem {
private:
eosio
::
asset
payment_per_block
(
double
rate
,
const
eosio
::
asset
&
token_supply
,
uint32_t
num_blocks
);
eosio
::
asset
payment_per_vote
(
const
account_name
&
owner
,
double
owners_votes
,
const
eosio
::
asset
&
eos
_bucket
);
eosio
::
asset
payment_per_vote
(
const
account_name
&
owner
,
double
owners_votes
,
const
eosio
::
asset
&
pervote
_bucket
);
eosio
::
asset
supply_growth
(
double
rate
,
const
eosio
::
asset
&
token_supply
,
time
seconds
);
...
...
contracts/eosio.system/producer_pay.cpp
浏览文件 @
208a6016
...
...
@@ -29,11 +29,11 @@ namespace eosiosystem {
using
namespace
eosio
;
/** until activated stake crosses this threshold no new rewards are paid */
if
(
_gstate
.
total_activated_stake
<
150
0000000000
/* 150'000'000'0000 */
)
if
(
_gstate
.
total_activated_stake
<
150
'000'000'0000
)
return
;
if
(
_gstate
.
last_pervote_bucket_fill
==
0
)
/// start the presses
_gstate
.
last_pervote_bucket_fill
=
timestamp
;
_gstate
.
last_pervote_bucket_fill
=
current_time
()
;
auto
prod
=
_producers
.
find
(
producer
);
if
(
prod
!=
_producers
.
end
()
)
{
...
...
@@ -50,9 +50,10 @@ namespace eosiosystem {
}
eosio
::
asset
system_contract
::
payment_per_vote
(
const
account_name
&
owner
,
double
owners_votes
,
const
eosio
::
asset
&
eos
_bucket
)
{
eosio
::
asset
system_contract
::
payment_per_vote
(
const
account_name
&
owner
,
double
owners_votes
,
const
eosio
::
asset
&
pervote
_bucket
)
{
eosio
::
asset
payment
(
0
,
S
(
4
,
EOS
));
if
(
eos_bucket
.
amount
<
min_daily_tokens
)
{
const
int64_t
min_daily_amount
=
100
*
10000
;
if
(
pervote_bucket
.
amount
<
min_daily_tokens
)
{
return
payment
;
}
...
...
@@ -74,8 +75,8 @@ namespace eosiosystem {
}
total_producer_votes
+=
itr
->
total_votes
;
running_payment_amount
=
(
itr
->
total_votes
)
*
double
(
eos
_bucket
.
amount
)
/
total_producer_votes
;
if
(
running_payment_amount
<
min_daily_
tokens
)
{
running_payment_amount
=
(
itr
->
total_votes
)
*
double
(
pervote
_bucket
.
amount
)
/
total_producer_votes
;
if
(
running_payment_amount
<
min_daily_
amount
)
{
if
(
itr
->
owner
==
owner
)
{
to_be_payed
=
false
;
}
...
...
@@ -85,7 +86,7 @@ namespace eosiosystem {
}
if
(
to_be_payed
)
{
payment
.
amount
=
static_cast
<
int64_t
>
(
(
double
(
eos
_bucket
.
amount
)
*
owners_votes
)
/
total_producer_votes
);
payment
.
amount
=
static_cast
<
int64_t
>
(
(
double
(
pervote
_bucket
.
amount
)
*
owners_votes
)
/
total_producer_votes
);
}
return
payment
;
...
...
@@ -102,24 +103,29 @@ namespace eosiosystem {
eosio_assert
(
current_time
()
>=
prod
->
last_claim_time
+
useconds_per_day
,
"already claimed rewards within a day"
);
}
auto
parameters
=
_global
.
get
();
const
asset
token_supply
=
token
(
N
(
eosio
.
token
)).
get_supply
(
symbol_type
(
system_token_symbol
).
name
()
);
const
uint32_t
secs_since_last_fill
=
static_cast
<
uint32_t
>
(
(
current_time
()
-
parameters
.
last_pervote_bucket_fill
)
/
1000000
);
const
uint32_t
secs_since_last_fill
=
static_cast
<
uint32_t
>
(
(
current_time
()
-
_gstate
.
last_pervote_bucket_fill
)
/
1000000
);
const
asset
to_
eos
_bucket
=
supply_growth
(
standby_rate
,
token_supply
,
secs_since_last_fill
);
const
asset
to_
pervote
_bucket
=
supply_growth
(
standby_rate
,
token_supply
,
secs_since_last_fill
);
const
asset
to_savings
=
supply_growth
(
continuous_rate
-
(
perblock_rate
+
standby_rate
),
token_supply
,
secs_since_last_fill
);
const
asset
perblock_pay
=
payment_per_block
(
perblock_rate
,
token_supply
,
prod
->
produced_blocks
);
const
asset
issue_amount
=
to_eos_bucket
+
to_savings
+
perblock_pay
;
const
asset
issue_amount
=
to_pervote_bucket
+
to_savings
+
perblock_pay
;
const
asset
pervote_pay
=
payment_per_vote
(
owner
,
prod
->
total_votes
,
to_pervote_bucket
+
_gstate
.
pervote_bucket
);
if
(
perblock_pay
.
amount
+
pervote_pay
.
amount
==
0
)
{
_producers
.
modify
(
prod
,
0
,
[
&
](
auto
&
p
)
{
p
.
last_claim_time
=
current_time
();
});
return
;
}
INLINE_ACTION_SENDER
(
eosio
::
token
,
issue
)(
N
(
eosio
.
token
),
{{
N
(
eosio
),
N
(
active
)}},
{
N
(
eosio
),
issue_amount
,
std
::
string
(
"issue tokens for producer pay and savings"
)}
);
const
asset
pervote_pay
=
payment_per_vote
(
owner
,
prod
->
total_votes
,
to_eos_bucket
+
parameters
.
eos_bucket
);
parameters
.
eos_bucket
+=
(
to_eos_bucket
-
pervote_pay
);
parameters
.
last_pervote_bucket_fill
=
current_time
();
parameters
.
savings
+=
to_savings
;
_global
.
set
(
parameters
,
_self
);
_gstate
.
pervote_bucket
+=
(
to_pervote_bucket
-
pervote_pay
);
_gstate
.
last_pervote_bucket_fill
=
current_time
();
_gstate
.
savings
+=
to_savings
;
INLINE_ACTION_SENDER
(
eosio
::
token
,
transfer
)(
N
(
eosio
.
token
),
{
N
(
eosio
),
N
(
active
)},
{
N
(
eosio
),
owner
,
perblock_pay
+
pervote_pay
,
std
::
string
(
"producer claiming rewards"
)
}
);
...
...
contracts/eosio.token/eosio.token.cpp
浏览文件 @
208a6016
...
...
@@ -38,9 +38,14 @@ void token::create( account_name issuer,
void
token
::
issue
(
account_name
to
,
asset
quantity
,
string
memo
)
{
print
(
"issue"
);
auto
sym
=
quantity
.
symbol
.
name
();
stats
statstable
(
_self
,
sym
);
const
auto
&
st
=
statstable
.
get
(
sym
);
auto
sym
=
quantity
.
symbol
;
eosio_assert
(
sym
.
is_valid
(),
"invalid symbol name"
);
auto
sym_name
=
sym
.
name
();
stats
statstable
(
_self
,
sym_name
);
auto
existing
=
statstable
.
find
(
sym_name
);
eosio_assert
(
existing
!=
statstable
.
end
(),
"token with symbol does not exist, create token before issue"
);
const
auto
&
st
=
*
existing
;
require_auth
(
st
.
issuer
);
eosio_assert
(
quantity
.
is_valid
(),
"invalid quantity"
);
...
...
@@ -55,8 +60,7 @@ void token::issue( account_name to, asset quantity, string memo )
add_balance
(
st
.
issuer
,
quantity
,
st
,
st
.
issuer
);
if
(
to
!=
st
.
issuer
)
{
if
(
to
!=
st
.
issuer
)
{
SEND_INLINE_ACTION
(
*
this
,
transfer
,
{
st
.
issuer
,
N
(
active
)},
{
st
.
issuer
,
to
,
quantity
,
memo
}
);
}
}
...
...
contracts/eosiolib/account.h
已删除
100644 → 0
浏览文件 @
111599bf
/**
* @file account.h
* @copyright defined in eos/LICENSE.txt
*/
#pragma once
#include <eosiolib/types.h>
/**
* @defgroup accountapi Account API
* @brief Define API for querying account data
* @ingroup contractdev
*/
/**
* @defgroup accountcapi Account C API
* @brief C API for querying account data
* @ingroup accountapi
* @{
*/
extern
"C"
{
/**
* @brief Retrieve the balance for the provided account
* @details Retrieve the balance for the provided account
*
* @param balance - a pointer to a range of memory to store balance data
* @param len - length of the range of memory to store balance data
* @return true if account information is retrieved
*
* @pre data is a valid pointer to a range of memory at least datalen bytes long
* @pre data is a pointer to a balance object
* @pre *((uint64_t*)data) stores the primary key
*
* Example:
* @code
* balance b;
* b.account = N(myaccount);
* balance(b, sizeof(balance));
* @endcode
*
*/
bool
account_balance_get
(
void
*
balance
,
uint32_t
len
);
///@ } accountcapi
}
contracts/eosiolib/account.hpp
已删除
100644 → 0
浏览文件 @
111599bf
/**
* @file account.hpp
* @copyright defined in eos/LICENSE.txt
* @brief Defines types and ABI for account API interactions
*
*/
#pragma once
#include <eosiolib/account.h>
#include <eosiolib/print.hpp>
#include <eosiolib/asset.hpp>
namespace
eosio
{
namespace
account
{
/**
* @defgroup accountcppapi Account C++ API
* @brief C++ API for querying account data, e.g. account balance
* @ingroup accountapi
*
* @{
*/
/**
* @brief The binary structure expected and populated by native balance function.
* @details
* Example:
* @code
* account_balance test1_balance;
* test1_balance.account = N(test1);
* if (account_api::get(test1_balance))
* {
* eosio::print("test1 balance=", test1_balance.eos_balance, "\n");
* }
* @endcode
* @{
*/
struct
PACKED
(
account_balance
)
{
/**
* @brief Name of the account who's balance this is
* @details Name of the account who's balance this is
*/
account_name
account
;
/**
* @brief Balance for this account
* @details Balance for this account
*/
asset
eos_balance
;
/**
* @brief Staked balance for this account
* @details Staked balance for this account
*/
asset
staked_balance
;
/**
* @brief Unstaking balance for this account
* @details Unstaking balance for this account
*/
asset
unstaking_balance
;
/**
* @brief Time at which last unstaking occurred for this account
* @details Time at which last unstaking occurred for this account
*/
time
last_unstaking_time
;
};
/// @} account_balance
/**
* @brief Retrieve a populated balance structure
* @details Retrieve a populated balance structure
* @param acnt - account
* @return true if account's balance is found
*/
bool
get
(
account_balance
&
acnt
)
{
return
account_balance_get
(
&
acnt
,
sizeof
(
account_balance
));
}
/// @} eosio
}
}
contracts/eosiolib/permission.h
浏览文件 @
208a6016
...
...
@@ -28,7 +28,7 @@ extern "C" {
* @brief Checks if a permission is authorized by a provided delay and a provided set of keys and permissions
*
* @param account - the account owner of the permission
* @param permission - the
permission name
to check for authorization
* @param permission - the
name of the permission
to check for authorization
* @param pubkeys_data - pointer to the start of the serialized vector of provided public keys
* @param pubkeys_size - size (in bytes) of serialized vector of provided public keys (can be 0 if no public keys are to be provided)
* @param perms_data - pointer to the start of the serialized vector of provided permissions (empty permission name acts as wildcard)
...
...
@@ -44,4 +44,25 @@ extern "C" {
const
char
*
perms_data
,
uint32_t
perms_size
,
uint64_t
delay_us
);
/**
* @brief Returns the last used time of a permission
*
* @param account - the account owner of the permission
* @param permission - the name of the permission
*
* @return the last used time (in microseconds since Unix epoch) of the permission
*/
int64_t
get_permission_last_used
(
account_name
account
,
permission_name
permission
);
/**
* @brief Returns the creation time of an account
*
* @param account - the account
*
* @return the creation time (in microseconds since Unix epoch) of the account
*/
int64_t
get_account_creation_time
(
account_name
account
);
}
contracts/test_api/test_api.cpp
浏览文件 @
208a6016
...
...
@@ -165,6 +165,8 @@ extern "C" {
// test permission
WASM_TEST_HANDLER_EX
(
test_permission
,
check_authorization
);
WASM_TEST_HANDLER_EX
(
test_permission
,
test_permission_last_used
);
WASM_TEST_HANDLER_EX
(
test_permission
,
test_account_creation_time
);
//unhandled test call
eosio_assert
(
false
,
"Unknown Test"
);
...
...
contracts/test_api/test_api.hpp
浏览文件 @
208a6016
...
...
@@ -252,6 +252,8 @@ struct test_softfloat {
struct
test_permission
{
static
void
check_authorization
(
uint64_t
receiver
,
uint64_t
code
,
uint64_t
action
);
static
void
test_permission_last_used
(
uint64_t
receiver
,
uint64_t
code
,
uint64_t
action
);
static
void
test_account_creation_time
(
uint64_t
receiver
,
uint64_t
code
,
uint64_t
action
);
};
struct
test_datastream
{
...
...
contracts/test_api/test_permission.cpp
浏览文件 @
208a6016
...
...
@@ -49,3 +49,31 @@ void test_permission::check_authorization(uint64_t receiver, uint64_t code, uint
db_update_i64
(
itr
,
self
,
&
res64
,
sizeof
(
int64_t
));
}
}
struct
test_permission_last_used_msg
{
account_name
account
;
permission_name
permission
;
int64_t
last_used_time
;
EOSLIB_SERIALIZE
(
test_permission_last_used_msg
,
(
account
)(
permission
)(
last_used_time
)
)
};
void
test_permission
::
test_permission_last_used
(
uint64_t
receiver
,
uint64_t
code
,
uint64_t
action
)
{
(
void
)
code
;
(
void
)
action
;
using
namespace
eosio
;
auto
params
=
unpack_action_data
<
test_permission_last_used_msg
>
();
eosio_assert
(
get_permission_last_used
(
params
.
account
,
params
.
permission
)
==
params
.
last_used_time
,
"unexpected last used permission time"
);
}
void
test_permission
::
test_account_creation_time
(
uint64_t
receiver
,
uint64_t
code
,
uint64_t
action
)
{
(
void
)
code
;
(
void
)
action
;
using
namespace
eosio
;
auto
params
=
unpack_action_data
<
test_permission_last_used_msg
>
();
eosio_assert
(
get_account_creation_time
(
params
.
account
)
==
params
.
last_used_time
,
"unexpected account creation time"
);
}
libraries/chain/apply_context.cpp
浏览文件 @
208a6016
...
...
@@ -222,6 +222,7 @@ void apply_context::execute_inline( action&& a ) {
// action was made at the moment the deferred transaction was executed with potentially no forewarning?
}
}
_inline_actions
.
emplace_back
(
move
(
a
)
);
}
...
...
@@ -476,6 +477,7 @@ void apply_context::db_update_i64( int iterator, account_name payer, const char*
}
db
.
modify
(
obj
,
[
&
](
auto
&
o
)
{
o
.
value
.
resize
(
0
);
o
.
value
.
resize
(
buffer_size
);
memcpy
(
o
.
value
.
data
(),
buffer
,
buffer_size
);
o
.
payer
=
payer
;
...
...
libraries/chain/authorization_manager.cpp
浏览文件 @
208a6016
...
...
@@ -35,15 +35,22 @@ namespace eosio { namespace chain {
time_point
initial_creation_time
)
{
auto
creation_time
=
initial_creation_time
;
if
(
creation_time
==
time_point
()
)
{
creation_time
=
_control
.
pending_block_time
();
}
const
auto
&
perm_usage
=
_db
.
create
<
permission_usage_object
>
([
&
](
auto
&
p
)
{
p
.
last_used
=
creation_time
;
});
const
auto
&
perm
=
_db
.
create
<
permission_object
>
([
&
](
auto
&
p
)
{
p
.
name
=
name
;
p
.
parent
=
parent
;
p
.
owner
=
account
;
p
.
auth
=
auth
;
if
(
initial_creation_time
==
time_point
())
p
.
last_updated
=
_control
.
pending_block_time
();
else
p
.
last_updated
=
initial_creation_time
;
p
.
usage_id
=
perm_usage
.
id
;
p
.
parent
=
parent
;
p
.
owner
=
account
;
p
.
name
=
name
;
p
.
last_updated
=
creation_time
;
p
.
auth
=
auth
;
});
return
perm
;
}
...
...
@@ -55,19 +62,54 @@ namespace eosio { namespace chain {
time_point
initial_creation_time
)
{
auto
creation_time
=
initial_creation_time
;
if
(
creation_time
==
time_point
()
)
{
creation_time
=
_control
.
pending_block_time
();
}
const
auto
&
perm_usage
=
_db
.
create
<
permission_usage_object
>
([
&
](
auto
&
p
)
{
p
.
last_used
=
creation_time
;
});
const
auto
&
perm
=
_db
.
create
<
permission_object
>
([
&
](
auto
&
p
)
{
p
.
name
=
name
;
p
.
parent
=
parent
;
p
.
owner
=
account
;
p
.
auth
=
std
::
move
(
auth
);
if
(
initial_creation_time
==
time_point
())
p
.
last_updated
=
_control
.
pending_block_time
();
else
p
.
last_updated
=
initial_creation_time
;
p
.
usage_id
=
perm_usage
.
id
;
p
.
parent
=
parent
;
p
.
owner
=
account
;
p
.
name
=
name
;
p
.
last_updated
=
creation_time
;
p
.
auth
=
std
::
move
(
auth
);
});
return
perm
;
}
void
authorization_manager
::
modify_permission
(
const
permission_object
&
permission
,
const
authority
&
auth
)
{
_db
.
modify
(
permission
,
[
&
](
permission_object
&
po
)
{
po
.
auth
=
auth
;
po
.
last_updated
=
_control
.
pending_block_time
();
});
}
void
authorization_manager
::
remove_permission
(
const
permission_object
&
permission
)
{
const
auto
&
index
=
_db
.
template
get_index
<
permission_index
,
by_parent
>();
auto
range
=
index
.
equal_range
(
permission
.
id
);
EOS_ASSERT
(
range
.
first
==
range
.
second
,
action_validate_exception
,
"Cannot remove a permission which has children. Remove the children first."
);
_db
.
get_mutable_index
<
permission_usage_index
>
().
remove_object
(
permission
.
usage_id
.
_id
);
_db
.
remove
(
permission
);
}
void
authorization_manager
::
update_permission_usage
(
const
permission_object
&
permission
)
{
const
auto
&
puo
=
_db
.
get
<
permission_usage_object
,
by_id
>
(
permission
.
usage_id
);
_db
.
modify
(
puo
,
[
&
](
permission_usage_object
&
p
)
{
p
.
last_used
=
_control
.
pending_block_time
();
});
}
fc
::
time_point
authorization_manager
::
get_permission_last_used
(
const
permission_object
&
permission
)
const
{
return
_db
.
get
<
permission_usage_object
,
by_id
>
(
permission
.
usage_id
).
last_used
;
}
const
permission_object
*
authorization_manager
::
find_permission
(
const
permission_level
&
level
)
const
{
try
{
FC_ASSERT
(
!
level
.
actor
.
empty
()
&&
!
level
.
permission
.
empty
(),
"Invalid permission"
);
...
...
libraries/chain/block_header_state.cpp
浏览文件 @
208a6016
...
...
@@ -245,7 +245,7 @@ namespace eosio { namespace chain {
void
block_header_state
::
add_confirmation
(
const
header_confirmation
&
conf
)
{
for
(
const
auto
&
c
:
confirmations
)
FC_ASSERT
(
c
.
producer
=
=
conf
.
producer
,
"block already confirmed by this producer"
);
FC_ASSERT
(
c
.
producer
!
=
conf
.
producer
,
"block already confirmed by this producer"
);
auto
key
=
active_schedule
.
get_producer_key
(
conf
.
producer
);
FC_ASSERT
(
key
!=
public_key_type
(),
"producer not in current schedule"
);
...
...
libraries/chain/controller.cpp
浏览文件 @
208a6016
...
...
@@ -122,7 +122,9 @@ struct controller_impl {
* errors and throw exceptions. Unless those exceptions are caught it could impact consensus and/or
* cause a node to fork.
*
* TODO: define special exceptions that can be thrown to reject transactions or blocks
* If it is ever desirable to let a signal handler bubble an exception out of this method
* a full audit of its uses needs to be undertaken.
*
*/
template
<
typename
Signal
,
typename
Arg
>
void
emit
(
const
Signal
&
s
,
Arg
&&
a
)
{
...
...
@@ -133,10 +135,6 @@ struct controller_impl {
}
}
void
emit_transaction
(
const
transaction_metadata_ptr
&
trx
,
const
transaction_trace_ptr
&
trace
)
{
}
void
on_irreversible
(
const
block_state_ptr
&
s
)
{
if
(
!
blog
.
head
()
)
blog
.
read_head
();
...
...
@@ -410,8 +408,6 @@ struct controller_impl {
trace
->
receipt
=
push_receipt
(
gto
.
trx_id
,
transaction_receipt
::
soft_fail
,
trace
->
cpu_usage
,
trace
->
net_usage
);
fc
::
move_append
(
pending
->
_actions
,
move
(
trx_context
.
executed
)
);
remove_scheduled_transaction
(
gto
);
emit
(
self
.
applied_transaction
,
trace
);
trx_context
.
squash
();
...
...
@@ -424,11 +420,7 @@ struct controller_impl {
return
trace
;
}
void
remove_scheduled_transaction
(
const
generated_transaction_object
&
gto
,
bool
expire
=
false
)
{
if
(
expire
)
{
push_receipt
(
gto
.
trx_id
,
transaction_receipt
::
expired
,
0
,
0
);
}
void
remove_scheduled_transaction
(
const
generated_transaction_object
&
gto
)
{
resource_limits
.
add_pending_ram_usage
(
gto
.
payer
,
-
(
config
::
billable_size_v
<
generated_transaction_object
>
+
gto
.
packed_trx
.
size
())
...
...
@@ -438,17 +430,30 @@ struct controller_impl {
db
.
remove
(
gto
);
}
void
push_scheduled_transaction
(
const
generated_transaction_object
&
gto
,
fc
::
time_point
deadline
)
bool
failure_is_subjective
(
const
fc
::
exception
&
e
)
{
auto
code
=
e
.
code
();
return
(
code
==
tx_soft_cpu_usage_exceeded
::
code_value
)
||
(
code
==
tx_soft_net_usage_exceeded
::
code_value
)
||
(
code
==
tx_deadline_exceeded
::
code_value
);
}
transaction_trace_ptr
push_scheduled_transaction
(
const
generated_transaction_object
&
gto
,
fc
::
time_point
deadline
)
{
try
{
auto
undo_session
=
db
.
start_undo_session
(
true
);
fc
::
datastream
<
const
char
*>
ds
(
gto
.
packed_trx
.
data
(),
gto
.
packed_trx
.
size
()
);
auto
remove_retained_state
=
fc
::
make_scoped_exit
([
&
,
this
](){
remove_scheduled_transaction
(
gto
);
});
FC_ASSERT
(
gto
.
delay_until
<=
self
.
pending_block_time
(),
"this transaction isn't ready"
,
(
"gto.delay_until"
,
gto
.
delay_until
)(
"pbt"
,
self
.
pending_block_time
())
);
if
(
gto
.
expiration
<
self
.
pending_block_time
()
)
{
remove_scheduled_transaction
(
gto
,
true
);
// expire the transaction
return
;
auto
trace
=
std
::
make_shared
<
transaction_trace
>
();
trace
->
id
=
gto
.
trx_id
;
trace
->
scheduled
=
false
;
trace
->
receipt
=
push_receipt
(
gto
.
trx_id
,
transaction_receipt
::
expired
,
0
,
0
);
// expire the transaction
return
trace
;
}
auto
start
=
fc
::
time_point
::
now
();
...
...
@@ -459,7 +464,6 @@ struct controller_impl {
transaction_trace_ptr
trace
=
trx_context
.
trace
;
flat_set
<
account_name
>
bill_to_accounts
;
uint64_t
max_cpu
=
0
;
bool
abort_on_error
=
false
;
try
{
trx_context
.
init_for_deferred_trx
(
deadline
,
gto
.
published
);
bill_to_accounts
=
trx_context
.
bill_to_accounts
;
...
...
@@ -477,21 +481,13 @@ struct controller_impl {
fc
::
move_append
(
pending
->
_actions
,
move
(
trx_context
.
executed
)
);
remove_scheduled_transaction
(
gto
);
emit
(
self
.
applied_transaction
,
trace
);
try
{
emit
(
self
.
applied_transaction
,
trace
);
}
catch
(
...
)
{
abort_on_error
=
true
;
throw
;
}
trx_context
.
squash
();
undo_session
.
squash
();
restore
.
cancel
();
return
;
return
trace
;
}
catch
(
const
fc
::
exception
&
e
)
{
if
(
abort_on_error
)
// abort_on_error should normally should not be set at this point, but if it is then that means
throw
;
// something went wrong while emitting the applied_transaction signal and we should abort
trace
->
except
=
e
;
trace
->
except_ptr
=
std
::
current_exception
();
trace
->
elapsed
=
fc
::
time_point
::
now
()
-
start
;
...
...
@@ -500,7 +496,7 @@ struct controller_impl {
// Only soft or hard failure logic below:
if
(
gto
.
sender
!=
account_name
()
)
{
if
(
gto
.
sender
!=
account_name
()
&&
!
failure_is_subjective
(
*
trace
->
except
)
)
{
// Attempt error handling for the generated transaction.
edump
((
trace
->
except
->
to_detail_string
()));
auto
error_trace
=
apply_onerror
(
gto
,
deadline
,
trace
->
cpu_usage
,
start
);
...
...
@@ -508,11 +504,11 @@ struct controller_impl {
trace
=
error_trace
;
if
(
!
trace
->
except_ptr
)
{
undo_session
.
squash
();
return
;
return
trace
;
}
}
// Only hard failure logic below:
// Only hard failure
OR subjective failure
logic below:
trace
->
cpu_usage
=
((
trace
->
cpu_usage
+
1023
)
/
1024
)
*
1024
;
// Round up cpu_usage to nearest multiple of 1024
trace
->
cpu_usage
=
std
::
min
(
trace
->
cpu_usage
,
max_cpu
);
...
...
@@ -520,14 +516,17 @@ struct controller_impl {
block_timestamp_type
(
self
.
pending_block_time
()).
slot
);
// Should never fail
trace
->
elapsed
=
fc
::
time_point
::
now
()
-
start
;
trace
->
receipt
=
push_receipt
(
gto
.
trx_id
,
transaction_receipt
::
hard_fail
,
trace
->
cpu_usage
,
0
);
remove_scheduled_transaction
(
gto
);
emit
(
self
.
applied_transaction
,
trace
);
if
(
failure_is_subjective
(
*
trace
->
except
))
{
// this is a subjective failure, don't remove the retained state so it can be
// retried at a later time and don't include any artifact of the transaction in the pending block
remove_retained_state
.
cancel
();
}
else
{
trace
->
receipt
=
push_receipt
(
gto
.
trx_id
,
transaction_receipt
::
hard_fail
,
trace
->
cpu_usage
,
0
);
emit
(
self
.
applied_transaction
,
trace
);
undo_session
.
squash
();
}
undo_session
.
squash
()
;
return
trace
;
}
FC_CAPTURE_AND_RETHROW
()
}
/// push_scheduled_transaction
...
...
@@ -549,16 +548,6 @@ struct controller_impl {
return
r
;
}
bool
push_next_unapplied_transaction
(
fc
::
time_point
deadline
)
{
auto
itr
=
unapplied_transactions
.
begin
();
if
(
itr
==
unapplied_transactions
.
end
()
)
return
false
;
// Intentionally copy transaction_metadata_ptr because it will be removed from unapplied_transactions and make the const& dangling.
push_transaction
(
transaction_metadata_ptr
(
itr
->
second
),
deadline
);
return
true
;
}
void
transaction_trace_notify
(
const
transaction_metadata_ptr
&
trx
,
const
transaction_trace_ptr
&
trace
)
{
if
(
trx
->
on_result
)
{
(
trx
->
on_result
)(
trace
);
...
...
@@ -576,79 +565,80 @@ struct controller_impl {
* determine whether to execute it now or to delay it. Lastly it inserts a transaction receipt into
* the pending block.
*/
void
push_transaction
(
const
transaction_metadata_ptr
&
trx
,
fc
::
time_point
deadline
=
fc
::
time_point
::
maximum
()
,
bool
implicit
=
false
)
transaction_trace_ptr
push_transaction
(
const
transaction_metadata_ptr
&
trx
,
fc
::
time_point
deadline
,
bool
implicit
=
false
)
{
transaction_trace_ptr
trace
;
try
{
if
(
deadline
==
fc
::
time_point
()
&&
!
implicit
)
{
unapplied_transactions
[
trx
->
signed_id
]
=
trx
;
return
;
}
FC_ASSERT
(
deadline
!=
fc
::
time_point
(),
"deadline cannot be uninitialized"
);
auto
start
=
fc
::
time_point
::
now
();
transaction_context
trx_context
(
self
,
trx
->
trx
,
trx
->
id
);
trace
=
trx_context
.
trace
;
transaction_trace_ptr
trace
;
try
{
if
(
implicit
)
{
trx_context
.
init_for_implicit_trx
(
deadline
);
}
else
{
unapplied_transactions
.
erase
(
trx
->
signed_id
);
trx_context
.
init_for_input_trx
(
deadline
,
trx
->
packed_trx
.
get_unprunable_size
(),
trx
->
packed_trx
.
get_prunable_size
(),
trx
->
trx
.
signatures
.
size
()
);
}
trx_context
.
delay
=
fc
::
seconds
(
trx
->
trx
.
delay_sec
);
if
(
!
implicit
)
{
authorization
.
check_authorization
(
trx
->
trx
.
actions
,
trx
->
recover_keys
(),
{},
trx_context
.
delay
,
std
::
bind
(
&
transaction_context
::
add_cpu_usage_and_check_time
,
&
trx_context
,
std
::
placeholders
::
_1
),
false
);
}
auto
start
=
fc
::
time_point
::
now
();
transaction_context
trx_context
(
self
,
trx
->
trx
,
trx
->
id
);
trace
=
trx_context
.
trace
;
try
{
if
(
implicit
)
{
trx_context
.
init_for_implicit_trx
(
deadline
);
}
else
{
trx_context
.
init_for_input_trx
(
deadline
,
trx
->
packed_trx
.
get_unprunable_size
(),
trx
->
packed_trx
.
get_prunable_size
(),
trx
->
trx
.
signatures
.
size
());
}
trx_context
.
exec
();
trx_context
.
finalize
();
// Automatically rounds up network and CPU usage in trace and bills payers if successful
trace
->
elapsed
=
fc
::
time_point
::
now
()
-
start
;
trx_context
.
delay
=
fc
::
seconds
(
trx
->
trx
.
delay_sec
);
if
(
!
implicit
)
{
authorization
.
check_authorization
(
trx
->
trx
.
actions
,
trx
->
recover_keys
(),
{},
trx_context
.
delay
,
std
::
bind
(
&
transaction_context
::
add_cpu_usage_and_check_time
,
&
trx_context
,
std
::
placeholders
::
_1
),
false
);
}
auto
restore
=
make_block_restore_point
();
trx_context
.
exec
();
trx_context
.
finalize
();
// Automatically rounds up network and CPU usage in trace and bills payers if successful
trace
->
elapsed
=
fc
::
time_point
::
now
()
-
start
;
auto
restore
=
make_block_restore_point
();
if
(
!
implicit
)
{
transaction_receipt
::
status_enum
s
=
(
trx_context
.
delay
==
fc
::
seconds
(
0
))
?
transaction_receipt
::
executed
:
transaction_receipt
::
delayed
;
trace
->
receipt
=
push_receipt
(
trx
->
packed_trx
,
s
,
trace
->
cpu_usage
,
trace
->
net_usage
);
pending
->
_pending_block_state
->
trxs
.
emplace_back
(
trx
);
unapplied_transactions
.
erase
(
trx
->
signed_id
);
}
else
{
transaction_receipt_header
r
;
r
.
status
=
transaction_receipt
::
executed
;
r
.
kcpu_usage
=
trace
->
cpu_usage
/
1024
;
r
.
net_usage_words
=
trace
->
net_usage
/
8
;
trace
->
receipt
=
r
;
}
if
(
!
implicit
)
{
transaction_receipt
::
status_enum
s
=
(
trx_context
.
delay
==
fc
::
seconds
(
0
)
)
?
transaction_receipt
::
executed
:
transaction_receipt
::
delayed
;
trace
->
receipt
=
push_receipt
(
trx
->
packed_trx
,
s
,
trace
->
cpu_usage
,
trace
->
net_usage
);
pending
->
_pending_block_state
->
trxs
.
emplace_back
(
trx
);
}
else
{
transaction_receipt_header
r
;
r
.
status
=
transaction_receipt
::
executed
;
r
.
kcpu_usage
=
trace
->
cpu_usage
/
1024
;
r
.
net_usage_words
=
trace
->
net_usage
/
8
;
trace
->
receipt
=
r
;
}
fc
::
move_append
(
pending
->
_actions
,
move
(
trx_context
.
executed
));
fc
::
move_append
(
pending
->
_actions
,
move
(
trx_context
.
executed
)
);
transaction_trace_notify
(
trx
,
trace
);
transaction_trace_notify
(
trx
,
trace
);
emit
(
self
.
applied_transaction
,
trace
);
emit
(
self
.
applied_transaction
,
trace
);
trx_context
.
squash
();
restore
.
cancel
();
return
trace
;
}
catch
(
const
fc
::
exception
&
e
)
{
trace
->
except
=
e
;
trace
->
except_ptr
=
std
::
current_exception
();
}
trx_context
.
squash
();
restore
.
cancel
();
return
;
}
catch
(
const
fc
::
exception
&
e
)
{
trace
->
except
=
e
;
trace
->
except_ptr
=
std
::
current_exception
();
}
transaction_trace_notify
(
trx
,
trace
);
}
FC_CAPTURE_AND_RETHROW
((
trace
))
}
/// push_transaction
transaction_trace_notify
(
trx
,
trace
);
return
trace
;
}
FC_CAPTURE_AND_RETHROW
((
trace
))
}
/// push_transaction
void
start_block
(
block_timestamp_type
when
,
uint16_t
confirm_block_count
)
{
...
...
@@ -716,10 +706,10 @@ struct controller_impl {
if
(
receipt
.
trx
.
contains
<
packed_transaction
>
()
)
{
auto
&
pt
=
receipt
.
trx
.
get
<
packed_transaction
>
();
auto
mtrx
=
std
::
make_shared
<
transaction_metadata
>
(
pt
);
push_transaction
(
mtrx
);
push_transaction
(
mtrx
,
fc
::
time_point
::
maximum
()
);
}
else
if
(
receipt
.
trx
.
contains
<
transaction_id_type
>
()
)
{
self
.
push_scheduled_transaction
(
receipt
.
trx
.
get
<
transaction_id_type
>
()
);
self
.
push_scheduled_transaction
(
receipt
.
trx
.
get
<
transaction_id_type
>
()
,
fc
::
time_point
::
maximum
()
);
}
}
...
...
@@ -1029,6 +1019,8 @@ void controller::startup() {
chainbase
::
database
&
controller
::
db
()
const
{
return
my
->
db
;
}
fork_database
&
controller
::
fork_db
()
const
{
return
my
->
fork_db
;
}
void
controller
::
start_block
(
block_timestamp_type
when
,
uint16_t
confirm_block_count
)
{
my
->
start_block
(
when
,
confirm_block_count
);
...
...
@@ -1059,40 +1051,15 @@ void controller::push_confirmation( const header_confirmation& c ) {
my
->
push_confirmation
(
c
);
}
void
controller
::
push_transaction
(
const
transaction_metadata_ptr
&
trx
,
fc
::
time_point
deadline
)
{
my
->
push_transaction
(
trx
,
deadline
);
transaction_trace_ptr
controller
::
push_transaction
(
const
transaction_metadata_ptr
&
trx
,
fc
::
time_point
deadline
)
{
return
my
->
push_transaction
(
trx
,
deadline
);
}
bool
controller
::
push_next_unapplied_transaction
(
fc
::
time_point
deadline
)
{
return
my
->
push_next_unapplied_transaction
(
deadline
);
}
transaction_trace_ptr
controller
::
sync_push
(
const
transaction_metadata_ptr
&
trx
,
time_point
deadline
)
{
auto
start
=
fc
::
time_point
::
now
();
try
{
FC_ASSERT
(
deadline
!=
fc
::
time_point
()
);
transaction_trace_ptr
trace
;
trx
->
on_result
=
[
&
](
const
transaction_trace_ptr
&
t
){
trace
=
t
;
};
my
->
push_transaction
(
trx
,
deadline
);
return
trace
;
}
FC_CAPTURE_AND_RETHROW
(
(
fc
::
time_point
::
now
()
-
start
)(
deadline
)
)
}
bool
controller
::
push_next_scheduled_transaction
(
fc
::
time_point
deadline
)
{
const
auto
&
idx
=
db
().
get_index
<
generated_transaction_multi_index
,
by_delay
>
();
auto
itr
=
idx
.
begin
();
if
(
itr
!=
idx
.
end
()
&&
itr
->
delay_until
<=
pending_block_time
()
)
{
my
->
push_scheduled_transaction
(
*
itr
,
deadline
);
return
true
;
}
return
false
;
}
void
controller
::
push_scheduled_transaction
(
const
transaction_id_type
&
trxid
,
fc
::
time_point
deadline
)
{
transaction_trace_ptr
controller
::
push_scheduled_transaction
(
const
transaction_id_type
&
trxid
,
fc
::
time_point
deadline
)
{
const
auto
&
idx
=
db
().
get_index
<
generated_transaction_multi_index
,
by_trx_id
>
();
auto
itr
=
idx
.
find
(
trxid
);
FC_ASSERT
(
itr
!=
idx
.
end
(),
"unknown transaction"
);
my
->
push_scheduled_transaction
(
*
itr
,
deadline
);
return
my
->
push_scheduled_transaction
(
*
itr
,
deadline
);
}
uint32_t
controller
::
head_block_num
()
const
{
...
...
@@ -1298,8 +1265,31 @@ const account_object& controller::get_account( account_name name )const
return
my
->
db
.
get
<
account_object
,
by_name
>
(
name
);
}
FC_CAPTURE_AND_RETHROW
(
(
name
)
)
}
const
map
<
digest_type
,
transaction_metadata_ptr
>&
controller
::
unapplied_transactions
()
const
{
return
my
->
unapplied_transactions
;
vector
<
transaction_metadata_ptr
>
controller
::
get_unapplied_transactions
()
const
{
vector
<
transaction_metadata_ptr
>
result
;
result
.
reserve
(
my
->
unapplied_transactions
.
size
());
for
(
const
auto
&
entry
:
my
->
unapplied_transactions
)
{
result
.
emplace_back
(
entry
.
second
);
}
return
result
;
}
void
controller
::
drop_unapplied_transaction
(
const
transaction_metadata_ptr
&
trx
)
{
my
->
unapplied_transactions
.
erase
(
trx
->
signed_id
);
}
vector
<
transaction_id_type
>
controller
::
get_scheduled_transactions
()
const
{
const
auto
&
idx
=
db
().
get_index
<
generated_transaction_multi_index
,
by_delay
>
();
vector
<
transaction_id_type
>
result
;
result
.
reserve
(
idx
.
size
());
auto
itr
=
idx
.
begin
();
while
(
itr
!=
idx
.
end
()
&&
itr
->
delay_until
<=
pending_block_time
()
)
{
result
.
emplace_back
(
itr
->
trx_id
);
++
itr
;
}
return
result
;
}
void
controller
::
validate_referenced_accounts
(
const
transaction
&
trx
)
const
{
...
...
libraries/chain/eosio_contract.cpp
浏览文件 @
208a6016
...
...
@@ -242,11 +242,7 @@ void apply_eosio_updateauth(apply_context& context) {
int64_t
old_size
=
(
int64_t
)(
config
::
billable_size_v
<
permission_object
>
+
permission
->
auth
.
get_billable_size
());
db
.
modify
(
*
permission
,
[
&
update
,
&
parent_id
,
&
context
](
permission_object
&
po
)
{
po
.
auth
=
update
.
auth
;
po
.
parent
=
parent_id
;
po
.
last_updated
=
context
.
control
.
pending_block_time
();
});
authorization
.
modify_permission
(
*
permission
,
update
.
auth
);
int64_t
new_size
=
(
int64_t
)(
config
::
billable_size_v
<
permission_object
>
+
permission
->
auth
.
get_billable_size
());
...
...
@@ -269,17 +265,10 @@ void apply_eosio_deleteauth(apply_context& context) {
EOS_ASSERT
(
remove
.
permission
!=
config
::
active_name
,
action_validate_exception
,
"Cannot delete active authority"
);
EOS_ASSERT
(
remove
.
permission
!=
config
::
owner_name
,
action_validate_exception
,
"Cannot delete owner authority"
);
auto
&
authorization
=
context
.
control
.
get_authorization_manager
();
auto
&
authorization
=
context
.
control
.
get_
mutable_
authorization_manager
();
auto
&
db
=
context
.
db
;
const
auto
&
permission
=
authorization
.
get_permission
({
remove
.
account
,
remove
.
permission
});
{
// Check for children
const
auto
&
index
=
db
.
get_index
<
permission_index
,
by_parent
>
();
auto
range
=
index
.
equal_range
(
permission
.
id
);
EOS_ASSERT
(
range
.
first
==
range
.
second
,
action_validate_exception
,
"Cannot delete an authority which has children. Delete the children first"
);
}
{
// Check for links to this permission
const
auto
&
index
=
db
.
get_index
<
permission_link_index
,
by_permission_name
>
();
...
...
@@ -288,11 +277,12 @@ void apply_eosio_deleteauth(apply_context& context) {
"Cannot delete a linked authority. Unlink the authority first"
);
}
context
.
trx_context
.
add_ram_usage
(
permission
.
owner
,
-
(
int64_t
)(
config
::
billable_size_v
<
permission_object
>
+
permission
.
auth
.
get_billable_size
())
);
db
.
remove
(
permission
);
const
auto
&
permission
=
authorization
.
get_permission
({
remove
.
account
,
remove
.
permission
});
int64_t
old_size
=
config
::
billable_size_v
<
permission_object
>
+
permission
.
auth
.
get_billable_size
();
authorization
.
remove_permission
(
permission
);
context
.
trx_context
.
add_ram_usage
(
remove
.
account
,
-
old_size
);
context
.
checktime
(
3000
);
}
...
...
libraries/chain/include/eosio/chain/authority.hpp
浏览文件 @
208a6016
...
...
@@ -128,6 +128,13 @@ struct shared_authority {
}
};
namespace
config
{
template
<
>
struct
billable_size
<
shared_authority
>
{
static
const
uint64_t
value
=
(
3
*
config
::
fixed_overhead_shared_vector_ram_bytes
)
+
4
;
};
}
/**
* Makes sure all keys are unique and sorted and all account permissions are unique and sorted and that authority can
* be satisfied
...
...
libraries/chain/include/eosio/chain/authorization_manager.hpp
浏览文件 @
208a6016
...
...
@@ -42,6 +42,14 @@ namespace eosio { namespace chain {
time_point
initial_creation_time
=
time_point
()
);
void
modify_permission
(
const
permission_object
&
permission
,
const
authority
&
auth
);
void
remove_permission
(
const
permission_object
&
permission
);
void
update_permission_usage
(
const
permission_object
&
permission
);
fc
::
time_point
get_permission_last_used
(
const
permission_object
&
permission
)
const
;
const
permission_object
*
find_permission
(
const
permission_level
&
level
)
const
;
const
permission_object
&
get_permission
(
const
permission_level
&
level
)
const
;
...
...
libraries/chain/include/eosio/chain/config.hpp
浏览文件 @
208a6016
...
...
@@ -91,6 +91,7 @@ const static uint32_t ram_usage_validation_overhead_per_account = 64
const
static
uint32_t
fixed_net_overhead_of_packed_trx
=
16
;
// TODO: is this reasonable?
const
static
uint32_t
fixed_overhead_shared_vector_ram_bytes
=
16
;
///< overhead accounts for fixed portion of size of shared_vector field
const
static
uint32_t
overhead_per_row_per_index_ram_bytes
=
32
;
///< overhead accounts for basic tracking structures in a row per index
const
static
uint32_t
overhead_per_account_ram_bytes
=
2
*
1024
;
///< overhead accounts for basic account storage and pre-pays features like account recovery
const
static
uint32_t
setcode_ram_bytes_multiplier
=
10
;
///< multiplier on contract size to account for multiple copies and cached compilation
...
...
libraries/chain/include/eosio/chain/controller.hpp
浏览文件 @
208a6016
...
...
@@ -31,6 +31,8 @@ namespace eosio { namespace chain {
using
resource_limits
::
resource_limits_manager
;
using
apply_handler
=
std
::
function
<
void
(
apply_context
&
)
>
;
class
fork_database
;
class
controller
{
public:
struct
config
{
...
...
@@ -55,39 +57,41 @@ namespace eosio { namespace chain {
*/
void
start_block
(
block_timestamp_type
time
=
block_timestamp_type
(),
uint16_t
confirm_block_count
=
0
);
void
abort_block
();
void
abort_block
();
/**
* These transactions were previously pushed by have since been unapplied, recalling push_transaction
* with the transaction_metadata_ptr will remove them from this map whether it fails or succeeds.
* with the transaction_metadata_ptr will remove them from the source of this data IFF it succeeds.
*
* The caller is responsible for calling drop_unapplied_transaction on a failing transaction that
* they never intend to retry
*
* @return
map of the hash of a signed transaction (with context free data) to a transaction metadata
* @return
vector of transactions which have been unapplied
*/
const
map
<
digest_type
,
transaction_metadata_ptr
>&
unapplied_transactions
()
const
;
vector
<
transaction_metadata_ptr
>
get_unapplied_transactions
()
const
;
void
drop_unapplied_transaction
(
const
transaction_metadata_ptr
&
trx
);
/**
* These transaction IDs represent transactions available in the head chain state as scheduled
* or otherwise generated transactions.
*
* calling push_scheduled_transaction with these IDs will remove the associated transaction from
* the chain state IFF it succeeds or objectively fails
*
* @return
*/
void
push_transaction
(
const
transaction_metadata_ptr
&
trx
,
fc
::
time_point
deadline
);
bool
push_next_unapplied_transaction
(
fc
::
time_point
deadline
);
transaction_trace_ptr
sync_push
(
const
transaction_metadata_ptr
&
trx
,
fc
::
time_point
deadline
);
vector
<
transaction_id_type
>
get_scheduled_transactions
()
const
;
/**
* Attempt to execute a specific transaction in our deferred trx database
*
*/
void
push_scheduled_transaction
(
const
transaction_id_type
&
scheduled
,
fc
::
time_point
deadline
=
fc
::
time_point
::
maximum
()
);
transaction_trace_ptr
push_transaction
(
const
transaction_metadata_ptr
&
trx
,
fc
::
time_point
deadline
);
/**
* Attempt to execute
the oldest unexecuted deferred transaction
* Attempt to execute
a specific transaction in our deferred trx database
*
* @return nullptr if there is nothing pending
*/
bool
push_next_scheduled_transaction
(
fc
::
time_point
deadline
=
fc
::
time_point
::
maximum
()
);
transaction_trace_ptr
push_scheduled_transaction
(
const
transaction_id_type
&
scheduled
,
fc
::
time_point
deadline
);
void
finalize_block
();
void
sign_block
(
const
std
::
function
<
signature_type
(
const
digest_type
&
)
>&
signer_callback
);
...
...
@@ -105,6 +109,8 @@ namespace eosio { namespace chain {
chainbase
::
database
&
db
()
const
;
fork_database
&
fork_db
()
const
;
const
account_object
&
get_account
(
account_name
n
)
const
;
const
global_property_object
&
get_global_properties
()
const
;
const
dynamic_global_property_object
&
get_dynamic_global_properties
()
const
;
...
...
libraries/chain/include/eosio/chain/permission_object.hpp
浏览文件 @
208a6016
...
...
@@ -8,15 +8,33 @@
#include "multi_index_includes.hpp"
namespace
eosio
{
namespace
chain
{
class
permission_usage_object
:
public
chainbase
::
object
<
permission_usage_object_type
,
permission_usage_object
>
{
OBJECT_CTOR
(
permission_usage_object
)
id_type
id
;
time_point
last_used
;
///< when this permission was last used
};
struct
by_account_permission
;
using
permission_usage_index
=
chainbase
::
shared_multi_index_container
<
permission_usage_object
,
indexed_by
<
ordered_unique
<
tag
<
by_id
>
,
member
<
permission_usage_object
,
permission_usage_object
::
id_type
,
&
permission_usage_object
::
id
>>
>
>
;
class
permission_object
:
public
chainbase
::
object
<
permission_object_type
,
permission_object
>
{
OBJECT_CTOR
(
permission_object
,
(
auth
)
)
id_type
id
;
account_name
owner
;
///< the account this permission belongs to
id_type
parent
;
///< parent permission
permission_name
name
;
///< human-readable name for the permission
shared_authority
auth
;
///< authority required to execute this permission
time_point
last_updated
;
///< the last time this authority was updated
id_type
id
;
permission_usage_object
::
id_type
usage_id
;
id_type
parent
;
///< parent permission
account_name
owner
;
///< the account this permission belongs to
permission_name
name
;
///< human-readable name for the permission
time_point
last_updated
;
///< the last time this authority was updated
shared_authority
auth
;
///< authority required to execute this permission
/**
...
...
@@ -80,35 +98,11 @@ namespace eosio { namespace chain {
>
>
;
class
permission_usage_object
:
public
chainbase
::
object
<
permission_usage_object_type
,
permission_usage_object
>
{
OBJECT_CTOR
(
permission_usage_object
)
id_type
id
;
account_name
account
;
///< the account this permission belongs to
permission_name
permission
;
///< human-readable name for the permission
time_point
last_used
;
///< when this permission was last used
};
struct
by_account_permission
;
using
permission_usage_index
=
chainbase
::
shared_multi_index_container
<
permission_usage_object
,
indexed_by
<
ordered_unique
<
tag
<
by_id
>
,
member
<
permission_usage_object
,
permission_usage_object
::
id_type
,
&
permission_usage_object
::
id
>>
,
ordered_unique
<
tag
<
by_account_permission
>
,
composite_key
<
permission_usage_object
,
member
<
permission_usage_object
,
account_name
,
&
permission_usage_object
::
account
>
,
member
<
permission_usage_object
,
permission_name
,
&
permission_usage_object
::
permission
>
,
member
<
permission_usage_object
,
permission_usage_object
::
id_type
,
&
permission_usage_object
::
id
>
>
>
>
>
;
namespace
config
{
template
<
>
struct
billable_size
<
permission_object
>
{
static
const
uint64_t
overhead
=
6
*
overhead_per_row_per_index_ram_bytes
;
///< 6 indices 2x internal ID, parent, owner, name, name_usag
e
static
const
uint64_t
value
=
80
+
overhead
;
///< fixed field size + overhead
struct
billable_size
<
permission_object
>
{
// Also counts memory usage of the associated permission_usage_object
static
const
uint64_t
overhead
=
5
*
overhead_per_row_per_index_ram_bytes
;
///< 5 indices 2x internal ID, parent, owner, nam
e
static
const
uint64_t
value
=
(
config
::
billable_size_v
<
shared_authority
>
+
64
)
+
overhead
;
///< fixed field size + overhead
};
}
}
}
// eosio::chain
...
...
@@ -117,7 +111,7 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::permission_object, eosio::chain::permissi
CHAINBASE_SET_INDEX_TYPE
(
eosio
::
chain
::
permission_usage_object
,
eosio
::
chain
::
permission_usage_index
)
FC_REFLECT
(
chainbase
::
oid
<
eosio
::
chain
::
permission_object
>
,
(
_id
))
FC_REFLECT
(
eosio
::
chain
::
permission_object
,
(
id
)(
owner
)(
parent
)(
name
)(
auth
)(
last_updated
))
FC_REFLECT
(
eosio
::
chain
::
permission_object
,
(
id
)(
usage_id
)(
parent
)(
owner
)(
name
)(
last_updated
)(
auth
))
FC_REFLECT
(
chainbase
::
oid
<
eosio
::
chain
::
permission_usage_object
>
,
(
_id
))
FC_REFLECT
(
eosio
::
chain
::
permission_usage_object
,
(
id
)(
account
)(
permission
)(
last_used
))
FC_REFLECT
(
eosio
::
chain
::
permission_usage_object
,
(
id
)(
last_used
))
libraries/chain/transaction_context.cpp
浏览文件 @
208a6016
#include <eosio/chain/apply_context.hpp>
#include <eosio/chain/transaction_context.hpp>
#include <eosio/chain/authorization_manager.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/resource_limits.hpp>
#include <eosio/chain/generated_transaction_object.hpp>
...
...
@@ -213,6 +214,15 @@ namespace eosio { namespace chain {
void
transaction_context
::
finalize
()
{
FC_ASSERT
(
is_initialized
,
"must first initialize"
);
if
(
is_input
)
{
auto
&
am
=
control
.
get_mutable_authorization_manager
();
for
(
const
auto
&
act
:
trx
.
actions
)
{
for
(
const
auto
&
auth
:
act
.
authorization
)
{
am
.
update_permission_usage
(
am
.
get_permission
(
auth
)
);
}
}
}
add_cpu_usage
(
validate_ram_usage
.
size
()
*
config
::
ram_usage_validation_overhead_per_account
);
auto
&
rl
=
control
.
get_mutable_resource_limits_manager
();
...
...
libraries/chain/wasm_interface.cpp
浏览文件 @
208a6016
...
...
@@ -823,15 +823,18 @@ class permission_api : public context_aware_api {
return
false
;
}
int64_t
get_permission_last_used
(
account_name
account
,
permission_name
permission
)
{
return
context
.
db
.
get
<
permission_usage_object
,
by_account_permission
>
(
boost
::
make_tuple
(
account
,
permission
)).
last_used
.
time_since_epoch
().
count
();
int64_t
get_permission_last_used
(
account_name
account
,
permission_name
permission
)
{
const
auto
&
am
=
context
.
control
.
get_authorization_manager
();
return
am
.
get_permission_last_used
(
am
.
get_permission
({
account
,
permission
})
).
time_since_epoch
().
count
();
};
int64_t
get_account_creation_date
(
account_name
account
)
{
return
time_point
(
context
.
db
.
get
<
account_object
,
by_name
>
(
account
).
creation_date
).
time_since_epoch
().
count
();
int64_t
get_account_creation_time
(
account_name
account
)
{
auto
*
acct
=
context
.
db
.
find
<
account_object
,
by_name
>
(
account
);
EOS_ASSERT
(
acct
!=
nullptr
,
action_validate_exception
,
"account '${account}' does not exist"
,
(
"account"
,
account
)
);
return
time_point
(
acct
->
creation_date
).
time_since_epoch
().
count
();
}
private:
void
unpack_provided_keys
(
flat_set
<
public_key_type
>&
keys
,
const
char
*
pubkeys_data
,
size_t
pubkeys_size
)
{
keys
.
clear
();
...
...
@@ -1694,7 +1697,7 @@ REGISTER_INTRINSICS(permission_api,
(
check_transaction_authorization
,
int
(
int
,
int
,
int
,
int
,
int
,
int
)
)
(
check_permission_authorization
,
int
(
int64_t
,
int64_t
,
int
,
int
,
int
,
int
,
int64_t
)
)
(
get_permission_last_used
,
int64_t
(
int64_t
,
int64_t
)
)
(
get_account_creation_
dat
e
,
int64_t
(
int64_t
)
)
(
get_account_creation_
tim
e
,
int64_t
(
int64_t
)
)
);
...
...
libraries/testing/tester.cpp
浏览文件 @
208a6016
...
...
@@ -119,10 +119,21 @@ namespace eosio { namespace testing {
}
if
(
!
skip_pending_trxs
)
{
//wlog( "pushing all input transactions in waiting queue" );
while
(
control
->
push_next_unapplied_transaction
(
fc
::
time_point
::
maximum
()
)
);
//wlog( "pushing all available deferred transactions" );
while
(
control
->
push_next_scheduled_transaction
(
fc
::
time_point
::
maximum
()
)
);
auto
unapplied_trxs
=
control
->
get_unapplied_transactions
();
for
(
const
auto
&
trx
:
unapplied_trxs
)
{
auto
trace
=
control
->
push_transaction
(
trx
,
fc
::
time_point
::
maximum
());
if
(
trace
->
except
)
{
trace
->
except
->
dynamic_rethrow_exception
();
}
}
auto
scheduled_trxs
=
control
->
get_scheduled_transactions
();
for
(
const
auto
&
trx
:
scheduled_trxs
)
{
auto
trace
=
control
->
push_scheduled_transaction
(
trx
,
fc
::
time_point
::
maximum
());
if
(
trace
->
except
)
{
trace
->
except
->
dynamic_rethrow_exception
();
}
}
}
...
...
@@ -232,7 +243,7 @@ namespace eosio { namespace testing {
transaction_trace_ptr
base_tester
::
push_transaction
(
packed_transaction
&
trx
,
uint32_t
skip_flag
,
fc
::
time_point
deadline
)
{
try
{
if
(
!
control
->
pending_block_state
()
)
_start_block
(
control
->
head_block_time
()
+
fc
::
microseconds
(
config
::
block_interval_us
));
auto
r
=
control
->
sync_push
(
std
::
make_shared
<
transaction_metadata
>
(
trx
),
deadline
);
auto
r
=
control
->
push_transaction
(
std
::
make_shared
<
transaction_metadata
>
(
trx
),
deadline
);
if
(
r
->
except_ptr
)
std
::
rethrow_exception
(
r
->
except_ptr
);
if
(
r
->
except
)
throw
*
r
->
except
;
return
r
;
...
...
@@ -249,7 +260,7 @@ namespace eosio { namespace testing {
c
=
packed_transaction
::
zlib
;
}
auto
r
=
control
->
sync_push
(
std
::
make_shared
<
transaction_metadata
>
(
trx
,
c
),
deadline
);
auto
r
=
control
->
push_transaction
(
std
::
make_shared
<
transaction_metadata
>
(
trx
,
c
),
deadline
);
if
(
r
->
except_ptr
)
std
::
rethrow_exception
(
r
->
except_ptr
);
if
(
r
->
except
)
throw
*
r
->
except
;
return
r
;
...
...
plugins/producer_plugin/producer_plugin.cpp
浏览文件 @
208a6016
...
...
@@ -5,6 +5,7 @@
#include <eosio/producer_plugin/producer_plugin.hpp>
#include <eosio/chain/producer_object.hpp>
#include <eosio/chain/plugin_interface.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <fc/io/json.hpp>
#include <fc/smart_ref_impl.hpp>
...
...
@@ -17,6 +18,19 @@
#include <algorithm>
#include <boost/range/adaptor/map.hpp>
#include <boost/function_output_iterator.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
namespace
bmi
=
boost
::
multi_index
;
using
bmi
::
indexed_by
;
using
bmi
::
ordered_non_unique
;
using
bmi
::
member
;
using
bmi
::
tag
;
using
bmi
::
hashed_unique
;
using
boost
::
multi_index_container
;
using
std
::
string
;
using
std
::
vector
;
...
...
@@ -28,6 +42,31 @@ static appbase::abstract_plugin& _producer_plugin = app().register_plugin<produc
using
namespace
eosio
::
chain
;
using
namespace
eosio
::
chain
::
plugin_interface
;
namespace
{
bool
failure_is_subjective
(
const
fc
::
exception
&
e
,
bool
deadline_is_subjective
)
{
auto
code
=
e
.
code
();
return
(
code
==
tx_soft_cpu_usage_exceeded
::
code_value
)
||
(
code
==
tx_soft_net_usage_exceeded
::
code_value
)
||
(
code
==
tx_deadline_exceeded
::
code_value
&&
deadline_is_subjective
);
}
}
struct
blacklisted_transaction
{
transaction_id_type
trx_id
;
fc
::
time_point
expiry
;
};
struct
by_id
;
struct
by_expiry
;
using
blacklisted_transaction_index
=
multi_index_container
<
blacklisted_transaction
,
indexed_by
<
hashed_unique
<
tag
<
by_id
>
,
BOOST_MULTI_INDEX_MEMBER
(
blacklisted_transaction
,
transaction_id_type
,
trx_id
)
>
,
ordered_non_unique
<
tag
<
by_expiry
>
,
BOOST_MULTI_INDEX_MEMBER
(
blacklisted_transaction
,
fc
::
time_point
,
expiry
)
>
>
>
;
class
producer_plugin_impl
{
public:
producer_plugin_impl
(
boost
::
asio
::
io_service
&
io
)
...
...
@@ -49,8 +88,7 @@ class producer_plugin_impl {
boost
::
asio
::
deadline_timer
_timer
;
std
::
map
<
chain
::
account_name
,
uint32_t
>
_producer_watermarks
;
int32_t
_max_deferred_transaction_time_ms
;
int32_t
_max_pending_transaction_time_ms
;
int32_t
_max_transaction_time_ms
;
block_production_condition
::
block_production_condition_enum
_prev_result
=
block_production_condition
::
produced
;
uint32_t
_prev_result_count
=
0
;
...
...
@@ -69,6 +107,8 @@ class producer_plugin_impl {
incoming
::
methods
::
block_sync
::
method_type
::
handle
_incoming_block_sync_provider
;
incoming
::
methods
::
transaction_sync
::
method_type
::
handle
_incoming_transaction_sync_provider
;
blacklisted_transaction_index
_blacklisted_transactions
;
void
on_block
(
const
block_state_ptr
&
bsp
)
{
if
(
bsp
->
header
.
timestamp
<=
_last_signed_block_time
)
return
;
if
(
bsp
->
header
.
timestamp
<=
_start_time
)
return
;
...
...
@@ -164,13 +204,35 @@ class producer_plugin_impl {
}
transaction_trace_ptr
on_incoming_transaction
(
const
packed_transaction_ptr
&
trx
)
{
return
publish_results_of
(
trx
,
_transaction_ack_channel
,
[
&
]{
chain
::
controller
&
chain
=
app
().
get_plugin
<
chain_plugin
>
().
chain
();
return
chain
.
sync_push
(
std
::
make_shared
<
transaction_metadata
>
(
*
trx
),
fc
::
time_point
::
now
()
+
fc
::
milliseconds
(
_max_pending_transaction_time_ms
));
return
publish_results_of
(
trx
,
_transaction_ack_channel
,
[
&
]()
->
transaction_trace_ptr
{
while
(
true
)
{
chain
::
controller
&
chain
=
app
().
get_plugin
<
chain_plugin
>
().
chain
();
auto
block_time
=
chain
.
pending_block_state
()
->
header
.
timestamp
.
to_time_point
();
auto
max_deadline
=
fc
::
time_point
::
now
()
+
fc
::
milliseconds
(
_max_transaction_time_ms
);
auto
deadline
=
std
::
min
(
block_time
,
max_deadline
);
auto
trace
=
chain
.
push_transaction
(
std
::
make_shared
<
transaction_metadata
>
(
*
trx
),
deadline
);
// if we failed because the block was exhausted push the block out and try again
if
(
trace
->
except
)
{
if
(
failure_is_subjective
(
*
trace
->
except
,
deadline
==
block_time
))
{
block_production_loop
();
}
else
{
trace
->
except
->
dynamic_rethrow_exception
();
}
}
else
{
return
trace
;
}
}
});
}
bool
start_block
();
enum
class
start_block_result
{
succeeded
,
failed
,
exhausted
};
start_block_result
start_block
();
};
void
new_chain_banner
(
const
eosio
::
chain
::
controller
&
db
)
...
...
@@ -213,10 +275,8 @@ void producer_plugin::set_program_options(
producer_options
.
add_options
()
(
"enable-stale-production,e"
,
boost
::
program_options
::
bool_switch
()
->
notifier
([
this
](
bool
e
){
my
->
_production_enabled
=
e
;}),
"Enable block production, even if the chain is stale."
)
(
"max-
pending-
transaction-time"
,
bpo
::
value
<
int32_t
>
()
->
default_value
(
30
),
(
"max-transaction-time"
,
bpo
::
value
<
int32_t
>
()
->
default_value
(
30
),
"Limits the maximum time (in milliseconds) that is allowed a pushed transaction's code to execute before being considered invalid"
)
(
"max-deferred-transaction-time"
,
bpo
::
value
<
int32_t
>
()
->
default_value
(
20
),
"Limits the maximum time (in milliseconds) that is allowed a to push deferred transactions at the start of a block"
)
(
"required-participation"
,
boost
::
program_options
::
value
<
uint32_t
>
()
->
default_value
(
uint32_t
(
config
::
required_producer_participation
/
config
::
percent_1
))
->
notifier
([
this
](
uint32_t
e
)
{
...
...
@@ -279,8 +339,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_
}
}
my
->
_max_deferred_transaction_time_ms
=
options
.
at
(
"max-deferred-transaction-time"
).
as
<
int32_t
>
();
my
->
_max_pending_transaction_time_ms
=
options
.
at
(
"max-pending-transaction-time"
).
as
<
int32_t
>
();
my
->
_max_transaction_time_ms
=
options
.
at
(
"max-transaction-time"
).
as
<
int32_t
>
();
my
->
_incoming_block_subscription
=
app
().
get_channel
<
incoming
::
channels
::
block
>
().
subscribe
([
this
](
const
signed_block_ptr
&
block
){
...
...
@@ -336,7 +395,7 @@ void producer_plugin::plugin_shutdown() {
}
}
bool
producer_plugin_impl
::
start_block
()
{
producer_plugin_impl
::
start_block_result
producer_plugin_impl
::
start_block
()
{
chain
::
controller
&
chain
=
app
().
get_plugin
<
chain_plugin
>
().
chain
();
const
auto
&
hbs
=
chain
.
head_block_state
();
...
...
@@ -380,39 +439,91 @@ bool producer_plugin_impl::start_block() {
}
FC_LOG_AND_DROP
();
if
(
chain
.
pending_block_state
())
{
// TODO: BIG BAD WARNING, THIS WILL HAPPILY BLOW PAST DEADLINES BUT CONTROLLER IS NOT YET SAFE FOR DEADLINE USAGE
try
{
while
(
chain
.
push_next_unapplied_transaction
(
fc
::
time_point
::
maximum
()));
}
FC_LOG_AND_DROP
();
bool
exhausted
=
false
;
auto
unapplied_trxs
=
chain
.
get_unapplied_transactions
();
for
(
const
auto
&
trx
:
unapplied_trxs
)
{
if
(
exhausted
)
{
break
;
}
try
{
while
(
chain
.
push_next_scheduled_transaction
(
fc
::
time_point
::
maximum
()));
}
FC_LOG_AND_DROP
();
try
{
auto
deadline
=
std
::
min
(
block_time
,
fc
::
time_point
::
now
()
+
fc
::
milliseconds
(
_max_transaction_time_ms
));
auto
trace
=
chain
.
push_transaction
(
trx
,
deadline
);
if
(
trace
->
except
)
{
if
(
failure_is_subjective
(
*
trace
->
except
,
deadline
==
block_time
))
{
exhausted
=
true
;
}
else
{
// this failed our configured maximum transaction time, we don't want to replay it
chain
.
drop_unapplied_transaction
(
trx
);
}
}
}
FC_LOG_AND_DROP
();
}
auto
&
blacklist_by_id
=
_blacklisted_transactions
.
get
<
by_id
>
();
auto
&
blacklist_by_expiry
=
_blacklisted_transactions
.
get
<
by_expiry
>
();
auto
now
=
fc
::
time_point
::
now
();
while
(
!
blacklist_by_expiry
.
empty
()
&&
blacklist_by_expiry
.
begin
()
->
expiry
<=
now
)
{
blacklist_by_expiry
.
erase
(
blacklist_by_expiry
.
begin
());
}
auto
scheduled_trxs
=
chain
.
get_scheduled_transactions
();
for
(
const
auto
&
trx
:
scheduled_trxs
)
{
if
(
exhausted
)
{
break
;
}
return
true
;
if
(
blacklist_by_id
.
find
(
trx
)
!=
blacklist_by_id
.
end
())
{
continue
;
}
try
{
auto
deadline
=
std
::
min
(
block_time
,
fc
::
time_point
::
now
()
+
fc
::
milliseconds
(
_max_transaction_time_ms
));
auto
trace
=
chain
.
push_scheduled_transaction
(
trx
,
deadline
);
if
(
trace
->
except
)
{
if
(
failure_is_subjective
(
*
trace
->
except
,
deadline
==
block_time
))
{
exhausted
=
true
;
}
else
{
auto
expiration
=
fc
::
time_point
::
now
()
+
fc
::
seconds
(
chain
.
get_global_properties
().
configuration
.
deferred_trx_expiration_window
);
// this failed our configured maximum transaction time, we don't want to replay it add it to a blacklist
_blacklisted_transactions
.
insert
(
blacklisted_transaction
{
trx
,
expiration
});
}
}
}
FC_LOG_AND_DROP
();
}
return
exhausted
?
start_block_result
::
exhausted
:
start_block_result
::
succeeded
;
}
return
false
;
return
start_block_result
::
failed
;
}
void
producer_plugin_impl
::
schedule_production_loop
()
{
_timer
.
cancel
();
if
(
start_block
())
{
//_timer.async_wait(boost::bind(&producer_plugin_impl::block_production_loop, this));
auto
result
=
start_block
();
switch
(
result
)
{
case
start_block_result
::
exhausted
:
// immediately proceed to making the block
block_production_loop
();
break
;
case
start_block_result
::
failed
:
elog
(
"Failed to start a pending block, will try again later"
);
// we failed to start a block, so try again later?
_timer
.
async_wait
([
&
](
const
boost
::
system
::
error_code
&
ec
)
{
if
(
ec
!=
boost
::
asio
::
error
::
operation_aborted
)
{
block
_production_loop
();
schedule
_production_loop
();
}
});
}
else
{
elog
(
"Failed to start a pending block, will try again later"
);
//
we failed to start a block, so try again later?
break
;
case
start_block_result
::
succeeded
:
//
_timer.async_wait(boost::bind(&producer_plugin_impl::block_production_loop, this));
_timer
.
async_wait
([
&
](
const
boost
::
system
::
error_code
&
ec
)
{
if
(
ec
!=
boost
::
asio
::
error
::
operation_aborted
)
{
schedule
_production_loop
();
block
_production_loop
();
}
});
break
;
}
}
...
...
unittests/api_tests.cpp
浏览文件 @
208a6016
...
...
@@ -76,7 +76,7 @@ struct test_api_action {
}
};
FC_REFLECT_TEMPLATE
((
uint64_t
T
),
test_api_action
<
T
>
,
BOOST_PP_SEQ_NIL
)
;
FC_REFLECT_TEMPLATE
((
uint64_t
T
),
test_api_action
<
T
>
,
BOOST_PP_SEQ_NIL
)
template
<
uint64_t
NAME
>
struct
test_chain_action
{
...
...
@@ -89,7 +89,7 @@ struct test_chain_action {
}
};
FC_REFLECT_TEMPLATE
((
uint64_t
T
),
test_chain_action
<
T
>
,
BOOST_PP_SEQ_NIL
)
;
FC_REFLECT_TEMPLATE
((
uint64_t
T
),
test_chain_action
<
T
>
,
BOOST_PP_SEQ_NIL
)
struct
check_auth
{
account_name
account
;
...
...
@@ -97,7 +97,15 @@ struct check_auth {
vector
<
public_key_type
>
pubkeys
;
};
FC_REFLECT
(
check_auth
,
(
account
)(
permission
)(
pubkeys
)
);
FC_REFLECT
(
check_auth
,
(
account
)(
permission
)(
pubkeys
)
)
struct
test_permission_last_used_action
{
account_name
account
;
permission_name
permission
;
fc
::
time_point
last_used_time
;
};
FC_REFLECT
(
test_permission_last_used_action
,
(
account
)(
permission
)(
last_used_time
)
)
constexpr
uint64_t
TEST_METHOD
(
const
char
*
CLASS
,
const
char
*
METHOD
)
{
return
(
(
uint64_t
(
DJBH
(
CLASS
))
<<
32
)
|
uint32_t
(
DJBH
(
METHOD
))
);
...
...
@@ -774,11 +782,9 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try {
return
expect_assert_message
(
e
,
"test_action::assert_false"
);
}
);
control
->
push_next_scheduled_transaction
();
// test send_transaction
CALL_TEST_FUNCTION
(
*
this
,
"test_transaction"
,
"send_transaction"
,
{});
control
->
push_next_scheduled_transaction
();
// test send_transaction_empty
BOOST_CHECK_EXCEPTION
(
CALL_TEST_FUNCTION
(
*
this
,
"test_transaction"
,
"send_transaction_empty"
,
{}),
tx_no_auths
,
...
...
@@ -786,7 +792,6 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try {
return
expect_assert_message
(
e
,
"transaction must have at least one authorization"
);
}
);
control
->
push_next_scheduled_transaction
();
{
produce_blocks
(
10
);
...
...
@@ -795,7 +800,6 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try {
// test error handling on deferred transaction failure
CALL_TEST_FUNCTION
(
*
this
,
"test_transaction"
,
"send_transaction_trigger_error_handler"
,
{});
control
->
push_next_scheduled_transaction
();
BOOST_CHECK
(
trace
);
BOOST_CHECK_EQUAL
(
trace
->
receipt
->
status
,
transaction_receipt
::
soft_fail
);
...
...
@@ -803,7 +807,6 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try {
// test test_transaction_size
CALL_TEST_FUNCTION
(
*
this
,
"test_transaction"
,
"test_transaction_size"
,
fc
::
raw
::
pack
(
54
)
);
// TODO: Need a better way to test this.
control
->
push_next_scheduled_transaction
();
// test test_read_transaction
// this is a bit rough, but I couldn't figure out a better way to compare the hashes
...
...
@@ -838,13 +841,10 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try {
transaction_trace_ptr
trace
;
auto
c
=
control
->
applied_transaction
.
connect
([
&
](
const
transaction_trace_ptr
&
t
)
{
if
(
t
->
scheduled
)
{
trace
=
t
;
}
}
);
CALL_TEST_FUNCTION
(
*
this
,
"test_transaction"
,
"send_deferred_transaction"
,
{}
);
//check that it doesn't get executed immediately
control
->
push_next_scheduled_transaction
();
BOOST_CHECK
(
!
trace
);
produce_block
(
fc
::
seconds
(
2
)
);
//check that it gets executed afterwards
control
->
push_next_scheduled_transaction
();
BOOST_CHECK
(
trace
);
//confirm printed message
...
...
@@ -862,11 +862,14 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try {
auto
c
=
control
->
applied_transaction
.
connect
([
&
](
const
transaction_trace_ptr
&
t
)
{
if
(
t
&&
t
->
scheduled
)
{
trace
=
t
;
++
count
;
}
}
);
CALL_TEST_FUNCTION
(
*
this
,
"test_transaction"
,
"send_deferred_transaction"
,
{});
CALL_TEST_FUNCTION
(
*
this
,
"test_transaction"
,
"send_deferred_transaction"
,
{});
produce_block
(
fc
::
seconds
(
2
)
);
produce_block
s
(
3
);
//check that only one deferred transaction executed
control
->
push_next_scheduled_transaction
();
control
->
push_next_scheduled_transaction
();
auto
dtrxs
=
control
->
get_scheduled_transactions
();
BOOST_CHECK_EQUAL
(
dtrxs
.
size
(),
1
);
for
(
const
auto
&
trx
:
dtrxs
)
{
control
->
push_scheduled_transaction
(
trx
,
fc
::
time_point
::
maximum
());
}
BOOST_CHECK_EQUAL
(
1
,
count
);
BOOST_CHECK
(
trace
);
BOOST_CHECK_EQUAL
(
1
,
trace
->
action_traces
.
size
()
);
...
...
@@ -882,7 +885,6 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try {
CALL_TEST_FUNCTION
(
*
this
,
"test_transaction"
,
"send_deferred_transaction"
,
{});
CALL_TEST_FUNCTION
(
*
this
,
"test_transaction"
,
"cancel_deferred_transaction"
,
{});
produce_block
(
fc
::
seconds
(
2
)
);
control
->
push_next_scheduled_transaction
();
BOOST_CHECK
(
!
trace
);
c
.
disconnect
();
}
...
...
@@ -1742,4 +1744,112 @@ BOOST_FIXTURE_TEST_CASE(new_api_feature_tests, TESTER) { try {
BOOST_REQUIRE_EQUAL
(
validate
(),
true
);
}
FC_LOG_AND_RETHROW
()
}
/*************************************************************************************
* permission_usage_tests test cases
*************************************************************************************/
BOOST_FIXTURE_TEST_CASE
(
permission_usage_tests
,
TESTER
)
{
try
{
produce_block
();
create_accounts
(
{
N
(
testapi
),
N
(
alice
),
N
(
bob
)}
);
produce_block
();
set_code
(
N
(
testapi
),
test_api_wast
);
produce_block
();
push_reqauth
(
N
(
alice
),
{{
N
(
alice
),
config
::
active_name
}},
{
get_private_key
(
N
(
alice
),
"active"
)}
);
CALL_TEST_FUNCTION
(
*
this
,
"test_permission"
,
"test_permission_last_used"
,
fc
::
raw
::
pack
(
test_permission_last_used_action
{
N
(
alice
),
config
::
active_name
,
control
->
pending_block_time
()
})
);
// Fails because the last used time is updated after the transaction executes.
BOOST_CHECK_THROW
(
CALL_TEST_FUNCTION
(
*
this
,
"test_permission"
,
"test_permission_last_used"
,
fc
::
raw
::
pack
(
test_permission_last_used_action
{
N
(
testapi
),
config
::
active_name
,
control
->
head_block_time
()
+
fc
::
milliseconds
(
config
::
block_interval_ms
)
})
),
fc
::
assert_exception
);
produce_blocks
(
5
);
set_authority
(
N
(
bob
),
N
(
perm1
),
authority
(
get_private_key
(
N
(
bob
),
"perm1"
).
get_public_key
()
)
);
push_action
(
config
::
system_account_name
,
linkauth
::
get_name
(),
N
(
bob
),
fc
::
mutable_variant_object
()
(
"account"
,
"bob"
)
(
"code"
,
"eosio"
)
(
"type"
,
"reqauth"
)
(
"requirement"
,
"perm1"
)
);
auto
permission_creation_time
=
control
->
pending_block_time
();
produce_blocks
(
5
);
CALL_TEST_FUNCTION
(
*
this
,
"test_permission"
,
"test_permission_last_used"
,
fc
::
raw
::
pack
(
test_permission_last_used_action
{
N
(
bob
),
N
(
perm1
),
permission_creation_time
})
);
produce_blocks
(
5
);
push_reqauth
(
N
(
bob
),
{{
N
(
bob
),
N
(
perm1
)}},
{
get_private_key
(
N
(
bob
),
"perm1"
)}
);
auto
perm1_last_used_time
=
control
->
pending_block_time
();
CALL_TEST_FUNCTION
(
*
this
,
"test_permission"
,
"test_permission_last_used"
,
fc
::
raw
::
pack
(
test_permission_last_used_action
{
N
(
bob
),
config
::
active_name
,
permission_creation_time
})
);
BOOST_CHECK_THROW
(
CALL_TEST_FUNCTION
(
*
this
,
"test_permission"
,
"test_permission_last_used"
,
fc
::
raw
::
pack
(
test_permission_last_used_action
{
N
(
bob
),
N
(
perm1
),
permission_creation_time
})
),
fc
::
assert_exception
);
CALL_TEST_FUNCTION
(
*
this
,
"test_permission"
,
"test_permission_last_used"
,
fc
::
raw
::
pack
(
test_permission_last_used_action
{
N
(
bob
),
N
(
perm1
),
perm1_last_used_time
})
);
produce_block
();
BOOST_REQUIRE_EQUAL
(
validate
(),
true
);
}
FC_LOG_AND_RETHROW
()
}
/*************************************************************************************
* account_creation_time_tests test cases
*************************************************************************************/
BOOST_FIXTURE_TEST_CASE
(
account_creation_time_tests
,
TESTER
)
{
try
{
produce_block
();
create_account
(
N
(
testapi
)
);
produce_block
();
set_code
(
N
(
testapi
),
test_api_wast
);
produce_block
();
create_account
(
N
(
alice
)
);
auto
alice_creation_time
=
control
->
pending_block_time
();
produce_blocks
(
10
);
CALL_TEST_FUNCTION
(
*
this
,
"test_permission"
,
"test_account_creation_time"
,
fc
::
raw
::
pack
(
test_permission_last_used_action
{
N
(
alice
),
config
::
active_name
,
alice_creation_time
})
);
produce_block
();
BOOST_REQUIRE_EQUAL
(
validate
(),
true
);
}
FC_LOG_AND_RETHROW
()
}
BOOST_AUTO_TEST_SUITE_END
()
unittests/delay_tests.cpp
浏览文件 @
208a6016
...
...
@@ -72,7 +72,13 @@ BOOST_FIXTURE_TEST_CASE( delay_error_create_account, validating_tester) { try {
auto
trace
=
push_transaction
(
trx
);
edump
((
*
trace
));
produce_blocks
(
8
);
produce_blocks
(
6
);
auto
scheduled_trxs
=
control
->
get_scheduled_transactions
();
BOOST_REQUIRE_EQUAL
(
scheduled_trxs
.
size
(),
1
);
auto
dtrace
=
control
->
push_scheduled_transaction
(
scheduled_trxs
.
front
(),
fc
::
time_point
::
maximum
());
BOOST_REQUIRE_EQUAL
(
dtrace
->
except
.
valid
(),
true
);
BOOST_REQUIRE_EQUAL
(
dtrace
->
except
->
code
(),
missing_auth_exception
::
code_value
);
}
FC_LOG_AND_RETHROW
()
}
...
...
unittests/eosio.system_tests.cpp
浏览文件 @
208a6016
...
...
@@ -45,16 +45,15 @@ public:
issue
(
config
::
system_account_name
,
"1000000000.0000 EOS"
);
BOOST_REQUIRE_EQUAL
(
asset
::
from_string
(
"1000000000.0000 EOS"
),
get_balance
(
"eosio"
)
);
// create_accounts_with_resources ( { N(inita), N(initb), N(voter1), N(voter2) }, asset::from_string("100000.0000 EOS") );
set_code
(
config
::
system_account_name
,
eosio_system_wast
);
set_abi
(
config
::
system_account_name
,
eosio_system_abi
);
produce_blocks
();
create_account_with_resources
(
N
(
alice
),
N
(
eosio
),
asset
::
from_string
(
"1.0000 EOS"
),
false
);
//{ N(alice), N(bob), N(carol) } );
create_account_with_resources
(
N
(
bob
),
N
(
eosio
),
asset
::
from_string
(
"0.4500 EOS"
),
false
);
//{ N(alice), N(bob), N(carol) } );
create_account_with_resources
(
N
(
carol
),
N
(
eosio
),
asset
::
from_string
(
"1.0000 EOS"
),
false
);
//{ N(alice), N(bob), N(carol) } );
create_account_with_resources
(
N
(
alice
),
N
(
eosio
),
asset
::
from_string
(
"1.0000 EOS"
),
false
);
create_account_with_resources
(
N
(
bob
),
N
(
eosio
),
asset
::
from_string
(
"0.4500 EOS"
),
false
);
create_account_with_resources
(
N
(
carol
),
N
(
eosio
),
asset
::
from_string
(
"1.0000 EOS"
),
false
);
BOOST_REQUIRE_EQUAL
(
asset
::
from_string
(
"1000000000.0000 EOS"
),
get_balance
(
"eosio"
)
);
// eosio pays it self for these...
...
...
@@ -62,18 +61,20 @@ public:
produce_blocks
();
const
auto
&
accnt
=
control
->
db
().
get
<
account_object
,
by_name
>
(
config
::
system_account_name
);
abi_def
abi
;
BOOST_REQUIRE_EQUAL
(
abi_serializer
::
to_abi
(
accnt
.
abi
,
abi
),
true
);
abi_ser
.
set_abi
(
abi
);
/*
const global_property_object &gpo = control->get_global_properties();
FC_ASSERT(0 < gpo.active_producers.producers.size(), "No producers");
producer_name = (string)gpo.active_producers.producers.front().producer_name;
*/
{
const
auto
&
accnt
=
control
->
db
().
get
<
account_object
,
by_name
>
(
config
::
system_account_name
);
abi_def
abi
;
BOOST_REQUIRE_EQUAL
(
abi_serializer
::
to_abi
(
accnt
.
abi
,
abi
),
true
);
abi_ser
.
set_abi
(
abi
);
}
{
const
auto
&
accnt
=
control
->
db
().
get
<
account_object
,
by_name
>
(
N
(
eosio
.
token
)
);
abi_def
abi
;
BOOST_REQUIRE_EQUAL
(
abi_serializer
::
to_abi
(
accnt
.
abi
,
abi
),
true
);
token_abi_ser
.
set_abi
(
abi
);
}
}
void
create_accounts_with_resources
(
vector
<
account_name
>
accounts
,
account_name
creator
=
N
(
eosio
)
)
{
for
(
auto
a
:
accounts
)
{
create_account_with_resources
(
a
,
creator
);
...
...
@@ -113,11 +114,10 @@ public:
set_transaction_headers
(
trx
);
trx
.
sign
(
get_private_key
(
creator
,
"active"
),
chain_id_type
()
);
return
push_transaction
(
trx
);
}
transaction_trace_ptr
create_account_with_resources
(
account_name
a
,
account_name
creator
,
asset
ramfunds
,
bool
multisig
,
asset
net
=
asset
::
from_string
(
"10.0000 EOS"
),
asset
cpu
=
asset
::
from_string
(
"10.0000 EOS"
)
)
{
transaction_trace_ptr
create_account_with_resources
(
account_name
a
,
account_name
creator
,
asset
ramfunds
,
bool
multisig
,
asset
net
=
asset
::
from_string
(
"10.0000 EOS"
),
asset
cpu
=
asset
::
from_string
(
"10.0000 EOS"
)
)
{
signed_transaction
trx
;
set_transaction_headers
(
trx
);
...
...
@@ -158,6 +158,53 @@ public:
return
push_transaction
(
trx
);
}
transaction_trace_ptr
setup_producer_accounts
()
{
std
::
vector
<
account_name
>
accounts
;
accounts
.
reserve
(
'z'
-
'a'
+
1
);
std
::
string
root
(
"init"
);
for
(
char
c
=
'a'
;
c
<=
'z'
;
++
c
)
{
accounts
.
emplace_back
(
root
+
std
::
string
(
1
,
c
)
);
}
account_name
creator
(
N
(
eosio
));
signed_transaction
trx
;
set_transaction_headers
(
trx
);
asset
cpu
=
asset
::
from_string
(
"1000000.0000 EOS"
);
asset
net
=
asset
::
from_string
(
"1000000.0000 EOS"
);
asset
ram
=
asset
::
from_string
(
"1.0000 EOS"
);
for
(
const
auto
&
a
:
accounts
)
{
authority
owner_auth
(
get_public_key
(
a
,
"owner"
)
);
trx
.
actions
.
emplace_back
(
vector
<
permission_level
>
{{
creator
,
config
::
active_name
}},
newaccount
{
.
creator
=
creator
,
.
name
=
a
,
.
owner
=
owner_auth
,
.
active
=
authority
(
get_public_key
(
a
,
"active"
)
)
});
trx
.
actions
.
emplace_back
(
get_action
(
N
(
eosio
),
N
(
buyram
),
vector
<
permission_level
>
{
{
creator
,
config
::
active_name
}
},
mvo
()
(
"payer"
,
creator
)
(
"receiver"
,
a
)
(
"quant"
,
ram
)
)
);
trx
.
actions
.
emplace_back
(
get_action
(
N
(
eosio
),
N
(
delegatebw
),
vector
<
permission_level
>
{
{
creator
,
config
::
active_name
}
},
mvo
()
(
"from"
,
creator
)
(
"receiver"
,
a
)
(
"stake_net_quantity"
,
net
)
(
"stake_cpu_quantity"
,
cpu
)
)
);
}
set_transaction_headers
(
trx
);
trx
.
sign
(
get_private_key
(
creator
,
"active"
),
chain_id_type
()
);
return
push_transaction
(
trx
);
}
action_result
buyram
(
const
account_name
&
payer
,
account_name
receiver
,
string
eosin
)
{
return
push_action
(
payer
,
N
(
buyram
),
mvo
()(
"payer"
,
payer
)(
"receiver"
,
receiver
)(
"quant"
,
eosin
)
);
}
...
...
@@ -320,7 +367,26 @@ public:
return
stake2votes
(
asset
::
from_string
(
s
)
);
}
fc
::
variant
get_stats
(
const
string
&
symbolname
)
{
auto
symb
=
eosio
::
chain
::
symbol
::
from_string
(
symbolname
);
auto
symbol_code
=
symb
.
to_symbol_code
().
value
;
vector
<
char
>
data
=
get_row_by_account
(
N
(
eosio
.
token
),
symbol_code
,
N
(
stat
),
symbol_code
);
return
data
.
empty
()
?
fc
::
variant
()
:
token_abi_ser
.
binary_to_variant
(
"currency_stats"
,
data
);
}
asset
get_token_supply
()
{
return
get_stats
(
"4,EOS"
)[
"supply"
].
as
<
asset
>
();
}
fc
::
variant
get_global_state
()
{
vector
<
char
>
data
=
get_row_by_account
(
N
(
eosio
),
N
(
eosio
),
N
(
global
),
N
(
global
)
);
if
(
data
.
empty
())
std
::
cout
<<
"
\n
Data is empty
\n
"
<<
std
::
endl
;
return
data
.
empty
()
?
fc
::
variant
()
:
abi_ser
.
binary_to_variant
(
"eosio_global_state"
,
data
);
}
abi_serializer
abi_ser
;
abi_serializer
token_abi_ser
;
};
fc
::
mutable_variant_object
voter
(
account_name
acct
)
{
...
...
@@ -1193,18 +1259,12 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester) try {
create_account_with_resources
(
N
(
vota
),
N
(
eosio
),
asset
::
from_string
(
"1.0000 EOS"
),
false
,
large_asset
,
large_asset
);
create_account_with_resources
(
N
(
votb
),
N
(
eosio
),
asset
::
from_string
(
"1.0000 EOS"
),
false
,
large_asset
,
large_asset
);
issue
(
"vota"
,
"400000000.0000 EOS"
,
config
::
system_account_name
);
produce_block
();
// 1 block produced
BOOST_REQUIRE_EQUAL
(
success
(),
regproducer
(
N
(
inita
)));
auto
prod
=
get_producer_info
(
N
(
inita
)
);
BOOST_REQUIRE_EQUAL
(
"inita"
,
prod
[
"owner"
].
as_string
());
BOOST_REQUIRE_EQUAL
(
0
,
prod
[
"total_votes"
].
as_double
());
issue
(
"vota"
,
"400000000.0000 EOS"
,
config
::
system_account_name
);
BOOST_REQUIRE_EQUAL
(
success
(),
stake
(
"vota"
,
"100000000.0000 EOS"
,
"100000000.0000 EOS"
));
BOOST_REQUIRE_EQUAL
(
success
(),
push_action
(
N
(
vota
),
N
(
voteproducer
),
mvo
()
...
...
@@ -1214,22 +1274,353 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester) try {
)
);
produce_blocks
(
200
);
prod
=
get_producer_info
(
"inita"
);
// inita is the only active producer
// produce enough blocks so new schedule kicks in and inita produces some blocks
{
produce_blocks
(
50
);
const
auto
initial_global_state
=
get_global_state
();
const
uint64_t
initial_claim_time
=
initial_global_state
[
"last_pervote_bucket_fill"
].
as_uint64
();
const
asset
initial_pervote_bucket
=
initial_global_state
[
"pervote_bucket"
].
as
<
asset
>
();
const
asset
initial_savings
=
initial_global_state
[
"savings"
].
as
<
asset
>
();
prod
=
get_producer_info
(
"inita"
);
const
uint32_t
produced_blocks
=
prod
[
"produced_blocks"
].
as
<
uint32_t
>
();
BOOST_REQUIRE
(
1
<
produced_blocks
);
BOOST_REQUIRE_EQUAL
(
0
,
prod
[
"last_claim_time"
].
as
<
uint64_t
>
());
const
asset
initial_supply
=
get_token_supply
();
const
asset
initial_balance
=
get_balance
(
N
(
inita
));
BOOST_REQUIRE_EQUAL
(
success
(),
push_action
(
N
(
inita
),
N
(
claimrewards
),
mvo
()(
"owner"
,
"inita"
)));
const
auto
global_state
=
get_global_state
();
const
uint64_t
claim_time
=
global_state
[
"last_pervote_bucket_fill"
].
as_uint64
();
const
asset
pervote_bucket
=
global_state
[
"pervote_bucket"
].
as
<
asset
>
();
const
asset
savings
=
global_state
[
"savings"
].
as
<
asset
>
();
prod
=
get_producer_info
(
"inita"
);
BOOST_REQUIRE_EQUAL
(
1
,
prod
[
"produced_blocks"
].
as
<
uint32_t
>
());
const
asset
supply
=
get_token_supply
();
const
asset
balance
=
get_balance
(
N
(
inita
));
BOOST_REQUIRE_EQUAL
(
claim_time
,
prod
[
"last_claim_time"
].
as
<
uint64_t
>
());
const
int32_t
secs_between_fills
=
static_cast
<
int32_t
>
((
claim_time
-
initial_claim_time
)
/
1000000
);
BOOST_REQUIRE_EQUAL
(
0
,
initial_pervote_bucket
.
amount
);
BOOST_REQUIRE_EQUAL
(
int64_t
(
(
initial_supply
.
amount
*
secs_between_fills
*
((
4.879
-
1.0
)
/
100.0
))
/
(
52
*
7
*
24
*
3600
)
),
savings
.
amount
-
initial_savings
.
amount
);
int64_t
block_payments
=
int64_t
(
initial_supply
.
amount
*
produced_blocks
*
(
0.25
/
100.0
)
/
(
52
*
7
*
24
*
3600
*
2
)
);
int64_t
from_pervote_bucket
=
int64_t
(
initial_supply
.
amount
*
secs_between_fills
*
(
0.75
/
100.0
)
/
(
52
*
7
*
24
*
3600
)
);
if
(
from_pervote_bucket
>=
100
*
10000
)
{
BOOST_REQUIRE_EQUAL
(
block_payments
+
from_pervote_bucket
,
balance
.
amount
-
initial_balance
.
amount
);
BOOST_REQUIRE_EQUAL
(
0
,
pervote_bucket
.
amount
);
}
else
{
BOOST_REQUIRE_EQUAL
(
block_payments
,
balance
.
amount
-
initial_balance
.
amount
);
BOOST_REQUIRE_EQUAL
(
from_pervote_bucket
,
pervote_bucket
.
amount
);
}
const
int64_t
max_supply_growth
=
int64_t
(
(
initial_supply
.
amount
*
secs_between_fills
*
(
4.879
/
100.0
))
/
(
52
*
7
*
24
*
3600
)
);
BOOST_REQUIRE
(
max_supply_growth
>=
supply
.
amount
-
initial_supply
.
amount
);
}
{
BOOST_REQUIRE_EQUAL
(
error
(
"condition: assertion failed: already claimed rewards within a day"
),
push_action
(
N
(
inita
),
N
(
claimrewards
),
mvo
()(
"owner"
,
"inita"
)));
}
BOOST_REQUIRE
(
1
<
prod
[
"produced_blocks"
].
as
<
uint32_t
>
());
BOOST_REQUIRE_EQUAL
(
success
(),
push_action
(
N
(
inita
),
N
(
claimrewards
),
mvo
()(
"owner"
,
"inita"
)));
// inita waits for 23 hours and 55 minutes, can't claim rewards yet
{
produce_block
(
fc
::
seconds
(
23
*
3600
+
55
*
60
));
BOOST_REQUIRE_EQUAL
(
error
(
"condition: assertion failed: already claimed rewards within a day"
),
push_action
(
N
(
inita
),
N
(
claimrewards
),
mvo
()(
"owner"
,
"inita"
)));
}
prod
=
get_producer_info
(
"inita"
);
BOOST_REQUIRE_EQUAL
(
1
,
prod
[
"produced_blocks"
].
as
<
uint32_t
>
());
// wait 5 more minutes, inita can now claim rewards again
{
produce_block
(
fc
::
seconds
(
5
*
60
));
const
auto
initial_global_state
=
get_global_state
();
const
uint64_t
initial_claim_time
=
initial_global_state
[
"last_pervote_bucket_fill"
].
as_uint64
();
const
asset
initial_pervote_bucket
=
initial_global_state
[
"pervote_bucket"
].
as
<
asset
>
();
const
asset
initial_savings
=
initial_global_state
[
"savings"
].
as
<
asset
>
();
prod
=
get_producer_info
(
"inita"
);
const
uint32_t
produced_blocks
=
prod
[
"produced_blocks"
].
as
<
uint32_t
>
();
BOOST_REQUIRE
(
1
<
produced_blocks
);
BOOST_REQUIRE
(
0
<
prod
[
"last_claim_time"
].
as
<
uint64_t
>
());
const
asset
initial_supply
=
get_token_supply
();
const
asset
initial_balance
=
get_balance
(
N
(
inita
));
BOOST_REQUIRE_EQUAL
(
success
(),
push_action
(
N
(
inita
),
N
(
claimrewards
),
mvo
()(
"owner"
,
"inita"
)));
const
auto
global_state
=
get_global_state
();
const
uint64_t
claim_time
=
global_state
[
"last_pervote_bucket_fill"
].
as_uint64
();
const
asset
pervote_bucket
=
global_state
[
"pervote_bucket"
].
as
<
asset
>
();
const
asset
savings
=
global_state
[
"savings"
].
as
<
asset
>
();
prod
=
get_producer_info
(
"inita"
);
BOOST_REQUIRE_EQUAL
(
1
,
prod
[
"produced_blocks"
].
as
<
uint32_t
>
());
const
asset
supply
=
get_token_supply
();
const
asset
balance
=
get_balance
(
N
(
inita
));
BOOST_REQUIRE_EQUAL
(
claim_time
,
prod
[
"last_claim_time"
].
as
<
uint64_t
>
());
const
int32_t
secs_between_fills
=
static_cast
<
int32_t
>
((
claim_time
-
initial_claim_time
)
/
1000000
);
BOOST_REQUIRE_EQUAL
(
int64_t
(
(
initial_supply
.
amount
*
secs_between_fills
*
((
4.879
-
1.0
)
/
100.0
))
/
(
52
*
7
*
24
*
3600
)
),
savings
.
amount
-
initial_savings
.
amount
);
int64_t
block_payments
=
int64_t
(
initial_supply
.
amount
*
produced_blocks
*
(
0.25
/
100.0
)
/
(
52
*
7
*
24
*
3600
*
2
)
);
int64_t
from_pervote_bucket
=
int64_t
(
initial_pervote_bucket
.
amount
+
initial_supply
.
amount
*
secs_between_fills
*
(
0.75
/
100.0
)
/
(
52
*
7
*
24
*
3600
)
);
if
(
from_pervote_bucket
>=
100
*
10000
)
{
BOOST_REQUIRE_EQUAL
(
block_payments
+
from_pervote_bucket
,
balance
.
amount
-
initial_balance
.
amount
);
BOOST_REQUIRE_EQUAL
(
0
,
pervote_bucket
.
amount
);
}
else
{
BOOST_REQUIRE_EQUAL
(
block_payments
,
balance
.
amount
-
initial_balance
.
amount
);
BOOST_REQUIRE_EQUAL
(
from_pervote_bucket
,
pervote_bucket
.
amount
);
}
const
int64_t
max_supply_growth
=
int64_t
(
(
initial_supply
.
amount
*
secs_between_fills
*
(
4.879
/
100.0
))
/
(
52
*
7
*
24
*
3600
)
);
BOOST_REQUIRE
(
max_supply_growth
>=
supply
.
amount
-
initial_supply
.
amount
);
}
// initb tries to claim rewards but he's not on the list
{
BOOST_REQUIRE_EQUAL
(
error
(
"condition: assertion failed: account name is not in producer list"
),
push_action
(
N
(
initb
),
N
(
claimrewards
),
mvo
()(
"owner"
,
"initb"
)));
}
}
FC_LOG_AND_RETHROW
()
BOOST_REQUIRE_EQUAL
(
error
(
"condition: assertion failed: already claimed rewards within a day"
),
push_action
(
N
(
inita
),
N
(
claimrewards
),
mvo
()(
"owner"
,
"inita"
)));
BOOST_FIXTURE_TEST_CASE
(
multiple_producer_pay
,
eosio_system_tester
)
try
{
produce_block
(
fc
::
seconds
(
1
)
);
const
auto
tol
=
boost
::
test_tools
::
tolerance
(
0.0000000001
);
}
FC_LOG_AND_RETHROW
()
const
int64_t
secs_per_year
=
52
*
7
*
24
*
3600
;
const
int64_t
blocks_per_year
=
52
*
7
*
24
*
3600
*
2
;
const
double
cont_rate
=
4.879
/
100.
;
const
double
standby_rate
=
0.750
/
100.
;
const
double
block_rate
=
0.250
/
100.
;
const
asset
large_asset
=
asset
::
from_string
(
"100000000.0000 EOS"
);
create_account_with_resources
(
N
(
vota
),
N
(
eosio
),
asset
::
from_string
(
"1.0000 EOS"
),
false
,
large_asset
,
large_asset
);
create_account_with_resources
(
N
(
votb
),
N
(
eosio
),
asset
::
from_string
(
"1.0000 EOS"
),
false
,
large_asset
,
large_asset
);
create_account_with_resources
(
N
(
votc
),
N
(
eosio
),
asset
::
from_string
(
"1.0000 EOS"
),
false
,
large_asset
,
large_asset
);
// create accounts {inita, initb, ..., initz} and register as producers
setup_producer_accounts
();
std
::
vector
<
account_name
>
producer_names
;
{
producer_names
.
reserve
(
'z'
-
'a'
+
1
);
const
std
::
string
root
(
"init"
);
for
(
char
c
=
'a'
;
c
<=
'z'
;
++
c
)
{
producer_names
.
emplace_back
(
root
+
std
::
string
(
1
,
c
));
regproducer
(
producer_names
.
back
()
);
}
BOOST_REQUIRE_EQUAL
(
0
,
get_producer_info
(
N
(
inita
)
)[
"total_votes"
].
as
<
double
>
());
BOOST_REQUIRE_EQUAL
(
0
,
get_producer_info
(
N
(
initz
)
)[
"total_votes"
].
as
<
double
>
());
}
{
issue
(
"vota"
,
"100000000.0000 EOS"
,
config
::
system_account_name
);
BOOST_REQUIRE_EQUAL
(
success
(),
stake
(
"vota"
,
"30000000.0000 EOS"
,
"30000000.0000 EOS"
));
issue
(
"votb"
,
"100000000.0000 EOS"
,
config
::
system_account_name
);
BOOST_REQUIRE_EQUAL
(
success
(),
stake
(
"votb"
,
"30000000.0000 EOS"
,
"30000000.0000 EOS"
));
issue
(
"votc"
,
"100000000.0000 EOS"
,
config
::
system_account_name
);
BOOST_REQUIRE_EQUAL
(
success
(),
stake
(
"votc"
,
"30000000.0000 EOS"
,
"30000000.0000 EOS"
));
}
// vota votes for inita ... initj
// votb votes for inita ... initu
// votc votes for inita ... initz
{
BOOST_REQUIRE_EQUAL
(
success
(),
push_action
(
N
(
vota
),
N
(
voteproducer
),
mvo
()
(
"voter"
,
"vota"
)
(
"proxy"
,
name
(
0
).
to_string
())
(
"producers"
,
vector
<
account_name
>
(
producer_names
.
begin
(),
producer_names
.
begin
()
+
10
))
)
);
BOOST_REQUIRE_EQUAL
(
success
(),
push_action
(
N
(
votb
),
N
(
voteproducer
),
mvo
()
(
"voter"
,
"votb"
)
(
"proxy"
,
name
(
0
).
to_string
())
(
"producers"
,
vector
<
account_name
>
(
producer_names
.
begin
(),
producer_names
.
begin
()
+
21
))
)
);
BOOST_REQUIRE_EQUAL
(
success
(),
push_action
(
N
(
votc
),
N
(
voteproducer
),
mvo
()
(
"voter"
,
"votc"
)
(
"proxy"
,
name
(
0
).
to_string
())
(
"producers"
,
vector
<
account_name
>
(
producer_names
.
begin
(),
producer_names
.
end
()))
)
);
}
{
auto
proda
=
get_producer_info
(
N
(
inita
)
);
auto
prodj
=
get_producer_info
(
N
(
initj
)
);
auto
prodk
=
get_producer_info
(
N
(
initk
)
);
auto
produ
=
get_producer_info
(
N
(
initu
)
);
auto
prodv
=
get_producer_info
(
N
(
initv
)
);
auto
prodz
=
get_producer_info
(
N
(
initz
)
);
BOOST_REQUIRE
(
0
==
proda
[
"produced_blocks"
].
as
<
uint32_t
>
()
&&
0
==
prodz
[
"produced_blocks"
].
as
<
uint32_t
>
());
BOOST_REQUIRE
(
0
==
proda
[
"last_claim_time"
].
as
<
uint64_t
>
()
&&
0
==
prodz
[
"last_claim_time"
].
as
<
uint64_t
>
());
// check vote ratios
BOOST_REQUIRE
(
0
<
proda
[
"total_votes"
].
as
<
double
>
()
&&
0
<
prodz
[
"total_votes"
].
as
<
double
>
()
);
BOOST_TEST
(
proda
[
"total_votes"
].
as
<
double
>
()
==
prodj
[
"total_votes"
].
as
<
double
>
(),
tol
);
BOOST_TEST
(
prodk
[
"total_votes"
].
as
<
double
>
()
==
produ
[
"total_votes"
].
as
<
double
>
(),
tol
);
BOOST_TEST
(
prodv
[
"total_votes"
].
as
<
double
>
()
==
prodz
[
"total_votes"
].
as
<
double
>
(),
tol
);
BOOST_TEST
(
2
*
proda
[
"total_votes"
].
as
<
double
>
()
==
3
*
produ
[
"total_votes"
].
as
<
double
>
(),
tol
);
BOOST_TEST
(
proda
[
"total_votes"
].
as
<
double
>
()
==
3
*
prodz
[
"total_votes"
].
as
<
double
>
(),
tol
);
}
// give a chance for everyone to produce blocks
{
produce_blocks
(
21
*
12
+
20
);
bool
all_21_produced
=
true
;
for
(
uint32_t
i
=
0
;
i
<
21
;
++
i
)
{
if
(
0
==
get_producer_info
(
producer_names
[
i
])[
"produced_blocks"
].
as
<
uint32_t
>
())
{
all_21_produced
=
false
;
}
}
bool
rest_didnt_produce
=
true
;
for
(
uint32_t
i
=
21
;
i
<
producer_names
.
size
();
++
i
)
{
if
(
0
<
get_producer_info
(
producer_names
[
i
])[
"produced_blocks"
].
as
<
uint32_t
>
())
{
rest_didnt_produce
=
false
;
}
}
BOOST_REQUIRE
(
all_21_produced
&&
rest_didnt_produce
);
}
std
::
vector
<
double
>
vote_shares
(
producer_names
.
size
());
{
double
total_votes
=
0
;
for
(
uint32_t
i
=
0
;
i
<
producer_names
.
size
();
++
i
)
{
vote_shares
[
i
]
=
get_producer_info
(
producer_names
[
i
])[
"total_votes"
].
as
<
double
>
();
total_votes
+=
vote_shares
[
i
];
}
std
::
for_each
(
vote_shares
.
begin
(),
vote_shares
.
end
(),
[
total_votes
](
double
&
x
)
{
x
/=
total_votes
;
});
BOOST_TEST
(
double
(
1
)
==
std
::
accumulate
(
vote_shares
.
begin
(),
vote_shares
.
end
(),
double
(
0
)),
tol
);
BOOST_TEST
(
double
(
3.
/
57.
)
==
vote_shares
[
0
],
tol
);
}
{
const
uint32_t
prod_index
=
2
;
const
auto
prod_name
=
producer_names
[
prod_index
];
const
auto
produced_blocks
=
get_producer_info
(
prod_name
)[
"produced_blocks"
].
as
<
uint32_t
>
();
const
auto
initial_global_state
=
get_global_state
();
const
uint64_t
initial_claim_time
=
initial_global_state
[
"last_pervote_bucket_fill"
].
as_uint64
();
const
asset
initial_pervote_bucket
=
initial_global_state
[
"pervote_bucket"
].
as
<
asset
>
();
const
asset
initial_savings
=
initial_global_state
[
"savings"
].
as
<
asset
>
();
const
asset
initial_supply
=
get_token_supply
();
const
asset
initial_balance
=
get_balance
(
prod_name
);
BOOST_REQUIRE_EQUAL
(
success
(),
push_action
(
prod_name
,
N
(
claimrewards
),
mvo
()(
"owner"
,
prod_name
)));
const
auto
global_state
=
get_global_state
();
const
uint64_t
claim_time
=
global_state
[
"last_pervote_bucket_fill"
].
as_uint64
();
const
asset
pervote_bucket
=
global_state
[
"pervote_bucket"
].
as
<
asset
>
();
const
asset
savings
=
global_state
[
"savings"
].
as
<
asset
>
();
const
asset
supply
=
get_token_supply
();
const
asset
balance
=
get_balance
(
prod_name
);
const
int32_t
secs_between_fills
=
static_cast
<
int32_t
>
((
claim_time
-
initial_claim_time
)
/
1000000
);
BOOST_REQUIRE_EQUAL
(
int64_t
(
(
initial_supply
.
amount
*
secs_between_fills
*
(
cont_rate
-
standby_rate
-
block_rate
))
/
secs_per_year
),
savings
.
amount
-
initial_savings
.
amount
);
int64_t
block_payments
=
int64_t
(
initial_supply
.
amount
*
produced_blocks
*
block_rate
/
blocks_per_year
);
int64_t
expected_pervote_bucket
=
int64_t
(
initial_pervote_bucket
.
amount
+
initial_supply
.
amount
*
secs_between_fills
*
standby_rate
/
secs_per_year
);
int64_t
from_pervote_bucket
=
int64_t
(
vote_shares
[
prod_index
]
*
expected_pervote_bucket
);
if
(
from_pervote_bucket
>=
100
*
10000
)
{
BOOST_REQUIRE_EQUAL
(
block_payments
+
from_pervote_bucket
,
balance
.
amount
-
initial_balance
.
amount
);
BOOST_REQUIRE_EQUAL
(
expected_pervote_bucket
-
from_pervote_bucket
,
pervote_bucket
.
amount
);
}
else
{
BOOST_REQUIRE_EQUAL
(
block_payments
,
balance
.
amount
-
initial_balance
.
amount
);
BOOST_REQUIRE_EQUAL
(
expected_pervote_bucket
,
pervote_bucket
.
amount
);
}
produce_blocks
(
5
);
BOOST_REQUIRE_EQUAL
(
error
(
"condition: assertion failed: already claimed rewards within a day"
),
push_action
(
prod_name
,
N
(
claimrewards
),
mvo
()(
"owner"
,
prod_name
)));
}
{
const
uint32_t
prod_index
=
23
;
const
auto
prod_name
=
producer_names
[
prod_index
];
const
uint64_t
initial_claim_time
=
get_global_state
()[
"last_pervote_bucket_fill"
].
as_uint64
();
const
asset
initial_supply
=
get_token_supply
();
BOOST_REQUIRE_EQUAL
(
success
(),
push_action
(
prod_name
,
N
(
claimrewards
),
mvo
()(
"owner"
,
prod_name
)));
BOOST_REQUIRE_EQUAL
(
0
,
get_balance
(
prod_name
).
amount
);
BOOST_REQUIRE_EQUAL
(
initial_claim_time
,
get_global_state
()[
"last_pervote_bucket_fill"
].
as_uint64
());
BOOST_REQUIRE_EQUAL
(
initial_supply
,
get_token_supply
());
BOOST_REQUIRE_EQUAL
(
error
(
"condition: assertion failed: already claimed rewards within a day"
),
push_action
(
prod_name
,
N
(
claimrewards
),
mvo
()(
"owner"
,
prod_name
)));
}
produce_block
(
fc
::
seconds
(
24
*
3600
));
{
const
uint32_t
prod_index
=
15
;
const
auto
prod_name
=
producer_names
[
prod_index
];
const
auto
produced_blocks
=
get_producer_info
(
prod_name
)[
"produced_blocks"
].
as
<
uint32_t
>
();
const
auto
initial_global_state
=
get_global_state
();
const
uint64_t
initial_claim_time
=
initial_global_state
[
"last_pervote_bucket_fill"
].
as_uint64
();
const
asset
initial_pervote_bucket
=
initial_global_state
[
"pervote_bucket"
].
as
<
asset
>
();
const
asset
initial_savings
=
initial_global_state
[
"savings"
].
as
<
asset
>
();
const
asset
initial_supply
=
get_token_supply
();
const
asset
initial_balance
=
get_balance
(
prod_name
);
BOOST_REQUIRE_EQUAL
(
success
(),
push_action
(
prod_name
,
N
(
claimrewards
),
mvo
()(
"owner"
,
prod_name
)));
const
auto
global_state
=
get_global_state
();
const
uint64_t
claim_time
=
global_state
[
"last_pervote_bucket_fill"
].
as_uint64
();
const
asset
pervote_bucket
=
global_state
[
"pervote_bucket"
].
as
<
asset
>
();
const
asset
savings
=
global_state
[
"savings"
].
as
<
asset
>
();
const
asset
supply
=
get_token_supply
();
const
asset
balance
=
get_balance
(
prod_name
);
const
int32_t
secs_between_fills
=
static_cast
<
int32_t
>
((
claim_time
-
initial_claim_time
)
/
1000000
);
BOOST_REQUIRE_EQUAL
(
int64_t
(
(
initial_supply
.
amount
*
secs_between_fills
*
(
cont_rate
-
standby_rate
-
block_rate
))
/
secs_per_year
),
savings
.
amount
-
initial_savings
.
amount
);
int64_t
block_payments
=
int64_t
(
initial_supply
.
amount
*
produced_blocks
*
block_rate
/
blocks_per_year
);
int64_t
expected_pervote_bucket
=
int64_t
(
initial_pervote_bucket
.
amount
+
initial_supply
.
amount
*
secs_between_fills
*
standby_rate
/
secs_per_year
);
int64_t
from_pervote_bucket
=
int64_t
(
vote_shares
[
prod_index
]
*
expected_pervote_bucket
);
BOOST_REQUIRE_EQUAL
(
block_payments
+
from_pervote_bucket
,
balance
.
amount
-
initial_balance
.
amount
);
BOOST_REQUIRE_EQUAL
(
expected_pervote_bucket
-
from_pervote_bucket
,
pervote_bucket
.
amount
);
produce_blocks
(
5
);
BOOST_REQUIRE_EQUAL
(
error
(
"condition: assertion failed: already claimed rewards within a day"
),
push_action
(
prod_name
,
N
(
claimrewards
),
mvo
()(
"owner"
,
prod_name
)));
}
{
const
uint32_t
prod_index
=
23
;
const
auto
prod_name
=
producer_names
[
prod_index
];
BOOST_REQUIRE_EQUAL
(
success
(),
push_action
(
prod_name
,
N
(
claimrewards
),
mvo
()(
"owner"
,
prod_name
)));
BOOST_REQUIRE
(
100
*
10000
<=
get_balance
(
prod_name
).
amount
);
BOOST_REQUIRE_EQUAL
(
error
(
"condition: assertion failed: already claimed rewards within a day"
),
push_action
(
prod_name
,
N
(
claimrewards
),
mvo
()(
"owner"
,
prod_name
)));
}
}
FC_LOG_AND_RETHROW
()
BOOST_FIXTURE_TEST_CASE
(
voters_actions_affect_proxy_and_producers
,
eosio_system_tester
)
try
{
create_accounts_with_resources
(
{
N
(
donald
),
N
(
producer1
),
N
(
producer2
),
N
(
producer3
)
}
);
...
...
unittests/forked_tests.cpp
浏览文件 @
208a6016
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/fork_database.hpp>
#include <eosio.token/eosio.token.wast.hpp>
#include <eosio.token/eosio.token.abi.hpp>
...
...
@@ -258,6 +259,100 @@ BOOST_AUTO_TEST_CASE( prune_remove_branch ) try {
BOOST_AUTO_TEST_CASE
(
confirmation
)
try
{
tester
c
;
c
.
produce_blocks
(
10
);
auto
r
=
c
.
create_accounts
(
{
N
(
dan
),
N
(
sam
),
N
(
pam
),
N
(
scott
)}
);
auto
res
=
c
.
set_producers
(
{
N
(
dan
),
N
(
sam
),
N
(
pam
),
N
(
scott
)}
);
private_key_type
priv_sam
=
c
.
get_private_key
(
N
(
sam
),
"active"
);
private_key_type
priv_dan
=
c
.
get_private_key
(
N
(
dan
),
"active"
);
private_key_type
priv_pam
=
c
.
get_private_key
(
N
(
pam
),
"active"
);
private_key_type
priv_scott
=
c
.
get_private_key
(
N
(
scott
),
"active"
);
private_key_type
priv_invalid
=
c
.
get_private_key
(
N
(
invalid
),
"active"
);
wlog
(
"set producer schedule to [dan,sam,pam,scott]"
);
c
.
produce_blocks
(
50
);
c
.
control
->
abort_block
();
// discard pending block
BOOST_REQUIRE_EQUAL
(
61
,
c
.
control
->
head_block_num
());
// 55 is by dan
block_state_ptr
blk
=
c
.
control
->
fork_db
().
get_block_in_current_chain_by_num
(
55
);
block_state_ptr
blk61
=
c
.
control
->
fork_db
().
get_block_in_current_chain_by_num
(
61
);
block_state_ptr
blk50
=
c
.
control
->
fork_db
().
get_block_in_current_chain_by_num
(
50
);
BOOST_REQUIRE_EQUAL
(
0
,
blk
->
bft_irreversible_blocknum
);
BOOST_REQUIRE_EQUAL
(
0
,
blk
->
confirmations
.
size
());
printf
(
"bft number is %d #confirms %d
\n
"
,
blk
->
bft_irreversible_blocknum
,
(
int
)
blk
->
confirmations
.
size
());
// invalid signature
BOOST_REQUIRE_EXCEPTION
(
c
.
control
->
push_confirmation
(
header_confirmation
{
blk
->
id
,
N
(
sam
),
priv_invalid
.
sign
(
blk
->
sig_digest
())}),
fc
::
exception
,
[]
(
const
fc
::
exception
&
ex
)
->
bool
{
return
ex
.
to_detail_string
().
find
(
"confirmation not signed by expected key"
)
!=
std
::
string
::
npos
;
});
// invalid schedule
BOOST_REQUIRE_EXCEPTION
(
c
.
control
->
push_confirmation
(
header_confirmation
{
blk
->
id
,
N
(
invalid
),
priv_invalid
.
sign
(
blk
->
sig_digest
())}),
fc
::
exception
,
[]
(
const
fc
::
exception
&
ex
)
->
bool
{
return
ex
.
to_detail_string
().
find
(
"producer not in current schedule"
)
!=
std
::
string
::
npos
;
});
// signed by sam
c
.
control
->
push_confirmation
(
header_confirmation
{
blk
->
id
,
N
(
sam
),
priv_sam
.
sign
(
blk
->
sig_digest
())});
BOOST_REQUIRE_EQUAL
(
0
,
blk
->
bft_irreversible_blocknum
);
BOOST_REQUIRE_EQUAL
(
1
,
blk
->
confirmations
.
size
());
printf
(
"bft number is %d #confirms %d
\n
"
,
blk
->
bft_irreversible_blocknum
,
(
int
)
blk
->
confirmations
.
size
());
// double confirm not allowed
BOOST_REQUIRE_EXCEPTION
(
c
.
control
->
push_confirmation
(
header_confirmation
{
blk
->
id
,
N
(
sam
),
priv_sam
.
sign
(
blk
->
sig_digest
())}),
fc
::
exception
,
[]
(
const
fc
::
exception
&
ex
)
->
bool
{
return
ex
.
to_detail_string
().
find
(
"block already confirmed by this producer"
)
!=
std
::
string
::
npos
;
});
// signed by dan
c
.
control
->
push_confirmation
(
header_confirmation
{
blk
->
id
,
N
(
dan
),
priv_dan
.
sign
(
blk
->
sig_digest
())});
BOOST_REQUIRE_EQUAL
(
0
,
blk
->
bft_irreversible_blocknum
);
BOOST_REQUIRE_EQUAL
(
2
,
blk
->
confirmations
.
size
());
printf
(
"bft number is %d #confirms %d
\n
"
,
blk
->
bft_irreversible_blocknum
,
(
int
)
blk
->
confirmations
.
size
());
// signed by pam
c
.
control
->
push_confirmation
(
header_confirmation
{
blk
->
id
,
N
(
pam
),
priv_pam
.
sign
(
blk
->
sig_digest
())});
// we have more than 2/3 of confirmations, bft irreversible number should be set
BOOST_REQUIRE_EQUAL
(
55
,
blk
->
bft_irreversible_blocknum
);
BOOST_REQUIRE_EQUAL
(
55
,
blk61
->
bft_irreversible_blocknum
);
// bft irreversible number will propagate to higher block
BOOST_REQUIRE_EQUAL
(
0
,
blk50
->
bft_irreversible_blocknum
);
// bft irreversible number will not propagate to lower block
BOOST_REQUIRE_EQUAL
(
3
,
blk
->
confirmations
.
size
());
printf
(
"bft number is %d #confirms %d
\n
"
,
blk
->
bft_irreversible_blocknum
,
(
int
)
blk
->
confirmations
.
size
());
// signed by scott
c
.
control
->
push_confirmation
(
header_confirmation
{
blk
->
id
,
N
(
scott
),
priv_scott
.
sign
(
blk
->
sig_digest
())});
BOOST_REQUIRE_EQUAL
(
55
,
blk
->
bft_irreversible_blocknum
);
BOOST_REQUIRE_EQUAL
(
4
,
blk
->
confirmations
.
size
());
printf
(
"bft number is %d #confirms %d
\n
"
,
blk
->
bft_irreversible_blocknum
,
(
int
)
blk
->
confirmations
.
size
());
// let's confirm block 50 as well
c
.
control
->
push_confirmation
(
header_confirmation
{
blk50
->
id
,
N
(
sam
),
priv_sam
.
sign
(
blk50
->
sig_digest
())});
c
.
control
->
push_confirmation
(
header_confirmation
{
blk50
->
id
,
N
(
dan
),
priv_dan
.
sign
(
blk50
->
sig_digest
())});
c
.
control
->
push_confirmation
(
header_confirmation
{
blk50
->
id
,
N
(
pam
),
priv_pam
.
sign
(
blk50
->
sig_digest
())});
BOOST_REQUIRE_EQUAL
(
50
,
blk50
->
bft_irreversible_blocknum
);
// bft irreversible number will not propagate to lower block
block_state_ptr
blk54
=
c
.
control
->
fork_db
().
get_block_in_current_chain_by_num
(
54
);
BOOST_REQUIRE_EQUAL
(
50
,
blk54
->
bft_irreversible_blocknum
);
BOOST_REQUIRE_EQUAL
(
55
,
blk
->
bft_irreversible_blocknum
);
// bft irreversible number will not be updated to lower value
BOOST_REQUIRE_EQUAL
(
55
,
blk61
->
bft_irreversible_blocknum
);
c
.
produce_blocks
(
20
);
block_state_ptr
blk81
=
c
.
control
->
fork_db
().
get_block_in_current_chain_by_num
(
81
);
BOOST_REQUIRE_EQUAL
(
55
,
blk81
->
bft_irreversible_blocknum
);
// bft irreversible number will propagate into new blocks
}
FC_LOG_AND_RETHROW
()
BOOST_AUTO_TEST_SUITE_END
()
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录