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
此差异已折叠。
点击以展开。
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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录