Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
YottaChain
YTBP
提交
331d4218
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,发现更多精彩内容 >>
未验证
提交
331d4218
编写于
3月 28, 2018
作者:
D
Daniel Larimer
提交者:
GitHub
3月 28, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #1859 from brianjohnson5972/398-delayed-signed-txn
Delayed Transactions
上级
13a30de0
4694ddb9
变更
19
展开全部
显示空白变更内容
内联
并排
Showing
19 changed file
with
1114 addition
and
137 deletion
+1114
-137
libraries/chain/apply_context.cpp
libraries/chain/apply_context.cpp
+32
-4
libraries/chain/chain_controller.cpp
libraries/chain/chain_controller.cpp
+167
-34
libraries/chain/contracts/chain_initializer.cpp
libraries/chain/contracts/chain_initializer.cpp
+17
-0
libraries/chain/contracts/eosio_contract.cpp
libraries/chain/contracts/eosio_contract.cpp
+37
-19
libraries/chain/include/eosio/chain/apply_context.hpp
libraries/chain/include/eosio/chain/apply_context.hpp
+4
-0
libraries/chain/include/eosio/chain/authority_checker.hpp
libraries/chain/include/eosio/chain/authority_checker.hpp
+15
-5
libraries/chain/include/eosio/chain/chain_controller.hpp
libraries/chain/include/eosio/chain/chain_controller.hpp
+22
-10
libraries/chain/include/eosio/chain/contracts/eos_contract.hpp
...ries/chain/include/eosio/chain/contracts/eos_contract.hpp
+3
-0
libraries/chain/include/eosio/chain/contracts/types.hpp
libraries/chain/include/eosio/chain/contracts/types.hpp
+27
-1
libraries/chain/include/eosio/chain/permission_object.hpp
libraries/chain/include/eosio/chain/permission_object.hpp
+19
-10
libraries/chain/include/eosio/chain/transaction.hpp
libraries/chain/include/eosio/chain/transaction.hpp
+12
-2
libraries/fc/include/fc/time.hpp
libraries/fc/include/fc/time.hpp
+3
-0
libraries/testing/include/eosio/testing/tester.hpp
libraries/testing/include/eosio/testing/tester.hpp
+6
-4
libraries/testing/tester.cpp
libraries/testing/tester.cpp
+22
-7
plugins/net_plugin/net_plugin.cpp
plugins/net_plugin/net_plugin.cpp
+5
-1
tests/chain_tests/block_tests.cpp
tests/chain_tests/block_tests.cpp
+4
-2
tests/chain_tests/delay_tests.cpp
tests/chain_tests/delay_tests.cpp
+672
-0
tests/tests/abi_tests.cpp
tests/tests/abi_tests.cpp
+2
-1
tests/tests/misc_tests.cpp
tests/tests/misc_tests.cpp
+45
-37
未找到文件。
libraries/chain/apply_context.cpp
浏览文件 @
331d4218
...
...
@@ -198,7 +198,10 @@ void apply_context::require_recipient( account_name code ) {
void
apply_context
::
execute_inline
(
action
&&
a
)
{
if
(
!
privileged
)
{
if
(
a
.
account
!=
receiver
)
{
controller
.
check_authorization
({
a
},
flat_set
<
public_key_type
>
(),
false
,
{
receiver
});
const
auto
delay
=
controller
.
check_authorization
({
a
},
flat_set
<
public_key_type
>
(),
false
,
{
receiver
});
FC_ASSERT
(
trx_meta
.
published
+
delay
<=
controller
.
head_block_time
(),
"inline action uses a permission that imposes a delay that is not met, add an action of mindelay with delay of atleast ${delay}"
,
(
"delay"
,
delay
.
sec_since_epoch
())
);
}
}
_inline_actions
.
emplace_back
(
move
(
a
)
);
...
...
@@ -232,8 +235,12 @@ void apply_context::execute_deferred( deferred_transaction&& trx ) {
break
;
}
}
if
(
check_auth
)
controller
.
check_authorization
(
trx
.
actions
,
flat_set
<
public_key_type
>
(),
false
,
{
receiver
});
if
(
check_auth
)
{
const
auto
delay
=
controller
.
check_authorization
(
trx
.
actions
,
flat_set
<
public_key_type
>
(),
false
,
{
receiver
});
FC_ASSERT
(
trx_meta
.
published
+
delay
<=
controller
.
head_block_time
(),
"deferred transaction uses a permission that imposes a delay that is not met, add an action of mindelay with delay of atleast ${delay}"
,
(
"delay"
,
delay
.
sec_since_epoch
())
);
}
}
trx
.
sender
=
receiver
;
// "Attempting to send from another account"
...
...
@@ -355,10 +362,31 @@ int apply_context::get_context_free_data( uint32_t index, char* buffer, size_t b
return
s
;
}
uint32_t
apply_context
::
get_next_sender_id
()
{
const
uint64_t
id
=
N
(
config
::
eosio_auth_scope
);
const
auto
table
=
N
(
deferred
.
seq
);
const
auto
payer
=
config
::
system_account_name
;
const
auto
iter
=
db_find_i64
(
config
::
system_account_name
,
config
::
eosio_auth_scope
,
table
,
id
);
if
(
iter
==
-
1
)
{
const
uint32_t
next_serial
=
1
;
db_store_i64
(
config
::
system_account_name
,
config
::
eosio_auth_scope
,
table
,
payer
,
id
,
(
const
char
*
)
&
next_serial
,
sizeof
(
next_serial
));
return
0
;
}
uint32_t
next_serial
=
0
;
db_get_i64
(
iter
,
(
char
*
)
&
next_serial
,
sizeof
(
next_serial
));
const
auto
result
=
next_serial
++
;
db_update_i64
(
iter
,
payer
,
(
const
char
*
)
&
next_serial
,
sizeof
(
next_serial
));
return
result
;
}
int
apply_context
::
db_store_i64
(
uint64_t
scope
,
uint64_t
table
,
const
account_name
&
payer
,
uint64_t
id
,
const
char
*
buffer
,
size_t
buffer_size
)
{
return
db_store_i64
(
receiver
,
scope
,
table
,
payer
,
id
,
buffer
,
buffer_size
);
}
int
apply_context
::
db_store_i64
(
uint64_t
code
,
uint64_t
scope
,
uint64_t
table
,
const
account_name
&
payer
,
uint64_t
id
,
const
char
*
buffer
,
size_t
buffer_size
)
{
require_write_lock
(
scope
);
const
auto
&
tab
=
find_or_create_table
(
receiver
,
scope
,
table
);
const
auto
&
tab
=
find_or_create_table
(
code
,
scope
,
table
);
auto
tableid
=
tab
.
id
;
FC_ASSERT
(
payer
!=
account_name
(),
"must specify a valid account to pay for new record"
);
...
...
libraries/chain/chain_controller.cpp
浏览文件 @
331d4218
...
...
@@ -256,18 +256,55 @@ transaction_trace chain_controller::push_transaction(const packed_transaction& t
});
}
FC_CAPTURE_AND_RETHROW
()
}
transaction_trace
chain_controller
::
_push_transaction
(
const
packed_transaction
&
trx
)
transaction_trace
chain_controller
::
_push_transaction
(
const
packed_transaction
&
packed_trx
)
{
try
{
transaction_metadata
mtrx
(
trx
,
get_chain_id
(),
head_block_time
());
transaction_metadata
mtrx
(
packed_
trx
,
get_chain_id
(),
head_block_time
());
check_transaction_authorization
(
mtrx
.
trx
(),
trx
.
signatures
,
trx
.
context_free_data
);
auto
result
=
_push_transaction
(
std
::
move
(
mtrx
));
const
auto
delay
=
check_transaction_authorization
(
mtrx
.
trx
(),
packed_trx
.
signatures
,
packed_trx
.
context_free_data
);
transaction_trace
result
(
mtrx
.
id
);
if
(
!
delay
.
sec_since_epoch
())
{
result
=
_push_transaction
(
std
::
move
(
mtrx
));
// notify anyone listening to pending transactions
on_pending_transaction
(
_pending_transaction_metas
.
back
(),
trx
);
on_pending_transaction
(
_pending_transaction_metas
.
back
(),
packed_
trx
);
_pending_block
->
input_transactions
.
emplace_back
(
trx
);
_pending_block
->
input_transactions
.
emplace_back
(
packed_
trx
);
}
else
{
result
.
status
=
transaction_trace
::
delayed
;
const
auto
trx
=
mtrx
.
trx
();
FC_ASSERT
(
!
trx
.
actions
.
empty
(),
"transaction must have at least one action"
);
FC_ASSERT
(
trx
.
expiration
>
(
head_block_time
()
+
fc
::
milliseconds
(
2
*
config
::
block_interval_ms
)),
"transaction is expired when created"
);
// add in the system account authorization
action
for_deferred
=
trx
.
actions
[
0
];
bool
found
=
false
;
for
(
const
auto
&
auth
:
for_deferred
.
authorization
)
{
if
(
auth
.
actor
==
config
::
system_account_name
&&
auth
.
permission
==
config
::
active_name
)
{
found
=
true
;
break
;
}
}
if
(
!
found
)
for_deferred
.
authorization
.
push_back
(
permission_level
{
config
::
system_account_name
,
config
::
active_name
});
apply_context
context
(
*
this
,
_db
,
for_deferred
,
mtrx
);
time_point_sec
execute_after
=
head_block_time
();
execute_after
+=
time_point_sec
(
delay
);
deferred_transaction
dtrx
(
context
.
get_next_sender_id
(),
config
::
system_account_name
,
execute_after
,
trx
);
FC_ASSERT
(
dtrx
.
execute_after
<
dtrx
.
expiration
,
"transaction expires before it can execute"
);
result
.
deferred_transaction_requests
.
push_back
(
std
::
move
(
dtrx
));
// notify anyone listening to pending transactions
on_pending_transaction
(
std
::
move
(
mtrx
),
packed_trx
);
store_deferred_transaction
(
result
.
deferred_transaction_requests
[
0
].
get
<
deferred_transaction
>
());
}
return
result
;
}
FC_CAPTURE_AND_RETHROW
()
}
...
...
@@ -412,6 +449,21 @@ void chain_controller::_finalize_pending_cycle()
_pending_cycle_trace
.
reset
();
}
void
chain_controller
::
store_deferred_transaction
(
const
deferred_transaction
&
dtrx
)
{
_db
.
create
<
generated_transaction_object
>
([
&
](
generated_transaction_object
&
obj
)
{
obj
.
trx_id
=
dtrx
.
id
();
obj
.
sender
=
dtrx
.
sender
;
obj
.
sender_id
=
dtrx
.
sender_id
;
obj
.
expiration
=
dtrx
.
expiration
;
obj
.
delay_until
=
dtrx
.
execute_after
;
obj
.
published
=
head_block_time
();
obj
.
packed_trx
.
resize
(
fc
::
raw
::
pack_size
(
dtrx
));
fc
::
datastream
<
char
*>
ds
(
obj
.
packed_trx
.
data
(),
obj
.
packed_trx
.
size
());
fc
::
raw
::
pack
(
ds
,
dtrx
);
});
}
void
chain_controller
::
_apply_cycle_trace
(
const
cycle_trace
&
res
)
{
auto
&
generated_transaction_idx
=
_db
.
get_mutable_index
<
generated_transaction_multi_index
>
();
...
...
@@ -433,17 +485,7 @@ void chain_controller::_apply_cycle_trace( const cycle_trace& res )
fc
::
raw
::
pack
(
ds
,
dt
);
});
}
else
{
_db
.
create
<
generated_transaction_object
>
([
&
](
generated_transaction_object
&
obj
)
{
obj
.
trx_id
=
dt
.
id
();
obj
.
sender
=
dt
.
sender
;
obj
.
sender_id
=
dt
.
sender_id
;
obj
.
expiration
=
dt
.
expiration
;
obj
.
delay_until
=
dt
.
execute_after
;
obj
.
published
=
head_block_time
();
obj
.
packed_trx
.
resize
(
fc
::
raw
::
pack_size
(
dt
));
fc
::
datastream
<
char
*>
ds
(
obj
.
packed_trx
.
data
(),
obj
.
packed_trx
.
size
());
fc
::
raw
::
pack
(
ds
,
dt
);
});
store_deferred_transaction
(
dt
);
}
}
else
if
(
req
.
contains
<
deferred_reference
>
()
)
{
const
auto
&
dr
=
req
.
get
<
deferred_reference
>
();
...
...
@@ -782,6 +824,7 @@ flat_set<public_key_type> chain_controller::get_required_keys(const transaction&
const
flat_set
<
public_key_type
>&
candidate_keys
)
const
{
auto
checker
=
make_auth_checker
(
[
&
](
const
permission_level
&
p
){
return
get_permission
(
p
).
auth
;
},
[](
const
permission_level
&
)
{},
get_global_properties
().
configuration
.
max_authority_depth
,
candidate_keys
);
...
...
@@ -798,64 +841,154 @@ flat_set<public_key_type> chain_controller::get_required_keys(const transaction&
return
checker
.
used_keys
();
}
void
chain_controller
::
check_authorization
(
const
vector
<
action
>&
actions
,
class
permission_visitor
{
public:
permission_visitor
(
const
chain_controller
&
controller
)
:
_chain_controller
(
controller
)
{}
void
operator
()(
const
permission_level
&
perm_level
)
{
const
auto
obj
=
_chain_controller
.
get_permission
(
perm_level
);
if
(
_max_delay
<
obj
.
delay
)
_max_delay
=
obj
.
delay
;
}
const
time_point
&
get_max_delay
()
const
{
return
_max_delay
;
}
private:
const
chain_controller
&
_chain_controller
;
time_point
_max_delay
;
};
time_point
chain_controller
::
check_authorization
(
const
vector
<
action
>&
actions
,
const
flat_set
<
public_key_type
>&
provided_keys
,
bool
allow_unused_signatures
,
flat_set
<
account_name
>
provided_accounts
)
const
{
auto
checker
=
make_auth_checker
(
[
&
](
const
permission_level
&
p
){
return
get_permission
(
p
).
auth
;
},
permission_visitor
(
*
this
),
get_global_properties
().
configuration
.
max_authority_depth
,
provided_keys
,
provided_accounts
);
time_point
max_delay
;
for
(
const
auto
&
act
:
actions
)
{
for
(
const
auto
&
declared_auth
:
act
.
authorization
)
{
// check a minimum permission if one is set, otherwise assume the contract code will validate
auto
min_permission_name
=
lookup_minimum_permission
(
declared_auth
.
actor
,
act
.
account
,
act
.
name
);
bool
min_permission_required
=
true
;
if
(
!
min_permission_name
)
{
// for updateauth actions, need to determine the permission that is changing
if
(
act
.
account
==
config
::
system_account_name
&&
act
.
name
==
contracts
::
updateauth
::
get_name
())
{
auto
update
=
act
.
data_as
<
contracts
::
updateauth
>
();
const
auto
permission_to_change
=
_db
.
find
<
permission_object
,
by_owner
>
(
boost
::
make_tuple
(
update
.
account
,
update
.
permission
));
if
(
permission_to_change
!=
nullptr
)
{
// only determining delay
min_permission_required
=
false
;
min_permission_name
=
update
.
permission
;
}
}
}
if
(
min_permission_name
)
{
const
auto
&
min_permission
=
_db
.
get
<
permission_object
,
by_owner
>
(
boost
::
make_tuple
(
declared_auth
.
actor
,
*
min_permission_name
));
if
((
_skip_flags
&
skip_authority_check
)
==
false
)
{
const
auto
&
index
=
_db
.
get_index
<
permission_index
>
().
indices
();
EOS_ASSERT
(
get_permission
(
declared_auth
).
satisfies
(
min_permission
,
index
),
const
auto
&
index
=
_db
.
get_index
<
permission_index
>
().
indices
();
const
optional
<
time_point
>
delay
=
get_permission
(
declared_auth
).
satisfies
(
min_permission
,
index
);
EOS_ASSERT
(
!
min_permission_required
||
delay
.
valid
(),
tx_irrelevant_auth
,
"action declares irrelevant authority '${auth}'; minimum authority is ${min}"
,
(
"auth"
,
declared_auth
)(
"min"
,
min_permission
.
name
));
if
(
max_delay
<
*
delay
)
max_delay
=
*
delay
;
}
}
if
(
act
.
account
==
config
::
system_account_name
)
{
// for link changes, we need to also determine the delay associated with an existing link that is being
// moved or removed
if
(
act
.
name
==
contracts
::
linkauth
::
get_name
())
{
auto
link
=
act
.
data_as
<
contracts
::
linkauth
>
();
if
(
declared_auth
.
actor
==
link
.
account
)
{
const
auto
linked_permission_name
=
lookup_linked_permission
(
link
.
account
,
link
.
code
,
link
.
type
);
if
(
linked_permission_name
.
valid
())
{
const
auto
&
linked_permission
=
_db
.
get
<
permission_object
,
by_owner
>
(
boost
::
make_tuple
(
link
.
account
,
*
linked_permission_name
));
const
auto
&
index
=
_db
.
get_index
<
permission_index
>
().
indices
();
const
optional
<
time_point
>
delay
=
get_permission
(
declared_auth
).
satisfies
(
linked_permission
,
index
);
if
(
delay
.
valid
()
&&
max_delay
<
*
delay
)
max_delay
=
*
delay
;
}
// else it is only a new link, so don't need to delay
}
}
else
if
(
act
.
name
==
contracts
::
unlinkauth
::
get_name
())
{
auto
unlink
=
act
.
data_as
<
contracts
::
unlinkauth
>
();
if
(
declared_auth
.
actor
==
unlink
.
account
)
{
const
auto
unlinked_permission_name
=
lookup_linked_permission
(
unlink
.
account
,
unlink
.
code
,
unlink
.
type
);
if
(
unlinked_permission_name
.
valid
())
{
const
auto
&
unlinked_permission
=
_db
.
get
<
permission_object
,
by_owner
>
(
boost
::
make_tuple
(
unlink
.
account
,
*
unlinked_permission_name
));
const
auto
&
index
=
_db
.
get_index
<
permission_index
>
().
indices
();
const
optional
<
time_point
>
delay
=
get_permission
(
declared_auth
).
satisfies
(
unlinked_permission
,
index
);
if
(
delay
.
valid
()
&&
max_delay
<
*
delay
)
max_delay
=
*
delay
;
}
}
}
}
if
((
_skip_flags
&
skip_transaction_signatures
)
==
false
)
{
EOS_ASSERT
(
checker
.
satisfied
(
declared_auth
),
tx_missing_sigs
,
"transaction declares authority '${auth}', but does not have signatures for it."
,
(
"auth"
,
declared_auth
));
}
}
if
(
act
.
account
==
config
::
system_account_name
&&
act
.
name
==
contracts
::
mindelay
::
get_name
())
{
const
auto
mindelay
=
act
.
data_as
<
contracts
::
mindelay
>
();
const
time_point
delay
=
time_point_sec
{
mindelay
.
delay
.
convert_to
<
uint32_t
>
()};
if
(
max_delay
<
delay
)
max_delay
=
delay
;
}
}
if
(
!
allow_unused_signatures
&&
(
_skip_flags
&
skip_transaction_signatures
)
==
false
)
EOS_ASSERT
(
checker
.
all_keys_used
(),
tx_irrelevant_sig
,
"transaction bears irrelevant signatures from these keys: ${keys}"
,
(
"keys"
,
checker
.
unused_keys
()));
const
auto
checker_max_delay
=
checker
.
get_permission_visitor
().
get_max_delay
();
if
(
max_delay
<
checker_max_delay
)
max_delay
=
checker_max_delay
;
return
max_delay
;
}
void
chain_controller
::
check_transaction_authorization
(
const
transaction
&
trx
,
time_point
chain_controller
::
check_transaction_authorization
(
const
transaction
&
trx
,
const
vector
<
signature_type
>&
signatures
,
const
vector
<
bytes
>&
cfd
,
bool
allow_unused_signatures
)
const
{
check_authorization
(
trx
.
actions
,
trx
.
get_signature_keys
(
signatures
,
chain_id_type
{},
cfd
),
allow_unused_signatures
);
return
check_authorization
(
trx
.
actions
,
trx
.
get_signature_keys
(
signatures
,
chain_id_type
{},
cfd
),
allow_unused_signatures
);
}
optional
<
permission_name
>
chain_controller
::
lookup_minimum_permission
(
account_name
authorizer_account
,
account_name
scope
,
action_name
act_name
)
const
{
#warning TODO: this comment sounds like it is expecting a check ("may") somewhere else, but I have not found anything else
// updateauth is a special case where any permission _may_ be suitable depending
// on the contents of the action
if
(
scope
==
config
::
system_account_name
&&
act_name
==
N
(
updateauth
))
{
if
(
scope
==
config
::
system_account_name
&&
act_name
==
contracts
::
updateauth
::
get_name
(
))
{
return
optional
<
permission_name
>
();
}
try
{
optional
<
permission_name
>
linked_permission
=
lookup_linked_permission
(
authorizer_account
,
scope
,
act_name
);
if
(
!
linked_permission
)
return
config
::
active_name
;
return
linked_permission
;
}
FC_CAPTURE_AND_RETHROW
((
authorizer_account
)(
scope
)(
act_name
))
}
optional
<
permission_name
>
chain_controller
::
lookup_linked_permission
(
account_name
authorizer_account
,
account_name
scope
,
action_name
act_name
)
const
{
try
{
// First look up a specific link for this message act_name
auto
key
=
boost
::
make_tuple
(
authorizer_account
,
scope
,
act_name
);
...
...
@@ -869,8 +1002,8 @@ optional<permission_name> chain_controller::lookup_minimum_permission(account_na
// If no specific or default link found, use active permission
if
(
link
!=
nullptr
)
return
link
->
required_permission
;
else
return
N
(
active
);
return
optional
<
permission_name
>
(
);
}
FC_CAPTURE_AND_RETHROW
((
authorizer_account
)(
scope
)(
act_name
))
}
...
...
@@ -1614,7 +1747,7 @@ vector<transaction_trace> chain_controller::push_deferred_transactions( bool flu
auto
&
generated_index
=
generated_transaction_idx
.
indices
().
get
<
by_delay
>
();
vector
<
const
generated_transaction_object
*>
candidates
;
for
(
auto
itr
=
generated_index
.
rbegin
();
itr
!=
generated_index
.
r
end
()
&&
(
head_block_time
()
>=
itr
->
delay_until
);
++
itr
)
{
for
(
auto
itr
=
generated_index
.
begin
();
itr
!=
generated_index
.
end
()
&&
(
head_block_time
()
>=
itr
->
delay_until
);
++
itr
)
{
const
auto
&
gtrx
=
*
itr
;
candidates
.
emplace_back
(
&
gtrx
);
}
...
...
libraries/chain/contracts/chain_initializer.cpp
浏览文件 @
331d4218
...
...
@@ -46,6 +46,8 @@ void chain_initializer::register_types(chain_controller& chain, chainbase::datab
SET_APP_HANDLER
(
eosio
,
eosio
,
postrecovery
,
eosio
);
SET_APP_HANDLER
(
eosio
,
eosio
,
passrecovery
,
eosio
);
SET_APP_HANDLER
(
eosio
,
eosio
,
vetorecovery
,
eosio
);
SET_APP_HANDLER
(
eosio
,
eosio
,
canceldelay
,
eosio
);
SET_APP_HANDLER
(
eosio
,
eosio
,
mindelay
,
eosio
);
}
...
...
@@ -73,6 +75,8 @@ abi_def chain_initializer::eos_contract_abi(const abi_def& eosio_system_abi)
eos_abi
.
actions
.
push_back
(
action_def
{
name
(
"vetorecovery"
),
"vetorecovery"
}
);
eos_abi
.
actions
.
push_back
(
action_def
{
name
(
"onerror"
),
"onerror"
}
);
eos_abi
.
actions
.
push_back
(
action_def
{
name
(
"onblock"
),
"onblock"
}
);
eos_abi
.
actions
.
push_back
(
action_def
{
name
(
"canceldelay"
),
"canceldelay"
}
);
eos_abi
.
actions
.
push_back
(
action_def
{
name
(
"mindelay"
),
"mindelay"
}
);
// ACTION PAYLOADS
...
...
@@ -99,6 +103,7 @@ abi_def chain_initializer::eos_contract_abi(const abi_def& eosio_system_abi)
{
"permission"
,
"permission_name"
},
{
"parent"
,
"permission_name"
},
{
"data"
,
"authority"
},
{
"delay"
,
"uint32"
}
}
});
...
...
@@ -156,6 +161,18 @@ abi_def chain_initializer::eos_contract_abi(const abi_def& eosio_system_abi)
}
});
eos_abi
.
structs
.
emplace_back
(
struct_def
{
"canceldelay"
,
""
,
{
{
"sender_id"
,
"uint32"
},
}
});
eos_abi
.
structs
.
emplace_back
(
struct_def
{
"mindelay"
,
""
,
{
{
"delay"
,
"uint32"
},
}
});
// DATABASE RECORDS
eos_abi
.
structs
.
emplace_back
(
struct_def
{
...
...
libraries/chain/contracts/eosio_contract.cpp
浏览文件 @
331d4218
...
...
@@ -14,6 +14,7 @@
#include <eosio/chain/account_object.hpp>
#include <eosio/chain/permission_object.hpp>
#include <eosio/chain/permission_link_object.hpp>
#include <eosio/chain/generated_transaction_object.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <eosio/chain/contracts/types.hpp>
#include <eosio/chain/producer_object.hpp>
...
...
@@ -199,6 +200,7 @@ void apply_eosio_updateauth(apply_context& context) {
po
.
auth
=
update
.
data
;
po
.
parent
=
parent_id
;
po
.
last_updated
=
context
.
controller
.
head_block_time
();
po
.
delay
=
time_point_sec
(
update
.
delay
.
convert_to
<
uint64_t
>
());
});
}
else
{
// TODO/QUESTION: If we are creating a new permission, should we check if the message declared
...
...
@@ -209,6 +211,7 @@ void apply_eosio_updateauth(apply_context& context) {
po
.
auth
=
update
.
data
;
po
.
parent
=
parent_id
;
po
.
last_updated
=
context
.
controller
.
head_block_time
();
po
.
delay
=
time_point_sec
(
update
.
delay
.
convert_to
<
uint64_t
>
());
});
}
}
...
...
@@ -313,24 +316,6 @@ static optional<variant> get_pending_recovery(apply_context& context, account_na
return
optional
<
variant_object
>
();
}
static
uint32_t
get_next_sender_id
(
apply_context
&
context
)
{
const
uint64_t
id
=
N
(
config
::
eosio_auth_scope
);
const
auto
table
=
N
(
deferred
.
seq
);
const
auto
payer
=
config
::
system_account_name
;
const
auto
iter
=
context
.
db_find_i64
(
config
::
system_account_name
,
config
::
eosio_auth_scope
,
table
,
id
);
if
(
iter
==
-
1
)
{
const
uint32_t
next_serial
=
1
;
context
.
db_store_i64
(
config
::
eosio_auth_scope
,
table
,
payer
,
id
,
(
const
char
*
)
&
next_serial
,
sizeof
(
next_serial
));
return
0
;
}
uint32_t
next_serial
=
0
;
context
.
db_get_i64
(
iter
,
(
char
*
)
&
next_serial
,
sizeof
(
next_serial
));
const
auto
result
=
next_serial
++
;
context
.
db_update_i64
(
iter
,
payer
,
(
const
char
*
)
&
next_serial
,
sizeof
(
next_serial
));
return
result
;
}
static
auto
get_account_creation
(
const
apply_context
&
context
,
const
account_name
&
account
)
{
auto
const
&
accnt
=
context
.
db
.
get
<
account_object
,
by_name
>
(
account
);
return
(
time_point
)
accnt
.
creation_date
;
...
...
@@ -393,7 +378,7 @@ void apply_eosio_postrecovery(apply_context& context) {
.
data
=
recover_act
.
data
},
update
);
uint32_t
request_id
=
get_next_sender_id
(
context
);
uint32_t
request_id
=
context
.
get_next_sender_id
(
);
auto
record_data
=
mutable_variant_object
()
(
"account"
,
account
)
...
...
@@ -473,5 +458,38 @@ void apply_eosio_vetorecovery(apply_context& context) {
context
.
console_append_formatted
(
"Recovery for account ${account} vetoed!
\n
"
,
mutable_variant_object
()(
"account"
,
account
));
}
void
apply_eosio_canceldelay
(
apply_context
&
context
)
{
auto
cancel
=
context
.
act
.
data_as
<
canceldelay
>
();
const
auto
sender_id
=
cancel
.
sender_id
.
convert_to
<
uint32_t
>
();
const
auto
&
generated_transaction_idx
=
context
.
controller
.
get_database
().
get_index
<
generated_transaction_multi_index
>
();
const
auto
&
generated_index
=
generated_transaction_idx
.
indices
().
get
<
by_sender_id
>
();
const
auto
&
itr
=
generated_index
.
lower_bound
(
boost
::
make_tuple
(
config
::
system_account_name
,
sender_id
));
FC_ASSERT
(
itr
==
generated_index
.
end
()
||
itr
->
sender
!=
config
::
system_account_name
||
itr
->
sender_id
!=
sender_id
,
"cannot cancel sender_id=${sid}, there is no deferred transaction with that sender_id"
,(
"sid"
,
sender_id
));
auto
dtrx
=
fc
::
raw
::
unpack
<
deferred_transaction
>
(
itr
->
packed_trx
.
data
(),
itr
->
packed_trx
.
size
());
set
<
account_name
>
accounts
;
for
(
const
auto
&
act
:
dtrx
.
actions
)
{
for
(
const
auto
&
auth
:
act
.
authorization
)
{
accounts
.
insert
(
auth
.
actor
);
}
}
bool
found
=
false
;
for
(
const
auto
&
auth
:
context
.
act
.
authorization
)
{
if
(
auth
.
permission
==
config
::
active_name
&&
accounts
.
count
(
auth
.
actor
))
{
found
=
true
;
break
;
}
}
FC_ASSERT
(
found
,
"canceldelay action must be signed with the
\"
active
\"
permission for one of the actors"
" provided in the authorizations on the original transaction"
);
context
.
cancel_deferred
(
sender_id
);
}
void
apply_eosio_mindelay
(
apply_context
&
context
)
{
// all processing is performed in chain_controller::check_authorization
}
}
}
}
// namespace eosio::chain::contracts
libraries/chain/include/eosio/chain/apply_context.hpp
浏览文件 @
331d4218
...
...
@@ -504,6 +504,8 @@ class apply_context {
const
bytes
&
get_packed_transaction
();
uint32_t
get_next_sender_id
();
const
chain_controller
&
controller
;
const
chainbase
::
database
&
db
;
///< database where state is stored
const
action
&
act
;
///< message being applied
...
...
@@ -585,6 +587,8 @@ class apply_context {
const
table_id_object
*
find_table
(
name
code
,
name
scope
,
name
table
);
const
table_id_object
&
find_or_create_table
(
name
code
,
name
scope
,
name
table
);
int
db_store_i64
(
uint64_t
code
,
uint64_t
scope
,
uint64_t
table
,
const
account_name
&
payer
,
uint64_t
id
,
const
char
*
buffer
,
size_t
buffer_size
);
vector
<
account_name
>
_notified
;
///< keeps track of new accounts to be notifed of current message
vector
<
action
>
_inline_actions
;
///< queued inline messages
vector
<
action
>
_cfa_inline_actions
;
///< queued inline messages
...
...
libraries/chain/include/eosio/chain/authority_checker.hpp
浏览文件 @
331d4218
...
...
@@ -50,10 +50,11 @@ namespace detail {
* @tparam F A callable which takes a single argument of type @ref AccountPermission and returns the corresponding
* authority
*/
template
<
typename
PermissionToAuthorityFunc
>
template
<
typename
PermissionToAuthorityFunc
,
typename
PermissionVisitorFunc
>
class
authority_checker
{
private:
PermissionToAuthorityFunc
permission_to_authority
;
PermissionVisitorFunc
permission_visitor
;
uint16_t
recursion_depth_limit
;
vector
<
public_key_type
>
signing_keys
;
flat_set
<
account_name
>
_provided_auths
;
/// accounts which have authorized the transaction at owner level
...
...
@@ -79,6 +80,8 @@ namespace detail {
}
uint32_t
operator
()(
const
permission_level_weight
&
permission
)
{
if
(
recursion_depth
<
checker
.
recursion_depth_limit
)
{
checker
.
permission_visitor
(
permission
.
permission
);
if
(
checker
.
has_permission
(
permission
.
permission
.
actor
)
)
total_weight
+=
permission
.
weight
;
else
if
(
checker
.
satisfied
(
permission
.
permission
,
recursion_depth
+
1
)
)
...
...
@@ -94,9 +97,11 @@ namespace detail {
public:
authority_checker
(
PermissionToAuthorityFunc
permission_to_authority
,
PermissionVisitorFunc
permission_visitor
,
uint16_t
recursion_depth_limit
,
const
flat_set
<
public_key_type
>&
signing_keys
,
flat_set
<
account_name
>
provided_auths
=
flat_set
<
account_name
>
()
)
:
permission_to_authority
(
permission_to_authority
),
permission_visitor
(
permission_visitor
),
recursion_depth_limit
(
recursion_depth_limit
),
signing_keys
(
signing_keys
.
begin
(),
signing_keys
.
end
()),
_provided_auths
(
provided_auths
.
begin
(),
provided_auths
.
end
()),
...
...
@@ -146,14 +151,19 @@ namespace detail {
auto
range
=
utilities
::
filter_data_by_marker
(
signing_keys
,
_used_keys
,
false
);
return
{
range
.
begin
(),
range
.
end
()};
}
const
PermissionVisitorFunc
&
get_permission_visitor
()
{
return
permission_visitor
;
}
};
/// authority_checker
template
<
typename
PermissionToAuthorityFunc
>
template
<
typename
PermissionToAuthorityFunc
,
typename
PermissionVisitorFunc
>
auto
make_auth_checker
(
PermissionToAuthorityFunc
&&
pta
,
PermissionVisitorFunc
&&
permission_visitor
,
uint16_t
recursion_depth_limit
,
const
flat_set
<
public_key_type
>&
signing_keys
,
const
flat_set
<
account_name
>&
accounts
=
flat_set
<
account_name
>
()
)
{
return
authority_checker
<
PermissionToAuthorityFunc
>
(
std
::
forward
<
PermissionToAuthorityFunc
>
(
pta
),
recursion_depth_limit
,
signing_keys
,
accounts
);
return
authority_checker
<
PermissionToAuthorityFunc
,
PermissionVisitorFunc
>
(
std
::
forward
<
PermissionToAuthorityFunc
>
(
pta
),
std
::
forward
<
PermissionVisitorFunc
>
(
permission_visitor
),
recursion_depth_limit
,
signing_keys
,
accounts
);
}
}
}
// namespace eosio::chain
libraries/chain/include/eosio/chain/chain_controller.hpp
浏览文件 @
331d4218
...
...
@@ -284,9 +284,9 @@ namespace eosio { namespace chain {
* @param allow_unused_signatures - true if method should not assert on unused signatures
* @param provided_accounts - the set of accounts which have authorized the transaction (presumed to be owner)
*
* @return t
rue if the provided keys and accounts are sufficient to authorize actions of the transaction
* @return t
ime_point set to the max delay that this authorization requires to complete
*/
void
check_authorization
(
const
vector
<
action
>&
actions
,
time_point
check_authorization
(
const
vector
<
action
>&
actions
,
const
flat_set
<
public_key_type
>&
provided_keys
,
bool
allow_unused_signatures
=
false
,
flat_set
<
account_name
>
provided_accounts
=
flat_set
<
account_name
>
()
...
...
@@ -337,7 +337,7 @@ namespace eosio { namespace chain {
return
f
();
}
void
check_transaction_authorization
(
const
transaction
&
trx
,
time_point
check_transaction_authorization
(
const
transaction
&
trx
,
const
vector
<
signature_type
>&
signatures
,
const
vector
<
bytes
>&
cfd
=
vector
<
bytes
>
(),
bool
allow_unused_signatures
=
false
)
const
;
...
...
@@ -381,6 +381,17 @@ namespace eosio { namespace chain {
scope_name
code_account
,
action_name
type
)
const
;
/**
* @brief Find the linked permission for the passed in parameters
* @param authorizer_account The account authorizing the message
* @param code_account The account which publishes the contract that handles the message
* @param type The type of message
* @return an optional<permission_name> for the linked permission if one exists; otherwise an invalid
* optional<permission_name>
*/
optional
<
permission_name
>
lookup_linked_permission
(
account_name
authorizer_account
,
scope_name
code_account
,
action_name
type
)
const
;
bool
should_check_for_duplicate_transactions
()
const
{
return
!
(
_skip_flags
&
skip_transaction_dupe_check
);
}
bool
should_check_tapos
()
const
{
return
!
(
_skip_flags
&
skip_tapos_check
);
}
...
...
@@ -413,6 +424,7 @@ namespace eosio { namespace chain {
transaction
_get_on_block_transaction
();
void
_apply_on_block_transaction
();
void
store_deferred_transaction
(
const
deferred_transaction
&
dtrx
);
// producer_schedule_type calculate_next_round( const signed_block& next_block );
...
...
libraries/chain/include/eosio/chain/contracts/eos_contract.hpp
浏览文件 @
331d4218
...
...
@@ -29,6 +29,9 @@ namespace eosio { namespace chain { namespace contracts {
void
apply_eosio_setabi
(
apply_context
&
);
void
apply_eosio_onerror
(
apply_context
&
);
void
apply_eosio_canceldelay
(
apply_context
&
);
void
apply_eosio_mindelay
(
apply_context
&
);
///@} end action handlers
}
}
}
/// namespace eosio::contracts
libraries/chain/include/eosio/chain/contracts/types.hpp
浏览文件 @
331d4218
...
...
@@ -150,6 +150,7 @@ struct updateauth {
permission_name
permission
;
permission_name
parent
;
authority
data
;
uint32
delay
;
static
account_name
get_account
()
{
return
config
::
system_account_name
;
...
...
@@ -268,6 +269,29 @@ struct vetorecovery {
}
};
struct
canceldelay
{
uint32
sender_id
;
static
account_name
get_account
()
{
return
config
::
system_account_name
;
}
static
action_name
get_name
()
{
return
N
(
canceldelay
);
}
};
struct
mindelay
{
uint32
delay
;
static
account_name
get_account
()
{
return
config
::
system_account_name
;
}
static
action_name
get_name
()
{
return
N
(
mindelay
);
}
};
}
}
}
/// namespace eosio::chain::contracts
...
...
@@ -281,10 +305,12 @@ FC_REFLECT( eosio::chain::contracts::abi_def , (types)(
FC_REFLECT
(
eosio
::
chain
::
contracts
::
newaccount
,
(
creator
)(
name
)(
owner
)(
active
)(
recovery
)
)
FC_REFLECT
(
eosio
::
chain
::
contracts
::
setcode
,
(
account
)(
vmtype
)(
vmversion
)(
code
)
)
//abi
FC_REFLECT
(
eosio
::
chain
::
contracts
::
setabi
,
(
account
)(
abi
)
)
FC_REFLECT
(
eosio
::
chain
::
contracts
::
updateauth
,
(
account
)(
permission
)(
parent
)(
data
)
)
FC_REFLECT
(
eosio
::
chain
::
contracts
::
updateauth
,
(
account
)(
permission
)(
parent
)(
data
)
(
delay
)
)
FC_REFLECT
(
eosio
::
chain
::
contracts
::
deleteauth
,
(
account
)(
permission
)
)
FC_REFLECT
(
eosio
::
chain
::
contracts
::
linkauth
,
(
account
)(
code
)(
type
)(
requirement
)
)
FC_REFLECT
(
eosio
::
chain
::
contracts
::
unlinkauth
,
(
account
)(
code
)(
type
)
)
FC_REFLECT
(
eosio
::
chain
::
contracts
::
postrecovery
,
(
account
)(
data
)(
memo
)
)
FC_REFLECT
(
eosio
::
chain
::
contracts
::
passrecovery
,
(
account
)
)
FC_REFLECT
(
eosio
::
chain
::
contracts
::
vetorecovery
,
(
account
)
)
FC_REFLECT
(
eosio
::
chain
::
contracts
::
canceldelay
,
(
sender_id
)
)
FC_REFLECT
(
eosio
::
chain
::
contracts
::
mindelay
,
(
delay
)
)
libraries/chain/include/eosio/chain/permission_object.hpp
浏览文件 @
331d4218
...
...
@@ -17,36 +17,45 @@ namespace eosio { namespace chain {
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
time_point
delay
;
///< delay associated with this permission
/**
* @brief Checks if this permission is equivalent or greater than other
* @tparam Index The permission_index
* @return True if this permission matches, or is a parent of, other; false otherwise
* @return a time_point set to the maximum delay encountered between this and the permission that is other;
* empty optional otherwise
*
* Permissions are organized hierarchically such that a parent permission is strictly more powerful than its
* children/grandchildren. This method checks whether this permission is of greater or equal power (capable of
* satisfying) permission @ref other. This would be the case if this permission matches, or is some parent of,
* other.
* satisfying) permission @ref other. The returned value is an optional<time_point> that will indicate the
* maximum delay encountered walking the hierarchy between this permission and other, if other satisfies this,
* otherwise an empty optional is returned.
*/
template
<
typename
Index
>
bool
satisfies
(
const
permission_object
&
other
,
const
Index
&
permission_index
)
const
{
optional
<
time_point
>
satisfies
(
const
permission_object
&
other
,
const
Index
&
permission_index
)
const
{
// If the owners are not the same, this permission cannot satisfy other
if
(
owner
!=
other
.
owner
)
return
false
;
return
optional
<
time_point
>
();
// if other satisfies this permission, then other's delay and this delay will have to contribute
auto
max_delay
=
other
.
delay
>
delay
?
other
.
delay
:
delay
;
// If this permission matches other, or is the immediate parent of other, then this permission satisfies other
if
(
id
==
other
.
id
||
id
==
other
.
parent
)
return
true
;
return
optional
<
time_point
>
(
max_delay
)
;
// Walk up other's parent tree, seeing if we find this permission. If so, this permission satisfies other
const
permission_object
*
parent
=
&*
permission_index
.
template
get
<
by_id
>().
find
(
other
.
parent
);
while
(
parent
)
{
if
(
max_delay
<
parent
->
delay
)
max_delay
=
parent
->
delay
;
if
(
id
==
parent
->
parent
)
return
true
;
return
optional
<
time_point
>
(
max_delay
)
;
if
(
parent
->
parent
.
_id
==
0
)
return
false
;
return
optional
<
time_point
>
()
;
parent
=
&*
permission_index
.
template
get
<
by_id
>().
find
(
parent
->
parent
);
}
// This permission is not a parent of other, and so does not satisfy other
return
false
;
return
optional
<
time_point
>
()
;
}
};
...
...
@@ -108,7 +117,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
))
FC_REFLECT
(
eosio
::
chain
::
permission_object
,
(
id
)(
owner
)(
parent
)(
name
)(
auth
)
(
last_updated
)(
delay
)
)
FC_REFLECT
(
chainbase
::
oid
<
eosio
::
chain
::
permission_usage_object
>
,
(
_id
))
FC_REFLECT
(
eosio
::
chain
::
permission_usage_object
,
(
id
)(
account
)(
permission
)(
last_used
))
libraries/chain/include/eosio/chain/transaction.hpp
浏览文件 @
331d4218
...
...
@@ -82,7 +82,8 @@ namespace eosio { namespace chain {
enum
status_enum
{
executed
=
0
,
///< succeed, no error handler executed
soft_fail
=
1
,
///< objectively failed (not executed), error handler executed
hard_fail
=
2
///< objectively failed and error handler objectively failed thus no state change
hard_fail
=
2
,
///< objectively failed and error handler objectively failed thus no state change
delayed
=
3
///< transaction delayed
};
transaction_receipt
()
:
status
(
hard_fail
)
{}
...
...
@@ -216,6 +217,15 @@ namespace eosio { namespace chain {
uint64_t
sender_id
;
/// ID assigned by sender of generated, accessible via WASM api when executing normal or error
account_name
sender
;
/// receives error handler callback
time_point_sec
execute_after
;
/// delayed exeuction
deferred_transaction
()
=
default
;
deferred_transaction
(
uint32_t
sender_id
,
account_name
sender
,
time_point_sec
execute_after
,
const
transaction
&
txn
)
:
transaction
(
txn
),
sender_id
(
sender_id
),
sender
(
sender
),
execute_after
(
execute_after
)
{}
};
struct
deferred_reference
{
...
...
@@ -270,7 +280,7 @@ FC_REFLECT_ENUM( eosio::chain::data_access_info::access_type, (read)(write))
FC_REFLECT
(
eosio
::
chain
::
data_access_info
,
(
type
)(
code
)(
scope
)(
sequence
))
FC_REFLECT
(
eosio
::
chain
::
action_trace
,
(
receiver
)(
act
)(
console
)(
region_id
)(
cycle_index
)(
data_access
)
)
FC_REFLECT
(
eosio
::
chain
::
transaction_receipt
,
(
status
)(
id
))
FC_REFLECT_ENUM
(
eosio
::
chain
::
transaction_receipt
::
status_enum
,
(
executed
)(
soft_fail
)(
hard_fail
))
FC_REFLECT_ENUM
(
eosio
::
chain
::
transaction_receipt
::
status_enum
,
(
executed
)(
soft_fail
)(
hard_fail
)
(
delayed
)
)
FC_REFLECT_DERIVED
(
eosio
::
chain
::
transaction_trace
,
(
eosio
::
chain
::
transaction_receipt
),
(
action_traces
)(
deferred_transaction_requests
)
)
...
...
libraries/fc/include/fc/time.hpp
浏览文件 @
331d4218
...
...
@@ -62,6 +62,7 @@ namespace fc {
time_point
&
operator
+=
(
const
microseconds
&
m
)
{
elapsed
+=
m
;
return
*
this
;
}
time_point
&
operator
-=
(
const
microseconds
&
m
)
{
elapsed
-=
m
;
return
*
this
;
}
time_point
operator
+
(
const
microseconds
&
m
)
const
{
return
time_point
(
elapsed
+
m
);
}
time_point
operator
+
(
const
time_point
&
m
)
const
{
return
time_point
(
elapsed
+
m
.
elapsed
);
}
time_point
operator
-
(
const
microseconds
&
m
)
const
{
return
time_point
(
elapsed
-
m
);
}
microseconds
operator
-
(
const
time_point
&
m
)
const
{
return
microseconds
(
elapsed
.
count
()
-
m
.
elapsed
.
count
());
}
private:
...
...
@@ -102,8 +103,10 @@ namespace fc {
friend
bool
operator
!=
(
const
time_point_sec
&
a
,
const
time_point_sec
&
b
)
{
return
a
.
utc_seconds
!=
b
.
utc_seconds
;
}
time_point_sec
&
operator
+=
(
uint32_t
m
)
{
utc_seconds
+=
m
;
return
*
this
;
}
time_point_sec
&
operator
+=
(
microseconds
m
)
{
utc_seconds
+=
m
.
to_seconds
();
return
*
this
;
}
time_point_sec
&
operator
+=
(
time_point_sec
m
)
{
utc_seconds
+=
m
.
utc_seconds
;
return
*
this
;
}
time_point_sec
&
operator
-=
(
uint32_t
m
)
{
utc_seconds
-=
m
;
return
*
this
;
}
time_point_sec
&
operator
-=
(
microseconds
m
)
{
utc_seconds
-=
m
.
to_seconds
();
return
*
this
;
}
time_point_sec
&
operator
-=
(
time_point_sec
m
)
{
utc_seconds
-=
m
.
utc_seconds
;
return
*
this
;
}
time_point_sec
operator
+
(
uint32_t
offset
)
const
{
return
time_point_sec
(
utc_seconds
+
offset
);
}
time_point_sec
operator
-
(
uint32_t
offset
)
const
{
return
time_point_sec
(
utc_seconds
-
offset
);
}
...
...
libraries/testing/include/eosio/testing/tester.hpp
浏览文件 @
331d4218
...
...
@@ -64,6 +64,8 @@ namespace eosio { namespace testing {
public:
typedef
string
action_result
;
static
const
uint32_t
DEFAULT_EXPIRATION_DELTA
=
6
;
base_tester
(
chain_controller
::
runtime_limits
limits
=
chain_controller
::
runtime_limits
());
explicit
base_tester
(
chain_controller
::
controller_config
config
);
...
...
@@ -78,10 +80,10 @@ namespace eosio { namespace testing {
transaction_trace
push_transaction
(
signed_transaction
&
trx
,
uint32_t
skip_flag
=
skip_nothing
);
action_result
push_action
(
action
&&
cert_act
,
uint64_t
authorizer
);
transaction_trace
push_action
(
const
account_name
&
code
,
const
action_name
&
act
,
const
account_name
&
signer
,
const
variant_object
&
data
);
transaction_trace
push_action
(
const
account_name
&
code
,
const
action_name
&
act
type
,
const
account_name
&
actor
,
const
variant_object
&
data
,
uint32_t
expiration
=
DEFAULT_EXPIRATION_DELTA
);
transaction_trace
push_action
(
const
account_name
&
code
,
const
action_name
&
acttype
,
const
vector
<
account_name
>&
actors
,
const
variant_object
&
data
,
uint32_t
expiration
=
DEFAULT_EXPIRATION_DELTA
);
void
set_tapos
(
signed_transaction
&
trx
)
const
;
void
set_tapos
(
signed_transaction
&
trx
,
uint32_t
expiration
=
DEFAULT_EXPIRATION_DELTA
)
const
;
void
create_accounts
(
vector
<
account_name
>
names
,
bool
multisig
=
false
)
{
for
(
auto
n
:
names
)
create_account
(
n
,
config
::
system_account_name
,
multisig
);
...
...
libraries/testing/tester.cpp
浏览文件 @
331d4218
...
...
@@ -106,8 +106,8 @@ namespace eosio { namespace testing {
}
}
void
base_tester
::
set_tapos
(
signed_transaction
&
trx
)
const
{
trx
.
expiration
=
control
->
head_block_time
()
+
fc
::
seconds
(
6
);
void
base_tester
::
set_tapos
(
signed_transaction
&
trx
,
uint32_t
expiration
)
const
{
trx
.
expiration
=
control
->
head_block_time
()
+
fc
::
seconds
(
expiration
);
trx
.
set_reference_block
(
control
->
head_block_id
()
);
}
...
...
@@ -169,7 +169,18 @@ namespace eosio { namespace testing {
transaction_trace
base_tester
::
push_action
(
const
account_name
&
code
,
const
action_name
&
acttype
,
const
account_name
&
actor
,
const
variant_object
&
data
)
const
variant_object
&
data
,
uint32_t
expiration
)
{
try
{
return
push_action
(
code
,
acttype
,
vector
<
account_name
>
{
actor
},
data
,
expiration
);
}
FC_CAPTURE_AND_RETHROW
(
(
code
)(
acttype
)(
actor
)(
data
)(
expiration
)
)
}
transaction_trace
base_tester
::
push_action
(
const
account_name
&
code
,
const
action_name
&
acttype
,
const
vector
<
account_name
>&
actors
,
const
variant_object
&
data
,
uint32_t
expiration
)
{
try
{
const
auto
&
acnt
=
control
->
get_database
().
get
<
account_object
,
by_name
>
(
code
);
...
...
@@ -184,16 +195,20 @@ namespace eosio { namespace testing {
action
act
;
act
.
account
=
code
;
act
.
name
=
acttype
;
act
.
authorization
=
vector
<
permission_level
>
{{
actor
,
config
::
active_name
}};
for
(
const
auto
&
actor
:
actors
)
{
act
.
authorization
.
push_back
(
permission_level
{
actor
,
config
::
active_name
});
}
act
.
data
=
abis
.
variant_to_binary
(
action_type_name
,
data
);
signed_transaction
trx
;
trx
.
actions
.
emplace_back
(
std
::
move
(
act
));
set_tapos
(
trx
);
set_tapos
(
trx
,
expiration
);
for
(
const
auto
&
actor
:
actors
)
{
trx
.
sign
(
get_private_key
(
actor
,
"active"
),
chain_id_type
());
}
return
push_transaction
(
trx
);
}
FC_CAPTURE_AND_RETHROW
(
(
code
)(
acttype
)(
actor
)(
data
)
)
}
}
FC_CAPTURE_AND_RETHROW
(
(
code
)(
acttype
)(
actor
s
)(
data
)(
expiration
)
)
}
transaction_trace
base_tester
::
push_reqauth
(
account_name
from
,
const
vector
<
permission_level
>&
auths
,
const
vector
<
private_key_type
>&
keys
)
{
variant
pretty_trx
=
fc
::
mutable_variant_object
()
...
...
plugins/net_plugin/net_plugin.cpp
浏览文件 @
331d4218
...
...
@@ -2253,7 +2253,11 @@ namespace eosio {
}
}
break
;
}}
}
case
transaction_receipt
::
delayed
:
#warning TODO: Not sure what should happen here
break
;
}
}
}
}
...
...
tests/chain_tests/block_tests.cpp
浏览文件 @
331d4218
...
...
@@ -225,12 +225,14 @@ BOOST_AUTO_TEST_CASE(order_dependent_transactions)
(
"account"
,
"tester"
)
(
"permission"
,
"first"
)
(
"parent"
,
"active"
)
(
"data"
,
authority
(
chain
.
get_public_key
(
name
(
"tester"
),
"first"
))));
(
"data"
,
authority
(
chain
.
get_public_key
(
name
(
"tester"
),
"first"
)))
(
"delay"
,
0
));
chain
.
push_action
(
name
(
"eosio"
),
name
(
"updateauth"
),
name
(
"tester"
),
fc
::
mutable_variant_object
()
(
"account"
,
"tester"
)
(
"permission"
,
"second"
)
(
"parent"
,
"first"
)
(
"data"
,
authority
(
chain
.
get_public_key
(
name
(
"tester"
),
"second"
))));
(
"data"
,
authority
(
chain
.
get_public_key
(
name
(
"tester"
),
"second"
)))
(
"delay"
,
0
));
// Ensure the related auths are created
const
auto
*
first_auth
=
chain
.
find
<
permission_object
,
by_owner
>
(
boost
::
make_tuple
(
name
(
"tester"
),
name
(
"first"
)));
...
...
tests/chain_tests/delay_tests.cpp
0 → 100644
浏览文件 @
331d4218
此差异已折叠。
点击以展开。
tests/tests/abi_tests.cpp
浏览文件 @
331d4218
...
...
@@ -1937,7 +1937,8 @@ BOOST_AUTO_TEST_CASE(updateauth)
{"key" : "EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf", "weight" : 57605} ],
"accounts" : [ {"permission" : {"actor" : "prm.acct1", "permission" : "prm.prm1"}, "weight" : 53005 },
{"permission" : {"actor" : "prm.acct2", "permission" : "prm.prm2"}, "weight" : 53405 }]
}
},
"delay" : 0
}
)====="
;
...
...
tests/tests/misc_tests.cpp
浏览文件 @
331d4218
...
...
@@ -110,6 +110,13 @@ BOOST_AUTO_TEST_CASE(deterministic_distributions)
BOOST_TEST
(
std
::
equal
(
nums
.
begin
(),
nums
.
end
(),
c
.
begin
()));
}
FC_LOG_AND_RETHROW
()
}
struct
permission_visitor
{
std
::
vector
<
permission_level
>
permissions
;
void
operator
()(
const
permission_level
&
permission
)
{
permissions
.
push_back
(
permission
);
}
};
BOOST_AUTO_TEST_CASE
(
authority_checker
)
{
try
{
testing
::
tester
test
;
...
...
@@ -119,23 +126,24 @@ BOOST_AUTO_TEST_CASE(authority_checker)
auto
GetNullAuthority
=
[](
auto
){
abort
();
return
authority
();};
permission_visitor
pv
;
auto
A
=
authority
(
2
,
{
key_weight
{
a
,
1
},
key_weight
{
b
,
1
}});
{
auto
checker
=
make_auth_checker
(
GetNullAuthority
,
2
,
{
a
,
b
});
auto
checker
=
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
a
,
b
});
BOOST_TEST
(
checker
.
satisfied
(
A
));
BOOST_TEST
(
checker
.
all_keys_used
());
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
2
);
BOOST_TEST
(
checker
.
unused_keys
().
size
()
==
0
);
}
{
auto
checker
=
make_auth_checker
(
GetNullAuthority
,
2
,
{
a
,
c
});
auto
checker
=
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
a
,
c
});
BOOST_TEST
(
!
checker
.
satisfied
(
A
));
BOOST_TEST
(
!
checker
.
all_keys_used
());
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
0
);
BOOST_TEST
(
checker
.
unused_keys
().
size
()
==
2
);
}
{
auto
checker
=
make_auth_checker
(
GetNullAuthority
,
2
,
{
a
,
b
,
c
});
auto
checker
=
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
a
,
b
,
c
});
BOOST_TEST
(
checker
.
satisfied
(
A
));
BOOST_TEST
(
!
checker
.
all_keys_used
());
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
2
);
...
...
@@ -145,27 +153,27 @@ BOOST_AUTO_TEST_CASE(authority_checker)
BOOST_TEST
(
checker
.
unused_keys
().
count
(
c
)
==
1
);
}
{
auto
checker
=
make_auth_checker
(
GetNullAuthority
,
2
,
{
b
,
c
});
auto
checker
=
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
b
,
c
});
BOOST_TEST
(
!
checker
.
satisfied
(
A
));
BOOST_TEST
(
!
checker
.
all_keys_used
());
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
0
);
}
A
=
authority
(
3
,
{
key_weight
{
a
,
1
},
key_weight
{
b
,
1
},
key_weight
{
c
,
1
}});
BOOST_TEST
(
make_auth_checker
(
GetNullAuthority
,
2
,
{
c
,
b
,
a
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetNullAuthority
,
2
,
{
a
,
b
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetNullAuthority
,
2
,
{
a
,
c
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetNullAuthority
,
2
,
{
b
,
c
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
c
,
b
,
a
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
a
,
b
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
a
,
c
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
b
,
c
}).
satisfied
(
A
));
A
=
authority
(
1
,
{
key_weight
{
a
,
1
},
key_weight
{
b
,
1
}});
BOOST_TEST
(
make_auth_checker
(
GetNullAuthority
,
2
,
{
a
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetNullAuthority
,
2
,
{
b
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetNullAuthority
,
2
,
{
c
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
a
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
b
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
c
}).
satisfied
(
A
));
A
=
authority
(
1
,
{
key_weight
{
a
,
2
},
key_weight
{
b
,
1
}});
BOOST_TEST
(
make_auth_checker
(
GetNullAuthority
,
2
,
{
a
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetNullAuthority
,
2
,
{
b
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetNullAuthority
,
2
,
{
c
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
a
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
b
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
c
}).
satisfied
(
A
));
auto
GetCAuthority
=
[
c
](
auto
){
return
authority
(
1
,
{
key_weight
{
c
,
1
}});
...
...
@@ -173,26 +181,26 @@ BOOST_AUTO_TEST_CASE(authority_checker)
A
=
authority
(
2
,
{
key_weight
{
a
,
2
},
key_weight
{
b
,
1
}},
{
permission_level_weight
{{
"hello"
,
"world"
},
1
}});
{
auto
checker
=
make_auth_checker
(
GetCAuthority
,
2
,
{
a
});
auto
checker
=
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
a
});
BOOST_TEST
(
checker
.
satisfied
(
A
));
BOOST_TEST
(
checker
.
all_keys_used
());
}
{
auto
checker
=
make_auth_checker
(
GetCAuthority
,
2
,
{
b
});
auto
checker
=
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
b
});
BOOST_TEST
(
!
checker
.
satisfied
(
A
));
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
0
);
BOOST_TEST
(
checker
.
unused_keys
().
size
()
==
1
);
BOOST_TEST
(
checker
.
unused_keys
().
count
(
b
)
==
1
);
}
{
auto
checker
=
make_auth_checker
(
GetCAuthority
,
2
,
{
c
});
auto
checker
=
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
c
});
BOOST_TEST
(
!
checker
.
satisfied
(
A
));
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
0
);
BOOST_TEST
(
checker
.
unused_keys
().
size
()
==
1
);
BOOST_TEST
(
checker
.
unused_keys
().
count
(
c
)
==
1
);
}
{
auto
checker
=
make_auth_checker
(
GetCAuthority
,
2
,
{
b
,
c
});
auto
checker
=
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
b
,
c
});
BOOST_TEST
(
checker
.
satisfied
(
A
));
BOOST_TEST
(
checker
.
all_keys_used
());
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
2
);
...
...
@@ -201,7 +209,7 @@ BOOST_AUTO_TEST_CASE(authority_checker)
BOOST_TEST
(
checker
.
used_keys
().
count
(
c
)
==
1
);
}
{
auto
checker
=
make_auth_checker
(
GetCAuthority
,
2
,
{
b
,
c
,
a
});
auto
checker
=
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
b
,
c
,
a
});
BOOST_TEST
(
checker
.
satisfied
(
A
));
BOOST_TEST
(
!
checker
.
all_keys_used
());
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
1
);
...
...
@@ -212,14 +220,14 @@ BOOST_AUTO_TEST_CASE(authority_checker)
}
A
=
authority
(
2
,
{
key_weight
{
a
,
1
},
key_weight
{
b
,
1
}},
{
permission_level_weight
{{
"hello"
,
"world"
},
1
}});
BOOST_TEST
(
!
make_auth_checker
(
GetCAuthority
,
2
,
{
a
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetCAuthority
,
2
,
{
b
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetCAuthority
,
2
,
{
c
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetCAuthority
,
2
,
{
a
,
b
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetCAuthority
,
2
,
{
b
,
c
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetCAuthority
,
2
,
{
a
,
c
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
a
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
b
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
c
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
a
,
b
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
b
,
c
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
a
,
c
}).
satisfied
(
A
));
{
auto
checker
=
make_auth_checker
(
GetCAuthority
,
2
,
{
a
,
b
,
c
});
auto
checker
=
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
a
,
b
,
c
});
BOOST_TEST
(
checker
.
satisfied
(
A
));
BOOST_TEST
(
!
checker
.
all_keys_used
());
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
2
);
...
...
@@ -228,12 +236,12 @@ BOOST_AUTO_TEST_CASE(authority_checker)
}
A
=
authority
(
2
,
{
key_weight
{
a
,
1
},
key_weight
{
b
,
1
}},
{
permission_level_weight
{{
"hello"
,
"world"
},
2
}});
BOOST_TEST
(
make_auth_checker
(
GetCAuthority
,
2
,
{
a
,
b
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetCAuthority
,
2
,
{
c
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetCAuthority
,
2
,
{
a
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetCAuthority
,
2
,
{
b
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
a
,
b
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
c
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
a
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
b
}).
satisfied
(
A
));
{
auto
checker
=
make_auth_checker
(
GetCAuthority
,
2
,
{
a
,
b
,
c
});
auto
checker
=
make_auth_checker
(
GetCAuthority
,
pv
,
2
,
{
a
,
b
,
c
});
BOOST_TEST
(
checker
.
satisfied
(
A
));
BOOST_TEST
(
!
checker
.
all_keys_used
());
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
1
);
...
...
@@ -252,12 +260,12 @@ BOOST_AUTO_TEST_CASE(authority_checker)
A
=
authority
(
5
,
{
key_weight
{
a
,
2
},
key_weight
{
b
,
2
},
key_weight
{
c
,
2
}},
{
permission_level_weight
{{
"top"
,
"top"
},
5
}});
{
auto
checker
=
make_auth_checker
(
GetAuthority
,
2
,
{
d
,
e
});
auto
checker
=
make_auth_checker
(
GetAuthority
,
pv
,
2
,
{
d
,
e
});
BOOST_TEST
(
checker
.
satisfied
(
A
));
BOOST_TEST
(
checker
.
all_keys_used
());
}
{
auto
checker
=
make_auth_checker
(
GetAuthority
,
2
,
{
a
,
b
,
c
,
d
,
e
});
auto
checker
=
make_auth_checker
(
GetAuthority
,
pv
,
2
,
{
a
,
b
,
c
,
d
,
e
});
BOOST_TEST
(
checker
.
satisfied
(
A
));
BOOST_TEST
(
!
checker
.
all_keys_used
());
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
2
);
...
...
@@ -266,7 +274,7 @@ BOOST_AUTO_TEST_CASE(authority_checker)
BOOST_TEST
(
checker
.
used_keys
().
count
(
e
)
==
1
);
}
{
auto
checker
=
make_auth_checker
(
GetAuthority
,
2
,
{
a
,
b
,
c
,
e
});
auto
checker
=
make_auth_checker
(
GetAuthority
,
pv
,
2
,
{
a
,
b
,
c
,
e
});
BOOST_TEST
(
checker
.
satisfied
(
A
));
BOOST_TEST
(
!
checker
.
all_keys_used
());
BOOST_TEST
(
checker
.
used_keys
().
size
()
==
3
);
...
...
@@ -275,14 +283,14 @@ BOOST_AUTO_TEST_CASE(authority_checker)
BOOST_TEST
(
checker
.
used_keys
().
count
(
b
)
==
1
);
BOOST_TEST
(
checker
.
used_keys
().
count
(
c
)
==
1
);
}
BOOST_TEST
(
make_auth_checker
(
GetAuthority
,
1
,
{
a
,
b
,
c
}).
satisfied
(
A
));
BOOST_TEST
(
make_auth_checker
(
GetAuthority
,
pv
,
1
,
{
a
,
b
,
c
}).
satisfied
(
A
));
// Fails due to short recursion depth limit
BOOST_TEST
(
!
make_auth_checker
(
GetAuthority
,
1
,
{
d
,
e
}).
satisfied
(
A
));
BOOST_TEST
(
!
make_auth_checker
(
GetAuthority
,
pv
,
1
,
{
d
,
e
}).
satisfied
(
A
));
A
=
authority
(
2
,
{
key_weight
{
c
,
1
},
key_weight
{
b
,
1
},
key_weight
{
a
,
1
}});
auto
B
=
authority
(
1
,
{
key_weight
{
c
,
1
},
key_weight
{
b
,
1
}});
{
auto
checker
=
make_auth_checker
(
GetNullAuthority
,
2
,
{
a
,
b
,
c
});
auto
checker
=
make_auth_checker
(
GetNullAuthority
,
pv
,
2
,
{
a
,
b
,
c
});
BOOST_TEST
(
validate
(
A
));
BOOST_TEST
(
validate
(
B
));
BOOST_TEST
(
checker
.
satisfied
(
A
));
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录