From dd4ac0f44083316a005c01e48fb81f3a64d5d79b Mon Sep 17 00:00:00 2001 From: ton Date: Fri, 28 Feb 2020 18:59:47 +0400 Subject: [PATCH] vm bugfixes --- crypto/block/block-parse.cpp | 16 +++++++------- crypto/block/block-parse.h | 20 +++++++++++++---- crypto/block/block.cpp | 2 +- crypto/block/create-state.cpp | 20 +++++++++++++++++ crypto/block/transaction.cpp | 14 ++++++++++-- crypto/fift/lib/TonUtil.fif | 41 ++++++++++++++++++++++++++++++----- crypto/smartcont/wallet.fif | 9 +++++--- validator/db/package.cpp | 3 ++- validator/impl/collator.cpp | 12 +++++----- 9 files changed, 107 insertions(+), 30 deletions(-) diff --git a/crypto/block/block-parse.cpp b/crypto/block/block-parse.cpp index a0322366..ae74fa38 100644 --- a/crypto/block/block-parse.cpp +++ b/crypto/block/block-parse.cpp @@ -500,8 +500,8 @@ bool HashmapE::add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice int n = root_type.n; vm::Dictionary dict1{vm::DictAdvance(), cs1, n}, dict2{vm::DictAdvance(), cs2, n}; const TLB& vt = root_type.value_type; - vm::Dictionary::simple_combine_func_t combine = [vt](vm::CellBuilder& cb, Ref cs1_ref, - Ref cs2_ref) -> bool { + vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref cs1_ref, + Ref cs2_ref) -> bool { if (!vt.add_values(cb, cs1_ref.write(), cs2_ref.write())) { throw CombineError{}; } @@ -514,8 +514,8 @@ bool HashmapE::add_values_ref(Ref& res, Ref arg1, Ref cs1_ref, - Ref cs2_ref) -> bool { + vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref cs1_ref, + Ref cs2_ref) -> bool { if (!vt.add_values(cb, cs1_ref.write(), cs2_ref.write())) { throw CombineError{}; } @@ -535,8 +535,8 @@ int HashmapE::sub_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& int n = root_type.n; vm::Dictionary dict1{vm::DictAdvance(), cs1, n}, dict2{vm::DictAdvance(), cs2, n}; const TLB& vt = root_type.value_type; - vm::Dictionary::simple_combine_func_t combine = [vt](vm::CellBuilder& cb, Ref cs1_ref, - Ref cs2_ref) -> bool { + vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref cs1_ref, + Ref cs2_ref) -> bool { int r = vt.sub_values(cb, cs1_ref.write(), cs2_ref.write()); if (r < 0) { throw CombineError{}; @@ -555,8 +555,8 @@ int HashmapE::sub_values_ref(Ref& res, Ref arg1, Ref cs1_ref, - Ref cs2_ref) -> bool { + vm::Dictionary::simple_combine_func_t combine = [&vt](vm::CellBuilder& cb, Ref cs1_ref, + Ref cs2_ref) -> bool { int r = vt.sub_values(cb, cs1_ref.write(), cs2_ref.write()); if (r < 0) { throw CombineError{}; diff --git a/crypto/block/block-parse.h b/crypto/block/block-parse.h index 95906311..e50535cb 100644 --- a/crypto/block/block-parse.h +++ b/crypto/block/block-parse.h @@ -68,6 +68,9 @@ struct VarUInteger final : TLB_Complex { bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override; unsigned precompute_integer_size(const td::BigInt256& value) const; unsigned precompute_integer_size(td::RefInt256 value) const; + std::ostream& print_type(std::ostream& os) const override { + return os << "(VarUInteger " << n << ")"; + } }; extern const VarUInteger t_VarUInteger_3, t_VarUInteger_7, t_VarUInteger_16, t_VarUInteger_32; @@ -82,6 +85,9 @@ struct VarUIntegerPos final : TLB_Complex { td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override; unsigned long long as_uint(const vm::CellSlice& cs) const override; bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "(VarUIntegerPos " << n << ")"; + } }; extern const VarUIntegerPos t_VarUIntegerPos_16, t_VarUIntegerPos_32; @@ -99,6 +105,9 @@ struct VarInteger final : TLB_Complex { return cb.store_zeroes_bool(ln); } bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "(VarInteger " << n << ")"; + } }; struct VarIntegerNz final : TLB_Complex { @@ -111,6 +120,9 @@ struct VarIntegerNz final : TLB_Complex { td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override; long long as_int(const vm::CellSlice& cs) const override; bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override; + std::ostream& print_type(std::ostream& os) const override { + return os << "(VarIntegerNz " << n << ")"; + } }; struct Unary final : TLB { @@ -312,8 +324,8 @@ struct MsgAddress final : TLB_Complex { extern const MsgAddress t_MsgAddress; struct ExtraCurrencyCollection final : TLB { - HashmapE dict_type; - ExtraCurrencyCollection() : dict_type(32, t_VarUIntegerPos_32) { + HashmapE dict_type, dict_type2; + ExtraCurrencyCollection() : dict_type(32, t_VarUIntegerPos_32), dict_type2(32, t_VarUInteger_32) { } int get_size(const vm::CellSlice& cs) const override { return dict_type.get_size(cs); @@ -328,13 +340,13 @@ struct ExtraCurrencyCollection final : TLB { return dict_type.add_values(cb, cs1, cs2); } int sub_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const override { - return dict_type.sub_values(cb, cs1, cs2); + return dict_type2.sub_values(cb, cs1, cs2); } bool add_values_ref(Ref& res, Ref arg1, Ref arg2) const { return dict_type.add_values_ref(res, std::move(arg1), std::move(arg2)); } int sub_values_ref(Ref& res, Ref arg1, Ref arg2) const { - return dict_type.sub_values_ref(res, std::move(arg1), std::move(arg2)); + return dict_type2.sub_values_ref(res, std::move(arg1), std::move(arg2)); } bool store_ref(vm::CellBuilder& cb, Ref arg) const { return dict_type.store_ref(cb, std::move(arg)); diff --git a/crypto/block/block.cpp b/crypto/block/block.cpp index d9d3c267..af05b324 100644 --- a/crypto/block/block.cpp +++ b/crypto/block/block.cpp @@ -1651,7 +1651,7 @@ bool sub_extra_currency(Ref extra1, Ref extra2, Ref= 0; } } diff --git a/crypto/block/create-state.cpp b/crypto/block/create-state.cpp index 5eb14528..024037e2 100644 --- a/crypto/block/create-state.cpp +++ b/crypto/block/create-state.cpp @@ -616,6 +616,24 @@ void interpret_is_workchain_descr(vm::Stack& stack) { stack.push_bool(block::gen::t_WorkchainDescr.validate_ref(std::move(cell))); } +void interpret_add_extra_currencies(vm::Stack& stack) { + Ref y = stack.pop_maybe_cell(), x = stack.pop_maybe_cell(), res; + bool ok = block::add_extra_currency(std::move(x), std::move(y), res); + if (ok) { + stack.push_maybe_cell(std::move(res)); + } + stack.push_bool(ok); +} + +void interpret_sub_extra_currencies(vm::Stack& stack) { + Ref y = stack.pop_maybe_cell(), x = stack.pop_maybe_cell(), res; + bool ok = block::sub_extra_currency(std::move(x), std::move(y), res); + if (ok) { + stack.push_maybe_cell(std::move(res)); + } + stack.push_bool(ok); +} + void init_words_custom(fift::Dictionary& d) { d.def_stack_word("verb@ ", interpret_get_verbosity); d.def_stack_word("verb! ", interpret_set_verbosity); @@ -631,6 +649,8 @@ void init_words_custom(fift::Dictionary& d) { d.def_stack_word("create_state ", interpret_create_state); d.def_stack_word("isShardState? ", interpret_is_shard_state); d.def_stack_word("isWorkchainDescr? ", interpret_is_workchain_descr); + d.def_stack_word("CC+? ", interpret_add_extra_currencies); + d.def_stack_word("CC-? ", interpret_sub_extra_currencies); } tlb::TypenameLookup tlb_dict; diff --git a/crypto/block/transaction.cpp b/crypto/block/transaction.cpp index 34abfff1..7c19bdcd 100644 --- a/crypto/block/transaction.cpp +++ b/crypto/block/transaction.cpp @@ -1555,9 +1555,17 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap, Ref new_extra; if (!block::sub_extra_currency(ap.remaining_balance.extra, req.extra, new_extra)) { - LOG(DEBUG) << "not enough extra currency to send with the message"; + LOG(DEBUG) << "not enough extra currency to send with the message: " + << block::CurrencyCollection{0, req.extra}.to_str() << " required, only " + << block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() << " available"; return skip_invalid ? 0 : 38; // not enough (extra) funds } + if (ap.remaining_balance.extra.not_null() || req.extra.not_null()) { + LOG(WARNING) << "subtracting extra currencies: " + << block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() << " minus " + << block::CurrencyCollection{0, req.extra}.to_str() << " equals " + << block::CurrencyCollection{0, new_extra}.to_str(); + } auto fwd_fee_mine = msg_prices.get_first_part(fwd_fee); auto fwd_fee_remain = fwd_fee - fwd_fee_mine; @@ -1691,7 +1699,9 @@ int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap, } } if (!block::sub_extra_currency(ap.remaining_balance.extra, reserve.extra, newc.extra)) { - LOG(DEBUG) << "not enough extra currency to reserve"; + LOG(DEBUG) << "not enough extra currency to reserve: " << block::CurrencyCollection{0, reserve.extra}.to_str() + << " required, only " << block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() + << " available"; if (mode & 2) { // TODO: process (mode & 2) correctly by setting res_extra := inf (reserve.extra, ap.remaining_balance.extra) } diff --git a/crypto/fift/lib/TonUtil.fif b/crypto/fift/lib/TonUtil.fif index 0e2155e1..3fdf1775 100644 --- a/crypto/fift/lib/TonUtil.fif +++ b/crypto/fift/lib/TonUtil.fif @@ -85,7 +85,8 @@ library TonUtil // TON Blockchain Fift Library // ( nanograms -- S ) { dup abs <# ' # 9 times char . hold #s rot sign #> nip -trailing0 } : (.GR) -{ (.GR) ."GR$" type space } : .GR +{ (.GR) ."GR$" type } : .GR_ +{ .GR_ space } : .GR // b x -- b' ( serializes a Gram amount ) { -1 { 1+ 2dup 8 * ufits } until @@ -105,19 +106,49 @@ nip -trailing0 } : (.GR) ' VarUInt32, : val, ' VarUInt32@ : val@ // d k v -- d' -{ cc -{ dup null? { ."(null) " drop } { val@ . } cond } dup : .maybeVarUInt32 : .val -{ cc-key-bits { swap 32 1<< rmod . ."-> " .val ."; " true } dictforeach drop cr } : .cc +{ dup null? { ."(null)" drop } { val@ ._ } cond } dup : .maybeVarUInt32 : .val +{ swap cc-key-bits { rot { ."+" } if .val ."*$" ._ true true } idictforeach drop } : (.cc) +{ false (.cc) { ."0" } ifnot } : .cc_ +{ .cc_ space } : .cc +{ true (.cc) } : .+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+ -{ null swap cc-key-bits { val@ pair swap cons true } dictforeach drop } : cc>list-rev +{ null swap cc-key-bits { val@ pair swap cons true } idictforeach drop } : cc>list-rev { cc>list-rev list-reverse } : cc>list forget val, forget val@ forget .val +// ( S -- x -1 or 0 ) +{ (number) dup 2 = { -rot 2drop } if 1 = } : int? +{ int? dup { drop dup 0< { drop false } { true } cond } if } : pos-int? +// ( S -- k v -1 or 0 ) Parses expression * or *$ +{ dup "*" $pos dup 0< { 2drop false } { + $| dup $len 2 < { 2drop false } { + 1 $| nip dup 1 $| swap "$" $= { swap } if drop + int? dup { over 32 fits { 2drop false } ifnot } if + not { drop false } { + swap pos-int? not { drop false } { + true + } cond } cond } cond } cond +} : cc-key-value? +// ( S -- D -1 or 0 ) Parses an extra currency collection +{ 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 +} : $>cc? +{ $>cc? not abort"invalid extra currency collection" } : $>cc +{ char } word dup $len { $>cc } { drop dictnew } cond 1 'nop } ::_ CX{ + // Libraries // ( -- D ) New empty library collection ' dictnew : Libs{ diff --git a/crypto/smartcont/wallet.fif b/crypto/smartcont/wallet.fif index d752476d..535a295b 100755 --- a/crypto/smartcont/wallet.fif +++ b/crypto/smartcont/wallet.fif @@ -8,9 +8,10 @@ true =: allow-bounce false =: force-bounce 3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors +variable extra-currencies begin-options - " [-n|-b] [-B ] [-C ] []" +cr +tab + " [-x *] [-n|-b] [-B ] [-C ] []" +cr +tab +"Creates a request to simple wallet created by new-wallet.fif, with private key loaded from file .pk " +"and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" disable-digit-options generic-help-setopt @@ -18,6 +19,8 @@ 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 + "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 "C" "--comment" { =: comment } short-long-option-arg @@ -48,13 +51,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_ extra-currencies @ .+cc ."to account " dest_addr 2dup bounce 7 + .Addr ." = " .addr ."seqno=0x" seqno x. ."bounce=" bounce . cr ."Body of transfer message is " body-cell diff --git a/validator/db/package.cpp b/validator/db/package.cpp index 87090738..cc699baa 100644 --- a/validator/db/package.cpp +++ b/validator/db/package.cpp @@ -95,7 +95,8 @@ td::Result> Package::read(td::uint64 off return td::Status::Error(ErrorCode::notready, "too short read"); } if ((header[0] & 0xffff) != entry_header_magic()) { - return td::Status::Error(ErrorCode::notready, "bad entry magic"); + return td::Status::Error(ErrorCode::notready, + PSTRING() << "bad entry magic " << (header[0] & 0xffff) << " offset=" << offset); } offset += 8; auto fname_size = header[0] >> 16; diff --git a/validator/impl/collator.cpp b/validator/impl/collator.cpp index 0961cb04..efe356aa 100644 --- a/validator/impl/collator.cpp +++ b/validator/impl/collator.cpp @@ -1628,7 +1628,7 @@ bool Collator::do_collate() { return fatal_error("cannot compute the value to be created / minted / recovered"); } // 2. tick transactions - LOG(DEBUG) << "create tick transactions"; + LOG(INFO) << "create tick transactions"; if (!create_ticktock_transactions(2)) { return fatal_error("cannot generate tick transactions"); } @@ -1642,18 +1642,18 @@ bool Collator::do_collate() { // ... } // 4. import inbound internal messages, process or transit - LOG(DEBUG) << "process inbound internal messages"; + LOG(INFO) << "process inbound internal messages"; if (!process_inbound_internal_messages()) { return fatal_error("cannot process inbound internal messages"); } // 5. import inbound external messages (if space&gas left) - LOG(DEBUG) << "process inbound external messages"; + LOG(INFO) << "process inbound external messages"; if (!process_inbound_external_messages()) { return fatal_error("cannot process inbound external messages"); } // 6. process newly-generated messages (if space&gas left) // (if we were unable to process all inbound messages, all new messages must be queued) - LOG(DEBUG) << "process newly-generated messages"; + LOG(INFO) << "process newly-generated messages"; if (!process_new_messages(!inbound_queues_empty_)) { return fatal_error("cannot process newly-generated outbound messages"); } @@ -1664,12 +1664,12 @@ bool Collator::do_collate() { // ... } // 8. tock transactions - LOG(DEBUG) << "create tock transactions"; + LOG(INFO) << "create tock transactions"; if (!create_ticktock_transactions(1)) { return fatal_error("cannot generate tock transactions"); } // 9. process newly-generated messages (only by including them into output queue) - LOG(DEBUG) << "enqueue newly-generated messages"; + LOG(INFO) << "enqueue newly-generated messages"; if (!process_new_messages(true)) { return fatal_error("cannot process newly-generated outbound messages"); }