Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
YottaChain
YTBP
提交
0a301c4c
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,发现更多精彩内容 >>
提交
0a301c4c
编写于
7月 13, 2017
作者:
D
Daniel Larimer
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
progress toward testing exchange contract
上级
2890b469
变更
18
隐藏空白更改
内联
并排
Showing
18 changed file
with
604 addition
and
250 deletion
+604
-250
contracts/currency/Makefile
contracts/currency/Makefile
+1
-2
contracts/currency/currency.wast.hpp
contracts/currency/currency.wast.hpp
+0
-1
contracts/eoslib/db.h
contracts/eoslib/db.h
+1
-2
contracts/eoslib/db.hpp
contracts/eoslib/db.hpp
+4
-3
contracts/eoslib/eos.hpp
contracts/eoslib/eos.hpp
+3
-1
contracts/eoslib/math.h
contracts/eoslib/math.h
+2
-1
contracts/eoslib/math.hpp
contracts/eoslib/math.hpp
+58
-0
contracts/eoslib/print.hpp
contracts/eoslib/print.hpp
+41
-0
contracts/eoslib/token.hpp
contracts/eoslib/token.hpp
+8
-6
contracts/exchange/Makefile
contracts/exchange/Makefile
+2
-3
contracts/exchange/exchange.cpp
contracts/exchange/exchange.cpp
+57
-93
contracts/exchange/exchange.hpp
contracts/exchange/exchange.hpp
+1
-1
libraries/chain/chain_controller.cpp
libraries/chain/chain_controller.cpp
+5
-3
libraries/chain/include/eos/chain/message_handling_contexts.hpp
...ies/chain/include/eos/chain/message_handling_contexts.hpp
+18
-6
libraries/chain/message_handling_contexts.cpp
libraries/chain/message_handling_contexts.cpp
+149
-1
libraries/chain/wasm_interface.cpp
libraries/chain/wasm_interface.cpp
+98
-4
libraries/native_contract/system_contract.cpp
libraries/native_contract/system_contract.cpp
+1
-1
tests/slow_tests/slow_tests.cpp
tests/slow_tests/slow_tests.cpp
+155
-122
未找到文件。
contracts/currency/Makefile
浏览文件 @
0a301c4c
...
...
@@ -3,8 +3,7 @@ currency.wast: currency.cpp Makefile ../eoslib/eos.hpp currency.hpp
/Users/dlarimer/Downloads/llvm/build/bin/llc
-asm-verbose
=
false
.currency.bc
/Users/dlarimer/eos/libraries/binaryen/bin/s2wasm
-s
1024 .currency.s
>
currency.wast
wc
-l
currency.wast
echo
'#pragma once '
>
currency.wast.hpp
echo
'const char* currency_wast = R"=====('
>>
currency.wast.hpp
echo
'const char* currency_wast = R"=====('
>
currency.wast.hpp
cat
currency.wast
>>
currency.wast.hpp
echo
')=====";'
>>
currency.wast.hpp
...
...
contracts/currency/currency.wast.hpp
浏览文件 @
0a301c4c
#pragma once
const
char
*
currency_wast
=
R"=====(
(module
(type $FUNCSIG$vj (func (param i64)))
...
...
contracts/eoslib/db.h
浏览文件 @
0a301c4c
...
...
@@ -39,8 +39,7 @@ int32_t back_primary_i128i128( AccountName scope, AccountName code, TableName ta
int32_t
next_primary_i128i128
(
AccountName
scope
,
AccountName
code
,
TableName
table
,
void
*
data
,
uint32_t
len
);
int32_t
previous_primary_i128i128
(
AccountName
scope
,
AccountName
code
,
TableName
table
,
void
*
data
,
uint32_t
len
);
int32_t
load_primary_i128i128
(
AccountName
scope
,
AccountName
code
,
TableName
table
,
const
void
*
primary
,
void
*
data
,
uint32_t
len
);
int32_t
load_primary_i128i128
(
AccountName
scope
,
AccountName
code
,
TableName
table
,
void
*
data
,
uint32_t
len
);
int32_t
upper_bound_primary_i128i128
(
AccountName
scope
,
AccountName
code
,
TableName
table
,
const
void
*
key
,
void
*
data
,
uint32_t
len
);
...
...
contracts/eoslib/db.hpp
浏览文件 @
0a301c4c
...
...
@@ -56,8 +56,8 @@ struct table_impl<sizeof(uint128_t),sizeof(uint128_t)> {
static
bool
remove
(
uint64_t
scope
,
uint64_t
table
,
const
void
*
data
)
{
return
remove_i128i128
(
scope
,
table
,
data
);
}
static
int32_t
load_primary
(
uint64_t
scope
,
uint64_t
code
,
uint64_t
table
,
const
void
*
primary
,
void
*
data
,
uint32_t
len
)
{
return
load_primary_i128i128
(
scope
,
code
,
table
,
primary
,
data
,
len
);
static
int32_t
load_primary
(
uint64_t
scope
,
uint64_t
code
,
uint64_t
table
,
void
*
data
,
uint32_t
len
)
{
return
load_primary_i128i128
(
scope
,
code
,
table
,
data
,
len
);
}
static
int32_t
front_secondary
(
AccountName
scope
,
AccountName
code
,
TableName
table
,
void
*
data
,
uint32_t
len
)
{
return
front_secondary_i128i128
(
scope
,
code
,
table
,
data
,
len
);
...
...
@@ -96,7 +96,8 @@ struct Table {
return
impl
::
previous_primary
(
scope
,
code
,
table
,
&
r
,
sizeof
(
Record
)
)
==
sizeof
(
Record
);
}
static
bool
get
(
const
PrimaryType
&
p
,
Record
&
r
)
{
return
impl
::
load_primary
(
scope
,
code
,
table
,
&
p
,
&
r
,
sizeof
(
Record
)
)
==
sizeof
(
Record
);
*
reinterpret_cast
<
PrimaryType
*>
(
&
r
)
=
p
;
return
impl
::
load_primary
(
scope
,
code
,
table
,
&
r
,
sizeof
(
Record
)
)
==
sizeof
(
Record
);
}
static
bool
lower_bound
(
const
PrimaryType
&
p
,
Record
&
r
)
{
return
impl
::
lower_bound_primary
(
scope
,
code
,
table
,
&
p
&
r
,
sizeof
(
Record
)
)
==
sizeof
(
Record
);
...
...
contracts/eoslib/eos.hpp
浏览文件 @
0a301c4c
...
...
@@ -28,8 +28,10 @@ uint32_t readMessage( void* msg, uint32_t len );
*/
uint32_t
messageSize
();
void
print
(
const
char
*
cstr
);
void
print
s
(
const
char
*
cstr
);
void
printi
(
uint64_t
value
);
void
printi128
(
const
uint128_t
*
value
);
void
printn
(
uint64_t
name
);
/**
* @return the account which specifes the code that is being run
...
...
contracts/eoslib/math.h
浏览文件 @
0a301c4c
#pragma once
extern
"C"
{
void
multeq_i128
(
uint128_t
*
self
,
const
uint128_t
*
other
);
void
diveq_i128
(
uint128_t
*
self
,
const
uint128_t
*
other
);
}
// extern "C"
contracts/eoslib/math.hpp
0 → 100644
浏览文件 @
0a301c4c
#pragma once
#include <eoslib/math.h>
namespace
eos
{
inline
void
multeq
(
uint128_t
&
self
,
const
uint128_t
&
other
)
{
multeq_i128
(
&
self
,
&
other
);
}
inline
void
diveq
(
uint128_t
&
self
,
const
uint128_t
&
other
)
{
diveq_i128
(
&
self
,
&
other
);
}
struct
uint128
{
public:
uint128
(
uint128_t
i
=
0
)
:
value
(
i
){}
uint128
(
uint64_t
i
)
:
value
(
i
){}
uint128
(
uint32_t
i
)
:
value
(
i
){}
friend
uint128
operator
*
(
uint128
a
,
const
uint128
&
b
)
{
return
a
*=
b
;
}
friend
uint128
operator
/
(
uint128
a
,
const
uint128
&
b
)
{
return
a
/=
b
;
}
friend
bool
operator
<=
(
const
uint128
&
a
,
const
uint128
&
b
)
{
return
a
.
value
<=
b
.
value
;
}
friend
bool
operator
>=
(
const
uint128
&
a
,
const
uint128
&
b
)
{
return
a
.
value
>=
b
.
value
;
}
uint128
&
operator
*=
(
const
uint128_t
&
other
)
{
multeq
(
value
,
other
);
return
*
this
;
}
uint128
&
operator
*=
(
const
uint128
&
other
)
{
multeq
(
value
,
other
.
value
);
return
*
this
;
}
uint128
&
operator
/=
(
const
uint128_t
&
other
)
{
diveq
(
value
,
other
);
return
*
this
;
}
uint128
&
operator
/=
(
const
uint128
&
other
)
{
diveq
(
value
,
other
.
value
);
return
*
this
;
}
explicit
operator
uint64_t
()
const
{
assert
(
!
(
value
>>
64
),
"cast to 64 bit loss of precision"
);
return
uint64_t
(
value
);
}
private:
uint128_t
value
;
};
}
contracts/eoslib/print.hpp
0 → 100644
浏览文件 @
0a301c4c
#pragma once
#include <eoslib/eos.hpp>
namespace
eos
{
inline
void
print_native
(
const
char
*
ptr
)
{
prints
(
ptr
);
}
inline
void
print_native
(
uint64_t
num
)
{
printi
(
num
);
}
inline
void
print_native
(
uint32_t
num
)
{
printi
(
num
);
}
inline
void
print_native
(
int
num
)
{
printi
(
num
);
}
inline
void
print_native
(
uint128
num
)
{
printi128
((
uint128_t
*
)
&
num
);
}
inline
void
print_native
(
uint128_t
num
)
{
printi128
((
uint128_t
*
)
&
num
);
}
inline
void
print_native
(
Name
name
)
{
printn
(
name
.
value
);
}
template
<
typename
Arg
>
inline
void
print
(
Arg
a
)
{
print_native
(
a
);
}
template
<
typename
Arg
,
typename
...
Args
>
void
print
(
Arg
a
,
Args
...
args
)
{
print
(
a
);
print
(
args
...);
}
}
contracts/eoslib/token.hpp
浏览文件 @
0a301c4c
#pragma once
#include <eoslib/math.hpp>
namespace
eos
{
template
<
typename
NumberType
,
uint64_t
CurrencyType
=
N
(
eos
)
>
...
...
@@ -55,11 +57,11 @@ namespace eos {
*/
static
const
uint64_t
precision
=
1000ll
*
1000ll
*
1000ll
*
1000ll
*
1000ll
;
price
()
:
base_per_quote
(
1
){}
price
()
:
base_per_quote
(
1
ul
){}
price
(
BaseToken
base
,
QuoteToken
quote
)
{
assert
(
base
>=
BaseToken
(
1
),
"invalid price"
);
assert
(
quote
>=
QuoteToken
(
1
),
"invalid price"
);
assert
(
base
>=
BaseToken
(
1
ul
),
"invalid price"
);
assert
(
quote
>=
QuoteToken
(
1
ul
),
"invalid price"
);
base_per_quote
=
base
.
quantity
;
base_per_quote
*=
precision
;
...
...
@@ -67,7 +69,7 @@ namespace eos {
}
friend
QuoteToken
operator
/
(
BaseToken
b
,
const
price
&
q
)
{
return
QuoteToken
(
uint64_t
((
uint128
_t
(
b
.
quantity
)
*
precision
)
/
q
.
base_per_quote
)
);
return
QuoteToken
(
uint64_t
((
uint128
(
b
.
quantity
)
*
uint128
(
precision
)
)
/
q
.
base_per_quote
)
);
}
friend
BaseToken
operator
*
(
QuoteToken
b
,
const
price
&
q
)
{
...
...
@@ -82,11 +84,11 @@ namespace eos {
friend
bool
operator
==
(
const
price
&
a
,
const
price
&
b
)
{
return
a
.
base_per_quote
==
b
.
base_per_quote
;
}
friend
bool
operator
!=
(
const
price
&
a
,
const
price
&
b
)
{
return
a
.
base_per_quote
!=
b
.
base_per_quote
;
}
private:
//
private:
/**
* represented as number of base tokens to purchase 1 quote token
*/
uint128_t
base_per_quote
;
eos
::
uint128
base_per_quote
;
};
typedef
eos
::
token
<
uint64_t
,
N
(
eos
)
>
Tokens
;
...
...
contracts/exchange/Makefile
浏览文件 @
0a301c4c
exchange.wast
:
exchange.cpp Makefile ../eoslib/
eos.hpp
exchange.hpp
exchange.wast
:
exchange.cpp Makefile ../eoslib/
*
exchange.hpp
/usr/local/Cellar/llvm/4.0.0_1/bin/clang-4.0
-emit-llvm
-O3
--std
=
c++14
--target
=
wasm32
-c
exchange.cpp
-I
..
-fno-threadsafe-statics
-fno-rtti
-fno-exceptions
-o
.exchange.bc
-I
/usr/local/Cellar/llvm/4.0.0_1/include/c++/v1/
/Users/dlarimer/Downloads/llvm/build/bin/llc
-asm-verbose
=
false
.exchange.bc
/Users/dlarimer/eos/libraries/binaryen/bin/s2wasm
-s
1024 .exchange.s
>
exchange.wast
wc
-l
exchange.wast
echo
'#pragma once '
>
exchange.wast.hpp
echo
'const char* exchange_wast = R"=====('
>>
exchange.wast.hpp
echo
'const char* exchange_wast = R"=====('
>
exchange.wast.hpp
cat
exchange.wast
>>
exchange.wast.hpp
echo
')=====";'
>>
exchange.wast.hpp
...
...
contracts/exchange/exchange.cpp
浏览文件 @
0a301c4c
...
...
@@ -34,18 +34,25 @@
* contract. Users can only deposit or withdraw to their own currency account.
*/
#include <exchange/exchange.hpp> /// defines transfer struct
#include <eoslib/print.hpp>
using
namespace
exchange
;
using
namespace
eos
;
namespace
exchange
{
void
save
(
const
Account
&
a
)
{
if
(
a
.
isEmpty
()
)
inline
void
save
(
const
Account
&
a
)
{
if
(
a
.
isEmpty
()
)
{
print
(
"remove"
);
Db
::
remove
(
N
(
exchange
),
N
(
account
),
a
.
owner
);
else
}
else
{
print
(
"store"
);
Db
::
store
(
N
(
exchange
),
N
(
account
),
a
.
owner
,
a
);
}
}
template
<
typename
Lambda
>
void
modifyAccount
(
AccountName
a
,
Lambda
&&
modify
)
{
inline
void
modifyAccount
(
AccountName
a
,
Lambda
&&
modify
)
{
auto
acnt
=
getAccount
(
a
);
modify
(
acnt
);
save
(
acnt
);
...
...
@@ -57,13 +64,21 @@ void modifyAccount( AccountName a, Lambda&& modify ) {
*/
void
apply_currency_transfer
(
const
currency
::
Transfer
&
transfer
)
{
if
(
transfer
.
to
==
N
(
exchange
)
)
{
modifyAccount
(
transfer
.
to
,
[
&
](
Account
&
account
){
modifyAccount
(
transfer
.
from
,
[
&
](
Account
&
account
){
print
(
"balance: "
);
printi
(
account
.
currency_balance
.
quantity
);
print
(
"deposit: "
);
printi
(
transfer
.
quantity
.
quantity
);
account
.
currency_balance
+=
transfer
.
quantity
;
});
}
else
if
(
transfer
.
from
==
N
(
exchange
)
)
{
requireAuth
(
transfer
.
to
);
/// require the reciever of funds (account owner) to authorize this transfer
modifyAccount
(
transfer
.
to
,
[
&
](
Account
&
account
){
print
(
"balance: "
);
printi
(
account
.
currency_balance
.
quantity
);
print
(
"withdraw: "
);
printi
(
transfer
.
quantity
.
quantity
);
account
.
currency_balance
-=
transfer
.
quantity
;
});
}
else
{
...
...
@@ -77,7 +92,7 @@ void apply_currency_transfer( const currency::Transfer& transfer ) {
*/
void
apply_eos_transfer
(
const
eos
::
Transfer
&
transfer
)
{
if
(
transfer
.
to
==
N
(
exchange
)
)
{
modifyAccount
(
transfer
.
to
,
[
&
](
Account
&
account
){
modifyAccount
(
transfer
.
from
,
[
&
](
Account
&
account
){
account
.
eos_balance
+=
transfer
.
quantity
;
});
}
else
if
(
transfer
.
from
==
N
(
exchange
)
)
{
...
...
@@ -91,16 +106,6 @@ void apply_eos_transfer( const eos::Transfer& transfer ) {
}
}
void
fill
(
Bid
&
bid
,
Ask
&
ask
,
Account
&
buyer
,
Account
&
seller
,
eos
::
Tokens
e
,
currency
::
Tokens
c
)
{
bid
.
quantity
-=
e
;
seller
.
eos_balance
+=
e
;
ask
.
quantity
-=
c
;
buyer
.
currency_balance
+=
c
;
}
void
match
(
Bid
&
bid
,
Account
&
buyer
,
Ask
&
ask
,
Account
&
seller
)
{
eos
::
Tokens
ask_eos
=
ask
.
quantity
*
ask
.
price
;
...
...
@@ -113,7 +118,15 @@ void match( Bid& bid, Account& buyer, Ask& ask, Account& seller ) {
fill_amount_currency
=
fill_amount_eos
/
ask
.
price
;
}
fill
(
bid
,
ask
,
buyer
,
seller
,
fill_amount_eos
,
fill_amount_currency
);
print
(
"
\n\n
match bid: "
,
Name
(
bid
.
buyer
.
name
),
":"
,
bid
.
buyer
.
number
,
"match ask: "
,
Name
(
ask
.
seller
.
name
),
":"
,
ask
.
seller
.
number
,
"
\n\n
"
);
bid
.
quantity
-=
fill_amount_eos
;
seller
.
eos_balance
+=
fill_amount_eos
;
ask
.
quantity
-=
fill_amount_currency
;
buyer
.
currency_balance
+=
fill_amount_currency
;
}
/**
...
...
@@ -127,23 +140,30 @@ void apply_exchange_buy( BuyOrder order ) {
assert
(
bid
.
quantity
>
eos
::
Tokens
(
0
),
"invalid quantity"
);
assert
(
bid
.
expiration
>
now
(),
"order expired"
);
static
Bid
existing_bid
;
assert
(
BidsById
::
get
(
bid
.
buyer
,
existing_bid
),
"order with this id already exists"
);
print
(
Name
(
bid
.
buyer
.
name
),
" created bid for "
,
order
.
quantity
.
quantity
,
" currency at price: "
,
order
.
price
.
base_per_quote
,
"
\n
"
);
Bid
existing_bid
;
assert
(
!
BidsById
::
get
(
bid
.
buyer
,
existing_bid
),
"order with this id already exists"
);
print
(
__FILE__
,
__LINE__
,
"
\n
"
);
auto
buyer_account
=
getAccount
(
bid
.
buyer
.
name
);
buyer_account
.
eos_balance
-=
bid
.
quantity
;
static
Ask
lowest_ask
;
Ask
lowest_ask
;
if
(
!
AsksByPrice
::
front
(
lowest_ask
)
)
{
print
(
"
\n
No asks found, saving buyer account and storing bid
\n
"
);
assert
(
!
order
.
fill_or_kill
,
"order not completely filled"
);
Bids
::
store
(
bid
);
save
(
buyer_account
);
return
;
}
print
(
"asks found, lets see what matches
\n
"
);
auto
seller_account
=
getAccount
(
lowest_ask
.
seller
.
name
);
while
(
lowest_ask
.
price
<=
bid
.
price
)
{
print
(
"lowest ask <= bid.price
\n
"
);
match
(
bid
,
buyer_account
,
lowest_ask
,
seller_account
);
if
(
lowest_ask
.
quantity
==
currency
::
Tokens
(
0
)
)
{
...
...
@@ -158,12 +178,18 @@ void apply_exchange_buy( BuyOrder order ) {
break
;
// buyer's bid should be filled
}
}
print
(
"lowest_ask >= bid.price or buyer's bid has been filled
\n
"
);
save
(
buyer_account
);
print
(
"saving buyer's account
\n
"
);
if
(
bid
.
quantity
)
{
print
(
bid
.
quantity
.
quantity
,
" eos left over"
);
assert
(
!
order
.
fill_or_kill
,
"order not completely filled"
);
Bids
::
store
(
bid
);
return
;
}
print
(
"bid filled
\n
"
);
}
void
apply_exchange_sell
(
SellOrder
order
)
{
...
...
@@ -173,20 +199,26 @@ void apply_exchange_sell( SellOrder order ) {
assert
(
ask
.
quantity
>
currency
::
Tokens
(
0
),
"invalid quantity"
);
assert
(
ask
.
expiration
>
now
(),
"order expired"
);
static
Ask
existing_ask
;
assert
(
AsksById
::
get
(
ask
.
seller
,
existing_ask
),
"order with this id already exists"
);
print
(
"
\n\n
"
,
Name
(
ask
.
seller
.
name
),
" created sell for "
,
order
.
quantity
.
quantity
,
" currency at price: "
,
order
.
price
.
base_per_quote
,
"
\n
"
);
Ask
existing_ask
;
assert
(
!
AsksById
::
get
(
ask
.
seller
,
existing_ask
),
"order with this id already exists"
);
auto
seller_account
=
getAccount
(
ask
.
seller
.
name
);
seller_account
.
currency_balance
-=
ask
.
quantity
;
static
Bid
highest_bid
;
Bid
highest_bid
;
if
(
!
BidsByPrice
::
back
(
highest_bid
)
)
{
assert
(
!
order
.
fill_or_kill
,
"order not completely filled"
);
print
(
"
\n
No bids found, saving seller account and storing ask
\n
"
);
Asks
::
store
(
ask
);
save
(
seller_account
);
return
;
}
print
(
"
\n
bids found, lets see what matches
\n
"
);
auto
buyer_account
=
getAccount
(
highest_bid
.
buyer
.
name
);
while
(
highest_bid
.
price
>=
ask
.
price
)
{
...
...
@@ -208,80 +240,11 @@ void apply_exchange_sell( SellOrder order ) {
save
(
seller_account
);
if
(
ask
.
quantity
)
{
assert
(
!
order
.
fill_or_kill
,
"order not completely filled"
);
print
(
"saving ask
\n
"
);
Asks
::
store
(
ask
);
}
}
/*
void apply_exchange_sell() {
auto sell = currentMessage<Sell>();
assert( sell.expiration > now(), "order expired" );
Account seller_account;
Db::get( sell.seller, seller_account );
assert( seller_account.b >= sell.quantity, "insufficient funds" );
assert( sell.quantity > 0, "invalid quantity" );
seller_account.b -= sell.quantity;
Order seller_ask;
assert( AsksById::get( OrderID{ sell.seller, sell.id}, seller_ask ), "order with this id already exists" );
seller_ask.price = sell.price;
seller_ask.id.owner = sell.seller;
seller_ask.id.id = sell.id;
seller_ask.quantity = sell.quantity;
seller_ask.expiration = sell.expiration;
Order highest_bid;
if( !BidsByPrice::back( highest_bid ) ) {
assert( !sell.fill_or_kill, "order not completely filled" );
Bids::store( seller_ask );
Db::store( sell.seller, seller_account );
return;
}
Account buyer_account;
Db::get( highest_bid.id.owner, buyer_account );
while( highest_bid.price >= seller_ask.price ) {
auto ask_usd = seller_ask.quantity;
auto bid_usd = seller_ask.price * seller_ask.quantity;
auto fill_amount_usd = min<uint64_t>( ask_usd, bid_usd );
uint64_t fill_amount_token = 0;
seller_ask.quantity -= fill_amount_token;
highest_bid.quantity -= fill_amount_usd;
if( fill_amount_usd == ask_usd ) { /// complete fill of ask
fill_amount_token = seller_ask.quantity;
} else { /// complete fill of buy
fill_amount_token = fill_amount_usd / seller_ask.price;
}
/// either fill_amount_token == seller.quantity or fill_amount_usd == buy.quantity
fill( highest_bid, seller_ask, buyer_account, seller_account, fill_amount_usd, fill_amount_token );
if( highest_bid.quantity == 0 ) {
Db::store( highest_bid.id.owner, buyer_account );
Asks::remove( highest_bid );
if( !BidsByPrice::back( highest_bid ) ) {
break;
}
Db::get( highest_bid.id.owner, buyer_account );
} else {
break; // buyer's bid should be filled
}
}
Db::store( sell.seller, seller_account );
if( seller_ask.quantity > 0 ) {
assert( !sell.fill_or_kill, "order not completely filled" );
Asks::store( seller_ask );
}
}
*/
}
// namespace exchange
extern
"C"
{
...
...
@@ -306,6 +269,7 @@ extern "C" {
apply_exchange_buy
(
currentMessage
<
exchange
::
BuyOrder
>
()
);
break
;
case
N
(
sell
):
apply_exchange_sell
(
currentMessage
<
exchange
::
SellOrder
>
()
);
break
;
default:
assert
(
false
,
"unknown action"
);
...
...
contracts/exchange/exchange.hpp
浏览文件 @
0a301c4c
...
...
@@ -34,7 +34,7 @@ namespace exchange {
bool
isEmpty
()
const
{
return
!
(
bool
(
eos_balance
)
|
bool
(
currency_balance
)
|
open_orders
);
}
};
Account
getAccount
(
AccountName
owner
)
{
inline
Account
getAccount
(
AccountName
owner
)
{
Account
account
(
owner
);
Db
::
get
(
N
(
exchange
),
N
(
exchange
),
N
(
account
),
owner
,
account
);
return
account
;
...
...
libraries/chain/chain_controller.cpp
浏览文件 @
0a301c4c
...
...
@@ -484,7 +484,7 @@ try {
#warning TODO: call validate handlers on all notified accounts, currently it only calls the recipient's validate
message_validate_context
mvc
(
_db
,
trx
,
*
m
,
a
);
message_validate_context
mvc
(
*
this
,
_db
,
trx
,
*
m
,
a
);
auto
contract_handlers_itr
=
message_validate_handlers
.
find
(
a
);
/// namespace is the notifier
if
(
contract_handlers_itr
!=
message_validate_handlers
.
end
())
{
auto
message_handler_itr
=
contract_handlers_itr
->
second
.
find
({
m
->
code
,
m
->
type
});
...
...
@@ -597,7 +597,7 @@ void chain_controller::validate_message_precondition( precondition_validate_cont
* entire message.
*/
void
chain_controller
::
process_message
(
const
Transaction
&
trx
,
const
Message
&
message
)
{
apply_context
apply_ctx
(
_db
,
trx
,
message
,
message
.
code
);
apply_context
apply_ctx
(
*
this
,
_db
,
trx
,
message
,
message
.
code
);
/** TODO: pre condition validation and application can occur in parallel */
/** TODO: verify that message is fully authorized
...
...
@@ -607,7 +607,7 @@ void chain_controller::process_message( const Transaction& trx, const Message& m
for
(
const
auto
&
recipient
:
message
.
recipients
)
{
try
{
apply_context
recipient_ctx
(
_db
,
trx
,
message
,
recipient
);
apply_context
recipient_ctx
(
*
this
,
_db
,
trx
,
message
,
recipient
);
validate_message_precondition
(
recipient_ctx
);
apply_message
(
recipient_ctx
);
}
FC_CAPTURE_AND_RETHROW
((
recipient
)(
message
))
...
...
@@ -629,6 +629,7 @@ void chain_controller::apply_message(apply_context& context)
}
const
auto
&
recipient
=
_db
.
get
<
account_object
,
by_name
>
(
context
.
code
);
if
(
recipient
.
code
.
size
())
{
//idump((context.code)(context.msg.type));
wasm_interface
::
get
().
apply
(
context
);
}
...
...
@@ -767,6 +768,7 @@ void chain_controller::initialize_indexes() {
_db
.
add_index
<
permission_index
>
();
_db
.
add_index
<
action_permission_index
>
();
_db
.
add_index
<
key_value_index
>
();
_db
.
add_index
<
key128x128_value_index
>
();
_db
.
add_index
<
global_property_multi_index
>
();
_db
.
add_index
<
dynamic_global_property_multi_index
>
();
...
...
libraries/chain/include/eos/chain/message_handling_contexts.hpp
浏览文件 @
0a301c4c
...
...
@@ -8,13 +8,15 @@ namespace chainbase { class database; }
namespace
eos
{
namespace
chain
{
class
chain_controller
;
class
message_validate_context
{
public:
explicit
message_validate_context
(
const
chainbase
::
database
&
d
,
explicit
message_validate_context
(
const
chain_controller
&
control
,
const
chainbase
::
database
&
d
,
const
chain
::
Transaction
&
t
,
const
chain
::
Message
&
m
,
types
::
AccountName
c
)
:
db
(
d
),
trx
(
t
),
msg
(
m
),
code
(
c
),
used_authorizations
(
msg
.
authorization
.
size
(),
false
){}
:
controller
(
control
),
db
(
d
),
trx
(
t
),
msg
(
m
),
code
(
c
),
used_authorizations
(
msg
.
authorization
.
size
(),
false
){}
/**
* @brief Require @ref account to have approved of this message
...
...
@@ -30,6 +32,7 @@ public:
void
require_recipient
(
const
types
::
AccountName
&
account
)
const
;
bool
all_authorizations_used
()
const
;
const
chain_controller
&
controller
;
const
chainbase
::
database
&
db
;
///< database where state is stored
const
chain
::
Transaction
&
trx
;
///< used to gather the valid read/write scopes
const
chain
::
Message
&
msg
;
///< message being applied
...
...
@@ -43,6 +46,10 @@ public:
uint128_t
*
primary
,
uint128_t
*
secondary
,
char
*
data
,
uint32_t
maxlen
);
int32_t
back_primary_i128i128
(
Name
scope
,
Name
code
,
Name
table
,
uint128_t
*
primary
,
uint128_t
*
secondary
,
char
*
data
,
uint32_t
maxlen
);
int32_t
front_secondary_i128i128
(
Name
scope
,
Name
code
,
Name
table
,
uint128_t
*
primary
,
uint128_t
*
secondary
,
char
*
data
,
uint32_t
maxlen
);
int32_t
back_secondary_i128i128
(
Name
scope
,
Name
code
,
Name
table
,
uint128_t
*
primary
,
uint128_t
*
secondary
,
char
*
data
,
uint32_t
maxlen
);
int32_t
load_primary_i128i128
(
Name
scope
,
Name
code
,
Name
table
,
uint128_t
*
primary
,
uint128_t
*
secondary
,
char
*
data
,
uint32_t
maxlen
);
int32_t
lowerbound_primary_i128i128
(
Name
scope
,
Name
code
,
Name
table
,
...
...
@@ -56,27 +63,32 @@ public:
class
precondition_validate_context
:
public
message_validate_context
{
public:
precondition_validate_context
(
const
chainbase
::
database
&
db
,
precondition_validate_context
(
const
chain_controller
&
con
,
const
chainbase
::
database
&
db
,
const
chain
::
Transaction
&
t
,
const
chain
::
Message
&
m
,
const
types
::
AccountName
&
code
)
:
message_validate_context
(
db
,
t
,
m
,
code
){}
:
message_validate_context
(
con
,
db
,
t
,
m
,
code
){}
};
class
apply_context
:
public
precondition_validate_context
{
public:
apply_context
(
chainbase
::
database
&
db
,
apply_context
(
chain_controller
&
con
,
chainbase
::
database
&
db
,
const
chain
::
Transaction
&
t
,
const
chain
::
Message
&
m
,
const
types
::
AccountName
&
code
)
:
precondition_validate_context
(
db
,
t
,
m
,
code
),
mutable_db
(
db
){}
:
precondition_validate_context
(
con
,
db
,
t
,
m
,
code
),
mutable_controller
(
con
),
mutable_db
(
db
){}
int32_t
store_i64
(
Name
scope
,
Name
table
,
Name
key
,
const
char
*
data
,
uint32_t
len
);
int32_t
remove_i64
(
Name
scope
,
Name
table
,
Name
key
);
int32_t
store_i128i128
(
Name
scope
,
Name
table
,
uint128_t
primary
,
uint128_t
secondary
,
const
char
*
data
,
uint32_t
len
);
std
::
deque
<
eos
::
chain
::
generated_transaction
>
applied
;
///< sync calls made
std
::
deque
<
eos
::
chain
::
generated_transaction
>
generated
;
///< async calls requested
chain_controller
&
mutable_controller
;
chainbase
::
database
&
mutable_db
;
};
...
...
libraries/chain/message_handling_contexts.cpp
浏览文件 @
0a301c4c
...
...
@@ -58,6 +58,127 @@ int32_t message_validate_context::load_i64( Name scope, Name code, Name table, N
return
copylen
;
}
int32_t
message_validate_context
::
back_primary_i128i128
(
Name
scope
,
Name
code
,
Name
table
,
uint128_t
*
primary
,
uint128_t
*
secondary
,
char
*
value
,
uint32_t
valuelen
)
{
require_scope
(
scope
);
const
auto
&
idx
=
db
.
get_index
<
key128x128_value_index
,
by_scope_primary
>
();
auto
itr
=
idx
.
lower_bound
(
boost
::
make_tuple
(
AccountName
(
scope
),
AccountName
(
code
),
table
.
value
+
1
,
*
primary
,
uint128_t
(
0
)
)
);
if
(
itr
==
idx
.
begin
()
&&
itr
==
idx
.
end
()
)
return
0
;
--
itr
;
if
(
itr
->
scope
!=
scope
||
itr
->
code
!=
code
||
itr
->
table
!=
table
||
itr
->
primary_key
!=
*
primary
)
return
-
1
;
*
secondary
=
itr
->
secondary_key
;
*
primary
=
itr
->
primary_key
;
auto
copylen
=
std
::
min
<
size_t
>
(
itr
->
value
.
size
(),
valuelen
);
if
(
copylen
)
{
itr
->
value
.
copy
(
value
,
copylen
);
}
return
copylen
;
}
int32_t
message_validate_context
::
back_secondary_i128i128
(
Name
scope
,
Name
code
,
Name
table
,
uint128_t
*
primary
,
uint128_t
*
secondary
,
char
*
value
,
uint32_t
valuelen
)
{
require_scope
(
scope
);
const
auto
&
idx
=
db
.
get_index
<
key128x128_value_index
,
by_scope_secondary
>
();
auto
itr
=
idx
.
lower_bound
(
boost
::
make_tuple
(
AccountName
(
scope
),
AccountName
(
code
),
table
.
value
+
1
,
*
secondary
,
uint128_t
(
0
)
)
);
if
(
itr
==
idx
.
begin
()
&&
itr
==
idx
.
end
()
)
return
0
;
--
itr
;
if
(
itr
->
scope
!=
scope
||
itr
->
code
!=
code
||
itr
->
table
!=
table
||
itr
->
primary_key
!=
*
primary
)
return
-
1
;
*
secondary
=
itr
->
secondary_key
;
*
primary
=
itr
->
primary_key
;
auto
copylen
=
std
::
min
<
size_t
>
(
itr
->
value
.
size
(),
valuelen
);
if
(
copylen
)
{
itr
->
value
.
copy
(
value
,
copylen
);
}
return
copylen
;
}
int32_t
message_validate_context
::
front_primary_i128i128
(
Name
scope
,
Name
code
,
Name
table
,
uint128_t
*
primary
,
uint128_t
*
secondary
,
char
*
value
,
uint32_t
valuelen
)
{
require_scope
(
scope
);
const
auto
&
idx
=
db
.
get_index
<
key128x128_value_index
,
by_scope_primary
>
();
auto
itr
=
idx
.
lower_bound
(
boost
::
make_tuple
(
AccountName
(
scope
),
AccountName
(
code
),
AccountName
(
table
),
*
primary
,
uint128_t
(
0
)
)
);
if
(
itr
==
idx
.
end
()
)
return
-
1
;
--
itr
;
if
(
itr
->
scope
!=
scope
||
itr
->
code
!=
code
||
itr
->
table
!=
table
||
itr
->
primary_key
!=
*
primary
)
return
-
1
;
*
secondary
=
itr
->
secondary_key
;
*
primary
=
itr
->
primary_key
;
auto
copylen
=
std
::
min
<
size_t
>
(
itr
->
value
.
size
(),
valuelen
);
if
(
copylen
)
{
itr
->
value
.
copy
(
value
,
copylen
);
}
return
copylen
;
}
int32_t
message_validate_context
::
front_secondary_i128i128
(
Name
scope
,
Name
code
,
Name
table
,
uint128_t
*
primary
,
uint128_t
*
secondary
,
char
*
value
,
uint32_t
valuelen
)
{
require_scope
(
scope
);
const
auto
&
idx
=
db
.
get_index
<
key128x128_value_index
,
by_scope_secondary
>
();
auto
itr
=
idx
.
lower_bound
(
boost
::
make_tuple
(
AccountName
(
scope
),
AccountName
(
code
),
AccountName
(
table
),
*
secondary
,
uint128_t
(
0
)
)
);
if
(
itr
==
idx
.
end
()
)
return
-
1
;
--
itr
;
if
(
itr
->
scope
!=
scope
||
itr
->
code
!=
code
||
itr
->
table
!=
table
||
itr
->
primary_key
!=
*
primary
)
return
-
1
;
*
secondary
=
itr
->
secondary_key
;
*
primary
=
itr
->
primary_key
;
auto
copylen
=
std
::
min
<
size_t
>
(
itr
->
value
.
size
(),
valuelen
);
if
(
copylen
)
{
itr
->
value
.
copy
(
value
,
copylen
);
}
return
copylen
;
}
int32_t
message_validate_context
::
load_primary_i128i128
(
Name
scope
,
Name
code
,
Name
table
,
uint128_t
*
primary
,
uint128_t
*
secondary
,
char
*
value
,
uint32_t
valuelen
)
{
...
...
@@ -168,7 +289,34 @@ int32_t apply_context::store_i64( Name scope, Name table, Name key, const char*
o
.
key
=
key
;
o
.
value
.
insert
(
0
,
value
,
valuelen
);
});
return
1
;
return
valuelen
;
}
}
int32_t
apply_context
::
store_i128i128
(
Name
scope
,
Name
table
,
uint128_t
primary
,
uint128_t
secondary
,
const
char
*
value
,
uint32_t
valuelen
)
{
const
auto
*
obj
=
db
.
find
<
key128x128_value_object
,
by_scope_primary
>
(
boost
::
make_tuple
(
AccountName
(
scope
),
AccountName
(
code
),
AccountName
(
table
),
primary
,
secondary
)
);
if
(
obj
)
{
mutable_db
.
modify
(
*
obj
,
[
&
](
auto
&
o
)
{
o
.
primary_key
=
primary
;
o
.
secondary_key
=
secondary
;
o
.
value
.
assign
(
value
,
valuelen
);
});
return
0
;
}
else
{
mutable_db
.
create
<
key128x128_value_object
>
(
[
&
](
auto
&
o
)
{
o
.
scope
=
scope
;
o
.
code
=
code
;
o
.
table
=
table
;
o
.
primary_key
=
primary
;
o
.
secondary_key
=
secondary
;
o
.
value
.
insert
(
0
,
value
,
valuelen
);
});
return
valuelen
;
}
}
...
...
libraries/chain/wasm_interface.cpp
浏览文件 @
0a301c4c
#include <eos/chain/wasm_interface.hpp>
#include <eos/chain/chain_controller.hpp>
#include "Platform/Platform.h"
#include "WAST/WAST.h"
#include "Runtime/Runtime.h"
...
...
@@ -17,6 +18,87 @@ namespace eos { namespace chain {
wasm_interface
::
wasm_interface
()
{
}
DEFINE_INTRINSIC_FUNCTION2
(
env
,
multeq_i128
,
multeq_i128
,
none
,
i32
,
self
,
i32
,
other
)
{
auto
&
wasm
=
wasm_interface
::
get
();
auto
mem
=
wasm
.
current_memory
;
uint128_t
&
v
=
memoryRef
<
uint128_t
>
(
mem
,
self
);
const
uint128_t
&
o
=
memoryRef
<
const
uint128_t
>
(
mem
,
other
);
v
*=
o
;
}
DEFINE_INTRINSIC_FUNCTION2
(
env
,
diveq_i128
,
diveq_i128
,
none
,
i32
,
self
,
i32
,
other
)
{
auto
&
wasm
=
wasm_interface
::
get
();
auto
mem
=
wasm
.
current_memory
;
uint128_t
&
v
=
memoryRef
<
uint128_t
>
(
mem
,
self
);
const
uint128_t
&
o
=
memoryRef
<
const
uint128_t
>
(
mem
,
other
);
FC_ASSERT
(
o
!=
0
,
"divide by zero"
);
v
/=
o
;
}
DEFINE_INTRINSIC_FUNCTION0
(
env
,
now
,
now
,
i32
)
{
return
wasm_interface
::
get
().
current_validate_context
->
controller
.
head_block_time
().
sec_since_epoch
();
}
DEFINE_INTRINSIC_FUNCTION4
(
env
,
store_i128i128
,
store_i128i128
,
i32
,
i64
,
scope
,
i64
,
table
,
i32
,
data
,
i32
,
datalen
)
{
auto
&
wasm
=
wasm_interface
::
get
();
FC_ASSERT
(
wasm
.
current_apply_context
,
"not a valid apply context"
);
char
*
v
=
&
memoryRef
<
char
>
(
wasm
.
current_memory
,
data
);
uint128_t
&
primary
=
*
((
uint128_t
*
)
v
);
uint128_t
&
secondary
=
*
(((
uint128_t
*
)
v
)
+
1
);
char
*
value
=
v
+
2
*
sizeof
(
uint128_t
);
return
wasm_interface
::
get
().
current_apply_context
->
store_i128i128
(
Name
(
scope
),
Name
(
table
),
primary
,
secondary
,
value
,
datalen
-
2
*
sizeof
(
uint128_t
)
);
}
DEFINE_INTRINSIC_FUNCTION3
(
env
,
remove_i128i128
,
remove_i128i128
,
i32
,
i64
,
scope
,
i64
,
table
,
i32
,
data
)
{
FC_ASSERT
(
!
"remove not implemented"
);
return
0
;
}
DEFINE_INTRINSIC_FUNCTION5
(
env
,
load_primary_i128i128
,
load_primary_i128i128
,
i32
,
i64
,
scope
,
i64
,
code
,
i64
,
table
,
i32
,
data
,
i32
,
datalen
)
{
auto
&
wasm
=
wasm_interface
::
get
();
char
*
v
=
&
memoryRef
<
char
>
(
wasm
.
current_memory
,
data
);
return
wasm_interface
::
get
().
current_validate_context
->
load_primary_i128i128
(
Name
(
scope
),
Name
(
code
),
Name
(
table
),
(
uint128_t
*
)
v
,
(
uint128_t
*
)(
v
+
sizeof
(
uint128_t
)),
v
,
datalen
-
(
2
*
sizeof
(
uint128_t
))
);
}
DEFINE_INTRINSIC_FUNCTION5
(
env
,
load_secondary_i128i128
,
load_secondary_i128i128
,
i32
,
i64
,
scope
,
i64
,
code
,
i64
,
table
,
i32
,
data
,
i32
,
datalen
)
{
FC_ASSERT
(
!
"load_secondary_i128i128 not implemented"
);
return
0
;
}
DEFINE_INTRINSIC_FUNCTION5
(
env
,
back_primary_i128i128
,
back_primary_i128i128
,
i32
,
i64
,
scope
,
i64
,
code
,
i64
,
table
,
i32
,
data
,
i32
,
datalen
)
{
auto
&
wasm
=
wasm_interface
::
get
();
char
*
v
=
&
memoryRef
<
char
>
(
wasm
.
current_memory
,
data
);
return
wasm_interface
::
get
().
current_validate_context
->
back_primary_i128i128
(
Name
(
scope
),
Name
(
code
),
Name
(
table
),
(
uint128_t
*
)
v
,
(
uint128_t
*
)(
v
+
sizeof
(
uint128_t
)),
v
,
datalen
-
(
2
*
sizeof
(
uint128_t
))
);
}
DEFINE_INTRINSIC_FUNCTION5
(
env
,
front_primary_i128i128
,
front_primary
,
i32
,
i64
,
scope
,
i64
,
code
,
i64
,
table
,
i32
,
data
,
i32
,
datalen
)
{
auto
&
wasm
=
wasm_interface
::
get
();
char
*
v
=
&
memoryRef
<
char
>
(
wasm
.
current_memory
,
data
);
return
wasm_interface
::
get
().
current_validate_context
->
front_primary_i128i128
(
Name
(
scope
),
Name
(
code
),
Name
(
table
),
(
uint128_t
*
)
v
,
(
uint128_t
*
)(
v
+
sizeof
(
uint128_t
)),
v
,
datalen
-
(
2
*
sizeof
(
uint128_t
))
);
}
DEFINE_INTRINSIC_FUNCTION5
(
env
,
back_secondary_i128i128
,
back_secondary_i128i128
,
i32
,
i64
,
scope
,
i64
,
code
,
i64
,
table
,
i32
,
data
,
i32
,
datalen
)
{
auto
&
wasm
=
wasm_interface
::
get
();
char
*
v
=
&
memoryRef
<
char
>
(
wasm
.
current_memory
,
data
);
return
wasm_interface
::
get
().
current_validate_context
->
back_secondary_i128i128
(
Name
(
scope
),
Name
(
code
),
Name
(
table
),
(
uint128_t
*
)
v
,
(
uint128_t
*
)(
v
+
sizeof
(
uint128_t
)),
v
,
datalen
-
(
2
*
sizeof
(
uint128_t
))
);
return
0
;
}
DEFINE_INTRINSIC_FUNCTION5
(
env
,
front_secondary_i128i128
,
front_secondary_i128i128
,
i32
,
i64
,
scope
,
i64
,
code
,
i64
,
table
,
i32
,
data
,
i32
,
datalen
)
{
auto
&
wasm
=
wasm_interface
::
get
();
char
*
v
=
&
memoryRef
<
char
>
(
wasm
.
current_memory
,
data
);
return
wasm_interface
::
get
().
current_validate_context
->
front_secondary_i128i128
(
Name
(
scope
),
Name
(
code
),
Name
(
table
),
(
uint128_t
*
)
v
,
(
uint128_t
*
)(
v
+
sizeof
(
uint128_t
)),
v
,
datalen
-
(
2
*
sizeof
(
uint128_t
))
);
}
DEFINE_INTRINSIC_FUNCTION0
(
env
,
currentCode
,
currentCode
,
i64
)
{
auto
&
wasm
=
wasm_interface
::
get
();
return
wasm
.
current_validate_context
->
code
.
value
;
...
...
@@ -173,18 +255,26 @@ DEFINE_INTRINSIC_FUNCTION1(env,malloc,malloc,i32,i32,size) {
}
DEFINE_INTRINSIC_FUNCTION1
(
env
,
printi
,
printi
,
none
,
i64
,
val
)
{
std
::
cerr
<<
uint64_t
(
val
)
<<
" "
<<
Name
(
val
).
toString
();
//idump((val)(Name(val)));
std
::
cerr
<<
uint64_t
(
val
);
}
DEFINE_INTRINSIC_FUNCTION1
(
env
,
printi128
,
printi128
,
none
,
i32
,
val
)
{
auto
&
wasm
=
wasm_interface
::
get
();
auto
mem
=
wasm
.
current_memory
;
fc
::
uint128_t
&
value
=
memoryRef
<
fc
::
uint128_t
>
(
mem
,
val
);
std
::
cerr
<<
fc
::
variant
(
value
).
get_string
();
}
DEFINE_INTRINSIC_FUNCTION1
(
env
,
printn
,
printn
,
none
,
i64
,
val
)
{
std
::
cerr
<<
Name
(
val
).
toString
();
}
DEFINE_INTRINSIC_FUNCTION1
(
env
,
print
,
print
,
none
,
i32
,
charptr
)
{
DEFINE_INTRINSIC_FUNCTION1
(
env
,
print
s
,
prints
,
none
,
i32
,
charptr
)
{
auto
&
wasm
=
wasm_interface
::
get
();
auto
mem
=
wasm
.
current_memory
;
const
char
*
str
=
&
memoryRef
<
const
char
>
(
mem
,
charptr
);
std
::
cerr
<<
std
::
string
(
str
,
strlen
(
str
)
);
wdump
(
(
std
::
string
(
str
,
strlen
(
str
)
))
);
}
DEFINE_INTRINSIC_FUNCTION1
(
env
,
free
,
free
,
none
,
i32
,
ptr
)
{
...
...
@@ -261,6 +351,8 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
//FC_ASSERT( apply, "no entry point found for ${call}", ("call", std::string(name)) );
FC_ASSERT
(
getFunctionType
(
call
)
->
parameters
.
size
()
==
2
);
idump
((
current_validate_context
->
msg
.
code
)(
current_validate_context
->
msg
.
type
)(
current_validate_context
->
code
));
std
::
vector
<
Value
>
args
=
{
Value
(
uint64_t
(
current_validate_context
->
msg
.
code
)),
Value
(
uint64_t
(
current_validate_context
->
msg
.
type
))
};
...
...
@@ -351,6 +443,7 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
void
wasm_interface
::
load
(
const
AccountName
&
name
,
const
chainbase
::
database
&
db
)
{
const
auto
&
recipient
=
db
.
get
<
account_object
,
by_name
>
(
name
);
// idump(("recipient")(Name(name))(recipient.code_version));
auto
&
state
=
instances
[
name
];
if
(
state
.
code_version
!=
recipient
.
code_version
)
{
...
...
@@ -392,6 +485,7 @@ DEFINE_INTRINSIC_FUNCTION1(env,toUpper,toUpper,none,i32,charptr) {
memcpy
(
state
.
init_memory
.
data
(),
memstart
,
state
.
mem_end
);
//state.init_memory.size() );
std
::
cerr
<<
"
\n
"
;
state
.
code_version
=
recipient
.
code_version
;
idump
((
state
.
code_version
));
}
catch
(
Serialization
::
FatalSerializationException
exception
)
{
...
...
libraries/native_contract/system_contract.cpp
浏览文件 @
0a301c4c
...
...
@@ -39,7 +39,7 @@ void apply_system_setcode(apply_context& context) {
memcpy
(
a
.
code
.
data
(),
msg
.
code
.
data
(),
msg
.
code
.
size
()
);
});
apply_context
init_context
(
context
.
mutable_db
,
context
.
trx
,
context
.
msg
,
msg
.
account
);
apply_context
init_context
(
context
.
mutable_
controller
,
context
.
mutable_
db
,
context
.
trx
,
context
.
msg
,
msg
.
account
);
wasm_interface
::
get
().
init
(
init_context
);
}
...
...
tests/slow_tests/slow_tests.cpp
浏览文件 @
0a301c4c
...
...
@@ -46,6 +46,27 @@
using
namespace
eos
;
using
namespace
chain
;
struct
OrderID
{
AccountName
name
;
uint64_t
number
=
0
;
};
struct
Bid
{
OrderID
buyer
;
fc
::
uint128_t
price
;
uint64_t
quantity
;
Time
expiration
;
};
struct
Ask
{
OrderID
seller
;
fc
::
uint128_t
price
;
uint64_t
quantity
;
Time
expiration
;
};
FC_REFLECT
(
OrderID
,
(
name
)(
number
)
);
FC_REFLECT
(
Bid
,
(
buyer
)(
price
)(
quantity
)(
expiration
)
);
FC_REFLECT
(
Ask
,
(
seller
)(
price
)(
quantity
)(
expiration
)
);
BOOST_AUTO_TEST_SUITE
(
slow_tests
)
// Test that TaPoS still works after block 65535 (See Issue #55)
...
...
@@ -157,6 +178,51 @@ vector<uint8_t> assemble_wast( const std::string& wast ) {
}
}
void
SetCode
(
testing_blockchain
&
chain
,
AccountName
account
,
const
char
*
wast
)
{
try
{
types
::
setcode
handler
;
handler
.
account
=
account
;
auto
wasm
=
assemble_wast
(
wast
);
handler
.
code
.
resize
(
wasm
.
size
());
memcpy
(
handler
.
code
.
data
(),
wasm
.
data
(),
wasm
.
size
()
);
{
eos
::
chain
::
SignedTransaction
trx
;
trx
.
scope
=
{
account
};
trx
.
messages
.
resize
(
1
);
trx
.
messages
[
0
].
code
=
config
::
SystemContractName
;
trx
.
messages
[
0
].
recipients
=
{
account
};
trx
.
setMessage
(
0
,
"setcode"
,
handler
);
trx
.
expiration
=
chain
.
head_block_time
()
+
100
;
trx
.
set_reference_block
(
chain
.
head_block_id
());
chain
.
push_transaction
(
trx
);
chain
.
produce_blocks
(
1
);
}
}
FC_LOG_AND_RETHROW
(
)
}
void
TransferCurrency
(
testing_blockchain
&
chain
,
AccountName
from
,
AccountName
to
,
uint64_t
amount
)
{
eos
::
chain
::
SignedTransaction
trx
;
trx
.
scope
=
sort_names
({
from
,
to
});
trx
.
emplaceMessage
(
"currency"
,
sort_names
(
{
from
,
to
}
),
vector
<
types
::
AccountPermission
>
{
{
from
,
"active"
}
},
"transfer"
,
types
::
transfer
{
from
,
to
,
amount
,
""
});
trx
.
expiration
=
chain
.
head_block_time
()
+
100
;
trx
.
set_reference_block
(
chain
.
head_block_id
());
chain
.
push_transaction
(
trx
);
}
void
WithdrawCurrency
(
testing_blockchain
&
chain
,
AccountName
from
,
AccountName
to
,
uint64_t
amount
)
{
eos
::
chain
::
SignedTransaction
trx
;
trx
.
scope
=
sort_names
({
from
,
to
});
trx
.
emplaceMessage
(
"currency"
,
sort_names
(
{
from
,
to
}
),
vector
<
types
::
AccountPermission
>
{
{
from
,
"active"
},{
to
,
"active"
}
},
"transfer"
,
types
::
transfer
{
from
,
to
,
amount
,
""
});
trx
.
expiration
=
chain
.
head_block_time
()
+
100
;
trx
.
set_reference_block
(
chain
.
head_block_id
());
chain
.
push_transaction
(
trx
);
}
//Test account script processing
BOOST_FIXTURE_TEST_CASE
(
create_script
,
testing_fixture
)
{
try
{
...
...
@@ -208,156 +274,123 @@ BOOST_FIXTURE_TEST_CASE(create_script, testing_fixture)
}
FC_LOG_AND_RETHROW
()
}
//Test account script float rejection
BOOST_FIXTURE_TEST_CASE
(
create_script_w_float
,
testing_fixture
)
{
try
{
Make_Blockchain
(
chain
);
chain
.
produce_blocks
(
10
);
Make_Account
(
chain
,
simplecoin
);
chain
.
produce_blocks
(
1
);
static
const
uint64_t
precision
=
1000ll
*
1000ll
*
1000ll
*
1000ll
*
1000ll
;
fc
::
uint128_t
to_price
(
double
p
)
{
uint64_t
pi
(
p
);
fc
::
uint128_t
result
(
pi
);
result
*=
precision
;
/*
auto c_apply = R"(
typedef long long uint64_t;
typedef unsigned int uint32_t;
void print( char* string, int length );
void printi( int );
void printi64( uint64_t );
void assert( int test, char* message );
void store( const char* key, int keylength, const char* value, int valuelen );
int load( const char* key, int keylength, char* value, int maxlen );
int remove( const char* key, int keyLength );
void* memcpy( void* dest, const void* src, uint32_t size );
int readMessage( char* dest, int destsize );
void* malloc( unsigned int size ) {
static char dynamic_memory[1024*8];
static int start = 0;
int old_start = start;
start += 8*((size+7)/8);
assert( start < sizeof(dynamic_memory), "out of memory" );
return &dynamic_memory[old_start];
double
fract
=
p
-
pi
;
result
+=
uint64_t
(
fract
*
precision
);
return
result
;
}
typedef struct {
uint64_t name[4];
} AccountName;
typedef struct {
uint32_t length;
char data[];
} String;
void
SellCurrency
(
testing_blockchain
&
chain
,
AccountName
seller
,
AccountName
exchange
,
uint64_t
ordernum
,
uint64_t
cur_quantity
,
double
price
)
{
typedef struct {
char* start;
char* pos;
char* end;
} DataStream
;
Ask
b
{
OrderID
{
seller
,
ordernum
},
to_price
(
price
),
cur_quantity
,
chain
.
head_block_time
()
+
fc
::
days
(
3
)
}
;
void DataStream_init( DataStream* ds, char* start, int length ) {
ds->start = start;
ds->end = start + length;
ds->pos = start;
}
void AccountName_initString( AccountName* a, String* s ) {
assert( s->length <= sizeof(AccountName), "String is longer than account name allows" );
memcpy( a, s->data, s->length );
}
void AccountName_initCString( AccountName* a, const char* s, uint32_t len ) {
assert( len <= sizeof(AccountName), "String is longer than account name allows" );
memcpy( a, s, len );
}
eos
::
chain
::
SignedTransaction
trx
;
trx
.
scope
=
sort_names
({
"exchange"
});
trx
.
emplaceMessage
(
"exchange"
,
sort_names
(
{
"exchange"
}
),
vector
<
types
::
AccountPermission
>
{
{
seller
,
"active"
}
},
"sell"
,
b
);
trx
.
expiration
=
chain
.
head_block_time
()
+
100
;
trx
.
set_reference_block
(
chain
.
head_block_id
());
chain
.
push_transaction
(
trx
);
void AccountName_unpack( DataStream* ds, AccountName* account );
void uint64_unpack( DataStream* ds, uint64_t* value ) {
assert( ds->pos + sizeof(uint64_t) <= ds->end, "read past end of stream" );
memcpy( (char*)value, ds->pos, 8 );
ds->pos += sizeof(uint64_t);
}
void Varint_unpack( DataStream* ds, uint32_t* value );
void String_unpack( DataStream* ds, String** value ) {
static uint32_t size;
Varint_unpack( ds, &size );
assert( ds->pos + size <= ds->end, "read past end of stream");
String* str = (String*)malloc( size + sizeof(String) );
memcpy( str->data, ds->pos, size );
*value = str;
void
BuyCurrency
(
testing_blockchain
&
chain
,
AccountName
buyer
,
AccountName
exchange
,
uint64_t
ordernum
,
uint64_t
cur_quantity
,
double
price
)
{
Bid
b
{
OrderID
{
buyer
,
ordernum
},
to_price
(
price
),
cur_quantity
,
chain
.
head_block_time
()
+
fc
::
days
(
3
)
};
eos
::
chain
::
SignedTransaction
trx
;
trx
.
scope
=
sort_names
({
"exchange"
});
trx
.
emplaceMessage
(
"exchange"
,
sort_names
(
{
"exchange"
}
),
vector
<
types
::
AccountPermission
>
{
{
buyer
,
"active"
}
},
"buy"
,
b
);
trx
.
expiration
=
chain
.
head_block_time
()
+
100
;
trx
.
set_reference_block
(
chain
.
head_block_id
());
chain
.
push_transaction
(
trx
);
}
/// END BUILT IN LIBRARY.... everything below this is "user contract"
BOOST_FIXTURE_TEST_CASE
(
create_exchange
,
testing_fixture
)
{
#include <currency/currency.wast.hpp>
#include <exchange/exchange.wast.hpp>
try
{
try
{
Make_Blockchain
(
chain
);
chain
.
produce_blocks
(
2
);
Make_Account
(
chain
,
currency
);
Make_Account
(
chain
,
exchange
);
chain
.
produce_blocks
(
1
);
SetCode
(
chain
,
"currency"
,
currency_wast
);
SetCode
(
chain
,
"exchange"
,
exchange_wast
);
typedef struct {
AccountName from;
AccountName to;
uint64_t amount;
String* memo;
} Transfer;
chain
.
produce_blocks
(
1
);
void Transfer_unpack( DataStream* ds, Transfer* transfer )
{
AccountName_unpack( ds, &transfer->from );
AccountName_unpack( ds, &transfer->to );
uint64_unpack( ds, &transfer->amount );
String_unpack( ds, &transfer->memo );
}
ilog
(
"transfering currency to the users"
);
TransferCurrency
(
chain
,
"currency"
,
"inita"
,
1000
);
TransferCurrency
(
chain
,
"currency"
,
"initb"
,
2000
);
typedef struct {
uint64_t balance;
} Balance;
Transfer_Asset
(
chain
,
system
,
inita
,
Asset
(
50
));
Transfer_Asset
(
chain
,
system
,
initb
,
Asset
(
50
));
chain
.
produce_blocks
(
1
);
ilog
(
"transfering funds to the exchange"
);
TransferCurrency
(
chain
,
"inita"
,
"exchange"
,
1000
);
TransferCurrency
(
chain
,
"initb"
,
"exchange"
,
2000
);
void onInit() {
static Balance initial;
static AccountName simplecoin;
AccountName_initCString( &simplecoin, "simplecoin", 10 );
initial.balance = 1000*1000;
Transfer_Asset
(
chain
,
inita
,
exchange
,
Asset
(
500
));
Transfer_Asset
(
chain
,
initb
,
exchange
,
Asset
(
500
));
store( (const char*)&simplecoin, sizeof(AccountName), (const char*)&initial, sizeof(Balance));
}
BOOST_REQUIRE_THROW
(
TransferCurrency
(
chain
,
"initb"
,
"exchange"
,
2000
),
fc
::
exception
);
// insufficient funds
void onApply_Transfer_simplecoin() {
static char buffer[100];
BOOST_REQUIRE_THROW
(
WithdrawCurrency
(
chain
,
"exchange"
,
"initb"
,
2001
),
fc
::
exception
);
// insufficient funds
int read = readMessage( buffer, 100 );
static Transfer message;
static DataStream ds;
DataStream_init( &ds, buffer, read );
Transfer_unpack( &ds, &message );
ilog
(
"withdrawing from exchange"
);
static Balance from_balance;
static Balance to_balance;
to_balance.balance = 0;
WithdrawCurrency
(
chain
,
"exchange"
,
"initb"
,
2000
);
chain
.
produce_blocks
(
1
);
read = load( (const char*)&message.from, sizeof(message.from), (char*)&from_balance.balance,
sizeof(from_balance.balance) );
assert( read == sizeof(Balance), "no existing balance" );
assert( from_balance.balance >= message.amount, "insufficient funds" );
read = load( (const char*)&message.to, sizeof(message.to), (char*)&to_balance.balance, sizeof(to_balance.balance) );
ilog
(
"send back to exchange"
);
TransferCurrency
(
chain
,
"initb"
,
"exchange"
,
2000
);
chain
.
produce_blocks
(
1
);
to_balance.balance += message.amount;
from_balance.balance -= message.amount;
SellCurrency
(
chain
,
"initb"
,
"exchange"
,
1
,
100
,
.5
);
//BOOST_REQUIRE_THROW( SellCurrency( chain, "initb", "exchange", 1, 100, .5 ), fc::exception ); // order id already exists
SellCurrency
(
chain
,
"initb"
,
"exchange"
,
2
,
100
,
.75
);
double bal = to_balance.balance;
if( bal + 0.5 < 50.5 )
return;
BuyCurrency
(
chain
,
"initb"
,
"exchange"
,
1
,
50
,
.25
);
//BOOST_REQUIRE_THROW( BuyCurrency( chain, "initb", "exchange", 1, 50, .25 ), fc::exception ); // order id already exists
if( from_balance.balance )
store( (const char*)&message.from, sizeof(AccountName), (const char*)&from_balance.balance,
sizeof(from_balance.balance) );
else
remove( (const char*)&message.from, sizeof(AccountName) );
/// this should buy 5 from initb order 2 at a price of .75
BuyCurrency
(
chain
,
"initb"
,
"exchange"
,
2
,
50
,
.8
);
store( (const char*)&message.to, sizeof(message.to), (const char*)&to_balance.balance, sizeof(to_balance.balance) );
}
FC_LOG_AND_RETHROW
()
}
catch
(...)
{
elog
(
"unexpected exception"
);
}
}
");
*/
//Test account script float rejection
BOOST_FIXTURE_TEST_CASE
(
create_script_w_float
,
testing_fixture
)
{
try
{
Make_Blockchain
(
chain
);
chain
.
produce_blocks
(
10
);
Make_Account
(
chain
,
simplecoin
);
chain
.
produce_blocks
(
1
);
std
::
string
wast_apply
=
R"(
(module
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录