mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
vm: bugfixes
This commit is contained in:
parent
27aaa11524
commit
ba76f1404e
30 changed files with 396 additions and 178 deletions
|
@ -344,11 +344,11 @@ unsigned long long VarUIntegerPos::as_uint(const vm::CellSlice& cs) const {
|
|||
|
||||
bool VarUIntegerPos::store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const {
|
||||
int k = value.bit_size(false);
|
||||
return k <= (n - 1) * 8 && value.sgn() > 0 && cb.store_long_bool((k + 7) >> 3, ln) &&
|
||||
return k <= (n - 1) * 8 && value.sgn() >= (int)store_pos_only && cb.store_long_bool((k + 7) >> 3, ln) &&
|
||||
cb.store_int256_bool(value, (k + 7) & -8, false);
|
||||
}
|
||||
|
||||
const VarUIntegerPos t_VarUIntegerPos_16{16}, t_VarUIntegerPos_32{32};
|
||||
const VarUIntegerPos t_VarUIntegerPos_16{16}, t_VarUIntegerPos_32{32}, t_VarUIntegerPosRelaxed_32{32, true};
|
||||
|
||||
static inline bool redundant_int(const vm::CellSlice& cs) {
|
||||
int t = (int)cs.prefetch_long(9);
|
||||
|
|
|
@ -77,7 +77,8 @@ extern const VarUInteger t_VarUInteger_3, t_VarUInteger_7, t_VarUInteger_16, t_V
|
|||
|
||||
struct VarUIntegerPos final : TLB_Complex {
|
||||
int n, ln;
|
||||
VarUIntegerPos(int _n) : n(_n) {
|
||||
bool store_pos_only;
|
||||
VarUIntegerPos(int _n, bool relaxed = false) : n(_n), store_pos_only(!relaxed) {
|
||||
ln = 32 - td::count_leading_zeroes32(n - 1);
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
|
@ -90,7 +91,7 @@ struct VarUIntegerPos final : TLB_Complex {
|
|||
}
|
||||
};
|
||||
|
||||
extern const VarUIntegerPos t_VarUIntegerPos_16, t_VarUIntegerPos_32;
|
||||
extern const VarUIntegerPos t_VarUIntegerPos_16, t_VarUIntegerPos_32, t_VarUIntegerPosRelaxed_32;
|
||||
|
||||
struct VarInteger final : TLB_Complex {
|
||||
int n, ln;
|
||||
|
@ -325,7 +326,7 @@ extern const MsgAddress t_MsgAddress;
|
|||
|
||||
struct ExtraCurrencyCollection final : TLB {
|
||||
HashmapE dict_type, dict_type2;
|
||||
ExtraCurrencyCollection() : dict_type(32, t_VarUIntegerPos_32), dict_type2(32, t_VarUInteger_32) {
|
||||
ExtraCurrencyCollection() : dict_type(32, t_VarUIntegerPos_32), dict_type2(32, t_VarUIntegerPosRelaxed_32) {
|
||||
}
|
||||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return dict_type.get_size(cs);
|
||||
|
|
|
@ -724,7 +724,12 @@ void interpret_tlb_validate_skip(vm::Stack& stack) {
|
|||
stack.push_bool(ok);
|
||||
}
|
||||
|
||||
void interpret_tlb_type_const(vm::Stack& stack, const tlb::TLB* ptr) {
|
||||
stack.push_make_object<tlb::TlbTypeHolder>(ptr);
|
||||
}
|
||||
|
||||
void init_words_tlb(fift::Dictionary& d) {
|
||||
using namespace std::placeholders;
|
||||
tlb_dict.register_types(block::gen::register_simple_types);
|
||||
d.def_stack_word("tlb-type-lookup ", interpret_tlb_type_lookup);
|
||||
d.def_stack_word("tlb-type-name ", interpret_tlb_type_name);
|
||||
|
@ -733,6 +738,7 @@ void init_words_tlb(fift::Dictionary& d) {
|
|||
d.def_stack_word("(tlb-dump-str?) ", interpret_tlb_dump_to_str);
|
||||
d.def_stack_word("tlb-skip ", interpret_tlb_skip);
|
||||
d.def_stack_word("tlb-validate-skip ", interpret_tlb_validate_skip);
|
||||
d.def_stack_word("ExtraCurrencyCollection", std::bind(interpret_tlb_type_const, _1, &block::tlb::t_ExtraCurrencyCollection));
|
||||
}
|
||||
|
||||
void usage(const char* progname) {
|
||||
|
|
|
@ -111,6 +111,8 @@ variable base
|
|||
{ cdr cdr } : cddr
|
||||
{ cdr cdr car } : caddr
|
||||
{ null ' cons rot times } : list
|
||||
{ -rot pair swap ! } : 2!
|
||||
{ @ unpair } : 2@
|
||||
{ true (atom) drop } : atom
|
||||
{ bl word atom 1 'nop } ::_ `
|
||||
{ hole dup 1 { @ execute } does create } : recursive
|
||||
|
@ -121,13 +123,18 @@ variable base
|
|||
{ 0 word -trailing scan-until-word 1 'nop } ::_ $<<
|
||||
{ 0x40 runvmx } : runvmcode
|
||||
{ 0x48 runvmx } : gasrunvmcode
|
||||
{ 0xc8 runvmx } : gas2runvmcode
|
||||
{ 0x43 runvmx } : runvmdict
|
||||
{ 0x4b runvmx } : gasrunvmdict
|
||||
{ 0xcb runvmx } : gas2runvmdict
|
||||
{ 0x45 runvmx } : runvm
|
||||
{ 0x4d runvmx } : gasrunvm
|
||||
{ 0xcd runvmx } : gas2runvm
|
||||
{ 0x55 runvmx } : runvmctx
|
||||
{ 0x5d runvmx } : gasrunvmctx
|
||||
{ 0xdd runvmx } : gas2runvmctx
|
||||
{ 0x75 runvmx } : runvmctxact
|
||||
{ 0x7d runvmx } : gasrunvmctxact
|
||||
{ 0xfd runvmx } : gas2runvmctxact
|
||||
{ 0x35 runvmx } : runvmctxactq
|
||||
{ 0x3d runvmx } : gasrunvmctxactq
|
||||
|
|
|
@ -77,9 +77,10 @@ library TonUtil // TON Blockchain Fift Library
|
|||
1000000000 constant Gram
|
||||
{ Gram swap */r } : Gram*/
|
||||
{ Gram * } : Gram*
|
||||
{ (number) dup { 1- ' Gram*/ ' Gram* cond true } if
|
||||
} : $>GR?
|
||||
// ( S -- nanograms )
|
||||
{ (number) ?dup 0= abort"not a valid Gram amount"
|
||||
1- ' Gram*/ ' Gram* cond
|
||||
{ $>GR? not abort"not a valid Gram amount"
|
||||
} : $>GR
|
||||
{ bl word $>GR 1 'nop } ::_ GR$
|
||||
// ( nanograms -- S )
|
||||
|
@ -119,7 +120,7 @@ dictnew constant cc0 // zero currency collection
|
|||
{ swap cc-key-bits { rot { ."+" } if .val ."*$" ._ true true } idictforeach drop } : (.cc)
|
||||
{ false (.cc) { ."0" } ifnot } : .cc_
|
||||
{ .cc_ space } : .cc
|
||||
{ true (.cc) } : .+cc_
|
||||
{ true (.cc) drop } : .+cc_
|
||||
{ .+cc_ space } : .+cc
|
||||
{ cc-key-bits { rot . ."-> " swap .val .val ."; " true } dictdiff drop cr } : show-cc-diff
|
||||
{ cc-key-bits { val@ swap val@ + val, true } dictmerge } : cc+
|
||||
|
@ -141,13 +142,30 @@ forget val, forget val@ forget .val
|
|||
} cond } cond } cond } cond
|
||||
} : cc-key-value?
|
||||
// ( S -- D -1 or 0 ) Parses an extra currency collection
|
||||
// e.g. "10000*$3+7777*$-11" means "10000 units of currency #3 and 7777 units of currency #-11"
|
||||
{ dictnew { // S D
|
||||
swap dup "+" $pos dup 0< { drop null -rot } { $| 1 $| nip -rot } cond
|
||||
cc-key-value? { +ccpair over null? dup { rot drop true } if } { 2drop false true } cond
|
||||
} until
|
||||
} : $>xcc?
|
||||
{ $>xcc? not abort"invalid extra currency collection" } : $>xcc
|
||||
{ char } word dup $len { $>xcc } { drop dictnew } cond 1 'nop } ::_ CX{
|
||||
|
||||
// complete currency collections
|
||||
{ $>xcc? { true } { drop false } cond } : end-parse-cc
|
||||
// ( S -- x D -1 or 0 ) Parses a currency collection
|
||||
// e.g. "1.2+300*$2" means "1200000000ng plus 300 units of currency #2"
|
||||
{ 0 swap dup "+" $pos dup 0< { drop dup
|
||||
$>GR? { nip nip dictnew true } { end-parse-cc } cond
|
||||
} { over swap $| swap $>GR? { 2swap 2drop swap 1 $| nip } { drop
|
||||
} cond end-parse-cc } cond
|
||||
} : $>cc?
|
||||
{ $>cc? not abort"invalid extra currency collection" } : $>cc
|
||||
{ char } word dup $len { $>cc } { drop dictnew } cond 1 'nop } ::_ CX{
|
||||
{ $>cc? not abort"invalid currency collection" } : $>cc
|
||||
{ char } word dup $len { $>cc } { drop 0 dictnew } cond 2 'nop } ::_ CC{
|
||||
// ( x D -- )
|
||||
{ swap ?dup { .GR_ .+cc_ } { .cc_ } cond } : .GR+cc_
|
||||
{ .GR+cc_ space } : .GR+cc
|
||||
{ -rot Gram, swap dict, } : Gram+cc,
|
||||
|
||||
// Libraries
|
||||
// ( -- D ) New empty library collection
|
||||
|
|
|
@ -2242,6 +2242,7 @@ std::vector<Ref<vm::Cell>> get_vm_libraries() {
|
|||
// +16 = load c7 (smart-contract context)
|
||||
// +32 = return c5 (actions)
|
||||
// +64 = log vm ops to stderr
|
||||
// +128 = pop hard gas limit (enabled by ACCEPT) from stack as well
|
||||
void interpret_run_vm(IntCtx& ctx, int mode) {
|
||||
if (mode < 0) {
|
||||
mode = ctx.stack.pop_smallint_range(0xff);
|
||||
|
@ -2249,7 +2250,13 @@ void interpret_run_vm(IntCtx& ctx, int mode) {
|
|||
bool with_data = mode & 4;
|
||||
Ref<vm::Tuple> c7;
|
||||
Ref<vm::Cell> data, actions;
|
||||
long long gas_max = (mode & 128) ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty;
|
||||
long long gas_limit = (mode & 8) ? ctx.stack.pop_long_range(vm::GasLimits::infty) : vm::GasLimits::infty;
|
||||
if (!(mode & 128)) {
|
||||
gas_max = gas_limit;
|
||||
} else {
|
||||
gas_max = std::max(gas_max, gas_limit);
|
||||
}
|
||||
if (mode & 16) {
|
||||
c7 = ctx.stack.pop_tuple();
|
||||
}
|
||||
|
@ -2259,7 +2266,7 @@ void interpret_run_vm(IntCtx& ctx, int mode) {
|
|||
auto cs = ctx.stack.pop_cellslice();
|
||||
OstreamLogger ostream_logger(ctx.error_stream);
|
||||
auto log = create_vm_log((mode & 64) && ctx.error_stream ? &ostream_logger : nullptr);
|
||||
vm::GasLimits gas{gas_limit};
|
||||
vm::GasLimits gas{gas_limit, gas_max};
|
||||
int res =
|
||||
vm::run_vm_code(cs, ctx.stack, mode & 3, &data, log, nullptr, &gas, get_vm_libraries(), std::move(c7), &actions);
|
||||
ctx.stack.push_smallint(res);
|
||||
|
|
|
@ -9,9 +9,11 @@ true =: allow-bounce
|
|||
false =: force-bounce
|
||||
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 =: timeout // external message expires in 60 seconds
|
||||
variable extra-currencies
|
||||
{ extra-currencies @ cc+ extra-currencies ! } : extra-cc+!
|
||||
|
||||
begin-options
|
||||
" <filename-base> <dest-addr> <seqno> <amount> [-n|-b] [-t<timeout>] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
|
||||
" <filename-base> <dest-addr> <seqno> <amount> [-x <extra-amount>*<extra-currency-id>] [-n|-b] [-t<timeout>] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
|
||||
+"Creates a request to advanced wallet created by new-wallet-v2.fif, with private key loaded from file <filename-base>.pk "
|
||||
+"and address from <filename-base>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)"
|
||||
disable-digit-options generic-help-setopt
|
||||
|
@ -19,6 +21,8 @@ begin-options
|
|||
"Clears bounce flag" option-help
|
||||
"b" "--force-bounce" { true =: force-bounce } short-long-option
|
||||
"Forces bounce flag" option-help
|
||||
"x" "--extra" { $>xcc extra-cc+! } short-long-option-arg
|
||||
"Indicates the amount of extra currencies to be transfered" option-help
|
||||
"t" "--timeout" { parse-int =: timeout } short-long-option-arg
|
||||
"Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help
|
||||
"B" "--body" { =: body-boc-file } short-long-option-arg
|
||||
|
@ -38,7 +42,7 @@ true constant bounce
|
|||
$1 =: file-base
|
||||
$2 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: dest_addr
|
||||
$3 parse-int =: seqno
|
||||
$4 $>GR =: amount
|
||||
$4 $>cc extra-cc+! extra-currencies @ 2=: amount
|
||||
$5 "wallet-query" replace-if-null =: savefile
|
||||
|
||||
file-base +".addr" load-address
|
||||
|
@ -49,13 +53,13 @@ file-base +".pk" load-keypair nip constant wallet_pk
|
|||
def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond
|
||||
constant body-cell
|
||||
|
||||
."Transferring " amount .GR ."to account "
|
||||
."Transferring " amount .GR+cc ."to account "
|
||||
dest_addr 2dup bounce 7 + .Addr ." = " .addr
|
||||
."seqno=0x" seqno x. ."bounce=" bounce . cr
|
||||
."Body of transfer message is " body-cell <s csr. cr
|
||||
|
||||
// create a message
|
||||
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram, 0 9 64 32 + + 1+ u,
|
||||
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram+cc, 0 9 64 32 + + u,
|
||||
body-cell <s 2dup 1 s-fits-with? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
|
||||
b>
|
||||
<b seqno 32 u, now timeout + 32 u, send-mode 8 u, swap ref, b>
|
||||
|
|
|
@ -9,9 +9,11 @@ true =: allow-bounce
|
|||
false =: force-bounce
|
||||
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
60 =: timeout // external message expires in 60 seconds
|
||||
variable extra-currencies
|
||||
{ extra-currencies @ cc+ extra-currencies ! } : extra-cc+!
|
||||
|
||||
begin-options
|
||||
" <filename-base> <dest-addr> <subwallet-id> <seqno> <amount> [-n|-b] [-t<timeout>] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
|
||||
" <filename-base> <dest-addr> <subwallet-id> <seqno> <amount> [-x <extra-amount>*<extra-currency-id>] [-n|-b] [-t<timeout>] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
|
||||
+"Creates a request to advanced wallet created by new-wallet-v3.fif, with private key loaded from file <filename-base>.pk "
|
||||
+"and address from <filename-base>.addr, and saves it into <savefile>.boc ('wallet-query.boc' by default)"
|
||||
disable-digit-options generic-help-setopt
|
||||
|
@ -19,6 +21,8 @@ begin-options
|
|||
"Clears bounce flag" option-help
|
||||
"b" "--force-bounce" { true =: force-bounce } short-long-option
|
||||
"Forces bounce flag" option-help
|
||||
"x" "--extra" { $>xcc extra-cc+! } short-long-option-arg
|
||||
"Indicates the amount of extra currencies to be transfered" option-help
|
||||
"t" "--timeout" { parse-int =: timeout } short-long-option-arg
|
||||
"Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help
|
||||
"B" "--body" { =: body-boc-file } short-long-option-arg
|
||||
|
@ -40,7 +44,7 @@ $1 =: file-base
|
|||
$2 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: dest_addr
|
||||
$3 parse-int =: subwallet_id
|
||||
$4 parse-int =: seqno
|
||||
$5 $>GR =: amount
|
||||
$5 $>cc extra-cc+! extra-currencies @ 2=: amount
|
||||
$6 "wallet-query" replace-if-null =: savefile
|
||||
|
||||
file-base +".addr" load-address
|
||||
|
@ -51,14 +55,14 @@ file-base +".pk" load-keypair nip constant wallet_pk
|
|||
def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond
|
||||
constant body-cell
|
||||
|
||||
."Transferring " amount .GR ."to account "
|
||||
."Transferring " amount .GR+cc ."to account "
|
||||
dest_addr 2dup bounce 7 + .Addr ." = " .addr
|
||||
."subwallet_id=0x" subwallet_id x.
|
||||
."seqno=0x" seqno x. ."bounce=" bounce . cr
|
||||
."Body of transfer message is " body-cell <s csr. cr
|
||||
|
||||
// create a message
|
||||
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram, 0 9 64 32 + + 1+ u,
|
||||
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram+cc, 0 9 64 32 + + u,
|
||||
body-cell <s 2dup 1 s-fits-with? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
|
||||
b>
|
||||
<b subwallet_id 32 u, now timeout + 32 u, seqno 32 u, send-mode 8 u, swap ref, b>
|
||||
|
|
|
@ -9,6 +9,7 @@ true =: allow-bounce
|
|||
false =: force-bounce
|
||||
3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors
|
||||
variable extra-currencies
|
||||
{ extra-currencies @ cc+ extra-currencies ! } : extra-cc+!
|
||||
|
||||
begin-options
|
||||
" <filename-base> <dest-addr> <seqno> <amount> [-x <extra-amount>*<extra-currency-id>] [-n|-b] [-B <body-boc>] [-C <comment>] [<savefile>]" +cr +tab
|
||||
|
@ -19,7 +20,7 @@ begin-options
|
|||
"Clears bounce flag" option-help
|
||||
"b" "--force-bounce" { true =: force-bounce } short-long-option
|
||||
"Forces bounce flag" option-help
|
||||
"x" "--extra" { $>cc extra-currencies @ cc+ extra-currencies ! } short-long-option-arg
|
||||
"x" "--extra" { $>xcc extra-cc+! } short-long-option-arg
|
||||
"Indicates the amount of extra currencies to be transfered" option-help
|
||||
"B" "--body" { =: body-boc-file } short-long-option-arg
|
||||
"Sets the payload of the transfer message" option-help
|
||||
|
@ -38,7 +39,7 @@ true =: bounce
|
|||
$1 =: file-base
|
||||
$2 bounce parse-load-address allow-bounce and force-bounce or =: bounce 2=: dest_addr
|
||||
$3 parse-int =: seqno
|
||||
$4 $>GR =: amount
|
||||
$4 $>cc extra-cc+! extra-currencies @ 2=: amount
|
||||
$5 "wallet-query" replace-if-null =: savefile
|
||||
allow-bounce not force-bounce and abort"cannot have bounce flag both set and cleared"
|
||||
// "" 1 { 69091 * 1+ 65535 and tuck 2521 / 65 + hold swap } 1000 times drop =: comment
|
||||
|
@ -51,13 +52,13 @@ file-base +".pk" load-keypair nip constant wallet_pk
|
|||
def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond
|
||||
constant body-cell
|
||||
|
||||
."Transferring " amount .GR_ extra-currencies @ .+cc ."to account "
|
||||
."Transferring " amount .GR+cc ."to account "
|
||||
dest_addr 2dup bounce 7 + .Addr ." = " .addr
|
||||
."seqno=0x" seqno x. ."bounce=" bounce . cr
|
||||
."Body of transfer message is " body-cell <s csr. cr
|
||||
|
||||
// create a message
|
||||
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram, extra-currencies @ dict, 0 9 64 32 + + u,
|
||||
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram+cc, 0 9 64 32 + + u,
|
||||
body-cell <s 2dup 1 s-fits-with? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
|
||||
b>
|
||||
<b seqno 32 u, send-mode 8 u, swap ref, b>
|
||||
|
|
20
crypto/test/fift/test-stack-copy.fif
Normal file
20
crypto/test/fift/test-stack-copy.fif
Normal file
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/fift -s
|
||||
"Asm.fif" include
|
||||
2500 =: N
|
||||
{ 5 * } : *K
|
||||
N 100 / =: N/100
|
||||
N 10 / =: N/10
|
||||
{ { EXECUTE } 100 times } : 100EXECUTE
|
||||
{ DUP { 2DUP } 7 times } : 15DUP
|
||||
{ { 2DUP } 50 times } : 100DUP
|
||||
{ { 15 -1 SETCONTARGS 15DUP } 10 times } : 10SET&DUP
|
||||
<{
|
||||
CONT:<{ }>
|
||||
15DUP
|
||||
N/10 INT REPEAT:<{ 10SET&DUP }>
|
||||
N/100 *K INT REPEAT:<{ 100DUP }>
|
||||
N/100 *K INT REPEAT:<{ 100EXECUTE }>
|
||||
}>s =: Code
|
||||
|
||||
Code csr.
|
||||
Code 1000000 gasrunvmcode
|
32
crypto/test/fift/testcc.fif
Normal file
32
crypto/test/fift/testcc.fif
Normal file
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/create-state -s
|
||||
{ dup tlb-type-lookup { nip } { "unknown TLB type " swap $+ abort } cond } : $>tlb
|
||||
{ bl word $>tlb 1 'nop } ::_ tlb:
|
||||
{ dup null? { drop true } {
|
||||
<b true 1 i, swap ref, b> <s ExtraCurrencyCollection
|
||||
tlb-validate-skip { empty? } { false } cond
|
||||
} cond
|
||||
} : cc-valid?
|
||||
{ cc-valid? { ."(valid)" } { ."(invalid)" } cond } : .cc-valid
|
||||
{ { dup .cc space .cc-valid } { ."<error>" } cond cr } : cshow
|
||||
{ ."X = " over dup .cc space .cc-valid cr
|
||||
."Y = " dup dup .cc space .cc-valid cr
|
||||
."X + Y = " 2dup CC+? cshow
|
||||
."X - Y = " 2dup CC-? cshow
|
||||
."Y - X = " 2dup swap CC-? cshow
|
||||
."X + X = " over dup CC+? cshow
|
||||
."Y + Y = " dup dup CC+? cshow
|
||||
."X - X = " over dup CC-? cshow
|
||||
."Y - Y = " dup dup CC-? cshow
|
||||
2drop ."********************" cr
|
||||
} : one-test
|
||||
CX{666666666666*$239+1000000000000*$-17} =: X
|
||||
X CX{666666666666*$239+4444*$-17} one-test
|
||||
X CX{666666666665*$239+4444*$-17} one-test
|
||||
X CX{666666666667*$239+4444*$-17} one-test
|
||||
X CX{666666666666*$239} one-test
|
||||
X CX{666666666665*$239} one-test
|
||||
X CX{666666666667*$239} one-test
|
||||
X CX{1111*$1} one-test
|
||||
X CX{0*$-17} one-test
|
||||
X cc0 1 0 +newccpair one-test
|
||||
X cc0 239 0 +newccpair one-test
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "vm/boc.h"
|
||||
#include "vm/cellslice.h"
|
||||
|
@ -694,6 +694,32 @@ TEST(TonDb, BenchCellBuilder3) {
|
|||
td::bench(BenchCellBuilder3());
|
||||
}
|
||||
|
||||
TEST(TonDb, BocFuzz) {
|
||||
vm::std_boc_deserialize(td::base64_decode("te6ccgEBAQEAAgAoAAA=").move_as_ok()).ensure_error();
|
||||
vm::std_boc_deserialize(td::base64_decode("te6ccgQBQQdQAAAAAAEAte6ccgQBB1BBAAAAAAEAAAAAAP/"
|
||||
"wAACJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJicmJiYmJiYmJiYmJiQ0NDQ0NDQ0NDQ0NDQ0ND"
|
||||
"Q0NiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiQAA//AAAO4=")
|
||||
.move_as_ok());
|
||||
vm::std_boc_deserialize(td::base64_decode("SEkh/w==").move_as_ok()).ensure_error();
|
||||
vm::std_boc_deserialize(
|
||||
td::base64_decode(
|
||||
"te6ccqwBMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMAKCEAAAAgAQ==")
|
||||
.move_as_ok())
|
||||
.ensure_error();
|
||||
}
|
||||
void test_parse_prefix(td::Slice boc) {
|
||||
for (size_t i = 0; i <= boc.size(); i++) {
|
||||
auto prefix = boc.substr(0, i);
|
||||
vm::BagOfCells::Info info;
|
||||
auto res = info.parse_serialized_header(prefix);
|
||||
if (res > 0) {
|
||||
break;
|
||||
}
|
||||
CHECK(res != 0);
|
||||
CHECK(-res > (int)i);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TonDb, Boc) {
|
||||
td::Random::Xorshift128plus rnd{123};
|
||||
for (int t = 0; t < 1000; t++) {
|
||||
|
@ -704,6 +730,8 @@ TEST(TonDb, Boc) {
|
|||
auto serialized = serialize_boc(std::move(cell), mode);
|
||||
CHECK(serialized.size() != 0);
|
||||
|
||||
test_parse_prefix(serialized);
|
||||
|
||||
auto loaded_cell = deserialize_boc(serialized);
|
||||
ASSERT_EQ(cell_hash, loaded_cell->get_hash());
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "fift/utils.h"
|
||||
#include "common/bigint.hpp"
|
||||
|
||||
#include "td/utils/base64.h"
|
||||
#include "td/utils/tests.h"
|
||||
#include "td/utils/ScopeGuard.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
@ -53,7 +54,10 @@ std::string run_vm(td::Ref<vm::Cell> cell) {
|
|||
|
||||
vm::Stack stack;
|
||||
try {
|
||||
vm::run_vm_code(vm::load_cell_slice_ref(cell), stack, 0 /*flags*/, nullptr /*data*/, std::move(log) /*VmLog*/);
|
||||
vm::GasLimits gas_limit(1000, 1000);
|
||||
|
||||
vm::run_vm_code(vm::load_cell_slice_ref(cell), stack, 0 /*flags*/, nullptr /*data*/, std::move(log) /*VmLog*/,
|
||||
nullptr, &gas_limit);
|
||||
} catch (...) {
|
||||
LOG(FATAL) << "catch unhandled exception";
|
||||
}
|
||||
|
@ -77,6 +81,14 @@ void test_run_vm(td::Slice code_hex) {
|
|||
test_run_vm(to_cell(buff, bits));
|
||||
}
|
||||
|
||||
void test_run_vm_raw(td::Slice code64) {
|
||||
auto code = td::base64_decode(code64).move_as_ok();
|
||||
if (code.size() > 127) {
|
||||
code.resize(127);
|
||||
}
|
||||
test_run_vm(vm::CellBuilder().store_bytes(code).finalize());
|
||||
}
|
||||
|
||||
TEST(VM, simple) {
|
||||
test_run_vm("ABCBABABABA");
|
||||
}
|
||||
|
@ -126,12 +138,12 @@ TEST(VM, unhandled_exception_1) {
|
|||
|
||||
TEST(VM, unhandled_exception_2) {
|
||||
// infinite loop now
|
||||
// test_run_vm("EBEDB4");
|
||||
test_run_vm("EBEDB4");
|
||||
}
|
||||
|
||||
TEST(VM, unhandled_exception_3) {
|
||||
// infinite loop now
|
||||
// test_run_vm("EBEDC0");
|
||||
test_run_vm("EBEDC0");
|
||||
}
|
||||
|
||||
TEST(VM, unhandled_exception_4) {
|
||||
|
@ -142,6 +154,13 @@ TEST(VM, unhandled_exception_5) {
|
|||
test_run_vm("738B04016D21F41476A721F49F");
|
||||
}
|
||||
|
||||
TEST(VM, infinity_loop_1) {
|
||||
test_run_vm_raw("f3r4AJGQ6rDraIQ=");
|
||||
}
|
||||
TEST(VM, infinity_loop_2) {
|
||||
test_run_vm_raw("kpTt7ZLrig==");
|
||||
}
|
||||
|
||||
TEST(VM, bigint) {
|
||||
td::StringBuilder sb({}, true);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
@ -94,10 +94,8 @@ td::Result<Ref<DataCell>> CellSerializationInfo::create_data_cell(td::Slice cell
|
|||
for (int k = 0; k < refs_cnt; k++) {
|
||||
cb.store_ref(std::move(refs[k]));
|
||||
}
|
||||
auto res = cb.finalize_novm(special);
|
||||
if (res.is_null()) {
|
||||
return td::Status::Error("CellBuilder::finalize failed");
|
||||
}
|
||||
TRY_RESULT(res, cb.finalize_novm_nothrow(special));
|
||||
CHECK(!res.is_null());
|
||||
if (res->is_special() != special) {
|
||||
return td::Status::Error("is_special mismatch");
|
||||
}
|
||||
|
@ -654,10 +652,10 @@ long long BagOfCells::Info::parse_serialized_header(const td::Slice& slice) {
|
|||
ptr += 6;
|
||||
sz -= 6;
|
||||
if (sz < ref_byte_size) {
|
||||
return -(int)roots_offset;
|
||||
return -static_cast<int>(roots_offset);
|
||||
}
|
||||
cell_count = (int)read_ref(ptr);
|
||||
if (cell_count < 0) {
|
||||
if (cell_count <= 0) {
|
||||
cell_count = -1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -671,7 +669,7 @@ long long BagOfCells::Info::parse_serialized_header(const td::Slice& slice) {
|
|||
}
|
||||
index_offset = roots_offset;
|
||||
if (magic == boc_generic) {
|
||||
index_offset += root_count * ref_byte_size;
|
||||
index_offset += (long long)root_count * ref_byte_size;
|
||||
has_roots = true;
|
||||
} else {
|
||||
if (root_count != 1) {
|
||||
|
@ -690,12 +688,18 @@ long long BagOfCells::Info::parse_serialized_header(const td::Slice& slice) {
|
|||
return 0;
|
||||
}
|
||||
if (sz < 3 * ref_byte_size + offset_byte_size) {
|
||||
return -(int)roots_offset;
|
||||
return -static_cast<int>(roots_offset);
|
||||
}
|
||||
data_size = read_offset(ptr + 3 * ref_byte_size);
|
||||
if (data_size > ((unsigned long long)cell_count << 10)) {
|
||||
return 0;
|
||||
}
|
||||
if (data_size > (1ull << 40)) {
|
||||
return 0; // bag of cells with more than 1TiB data is unlikely
|
||||
}
|
||||
if (data_size < cell_count * (2ull + ref_byte_size) - ref_byte_size) {
|
||||
return 0; // invalid header, too many cells for this amount of data bytes
|
||||
}
|
||||
valid = true;
|
||||
total_size = data_offset + data_size + (has_crc32c ? 4 : 0);
|
||||
return total_size;
|
||||
|
@ -747,14 +751,13 @@ td::Result<td::Ref<vm::DataCell>> BagOfCells::deserialize_cell(int idx, td::Slic
|
|||
return cell_info.create_data_cell(cell_slice, refs);
|
||||
}
|
||||
|
||||
td::Result<long long> BagOfCells::deserialize(const td::Slice& data) {
|
||||
td::Result<long long> BagOfCells::deserialize(const td::Slice& data, int max_roots) {
|
||||
clear();
|
||||
long long size_est = info.parse_serialized_header(data);
|
||||
//LOG(INFO) << "estimated size " << size_est << ", true size " << data.size();
|
||||
if (size_est == 0) {
|
||||
return td::Status::Error(PSLICE() << "cannot deserialize bag-of-cells: invalid header, error " << size_est);
|
||||
}
|
||||
|
||||
if (size_est < 0) {
|
||||
//LOG(ERROR) << "cannot deserialize bag-of-cells: not enough bytes (" << data.size() << " present, " << -size_est
|
||||
//<< " required)";
|
||||
|
@ -767,6 +770,9 @@ td::Result<long long> BagOfCells::deserialize(const td::Slice& data) {
|
|||
return -size_est;
|
||||
}
|
||||
//LOG(INFO) << "estimated size " << size_est << ", true size " << data.size();
|
||||
if (info.root_count > max_roots) {
|
||||
return td::Status::Error("Bag-of-cells has more root cells than expected");
|
||||
}
|
||||
if (info.has_crc32c) {
|
||||
unsigned crc_computed = td::crc32c(td::Slice{data.ubegin(), data.uend() - 4});
|
||||
unsigned crc_stored = td::as<unsigned>(data.uend() - 4);
|
||||
|
@ -906,7 +912,7 @@ td::Result<Ref<Cell>> std_boc_deserialize(td::Slice data, bool can_be_empty) {
|
|||
return Ref<Cell>();
|
||||
}
|
||||
BagOfCells boc;
|
||||
auto res = boc.deserialize(data);
|
||||
auto res = boc.deserialize(data, 1);
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
|
@ -923,12 +929,12 @@ td::Result<Ref<Cell>> std_boc_deserialize(td::Slice data, bool can_be_empty) {
|
|||
return std::move(root);
|
||||
}
|
||||
|
||||
td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi(td::Slice data) {
|
||||
td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi(td::Slice data, int max_roots) {
|
||||
if (data.empty()) {
|
||||
return std::vector<Ref<Cell>>{};
|
||||
}
|
||||
BagOfCells boc;
|
||||
auto res = boc.deserialize(data);
|
||||
auto res = boc.deserialize(data, max_roots);
|
||||
if (res.is_error()) {
|
||||
return res.move_as_error();
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include <set>
|
||||
|
@ -26,12 +26,6 @@
|
|||
namespace vm {
|
||||
using td::Ref;
|
||||
|
||||
td::Result<Ref<Cell>> std_boc_deserialize(td::Slice data, bool can_be_empty = false);
|
||||
td::Result<td::BufferSlice> std_boc_serialize(Ref<Cell> root, int mode = 0);
|
||||
|
||||
td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi(td::Slice data);
|
||||
td::Result<td::BufferSlice> std_boc_serialize_multi(std::vector<Ref<Cell>> root, int mode = 0);
|
||||
|
||||
class NewCellStorageStat {
|
||||
public:
|
||||
NewCellStorageStat() {
|
||||
|
@ -159,7 +153,7 @@ struct CellSerializationInfo {
|
|||
|
||||
class BagOfCells {
|
||||
public:
|
||||
enum { hash_bytes = vm::Cell::hash_bytes };
|
||||
enum { hash_bytes = vm::Cell::hash_bytes, default_max_roots = 16384 };
|
||||
enum Mode { WithIndex = 1, WithCRC32C = 2, WithTopHash = 4, WithIntHashes = 8, WithCacheBits = 16, max = 31 };
|
||||
enum { max_cell_whs = 64 };
|
||||
using Hash = Cell::Hash;
|
||||
|
@ -259,9 +253,10 @@ class BagOfCells {
|
|||
std::size_t serialize_to(unsigned char* buffer, std::size_t buff_size, int mode = 0);
|
||||
std::string extract_string() const;
|
||||
|
||||
td::Result<long long> deserialize(const td::Slice& data);
|
||||
td::Result<long long> deserialize(const unsigned char* buffer, std::size_t buff_size) {
|
||||
return deserialize(td::Slice{buffer, buff_size});
|
||||
td::Result<long long> deserialize(const td::Slice& data, int max_roots = default_max_roots);
|
||||
td::Result<long long> deserialize(const unsigned char* buffer, std::size_t buff_size,
|
||||
int max_roots = default_max_roots) {
|
||||
return deserialize(td::Slice{buffer, buff_size}, max_roots);
|
||||
}
|
||||
int get_root_count() const {
|
||||
return root_count;
|
||||
|
@ -311,4 +306,11 @@ class BagOfCells {
|
|||
std::vector<td::uint8>* cell_should_cache);
|
||||
};
|
||||
|
||||
td::Result<Ref<Cell>> std_boc_deserialize(td::Slice data, bool can_be_empty = false);
|
||||
td::Result<td::BufferSlice> std_boc_serialize(Ref<Cell> root, int mode = 0);
|
||||
|
||||
td::Result<std::vector<Ref<Cell>>> std_boc_deserialize_multi(td::Slice data,
|
||||
int max_roots = BagOfCells::default_max_roots);
|
||||
td::Result<td::BufferSlice> std_boc_serialize_multi(std::vector<Ref<Cell>> root, int mode = 0);
|
||||
|
||||
} // namespace vm
|
||||
|
|
|
@ -67,9 +67,14 @@ Ref<DataCell> CellBuilder::finalize_copy(bool special) const {
|
|||
return cell;
|
||||
}
|
||||
|
||||
Ref<DataCell> CellBuilder::finalize_novm(bool special) {
|
||||
td::Result<Ref<DataCell>> CellBuilder::finalize_novm_nothrow(bool special) {
|
||||
auto res = DataCell::create(data, size(), td::mutable_span(refs.data(), size_refs()), special);
|
||||
bits = refs_cnt = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
Ref<DataCell> CellBuilder::finalize_novm(bool special) {
|
||||
auto res = finalize_novm_nothrow(special);
|
||||
if (res.is_error()) {
|
||||
LOG(DEBUG) << res.error();
|
||||
throw CellWriteError{};
|
||||
|
@ -570,11 +575,11 @@ CellBuilder* CellBuilder::make_copy() const {
|
|||
return c;
|
||||
}
|
||||
|
||||
CellSlice CellBuilder::as_cellslice() const & {
|
||||
CellSlice CellBuilder::as_cellslice() const& {
|
||||
return CellSlice{finalize_copy()};
|
||||
}
|
||||
|
||||
Ref<CellSlice> CellBuilder::as_cellslice_ref() const & {
|
||||
Ref<CellSlice> CellBuilder::as_cellslice_ref() const& {
|
||||
return Ref<CellSlice>{true, finalize_copy()};
|
||||
}
|
||||
|
||||
|
|
|
@ -177,12 +177,13 @@ class CellBuilder : public td::CntObject {
|
|||
Ref<DataCell> finalize_copy(bool special = false) const;
|
||||
Ref<DataCell> finalize(bool special = false);
|
||||
Ref<DataCell> finalize_novm(bool special = false);
|
||||
td::Result<Ref<DataCell>> finalize_novm_nothrow(bool special = false);
|
||||
bool finalize_to(Ref<Cell>& res, bool special = false) {
|
||||
return (res = finalize(special)).not_null();
|
||||
}
|
||||
CellSlice as_cellslice() const &;
|
||||
CellSlice as_cellslice() const&;
|
||||
CellSlice as_cellslice() &&;
|
||||
Ref<CellSlice> as_cellslice_ref() const &;
|
||||
Ref<CellSlice> as_cellslice_ref() const&;
|
||||
Ref<CellSlice> as_cellslice_ref() &&;
|
||||
static td::int64 get_total_cell_builders() {
|
||||
return get_thread_safe_counter().sum();
|
||||
|
|
|
@ -492,6 +492,7 @@ int exec_setcontargs_common(VmState* st, int copy, int more) {
|
|||
} else {
|
||||
cdata->stack.write().move_from_stack(stack, copy);
|
||||
}
|
||||
st->consume_stack_gas(cdata->stack);
|
||||
if (cdata->nargs >= 0) {
|
||||
cdata->nargs -= copy;
|
||||
}
|
||||
|
@ -557,6 +558,7 @@ int exec_return_args_common(VmState* st, int count) {
|
|||
cdata->stack.write().move_from_stack(alt_stk.write(), copy);
|
||||
alt_stk.clear();
|
||||
}
|
||||
st->consume_stack_gas(cdata->stack);
|
||||
if (cdata->nargs >= 0) {
|
||||
cdata->nargs -= copy;
|
||||
}
|
||||
|
@ -587,6 +589,7 @@ int exec_bless_args_common(VmState* st, int copy, int more) {
|
|||
stack.check_underflow(copy + 1);
|
||||
auto cs = stack.pop_cellslice();
|
||||
auto new_stk = stack.split_top(copy);
|
||||
st->consume_stack_gas(new_stk);
|
||||
stack.push_cont(Ref<OrdCont>{true, std::move(cs), st->get_cp(), std::move(new_stk), more});
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -176,8 +176,10 @@ int VmState::call(Ref<Continuation> cont, int pass_args, int ret_args) {
|
|||
if (skip > 0) {
|
||||
get_stack().pop_many(skip);
|
||||
}
|
||||
consume_stack_gas(new_stk);
|
||||
} else if (copy >= 0) {
|
||||
new_stk = get_stack().split_top(copy, skip);
|
||||
consume_stack_gas(new_stk);
|
||||
} else {
|
||||
new_stk = std::move(stack);
|
||||
stack.clear();
|
||||
|
@ -196,7 +198,13 @@ int VmState::call(Ref<Continuation> cont, int pass_args, int ret_args) {
|
|||
throw VmError{Excno::stk_und, "stack underflow while calling a continuation: not enough arguments on stack"};
|
||||
}
|
||||
// create new stack from the top `pass_args` elements of the current stack
|
||||
Ref<Stack> new_stk = (pass_args >= 0 ? get_stack().split_top(pass_args) : std::move(stack));
|
||||
Ref<Stack> new_stk;
|
||||
if (pass_args >= 0) {
|
||||
new_stk = get_stack().split_top(pass_args);
|
||||
consume_stack_gas(new_stk);
|
||||
} else {
|
||||
new_stk = std::move(stack);
|
||||
}
|
||||
// create return continuation using the remainder of the current stack
|
||||
Ref<OrdCont> ret = Ref<OrdCont>{true, std::move(code), cp, std::move(stack), ret_args};
|
||||
ret.unique_write().get_cdata()->save.set_c0(std::move(cr.c[0]));
|
||||
|
@ -251,10 +259,12 @@ int VmState::jump(Ref<Continuation> cont, int pass_args) {
|
|||
new_stk = cont_data->stack;
|
||||
}
|
||||
new_stk.write().move_from_stack(get_stack(), copy);
|
||||
consume_stack_gas(new_stk);
|
||||
set_stack(std::move(new_stk));
|
||||
} else {
|
||||
if (copy >= 0) {
|
||||
if (copy >= 0 && copy < stack->depth()) {
|
||||
get_stack().drop_bottom(stack->depth() - copy);
|
||||
consume_stack_gas(copy);
|
||||
}
|
||||
}
|
||||
return jump_to(std::move(cont));
|
||||
|
@ -264,8 +274,10 @@ int VmState::jump(Ref<Continuation> cont, int pass_args) {
|
|||
int depth = get_stack().depth();
|
||||
if (pass_args > depth) {
|
||||
throw VmError{Excno::stk_und, "stack underflow while jumping to a continuation: not enough arguments on stack"};
|
||||
} else if (pass_args < depth) {
|
||||
get_stack().drop_bottom(depth - pass_args);
|
||||
consume_stack_gas(pass_args);
|
||||
}
|
||||
get_stack().drop_bottom(depth - pass_args);
|
||||
}
|
||||
return jump_to(std::move(cont));
|
||||
}
|
||||
|
@ -303,6 +315,7 @@ Ref<OrdCont> VmState::extract_cc(int save_cr, int stack_copy, int cc_args) {
|
|||
} else if (stack_copy > 0) {
|
||||
stack->check_underflow(stack_copy);
|
||||
new_stk = get_stack().split_top(stack_copy);
|
||||
consume_stack_gas(new_stk);
|
||||
} else {
|
||||
new_stk = Ref<Stack>{true};
|
||||
}
|
||||
|
@ -332,7 +345,7 @@ int VmState::throw_exception(int excno) {
|
|||
stack_ref.push_smallint(0);
|
||||
stack_ref.push_smallint(excno);
|
||||
code.clear();
|
||||
consume_gas(exception_gas_price);
|
||||
gas.consume_chk(exception_gas_price);
|
||||
return jump(get_c2());
|
||||
}
|
||||
|
||||
|
@ -342,7 +355,7 @@ int VmState::throw_exception(int excno, StackEntry&& arg) {
|
|||
stack_ref.push(std::move(arg));
|
||||
stack_ref.push_smallint(excno);
|
||||
code.clear();
|
||||
consume_gas(exception_gas_price);
|
||||
gas.consume_chk(exception_gas_price);
|
||||
return jump(get_c2());
|
||||
}
|
||||
|
||||
|
@ -403,7 +416,6 @@ int VmState::run() {
|
|||
int res;
|
||||
Guard guard(this);
|
||||
do {
|
||||
// LOG(INFO) << "[BS] data cells: " << DataCell::get_total_data_cells();
|
||||
try {
|
||||
try {
|
||||
try {
|
||||
|
@ -419,12 +431,10 @@ int VmState::run() {
|
|||
} catch (const VmError& vme) {
|
||||
VM_LOG(this) << "handling exception code " << vme.get_errno() << ": " << vme.get_msg();
|
||||
try {
|
||||
// LOG(INFO) << "[EX] data cells: " << DataCell::get_total_data_cells();
|
||||
++steps;
|
||||
res = throw_exception(vme.get_errno());
|
||||
} catch (const VmError& vme2) {
|
||||
VM_LOG(this) << "exception " << vme2.get_errno() << " while handling exception: " << vme.get_msg();
|
||||
// LOG(INFO) << "[EXX] data cells: " << DataCell::get_total_data_cells();
|
||||
return ~vme2.get_errno();
|
||||
}
|
||||
}
|
||||
|
@ -437,7 +447,6 @@ int VmState::run() {
|
|||
return vmoog.get_errno(); // no ~ for unhandled exceptions (to make their faking impossible)
|
||||
}
|
||||
} while (!res);
|
||||
// LOG(INFO) << "[EN] data cells: " << DataCell::get_total_data_cells();
|
||||
if ((res | 1) == -1 && !try_commit()) {
|
||||
VM_LOG(this) << "automatic commit failed (new data or action cells too deep)";
|
||||
get_stack().clear();
|
||||
|
|
|
@ -106,6 +106,8 @@ class VmState final : public VmStateInterface {
|
|||
tuple_entry_gas_price = 1,
|
||||
implicit_jmpref_gas_price = 10,
|
||||
implicit_ret_gas_price = 5,
|
||||
free_stack_depth = 32,
|
||||
stack_entry_gas_price = 1,
|
||||
max_data_depth = 512
|
||||
};
|
||||
VmState();
|
||||
|
@ -141,11 +143,19 @@ class VmState final : public VmStateInterface {
|
|||
void consume_tuple_gas(unsigned tuple_len) {
|
||||
consume_gas(tuple_len * tuple_entry_gas_price);
|
||||
}
|
||||
void consume_tuple_gas(const Ref<vm::Tuple>& tup) {
|
||||
void consume_tuple_gas(const Ref<Tuple>& tup) {
|
||||
if (tup.not_null()) {
|
||||
consume_tuple_gas((unsigned)tup->size());
|
||||
}
|
||||
}
|
||||
void consume_stack_gas(unsigned stack_depth) {
|
||||
consume_gas((std::max(stack_depth, (unsigned)free_stack_depth) - free_stack_depth) * stack_entry_gas_price);
|
||||
}
|
||||
void consume_stack_gas(const Ref<Stack>& stk) {
|
||||
if (stk.not_null()) {
|
||||
consume_stack_gas((unsigned)stk->depth());
|
||||
}
|
||||
}
|
||||
GasLimits get_gas_limits() const {
|
||||
return gas;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue