Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
YottaChain
YTBP
提交
53d20fc3
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,发现更多精彩内容 >>
提交
53d20fc3
编写于
11月 21, 2017
作者:
B
Bart Wyatt
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'feature/restore-abi-transaction-serialization' into eos-noon
上级
3ea85fee
06709516
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
419 addition
and
13 deletion
+419
-13
contracts/asserter/asserter.abi
contracts/asserter/asserter.abi
+13
-8
libraries/chain/contracts/chain_initializer.cpp
libraries/chain/contracts/chain_initializer.cpp
+1
-1
libraries/chain/include/eosio/chain/contracts/abi_serializer.hpp
...es/chain/include/eosio/chain/contracts/abi_serializer.hpp
+276
-0
libraries/chain/include/eosio/chain/contracts/types.hpp
libraries/chain/include/eosio/chain/contracts/types.hpp
+2
-0
libraries/testing/include/eosio/testing/tester.hpp
libraries/testing/include/eosio/testing/tester.hpp
+1
-0
libraries/testing/tester.cpp
libraries/testing/tester.cpp
+16
-0
plugins/chain_plugin/chain_plugin.cpp
plugins/chain_plugin/chain_plugin.cpp
+16
-3
tests/CMakeLists.txt
tests/CMakeLists.txt
+1
-1
tests/wasm_tests/wasm_tests.cpp
tests/wasm_tests/wasm_tests.cpp
+93
-0
未找到文件。
contracts/asserter/asserter.abi
浏览文件 @
53d20fc3
...
...
@@ -4,22 +4,27 @@
{
"name": "assertdef",
"base": "",
"fields": {
"condition": "int8",
"message": "string"
}
"fields": [
{
"name": "condition",
"type": "int8"
},{
"name": "message",
"type": "string"
}
]
}, {
"name": "nothing",
"base": "",
"fields":
{}
"fields":
[]
}
],
"actions": [
{
"
action
": "procassert",
"type": "assert
_
def"
"
name
": "procassert",
"type": "assertdef"
}, {
"
action
": "provereset",
"
name
": "provereset",
"type": "nothing"
}
],
...
...
libraries/chain/contracts/chain_initializer.cpp
浏览文件 @
53d20fc3
...
...
@@ -210,7 +210,7 @@ std::vector<action> chain_initializer::prepare_database( chain_controller& chain
a
.
creation_date
=
genesis
.
initial_timestamp
;
if
(
name
==
config
::
system_account_name
)
{
//
a.set_abi(eos_contract_abi());
a
.
set_abi
(
eos_contract_abi
());
}
});
const
auto
&
owner
=
db
.
create
<
permission_object
>
([
&
name
](
permission_object
&
p
)
{
...
...
libraries/chain/include/eosio/chain/contracts/abi_serializer.hpp
浏览文件 @
53d20fc3
...
...
@@ -4,6 +4,9 @@
*/
#pragma once
#include <eosio/chain/contracts/types.hpp>
#include <eosio/chain/transaction.hpp>
#include <fc/variant_object.hpp>
namespace
eosio
{
namespace
chain
{
namespace
contracts
{
...
...
@@ -11,6 +14,7 @@ using std::map;
using
std
::
string
;
using
std
::
function
;
using
std
::
pair
;
using
namespace
fc
;
/**
* Describes the binary representation message and table contents so that it can
...
...
@@ -53,6 +57,12 @@ struct abi_serializer {
fc
::
variant
binary_to_variant
(
const
type_name
&
type
,
fc
::
datastream
<
const
char
*>&
binary
)
const
;
void
variant_to_binary
(
const
type_name
&
type
,
const
fc
::
variant
&
var
,
fc
::
datastream
<
char
*>&
ds
)
const
;
template
<
typename
T
,
typename
Resolver
>
static
void
to_variant
(
const
T
&
o
,
fc
::
variant
&
vo
,
Resolver
resolver
);
template
<
typename
T
,
typename
Resolver
>
static
void
from_variant
(
const
fc
::
variant
&
v
,
T
&
o
,
Resolver
resolver
);
template
<
typename
Vec
>
static
bool
is_empty_abi
(
const
Vec
&
abi_vec
)
{
...
...
@@ -74,4 +84,270 @@ struct abi_serializer {
void
binary_to_variant
(
const
type_name
&
type
,
fc
::
datastream
<
const
char
*>&
stream
,
fc
::
mutable_variant_object
&
obj
)
const
;
};
namespace
impl
{
/**
* Determine if a type contains ABI related info, perhaps deeply nested
* @tparam T - the type to check
*/
template
<
typename
T
>
constexpr
bool
single_type_requires_abi_v
=
std
::
is_base_of
<
transaction
,
T
>::
value
||
std
::
is_same
<
T
,
action
>::
value
;
/**
* Basic constexpr for a type, aliases the basic check directly
* @tparam T - the type to check
*/
template
<
typename
T
>
constexpr
bool
type_requires_abi_v
=
single_type_requires_abi_v
<
T
>
;
/**
* specialization that catches common container patterns and checks their contained-type
* @tparam Container - a templated container type whose first argument is the contained type
*/
template
<
template
<
typename
...
>
class
Container
,
typename
T
,
typename
...
Args
>
constexpr
bool
type_requires_abi_v
<
Container
<
T
,
Args
...
>>
=
single_type_requires_abi_v
<
T
>
;
/**
* convenience aliases for creating overload-guards based on whether the type contains ABI related info
*/
template
<
typename
T
>
using
not_require_abi_t
=
std
::
enable_if_t
<!
type_requires_abi_v
<
T
>
,
int
>
;
template
<
typename
T
>
using
require_abi_t
=
std
::
enable_if_t
<
type_requires_abi_v
<
T
>
,
int
>
;
/**
* Reflection visitor that uses a resolver to resolve ABIs for nested types
* this will degrade to the common fc::to_variant as soon as the type no longer contains
* ABI related info
*
* @tparam Reslover - callable with the signature (const name& code_account) -> optional<abi_def>
*/
template
<
typename
T
,
typename
Resolver
>
class
abi_to_variant_visitor
{
public:
abi_to_variant_visitor
(
mutable_variant_object
&
_mvo
,
const
T
&
_val
,
Resolver
_resolver
)
:
_vo
(
_mvo
)
,
_val
(
_val
)
,
_resolver
(
_resolver
)
{}
/**
* Visit a single member and add it to the variant object
* @tparam Member - the member to visit
* @tparam Class - the class we are traversing
* @tparam member - pointer to the member
* @param name - the name of the member
*/
template
<
typename
Member
,
class
Class
,
Member
(
Class
::*
member
)
>
void
operator
()(
const
char
*
name
)
const
{
this
->
add
(
_vo
,
name
,(
_val
.
*
member
));
}
private:
/**
* template which overloads add for types which are not relvant to ABI information
* and can be degraded to the normal ::to_variant(...) processing
*/
template
<
typename
M
,
not_require_abi_t
<
M
>
=
1
>
void
add
(
mutable_variant_object
&
vo
,
const
char
*
name
,
const
M
&
v
)
const
{
vo
(
name
,
v
);
}
/**
* template which overloads add for types which contain ABI information in their trees
* for these types we create new ABI aware visitors
*/
template
<
typename
M
,
require_abi_t
<
M
>
=
1
>
void
add
(
mutable_variant_object
&
vo
,
const
char
*
name
,
const
M
&
v
)
const
{
mutable_variant_object
mvo
;
fc
::
reflector
<
M
>::
visit
(
impl
::
abi_to_variant_visitor
<
M
,
decltype
(
_resolver
)
>
(
mvo
,
v
,
_resolver
)
);
vo
(
name
,
std
::
move
(
mvo
));
}
/**
* template which overloads add for vectors of types which contain ABI information in their trees
* for these members we call ::add in order to trigger further processing
*/
template
<
typename
M
,
require_abi_t
<
M
>
=
1
>
void
add
(
mutable_variant_object
&
vo
,
const
char
*
name
,
const
vector
<
M
>&
v
)
const
{
vector
<
variant
>
array
(
v
.
size
());
for
(
const
auto
&
iter
:
v
)
{
mutable_variant_object
mvo
;
add
(
mvo
,
"_"
,
iter
);
array
.
emplace_back
(
std
::
move
(
mvo
[
"_"
]));
}
vo
(
name
,
std
::
move
(
array
));
}
/**
* Non templated overload that has priority for the action structure
* this type has members which must be directly translated by the ABI so it is
* exploded and processed explicitly
*/
void
add
(
mutable_variant_object
&
vo
,
const
char
*
name
,
const
action
&
v
)
const
{
mutable_variant_object
mvo
;
mvo
(
"scope"
,
v
.
scope
);
mvo
(
"name"
,
v
.
name
);
mvo
(
"authorization"
,
v
.
authorization
);
auto
abi
=
_resolver
(
v
.
scope
);
if
(
abi
.
valid
())
{
auto
type
=
abi
->
get_action_type
(
v
.
name
);
mvo
(
"data"
,
abi
->
binary_to_variant
(
type
,
v
.
data
));
mvo
(
"hex_data"
,
v
.
data
);
}
else
{
mvo
(
"data"
,
v
.
data
);
}
vo
(
name
,
std
::
move
(
mvo
));
}
mutable_variant_object
&
_vo
;
const
T
&
_val
;
Resolver
_resolver
;
};
/**
* Reflection visitor that uses a resolver to resolve ABIs for nested types
* this will degrade to the common fc::from_variant as soon as the type no longer contains
* ABI related info
*
* @tparam Reslover - callable with the signature (const name& code_account) -> optional<abi_def>
*/
template
<
typename
T
,
typename
Resolver
>
class
abi_from_variant_visitor
{
public:
abi_from_variant_visitor
(
const
variant_object
&
_vo
,
T
&
v
,
Resolver
_resolver
)
:
_vo
(
_vo
)
,
_val
(
v
)
,
_resolver
(
_resolver
)
{}
/**
* Visit a single member and extract it from the variant object
* @tparam Member - the member to visit
* @tparam Class - the class we are traversing
* @tparam member - pointer to the member
* @param name - the name of the member
*/
template
<
typename
Member
,
class
Class
,
Member
(
Class
::*
member
)>
void
operator
()(
const
char
*
name
)
const
{
auto
itr
=
_vo
.
find
(
name
);
if
(
itr
!=
_vo
.
end
()
)
extract
(
itr
->
value
(),
_val
.
*
member
);
}
private:
/**
* template which overloads extract for types which are not relvant to ABI information
* and can be degraded to the normal ::from_variant(...) processing
*/
template
<
typename
M
,
not_require_abi_t
<
M
>
=
1
>
void
extract
(
const
variant
&
v
,
M
&
o
)
const
{
from_variant
(
v
,
o
);
}
/**
* template which overloads extract for types which contain ABI information in their trees
* for these types we create new ABI aware visitors
*/
template
<
typename
M
,
require_abi_t
<
M
>
=
1
>
void
extract
(
const
variant
&
v
,
M
&
o
)
const
{
const
variant_object
&
vo
=
v
.
get_object
();
fc
::
reflector
<
M
>::
visit
(
abi_from_variant_visitor
<
M
,
decltype
(
_resolver
)
>
(
vo
,
o
,
_resolver
)
);
}
/**
* template which overloads extract for vectors of types which contain ABI information in their trees
* for these members we call ::extract in order to trigger further processing
*/
template
<
typename
M
,
require_abi_t
<
M
>
=
1
>
void
extract
(
const
variant
&
v
,
vector
<
M
>&
o
)
const
{
const
variants
&
array
=
v
.
get_array
();
o
.
clear
();
o
.
reserve
(
array
.
size
()
);
for
(
auto
itr
=
array
.
begin
();
itr
!=
array
.
end
();
++
itr
)
{
M
o_iter
;
extract
(
*
itr
,
o_iter
);
o
.
emplace_back
(
std
::
move
(
o_iter
));
}
}
/**
* Non templated overload that has priority for the action structure
* this type has members which must be directly translated by the ABI so it is
* exploded and processed explicitly
*/
void
extract
(
const
variant
&
v
,
action
&
act
)
const
{
const
variant_object
&
vo
=
v
.
get_object
();
FC_ASSERT
(
vo
.
contains
(
"scope"
));
FC_ASSERT
(
vo
.
contains
(
"name"
));
from_variant
(
vo
[
"scope"
],
act
.
scope
);
from_variant
(
vo
[
"name"
],
act
.
name
);
if
(
vo
.
contains
(
"authorization"
))
{
from_variant
(
vo
[
"authorization"
],
act
.
authorization
);
}
if
(
vo
.
contains
(
"data"
)
)
{
const
auto
&
data
=
vo
[
"data"
];
if
(
data
.
is_string
()
)
{
from_variant
(
data
,
act
.
data
);
}
else
if
(
data
.
is_object
()
)
{
auto
abi
=
_resolver
(
act
.
scope
);
if
(
abi
.
valid
())
{
auto
type
=
abi
->
get_action_type
(
act
.
name
);
act
.
data
=
std
::
move
(
abi
->
variant_to_binary
(
type
,
data
));
}
}
}
if
(
act
.
data
.
empty
())
{
if
(
vo
.
contains
(
"hex_data"
)
)
{
const
auto
&
data
=
vo
[
"hex_data"
];
if
(
data
.
is_string
()
)
{
from_variant
(
data
,
act
.
data
);
}
}
}
FC_ASSERT
(
!
act
.
data
.
empty
(),
"Failed to deserialize data for ${scope}:${name}"
,
(
"scope"
,
act
.
scope
)(
"name"
,
act
.
name
));
}
const
variant_object
&
_vo
;
T
&
_val
;
Resolver
_resolver
;
};
}
template
<
typename
T
,
typename
Resolver
>
void
abi_serializer
::
to_variant
(
const
T
&
o
,
variant
&
vo
,
Resolver
resolver
)
try
{
mutable_variant_object
mvo
;
fc
::
reflector
<
T
>::
visit
(
impl
::
abi_to_variant_visitor
<
T
,
Resolver
>
(
mvo
,
o
,
resolver
)
);
vo
=
std
::
move
(
mvo
);
}
FC_RETHROW_EXCEPTIONS
(
error
,
"Failed to serialize type"
,
(
"object"
,
o
))
template
<
typename
T
,
typename
Resolver
>
void
abi_serializer
::
from_variant
(
const
variant
&
v
,
T
&
o
,
Resolver
resolver
)
try
{
const
variant_object
&
vo
=
v
.
get_object
();
fc
::
reflector
<
T
>::
visit
(
impl
::
abi_from_variant_visitor
<
T
,
Resolver
>
(
vo
,
o
,
resolver
)
);
}
FC_RETHROW_EXCEPTIONS
(
error
,
"Failed to deserialize variant"
,
(
"variant"
,
v
))
}
}
}
// eosio::chain::contracts
libraries/chain/include/eosio/chain/contracts/types.hpp
浏览文件 @
53d20fc3
...
...
@@ -219,10 +219,12 @@ struct setcode {
};
struct
setabi
{
/*
setabi() = default;
setabi(const account_name& account, const abi_def& abi)
:account(account), abi(abi)
{}
*/
account_name
account
;
abi_def
abi
;
...
...
libraries/testing/include/eosio/testing/tester.hpp
浏览文件 @
53d20fc3
...
...
@@ -46,6 +46,7 @@ namespace eosio { namespace testing {
private_key_type
get_private_key
(
name
keyname
,
string
role
=
"owner"
);
void
set_code
(
account_name
name
,
const
char
*
wast
);
void
set_abi
(
account_name
name
,
const
char
*
abi_json
);
unique_ptr
<
chain_controller
>
control
;
...
...
libraries/testing/tester.cpp
浏览文件 @
53d20fc3
...
...
@@ -3,6 +3,7 @@
#include <eosio/chain/contracts/types.hpp>
#include <fc/utility.hpp>
#include <fc/io/json.hpp>
#include "WAST/WAST.h"
#include "WASM/WASM.h"
...
...
@@ -211,6 +212,21 @@ namespace eosio { namespace testing {
control
->
push_transaction
(
trx
);
}
FC_CAPTURE_AND_RETHROW
(
(
account
)(
wast
)
)
void
tester
::
set_abi
(
account_name
account
,
const
char
*
abi_json
)
{
auto
abi
=
fc
::
json
::
from_string
(
abi_json
).
template
as
<
contracts
::
abi_def
>();
signed_transaction
trx
;
trx
.
write_scope
=
{
config
::
eosio_auth_scope
};
trx
.
actions
.
emplace_back
(
vector
<
permission_level
>
{{
account
,
config
::
active_name
}},
contracts
::
setabi
{
.
account
=
account
,
.
abi
=
abi
});
set_tapos
(
trx
);
trx
.
sign
(
get_private_key
(
account
,
"active"
),
chain_id_type
()
);
control
->
push_transaction
(
trx
);
}
bool
tester
::
chain_has_transaction
(
const
transaction_id_type
&
txid
)
const
{
return
chain_transactions
.
count
(
txid
)
!=
0
;
}
...
...
plugins/chain_plugin/chain_plugin.cpp
浏览文件 @
53d20fc3
...
...
@@ -344,11 +344,24 @@ read_write::push_block_results read_write::push_block(const read_write::push_blo
read_write
::
push_transaction_results
read_write
::
push_transaction
(
const
read_write
::
push_transaction_params
&
params
)
{
signed_transaction
pretty_input
;
from_variant
(
params
,
pretty_input
);
auto
resolver
=
[
&
,
this
](
const
account_name
&
name
)
->
optional
<
abi_serializer
>
{
const
auto
*
accnt
=
db
.
get_database
().
find
<
account_object
,
by_name
>
(
name
);
if
(
accnt
!=
nullptr
)
{
abi_def
abi
;
if
(
abi_serializer
::
to_abi
(
accnt
->
abi
,
abi
))
{
return
abi_serializer
(
abi
);
}
}
return
optional
<
abi_serializer
>
();
};
abi_serializer
::
from_variant
(
params
,
pretty_input
,
resolver
);
db
.
push_transaction
(
pretty_input
,
skip_flags
);
#warning TODO: get transaction results asynchronously
//auto pretty_trx = db.transaction_to_variant( ptrx );
return
read_write
::
push_transaction_results
{
pretty_input
.
id
(),
fc
::
variant_object
()
};
fc
::
variant
pretty_output
;
abi_serializer
::
to_variant
(
pretty_input
,
pretty_output
,
resolver
);
return
read_write
::
push_transaction_results
{
pretty_input
.
id
(),
pretty_output
};
}
read_write
::
push_transactions_results
read_write
::
push_transactions
(
const
read_write
::
push_transactions_params
&
params
)
{
...
...
tests/CMakeLists.txt
浏览文件 @
53d20fc3
...
...
@@ -33,7 +33,7 @@ target_link_libraries( chain_test eosio_testing eosio_chain chainbase eos_utilit
if
(
WASM_TOOLCHAIN
)
target_include_directories
(
chain_test PUBLIC
${
CMAKE_BINARY_DIR
}
/contracts
${
CMAKE_CURRENT_BINARY_DIR
}
/tests/contracts
)
# add_dependencies(chain_test rate_limit_auth
)
add_dependencies
(
chain_test asserter
)
endif
()
...
...
tests/wasm_tests/wasm_tests.cpp
浏览文件 @
53d20fc3
#include <boost/test/unit_test.hpp>
#include <eosio/testing/tester.hpp>
#include <eosio/chain/contracts/abi_serializer.hpp>
#include <asserter/asserter.wast.hpp>
#include <fc/variant_object.hpp>
using
namespace
eosio
;
using
namespace
eosio
::
chain
;
using
namespace
eosio
::
chain
::
contracts
;
using
namespace
eosio
::
testing
;
using
namespace
fc
;
struct
assertdef
{
int8_t
condition
;
...
...
@@ -34,6 +38,41 @@ struct provereset {
FC_REFLECT_EMPTY
(
provereset
);
const
char
*
const
asserter_abi
=
R"EOF(
{
"types": [],
"structs": [
{
"name": "assertdef",
"base": "",
"fields": [
{
"name": "condition",
"type": "int8"
},{
"name": "message",
"type": "string"
}
]
}, {
"name": "nothing",
"base": "",
"fields": []
}
],
"actions": [
{
"name": "procassert",
"type": "assertdef"
}, {
"name": "provereset",
"type": "nothing"
}
],
"tables": []
}
)EOF"
;
BOOST_AUTO_TEST_SUITE
(
wasm_tests
)
/**
...
...
@@ -116,5 +155,59 @@ BOOST_FIXTURE_TEST_CASE( prove_mem_reset, tester ) try {
}
FC_LOG_AND_RETHROW
()
/// prove_mem_reset
/**
* Prove the modifications to global variables are wiped between runs
*/
BOOST_FIXTURE_TEST_CASE
(
abi_from_variant
,
tester
)
try
{
produce_blocks
(
2
);
create_accounts
(
{
N
(
asserter
)}
);
transfer
(
N
(
inita
),
N
(
asserter
),
"10.0000 EOS"
,
"memo"
);
produce_block
();
set_code
(
N
(
asserter
),
asserter_wast
);
set_abi
(
N
(
asserter
),
asserter_abi
);
produce_blocks
(
1
);
auto
resolver
=
[
&
,
this
](
const
account_name
&
name
)
->
optional
<
abi_serializer
>
{
try
{
const
auto
&
accnt
=
this
->
control
->
get_database
().
get
<
account_object
,
by_name
>
(
name
);
abi_def
abi
;
if
(
abi_serializer
::
to_abi
(
accnt
.
abi
,
abi
))
{
return
abi_serializer
(
abi
);
}
return
optional
<
abi_serializer
>
();
}
FC_RETHROW_EXCEPTIONS
(
error
,
"Failed to find or parse ABI for ${name}"
,
(
"name"
,
name
))
};
variant
pretty_trx
=
mutable_variant_object
()
(
"actions"
,
variants
({
mutable_variant_object
()
(
"scope"
,
"asserter"
)
(
"name"
,
"procassert"
)
(
"authorization"
,
variants
({
mutable_variant_object
()
(
"actor"
,
"asserter"
)
(
"permission"
,
name
(
config
::
active_name
).
to_string
())
}))
(
"data"
,
mutable_variant_object
()
(
"condition"
,
1
)
(
"message"
,
"Should Not Assert!"
)
)
})
);
signed_transaction
trx
;
abi_serializer
::
from_variant
(
pretty_trx
,
trx
,
resolver
);
set_tapos
(
trx
);
trx
.
sign
(
get_private_key
(
N
(
asserter
),
"active"
),
chain_id_type
()
);
control
->
push_transaction
(
trx
);
produce_blocks
(
1
);
BOOST_REQUIRE_EQUAL
(
true
,
chain_has_transaction
(
trx
.
id
()));
const
auto
&
receipt
=
get_transaction_receipt
(
trx
.
id
());
BOOST_CHECK_EQUAL
(
transaction_receipt
::
executed
,
receipt
.
status
);
}
FC_LOG_AND_RETHROW
()
/// prove_mem_reset
BOOST_AUTO_TEST_SUITE_END
()
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录