mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated vm (breaking compatibility)
- updated vm - new actor scheduler - updated tonlib - updated DNS smartcontract
This commit is contained in:
parent
9e4816e7f6
commit
e27fb1e09c
100 changed files with 3692 additions and 1299 deletions
|
@ -519,7 +519,7 @@ if (NOT TON_ONLY_TONLIB)
|
|||
add_test(test-adnl test-adnl)
|
||||
add_test(test-dht test-dht)
|
||||
add_test(test-rldp test-rldp)
|
||||
add_test(test-validator-session-state test-validator-session-state)
|
||||
#add_test(test-validator-session-state test-validator-session-state)
|
||||
add_test(test-catchain test-catchain)
|
||||
|
||||
add_test(test-fec test-fec)
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/int_types.h"
|
||||
|
|
|
@ -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 "td/utils/bits.h"
|
||||
#include "block/block-parse.h"
|
||||
|
@ -80,7 +80,7 @@ bool Maybe_Anycast::skip_get_depth(vm::CellSlice& cs, int& depth) const {
|
|||
|
||||
const Maybe_Anycast t_Maybe_Anycast;
|
||||
|
||||
bool MsgAddressInt::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool MsgAddressInt::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
if (!cs.have(3)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -265,14 +265,14 @@ Ref<vm::CellSlice> MsgAddressInt::pack_std_address(ton::WorkchainId workchain, c
|
|||
|
||||
const MsgAddressInt t_MsgAddressInt;
|
||||
|
||||
bool MsgAddress::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool MsgAddress::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
switch (get_tag(cs)) {
|
||||
case addr_none:
|
||||
case addr_ext:
|
||||
return t_MsgAddressExt.validate_skip(cs, weak);
|
||||
return t_MsgAddressExt.validate_skip(ops, cs, weak);
|
||||
case addr_std:
|
||||
case addr_var:
|
||||
return t_MsgAddressInt.validate_skip(cs, weak);
|
||||
return t_MsgAddressInt.validate_skip(ops, cs, weak);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ bool VarUInteger::skip(vm::CellSlice& cs) const {
|
|||
return len >= 0 && len < n && cs.advance(len * 8);
|
||||
}
|
||||
|
||||
bool VarUInteger::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool VarUInteger::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
int len = (int)cs.fetch_ulong(ln);
|
||||
return len >= 0 && len < n && (!len || cs.prefetch_ulong(8)) && cs.advance(len * 8);
|
||||
}
|
||||
|
@ -325,7 +325,7 @@ bool VarUIntegerPos::skip(vm::CellSlice& cs) const {
|
|||
return len > 0 && len < n && cs.advance(len * 8);
|
||||
}
|
||||
|
||||
bool VarUIntegerPos::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool VarUIntegerPos::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
int len = (int)cs.fetch_ulong(ln);
|
||||
return len > 0 && len < n && cs.prefetch_ulong(8) && cs.advance(len * 8);
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ bool VarInteger::skip(vm::CellSlice& cs) const {
|
|||
return len >= 0 && len < n && cs.advance(len * 8);
|
||||
}
|
||||
|
||||
bool VarInteger::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool VarInteger::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
int len = (int)cs.fetch_ulong(ln);
|
||||
return len >= 0 && len < n && (!len || !redundant_int(cs)) && cs.advance(len * 8);
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ bool VarIntegerNz::skip(vm::CellSlice& cs) const {
|
|||
return len > 0 && len < n && cs.advance(len * 8);
|
||||
}
|
||||
|
||||
bool VarIntegerNz::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool VarIntegerNz::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
int len = (int)cs.fetch_ulong(ln);
|
||||
return len > 0 && len < n && !redundant_int(cs) && cs.advance(len * 8);
|
||||
}
|
||||
|
@ -409,8 +409,8 @@ bool VarIntegerNz::store_integer_value(vm::CellBuilder& cb, const td::BigInt256&
|
|||
cb.store_int256_bool(value, (k + 7) & -8, true);
|
||||
}
|
||||
|
||||
bool Grams::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_VarUInteger_16.validate_skip(cs, weak);
|
||||
bool Grams::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_VarUInteger_16.validate_skip(ops, cs, weak);
|
||||
}
|
||||
|
||||
td::RefInt256 Grams::as_integer_skip(vm::CellSlice& cs) const {
|
||||
|
@ -464,15 +464,15 @@ bool HashmapNode::skip(vm::CellSlice& cs) const {
|
|||
return n ? cs.advance_refs(2) : value_type.skip(cs);
|
||||
}
|
||||
|
||||
bool HashmapNode::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool HashmapNode::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
assert(n >= 0);
|
||||
if (!n) {
|
||||
// hmn_leaf
|
||||
return value_type.validate_skip(cs, weak);
|
||||
return value_type.validate_skip(ops, cs, weak);
|
||||
} else {
|
||||
// hmn_fork
|
||||
Hashmap branch_type{n - 1, value_type};
|
||||
return branch_type.validate_ref(cs.fetch_ref(), weak) && branch_type.validate_ref(cs.fetch_ref(), weak);
|
||||
return branch_type.validate_ref(ops, cs.fetch_ref(), weak) && branch_type.validate_ref(ops, cs.fetch_ref(), weak);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,9 +481,9 @@ bool Hashmap::skip(vm::CellSlice& cs) const {
|
|||
return HmLabel{n}.skip(cs, l) && HashmapNode{n - l, value_type}.skip(cs);
|
||||
}
|
||||
|
||||
bool Hashmap::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool Hashmap::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
int l;
|
||||
return HmLabel{n}.validate_skip(cs, weak, l) && HashmapNode{n - l, value_type}.validate_skip(cs, weak);
|
||||
return HmLabel{n}.validate_skip(cs, weak, l) && HashmapNode{n - l, value_type}.validate_skip(ops, cs, weak);
|
||||
}
|
||||
|
||||
int HashmapE::get_size(const vm::CellSlice& cs) const {
|
||||
|
@ -491,9 +491,9 @@ int HashmapE::get_size(const vm::CellSlice& cs) const {
|
|||
return (tag >= 0 ? (tag > 0 ? 0x10001 : 1) : -1);
|
||||
}
|
||||
|
||||
bool HashmapE::validate(const vm::CellSlice& cs, bool weak) const {
|
||||
bool HashmapE::validate(int* ops, const vm::CellSlice& cs, bool weak) const {
|
||||
int tag = get_tag(cs);
|
||||
return tag <= 0 ? !tag : root_type.validate_ref(cs.prefetch_ref(), weak);
|
||||
return tag <= 0 ? !tag : root_type.validate_ref(ops, cs.prefetch_ref(), weak);
|
||||
}
|
||||
|
||||
bool HashmapE::add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const {
|
||||
|
@ -583,8 +583,8 @@ bool HashmapE::store_ref(vm::CellBuilder& cb, Ref<vm::Cell> arg) const {
|
|||
|
||||
const ExtraCurrencyCollection t_ExtraCurrencyCollection;
|
||||
|
||||
bool CurrencyCollection::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_Grams.validate_skip(cs, weak) && t_ExtraCurrencyCollection.validate_skip(cs, weak);
|
||||
bool CurrencyCollection::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_Grams.validate_skip(ops, cs, weak) && t_ExtraCurrencyCollection.validate_skip(ops, cs, weak);
|
||||
}
|
||||
|
||||
bool CurrencyCollection::skip(vm::CellSlice& cs) const {
|
||||
|
@ -641,25 +641,25 @@ bool CurrencyCollection::pack(vm::CellBuilder& cb, const block::CurrencyCollecti
|
|||
|
||||
const CurrencyCollection t_CurrencyCollection;
|
||||
|
||||
bool CommonMsgInfo::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool CommonMsgInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
int tag = get_tag(cs);
|
||||
switch (tag) {
|
||||
case int_msg_info:
|
||||
return cs.advance(4) // int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
|
||||
&& t_MsgAddressInt.validate_skip(cs, weak) // src
|
||||
&& t_MsgAddressInt.validate_skip(cs, weak) // dest
|
||||
&& t_CurrencyCollection.validate_skip(cs, weak) // value
|
||||
&& t_Grams.validate_skip(cs, weak) // ihr_fee
|
||||
&& t_Grams.validate_skip(cs, weak) // fwd_fee
|
||||
&& cs.advance(64 + 32); // created_lt:uint64 created_at:uint32
|
||||
return cs.advance(4) // int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
|
||||
&& t_MsgAddressInt.validate_skip(ops, cs, weak) // src
|
||||
&& t_MsgAddressInt.validate_skip(ops, cs, weak) // dest
|
||||
&& t_CurrencyCollection.validate_skip(ops, cs, weak) // value
|
||||
&& t_Grams.validate_skip(ops, cs, weak) // ihr_fee
|
||||
&& t_Grams.validate_skip(ops, cs, weak) // fwd_fee
|
||||
&& cs.advance(64 + 32); // created_lt:uint64 created_at:uint32
|
||||
case ext_in_msg_info:
|
||||
return cs.advance(2) && t_MsgAddressExt.validate_skip(cs, weak) // src
|
||||
&& t_MsgAddressInt.validate_skip(cs, weak) // dest
|
||||
&& t_Grams.validate_skip(cs, weak); // import_fee
|
||||
return cs.advance(2) && t_MsgAddressExt.validate_skip(ops, cs, weak) // src
|
||||
&& t_MsgAddressInt.validate_skip(ops, cs, weak) // dest
|
||||
&& t_Grams.validate_skip(ops, cs, weak); // import_fee
|
||||
case ext_out_msg_info:
|
||||
return cs.advance(2) && t_MsgAddressInt.validate_skip(cs, weak) // src
|
||||
&& t_MsgAddressExt.validate_skip(cs, weak) // dest
|
||||
&& cs.advance(64 + 32); // created_lt:uint64 created_at:uint32
|
||||
return cs.advance(2) && t_MsgAddressInt.validate_skip(ops, cs, weak) // src
|
||||
&& t_MsgAddressExt.validate_skip(ops, cs, weak) // dest
|
||||
&& cs.advance(64 + 32); // created_lt:uint64 created_at:uint32
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -721,28 +721,29 @@ const CommonMsgInfo t_CommonMsgInfo;
|
|||
const TickTock t_TickTock;
|
||||
const RefAnything t_RefCell;
|
||||
|
||||
bool StateInit::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return Maybe<UInt>{5}.validate_skip(cs, weak) // split_depth:(Maybe (## 5))
|
||||
&& Maybe<TickTock>{}.validate_skip(cs, weak) // special:(Maybe TickTock)
|
||||
&& Maybe<RefAnything>{}.validate_skip(cs, weak) // code:(Maybe ^Cell)
|
||||
&& Maybe<RefAnything>{}.validate_skip(cs, weak) // data:(Maybe ^Cell)
|
||||
&& Maybe<RefAnything>{}.validate_skip(cs, weak); // library:(Maybe ^Cell)
|
||||
bool StateInit::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return Maybe<UInt>{5}.validate_skip(ops, cs, weak) // split_depth:(Maybe (## 5))
|
||||
&& Maybe<TickTock>{}.validate_skip(ops, cs, weak) // special:(Maybe TickTock)
|
||||
&& Maybe<RefAnything>{}.validate_skip(ops, cs, weak) // code:(Maybe ^Cell)
|
||||
&& Maybe<RefAnything>{}.validate_skip(ops, cs, weak) // data:(Maybe ^Cell)
|
||||
&& Maybe<RefAnything>{}.validate_skip(ops, cs, weak); // library:(Maybe ^Cell)
|
||||
}
|
||||
|
||||
bool StateInit::get_ticktock(vm::CellSlice& cs, int& ticktock) const {
|
||||
bool have_tt;
|
||||
ticktock = 0;
|
||||
return Maybe<UInt>{5}.validate_skip(cs) && cs.fetch_bool_to(have_tt) && (!have_tt || cs.fetch_uint_to(2, ticktock));
|
||||
return Maybe<UInt>{5}.validate_skip_upto(1, cs) && cs.fetch_bool_to(have_tt) &&
|
||||
(!have_tt || cs.fetch_uint_to(2, ticktock));
|
||||
}
|
||||
|
||||
const StateInit t_StateInit;
|
||||
|
||||
bool Message::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool Message::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
static const Maybe<Either<StateInit, RefTo<StateInit>>> init_type;
|
||||
static const Either<Anything, RefAnything> body_type;
|
||||
return t_CommonMsgInfo.validate_skip(cs, weak) // info:CommonMsgInfo
|
||||
&& init_type.validate_skip(cs, weak) // init:(Maybe (Either StateInit ^StateInit))
|
||||
&& body_type.validate_skip(cs, weak); // body:(Either X ^X)
|
||||
return t_CommonMsgInfo.validate_skip(ops, cs, weak) // info:CommonMsgInfo
|
||||
&& init_type.validate_skip(ops, cs, weak) // init:(Maybe (Either StateInit ^StateInit))
|
||||
&& body_type.validate_skip(ops, cs, weak); // body:(Either X ^X)
|
||||
}
|
||||
|
||||
bool Message::extract_info(vm::CellSlice& cs) const {
|
||||
|
@ -760,7 +761,7 @@ bool Message::is_internal(Ref<vm::Cell> ref) const {
|
|||
const Message t_Message;
|
||||
const RefTo<Message> t_Ref_Message;
|
||||
|
||||
bool IntermediateAddress::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool IntermediateAddress::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
switch (get_tag(cs)) {
|
||||
case interm_addr_regular:
|
||||
return cs.advance(1) && cs.fetch_ulong(7) <= 96U;
|
||||
|
@ -795,12 +796,12 @@ int IntermediateAddress::get_size(const vm::CellSlice& cs) const {
|
|||
|
||||
const IntermediateAddress t_IntermediateAddress;
|
||||
|
||||
bool MsgEnvelope::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return cs.fetch_ulong(4) == 4 // msg_envelope#4
|
||||
&& t_IntermediateAddress.validate_skip(cs, weak) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.validate_skip(cs, weak) // next_addr:IntermediateAddress
|
||||
&& t_Grams.validate_skip(cs, weak) // fwd_fee_remaining:Grams
|
||||
&& t_Ref_Message.validate_skip(cs, weak); // msg:^Message
|
||||
bool MsgEnvelope::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return cs.fetch_ulong(4) == 4 // msg_envelope#4
|
||||
&& t_IntermediateAddress.validate_skip(ops, cs, weak) // cur_addr:IntermediateAddress
|
||||
&& t_IntermediateAddress.validate_skip(ops, cs, weak) // next_addr:IntermediateAddress
|
||||
&& t_Grams.validate_skip(ops, cs, weak) // fwd_fee_remaining:Grams
|
||||
&& t_Ref_Message.validate_skip(ops, cs, weak); // msg:^Message
|
||||
}
|
||||
|
||||
bool MsgEnvelope::skip(vm::CellSlice& cs) const {
|
||||
|
@ -849,10 +850,10 @@ bool MsgEnvelope::get_created_lt(const vm::CellSlice& cs, unsigned long long& cr
|
|||
const MsgEnvelope t_MsgEnvelope;
|
||||
const RefTo<MsgEnvelope> t_Ref_MsgEnvelope;
|
||||
|
||||
bool StorageUsed::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_VarUInteger_7.validate_skip(cs, weak) // cells:(VarUInteger 7)
|
||||
&& t_VarUInteger_7.validate_skip(cs, weak) // bits:(VarUInteger 7)
|
||||
&& t_VarUInteger_7.validate_skip(cs, weak); // public_cells:(VarUInteger 7)
|
||||
bool StorageUsed::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_VarUInteger_7.validate_skip(ops, cs, weak) // cells:(VarUInteger 7)
|
||||
&& t_VarUInteger_7.validate_skip(ops, cs, weak) // bits:(VarUInteger 7)
|
||||
&& t_VarUInteger_7.validate_skip(ops, cs, weak); // public_cells:(VarUInteger 7)
|
||||
}
|
||||
|
||||
bool StorageUsed::skip(vm::CellSlice& cs) const {
|
||||
|
@ -863,9 +864,9 @@ bool StorageUsed::skip(vm::CellSlice& cs) const {
|
|||
|
||||
const StorageUsed t_StorageUsed;
|
||||
|
||||
bool StorageUsedShort::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_VarUInteger_7.validate_skip(cs, weak) // cells:(VarUInteger 7)
|
||||
&& t_VarUInteger_7.validate_skip(cs, weak); // bits:(VarUInteger 7)
|
||||
bool StorageUsedShort::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_VarUInteger_7.validate_skip(ops, cs, weak) // cells:(VarUInteger 7)
|
||||
&& t_VarUInteger_7.validate_skip(ops, cs, weak); // bits:(VarUInteger 7)
|
||||
}
|
||||
|
||||
bool StorageUsedShort::skip(vm::CellSlice& cs) const {
|
||||
|
@ -883,22 +884,22 @@ bool StorageInfo::skip(vm::CellSlice& cs) const {
|
|||
&& t_Maybe_Grams.skip(cs); // due_payment:(Maybe Grams)
|
||||
}
|
||||
|
||||
bool StorageInfo::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_StorageUsed.validate_skip(cs, weak) // used:StorageUsed
|
||||
&& cs.advance(32) // last_paid:uint32
|
||||
&& t_Maybe_Grams.validate_skip(cs, weak); // due_payment:(Maybe Grams)
|
||||
bool StorageInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_StorageUsed.validate_skip(ops, cs, weak) // used:StorageUsed
|
||||
&& cs.advance(32) // last_paid:uint32
|
||||
&& t_Maybe_Grams.validate_skip(ops, cs, weak); // due_payment:(Maybe Grams)
|
||||
}
|
||||
|
||||
const StorageInfo t_StorageInfo;
|
||||
|
||||
bool AccountState::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool AccountState::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
switch (get_tag(cs)) {
|
||||
case account_uninit:
|
||||
return cs.advance(2);
|
||||
case account_frozen:
|
||||
return cs.advance(2 + 256);
|
||||
case account_active:
|
||||
return cs.advance(1) && t_StateInit.validate_skip(cs, weak);
|
||||
return cs.advance(1) && t_StateInit.validate_skip(ops, cs, weak);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -921,8 +922,9 @@ bool AccountStorage::skip_copy_balance(vm::CellBuilder& cb, vm::CellSlice& cs) c
|
|||
return cs.advance(64) && t_CurrencyCollection.skip_copy(cb, cs) && t_AccountState.skip(cs);
|
||||
}
|
||||
|
||||
bool AccountStorage::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return cs.advance(64) && t_CurrencyCollection.validate_skip(cs, weak) && t_AccountState.validate_skip(cs, weak);
|
||||
bool AccountStorage::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return cs.advance(64) && t_CurrencyCollection.validate_skip(ops, cs, weak) &&
|
||||
t_AccountState.validate_skip(ops, cs, weak);
|
||||
}
|
||||
|
||||
const AccountStorage t_AccountStorage;
|
||||
|
@ -940,15 +942,15 @@ bool Account::skip(vm::CellSlice& cs) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Account::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool Account::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
switch (get_tag(cs)) {
|
||||
case account_none:
|
||||
return allow_empty && cs.advance(1);
|
||||
case account:
|
||||
return cs.advance(1) // account$1
|
||||
&& t_MsgAddressInt.validate_skip(cs, weak) // addr:MsgAddressInt
|
||||
&& t_StorageInfo.validate_skip(cs, weak) // storage_stat:StorageInfo
|
||||
&& t_AccountStorage.validate_skip(cs, weak); // storage:AccountStorage
|
||||
return cs.advance(1) // account$1
|
||||
&& t_MsgAddressInt.validate_skip(ops, cs, weak) // addr:MsgAddressInt
|
||||
&& t_StorageInfo.validate_skip(ops, cs, weak) // storage_stat:StorageInfo
|
||||
&& t_AccountStorage.validate_skip(ops, cs, weak); // storage:AccountStorage
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1032,19 +1034,19 @@ bool HashmapAugNode::skip(vm::CellSlice& cs) const {
|
|||
}
|
||||
}
|
||||
|
||||
bool HashmapAugNode::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool HashmapAugNode::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
if (n < 0) {
|
||||
return false;
|
||||
}
|
||||
if (!n) {
|
||||
// ahmn_leaf
|
||||
vm::CellSlice cs_extra{cs};
|
||||
if (!aug.extra_type.validate_skip(cs, weak)) {
|
||||
if (!aug.extra_type.validate_skip(ops, cs, weak)) {
|
||||
return false;
|
||||
}
|
||||
cs_extra.cut_tail(cs);
|
||||
vm::CellSlice cs_value{cs};
|
||||
if (!aug.value_type.validate_skip(cs, weak)) {
|
||||
if (!aug.value_type.validate_skip(ops, cs, weak)) {
|
||||
return false;
|
||||
}
|
||||
cs_value.cut_tail(cs);
|
||||
|
@ -1055,13 +1057,14 @@ bool HashmapAugNode::validate_skip(vm::CellSlice& cs, bool weak) const {
|
|||
return false;
|
||||
}
|
||||
HashmapAug branch_type{n - 1, aug};
|
||||
if (!branch_type.validate_ref(cs.prefetch_ref(0), weak) || !branch_type.validate_ref(cs.prefetch_ref(1), weak)) {
|
||||
if (!branch_type.validate_ref(ops, cs.prefetch_ref(0), weak) ||
|
||||
!branch_type.validate_ref(ops, cs.prefetch_ref(1), weak)) {
|
||||
return false;
|
||||
}
|
||||
auto cs_left = load_cell_slice(cs.fetch_ref());
|
||||
auto cs_right = load_cell_slice(cs.fetch_ref());
|
||||
vm::CellSlice cs_extra{cs};
|
||||
if (!aug.extra_type.validate_skip(cs, weak)) {
|
||||
if (!aug.extra_type.validate_skip(ops, cs, weak)) {
|
||||
return false;
|
||||
}
|
||||
cs_extra.cut_tail(cs);
|
||||
|
@ -1074,9 +1077,9 @@ bool HashmapAug::skip(vm::CellSlice& cs) const {
|
|||
return HmLabel{n}.skip(cs, l) && HashmapAugNode{n - l, aug}.skip(cs);
|
||||
}
|
||||
|
||||
bool HashmapAug::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool HashmapAug::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
int l;
|
||||
return HmLabel{n}.validate_skip(cs, weak, l) && HashmapAugNode{n - l, aug}.validate_skip(cs, weak);
|
||||
return HmLabel{n}.validate_skip(cs, weak, l) && HashmapAugNode{n - l, aug}.validate_skip(ops, cs, weak);
|
||||
}
|
||||
|
||||
bool HashmapAug::extract_extra(vm::CellSlice& cs) const {
|
||||
|
@ -1084,20 +1087,20 @@ bool HashmapAug::extract_extra(vm::CellSlice& cs) const {
|
|||
return HmLabel{n}.skip(cs, l) && (l == n || cs.advance_refs(2)) && aug.extra_type.extract(cs);
|
||||
}
|
||||
|
||||
bool HashmapAugE::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool HashmapAugE::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
Ref<vm::CellSlice> extra;
|
||||
switch (get_tag(cs)) {
|
||||
case ahme_empty:
|
||||
return cs.advance(1) && (extra = root_type.aug.extra_type.validate_fetch(cs, weak)).not_null() &&
|
||||
return cs.advance(1) && (extra = root_type.aug.extra_type.validate_fetch(ops, cs, weak)).not_null() &&
|
||||
root_type.aug.check_empty(extra.unique_write());
|
||||
case ahme_root:
|
||||
if (cs.advance(1) && root_type.validate_ref(cs.prefetch_ref(), weak)) {
|
||||
if (cs.advance(1) && root_type.validate_ref(ops, cs.prefetch_ref(), weak)) {
|
||||
bool special;
|
||||
auto cs_root = load_cell_slice_special(cs.fetch_ref(), special);
|
||||
if (special) {
|
||||
return weak;
|
||||
}
|
||||
return (extra = root_type.aug.extra_type.validate_fetch(cs, weak)).not_null() &&
|
||||
return (extra = root_type.aug.extra_type.validate_fetch(ops, cs, weak)).not_null() &&
|
||||
root_type.extract_extra(cs_root) && extra->contents_equal(cs_root);
|
||||
}
|
||||
break;
|
||||
|
@ -1121,9 +1124,10 @@ bool DepthBalanceInfo::skip(vm::CellSlice& cs) const {
|
|||
cs); // depth_balance$_ split_depth:(#<= 30) balance:CurrencyCollection = DepthBalanceInfo;
|
||||
}
|
||||
|
||||
bool DepthBalanceInfo::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return cs.fetch_ulong(5) <= 30 && t_CurrencyCollection.validate_skip(
|
||||
cs, weak); // depth_balance$_ split_depth:(#<= 30) balance:CurrencyCollection
|
||||
bool DepthBalanceInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return cs.fetch_ulong(5) <= 30 &&
|
||||
t_CurrencyCollection.validate_skip(ops, cs,
|
||||
weak); // depth_balance$_ split_depth:(#<= 30) balance:CurrencyCollection
|
||||
}
|
||||
|
||||
bool DepthBalanceInfo::null_value(vm::CellBuilder& cb) const {
|
||||
|
@ -1159,10 +1163,10 @@ bool TrStoragePhase::skip(vm::CellSlice& cs) const {
|
|||
&& t_AccStatusChange.skip(cs); // status_change:AccStatusChange
|
||||
}
|
||||
|
||||
bool TrStoragePhase::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_Grams.validate_skip(cs, weak) // storage_fees_collected:Grams
|
||||
&& t_Maybe_Grams.validate_skip(cs, weak) // storage_fees_due:Grams
|
||||
&& t_AccStatusChange.validate_skip(cs, weak); // status_change:AccStatusChange
|
||||
bool TrStoragePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_Grams.validate_skip(ops, cs, weak) // storage_fees_collected:Grams
|
||||
&& t_Maybe_Grams.validate_skip(ops, cs, weak) // storage_fees_due:Grams
|
||||
&& t_AccStatusChange.validate_skip(ops, cs, weak); // status_change:AccStatusChange
|
||||
}
|
||||
|
||||
bool TrStoragePhase::get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const {
|
||||
|
@ -1186,9 +1190,9 @@ bool TrCreditPhase::skip(vm::CellSlice& cs) const {
|
|||
&& t_CurrencyCollection.skip(cs); // credit:CurrencyCollection
|
||||
}
|
||||
|
||||
bool TrCreditPhase::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_Maybe_Grams.validate_skip(cs, weak) // due_fees_collected:(Maybe Grams)
|
||||
&& t_CurrencyCollection.validate_skip(cs, weak); // credit:CurrencyCollection
|
||||
bool TrCreditPhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_Maybe_Grams.validate_skip(ops, cs, weak) // due_fees_collected:(Maybe Grams)
|
||||
&& t_CurrencyCollection.validate_skip(ops, cs, weak); // credit:CurrencyCollection
|
||||
}
|
||||
|
||||
const TrCreditPhase t_TrCreditPhase;
|
||||
|
@ -1204,15 +1208,15 @@ bool TrComputeInternal1::skip(vm::CellSlice& cs) const {
|
|||
// vm_final_state_hash:uint256
|
||||
}
|
||||
|
||||
bool TrComputeInternal1::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_VarUInteger_7.validate_skip(cs, weak) // gas_used:(VarUInteger 7)
|
||||
&& t_VarUInteger_7.validate_skip(cs, weak) // gas_limit:(VarUInteger 7)
|
||||
&& Maybe<VarUInteger>{3}.validate_skip(cs, weak) // gas_credit:(Maybe (VarUInteger 3))
|
||||
&& cs.advance(8 + 32) // mode:int8 exit_code:int32
|
||||
&& Maybe<Int>{32}.validate_skip(cs, weak) // exit_arg:(Maybe int32)
|
||||
&& cs.advance(32 + 256 + 256); // vm_steps:uint32
|
||||
// vm_init_state_hash:uint256
|
||||
// vm_final_state_hash:uint256
|
||||
bool TrComputeInternal1::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_VarUInteger_7.validate_skip(ops, cs, weak) // gas_used:(VarUInteger 7)
|
||||
&& t_VarUInteger_7.validate_skip(ops, cs, weak) // gas_limit:(VarUInteger 7)
|
||||
&& Maybe<VarUInteger>{3}.validate_skip(ops, cs, weak) // gas_credit:(Maybe (VarUInteger 3))
|
||||
&& cs.advance(8 + 32) // mode:int8 exit_code:int32
|
||||
&& Maybe<Int>{32}.validate_skip(ops, cs, weak) // exit_arg:(Maybe int32)
|
||||
&& cs.advance(32 + 256 + 256); // vm_steps:uint32
|
||||
// vm_init_state_hash:uint256
|
||||
// vm_final_state_hash:uint256
|
||||
}
|
||||
|
||||
const TrComputeInternal1 t_TrComputeInternal1;
|
||||
|
@ -1231,14 +1235,14 @@ bool TrComputePhase::skip(vm::CellSlice& cs) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool TrComputePhase::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool TrComputePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
switch (get_tag(cs)) {
|
||||
case tr_phase_compute_skipped:
|
||||
return cs.advance(1) && t_ComputeSkipReason.validate_skip(cs, weak);
|
||||
return cs.advance(1) && t_ComputeSkipReason.validate_skip(ops, cs, weak);
|
||||
case tr_phase_compute_vm:
|
||||
return cs.advance(1 + 3) // tr_phase_compute_vm$1 success:Bool msg_state_used:Bool account_activated:Bool
|
||||
&& t_Grams.validate_skip(cs, weak) // gas_fees:Grams
|
||||
&& t_Ref_TrComputeInternal1.validate_skip(cs, weak); // ^[ gas_used:(..) .. ]
|
||||
&& t_Grams.validate_skip(ops, cs, weak) // gas_fees:Grams
|
||||
&& t_Ref_TrComputeInternal1.validate_skip(ops, cs, weak); // ^[ gas_used:(..) .. ]
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1258,17 +1262,17 @@ bool TrActionPhase::skip(vm::CellSlice& cs) const {
|
|||
&& t_StorageUsedShort.skip(cs); // tot_msg_size:StorageUsedShort
|
||||
}
|
||||
|
||||
bool TrActionPhase::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return cs.advance(3) // success:Bool valid:Bool no_funds:Bool
|
||||
&& t_AccStatusChange.validate_skip(cs, weak) // status_change:AccStatusChange
|
||||
&& t_Maybe_Grams.validate_skip(cs, weak) // total_fwd_fees:(Maybe Grams)
|
||||
&& t_Maybe_Grams.validate_skip(cs, weak) // total_action_fees:(Maybe Grams)
|
||||
&& cs.advance(32) // result_code:int32
|
||||
&& Maybe<Int>{32}.validate_skip(cs, weak) // result_arg:(Maybe int32)
|
||||
&& cs.advance(16 * 4 + 256) // tot_actions:uint16 spec_actions:uint16
|
||||
// skipped_actions:uint16 msgs_created:uint16
|
||||
// action_list_hash:uint256
|
||||
&& t_StorageUsedShort.validate_skip(cs, weak); // tot_msg_size:StorageUsed
|
||||
bool TrActionPhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return cs.advance(3) // success:Bool valid:Bool no_funds:Bool
|
||||
&& t_AccStatusChange.validate_skip(ops, cs, weak) // status_change:AccStatusChange
|
||||
&& t_Maybe_Grams.validate_skip(ops, cs, weak) // total_fwd_fees:(Maybe Grams)
|
||||
&& t_Maybe_Grams.validate_skip(ops, cs, weak) // total_action_fees:(Maybe Grams)
|
||||
&& cs.advance(32) // result_code:int32
|
||||
&& Maybe<Int>{32}.validate_skip(ops, cs, weak) // result_arg:(Maybe int32)
|
||||
&& cs.advance(16 * 4 + 256) // tot_actions:uint16 spec_actions:uint16
|
||||
// skipped_actions:uint16 msgs_created:uint16
|
||||
// action_list_hash:uint256
|
||||
&& t_StorageUsedShort.validate_skip(ops, cs, weak); // tot_msg_size:StorageUsed
|
||||
}
|
||||
|
||||
const TrActionPhase t_TrActionPhase;
|
||||
|
@ -1290,19 +1294,19 @@ bool TrBouncePhase::skip(vm::CellSlice& cs) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool TrBouncePhase::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool TrBouncePhase::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
switch (get_tag(cs)) {
|
||||
case tr_phase_bounce_negfunds:
|
||||
return cs.advance(2); // tr_phase_bounce_negfunds$00
|
||||
case tr_phase_bounce_nofunds:
|
||||
return cs.advance(2) // tr_phase_bounce_nofunds$01
|
||||
&& t_StorageUsedShort.validate_skip(cs, weak) // msg_size:StorageUsedShort
|
||||
&& t_Grams.validate_skip(cs, weak); // req_fwd_fees:Grams
|
||||
return cs.advance(2) // tr_phase_bounce_nofunds$01
|
||||
&& t_StorageUsedShort.validate_skip(ops, cs, weak) // msg_size:StorageUsedShort
|
||||
&& t_Grams.validate_skip(ops, cs, weak); // req_fwd_fees:Grams
|
||||
case tr_phase_bounce_ok:
|
||||
return cs.advance(1) // tr_phase_bounce_ok$1
|
||||
&& t_StorageUsedShort.validate_skip(cs, weak) // msg_size:StorageUsedShort
|
||||
&& t_Grams.validate_skip(cs, weak) // msg_fees:Grams
|
||||
&& t_Grams.validate_skip(cs, weak); // fwd_fees:Grams
|
||||
return cs.advance(1) // tr_phase_bounce_ok$1
|
||||
&& t_StorageUsedShort.validate_skip(ops, cs, weak) // msg_size:StorageUsedShort
|
||||
&& t_Grams.validate_skip(ops, cs, weak) // msg_fees:Grams
|
||||
&& t_Grams.validate_skip(ops, cs, weak); // fwd_fees:Grams
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1322,7 +1326,7 @@ bool SplitMergeInfo::skip(vm::CellSlice& cs) const {
|
|||
return cs.advance(6 + 6 + 256 + 256);
|
||||
}
|
||||
|
||||
bool SplitMergeInfo::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool SplitMergeInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
if (!cs.have(6 + 6 + 256 + 256)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1392,52 +1396,52 @@ bool TransactionDescr::skip(vm::CellSlice& cs) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool TransactionDescr::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool TransactionDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
switch (get_tag(cs)) {
|
||||
case trans_ord:
|
||||
return cs.advance(4 + 1) // trans_ord$0000 credit_first:Bool
|
||||
&& Maybe<TrStoragePhase>{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase)
|
||||
&& Maybe<TrCreditPhase>{}.validate_skip(cs, weak) // credit_ph:(Maybe TrCreditPhase)
|
||||
&& t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(1) // aborted:Bool
|
||||
&& Maybe<TrBouncePhase>{}.validate_skip(cs, weak) // bounce:(Maybe TrBouncePhase)
|
||||
&& cs.advance(1); // destroyed:Bool
|
||||
return cs.advance(4 + 1) // trans_ord$0000 credit_first:Bool
|
||||
&& Maybe<TrStoragePhase>{}.validate_skip(ops, cs, weak) // storage_ph:(Maybe TrStoragePhase)
|
||||
&& Maybe<TrCreditPhase>{}.validate_skip(ops, cs, weak) // credit_ph:(Maybe TrCreditPhase)
|
||||
&& t_TrComputePhase.validate_skip(ops, cs, weak) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(ops, cs, weak) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(1) // aborted:Bool
|
||||
&& Maybe<TrBouncePhase>{}.validate_skip(ops, cs, weak) // bounce:(Maybe TrBouncePhase)
|
||||
&& cs.advance(1); // destroyed:Bool
|
||||
case trans_storage:
|
||||
return cs.advance(4) // trans_storage$0001
|
||||
&& t_TrStoragePhase.validate_skip(cs, weak); // storage_ph:TrStoragePhase
|
||||
return cs.advance(4) // trans_storage$0001
|
||||
&& t_TrStoragePhase.validate_skip(ops, cs, weak); // storage_ph:TrStoragePhase
|
||||
case trans_tick_tock:
|
||||
return cs.advance(4) // trans_tick_tock$001 is_tock:Bool
|
||||
&& t_TrStoragePhase.validate_skip(cs, weak) // storage_ph:TrStoragePhase
|
||||
&& t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||
return cs.advance(4) // trans_tick_tock$001 is_tock:Bool
|
||||
&& t_TrStoragePhase.validate_skip(ops, cs, weak) // storage_ph:TrStoragePhase
|
||||
&& t_TrComputePhase.validate_skip(ops, cs, weak) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(ops, cs, weak) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||
case trans_split_prepare:
|
||||
return cs.advance(4) // trans_split_prepare$0100
|
||||
&& t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo
|
||||
&& Maybe<TrStoragePhase>{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase)
|
||||
&& t_TrComputePhase.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||
return cs.advance(4) // trans_split_prepare$0100
|
||||
&& t_SplitMergeInfo.validate_skip(ops, cs, weak) // split_info:SplitMergeInfo
|
||||
&& Maybe<TrStoragePhase>{}.validate_skip(ops, cs, weak) // storage_ph:(Maybe TrStoragePhase)
|
||||
&& t_TrComputePhase.validate_skip(ops, cs, weak) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(ops, cs, weak) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||
case trans_split_install:
|
||||
return cs.advance(4) // trans_split_install$0101
|
||||
&& t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo
|
||||
&& t_Ref_Transaction.validate_skip(cs, weak) // prepare_transaction:^Transaction
|
||||
&& cs.advance(1); // installed:Bool
|
||||
return cs.advance(4) // trans_split_install$0101
|
||||
&& t_SplitMergeInfo.validate_skip(ops, cs, weak) // split_info:SplitMergeInfo
|
||||
&& t_Ref_Transaction.validate_skip(ops, cs, weak) // prepare_transaction:^Transaction
|
||||
&& cs.advance(1); // installed:Bool
|
||||
case trans_merge_prepare:
|
||||
return cs.advance(4) // trans_merge_prepare$0110
|
||||
&& t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo
|
||||
&& t_TrStoragePhase.validate_skip(cs, weak) // storage_ph:TrStoragePhase
|
||||
&& cs.advance(1); // aborted:Bool
|
||||
return cs.advance(4) // trans_merge_prepare$0110
|
||||
&& t_SplitMergeInfo.validate_skip(ops, cs, weak) // split_info:SplitMergeInfo
|
||||
&& t_TrStoragePhase.validate_skip(ops, cs, weak) // storage_ph:TrStoragePhase
|
||||
&& cs.advance(1); // aborted:Bool
|
||||
case trans_merge_install:
|
||||
return cs.advance(4) // trans_merge_install$0111
|
||||
&& t_SplitMergeInfo.validate_skip(cs, weak) // split_info:SplitMergeInfo
|
||||
&& t_Ref_Transaction.validate_skip(cs, weak) // prepare_transaction:^Transaction
|
||||
&& Maybe<TrStoragePhase>{}.validate_skip(cs, weak) // storage_ph:(Maybe TrStoragePhase)
|
||||
&& Maybe<TrCreditPhase>{}.validate_skip(cs, weak) // credit_ph:(Maybe TrCreditPhase)
|
||||
&& Maybe<TrComputePhase>{}.validate_skip(cs, weak) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(cs, weak) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||
return cs.advance(4) // trans_merge_install$0111
|
||||
&& t_SplitMergeInfo.validate_skip(ops, cs, weak) // split_info:SplitMergeInfo
|
||||
&& t_Ref_Transaction.validate_skip(ops, cs, weak) // prepare_transaction:^Transaction
|
||||
&& Maybe<TrStoragePhase>{}.validate_skip(ops, cs, weak) // storage_ph:(Maybe TrStoragePhase)
|
||||
&& Maybe<TrCreditPhase>{}.validate_skip(ops, cs, weak) // credit_ph:(Maybe TrCreditPhase)
|
||||
&& Maybe<TrComputePhase>{}.validate_skip(ops, cs, weak) // compute_ph:TrComputePhase
|
||||
&& Maybe<RefTo<TrActionPhase>>{}.validate_skip(ops, cs, weak) // action:(Maybe ^TrActionPhase)
|
||||
&& cs.advance(2); // aborted:Bool destroyed:Bool
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1501,9 +1505,9 @@ bool Transaction_aux::skip(vm::CellSlice& cs) const {
|
|||
&& HashmapE{15, t_Ref_Message}.skip(cs); // out_msgs:(HashmapE 15 ^Message)
|
||||
}
|
||||
|
||||
bool Transaction_aux::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return Maybe<RefTo<Message>>{}.validate_skip(cs, weak) // in_msg:(Maybe ^Message)
|
||||
&& HashmapE{15, t_Ref_Message}.validate_skip(cs, weak); // out_msgs:(HashmapE 15 ^Message)
|
||||
bool Transaction_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return Maybe<RefTo<Message>>{}.validate_skip(ops, cs, weak) // in_msg:(Maybe ^Message)
|
||||
&& HashmapE{15, t_Ref_Message}.validate_skip(ops, cs, weak); // out_msgs:(HashmapE 15 ^Message)
|
||||
}
|
||||
|
||||
const Transaction_aux t_Transaction_aux;
|
||||
|
@ -1520,18 +1524,18 @@ bool Transaction::skip(vm::CellSlice& cs) const {
|
|||
&& RefTo<TransactionDescr>{}.skip(cs); // description:^TransactionDescr
|
||||
}
|
||||
|
||||
bool Transaction::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool Transaction::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return cs.fetch_ulong(4) == 7 // transaction$0111
|
||||
&&
|
||||
cs.advance(
|
||||
256 + 64 + 256 + 64 + 32 +
|
||||
15) // account_addr:uint256 lt:uint64 prev_trans_hash:bits256 prev_trans_lt:uint64 now:uint32 outmsg_cnt:uint15
|
||||
&& t_AccountStatus.validate_skip(cs, weak) // orig_status:AccountStatus
|
||||
&& t_AccountStatus.validate_skip(cs, weak) // end_status:AccountStatus
|
||||
&& RefTo<Transaction_aux>{}.validate_skip(cs, weak) // ^[ in_msg:... out_msgs:... ]
|
||||
&& t_CurrencyCollection.validate_skip(cs, weak) // total_fees:CurrencyCollection
|
||||
&& t_Ref_HashUpdate.validate_skip(cs, weak) // state_update:^(HASH_UPDATE Account)
|
||||
&& RefTo<TransactionDescr>{}.validate_skip(cs, weak); // description:^TransactionDescr
|
||||
&& t_AccountStatus.validate_skip(ops, cs, weak) // orig_status:AccountStatus
|
||||
&& t_AccountStatus.validate_skip(ops, cs, weak) // end_status:AccountStatus
|
||||
&& RefTo<Transaction_aux>{}.validate_skip(ops, cs, weak) // ^[ in_msg:... out_msgs:... ]
|
||||
&& t_CurrencyCollection.validate_skip(ops, cs, weak) // total_fees:CurrencyCollection
|
||||
&& t_Ref_HashUpdate.validate_skip(ops, cs, weak) // state_update:^(HASH_UPDATE Account)
|
||||
&& RefTo<TransactionDescr>{}.validate_skip(ops, cs, weak); // description:^TransactionDescr
|
||||
}
|
||||
|
||||
bool Transaction::get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const {
|
||||
|
@ -1595,12 +1599,12 @@ bool AccountBlock::skip(vm::CellSlice& cs) const {
|
|||
&& cs.advance_refs(1); // state_update:^(HASH_UPDATE Account)
|
||||
}
|
||||
|
||||
bool AccountBlock::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool AccountBlock::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return cs.fetch_ulong(4) == 5 // acc_trans#5
|
||||
&& cs.advance(256) // account_addr:bits256
|
||||
&&
|
||||
t_AccountTransactions.validate_skip(cs, weak) // transactions:(HashmapAug 64 ^Transaction CurrencyCollection)
|
||||
&& t_Ref_HashUpdate.validate_skip(cs, weak); // state_update:^(HASH_UPDATE Account)
|
||||
&& t_AccountTransactions.validate_skip(ops, cs,
|
||||
weak) // transactions:(HashmapAug 64 ^Transaction CurrencyCollection)
|
||||
&& t_Ref_HashUpdate.validate_skip(ops, cs, weak); // state_update:^(HASH_UPDATE Account)
|
||||
}
|
||||
|
||||
bool AccountBlock::get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const {
|
||||
|
@ -1620,8 +1624,8 @@ const Aug_ShardAccountBlocks aug_ShardAccountBlocks;
|
|||
const HashmapAugE t_ShardAccountBlocks{256,
|
||||
aug_ShardAccountBlocks}; // (HashmapAugE 256 AccountBlock CurrencyCollection)
|
||||
|
||||
bool ImportFees::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_Grams.validate_skip(cs, weak) && t_CurrencyCollection.validate_skip(cs, weak);
|
||||
bool ImportFees::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_Grams.validate_skip(ops, cs, weak) && t_CurrencyCollection.validate_skip(ops, cs, weak);
|
||||
}
|
||||
|
||||
bool ImportFees::skip(vm::CellSlice& cs) const {
|
||||
|
@ -1676,44 +1680,44 @@ bool InMsg::skip(vm::CellSlice& cs) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool InMsg::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool InMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
switch (get_tag(cs)) {
|
||||
case msg_import_ext:
|
||||
return cs.advance(3) // msg_import_ext$000
|
||||
&& t_Ref_Message.validate_skip(cs, weak) // msg:^Message
|
||||
&& t_Ref_Transaction.validate_skip(cs, weak); // transaction:^Transaction
|
||||
return cs.advance(3) // msg_import_ext$000
|
||||
&& t_Ref_Message.validate_skip(ops, cs, weak) // msg:^Message
|
||||
&& t_Ref_Transaction.validate_skip(ops, cs, weak); // transaction:^Transaction
|
||||
case msg_import_ihr:
|
||||
return cs.advance(3) // msg_import_ihr$010
|
||||
&& t_Ref_Message.validate_skip(cs, weak) // msg:^Message
|
||||
&& t_Ref_Transaction.validate_skip(cs, weak) // transaction:^Transaction
|
||||
&& t_Grams.validate_skip(cs, weak) // ihr_fee:Grams
|
||||
&& t_RefCell.validate_skip(cs, weak); // proof_created:^Cell
|
||||
return cs.advance(3) // msg_import_ihr$010
|
||||
&& t_Ref_Message.validate_skip(ops, cs, weak) // msg:^Message
|
||||
&& t_Ref_Transaction.validate_skip(ops, cs, weak) // transaction:^Transaction
|
||||
&& t_Grams.validate_skip(ops, cs, weak) // ihr_fee:Grams
|
||||
&& t_RefCell.validate_skip(ops, cs, weak); // proof_created:^Cell
|
||||
case msg_import_imm:
|
||||
return cs.advance(3) // msg_import_imm$011
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // in_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.validate_skip(cs, weak) // transaction:^Transaction
|
||||
&& t_Grams.validate_skip(cs, weak); // fwd_fee:Grams
|
||||
return cs.advance(3) // msg_import_imm$011
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.validate_skip(ops, cs, weak) // transaction:^Transaction
|
||||
&& t_Grams.validate_skip(ops, cs, weak); // fwd_fee:Grams
|
||||
case msg_import_fin:
|
||||
return cs.advance(3) // msg_import_fin$100
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // in_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.validate_skip(cs, weak) // transaction:^Transaction
|
||||
&& t_Grams.validate_skip(cs, weak); // fwd_fee:Grams
|
||||
return cs.advance(3) // msg_import_fin$100
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.validate_skip(ops, cs, weak) // transaction:^Transaction
|
||||
&& t_Grams.validate_skip(ops, cs, weak); // fwd_fee:Grams
|
||||
case msg_import_tr:
|
||||
return cs.advance(3) // msg_import_tr$101
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // in_msg:^MsgEnvelope
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope
|
||||
&& t_Grams.validate_skip(cs, weak); // transit_fee:Grams
|
||||
return cs.advance(3) // msg_import_tr$101
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope
|
||||
&& t_Grams.validate_skip(ops, cs, weak); // transit_fee:Grams
|
||||
case msg_discard_fin:
|
||||
return cs.advance(3) // msg_discard_fin$110
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // in_msg:^MsgEnvelope
|
||||
&& cs.advance(64) // transaction_id:uint64
|
||||
&& t_Grams.validate_skip(cs, weak); // fwd_fee:Grams
|
||||
return cs.advance(3) // msg_discard_fin$110
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope
|
||||
&& cs.advance(64) // transaction_id:uint64
|
||||
&& t_Grams.validate_skip(ops, cs, weak); // fwd_fee:Grams
|
||||
case msg_discard_tr:
|
||||
return cs.advance(3) // msg_discard_tr$111
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // in_msg:^MsgEnvelope
|
||||
&& cs.advance(64) // transaction_id:uint64
|
||||
&& t_Grams.validate_skip(cs, weak) // fwd_fee:Grams
|
||||
&& t_RefCell.validate_skip(cs, weak); // proof_delivered:^Cell
|
||||
return cs.advance(3) // msg_discard_tr$111
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // in_msg:^MsgEnvelope
|
||||
&& cs.advance(64) // transaction_id:uint64
|
||||
&& t_Grams.validate_skip(ops, cs, weak) // fwd_fee:Grams
|
||||
&& t_RefCell.validate_skip(ops, cs, weak); // proof_delivered:^Cell
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1851,37 +1855,37 @@ bool OutMsg::skip(vm::CellSlice& cs) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool OutMsg::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool OutMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
switch (get_tag(cs)) {
|
||||
case msg_export_ext:
|
||||
return cs.advance(3) // msg_export_ext$000
|
||||
&& t_Ref_Message.validate_skip(cs, weak) // msg:^Message
|
||||
&& t_Ref_Transaction.validate_skip(cs, weak); // transaction:^Transaction
|
||||
return cs.advance(3) // msg_export_ext$000
|
||||
&& t_Ref_Message.validate_skip(ops, cs, weak) // msg:^Message
|
||||
&& t_Ref_Transaction.validate_skip(ops, cs, weak); // transaction:^Transaction
|
||||
case msg_export_imm:
|
||||
return cs.advance(3) // msg_export_imm$010
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.validate_skip(cs, weak) // transaction:^Transaction
|
||||
&& RefTo<InMsg>{}.validate_skip(cs, weak); // reimport:^InMsg
|
||||
return cs.advance(3) // msg_export_imm$010
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.validate_skip(ops, cs, weak) // transaction:^Transaction
|
||||
&& RefTo<InMsg>{}.validate_skip(ops, cs, weak); // reimport:^InMsg
|
||||
case msg_export_new:
|
||||
return cs.advance(3) // msg_export_new$001
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.validate_skip(cs, weak); // transaction:^Transaction
|
||||
return cs.advance(3) // msg_export_new$001
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope
|
||||
&& t_Ref_Transaction.validate_skip(ops, cs, weak); // transaction:^Transaction
|
||||
case msg_export_tr:
|
||||
return cs.advance(3) // msg_export_tr$011
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope
|
||||
&& RefTo<InMsg>{}.validate_skip(cs, weak); // imported:^InMsg
|
||||
return cs.advance(3) // msg_export_tr$011
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope
|
||||
&& RefTo<InMsg>{}.validate_skip(ops, cs, weak); // imported:^InMsg
|
||||
case msg_export_deq_imm:
|
||||
return cs.advance(3) // msg_export_deq_imm$100
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope
|
||||
&& RefTo<InMsg>{}.validate_skip(cs, weak); // reimport:^InMsg
|
||||
return cs.advance(3) // msg_export_deq_imm$100
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope
|
||||
&& RefTo<InMsg>{}.validate_skip(ops, cs, weak); // reimport:^InMsg
|
||||
case msg_export_deq:
|
||||
return cs.advance(3) // msg_export_deq$110
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope
|
||||
&& cs.advance(64); // import_block_lt:uint64
|
||||
return cs.advance(3) // msg_export_deq$110
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope
|
||||
&& cs.advance(64); // import_block_lt:uint64
|
||||
case msg_export_tr_req:
|
||||
return cs.advance(3) // msg_export_tr_req$111
|
||||
&& t_Ref_MsgEnvelope.validate_skip(cs, weak) // out_msg:^MsgEnvelope
|
||||
&& RefTo<InMsg>{}.validate_skip(cs, weak); // imported:^InMsg
|
||||
return cs.advance(3) // msg_export_tr_req$111
|
||||
&& t_Ref_MsgEnvelope.validate_skip(ops, cs, weak) // out_msg:^MsgEnvelope
|
||||
&& RefTo<InMsg>{}.validate_skip(ops, cs, weak); // imported:^InMsg
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1954,8 +1958,8 @@ const OutMsg t_OutMsg;
|
|||
const Aug_OutMsgDescr aug_OutMsgDescr;
|
||||
const OutMsgDescr t_OutMsgDescr;
|
||||
|
||||
bool EnqueuedMsg::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return cs.advance(64) && t_Ref_MsgEnvelope.validate_skip(cs, weak);
|
||||
bool EnqueuedMsg::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return cs.advance(64) && t_Ref_MsgEnvelope.validate_skip(ops, cs, weak);
|
||||
}
|
||||
|
||||
const EnqueuedMsg t_EnqueuedMsg;
|
||||
|
@ -1989,9 +1993,9 @@ bool OutMsgQueueInfo::skip(vm::CellSlice& cs) const {
|
|||
return t_OutMsgQueue.skip(cs) && t_ProcessedInfo.skip(cs) && t_IhrPendingInfo.skip(cs);
|
||||
}
|
||||
|
||||
bool OutMsgQueueInfo::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_OutMsgQueue.validate_skip(cs, weak) && t_ProcessedInfo.validate_skip(cs, weak) &&
|
||||
t_IhrPendingInfo.validate_skip(cs, weak);
|
||||
bool OutMsgQueueInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_OutMsgQueue.validate_skip(ops, cs, weak) && t_ProcessedInfo.validate_skip(ops, cs, weak) &&
|
||||
t_IhrPendingInfo.validate_skip(ops, cs, weak);
|
||||
}
|
||||
|
||||
const OutMsgQueueInfo t_OutMsgQueueInfo;
|
||||
|
@ -2047,7 +2051,7 @@ bool ExtBlkRef::pack_to(Ref<vm::Cell>& cell, const ton::BlockIdExt& blkid, ton::
|
|||
const ExtBlkRef t_ExtBlkRef;
|
||||
const BlkMasterInfo t_BlkMasterInfo;
|
||||
|
||||
bool ShardIdent::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool ShardIdent::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
int shard_pfx_len, workchain_id;
|
||||
unsigned long long shard_pfx;
|
||||
if (cs.fetch_ulong(2) == 0 && cs.fetch_uint_to(6, shard_pfx_len) && cs.fetch_int_to(32, workchain_id) &&
|
||||
|
@ -2112,8 +2116,8 @@ bool ShardIdent::pack(vm::CellBuilder& cb, ton::ShardIdFull data) const {
|
|||
|
||||
const ShardIdent t_ShardIdent;
|
||||
|
||||
bool BlockIdExt::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_ShardIdent.validate_skip(cs, weak) && cs.advance(32 + 256 * 2);
|
||||
bool BlockIdExt::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_ShardIdent.validate_skip(ops, cs, weak) && cs.advance(32 + 256 * 2);
|
||||
}
|
||||
|
||||
bool BlockIdExt::unpack(vm::CellSlice& cs, ton::BlockIdExt& data) const {
|
||||
|
@ -2146,21 +2150,21 @@ bool ShardState::skip(vm::CellSlice& cs) const {
|
|||
&& Maybe<RefTo<McStateExtra>>{}.skip(cs); // custom:(Maybe ^McStateExtra)
|
||||
}
|
||||
|
||||
bool ShardState::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool ShardState::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
int seq_no;
|
||||
return get_tag(cs) == shard_state && cs.advance(64) // shard_state#9023afe2 blockchain_id:int32
|
||||
&& t_ShardIdent.validate_skip(cs, weak) // shard_id:ShardIdent
|
||||
&& t_ShardIdent.validate_skip(ops, cs, weak) // shard_id:ShardIdent
|
||||
&& cs.fetch_int_to(32, seq_no) // seq_no:int32
|
||||
&& seq_no >= -1 // { seq_no >= -1 }
|
||||
&& cs.advance(32 + 32 + 64 + 32) // vert_seq_no:# gen_utime:uint32 gen_lt:uint64 min_ref_mc_seqno:uint32
|
||||
&& t_Ref_OutMsgQueueInfo.validate_skip(cs, weak) // out_msg_queue_info:^OutMsgQueueInfo
|
||||
&& cs.advance(1) // before_split:Bool
|
||||
&& t_ShardAccounts.validate_skip_ref(cs, weak) // accounts:^ShardAccounts
|
||||
&& t_Ref_OutMsgQueueInfo.validate_skip(ops, cs, weak) // out_msg_queue_info:^OutMsgQueueInfo
|
||||
&& cs.advance(1) // before_split:Bool
|
||||
&& t_ShardAccounts.validate_skip_ref(ops, cs, weak) // accounts:^ShardAccounts
|
||||
&&
|
||||
t_ShardState_aux.validate_skip_ref(
|
||||
cs,
|
||||
ops, cs,
|
||||
weak) // ^[ total_balance:CurrencyCollection total_validator_fees:CurrencyCollection libraries:(HashmapE 256 LibDescr) master_ref:(Maybe BlkMasterInfo) ]
|
||||
&& Maybe<RefTo<McStateExtra>>{}.validate_skip(cs, weak); // custom:(Maybe ^McStateExtra)
|
||||
&& Maybe<RefTo<McStateExtra>>{}.validate_skip(ops, cs, weak); // custom:(Maybe ^McStateExtra)
|
||||
}
|
||||
|
||||
const ShardState t_ShardState;
|
||||
|
@ -2173,12 +2177,12 @@ bool ShardState_aux::skip(vm::CellSlice& cs) const {
|
|||
&& Maybe<BlkMasterInfo>{}.skip(cs); // master_ref:(Maybe BlkMasterInfo)
|
||||
}
|
||||
|
||||
bool ShardState_aux::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return cs.advance(128) // overload_history:uint64 underload_history:uint64
|
||||
&& t_CurrencyCollection.validate_skip(cs, weak) // total_balance:CurrencyCollection
|
||||
&& t_CurrencyCollection.validate_skip(cs, weak) // total_validator_fees:CurrencyCollection
|
||||
&& HashmapE{256, t_LibDescr}.validate_skip(cs, weak) // libraries:(HashmapE 256 LibDescr)
|
||||
&& Maybe<BlkMasterInfo>{}.validate_skip(cs, weak); // master_ref:(Maybe BlkMasterInfo)
|
||||
bool ShardState_aux::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return cs.advance(128) // overload_history:uint64 underload_history:uint64
|
||||
&& t_CurrencyCollection.validate_skip(ops, cs, weak) // total_balance:CurrencyCollection
|
||||
&& t_CurrencyCollection.validate_skip(ops, cs, weak) // total_validator_fees:CurrencyCollection
|
||||
&& HashmapE{256, t_LibDescr}.validate_skip(ops, cs, weak) // libraries:(HashmapE 256 LibDescr)
|
||||
&& Maybe<BlkMasterInfo>{}.validate_skip(ops, cs, weak); // master_ref:(Maybe BlkMasterInfo)
|
||||
}
|
||||
|
||||
const ShardState_aux t_ShardState_aux;
|
||||
|
@ -2189,10 +2193,10 @@ bool LibDescr::skip(vm::CellSlice& cs) const {
|
|||
&& Hashmap{256, t_True}.skip(cs); // publishers:(Hashmap 256 False)
|
||||
}
|
||||
|
||||
bool LibDescr::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return get_tag(cs) == shared_lib_descr && cs.advance(2) // shared_lib_descr$00
|
||||
&& cs.fetch_ref().not_null() // lib:^Cell
|
||||
&& Hashmap{256, t_True}.validate_skip(cs, weak); // publishers:(Hashmap 256 False)
|
||||
bool LibDescr::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return get_tag(cs) == shared_lib_descr && cs.advance(2) // shared_lib_descr$00
|
||||
&& cs.fetch_ref().not_null() // lib:^Cell
|
||||
&& Hashmap{256, t_True}.validate_skip(ops, cs, weak); // publishers:(Hashmap 256 False)
|
||||
}
|
||||
|
||||
const LibDescr t_LibDescr;
|
||||
|
@ -2202,9 +2206,9 @@ bool BlkPrevInfo::skip(vm::CellSlice& cs) const {
|
|||
&& (!merged || t_ExtBlkRef.skip(cs)); // prev_alt:merged?ExtBlkRef
|
||||
}
|
||||
|
||||
bool BlkPrevInfo::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_ExtBlkRef.validate_skip(cs, weak) // prev_blk_info$_ {merged:#} prev:ExtBlkRef
|
||||
&& (!merged || t_ExtBlkRef.validate_skip(cs, weak)); // prev_alt:merged?ExtBlkRef
|
||||
bool BlkPrevInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_ExtBlkRef.validate_skip(ops, cs, weak) // prev_blk_info$_ {merged:#} prev:ExtBlkRef
|
||||
&& (!merged || t_ExtBlkRef.validate_skip(ops, cs, weak)); // prev_alt:merged?ExtBlkRef
|
||||
}
|
||||
|
||||
const BlkPrevInfo t_BlkPrevInfo_0{0};
|
||||
|
@ -2213,8 +2217,8 @@ bool McStateExtra::skip(vm::CellSlice& cs) const {
|
|||
return block::gen::t_McStateExtra.skip(cs);
|
||||
}
|
||||
|
||||
bool McStateExtra::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return block::gen::t_McStateExtra.validate_skip(cs, weak); // ??
|
||||
bool McStateExtra::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return block::gen::t_McStateExtra.validate_skip(ops, cs, weak); // ??
|
||||
}
|
||||
|
||||
const McStateExtra t_McStateExtra;
|
||||
|
@ -2241,8 +2245,8 @@ bool ShardFeeCreated::skip(vm::CellSlice& cs) const {
|
|||
return t_CurrencyCollection.skip(cs) && t_CurrencyCollection.skip(cs);
|
||||
}
|
||||
|
||||
bool ShardFeeCreated::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
return t_CurrencyCollection.validate_skip(cs, weak) && t_CurrencyCollection.validate_skip(cs, weak);
|
||||
bool ShardFeeCreated::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
return t_CurrencyCollection.validate_skip(ops, cs, weak) && t_CurrencyCollection.validate_skip(ops, cs, weak);
|
||||
}
|
||||
|
||||
bool ShardFeeCreated::null_value(vm::CellBuilder& cb) const {
|
||||
|
|
|
@ -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 "common/refcnt.hpp"
|
||||
|
@ -59,7 +59,7 @@ struct VarUInteger final : TLB_Complex {
|
|||
ln = 32 - td::count_leading_zeroes32(n - 1);
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override;
|
||||
unsigned long long as_uint(const vm::CellSlice& cs) const override;
|
||||
bool null_value(vm::CellBuilder& cb) const override {
|
||||
|
@ -78,7 +78,7 @@ struct VarUIntegerPos final : TLB_Complex {
|
|||
ln = 32 - td::count_leading_zeroes32(n - 1);
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
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;
|
||||
|
@ -92,7 +92,7 @@ struct VarInteger final : TLB_Complex {
|
|||
ln = 32 - td::count_leading_zeroes32(n - 1);
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override;
|
||||
long long as_int(const vm::CellSlice& cs) const override;
|
||||
bool null_value(vm::CellBuilder& cb) const override {
|
||||
|
@ -107,7 +107,7 @@ struct VarIntegerNz final : TLB_Complex {
|
|||
ln = 32 - td::count_leading_zeroes32(n - 1);
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
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;
|
||||
|
@ -123,13 +123,13 @@ struct Unary final : TLB {
|
|||
bool skip(vm::CellSlice& cs, int& n) const {
|
||||
return validate_skip(cs, false, n);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return cs.advance(get_size(cs));
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return skip(cs);
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override {
|
||||
return validate_skip(cs);
|
||||
return cs.advance(get_size(cs));
|
||||
}
|
||||
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
|
||||
bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return cs.have(get_size(cs));
|
||||
}
|
||||
};
|
||||
|
@ -149,7 +149,7 @@ struct HmLabel final : TLB_Complex {
|
|||
int n;
|
||||
return skip(cs, n);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
int n;
|
||||
return validate_skip(cs, weak, n);
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ struct Hashmap final : TLB_Complex {
|
|||
Hashmap(int _n, const TLB& _val_type) : value_type(_val_type), n(_n) {
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
struct HashmapNode final : TLB_Complex {
|
||||
|
@ -173,7 +173,7 @@ struct HashmapNode final : TLB_Complex {
|
|||
}
|
||||
int get_size(const vm::CellSlice& cs) const override;
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return n > 0 ? hmn_fork : n;
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ struct HashmapE final : TLB {
|
|||
HashmapE(int _n, const TLB& _val_type) : root_type(_n, _val_type) {
|
||||
}
|
||||
int get_size(const vm::CellSlice& cs) const override;
|
||||
bool validate(const vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(1);
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ struct HashmapAug final : TLB_Complex {
|
|||
HashmapAug(int _n, const AugmentationCheckData& _aug) : aug(_aug), n(_n) {
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool extract_extra(vm::CellSlice& cs) const;
|
||||
};
|
||||
|
||||
|
@ -232,7 +232,7 @@ struct HashmapAugNode final : TLB_Complex {
|
|||
HashmapAugNode(int _n, const AugmentationCheckData& _aug) : aug(_aug), n(_n) {
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return n > 0 ? ahmn_fork : n;
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ struct HashmapAugE final : TLB_Complex {
|
|||
HashmapAugE(int _n, const AugmentationCheckData& _aug) : root_type(_n, std::move(_aug)) {
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool extract_extra(vm::CellSlice& cs) const;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(1);
|
||||
|
@ -252,7 +252,7 @@ struct HashmapAugE final : TLB_Complex {
|
|||
};
|
||||
|
||||
struct Grams final : TLB_Complex {
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override;
|
||||
bool null_value(vm::CellBuilder& cb) const override;
|
||||
bool store_integer_value(vm::CellBuilder& cb, const td::BigInt256& value) const override;
|
||||
|
@ -264,7 +264,7 @@ extern const Grams t_Grams;
|
|||
|
||||
struct MsgAddressInt final : TLB_Complex {
|
||||
enum { addr_std = 2, addr_var = 3 };
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(2);
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ extern const MsgAddressExt t_MsgAddressExt;
|
|||
|
||||
struct MsgAddress final : TLB_Complex {
|
||||
enum { addr_none = 0, addr_ext = 1, addr_std = 2, addr_var = 3 };
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(2);
|
||||
}
|
||||
|
@ -318,8 +318,8 @@ struct ExtraCurrencyCollection final : TLB {
|
|||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return dict_type.get_size(cs);
|
||||
}
|
||||
bool validate(const vm::CellSlice& cs, bool weak) const override {
|
||||
return dict_type.validate(cs, weak);
|
||||
bool validate(int* ops, const vm::CellSlice& cs, bool weak) const override {
|
||||
return dict_type.validate(ops, cs, weak);
|
||||
}
|
||||
bool null_value(vm::CellBuilder& cb) const override {
|
||||
return cb.store_zeroes_bool(1);
|
||||
|
@ -348,7 +348,7 @@ extern const ExtraCurrencyCollection t_ExtraCurrencyCollection;
|
|||
|
||||
struct CurrencyCollection final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
td::RefInt256 as_integer_skip(vm::CellSlice& cs) const override;
|
||||
bool null_value(vm::CellBuilder& cb) const override {
|
||||
return cb.store_bits_same_bool(1 + 4, false);
|
||||
|
@ -371,7 +371,7 @@ extern const CurrencyCollection t_CurrencyCollection;
|
|||
struct CommonMsgInfo final : TLB_Complex {
|
||||
enum { int_msg_info = 0, ext_in_msg_info = 2, ext_out_msg_info = 3 };
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
int v = (int)cs.prefetch_ulong(2);
|
||||
return v == 1 ? int_msg_info : v;
|
||||
|
@ -402,14 +402,14 @@ struct TickTock final : TLB {
|
|||
extern const TickTock t_TickTock;
|
||||
|
||||
struct StateInit final : TLB_Complex {
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool get_ticktock(vm::CellSlice& cs, int& ticktock) const;
|
||||
};
|
||||
|
||||
extern const StateInit t_StateInit;
|
||||
|
||||
struct Message final : TLB_Complex {
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool extract_info(vm::CellSlice& cs) const;
|
||||
bool get_created_lt(vm::CellSlice& cs, unsigned long long& created_lt) const;
|
||||
bool is_internal(const vm::CellSlice& cs) const {
|
||||
|
@ -425,7 +425,7 @@ struct IntermediateAddress final : TLB_Complex {
|
|||
enum { interm_addr_regular = 0, interm_addr_simple = 2, interm_addr_ext = 3 };
|
||||
int get_size(const vm::CellSlice& cs) const override;
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool fetch_regular(vm::CellSlice& cs, int& use_dst_bits) const {
|
||||
return cs.fetch_uint_to(8, use_dst_bits) && use_dst_bits <= 96;
|
||||
}
|
||||
|
@ -439,7 +439,7 @@ extern const IntermediateAddress t_IntermediateAddress;
|
|||
|
||||
struct MsgEnvelope final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool extract_fwd_fees_remaining(vm::CellSlice& cs) const;
|
||||
struct Record {
|
||||
typedef MsgEnvelope type_class;
|
||||
|
@ -463,28 +463,28 @@ extern const RefTo<MsgEnvelope> t_Ref_MsgEnvelope;
|
|||
|
||||
struct StorageUsed final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
extern const StorageUsed t_StorageUsed;
|
||||
|
||||
struct StorageUsedShort final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
extern const StorageUsedShort t_StorageUsedShort;
|
||||
|
||||
struct StorageInfo final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
extern const StorageInfo t_StorageInfo;
|
||||
|
||||
struct AccountState final : TLB_Complex {
|
||||
enum { account_uninit = 0, account_frozen = 1, account_active = 2 };
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
int t = (int)cs.prefetch_ulong(2);
|
||||
return t == 3 ? account_active : t;
|
||||
|
@ -496,7 +496,7 @@ extern const AccountState t_AccountState;
|
|||
|
||||
struct AccountStorage final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool skip_copy_balance(vm::CellBuilder& cb, vm::CellSlice& cs) const;
|
||||
};
|
||||
|
||||
|
@ -508,7 +508,7 @@ struct Account final : TLB_Complex {
|
|||
Account(bool _allow_empty = false) : allow_empty(_allow_empty) {
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
// Ref<vm::CellSlice> get_balance(const vm::CellSlice& cs) const;
|
||||
bool skip_copy_balance(vm::CellBuilder& cb, vm::CellSlice& cs) const;
|
||||
bool skip_copy_depth_balance(vm::CellBuilder& cb, vm::CellSlice& cs) const;
|
||||
|
@ -553,8 +553,8 @@ struct ShardAccount final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return cs.advance_ext(0x140, 1);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return cs.advance(0x140) && t_Ref_Account.validate_skip(cs, weak);
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return cs.advance(0x140) && t_Ref_Account.validate_skip(ops, cs, weak);
|
||||
}
|
||||
static bool unpack(vm::CellSlice& cs, Record& info) {
|
||||
return info.unpack(cs);
|
||||
|
@ -569,7 +569,7 @@ extern const ShardAccount t_ShardAccount;
|
|||
|
||||
struct DepthBalanceInfo final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool null_value(vm::CellBuilder& cb) const override;
|
||||
bool add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const override;
|
||||
};
|
||||
|
@ -590,8 +590,8 @@ struct ShardAccounts final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return dict_type.skip(cs);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return dict_type.validate_skip(cs, weak);
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return dict_type.validate_skip(ops, cs, weak);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -615,7 +615,7 @@ extern const AccStatusChange t_AccStatusChange;
|
|||
|
||||
struct TrStoragePhase final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const;
|
||||
bool maybe_get_storage_fees(vm::CellSlice& cs, td::RefInt256& storage_fees) const;
|
||||
};
|
||||
|
@ -624,14 +624,14 @@ extern const TrStoragePhase t_TrStoragePhase;
|
|||
|
||||
struct TrCreditPhase final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
extern const TrCreditPhase t_TrCreditPhase;
|
||||
|
||||
struct TrComputeInternal1 final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
struct ComputeSkipReason final : TLB {
|
||||
|
@ -639,7 +639,7 @@ struct ComputeSkipReason final : TLB {
|
|||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return 2;
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return get_tag(cs) >= 0 && cs.advance(2);
|
||||
}
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
|
@ -653,7 +653,7 @@ extern const ComputeSkipReason t_ComputeSkipReason;
|
|||
struct TrComputePhase final : TLB_Complex {
|
||||
enum { tr_phase_compute_skipped = 0, tr_phase_compute_vm = 1 };
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(1);
|
||||
}
|
||||
|
@ -663,7 +663,7 @@ extern const TrComputePhase t_TrComputePhase;
|
|||
|
||||
struct TrActionPhase final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
extern const TrActionPhase t_TrActionPhase;
|
||||
|
@ -671,7 +671,7 @@ extern const TrActionPhase t_TrActionPhase;
|
|||
struct TrBouncePhase final : TLB_Complex {
|
||||
enum { tr_phase_bounce_negfunds = 0, tr_phase_bounce_nofunds = 1, tr_phase_bounce_ok = 2 };
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override;
|
||||
};
|
||||
|
||||
|
@ -679,7 +679,7 @@ extern const TrBouncePhase t_TrBouncePhase;
|
|||
|
||||
struct SplitMergeInfo final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
extern const SplitMergeInfo t_SplitMergeInfo;
|
||||
|
@ -695,7 +695,7 @@ struct TransactionDescr final : TLB_Complex {
|
|||
trans_merge_install = 7
|
||||
};
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override;
|
||||
bool skip_to_storage_phase(vm::CellSlice& cs, bool& found) const;
|
||||
bool get_storage_fees(Ref<vm::Cell> cell, td::RefInt256& storage_fees) const;
|
||||
|
@ -705,14 +705,14 @@ extern const TransactionDescr t_TransactionDescr;
|
|||
|
||||
struct Transaction_aux final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
extern const Transaction_aux t_Transaction_aux;
|
||||
|
||||
struct Transaction final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const;
|
||||
bool get_descr(Ref<vm::Cell> cell, Ref<vm::Cell>& tdescr) const;
|
||||
bool get_descr(vm::CellSlice& cs, Ref<vm::Cell>& tdescr) const;
|
||||
|
@ -735,7 +735,7 @@ struct HashUpdate final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return cs.advance(8 + 256 * 2);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return cs.fetch_ulong(8) == 0x72 && cs.advance(256 * 2);
|
||||
}
|
||||
};
|
||||
|
@ -745,7 +745,7 @@ extern const RefTo<HashUpdate> t_Ref_HashUpdate;
|
|||
|
||||
struct AccountBlock final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool get_total_fees(vm::CellSlice&& cs, block::CurrencyCollection& total_fees) const;
|
||||
};
|
||||
|
||||
|
@ -762,7 +762,7 @@ extern const HashmapAugE t_ShardAccountBlocks; // (HashmapAugE 256 AccountBlock
|
|||
|
||||
struct ImportFees final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool null_value(vm::CellBuilder& cb) const override {
|
||||
return cb.store_bits_same_bool(4 + 4 + 1, false);
|
||||
}
|
||||
|
@ -782,7 +782,7 @@ struct InMsg final : TLB_Complex {
|
|||
msg_discard_tr = 7
|
||||
};
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(3);
|
||||
}
|
||||
|
@ -802,7 +802,7 @@ struct OutMsg final : TLB_Complex {
|
|||
msg_export_tr_req = 7
|
||||
};
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(3);
|
||||
}
|
||||
|
@ -830,8 +830,8 @@ struct InMsgDescr final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return dict_type.skip(cs);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return dict_type.validate_skip(cs, weak);
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return dict_type.validate_skip(ops, cs, weak);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -853,8 +853,8 @@ struct OutMsgDescr final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return dict_type.skip(cs);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return dict_type.validate_skip(cs, weak);
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return dict_type.validate_skip(ops, cs, weak);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -867,7 +867,7 @@ struct EnqueuedMsg final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return cs.advance_ext(0x10040);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, EnqueuedMsgDescr& descr) const {
|
||||
return descr.unpack(cs);
|
||||
}
|
||||
|
@ -891,8 +891,8 @@ struct OutMsgQueue final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return dict_type.skip(cs);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return dict_type.validate_skip(cs, weak);
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return dict_type.validate_skip(ops, cs, weak);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -910,7 +910,7 @@ extern const HashmapE t_IhrPendingInfo;
|
|||
|
||||
struct OutMsgQueueInfo final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
extern const OutMsgQueueInfo t_OutMsgQueueInfo;
|
||||
|
@ -946,7 +946,7 @@ struct ShardIdent final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return cs.advance(get_size(cs));
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return 0;
|
||||
}
|
||||
|
@ -985,7 +985,7 @@ struct BlockIdExt final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return cs.advance(get_size(cs));
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool unpack(vm::CellSlice& cs, ton::BlockIdExt& data) const;
|
||||
bool pack(vm::CellBuilder& cb, const ton::BlockIdExt& data) const;
|
||||
};
|
||||
|
@ -995,7 +995,7 @@ extern const BlockIdExt t_BlockIdExt;
|
|||
struct ShardState final : TLB_Complex {
|
||||
enum { shard_state = (int)0x9023afe2, split_state = 0x5f327da5 };
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(32) == shard_state ? shard_state : -1;
|
||||
}
|
||||
|
@ -1005,7 +1005,7 @@ extern const ShardState t_ShardState;
|
|||
|
||||
struct ShardState_aux final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1016,7 +1016,7 @@ extern const ShardState_aux t_ShardState_aux;
|
|||
struct LibDescr final : TLB_Complex {
|
||||
enum { shared_lib_descr = 0 };
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(2);
|
||||
}
|
||||
|
@ -1029,7 +1029,7 @@ struct BlkPrevInfo final : TLB_Complex {
|
|||
BlkPrevInfo(bool _merged) : merged(_merged) {
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
extern const BlkPrevInfo t_BlkPrevInfo_0;
|
||||
|
@ -1037,7 +1037,7 @@ extern const BlkPrevInfo t_BlkPrevInfo_0;
|
|||
struct McStateExtra final : TLB_Complex {
|
||||
enum { masterchain_state_extra = 0xcc26 };
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
};
|
||||
|
||||
extern const McStateExtra t_McStateExtra;
|
||||
|
@ -1074,7 +1074,7 @@ extern const Aug_OldMcBlocksInfo aug_OldMcBlocksInfo;
|
|||
|
||||
struct ShardFeeCreated final : TLB_Complex {
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool null_value(vm::CellBuilder& cb) const override;
|
||||
bool add_values(vm::CellBuilder& cb, vm::CellSlice& cs1, vm::CellSlice& cs2) const override;
|
||||
};
|
||||
|
|
|
@ -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 "td/utils/bits.h"
|
||||
#include "block/block.h"
|
||||
|
@ -813,11 +813,11 @@ td::Status ShardState::unpack_out_msg_queue_info(Ref<vm::Cell> out_msg_queue_inf
|
|||
LOG(DEBUG) << "unpacking ProcessedUpto of our previous block " << id_.to_str();
|
||||
block::gen::t_ProcessedInfo.print(std::cerr, qinfo.proc_info);
|
||||
}
|
||||
if (!block::gen::t_ProcessedInfo.validate_csr(qinfo.proc_info)) {
|
||||
if (!block::gen::t_ProcessedInfo.validate_csr(1024, qinfo.proc_info)) {
|
||||
return td::Status::Error(
|
||||
-666, "ProcessedInfo in the state of "s + id_.to_str() + " is invalid according to automated validity checks");
|
||||
}
|
||||
if (!block::gen::t_IhrPendingInfo.validate_csr(qinfo.ihr_pending)) {
|
||||
if (!block::gen::t_IhrPendingInfo.validate_csr(1024, qinfo.ihr_pending)) {
|
||||
return td::Status::Error(
|
||||
-666, "IhrPendingInfo in the state of "s + id_.to_str() + " is invalid according to automated validity checks");
|
||||
}
|
||||
|
@ -1036,7 +1036,7 @@ td::Status ShardState::split(ton::ShardIdFull subshard) {
|
|||
LOG(DEBUG) << "splitting total_balance";
|
||||
auto old_total_balance = total_balance_;
|
||||
auto accounts_extra = account_dict_->get_root_extra();
|
||||
if (!(accounts_extra.write().advance(5) && total_balance_.validate_unpack(accounts_extra))) {
|
||||
if (!(accounts_extra.write().advance(5) && total_balance_.validate_unpack(accounts_extra, 1024))) {
|
||||
LOG(ERROR) << "cannot unpack CurrencyCollection from the root of newly-split accounts dictionary";
|
||||
return td::Status::Error(
|
||||
-666, "error splitting total balance in account dictionary of shardchain state "s + id_.to_str());
|
||||
|
@ -1085,16 +1085,16 @@ int filter_out_msg_queue(vm::AugmentedDictionary& out_queue, ton::ShardIdFull ol
|
|||
});
|
||||
}
|
||||
|
||||
bool CurrencyCollection::validate() const {
|
||||
return is_valid() && td::sgn(grams) >= 0 && validate_extra();
|
||||
bool CurrencyCollection::validate(int max_cells) const {
|
||||
return is_valid() && td::sgn(grams) >= 0 && validate_extra(max_cells);
|
||||
}
|
||||
|
||||
bool CurrencyCollection::validate_extra() const {
|
||||
bool CurrencyCollection::validate_extra(int max_cells) const {
|
||||
if (extra.is_null()) {
|
||||
return true;
|
||||
}
|
||||
vm::CellBuilder cb;
|
||||
return cb.store_maybe_ref(extra) && block::tlb::t_ExtraCurrencyCollection.validate_ref(cb.finalize());
|
||||
return cb.store_maybe_ref(extra) && block::tlb::t_ExtraCurrencyCollection.validate_ref(max_cells, cb.finalize());
|
||||
}
|
||||
|
||||
bool CurrencyCollection::add(const CurrencyCollection& a, const CurrencyCollection& b, CurrencyCollection& c) {
|
||||
|
@ -1265,8 +1265,8 @@ bool CurrencyCollection::unpack(Ref<vm::CellSlice> csr) {
|
|||
return unpack_CurrencyCollection(std::move(csr), grams, extra) || invalidate();
|
||||
}
|
||||
|
||||
bool CurrencyCollection::validate_unpack(Ref<vm::CellSlice> csr) {
|
||||
return (csr.not_null() && block::tlb::t_CurrencyCollection.validate(*csr) &&
|
||||
bool CurrencyCollection::validate_unpack(Ref<vm::CellSlice> csr, int max_cells) {
|
||||
return (csr.not_null() && block::tlb::t_CurrencyCollection.validate_upto(max_cells, *csr) &&
|
||||
unpack_CurrencyCollection(std::move(csr), grams, extra)) ||
|
||||
invalidate();
|
||||
}
|
||||
|
@ -1593,7 +1593,7 @@ bool check_one_config_param(Ref<vm::CellSlice> cs_ref, td::ConstBitPtr key, td::
|
|||
} else if (idx < 0) {
|
||||
return true;
|
||||
}
|
||||
bool ok = block::gen::ConfigParam{idx}.validate_ref(std::move(cell));
|
||||
bool ok = block::gen::ConfigParam{idx}.validate_ref(1024, std::move(cell));
|
||||
if (!ok) {
|
||||
LOG(ERROR) << "configuration parameter #" << idx << " is invalid";
|
||||
}
|
||||
|
|
|
@ -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 "common/refcnt.hpp"
|
||||
|
@ -323,8 +323,8 @@ struct CurrencyCollection {
|
|||
grams.clear();
|
||||
return false;
|
||||
}
|
||||
bool validate() const;
|
||||
bool validate_extra() const;
|
||||
bool validate(int max_cells = 1024) const;
|
||||
bool validate_extra(int max_cells = 1024) const;
|
||||
bool operator==(const CurrencyCollection& other) const;
|
||||
bool operator!=(const CurrencyCollection& other) const {
|
||||
return !operator==(other);
|
||||
|
@ -360,7 +360,7 @@ struct CurrencyCollection {
|
|||
bool fetch(vm::CellSlice& cs);
|
||||
bool fetch_exact(vm::CellSlice& cs);
|
||||
bool unpack(Ref<vm::CellSlice> csr);
|
||||
bool validate_unpack(Ref<vm::CellSlice> csr);
|
||||
bool validate_unpack(Ref<vm::CellSlice> csr, int max_cells = 1024);
|
||||
Ref<vm::CellSlice> pack() const;
|
||||
bool pack_to(Ref<vm::CellSlice>& csr) const {
|
||||
return (csr = pack()).not_null();
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
@ -697,7 +697,7 @@ void interpret_tlb_skip(vm::Stack& stack) {
|
|||
void interpret_tlb_validate_skip(vm::Stack& stack) {
|
||||
auto tp = pop_tlb_type(stack);
|
||||
auto cs = stack.pop_cellslice();
|
||||
bool ok = (*tp)->validate_skip(cs.write());
|
||||
bool ok = (*tp)->validate_skip_upto(1048576, cs.write());
|
||||
if (ok) {
|
||||
stack.push(std::move(cs));
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "block/block.h"
|
||||
#include "vm/boc.h"
|
||||
|
@ -98,7 +98,7 @@ void test1() {
|
|||
|
||||
block::tlb::ShardIdent::Record shard_id;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::cout << "ShardIdent.validate() = " << block::tlb::t_ShardIdent.validate(csl) << std::endl;
|
||||
std::cout << "ShardIdent.validate() = " << block::tlb::t_ShardIdent.validate_upto(1024, csl) << std::endl;
|
||||
csl.print_rec(std::cerr);
|
||||
csl.dump(std::cerr, 7);
|
||||
std::cout << "ShardIdent.unpack() = " << block::tlb::t_ShardIdent.unpack(csl, shard_id) << std::endl;
|
||||
|
@ -107,9 +107,9 @@ void test1() {
|
|||
<< " shard_prefix:" << shard_id.shard_prefix << std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl;
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl;
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip(csl) << std::endl;
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip_upto(1024, csl) << std::endl;
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip_upto(1024, csl) << std::endl;
|
||||
std::cout << "ShardIdent.skip_validate() = " << block::tlb::t_ShardIdent.validate_skip_upto(1024, csl) << std::endl;
|
||||
using namespace td::literals;
|
||||
std::cout << "Grams.store_intval(239) = " << block::tlb::t_Grams.store_integer_value(cb, "239"_i256) << std::endl;
|
||||
std::cout << "Grams.store_intval(17239) = " << block::tlb::t_Grams.store_integer_value(cb, "17239"_i256) << std::endl;
|
||||
|
@ -120,13 +120,13 @@ void test1() {
|
|||
std::cout << "Grams.store_intval(666) = " << block::tlb::t_Grams.store_integer_value(cb, "666"_i256) << std::endl;
|
||||
std::cout << cb << std::endl;
|
||||
cs2 = td::Ref<vm::CellSlice>{true, cb.finalize()};
|
||||
std::cout << "Grams.validate(cs) = " << block::tlb::t_Grams.validate(*cs) << std::endl;
|
||||
std::cout << "Grams.validate(cs2) = " << block::tlb::t_Grams.validate(*cs2) << std::endl;
|
||||
std::cout << "Grams.validate(cs) = " << block::tlb::t_Grams.validate_upto(1024, *cs) << std::endl;
|
||||
std::cout << "Grams.validate(cs2) = " << block::tlb::t_Grams.validate_upto(1024, *cs2) << std::endl;
|
||||
//
|
||||
block::gen::SplitMergeInfo::Record data;
|
||||
block::gen::Grams::Record data2;
|
||||
std::cout << "block::gen::Grams.validate(cs) = " << block::gen::t_Grams.validate(*cs) << std::endl;
|
||||
std::cout << "block::gen::Grams.validate(cs2) = " << block::gen::t_Grams.validate(*cs2) << std::endl;
|
||||
std::cout << "block::gen::Grams.validate(cs) = " << block::gen::t_Grams.validate_upto(1024, *cs) << std::endl;
|
||||
std::cout << "block::gen::Grams.validate(cs2) = " << block::gen::t_Grams.validate_upto(1024, *cs2) << std::endl;
|
||||
std::cout << "[cs = " << cs << "]" << std::endl;
|
||||
bool ok = tlb::csr_unpack_inexact(cs, data);
|
||||
std::cout << "block::gen::SplitMergeInfo.unpack(cs, data) = " << ok << std::endl;
|
||||
|
@ -182,12 +182,12 @@ void test1() {
|
|||
}
|
||||
|
||||
void test2(vm::CellSlice& cs) {
|
||||
std::cout << "Bool.validate() = " << block::tlb::t_Bool.validate(cs) << std::endl;
|
||||
std::cout << "UInt16.validate() = " << block::tlb::t_uint16.validate(cs) << std::endl;
|
||||
std::cout << "HashmapE(32,UInt16).validate() = " << block::tlb::HashmapE(32, block::tlb::t_uint16).validate(cs)
|
||||
<< std::endl;
|
||||
std::cout << "Bool.validate() = " << block::tlb::t_Bool.validate_upto(1024, cs) << std::endl;
|
||||
std::cout << "UInt16.validate() = " << block::tlb::t_uint16.validate_upto(1024, cs) << std::endl;
|
||||
std::cout << "HashmapE(32,UInt16).validate() = "
|
||||
<< block::tlb::HashmapE(32, block::tlb::t_uint16).validate_upto(1024, cs) << std::endl;
|
||||
std::cout << "block::gen::HashmapE(32,UInt16).validate() = "
|
||||
<< block::gen::HashmapE{32, block::gen::t_uint16}.validate(cs) << std::endl;
|
||||
<< block::gen::HashmapE{32, block::gen::t_uint16}.validate_upto(1024, cs) << std::endl;
|
||||
}
|
||||
|
||||
void usage() {
|
||||
|
@ -249,7 +249,7 @@ int main(int argc, char* const argv[]) {
|
|||
}
|
||||
type->print_ref(std::cout, boc);
|
||||
std::cout << std::endl;
|
||||
bool ok = type->validate_ref(boc);
|
||||
bool ok = type->validate_ref(1048576, boc);
|
||||
std::cout << "(" << (ok ? "" : "in") << "valid " << *type << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1239,7 +1239,7 @@ bool ShardConfig::new_workchain(ton::WorkchainId workchain, ton::BlockSeqno reg_
|
|||
cb.store_zeroes_bool(
|
||||
1 + 5 +
|
||||
5) // split_merge_at:FutureSplitMerge fees_collected:CurrencyCollection funds_created:CurrencyCollection
|
||||
&& cb.finalize_to(cell) && block::gen::t_BinTree_ShardDescr.validate_ref(cell) &&
|
||||
&& cb.finalize_to(cell) && block::gen::t_BinTree_ShardDescr.validate_ref(1024, cell) &&
|
||||
shard_hashes_dict_->set_ref(td::BitArray<32>{workchain}, std::move(cell), vm::Dictionary::SetMode::Add);
|
||||
}
|
||||
|
||||
|
@ -1469,7 +1469,7 @@ static bool btree_set(Ref<vm::Cell>& root, ton::ShardId shard, Ref<vm::Cell> val
|
|||
}
|
||||
|
||||
bool ShardConfig::set_shard_info(ton::ShardIdFull shard, Ref<vm::Cell> value) {
|
||||
if (!gen::t_BinTree_ShardDescr.validate_ref(value)) {
|
||||
if (!gen::t_BinTree_ShardDescr.validate_ref(1024, value)) {
|
||||
LOG(ERROR) << "attempting to store an invalid (BinTree ShardDescr) at shard configuration position "
|
||||
<< shard.to_str();
|
||||
gen::t_BinTree_ShardDescr.print_ref(std::cerr, value);
|
||||
|
|
|
@ -150,7 +150,7 @@ bool Account::unpack_storage_info(vm::CellSlice& cs) {
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
due_payment = td::RefInt256{true, 0};
|
||||
due_payment = td::zero_refint();
|
||||
}
|
||||
unsigned long long u = 0;
|
||||
u |= storage_stat.cells = block::tlb::t_VarUInteger_7.as_uint(*used.cells);
|
||||
|
@ -369,7 +369,7 @@ bool Account::init_new(ton::UnixTime now) {
|
|||
now_ = now;
|
||||
last_paid = 0;
|
||||
storage_stat.clear();
|
||||
due_payment = td::RefInt256{true, 0};
|
||||
due_payment = td::zero_refint();
|
||||
balance.set_zero();
|
||||
if (my_addr_exact.is_null()) {
|
||||
vm::CellBuilder cb;
|
||||
|
@ -473,6 +473,9 @@ Transaction::Transaction(const Account& _account, int ttype, ton::LogicalTime re
|
|||
start_lt = std::max(req_start_lt, account.last_trans_end_lt_);
|
||||
end_lt = start_lt + 1;
|
||||
acc_status = (account.status == Account::acc_nonexist ? Account::acc_uninit : account.status);
|
||||
if (acc_status == Account::acc_frozen) {
|
||||
frozen_hash = account.state_hash;
|
||||
}
|
||||
}
|
||||
|
||||
bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* cfg) {
|
||||
|
@ -504,7 +507,7 @@ bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig*
|
|||
if (ihr_delivered) {
|
||||
in_fwd_fee = std::move(ihr_fee);
|
||||
} else {
|
||||
in_fwd_fee = td::RefInt256{true, 0};
|
||||
in_fwd_fee = td::zero_refint();
|
||||
msg_balance_remaining += std::move(ihr_fee);
|
||||
}
|
||||
if (info.created_lt >= start_lt) {
|
||||
|
@ -544,7 +547,7 @@ bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig*
|
|||
LOG(DEBUG) << "computed fwd fees set to zero for special account";
|
||||
fees_c.first = fees_c.second = 0;
|
||||
}
|
||||
in_fwd_fee = td::RefInt256{true, fees_c.first};
|
||||
in_fwd_fee = td::make_refint(fees_c.first);
|
||||
if (balance.grams < in_fwd_fee) {
|
||||
LOG(DEBUG) << "cannot pay for importing this external message";
|
||||
return false;
|
||||
|
@ -616,19 +619,19 @@ bool Transaction::prepare_storage_phase(const StoragePhaseConfig& cfg, bool forc
|
|||
res->is_special = account.is_special;
|
||||
last_paid = res->last_paid_updated = (res->is_special ? 0 : now);
|
||||
if (to_pay.is_null() || sgn(to_pay) == 0) {
|
||||
res->fees_collected = res->fees_due = td::RefInt256{true, 0};
|
||||
res->fees_collected = res->fees_due = td::zero_refint();
|
||||
} else if (to_pay <= balance.grams) {
|
||||
res->fees_collected = to_pay;
|
||||
res->fees_due = td::RefInt256{true, 0};
|
||||
res->fees_due = td::zero_refint();
|
||||
balance -= std::move(to_pay);
|
||||
} else if (acc_status == Account::acc_frozen && !force_collect && to_pay + due_payment < cfg.delete_due_limit) {
|
||||
// do not collect fee
|
||||
res->last_paid_updated = (res->is_special ? 0 : account.last_paid);
|
||||
res->fees_collected = res->fees_due = td::RefInt256{true, 0};
|
||||
res->fees_collected = res->fees_due = td::zero_refint();
|
||||
} else {
|
||||
res->fees_collected = balance.grams;
|
||||
res->fees_due = std::move(to_pay) - std::move(balance.grams);
|
||||
balance.grams = td::RefInt256{true, 0};
|
||||
balance.grams = td::zero_refint();
|
||||
if (!res->is_special) {
|
||||
auto total_due = res->fees_due + due_payment;
|
||||
switch (acc_status) {
|
||||
|
@ -707,8 +710,8 @@ bool ComputePhaseConfig::parse_GasLimitsPrices_internal(Ref<vm::CellSlice> cs, t
|
|||
special_gas_limit = spec_limit;
|
||||
gas_credit = r.gas_credit;
|
||||
gas_price = r.gas_price;
|
||||
freeze_due_limit = td::RefInt256{true, r.freeze_due_limit};
|
||||
delete_due_limit = td::RefInt256{true, r.delete_due_limit};
|
||||
freeze_due_limit = td::make_refint(r.freeze_due_limit);
|
||||
delete_due_limit = td::make_refint(r.delete_due_limit);
|
||||
};
|
||||
block::gen::GasLimitsPrices::Record_gas_prices_ext rec;
|
||||
if (tlb::csr_unpack(cs, rec)) {
|
||||
|
@ -728,10 +731,10 @@ bool ComputePhaseConfig::parse_GasLimitsPrices_internal(Ref<vm::CellSlice> cs, t
|
|||
}
|
||||
|
||||
void ComputePhaseConfig::compute_threshold() {
|
||||
gas_price256 = td::RefInt256{true, gas_price};
|
||||
gas_price256 = td::make_refint(gas_price);
|
||||
if (gas_limit > flat_gas_limit) {
|
||||
max_gas_threshold =
|
||||
td::rshift(gas_price256 * (gas_limit - flat_gas_limit), 16, 1) + td::make_refint(flat_gas_price);
|
||||
td::rshift(gas_price256 * (gas_limit - flat_gas_limit), 16, 1) + td::make_bigint(flat_gas_price);
|
||||
} else {
|
||||
max_gas_threshold = td::make_refint(flat_gas_price);
|
||||
}
|
||||
|
@ -828,8 +831,8 @@ Ref<vm::Tuple> Transaction::prepare_vm_c7(const ComputePhaseConfig& cfg) const {
|
|||
}
|
||||
auto tuple = vm::make_tuple_ref(
|
||||
td::make_refint(0x076ef1ea), // [ magic:0x076ef1ea
|
||||
td::make_refint(0), // actions:Integer
|
||||
td::make_refint(0), // msgs_sent:Integer
|
||||
td::zero_refint(), // actions:Integer
|
||||
td::zero_refint(), // msgs_sent:Integer
|
||||
td::make_refint(now), // unixtime:Integer
|
||||
td::make_refint(account.block_lt), // block_lt:Integer
|
||||
td::make_refint(start_lt), // trans_lt:Integer
|
||||
|
@ -1012,7 +1015,7 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
|
|||
}
|
||||
if (cp.accepted) {
|
||||
if (account.is_special) {
|
||||
cp.gas_fees = td::RefInt256{true, 0};
|
||||
cp.gas_fees = td::zero_refint();
|
||||
} else {
|
||||
cp.gas_fees = cfg.compute_gas_price(cp.gas_used);
|
||||
total_fees += cp.gas_fees;
|
||||
|
@ -1040,8 +1043,8 @@ bool Transaction::prepare_action_phase(const ActionPhaseConfig& cfg) {
|
|||
ap.action_list_hash = list->get_hash().bits();
|
||||
ap.remaining_balance = balance;
|
||||
ap.end_lt = end_lt;
|
||||
ap.total_fwd_fees = td::RefInt256{true, 0};
|
||||
ap.total_action_fees = td::RefInt256{true, 0};
|
||||
ap.total_fwd_fees = td::zero_refint();
|
||||
ap.total_action_fees = td::zero_refint();
|
||||
ap.reserved_balance.set_zero();
|
||||
|
||||
int n = 0;
|
||||
|
@ -1429,7 +1432,7 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
|||
info.ihr_disabled = true;
|
||||
info.bounce = false;
|
||||
info.bounced = false;
|
||||
fwd_fee = ihr_fee = td::RefInt256{true, 0};
|
||||
fwd_fee = ihr_fee = td::zero_refint();
|
||||
} else {
|
||||
// int_msg_info$0 constructor
|
||||
if (!tlb::csr_unpack(msg.info, info) || !block::tlb::t_CurrencyCollection.validate_csr(info.value)) {
|
||||
|
@ -1482,10 +1485,10 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
|||
|
||||
// set fees to computed values
|
||||
if (fwd_fee->unsigned_fits_bits(63) && fwd_fee->to_long() < (long long)fees_c.first) {
|
||||
fwd_fee = td::RefInt256{true, fees_c.first};
|
||||
fwd_fee = td::make_refint(fees_c.first);
|
||||
}
|
||||
if (fees_c.second && ihr_fee->unsigned_fits_bits(63) && ihr_fee->to_long() < (long long)fees_c.second) {
|
||||
ihr_fee = td::RefInt256{true, fees_c.second};
|
||||
ihr_fee = td::make_refint(fees_c.second);
|
||||
}
|
||||
|
||||
Ref<vm::Cell> new_msg;
|
||||
|
@ -1502,7 +1505,7 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap,
|
|||
}
|
||||
if (info.ihr_disabled) {
|
||||
// if IHR is disabled, IHR fees will be always zero
|
||||
ihr_fee = td::RefInt256{true, 0};
|
||||
ihr_fee = td::zero_refint();
|
||||
}
|
||||
// extract value to be carried by the message
|
||||
block::CurrencyCollection req;
|
||||
|
@ -1757,10 +1760,10 @@ bool Transaction::prepare_bounce_phase(const ActionPhaseConfig& cfg) {
|
|||
balance -= msg_balance;
|
||||
CHECK(balance.is_valid());
|
||||
// debit total forwarding fees from the message's balance, then split forwarding fees into our part and remaining part
|
||||
msg_balance -= td::RefInt256{true, bp.fwd_fees};
|
||||
msg_balance -= td::make_refint(bp.fwd_fees);
|
||||
bp.fwd_fees_collected = msg_prices.get_first_part(bp.fwd_fees);
|
||||
bp.fwd_fees -= bp.fwd_fees_collected;
|
||||
total_fees += td::RefInt256{true, bp.fwd_fees_collected};
|
||||
total_fees += td::make_refint(bp.fwd_fees_collected);
|
||||
// serialize outbound message
|
||||
info.created_lt = end_lt++;
|
||||
info.created_at = now;
|
||||
|
|
|
@ -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 <vector>
|
||||
|
@ -169,6 +169,8 @@ class PropagateConstSpan {
|
|||
size_t size_{0};
|
||||
};
|
||||
|
||||
struct Normalize {};
|
||||
|
||||
template <class Tr = BigIntInfo>
|
||||
class AnyIntView {
|
||||
public:
|
||||
|
@ -308,6 +310,10 @@ class BigIntG {
|
|||
explicit BigIntG(word_t x) : n(1) {
|
||||
digits[0] = x;
|
||||
}
|
||||
BigIntG(Normalize, word_t x) : n(1) {
|
||||
digits[0] = x;
|
||||
normalize_bool();
|
||||
}
|
||||
BigIntG(const BigIntG& x) : n(x.n) {
|
||||
std::memcpy(digits, x.digits, n * sizeof(word_t));
|
||||
///std::cout << "(BiCC " << (const void*)&x << "->" << (void*)this << ")";
|
||||
|
@ -2515,6 +2521,11 @@ extern template class AnyIntView<BigIntInfo>;
|
|||
extern template class BigIntG<257, BigIntInfo>;
|
||||
typedef BigIntG<257, BigIntInfo> BigInt256;
|
||||
|
||||
template <int n = 257>
|
||||
BigIntG<n, BigIntInfo> make_bigint(long long x) {
|
||||
return BigIntG<n, BigIntInfo>{Normalize(), x};
|
||||
}
|
||||
|
||||
namespace literals {
|
||||
|
||||
extern BigInt256 operator""_i256(const char* str, std::size_t str_len);
|
||||
|
|
|
@ -38,6 +38,11 @@ RefInt256 operator+(RefInt256 x, long long y) {
|
|||
return x;
|
||||
}
|
||||
|
||||
RefInt256 operator+(RefInt256 x, const BigInt256& y) {
|
||||
(x.write() += y).normalize();
|
||||
return x;
|
||||
}
|
||||
|
||||
RefInt256 operator-(RefInt256 x, RefInt256 y) {
|
||||
(x.write() -= *y).normalize();
|
||||
return x;
|
||||
|
@ -48,6 +53,11 @@ RefInt256 operator-(RefInt256 x, long long y) {
|
|||
return x;
|
||||
}
|
||||
|
||||
RefInt256 operator-(RefInt256 x, const BigInt256& y) {
|
||||
(x.write() -= y).normalize();
|
||||
return x;
|
||||
}
|
||||
|
||||
RefInt256 operator-(RefInt256 x) {
|
||||
x.write().negate().normalize();
|
||||
return x;
|
||||
|
@ -69,6 +79,12 @@ RefInt256 operator*(RefInt256 x, long long y) {
|
|||
return x;
|
||||
}
|
||||
|
||||
RefInt256 operator*(RefInt256 x, const BigInt256& y) {
|
||||
RefInt256 z{true, 0};
|
||||
z.write().add_mul(*x, y).normalize();
|
||||
return z;
|
||||
}
|
||||
|
||||
RefInt256 operator/(RefInt256 x, RefInt256 y) {
|
||||
RefInt256 quot{true};
|
||||
x.write().mod_div(*y, quot.write());
|
||||
|
@ -142,6 +158,11 @@ RefInt256& operator+=(RefInt256& x, long long y) {
|
|||
return x;
|
||||
}
|
||||
|
||||
RefInt256& operator+=(RefInt256& x, const BigInt256& y) {
|
||||
(x.write() += y).normalize();
|
||||
return x;
|
||||
}
|
||||
|
||||
RefInt256& operator-=(RefInt256& x, RefInt256 y) {
|
||||
(x.write() -= *y).normalize();
|
||||
return x;
|
||||
|
@ -152,6 +173,11 @@ RefInt256& operator-=(RefInt256& x, long long y) {
|
|||
return x;
|
||||
}
|
||||
|
||||
RefInt256& operator-=(RefInt256& x, const BigInt256& y) {
|
||||
(x.write() -= y).normalize();
|
||||
return x;
|
||||
}
|
||||
|
||||
RefInt256& operator*=(RefInt256& x, RefInt256 y) {
|
||||
RefInt256 z{true, 0};
|
||||
z.write().add_mul(*x, *y).normalize();
|
||||
|
@ -163,6 +189,12 @@ RefInt256& operator*=(RefInt256& x, long long y) {
|
|||
return x;
|
||||
}
|
||||
|
||||
RefInt256& operator*=(RefInt256& x, const BigInt256& y) {
|
||||
RefInt256 z{true, 0};
|
||||
z.write().add_mul(*x, y).normalize();
|
||||
return x = z;
|
||||
}
|
||||
|
||||
RefInt256& operator/=(RefInt256& x, RefInt256 y) {
|
||||
RefInt256 quot{true};
|
||||
x.write().mod_div(*y, quot.write());
|
||||
|
@ -214,9 +246,13 @@ int sgn(RefInt256 x) {
|
|||
}
|
||||
|
||||
RefInt256 make_refint(long long x) {
|
||||
auto xx = td::RefInt256{true, x};
|
||||
xx.unique_write().normalize();
|
||||
return xx;
|
||||
return td::RefInt256{true, td::Normalize(), x};
|
||||
}
|
||||
|
||||
RefInt256 zero_refint() {
|
||||
// static RefInt256 Zero = td::RefInt256{true, 0};
|
||||
// return Zero;
|
||||
return td::RefInt256{true, 0};
|
||||
}
|
||||
|
||||
RefInt256 bits_to_refint(td::ConstBitPtr bits, int n, bool sgnd) {
|
||||
|
|
|
@ -33,10 +33,13 @@ typedef Ref<CntInt256> RefInt256;
|
|||
|
||||
extern RefInt256 operator+(RefInt256 x, RefInt256 y);
|
||||
extern RefInt256 operator+(RefInt256 x, long long y);
|
||||
extern RefInt256 operator+(RefInt256 x, const BigInt256& y);
|
||||
extern RefInt256 operator-(RefInt256 x, RefInt256 y);
|
||||
extern RefInt256 operator-(RefInt256 x, long long y);
|
||||
extern RefInt256 operator-(RefInt256 x, const BigInt256& y);
|
||||
extern RefInt256 operator*(RefInt256 x, RefInt256 y);
|
||||
extern RefInt256 operator*(RefInt256 x, long long y);
|
||||
extern RefInt256 operator*(RefInt256 x, const BigInt256& y);
|
||||
extern RefInt256 operator/(RefInt256 x, RefInt256 y);
|
||||
extern RefInt256 operator%(RefInt256 x, RefInt256 y);
|
||||
extern RefInt256 div(RefInt256 x, RefInt256 y, int round_mode = -1);
|
||||
|
@ -53,10 +56,13 @@ extern RefInt256 rshift(RefInt256 x, int y, int round_mode = -1);
|
|||
|
||||
extern RefInt256& operator+=(RefInt256& x, RefInt256 y);
|
||||
extern RefInt256& operator+=(RefInt256& x, long long y);
|
||||
extern RefInt256& operator+=(RefInt256& x, const BigInt256& y);
|
||||
extern RefInt256& operator-=(RefInt256& x, RefInt256 y);
|
||||
extern RefInt256& operator-=(RefInt256& x, long long y);
|
||||
extern RefInt256& operator-=(RefInt256& x, const BigInt256& y);
|
||||
extern RefInt256& operator*=(RefInt256& x, RefInt256 y);
|
||||
extern RefInt256& operator*=(RefInt256& x, long long y);
|
||||
extern RefInt256& operator*=(RefInt256& x, const BigInt256& y);
|
||||
extern RefInt256& operator/=(RefInt256& x, RefInt256 y);
|
||||
extern RefInt256& operator%=(RefInt256& x, RefInt256 y);
|
||||
|
||||
|
@ -100,7 +106,14 @@ extern int cmp(RefInt256 x, RefInt256 y);
|
|||
extern int cmp(RefInt256 x, long long y);
|
||||
extern int sgn(RefInt256 x);
|
||||
|
||||
template <typename... Args>
|
||||
RefInt256 make_refint(Args&&... args) {
|
||||
return td::RefInt256{true, std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
extern RefInt256 make_refint(long long x);
|
||||
|
||||
extern RefInt256 zero_refint();
|
||||
extern RefInt256 bits_to_refint(td::ConstBitPtr bits, int n, bool sgnd = false);
|
||||
|
||||
extern std::string dec_string(RefInt256 x);
|
||||
|
|
|
@ -180,9 +180,9 @@ void interpret_times_div(vm::Stack& stack, int round_mode) {
|
|||
auto z = stack.pop_int();
|
||||
auto y = stack.pop_int();
|
||||
auto x = stack.pop_int();
|
||||
td::BigIntG<257 * 2> tmp{0};
|
||||
typename td::BigInt256::DoubleInt tmp{0};
|
||||
tmp.add_mul(*x, *y);
|
||||
auto q = td::RefInt256{true};
|
||||
auto q = td::make_refint();
|
||||
tmp.mod_div(*z, q.unique_write(), round_mode);
|
||||
q.unique_write().normalize();
|
||||
stack.push_int(std::move(q));
|
||||
|
@ -192,26 +192,23 @@ void interpret_times_divmod(vm::Stack& stack, int round_mode) {
|
|||
auto z = stack.pop_int();
|
||||
auto y = stack.pop_int();
|
||||
auto x = stack.pop_int();
|
||||
td::BigIntG<257 * 2> tmp{0};
|
||||
typename td::BigInt256::DoubleInt tmp{0};
|
||||
tmp.add_mul(*x, *y);
|
||||
auto q = td::RefInt256{true};
|
||||
auto q = td::make_refint();
|
||||
tmp.mod_div(*z, q.unique_write(), round_mode);
|
||||
q.unique_write().normalize();
|
||||
auto r = td::RefInt256{true, tmp};
|
||||
stack.push_int(std::move(q));
|
||||
stack.push_int(std::move(r));
|
||||
stack.push_int(td::make_refint(tmp));
|
||||
}
|
||||
|
||||
void interpret_times_mod(vm::Stack& stack, int round_mode) {
|
||||
auto z = stack.pop_int();
|
||||
auto y = stack.pop_int();
|
||||
auto x = stack.pop_int();
|
||||
td::BigIntG<257 * 2> tmp{0};
|
||||
typename td::BigInt256::DoubleInt tmp{0}, q;
|
||||
tmp.add_mul(*x, *y);
|
||||
td::BigIntG<257 * 2> q;
|
||||
tmp.mod_div(*z, q, round_mode);
|
||||
auto r = td::RefInt256{true, tmp};
|
||||
stack.push_int(std::move(r));
|
||||
stack.push_int(td::make_refint(tmp));
|
||||
}
|
||||
|
||||
void interpret_negate(vm::Stack& stack) {
|
||||
|
@ -253,21 +250,21 @@ void interpret_fits(vm::Stack& stack, bool sgnd) {
|
|||
|
||||
void interpret_pow2(vm::Stack& stack) {
|
||||
int x = stack.pop_smallint_range(255);
|
||||
auto r = td::RefInt256{true};
|
||||
auto r = td::make_refint();
|
||||
r.unique_write().set_pow2(x);
|
||||
stack.push_int(r);
|
||||
}
|
||||
|
||||
void interpret_neg_pow2(vm::Stack& stack) {
|
||||
int x = stack.pop_smallint_range(256);
|
||||
auto r = td::RefInt256{true};
|
||||
auto r = td::make_refint();
|
||||
r.unique_write().set_pow2(x).negate().normalize();
|
||||
stack.push_int(r);
|
||||
}
|
||||
|
||||
void interpret_pow2_minus1(vm::Stack& stack) {
|
||||
int x = stack.pop_smallint_range(256);
|
||||
auto r = td::RefInt256{true};
|
||||
auto r = td::make_refint();
|
||||
r.unique_write().set_pow2(x).add_tiny(-1).normalize();
|
||||
stack.push_int(r);
|
||||
}
|
||||
|
@ -301,19 +298,18 @@ void interpret_times_rshift(vm::Stack& stack, int round_mode) {
|
|||
int z = stack.pop_smallint_range(256);
|
||||
auto y = stack.pop_int();
|
||||
auto x = stack.pop_int();
|
||||
td::BigIntG<257 * 2> tmp{0};
|
||||
typename td::BigInt256::DoubleInt tmp{0};
|
||||
tmp.add_mul(*x, *y).rshift(z, round_mode).normalize();
|
||||
auto q = td::RefInt256{true, tmp};
|
||||
stack.push_int(std::move(q));
|
||||
stack.push_int(td::make_refint(tmp));
|
||||
}
|
||||
|
||||
void interpret_lshift_div(vm::Stack& stack, int round_mode) {
|
||||
int z = stack.pop_smallint_range(256);
|
||||
auto y = stack.pop_int();
|
||||
auto x = stack.pop_int();
|
||||
td::BigIntG<257 * 2> tmp{*x};
|
||||
typename td::BigInt256::DoubleInt tmp{*x};
|
||||
tmp <<= z;
|
||||
auto q = td::RefInt256{true};
|
||||
auto q = td::make_refint();
|
||||
tmp.mod_div(*y, q.unique_write(), round_mode);
|
||||
q.unique_write().normalize();
|
||||
stack.push_int(std::move(q));
|
||||
|
@ -1932,7 +1928,7 @@ int parse_number(std::string s, td::RefInt256& num, td::RefInt256& denom, bool a
|
|||
const char* str = s.c_str();
|
||||
int len = (int)s.size();
|
||||
int frac = -1, base, *frac_ptr = allow_frac ? &frac : nullptr;
|
||||
num = td::RefInt256{true};
|
||||
num = td::make_refint();
|
||||
auto& x = num.unique_write();
|
||||
if (len >= 4 && str[0] == '-' && str[1] == '0' && (str[2] == 'x' || str[2] == 'b')) {
|
||||
if (str[2] == 'x') {
|
||||
|
@ -1974,7 +1970,7 @@ int parse_number(std::string s, td::RefInt256& num, td::RefInt256& denom, bool a
|
|||
if (frac < 0) {
|
||||
return 1;
|
||||
} else {
|
||||
denom = td::RefInt256{true, 1};
|
||||
denom = td::make_refint(1);
|
||||
while (frac-- > 0) {
|
||||
if (!denom.unique_write().mul_tiny(base).normalize_bool()) {
|
||||
if (throw_error) {
|
||||
|
|
|
@ -138,7 +138,7 @@ void VarDescr::show(std::ostream& os, const char* name) const {
|
|||
}
|
||||
|
||||
void VarDescr::set_const(long long value) {
|
||||
return set_const(td::RefInt256{true, value});
|
||||
return set_const(td::make_refint(value));
|
||||
}
|
||||
|
||||
void VarDescr::set_const(td::RefInt256 value) {
|
||||
|
@ -169,7 +169,7 @@ void VarDescr::set_const(td::RefInt256 value) {
|
|||
}
|
||||
|
||||
void VarDescr::set_const_nan() {
|
||||
set_const(td::RefInt256{true});
|
||||
set_const(td::make_refint());
|
||||
}
|
||||
|
||||
void VarDescr::operator|=(const VarDescr& y) {
|
||||
|
|
|
@ -628,7 +628,7 @@ AsmOp compile_mod(std::vector<VarDescr>& res, std::vector<VarDescr>& args, int r
|
|||
if ((*y.int_const == 1 || *y.int_const == -1) && x.always_finite()) {
|
||||
x.unused();
|
||||
y.unused();
|
||||
r.set_const(td::RefInt256{true, 0});
|
||||
r.set_const(td::zero_refint());
|
||||
return push_const(r.int_const);
|
||||
}
|
||||
int k = is_pos_pow2(y.int_const);
|
||||
|
|
|
@ -934,7 +934,7 @@ struct AsmOp {
|
|||
void out_indent_nl(std::ostream& os, bool no_nl = false) const;
|
||||
std::string to_string() const;
|
||||
void compute_gconst() {
|
||||
gconst = (is_custom() && (op == "PUSHNULL" || op == "NEWC"));
|
||||
gconst = (is_custom() && (op == "PUSHNULL" || op == "NEWC" || op == "NEWB" || op == "TRUE" || op == "FALSE"));
|
||||
}
|
||||
bool is_nop() const {
|
||||
return t == a_none && op.empty();
|
||||
|
@ -975,6 +975,9 @@ struct AsmOp {
|
|||
*y = b;
|
||||
return is_xchg();
|
||||
}
|
||||
bool is_xchg_short() const {
|
||||
return is_xchg() && (a <= 1 || b <= 1);
|
||||
}
|
||||
bool is_swap() const {
|
||||
return is_xchg(0, 1);
|
||||
}
|
||||
|
@ -1265,10 +1268,14 @@ struct StackTransform {
|
|||
}
|
||||
bool is_xchg(int i, int j) const;
|
||||
bool is_xchg(int* i, int* j) const;
|
||||
bool is_xchg_xchg(int i, int j, int k, int l) const;
|
||||
bool is_xchg_xchg(int* i, int* j, int* k, int* l) const;
|
||||
bool is_push(int i) const;
|
||||
bool is_push(int* i) const;
|
||||
bool is_pop(int i) const;
|
||||
bool is_pop(int* i) const;
|
||||
bool is_pop_pop(int i, int j) const;
|
||||
bool is_pop_pop(int* i, int* j) const;
|
||||
bool is_rot() const;
|
||||
bool is_rotrev() const;
|
||||
bool is_push_rot(int i) const;
|
||||
|
@ -1407,8 +1414,10 @@ struct Optimizer {
|
|||
bool is_2swap();
|
||||
bool is_2over();
|
||||
bool is_xchg(int* i, int* j);
|
||||
bool is_xchg_xchg(int* i, int* j, int* k, int* l);
|
||||
bool is_push(int* i);
|
||||
bool is_pop(int* i);
|
||||
bool is_pop_pop(int* i, int* j);
|
||||
bool is_nop();
|
||||
bool is_push_rot(int* i);
|
||||
bool is_push_rotrev(int* i);
|
||||
|
|
|
@ -393,6 +393,13 @@ bool Optimizer::is_xchg(int* i, int* j) {
|
|||
return is_pred([i, j](const auto& t) { return t.is_xchg(i, j) && ((*i < 16 && *j < 16) || (!*i && *j < 256)); });
|
||||
}
|
||||
|
||||
bool Optimizer::is_xchg_xchg(int* i, int* j, int* k, int* l) {
|
||||
return is_pred([i, j, k, l](const auto& t) {
|
||||
return t.is_xchg_xchg(i, j, k, l) && (*i < 2 && *j < (*i ? 16 : 256) && *k < 2 && *l < (*k ? 16 : 256));
|
||||
}) &&
|
||||
(!(p_ == 2 && op_[0]->is_xchg(*i, *j) && op_[1]->is_xchg(*k, *l)));
|
||||
}
|
||||
|
||||
bool Optimizer::is_push(int* i) {
|
||||
return is_pred([i](const auto& t) { return t.is_push(i) && *i < 256; });
|
||||
}
|
||||
|
@ -401,6 +408,10 @@ bool Optimizer::is_pop(int* i) {
|
|||
return is_pred([i](const auto& t) { return t.is_pop(i) && *i < 256; });
|
||||
}
|
||||
|
||||
bool Optimizer::is_pop_pop(int* i, int* j) {
|
||||
return is_pred([i, j](const auto& t) { return t.is_pop_pop(i, j) && *i < 256 && *j < 256; }, 3);
|
||||
}
|
||||
|
||||
bool Optimizer::is_push_rot(int* i) {
|
||||
return is_pred([i](const auto& t) { return t.is_push_rot(i) && *i < 16; }, 3);
|
||||
}
|
||||
|
@ -543,12 +554,13 @@ bool Optimizer::find_at_least(int pb) {
|
|||
p_ = q_ = 0;
|
||||
pb_ = pb;
|
||||
// show_stack_transforms();
|
||||
int i = -100, j = -100, k = -100, c = 0;
|
||||
int i, j, k, l, c;
|
||||
return (is_push_const(&i, &c) && rewrite_push_const(i, c)) || (is_nop() && rewrite_nop()) ||
|
||||
(!(mode_ & 1) && is_const_rot(&c) && rewrite_const_rot(c)) ||
|
||||
(is_const_push_xchgs() && rewrite_const_push_xchgs()) || (is_const_pop(&c, &i) && rewrite_const_pop(c, i)) ||
|
||||
(is_xchg(&i, &j) && rewrite(AsmOp::Xchg(i, j))) || (is_push(&i) && rewrite(AsmOp::Push(i))) ||
|
||||
(is_pop(&i) && rewrite(AsmOp::Pop(i))) ||
|
||||
(is_pop(&i) && rewrite(AsmOp::Pop(i))) || (is_pop_pop(&i, &j) && rewrite(AsmOp::Pop(i), AsmOp::Pop(j))) ||
|
||||
(is_xchg_xchg(&i, &j, &k, &l) && rewrite(AsmOp::Xchg(i, j), AsmOp::Xchg(k, l))) ||
|
||||
(!(mode_ & 1) &&
|
||||
((is_rot() && rewrite(AsmOp::Custom("ROT", 3, 3))) || (is_rotrev() && rewrite(AsmOp::Custom("-ROT", 3, 3))) ||
|
||||
(is_2dup() && rewrite(AsmOp::Custom("2DUP", 2, 4))) ||
|
||||
|
@ -629,10 +641,9 @@ void optimize_code(AsmOpList& ops) {
|
|||
for (auto it = ops.list_.rbegin(); it < ops.list_.rend(); ++it) {
|
||||
op_list = AsmOpCons::cons(std::make_unique<AsmOp>(std::move(*it)), std::move(op_list));
|
||||
}
|
||||
op_list = optimize_code(std::move(op_list), 1);
|
||||
op_list = optimize_code(std::move(op_list), 1);
|
||||
op_list = optimize_code(std::move(op_list), 0);
|
||||
op_list = optimize_code(std::move(op_list), 0);
|
||||
for (int mode : {1, 1, 1, 1, 0, 0, 0, 0}) {
|
||||
op_list = optimize_code(std::move(op_list), mode);
|
||||
}
|
||||
ops.list_.clear();
|
||||
while (op_list) {
|
||||
ops.list_.push_back(std::move(*(op_list->car)));
|
||||
|
|
|
@ -401,6 +401,57 @@ bool StackTransform::is_xchg(int *i, int *j) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool StackTransform::is_xchg_xchg(int i, int j, int k, int l) const {
|
||||
if (is_valid() && !d && n <= 4 && (i | j | k | l) >= 0) {
|
||||
StackTransform t;
|
||||
return t.apply_xchg(i, j) && t.apply_xchg(k, l) && t <= *this;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool StackTransform::is_xchg_xchg(int *i, int *j, int *k, int *l) const {
|
||||
if (!is_valid() || d || n > 4 || !dp || !is_permutation()) {
|
||||
return false;
|
||||
}
|
||||
if (!n) {
|
||||
*i = *j = *k = *l = 0;
|
||||
return true;
|
||||
}
|
||||
if (n <= 2) {
|
||||
*k = *l = 0;
|
||||
return is_xchg(i, j);
|
||||
}
|
||||
if (n == 3) {
|
||||
// rotation: a -> b -> c -> a
|
||||
int a = A[0].first;
|
||||
int b = A[0].second;
|
||||
int s = (b == A[2].first ? 2 : 1);
|
||||
int c = A[s].second;
|
||||
if (b != A[s].first || c != A[3 - s].first || a != A[3 - s].second) {
|
||||
return false;
|
||||
}
|
||||
// implement as XCHG s(a),s(c) ; XCHG s(a),s(b)
|
||||
*i = *k = a;
|
||||
*j = c;
|
||||
*l = b;
|
||||
return is_xchg_xchg(*i, *j, *k, *l);
|
||||
}
|
||||
*i = A[0].first;
|
||||
*j = A[0].second;
|
||||
if (get(*j) != *i) {
|
||||
return false;
|
||||
}
|
||||
for (int s = 1; s < 4; s++) {
|
||||
if (A[s].first != *j) {
|
||||
*k = A[s].first;
|
||||
*l = A[s].second;
|
||||
return get(*l) == *k && is_xchg_xchg(*i, *j, *k, *l);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StackTransform::is_push(int i) const {
|
||||
return is_valid() && d == -1 && n == 1 && A[0].first == -1 && A[0].second == i;
|
||||
}
|
||||
|
@ -418,6 +469,7 @@ bool StackTransform::is_push(int *i) const {
|
|||
// 0 2 3 4 .. = pop1
|
||||
// 1 0 3 4 .. = pop2
|
||||
// 1 2 0 4 .. = pop3
|
||||
// POP s(i) : 1 2 ... i-1 0 i+1 ... ; d=1, n=1, {(i,0)}
|
||||
bool StackTransform::is_pop(int i) const {
|
||||
if (!is_valid() || d != 1 || n > 1 || i < 0) {
|
||||
return false;
|
||||
|
@ -443,6 +495,38 @@ bool StackTransform::is_pop(int *i) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
// POP s(i) ; POP s(j) : 2 ... i-1 0 i+1 ... j 1 j+2 ... ; d=2, n=2, {(i,0),(j+1,1)} if i <> j+1
|
||||
bool StackTransform::is_pop_pop(int i, int j) const {
|
||||
if (is_valid() && d == 2 && n <= 2 && i >= 0 && j >= 0) {
|
||||
StackTransform t;
|
||||
return t.apply_pop(i) && t.apply_pop(j) && t <= *this;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool StackTransform::is_pop_pop(int *i, int *j) const {
|
||||
if (!is_valid() || d != 2 || n > 2) {
|
||||
return false;
|
||||
}
|
||||
if (!n) {
|
||||
*i = *j = 0; // 2DROP
|
||||
} else if (n == 2) {
|
||||
*i = A[0].first - A[0].second;
|
||||
*j = A[1].first - A[1].second;
|
||||
if (A[0].second > A[1].second) {
|
||||
std::swap(*i, *j);
|
||||
}
|
||||
} else if (!A[0].second) {
|
||||
*i = A[0].first;
|
||||
*j = 0;
|
||||
} else {
|
||||
*i = 0;
|
||||
*j = A[0].first - 1;
|
||||
}
|
||||
return is_pop_pop(*i, *j);
|
||||
}
|
||||
|
||||
const StackTransform StackTransform::rot{2, 0, 1, 3};
|
||||
const StackTransform StackTransform::rot_rev{1, 2, 0, 3};
|
||||
|
||||
|
@ -519,10 +603,9 @@ bool StackTransform::is_xchg2(int *i, int *j) const {
|
|||
if (*i < 0 || *j < 0) {
|
||||
return false;
|
||||
}
|
||||
if (n != 3) {
|
||||
return is_xchg2(*i, *j);
|
||||
}
|
||||
if (*i) {
|
||||
if (n == 2 && !*i) {
|
||||
*j = *i; // XCHG s0,s1 = XCHG2 s0,s0
|
||||
} else if (n == 3 && *i) {
|
||||
// XCHG2 s(i),s(i) = XCHG s1,s(i) ; XCHG s0,s(i) : 0->1, 1->i
|
||||
*j = *i;
|
||||
} // XCHG2 s0,s(i) = XCHG s0,s1 ; XCHG s0,s(i) : 0->i, 1->0
|
||||
|
|
115
crypto/smartcont/auto-dns.fif
Normal file
115
crypto/smartcont/auto-dns.fif
Normal file
|
@ -0,0 +1,115 @@
|
|||
#!/usr/bin/fift -s
|
||||
"TonUtil.fif" include
|
||||
"GetOpt.fif" include
|
||||
|
||||
{ show-options-help 1 halt } : usage
|
||||
|
||||
"dns-msg-body.boc" =: savefile
|
||||
|
||||
begin-options
|
||||
" <auto-dns-addr> [-o<savefile-boc>] (add|update|prolong) <subdomain> <expire-in-sec> ... " +cr +tab
|
||||
+"Creates the internal message body containing a request to automatic DNS smart contract <auto-dns-addr> created by new-auto-dns.fif, "
|
||||
+"to be sent later with a suitable payment from a wallet to <auto-dns-addr>, and saves it into <savefile-boc> ('" savefile $+ +"' by default). "
|
||||
+"The operation to be performed is one of" +cr +tab
|
||||
+"add <subdomain> <expire-in-sec> { owner <smc-addr> | cat <cat-id> (smc <smc-addr> | next <next-resolver-smc-addr> | adnl <adnl-addr> | text <string>) }" +cr +tab
|
||||
+"update <subdomain> <expire-in-sec> { owner <smc-addr> | cat <cat-id> (smc <smc-addr> | next <next-resolver-smc-addr> | adnl <adnl-addr> | text <string>) }" +cr +tab
|
||||
+"prolong <subdomain> <expire-in-sec>"
|
||||
disable-digit-options generic-help-setopt
|
||||
"o" "--output" { =: savefile } short-long-option-arg
|
||||
"Sets output file for generated initialization message ('" savefile $+ +"' by default)" option-help
|
||||
"h" "--help" { usage } short-long-option
|
||||
"Shows a help message" option-help
|
||||
parse-options
|
||||
|
||||
$# 4 < ' usage if
|
||||
4 :$1..n
|
||||
|
||||
$1 true parse-load-address =: bounce 2=: dest-addr
|
||||
$2 dup =: main-op-name atom =: main-op
|
||||
$3 dup =: subdomain $len 127 > abort"subdomain name too long"
|
||||
$4 parse-int dup 30 1<< < { now + } if =: expire-at
|
||||
|
||||
{ $* @ dup null? { second $@ ! } { drop } cond } : @skip
|
||||
{ $* @ null? } : @end?
|
||||
{ $* @ uncons $* ! } : @next
|
||||
{ @next drop } 4 times
|
||||
|
||||
main-op dup `add eq? over `update eq? or swap `prolong eq? or
|
||||
{ "unknown main operation '" main-op-name $+ +"'; one of 'add', 'update' or 'prolong' expected" abort } ifnot
|
||||
main-op `prolong eq? not =: need-params
|
||||
|
||||
$# 4 > need-params <> abort"extra parameters, or no parameters for chosen main operation"
|
||||
|
||||
variable Values dictnew Values !
|
||||
// ( i c -- )
|
||||
{ over 0= abort"category cannot be zero"
|
||||
<b swap ref, swap Values @ 16 b>idict!+ not abort"duplicate category id"
|
||||
Values !
|
||||
} : register-value
|
||||
|
||||
{ @end? abort"category number expected" @next (number) 1 <> abort"category must be integer"
|
||||
dup 16 fits not abort"category does not fit into 16 bit integer"
|
||||
dup 0= abort"category must be non-zero"
|
||||
} : parse-cat-num
|
||||
{ @end? abort"smart contract address expected"
|
||||
@next false parse-load-address drop
|
||||
} : cl-parse-smc-addr
|
||||
{ @end? abort"adnl address expected"
|
||||
@next parse-adnl-addr
|
||||
} : cl-parse-adnl-addr
|
||||
{ <b x{9fd3} s, -rot Addr, 0 8 u, b> } : serialize-smc-addr
|
||||
{ <b x{ba93} s, -rot Addr, b> } : serialize-next-resolver
|
||||
{ <b x{ad01} s, swap 256 u, 0 8 u, b> } : serialize-adnl-addr
|
||||
{ <b x{1eda01} s, over $len 8 u, swap $, b> } : serialize-text
|
||||
{ @end? abort"subdomain record value expected" @next
|
||||
dup "smc" $= { drop cl-parse-smc-addr serialize-smc-addr } {
|
||||
dup "next" $= { drop cl-parse-smc-addr serialize-next-resolver } {
|
||||
dup "adnl" $= { drop cl-parse-adnl-addr serialize-adnl-addr } {
|
||||
dup "text" $= { drop @next serialize-text } {
|
||||
"unknown record type "' swap $+ +"'" abort
|
||||
} cond } cond } cond } cond
|
||||
} : parse-value
|
||||
{ @next dup "owner" $= { drop -2 cl-parse-smc-addr serialize-smc-addr } {
|
||||
dup "cat" $= { drop parse-cat-num parse-value } {
|
||||
"unknown action '" swap $+ +"'" abort
|
||||
} cond } cond
|
||||
register-value
|
||||
} : parse-action
|
||||
{ { @end? not } { parse-action } while } : parse-actions
|
||||
parse-actions
|
||||
|
||||
// ( S -- S1 .. Sn n )
|
||||
{ 1 swap { dup "." $pos dup 0>= } { $| 1 $| nip rot 1+ swap } while drop swap
|
||||
} : split-by-dots
|
||||
// ( S -- s )
|
||||
{ dup $len dup 0= abort"subdomain cannot be empty" 126 > abort"subdomain too long"
|
||||
dup 0 chr $pos 1+ abort"subdomain contains null characters"
|
||||
split-by-dots <b { // ... S b
|
||||
swap dup $len 0= abort"empty subdomain component" $, 0 8 u,
|
||||
} rot times b> <s
|
||||
} : subdomain>s
|
||||
|
||||
main-op ( _( `add 0x72656764 ) _( `update 0x75706464 ) _( `prolong 0x70726f6c ) )
|
||||
assq-val not abort"unknown main operation"
|
||||
=: op-id
|
||||
|
||||
."Automatic DNS smart contract address = " dest-addr 2dup .addr cr 6 .Addr cr
|
||||
|
||||
."Action: " main-op .l subdomain type space expire-at . cr
|
||||
."Operation code: 0x" op-id 8 0X. cr
|
||||
."Value: "
|
||||
Values @ dup null? { drop ."(none)" } { <s csr. } cond cr
|
||||
|
||||
<b op-id 32 u, expire-at 32 u, Values @ dict, b> =: actions-builder
|
||||
|
||||
// create an internal message
|
||||
now 32 << actions-builder hashu 32 1<<1- and + =: query_id
|
||||
<b op-id 32 i, query_id 64 u,
|
||||
subdomain subdomain>s tuck sbits 8 / 7 i, swap s,
|
||||
main-op `prolong eq? { Values @ ref, } ifnot
|
||||
expire-at 32 u, b>
|
||||
dup ."Internal message body is: " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
."Query_id is " query_id dup . ."= 0x" X. cr
|
||||
savefile tuck B>file
|
||||
."(Saved to file " type .")" cr
|
|
@ -107,22 +107,24 @@ global var query_info;
|
|||
;; no iterating and deleting all to not put too much gas gc
|
||||
;; burden on any random specific user request
|
||||
;; over time it will do the garbage collection required
|
||||
(int mkey, cell domain, int found?) = gc.udict_get_min_ref?(32 + 128);
|
||||
(int mkey, _, int found?) = gc.udict_get_min?(256);
|
||||
while (found? & max_steps) { ;; no short circuit optimization, two nested ifs
|
||||
nhk = (mkey >> 128);
|
||||
nhk = (mkey >> (256 - 32));
|
||||
if (nhk < n) {
|
||||
slice sdomain = domain.begin_parse();
|
||||
(_, slice val, _, found?) = dd.pfxdict_get?(1023, sdomain);
|
||||
int key = mkey % (1 << (256 - 32));
|
||||
(slice val, found?) = dd.udict_get?(256 - 32, key);
|
||||
if (found?) {
|
||||
int exp = val.preload_uint(32);
|
||||
if (exp <= n) {
|
||||
dd~pfxdict_delete?(1023, sdomain);
|
||||
dd~udict_delete?(256 - 32, key);
|
||||
}
|
||||
}
|
||||
gc~udict_delete?(32 + 128, mkey);
|
||||
(mkey, domain, found?) = gc.udict_get_min_ref?(32 + 128);
|
||||
nhk = (found? ? mkey >> 32 : 0xffffffff);
|
||||
gc~udict_delete?(256, mkey);
|
||||
(mkey, _, found?) = gc.udict_get_min?(256);
|
||||
nhk = (found? ? mkey >> (256 - 32) : 0xffffffff);
|
||||
max_steps -= 1;
|
||||
} else {
|
||||
found? = false;
|
||||
}
|
||||
}
|
||||
store_data(ctl, dd, gc, prices, nhk, n);
|
||||
|
@ -134,16 +136,15 @@ int calcprice_internal(slice domain, cell data, ppc, ppb) inline_ref { ;; only f
|
|||
return ppc * (refs + 2) + ppb * bits;
|
||||
}
|
||||
|
||||
int check_owner(cell cat_table, int src_wc, int src_addr) inline_ref {
|
||||
if (cat_table.null?()) { ;; domain not found: return notf | 2^31
|
||||
int check_owner(cell cat_table, cell owner_info, int src_wc, int src_addr, int strict) inline_ref {
|
||||
if (strict & cat_table.null?()) { ;; domain not found: return notf | 2^31
|
||||
return 0xee6f7466;
|
||||
}
|
||||
cell cown = cat_table.idict_get_ref(16, -2);
|
||||
if (cown.null?()) { ;; no owner on this domain: no-2
|
||||
return 0xee6f2d32;
|
||||
if (owner_info.null?()) { ;; no owner on this domain: no-2 (in strict mode), ok else
|
||||
return strict & 0xee6f2d32;
|
||||
}
|
||||
var ERR_BAD2 = 0xe2616432;
|
||||
slice sown = cown.begin_parse();
|
||||
slice sown = owner_info.begin_parse();
|
||||
if (sown.slice_bits() < 16 + 3 + 8 + 256) { ;; bad owner record: bad2
|
||||
return ERR_BAD2;
|
||||
}
|
||||
|
@ -272,38 +273,38 @@ int check_owner(cell cat_table, int src_wc, int src_addr) inline_ref {
|
|||
return send_error(0xee6f5c30);
|
||||
}
|
||||
|
||||
int zeros = 0;
|
||||
slice cdomain = domain;
|
||||
repeat (cdomain.slice_bits() ^>> 3) {
|
||||
int c = cdomain~load_uint(8);
|
||||
zeros -= (c == 0);
|
||||
}
|
||||
|
||||
;; if (zeros != 1) { ;; too much zero chars (overflow): ov\0
|
||||
;; return send_error(0xef765c30); }
|
||||
|
||||
domain = begin_cell().store_uint(zeros, 7).store_slice(domain).end_cell().begin_parse();
|
||||
|
||||
(slice pfx, slice val, slice tail, int found?) = domdata.pfxdict_get?(1023, domain);
|
||||
int n = now();
|
||||
cell cat_table = null();
|
||||
int exp = 0;
|
||||
|
||||
if (found?) {
|
||||
exp = val~load_uint(32);
|
||||
if (n > exp) { ;; expired domains behave as not registered
|
||||
found? = false;
|
||||
} else {
|
||||
cat_table = val.preload_ref();
|
||||
cell cat_table = cell owner_info = null();
|
||||
int key = int exp = int zeros = 0;
|
||||
slice tail = domain;
|
||||
repeat (tail.slice_bits() ^>> 3) {
|
||||
cat_table = null();
|
||||
int z = (tail~load_uint(8) == 0);
|
||||
zeros -= z;
|
||||
if (z) {
|
||||
key = (string_hash(domain.skip_last_bits(tail.slice_bits())) >> 32);
|
||||
var (val, found?) = domdata.udict_get?(256 - 32, key);
|
||||
if (found?) {
|
||||
exp = val~load_uint(32);
|
||||
if (exp >= n) { ;; entry not expired
|
||||
cell cat_table = val~load_ref();
|
||||
val.end_parse();
|
||||
var (cown, ok) = cat_table.idict_get_ref?(16, -2);
|
||||
if (ok) {
|
||||
owner_info = cown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zeros > 4) { ;; too much zero chars (overflow): ov\0
|
||||
return send_error(0xef765c30);
|
||||
}
|
||||
|
||||
;; ##########################################################################
|
||||
|
||||
int err = 0;
|
||||
if (qt != 1) { ;; not a "register", check that domain exists and is controlled by correct smc
|
||||
err = check_owner(cat_table, src_wc, src_addr);
|
||||
}
|
||||
int err = check_owner(cat_table, owner_info, src_wc, src_addr, qt != 1);
|
||||
if (err) {
|
||||
return send_error(err);
|
||||
}
|
||||
|
@ -317,8 +318,14 @@ int check_owner(cell cat_table, int src_wc, int src_addr) inline_ref {
|
|||
data = in_msg~load_ref();
|
||||
;; basic integrity check of (client-provided) dictionary
|
||||
ifnot (data.dict_empty?()) { ;; 1000 gas!
|
||||
(_, _, int minok) = idict_get_min?(data, 16);
|
||||
(_, _, int maxok) = idict_get_max?(data, 16);
|
||||
var (oinfo, ok) = data.idict_get_ref?(16, -2);
|
||||
if (ok) {
|
||||
var cs = oinfo.begin_parse();
|
||||
throw_unless(31, cs.slice_bits() >= 16 + 3 + 8 + 256);
|
||||
throw_unless(31, cs.preload_uint(19) == 0x9fd3 * 8 + 4);
|
||||
}
|
||||
(_, _, int minok) = data.idict_get_min?(16);
|
||||
(_, _, int maxok) = data.idict_get_max?(16);
|
||||
throw_unless(31, minok & maxok);
|
||||
}
|
||||
} else {
|
||||
|
@ -345,17 +352,12 @@ int check_owner(cell cat_table, int src_wc, int src_addr) inline_ref {
|
|||
if (exp > n + stdper) { ;; does not expire soon, cannot prolong
|
||||
return send_error(0xf365726f);
|
||||
}
|
||||
slice value = begin_cell().store_uint(exp + stdper, 32).store_ref(data).end_cell().begin_parse();
|
||||
|
||||
ifnot (domdata~pfxdict_set?(1023, domain, value)) { ;; Set ERR | 2^31
|
||||
return send_error(0xf3657272);
|
||||
}
|
||||
|
||||
int sh_low = domain.slice_hash() & ((1 << 128) - 1);
|
||||
int gckeyO = (exp << 128) + sh_low;
|
||||
int gckeyN = gckeyO + (stdper << 128);
|
||||
gc~udict_delete?(32 + 128, gckeyO); ;; delete old gc entry, add new
|
||||
gc~udict_set_ref(32 + 128, gckeyN, begin_cell().store_slice(domain).end_cell());
|
||||
domdata~udict_set_builder(256 - 32, key, begin_cell().store_uint(exp + stdper, 32).store_ref(data));
|
||||
|
||||
int gckeyO = (exp << (256 - 32)) + key;
|
||||
int gckeyN = gckeyO + (stdper << (256 - 32));
|
||||
gc~udict_delete?(256, gckeyO); ;; delete old gc entry, add new
|
||||
gc~udict_set_builder(256, gckeyN, begin_cell());
|
||||
|
||||
housekeeping(ctl, domdata, gc, prices, nhk, lhk, 1);
|
||||
return send_ok(price);
|
||||
|
@ -363,29 +365,22 @@ int check_owner(cell cat_table, int src_wc, int src_addr) inline_ref {
|
|||
|
||||
;; ##########################################################################
|
||||
if (qt == 1) { ;; 0x72656764 -> regd | register domain
|
||||
if (found?) { ;; domain already exists: return alre | 2^31
|
||||
ifnot (cat_table.null?()) { ;; domain already exists: return alre | 2^31
|
||||
return send_error(0xe16c7265);
|
||||
}
|
||||
int expires_at = n + stdper;
|
||||
slice value = begin_cell().store_uint(expires_at, 32).store_ref(data).end_cell().begin_parse();
|
||||
ifnot (domdata~pfxdict_set?(1023, domain, value)) { ;; Set ERR | 2^31
|
||||
return send_error(0xf3657272);
|
||||
}
|
||||
int gckey = (expires_at << 128) | (domain.slice_hash() & ((1 << 128) - 1));
|
||||
gc~udict_set_ref(32 + 128, gckey, begin_cell().store_slice(domain).end_cell());
|
||||
;; using ref requires additional cell, but using value (DICTUSET) may
|
||||
;; cause problems with very long domains or complex dictionaries
|
||||
domdata~udict_set_builder(256 - 32, key, begin_cell().store_uint(expires_at, 32).store_ref(data));
|
||||
|
||||
int gckey = (expires_at << (256 - 32)) | key;
|
||||
gc~udict_set_builder(256, gckey, begin_cell());
|
||||
|
||||
housekeeping(ctl, domdata, gc, prices, min(nhk, expires_at), lhk, 1);
|
||||
return send_ok(price);
|
||||
}
|
||||
|
||||
;; ##########################################################################
|
||||
if (qt == 4) { ;; 0x75706464 -> updd | update domain (data)
|
||||
slice value = begin_cell().store_uint(exp, 32).store_ref(data).end_cell().begin_parse();
|
||||
|
||||
ifnot (domdata~pfxdict_set?(1023, domain, value)) { ;; Set ERR | 2^31
|
||||
return send_error(0xf3657272);
|
||||
}
|
||||
domdata~udict_set_builder(256 - 32, key, begin_cell().store_uint(exp, 32).store_ref(data));
|
||||
housekeeping(ctl, domdata, gc, prices, nhk, lhk, 1);
|
||||
return send_ok(price);
|
||||
}
|
||||
|
@ -412,54 +407,46 @@ int check_owner(cell cat_table, int src_wc, int src_addr) inline_ref {
|
|||
;;===========================================================================;;
|
||||
|
||||
(int, cell, int, slice) dnsdictlookup(slice domain, int nowtime) inline_ref {
|
||||
int bits = domain.slice_bits();
|
||||
(int bits, int refs) = domain.slice_bits_refs();
|
||||
throw_if(30, refs | (bits & 7)); ;; malformed input (~ 8n-bit)
|
||||
ifnot (bits) {
|
||||
return (0, null(), 0, null()); ;; zero-length input
|
||||
}
|
||||
throw_if(30, bits & 7); ;; malformed input (~ 8n-bit)
|
||||
|
||||
int domain_last_byte = domain.slice_last(8).preload_uint(8);
|
||||
if (domain_last_byte) {
|
||||
domain = begin_cell().store_slice(domain) ;; append zero byte
|
||||
.store_uint(0, 8).end_cell().begin_parse();
|
||||
.store_uint(0, 8).end_cell().begin_parse();
|
||||
bits += 8;
|
||||
}
|
||||
if (bits == 8) {
|
||||
return (0, null(), 0, null()); ;; zero-length input, but with zero byte
|
||||
}
|
||||
(_, cell root) = get_data().begin_parse().load_dict();
|
||||
var ds = get_data().begin_parse();
|
||||
(_, cell root) = (ds~load_ref(), ds~load_dict());
|
||||
|
||||
slice sd_tail = domain;
|
||||
int zeros = 0;
|
||||
repeat (bits >> 3) {
|
||||
int c = sd_tail~load_uint(8);
|
||||
zeros -= (c == 0);
|
||||
}
|
||||
|
||||
;; can't move these declarations lower, will cause errors!
|
||||
slice tail = slice pfx = sd_tail;
|
||||
slice val = null();
|
||||
int exp = 0;
|
||||
int tail_bits = -1;
|
||||
slice tail = domain;
|
||||
|
||||
do {
|
||||
slice pfxname = begin_cell().store_uint(zeros, 7)
|
||||
.store_slice(domain).end_cell().begin_parse();
|
||||
(pfx, val, tail, int succ) = root.pfxdict_get?(1023, pfxname);
|
||||
if (succ) {
|
||||
int exp = val~load_uint(32);
|
||||
if (nowtime > exp) { ;; entry expired, skip
|
||||
succ = false;
|
||||
repeat (bits >> 3) {
|
||||
if (tail~load_uint(8) == 0) {
|
||||
var key = (string_hash(domain.skip_last_bits(tail.slice_bits())) >> 32);
|
||||
var (v, found?) = root.udict_get?(256 - 32, key);
|
||||
if (found?) {
|
||||
if (v.preload_uint(32) >= nowtime) { ;; entry not expired
|
||||
val = v;
|
||||
tail_bits = tail.slice_bits();
|
||||
}
|
||||
}
|
||||
}
|
||||
zeros = succ ^ (zeros - 1); ;; break on success
|
||||
} until (zeros <= 0);
|
||||
|
||||
ifnot (zeros) {
|
||||
return (0, null(), 0, null()); ;; failed to find entry in prefix dictionary
|
||||
}
|
||||
|
||||
zeros = - zeros;
|
||||
return (exp, val.preload_ref(), tail.slice_empty?(), pfx);
|
||||
if (val.null?()) {
|
||||
return (0, null(), 0, null()); ;; failed to find entry in subdomain dictionary
|
||||
}
|
||||
|
||||
return (val~load_uint(32), val~load_ref(), tail_bits == 0, domain.skip_last_bits(tail_bits));
|
||||
}
|
||||
|
||||
;;8m dns-record-value
|
||||
|
@ -472,12 +459,12 @@ int check_owner(cell cat_table, int src_wc, int src_addr) inline_ref {
|
|||
category = -1;
|
||||
}
|
||||
|
||||
int pfx_bits = pfx.slice_bits() - 7;
|
||||
int pfx_bits = pfx.slice_bits();
|
||||
|
||||
;; pfx.slice_bits() will contain 8m, where m is number of bytes in subdomain
|
||||
;; COUNTING the zero byte (if structurally correct: no multiple-ZB keys)
|
||||
;; which corresponds to 8m, m=one plus the number of bytes in the subdomain found)
|
||||
if (category == 0) {
|
||||
ifnot (category) {
|
||||
return (pfx_bits, cat_table); ;; return cell with entire dictionary for 0
|
||||
} else {
|
||||
cell cat_found = cat_table.idict_get_ref(16, category);
|
||||
|
|
|
@ -94,8 +94,8 @@ file-base +"-dns" +contractid +".addr" load-address
|
|||
// ( b V -- b' )
|
||||
{ dup first
|
||||
dup `smc eq? { drop untriple 2swap drop x{9fd3} s, -rot Addr, 0 8 u, } {
|
||||
dup `next eq? { drop untriple 2swap drop x{ba93} s, -rot Addr, 0 8 u, } {
|
||||
dup `adnl eq? { drop second swap x{ad01} s, swap 256 u, } {
|
||||
dup `next eq? { drop untriple 2swap drop x{ba93} s, -rot Addr, } {
|
||||
dup `adnl eq? { drop second swap x{ad01} s, swap 256 u, 0 8 u, } {
|
||||
dup `text eq? { drop second swap x{1eda01} s, over $len 8 u, swap $, } {
|
||||
abort"unknown value type"
|
||||
} cond } cond } cond } cond
|
||||
|
|
|
@ -6,6 +6,11 @@ forall X -> (X, tuple) uncons(tuple list) asm "UNCONS";
|
|||
forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS";
|
||||
forall X -> X car(tuple list) asm "CAR";
|
||||
tuple cdr(tuple list) asm "CDR";
|
||||
tuple empty_tuple() asm "NIL";
|
||||
forall X -> tuple tpush(tuple t, X value) asm "TPUSH";
|
||||
forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH";
|
||||
forall X -> [X] single(X x) asm "SINGLE";
|
||||
forall X -> X unsingle([X] t) asm "UNSINGLE";
|
||||
forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR";
|
||||
forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR";
|
||||
forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE";
|
||||
|
@ -22,6 +27,7 @@ forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST";
|
|||
forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND";
|
||||
forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD";
|
||||
forall X -> X null() asm "PUSHNULL";
|
||||
forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP";
|
||||
|
||||
int now() asm "NOW";
|
||||
slice my_address() asm "MYADDR";
|
||||
|
@ -115,7 +121,8 @@ cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value inde
|
|||
cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF";
|
||||
(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF";
|
||||
cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF";
|
||||
cell udict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETOPTREF";
|
||||
(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF";
|
||||
(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF";
|
||||
(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF";
|
||||
(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF";
|
||||
(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL";
|
||||
|
|
|
@ -146,6 +146,23 @@ td::Result<DnsInterface::EntryData> DnsInterface::EntryData::from_cellslice(vm::
|
|||
return td::Status::Error("Unknown entry data");
|
||||
}
|
||||
|
||||
SmartContract::Args DnsInterface::resolve_args_raw(td::Slice encoded_name, td::int16 category) {
|
||||
SmartContract::Args res;
|
||||
res.set_method_id("dnsresolve");
|
||||
res.set_stack(
|
||||
{vm::load_cell_slice_ref(vm::CellBuilder().store_bytes(encoded_name).finalize()), td::make_refint(category)});
|
||||
return res;
|
||||
}
|
||||
|
||||
td::Result<SmartContract::Args> DnsInterface::resolve_args(td::Slice name, td::int32 category_big) {
|
||||
TRY_RESULT(category, td::narrow_cast_safe<td::int16>(category_big));
|
||||
if (name.size() > get_default_max_name_size()) {
|
||||
return td::Status::Error("Name is too long");
|
||||
}
|
||||
auto encoded_name = encode_name(name);
|
||||
return resolve_args_raw(encoded_name, category);
|
||||
}
|
||||
|
||||
td::Result<std::vector<DnsInterface::Entry>> DnsInterface::resolve(td::Slice name, td::int32 category) const {
|
||||
TRY_RESULT(raw_entries, resolve_raw(name, category));
|
||||
std::vector<Entry> entries;
|
||||
|
@ -375,7 +392,7 @@ td::Ref<vm::Cell> ManualDns::create_init_data_fast(const td::Ed25519::PublicKey&
|
|||
}
|
||||
|
||||
size_t ManualDns::get_max_name_size() const {
|
||||
return 128;
|
||||
return get_default_max_name_size();
|
||||
}
|
||||
|
||||
td::Result<std::vector<ManualDns::RawEntry>> ManualDns::resolve_raw(td::Slice name, td::int32 category_big) const {
|
||||
|
@ -388,9 +405,7 @@ td::Result<std::vector<ManualDns::RawEntry>> ManualDns::resolve_raw_or_throw(td:
|
|||
return td::Status::Error("Name is too long");
|
||||
}
|
||||
auto encoded_name = encode_name(name);
|
||||
auto res = run_get_method(
|
||||
"dnsresolve",
|
||||
{vm::load_cell_slice_ref(vm::CellBuilder().store_bytes(encoded_name).finalize()), td::make_refint(category)});
|
||||
auto res = run_get_method(resolve_args_raw(encoded_name, category));
|
||||
if (!res.success) {
|
||||
return td::Status::Error("get method failed");
|
||||
}
|
||||
|
@ -471,7 +486,7 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_update_query(td::Ed25519::Privat
|
|||
return sign(pk, std::move(prepared));
|
||||
}
|
||||
|
||||
std::string ManualDns::encode_name(td::Slice name) {
|
||||
std::string DnsInterface::encode_name(td::Slice name) {
|
||||
std::string res;
|
||||
while (!name.empty()) {
|
||||
auto pos = name.rfind('.');
|
||||
|
@ -487,7 +502,7 @@ std::string ManualDns::encode_name(td::Slice name) {
|
|||
return res;
|
||||
}
|
||||
|
||||
std::string ManualDns::decode_name(td::Slice name) {
|
||||
std::string DnsInterface::decode_name(td::Slice name) {
|
||||
std::string res;
|
||||
if (!name.empty() && name.back() == 0) {
|
||||
name.remove_suffix(1);
|
||||
|
|
|
@ -165,6 +165,15 @@ class DnsInterface {
|
|||
td::uint32 valid_until = std::numeric_limits<td::uint32>::max()) const = 0;
|
||||
|
||||
td::Result<std::vector<Entry>> resolve(td::Slice name, td::int32 category) const;
|
||||
|
||||
static std::string encode_name(td::Slice name);
|
||||
static std::string decode_name(td::Slice name);
|
||||
|
||||
static size_t get_default_max_name_size() {
|
||||
return 128;
|
||||
}
|
||||
static SmartContract::Args resolve_args_raw(td::Slice encoded_name, td::int16 category);
|
||||
static td::Result<SmartContract::Args> resolve_args(td::Slice name, td::int32 category);
|
||||
};
|
||||
|
||||
class ManualDns : public ton::SmartContract, public DnsInterface {
|
||||
|
@ -223,9 +232,6 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
|
|||
td::Ed25519::PrivateKey& pk, td::Span<Action> actions,
|
||||
td::uint32 valid_until = std::numeric_limits<td::uint32>::max()) const override;
|
||||
|
||||
static std::string encode_name(td::Slice name);
|
||||
static std::string decode_name(td::Slice name);
|
||||
|
||||
template <class ActionT>
|
||||
struct CombinedActions {
|
||||
std::string name;
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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 2019-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "MultisigWallet.h"
|
||||
|
||||
#include "SmartContractCode.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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 2019-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "vm/cells.h"
|
||||
|
||||
|
|
|
@ -24,19 +24,21 @@
|
|||
#include "block/block-auto.h"
|
||||
#include "vm/cellslice.h"
|
||||
#include "vm/cp0.h"
|
||||
#include "vm/memo.h"
|
||||
#include "vm/vm.h"
|
||||
|
||||
#include "td/utils/crypto.h"
|
||||
|
||||
namespace ton {
|
||||
namespace {
|
||||
|
||||
td::Ref<vm::Stack> prepare_vm_stack(td::Ref<vm::CellSlice> body) {
|
||||
td::Ref<vm::Stack> stack_ref{true};
|
||||
td::RefInt256 acc_addr{true};
|
||||
//CHECK(acc_addr.write().import_bits(account.addr.cbits(), 256));
|
||||
vm::Stack& stack = stack_ref.write();
|
||||
stack.push_int(td::RefInt256{true, 10000000000});
|
||||
stack.push_int(td::RefInt256{true, 10000000000});
|
||||
stack.push_int(td::make_refint(10000000000));
|
||||
stack.push_int(td::make_refint(10000000000));
|
||||
stack.push_cell(vm::CellBuilder().finalize());
|
||||
stack.push_cellslice(std::move(body));
|
||||
return stack_ref;
|
||||
|
@ -90,6 +92,11 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
|
|||
}
|
||||
|
||||
SmartContract::Answer res;
|
||||
if (GET_VERBOSITY_LEVEL() >= VERBOSITY_NAME(DEBUG)) {
|
||||
std::ostringstream os;
|
||||
stack->dump(os, 2);
|
||||
LOG(DEBUG) << "VM stack:\n" << os.str();
|
||||
}
|
||||
vm::VmState vm{state.code, std::move(stack), gas, 1, state.data, log};
|
||||
vm.set_c7(std::move(c7));
|
||||
vm.set_chksig_always_succeed(ignore_chksig);
|
||||
|
@ -124,6 +131,21 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
|
|||
}
|
||||
} // namespace
|
||||
|
||||
td::Result<td::BufferSlice> SmartContract::Args::get_serialized_stack() {
|
||||
if (!stack) {
|
||||
return td::Status::Error("Args has no stack");
|
||||
}
|
||||
vm::FakeVmStateLimits fstate(1000); // limit recursive (de)serialization calls
|
||||
vm::VmStateInterface::Guard guard(&fstate);
|
||||
// serialize parameters
|
||||
vm::CellBuilder cb;
|
||||
td::Ref<vm::Cell> cell;
|
||||
if (!(stack.value()->serialize(cb) && cb.finalize_to(cell))) {
|
||||
return td::Status::Error("Cannot serialize stack in args");
|
||||
}
|
||||
return vm::std_boc_serialize(std::move(cell));
|
||||
}
|
||||
|
||||
td::Ref<vm::CellSlice> SmartContract::empty_slice() {
|
||||
return vm::load_cell_slice_ref(vm::CellBuilder().finalize());
|
||||
}
|
||||
|
|
|
@ -90,6 +90,14 @@ class SmartContract : public td::CntObject {
|
|||
this->ignore_chksig = ignore_chksig;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
td::Result<td::int32> get_method_id() const {
|
||||
if (!method_id) {
|
||||
return td::Status::Error("Args has no method id");
|
||||
}
|
||||
return method_id.value();
|
||||
}
|
||||
td::Result<td::BufferSlice> get_serialized_stack();
|
||||
};
|
||||
|
||||
Answer run_method(Args args = {});
|
||||
|
|
|
@ -25,12 +25,12 @@
|
|||
|
||||
namespace ton {
|
||||
namespace {
|
||||
constexpr static int WALLET_REVISION = 2;
|
||||
constexpr static int WALLET2_REVISION = 2;
|
||||
constexpr static int WALLET3_REVISION = 2;
|
||||
constexpr static int HIGHLOAD_WALLET_REVISION = 2;
|
||||
constexpr static int HIGHLOAD_WALLET2_REVISION = 2;
|
||||
constexpr static int DNS_REVISION = 1;
|
||||
// WALLET_REVISION = 2;
|
||||
// WALLET2_REVISION = 2;
|
||||
// WALLET3_REVISION = 2;
|
||||
// HIGHLOAD_WALLET_REVISION = 2;
|
||||
// HIGHLOAD_WALLET2_REVISION = 2;
|
||||
// DNS_REVISION = 1;
|
||||
const auto& get_map() {
|
||||
static auto map = [] {
|
||||
std::map<std::string, td::Ref<vm::Cell>, std::less<>> map;
|
||||
|
|
|
@ -31,8 +31,11 @@ class WalletInterface {
|
|||
struct Gift {
|
||||
block::StdAddress destination;
|
||||
td::int64 gramms;
|
||||
|
||||
bool is_encrypted{false};
|
||||
std::string message;
|
||||
|
||||
td::Ref<vm::Cell> body;
|
||||
};
|
||||
|
||||
virtual ~WalletInterface() {
|
||||
|
@ -50,6 +53,13 @@ class WalletInterface {
|
|||
return make_a_gift_message(private_key, valid_until, {});
|
||||
}
|
||||
static void store_gift_message(vm::CellBuilder &cb, const Gift &gift) {
|
||||
if (gift.body.not_null()) {
|
||||
auto body = vm::load_cell_slice(gift.body);
|
||||
//TODO: handle error
|
||||
cb.append_cellslice_bool(body);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gift.is_encrypted) {
|
||||
cb.store_long(1, 32);
|
||||
} else {
|
||||
|
|
|
@ -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 "tlbc-gen-cpp.h"
|
||||
#include "td/utils/bits.h"
|
||||
|
@ -94,6 +94,7 @@ void init_forbidden_cpp_idents() {
|
|||
l.insert("get_size");
|
||||
l.insert("pack");
|
||||
l.insert("unpack");
|
||||
l.insert("ops");
|
||||
l.insert("cs");
|
||||
l.insert("cb");
|
||||
l.insert("cell_ref");
|
||||
|
@ -2014,7 +2015,7 @@ void CppTypeCode::generate_skip_field(const Constructor& constr, const Field& fi
|
|||
output_cpp_expr(ss, expr, 100, true);
|
||||
ss << '.';
|
||||
}
|
||||
ss << (validating ? "validate_skip(cs, weak" : "skip(cs");
|
||||
ss << (validating ? "validate_skip(ops, cs, weak" : "skip(cs");
|
||||
output_negative_type_arguments(ss, expr);
|
||||
ss << ")";
|
||||
actions += Action{std::move(ss)};
|
||||
|
@ -2054,7 +2055,7 @@ void CppTypeCode::generate_skip_field(const Constructor& constr, const Field& fi
|
|||
output_cpp_expr(ss, expr, 100);
|
||||
ss << '.';
|
||||
}
|
||||
ss << (validating ? "validate_skip(cs, weak)" : "skip(cs)") << tail;
|
||||
ss << (validating ? "validate_skip(ops, cs, weak)" : "skip(cs)") << tail;
|
||||
actions += Action{std::move(ss)};
|
||||
return;
|
||||
}
|
||||
|
@ -2074,7 +2075,7 @@ void CppTypeCode::generate_skip_field(const Constructor& constr, const Field& fi
|
|||
output_cpp_expr(ss, expr, 100);
|
||||
ss << '.';
|
||||
}
|
||||
ss << "validate_skip_ref(cs, weak)" << tail;
|
||||
ss << "validate_skip_ref(ops, cs, weak)" << tail;
|
||||
actions += Action{ss.str()};
|
||||
}
|
||||
|
||||
|
@ -2101,8 +2102,8 @@ void CppTypeCode::generate_skip_cons_method(std::ostream& os, std::string nl, in
|
|||
void CppTypeCode::generate_skip_method(std::ostream& os, int options) {
|
||||
bool validate = options & 1;
|
||||
bool ret_ext = options & 2;
|
||||
os << "\nbool " << cpp_type_class_name << "::" << (validate ? "validate_" : "") << "skip(vm::CellSlice& cs"
|
||||
<< (validate ? ", bool weak" : "");
|
||||
os << "\nbool " << cpp_type_class_name
|
||||
<< "::" << (validate ? "validate_skip(int* ops, vm::CellSlice& cs, bool weak" : "skip(vm::CellSlice& cs");
|
||||
if (ret_ext) {
|
||||
os << skip_extra_args;
|
||||
}
|
||||
|
@ -2470,7 +2471,7 @@ void CppTypeCode::generate_unpack_field(const CppTypeCode::ConsField& fi, const
|
|||
output_cpp_expr(ss, expr, 100, true);
|
||||
ss << '.';
|
||||
}
|
||||
ss << (validating ? "validate_fetch_to(cs, weak, " : "fetch_to(cs, ") << field_vars.at(i);
|
||||
ss << (validating ? "validate_fetch_to(ops, cs, weak, " : "fetch_to(cs, ") << field_vars.at(i);
|
||||
output_negative_type_arguments(ss, expr);
|
||||
ss << ")";
|
||||
actions += Action{std::move(ss)};
|
||||
|
@ -2514,8 +2515,8 @@ void CppTypeCode::generate_unpack_field(const CppTypeCode::ConsField& fi, const
|
|||
output_cpp_expr(ss, expr, 100);
|
||||
ss << '.';
|
||||
}
|
||||
ss << (validating ? "validate_" : "") << "fetch_" << (cvt == ct_enum ? "enum_" : "") << "to(cs, "
|
||||
<< (validating ? "weak, " : "") << field_vars.at(i) << ")" << tail;
|
||||
ss << (validating ? "validate_" : "") << "fetch_" << (cvt == ct_enum ? "enum_" : "")
|
||||
<< (validating ? "to(ops, cs, weak, " : "to(cs, ") << field_vars.at(i) << ")" << tail;
|
||||
field_var_set[i] = true;
|
||||
actions += Action{std::move(ss)};
|
||||
return;
|
||||
|
@ -2540,7 +2541,7 @@ void CppTypeCode::generate_unpack_field(const CppTypeCode::ConsField& fi, const
|
|||
output_cpp_expr(ss, expr, 100);
|
||||
ss << '.';
|
||||
}
|
||||
ss << "validate_ref(" << field_vars.at(i) << "))" << tail;
|
||||
ss << "validate_ref(ops, " << field_vars.at(i) << "))" << tail;
|
||||
actions += Action{ss.str()};
|
||||
}
|
||||
|
||||
|
@ -2559,7 +2560,11 @@ void CppTypeCode::generate_unpack_method(std::ostream& os, CppTypeCode::ConsReco
|
|||
<< "\n auto cs = load_cell_slice(std::move(cell_ref));"
|
||||
<< "\n return " << (options & 1 ? "validate_" : "") << "unpack";
|
||||
if (!(options & 8)) {
|
||||
os << "(cs, data";
|
||||
os << "(";
|
||||
if (options & 1) {
|
||||
os << "ops, ";
|
||||
}
|
||||
os << "cs, data";
|
||||
} else {
|
||||
os << "_" << cons_enum_name.at(rec.cons_idx) << "(cs";
|
||||
for (const auto& f : rec.cpp_fields) {
|
||||
|
@ -2773,7 +2778,7 @@ void CppTypeCode::generate_pack_field(const CppTypeCode::ConsField& fi, const Co
|
|||
output_cpp_expr(ss, expr, 100);
|
||||
ss << '.';
|
||||
}
|
||||
ss << "validate_ref(" << field_vars.at(i) << "))" << tail;
|
||||
ss << "validate_ref(ops, " << field_vars.at(i) << "))" << tail;
|
||||
actions += Action{ss.str()};
|
||||
}
|
||||
|
||||
|
@ -3093,7 +3098,7 @@ void CppTypeCode::generate_header(std::ostream& os, int options) {
|
|||
if (ret_params) {
|
||||
os << " bool skip(vm::CellSlice& cs" << skip_extra_args << ") const;\n";
|
||||
}
|
||||
os << " bool validate_skip(vm::CellSlice& cs, bool weak = false) const override";
|
||||
os << " bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override";
|
||||
if (!inline_validate_skip) {
|
||||
os << ";\n";
|
||||
} else if (sz) {
|
||||
|
@ -3102,7 +3107,7 @@ void CppTypeCode::generate_header(std::ostream& os, int options) {
|
|||
os << " {\n return true;\n }\n";
|
||||
}
|
||||
if (ret_params) {
|
||||
os << " bool validate_skip(vm::CellSlice& cs, bool weak" << skip_extra_args << ") const;\n";
|
||||
os << " bool validate_skip(int *ops, vm::CellSlice& cs, bool weak" << skip_extra_args << ") const;\n";
|
||||
os << " bool fetch_to(vm::CellSlice& cs, Ref<vm::CellSlice>& res" << skip_extra_args << ") const;\n";
|
||||
}
|
||||
if (type.is_simple_enum) {
|
||||
|
|
|
@ -114,38 +114,43 @@ bool TupleT::skip(vm::CellSlice& cs) const {
|
|||
return !i;
|
||||
}
|
||||
|
||||
bool TupleT::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool TupleT::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
int i = n;
|
||||
for (; i > 0; --i) {
|
||||
if (!X.validate_skip(cs, weak)) {
|
||||
if (!X.validate_skip(ops, cs, weak)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return !i;
|
||||
}
|
||||
|
||||
bool TLB::validate_ref_internal(Ref<vm::Cell> cell_ref, bool weak) const {
|
||||
bool TLB::validate_ref_internal(int* ops, Ref<vm::Cell> cell_ref, bool weak) const {
|
||||
if (ops && --*ops < 0) {
|
||||
return false;
|
||||
}
|
||||
bool is_special;
|
||||
auto cs = load_cell_slice_special(std::move(cell_ref), is_special);
|
||||
return always_special() ? is_special : (is_special ? weak : (validate_skip(cs) && cs.empty_ext()));
|
||||
return always_special() ? is_special : (is_special ? weak : (validate_skip(ops, cs) && cs.empty_ext()));
|
||||
}
|
||||
|
||||
bool TLB::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {
|
||||
pp.open("raw@");
|
||||
pp << *this << ' ';
|
||||
vm::CellSlice cs_copy{cs};
|
||||
if (!validate_skip(cs) || !cs_copy.cut_tail(cs)) {
|
||||
int size_limit = pp.limit;
|
||||
if (!validate_skip(&size_limit, cs) || !cs_copy.cut_tail(cs)) {
|
||||
return pp.fail("invalid value");
|
||||
}
|
||||
pp.raw_nl();
|
||||
return cs_copy.print_rec(pp.os, &pp.limit, pp.indent) && pp.mkindent() && pp.close();
|
||||
return (cs_copy.print_rec(pp.os, &pp.limit, pp.indent) && pp.mkindent() && pp.close()) ||
|
||||
pp.fail("raw value too long");
|
||||
}
|
||||
|
||||
bool TLB::print_special(PrettyPrinter& pp, vm::CellSlice& cs) const {
|
||||
pp.open("raw@");
|
||||
pp << *this << ' ';
|
||||
pp.raw_nl();
|
||||
return cs.print_rec(pp.os, &pp.limit, pp.indent) && pp.mkindent() && pp.close();
|
||||
return (cs.print_rec(pp.os, &pp.limit, pp.indent) && pp.mkindent() && pp.close()) || pp.fail("raw value too long");
|
||||
}
|
||||
|
||||
bool TLB::print_ref(PrettyPrinter& pp, Ref<vm::Cell> cell_ref) const {
|
||||
|
@ -217,7 +222,7 @@ PrettyPrinter::~PrettyPrinter() {
|
|||
}
|
||||
|
||||
bool PrettyPrinter::fail(std::string msg) {
|
||||
os << "<FATAL: " << msg << ">";
|
||||
os << "<FATAL: " << msg << ">" << std::endl;
|
||||
failed = true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ struct PrettyPrinter;
|
|||
|
||||
class TLB {
|
||||
public:
|
||||
enum { default_validate_max_cells = 1024 };
|
||||
virtual ~TLB() = default;
|
||||
virtual int get_size(const vm::CellSlice& cs) const {
|
||||
return -1;
|
||||
|
@ -37,14 +38,26 @@ class TLB {
|
|||
virtual bool skip(vm::CellSlice& cs) const {
|
||||
return cs.skip_ext(get_size(cs));
|
||||
}
|
||||
virtual bool validate(const vm::CellSlice& cs, bool weak = false) const {
|
||||
virtual bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const {
|
||||
return cs.have_ext(get_size(cs));
|
||||
}
|
||||
virtual bool validate_exact(const vm::CellSlice& cs, bool weak = false) const {
|
||||
virtual bool validate_exact(int* ops, const vm::CellSlice& cs, bool weak = false) const {
|
||||
return (int)cs.size_ext() == get_size(cs);
|
||||
}
|
||||
bool validate_upto(int ops, const vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate(&ops, cs, weak);
|
||||
}
|
||||
bool validate_exact_upto(int ops, const vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate_exact(&ops, cs, weak);
|
||||
}
|
||||
bool validate_csr(int* ops, Ref<vm::CellSlice> cs_ref, bool weak = false) const {
|
||||
return cs_ref.not_null() && validate_skip_exact(ops, cs_ref.write(), weak);
|
||||
}
|
||||
bool validate_csr(int ops, Ref<vm::CellSlice> cs_ref, bool weak = false) const {
|
||||
return validate_csr(&ops, std::move(cs_ref), weak);
|
||||
}
|
||||
bool validate_csr(Ref<vm::CellSlice> cs_ref, bool weak = false) const {
|
||||
return cs_ref.not_null() && validate_skip_exact(cs_ref.write(), weak);
|
||||
return validate_csr(default_validate_max_cells, std::move(cs_ref), weak);
|
||||
}
|
||||
Ref<vm::CellSlice> fetch(vm::CellSlice& cs) const {
|
||||
return cs.fetch_subslice_ext(get_size(cs));
|
||||
|
@ -52,67 +65,71 @@ class TLB {
|
|||
Ref<vm::CellSlice> prefetch(const vm::CellSlice& cs) const {
|
||||
return cs.prefetch_subslice_ext(get_size(cs));
|
||||
}
|
||||
virtual Ref<vm::CellSlice> validate_fetch(vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate(cs, weak) ? cs.fetch_subslice_ext(get_size(cs)) : Ref<vm::CellSlice>{};
|
||||
virtual Ref<vm::CellSlice> validate_fetch(int* ops, vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate(ops, cs, weak) ? cs.fetch_subslice_ext(get_size(cs)) : Ref<vm::CellSlice>{};
|
||||
}
|
||||
virtual Ref<vm::CellSlice> validate_prefetch(const vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate(cs, weak) ? cs.prefetch_subslice_ext(get_size(cs)) : Ref<vm::CellSlice>{};
|
||||
virtual Ref<vm::CellSlice> validate_prefetch(int* ops, const vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate(ops, cs, weak) ? cs.prefetch_subslice_ext(get_size(cs)) : Ref<vm::CellSlice>{};
|
||||
}
|
||||
bool fetch_to(vm::CellSlice& cs, Ref<vm::CellSlice>& res) const {
|
||||
return (res = fetch(cs)).not_null();
|
||||
}
|
||||
bool validate_fetch_to(vm::CellSlice& cs, Ref<vm::CellSlice>& res, bool weak = false) const {
|
||||
return (res = validate_fetch(cs, weak)).not_null();
|
||||
bool validate_fetch_to(int* ops, vm::CellSlice& cs, Ref<vm::CellSlice>& res, bool weak = false) const {
|
||||
return (res = validate_fetch(ops, cs, weak)).not_null();
|
||||
}
|
||||
bool store_from(vm::CellBuilder& cb, Ref<vm::CellSlice> field) const {
|
||||
return field.not_null() && get_size(*field) == (int)field->size_ext() && cb.append_cellslice_bool(std::move(field));
|
||||
}
|
||||
bool validate_store_from(vm::CellBuilder& cb, Ref<vm::CellSlice> field, bool weak = false) const {
|
||||
bool validate_store_from(int* ops, vm::CellBuilder& cb, Ref<vm::CellSlice> field, bool weak = false) const {
|
||||
if (field.is_null()) {
|
||||
return false;
|
||||
}
|
||||
vm::CellSlice cs{*field};
|
||||
return validate_skip(cs, weak) && cs.empty_ext() && cb.append_cellslice_bool(std::move(field));
|
||||
return validate_skip(ops, cs, weak) && cs.empty_ext() && cb.append_cellslice_bool(std::move(field));
|
||||
}
|
||||
virtual bool extract(vm::CellSlice& cs) const {
|
||||
return cs.only_ext(get_size(cs));
|
||||
}
|
||||
virtual bool validate_extract(vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate(cs, weak) && extract(cs);
|
||||
virtual bool validate_extract(int* ops, vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate(ops, cs, weak) && extract(cs);
|
||||
}
|
||||
int get_size_by_skip(const vm::CellSlice& cs) const {
|
||||
vm::CellSlice copy{cs};
|
||||
return skip(copy) ? copy.subtract_base_ext(cs) : -1;
|
||||
}
|
||||
virtual bool validate_skip(vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate(cs, weak) && skip(cs);
|
||||
virtual bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate(ops, cs, weak) && skip(cs);
|
||||
}
|
||||
bool validate_skip_exact(vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate_skip(cs, weak) && cs.empty_ext();
|
||||
bool validate_skip_upto(int ops, vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate_skip(&ops, cs, weak);
|
||||
}
|
||||
bool validate_by_skip(const vm::CellSlice& cs, bool weak = false) const {
|
||||
bool validate_skip_exact(int* ops, vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate_skip(ops, cs, weak) && cs.empty_ext();
|
||||
}
|
||||
bool validate_by_skip(int* ops, const vm::CellSlice& cs, bool weak = false) const {
|
||||
vm::CellSlice copy{cs};
|
||||
return validate_skip(copy, weak);
|
||||
return validate_skip(ops, copy, weak);
|
||||
}
|
||||
bool validate_by_skip_exact(const vm::CellSlice& cs, bool weak = false) const {
|
||||
bool validate_by_skip_exact(int* ops, const vm::CellSlice& cs, bool weak = false) const {
|
||||
vm::CellSlice copy{cs};
|
||||
return validate_skip_exact(copy, weak);
|
||||
return validate_skip_exact(ops, copy, weak);
|
||||
}
|
||||
bool extract_by_skip(vm::CellSlice& cs) const {
|
||||
vm::CellSlice copy{cs};
|
||||
return skip(copy) && cs.cut_tail(copy);
|
||||
}
|
||||
bool validate_extract_by_skip(vm::CellSlice& cs, bool weak = false) const {
|
||||
bool validate_extract_by_skip(int* ops, vm::CellSlice& cs, bool weak = false) const {
|
||||
vm::CellSlice copy{cs};
|
||||
return validate_skip(copy, weak) && cs.cut_tail(copy);
|
||||
return validate_skip(ops, copy, weak) && cs.cut_tail(copy);
|
||||
}
|
||||
Ref<vm::CellSlice> validate_fetch_by_skip(vm::CellSlice& cs, bool weak = false) const {
|
||||
Ref<vm::CellSlice> validate_fetch_by_skip(int* ops, vm::CellSlice& cs, bool weak = false) const {
|
||||
Ref<vm::CellSlice> copy{true, cs};
|
||||
return validate_skip(cs, weak) && copy.unique_write().cut_tail(cs) ? copy : Ref<vm::CellSlice>{};
|
||||
return validate_skip(ops, cs, weak) && copy.unique_write().cut_tail(cs) ? copy : Ref<vm::CellSlice>{};
|
||||
}
|
||||
Ref<vm::CellSlice> validate_prefetch_by_skip(const vm::CellSlice& cs, bool weak = false) const {
|
||||
Ref<vm::CellSlice> validate_prefetch_by_skip(int* ops, const vm::CellSlice& cs, bool weak = false) const {
|
||||
vm::CellSlice copy{cs};
|
||||
return validate_skip(copy, false) ? cs.prefetch_subslice_ext(copy.subtract_base_ext(cs)) : Ref<vm::CellSlice>{};
|
||||
return validate_skip(ops, copy, false) ? cs.prefetch_subslice_ext(copy.subtract_base_ext(cs))
|
||||
: Ref<vm::CellSlice>{};
|
||||
}
|
||||
virtual bool skip_copy(vm::CellBuilder& cb, vm::CellSlice& cs) const {
|
||||
return cb.append_cellslice_bool(fetch(cs));
|
||||
|
@ -156,14 +173,29 @@ class TLB {
|
|||
bool as_integer_to(Ref<vm::CellSlice> cs_ref, td::RefInt256& res) const {
|
||||
return (res = as_integer(std::move(cs_ref))).not_null();
|
||||
}
|
||||
bool validate_ref(int* ops, Ref<vm::Cell> cell_ref, bool weak = false) const {
|
||||
return cell_ref.not_null() && validate_ref_internal(ops, std::move(cell_ref), weak);
|
||||
}
|
||||
bool validate_ref(int ops, Ref<vm::Cell> cell_ref, bool weak = false) const {
|
||||
return validate_ref(&ops, std::move(cell_ref), weak);
|
||||
}
|
||||
bool validate_ref(Ref<vm::Cell> cell_ref, bool weak = false) const {
|
||||
return cell_ref.not_null() && validate_ref_internal(std::move(cell_ref), weak);
|
||||
return validate_ref(default_validate_max_cells, std::move(cell_ref), weak);
|
||||
}
|
||||
bool force_validate_ref(int* ops, Ref<vm::Cell> cell_ref) const {
|
||||
return cell_ref.not_null() && validate_ref_internal(ops, std::move(cell_ref), false);
|
||||
}
|
||||
bool force_validate_ref(int ops, Ref<vm::Cell> cell_ref) const {
|
||||
return force_validate_ref(&ops, std::move(cell_ref));
|
||||
}
|
||||
bool force_validate_ref(Ref<vm::Cell> cell_ref) const {
|
||||
return cell_ref.not_null() && validate_ref_internal(std::move(cell_ref), false);
|
||||
return force_validate_ref(default_validate_max_cells, std::move(cell_ref));
|
||||
}
|
||||
bool validate_skip_ref(vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate_ref(cs.fetch_ref(), weak);
|
||||
bool validate_skip_ref(int* ops, vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate_ref(ops, cs.fetch_ref(), weak);
|
||||
}
|
||||
bool validate_skip_ref(int ops, vm::CellSlice& cs, bool weak = false) const {
|
||||
return validate_skip_ref(&ops, cs, weak);
|
||||
}
|
||||
virtual bool null_value(vm::CellBuilder& cb) const {
|
||||
return false;
|
||||
|
@ -214,6 +246,9 @@ class TLB {
|
|||
return print(os, *cs_ref, indent, rec_limit);
|
||||
}
|
||||
bool print_ref(std::ostream& os, Ref<vm::Cell> cell_ref, int indent = 0, int rec_limit = 0) const;
|
||||
bool print_ref(int rec_limit, std::ostream& os, Ref<vm::Cell> cell_ref, int indent = 0) const {
|
||||
return print_ref(os, std::move(cell_ref), indent, rec_limit);
|
||||
}
|
||||
std::string as_string_skip(vm::CellSlice& cs, int indent = 0) const;
|
||||
std::string as_string(const vm::CellSlice& cs, int indent = 0) const;
|
||||
std::string as_string(Ref<vm::CellSlice> cs_ref, int indent = 0) const {
|
||||
|
@ -225,7 +260,7 @@ class TLB {
|
|||
}
|
||||
|
||||
protected:
|
||||
bool validate_ref_internal(Ref<vm::Cell> cell_ref, bool weak = false) const;
|
||||
bool validate_ref_internal(int* ops, Ref<vm::Cell> cell_ref, bool weak = false) const;
|
||||
};
|
||||
|
||||
static inline std::ostream& operator<<(std::ostream& os, const TLB& type) {
|
||||
|
@ -234,29 +269,29 @@ static inline std::ostream& operator<<(std::ostream& os, const TLB& type) {
|
|||
|
||||
struct TLB_Complex : TLB {
|
||||
bool skip(vm::CellSlice& cs) const override {
|
||||
return validate_skip(cs);
|
||||
return validate_skip(nullptr, cs);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override = 0;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override = 0;
|
||||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return get_size_by_skip(cs);
|
||||
}
|
||||
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return validate_by_skip(cs, weak);
|
||||
bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return validate_by_skip(ops, cs, weak);
|
||||
}
|
||||
bool validate_exact(const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return validate_by_skip_exact(cs, weak);
|
||||
bool validate_exact(int* ops, const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return validate_by_skip_exact(ops, cs, weak);
|
||||
}
|
||||
bool extract(vm::CellSlice& cs) const override {
|
||||
return extract_by_skip(cs);
|
||||
}
|
||||
bool validate_extract(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return validate_extract_by_skip(cs, weak);
|
||||
bool validate_extract(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return validate_extract_by_skip(ops, cs, weak);
|
||||
}
|
||||
Ref<vm::CellSlice> validate_fetch(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return validate_fetch_by_skip(cs, weak);
|
||||
Ref<vm::CellSlice> validate_fetch(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return validate_fetch_by_skip(ops, cs, weak);
|
||||
}
|
||||
Ref<vm::CellSlice> validate_prefetch(const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return validate_prefetch_by_skip(cs, weak);
|
||||
Ref<vm::CellSlice> validate_prefetch(int* ops, const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return validate_prefetch_by_skip(ops, cs, weak);
|
||||
}
|
||||
td::RefInt256 as_integer(const vm::CellSlice& cs) const override {
|
||||
vm::CellSlice copy{cs};
|
||||
|
@ -615,23 +650,23 @@ struct FwdT final : TLB {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return X.skip(cs);
|
||||
}
|
||||
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate(cs, weak);
|
||||
bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate(ops, cs, weak);
|
||||
}
|
||||
Ref<vm::CellSlice> validate_fetch(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_fetch(cs, weak);
|
||||
Ref<vm::CellSlice> validate_fetch(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_fetch(ops, cs, weak);
|
||||
}
|
||||
Ref<vm::CellSlice> validate_prefetch(const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_prefetch(cs, weak);
|
||||
Ref<vm::CellSlice> validate_prefetch(int* ops, const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_prefetch(ops, cs, weak);
|
||||
}
|
||||
bool extract(vm::CellSlice& cs) const override {
|
||||
return X.extract(cs);
|
||||
}
|
||||
bool validate_extract(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_extract(cs, weak);
|
||||
bool validate_extract(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_extract(ops, cs, weak);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_skip(cs, weak);
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_skip(ops, cs, weak);
|
||||
}
|
||||
bool skip_copy(vm::CellBuilder& cb, vm::CellSlice& cs) const override {
|
||||
return X.skip_copy(cb, cs);
|
||||
|
@ -726,10 +761,10 @@ struct NatLess final : TLB {
|
|||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return n >= 0 ? w : -1;
|
||||
}
|
||||
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
|
||||
bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return n >= 0 && (unsigned)cs.prefetch_ulong(w) <= (unsigned)n;
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return n >= 0 && (unsigned)cs.fetch_ulong(w) <= (unsigned)n;
|
||||
}
|
||||
unsigned long long as_uint(const vm::CellSlice& cs) const override {
|
||||
|
@ -749,10 +784,10 @@ struct NatLeq final : TLB {
|
|||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return n >= 0 ? w : -1;
|
||||
}
|
||||
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
|
||||
bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return n >= 0 && (unsigned)cs.prefetch_ulong(w) <= (unsigned)n;
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return n >= 0 && (unsigned)cs.fetch_ulong(w) <= (unsigned)n;
|
||||
}
|
||||
unsigned long long as_uint(const vm::CellSlice& cs) const override {
|
||||
|
@ -771,7 +806,7 @@ struct TupleT final : TLB_Complex {
|
|||
TupleT(int _n, const TLB& _X) : n(_n), X(_X) {
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return 0;
|
||||
}
|
||||
|
@ -786,8 +821,8 @@ struct CondT final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return !n || X.skip(cs);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return !n || (n > 0 && X.validate_skip(cs, weak));
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return !n || (n > 0 && X.validate_skip(ops, cs, weak));
|
||||
}
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return 0;
|
||||
|
@ -808,8 +843,8 @@ struct Cond final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return !n || field_type.skip(cs);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return !n || (n > 0 && field_type.validate_skip(cs, weak));
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return !n || (n > 0 && field_type.validate_skip(ops, cs, weak));
|
||||
}
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return 0;
|
||||
|
@ -905,7 +940,7 @@ struct Maybe : TLB_Complex {
|
|||
Maybe(Args... args) : field_type(args...) {
|
||||
}
|
||||
bool skip(vm::CellSlice& cs) const override;
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override;
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return cs.have(1) ? (int)cs.prefetch_ulong(1) : -1;
|
||||
}
|
||||
|
@ -928,10 +963,10 @@ bool Maybe<T>::skip(vm::CellSlice& cs) const {
|
|||
}
|
||||
|
||||
template <class T>
|
||||
bool Maybe<T>::validate_skip(vm::CellSlice& cs, bool weak) const {
|
||||
bool Maybe<T>::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||
int t = get_tag(cs);
|
||||
if (t > 0) {
|
||||
return cs.advance(1) && field_type.validate_skip(cs, weak);
|
||||
return cs.advance(1) && field_type.validate_skip(ops, cs, weak);
|
||||
} else if (!t) {
|
||||
return cs.advance(1);
|
||||
} else {
|
||||
|
@ -979,11 +1014,11 @@ struct RefTo final : TLB {
|
|||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return 0x10000;
|
||||
}
|
||||
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return cs.size_refs() ? ref_type.validate_ref(cs.prefetch_ref(), weak) : false;
|
||||
bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return cs.size_refs() ? ref_type.validate_ref(ops, cs.prefetch_ref(), weak) : false;
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return ref_type.validate_skip_ref(cs, weak);
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return ref_type.validate_skip_ref(ops, cs, weak);
|
||||
}
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << '^' << ref_type;
|
||||
|
@ -1000,11 +1035,11 @@ struct RefT final : TLB {
|
|||
int get_size(const vm::CellSlice& cs) const override {
|
||||
return 0x10000;
|
||||
}
|
||||
bool validate(const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_ref(cs.prefetch_ref(), weak);
|
||||
bool validate(int* ops, const vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_ref(ops, cs.prefetch_ref(), weak);
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_skip_ref(cs, weak);
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return X.validate_skip_ref(ops, cs, weak);
|
||||
}
|
||||
std::ostream& print_type(std::ostream& os) const override {
|
||||
return os << '^' << X;
|
||||
|
@ -1021,9 +1056,10 @@ struct Either final : TLB_Complex {
|
|||
bool skip(vm::CellSlice& cs) const override {
|
||||
return cs.have(1) ? (cs.fetch_ulong(1) ? right_type.skip(cs) : left_type.skip(cs)) : false;
|
||||
}
|
||||
bool validate_skip(vm::CellSlice& cs, bool weak = false) const override {
|
||||
return cs.have(1) ? (cs.fetch_ulong(1) ? right_type.validate_skip(cs, weak) : left_type.validate_skip(cs, weak))
|
||||
: false;
|
||||
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
|
||||
return cs.have(1)
|
||||
? (cs.fetch_ulong(1) ? right_type.validate_skip(ops, cs, weak) : left_type.validate_skip(ops, cs, weak))
|
||||
: false;
|
||||
}
|
||||
int get_tag(const vm::CellSlice& cs) const override {
|
||||
return (int)cs.prefetch_ulong(1);
|
||||
|
|
|
@ -389,7 +389,7 @@ int exec_muldivmod(VmState* st, unsigned args, int quiet) {
|
|||
auto x = stack.pop_int();
|
||||
typename td::BigInt256::DoubleInt tmp{0};
|
||||
tmp.add_mul(*x, *y);
|
||||
auto q = td::RefInt256{true};
|
||||
auto q = td::make_refint();
|
||||
tmp.mod_div(*z, q.unique_write(), round_mode);
|
||||
switch ((args >> 2) & 3) {
|
||||
case 1:
|
||||
|
@ -401,7 +401,7 @@ int exec_muldivmod(VmState* st, unsigned args, int quiet) {
|
|||
stack.push_int_quiet(std::move(q), quiet);
|
||||
// fallthrough
|
||||
case 2:
|
||||
stack.push_int_quiet(td::RefInt256{true, tmp}, quiet);
|
||||
stack.push_int_quiet(td::make_refint(tmp), quiet);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
@ -450,17 +450,17 @@ int exec_mulshrmod(VmState* st, unsigned args, int mode) {
|
|||
switch ((args >> 2) & 3) {
|
||||
case 1:
|
||||
tmp.rshift(z, round_mode).normalize();
|
||||
stack.push_int_quiet(td::RefInt256{true, tmp}, mode & 1);
|
||||
stack.push_int_quiet(td::make_refint(tmp), mode & 1);
|
||||
break;
|
||||
case 3: {
|
||||
typename td::BigInt256::DoubleInt tmp2{tmp};
|
||||
tmp2.rshift(z, round_mode).normalize();
|
||||
stack.push_int_quiet(td::RefInt256{true, tmp2}, mode & 1);
|
||||
stack.push_int_quiet(td::make_refint(tmp2), mode & 1);
|
||||
}
|
||||
// fallthrough
|
||||
case 2:
|
||||
tmp.mod_pow2(z, round_mode).normalize();
|
||||
stack.push_int_quiet(td::RefInt256{true, tmp}, mode & 1);
|
||||
stack.push_int_quiet(td::make_refint(tmp), mode & 1);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
@ -524,24 +524,24 @@ int exec_shldivmod(VmState* st, unsigned args, int mode) {
|
|||
tmp <<= y;
|
||||
switch ((args >> 2) & 3) {
|
||||
case 1: {
|
||||
auto q = td::RefInt256{true};
|
||||
auto q = td::make_refint();
|
||||
tmp.mod_div(*z, q.unique_write(), round_mode);
|
||||
q.unique_write().normalize();
|
||||
stack.push_int_quiet(std::move(q), mode & 1);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
auto q = td::RefInt256{true};
|
||||
auto q = td::make_refint();
|
||||
tmp.mod_div(*z, q.unique_write(), round_mode);
|
||||
q.unique_write().normalize();
|
||||
stack.push_int_quiet(std::move(q), mode & 1);
|
||||
stack.push_int_quiet(td::RefInt256{true, tmp}, mode & 1);
|
||||
stack.push_int_quiet(td::make_refint(tmp), mode & 1);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
typename td::BigInt256::DoubleInt tmp2;
|
||||
tmp.mod_div(*z, tmp2, round_mode);
|
||||
stack.push_int_quiet(td::RefInt256{true, tmp}, mode & 1);
|
||||
stack.push_int_quiet(td::make_refint(tmp), mode & 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -740,7 +740,7 @@ int exec_bitsize(VmState* st, bool sgnd, bool quiet) {
|
|||
} else if (!quiet) {
|
||||
throw VmError{Excno::range_chk, "CHKSIZE for negative integer"};
|
||||
} else {
|
||||
stack.push_int_quiet(td::RefInt256{true}, quiet);
|
||||
stack.push_int_quiet(td::make_refint(), quiet);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -594,8 +594,7 @@ td::RefInt256 CellSlice::fetch_int256(unsigned bits, bool sgnd) {
|
|||
if (!have(bits)) {
|
||||
return {};
|
||||
} else if (bits < td::BigInt256::word_shift) {
|
||||
long long val = sgnd ? fetch_long(bits) : fetch_ulong(bits);
|
||||
return td::RefInt256{true, val};
|
||||
return td::make_refint(sgnd ? fetch_long(bits) : fetch_ulong(bits));
|
||||
} else {
|
||||
td::RefInt256 res{true};
|
||||
res.unique_write().import_bits(data_bits(), bits, sgnd);
|
||||
|
@ -608,8 +607,7 @@ td::RefInt256 CellSlice::prefetch_int256(unsigned bits, bool sgnd) const {
|
|||
if (!have(bits)) {
|
||||
return {};
|
||||
} else if (bits < td::BigInt256::word_shift) {
|
||||
long long val = sgnd ? prefetch_long(bits) : prefetch_ulong(bits);
|
||||
return td::RefInt256{true, val};
|
||||
return td::make_refint(sgnd ? prefetch_long(bits) : prefetch_ulong(bits));
|
||||
} else {
|
||||
td::RefInt256 res{true};
|
||||
res.unique_write().import_bits(data_bits(), bits, sgnd);
|
||||
|
@ -619,15 +617,15 @@ td::RefInt256 CellSlice::prefetch_int256(unsigned bits, bool sgnd) const {
|
|||
|
||||
td::RefInt256 CellSlice::prefetch_int256_zeroext(unsigned bits, bool sgnd) const {
|
||||
if (bits > 256u + sgnd) {
|
||||
return td::RefInt256{false};
|
||||
return td::make_refint();
|
||||
} else {
|
||||
unsigned ld_bits = std::min(bits, size());
|
||||
if (bits < td::BigInt256::word_shift) {
|
||||
long long val = sgnd ? prefetch_long(ld_bits) : prefetch_ulong(ld_bits);
|
||||
val <<= bits - ld_bits;
|
||||
return td::RefInt256{true, val};
|
||||
return td::make_refint(val);
|
||||
} else {
|
||||
td::RefInt256 res{true};
|
||||
auto res = td::make_refint();
|
||||
res.unique_write().import_bits(data_bits(), ld_bits, sgnd);
|
||||
res <<= bits - ld_bits;
|
||||
return res;
|
||||
|
|
|
@ -556,7 +556,7 @@ void Stack::push_int_quiet(td::RefInt256 val, bool quiet) {
|
|||
if (!quiet) {
|
||||
throw VmError{Excno::int_ov};
|
||||
} else if (val->is_valid()) {
|
||||
push(td::RefInt256{true});
|
||||
push(td::make_refint());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -592,7 +592,7 @@ void Stack::push_builder(Ref<CellBuilder> cb) {
|
|||
}
|
||||
|
||||
void Stack::push_smallint(long long val) {
|
||||
push(td::RefInt256{true, val});
|
||||
push(td::make_refint(val));
|
||||
}
|
||||
|
||||
void Stack::push_bool(bool val) {
|
||||
|
@ -763,7 +763,7 @@ bool StackEntry::deserialize(CellSlice& cs, int mode) {
|
|||
t = (int)cs.prefetch_ulong(16) & 0x1ff;
|
||||
if (t == 0xff) {
|
||||
// vm_stk_nan#02ff = VmStackValue;
|
||||
return cs.advance(16) && set_int(td::RefInt256{true});
|
||||
return cs.advance(16) && set_int(td::make_refint());
|
||||
} else {
|
||||
// vm_stk_int#0201_ value:int257 = VmStackValue;
|
||||
td::RefInt256 val;
|
||||
|
|
|
@ -147,6 +147,15 @@ class StackEntry {
|
|||
bool is_atom() const {
|
||||
return tp == t_atom;
|
||||
}
|
||||
bool is_int() const {
|
||||
return tp == t_int;
|
||||
}
|
||||
bool is_cell() const {
|
||||
return tp == t_cell;
|
||||
}
|
||||
bool is_null() const {
|
||||
return tp == t_null;
|
||||
}
|
||||
bool is(int wanted) const {
|
||||
return tp == wanted;
|
||||
}
|
||||
|
@ -433,6 +442,12 @@ class Stack : public td::CntObject {
|
|||
}
|
||||
return *this;
|
||||
}
|
||||
std::vector<StackEntry> extract_contents() const & {
|
||||
return stack;
|
||||
}
|
||||
std::vector<StackEntry> extract_contents() && {
|
||||
return std::move(stack);
|
||||
}
|
||||
template <typename... Args>
|
||||
const Stack& check_underflow(Args... args) const {
|
||||
if (!at_least(args...)) {
|
||||
|
|
|
@ -260,7 +260,7 @@ int exec_rand_int(VmState* st) {
|
|||
typename td::BigInt256::DoubleInt tmp{0};
|
||||
tmp.add_mul(*x, *y);
|
||||
tmp.rshift(256, -1).normalize();
|
||||
stack.push_int(td::RefInt256{true, tmp});
|
||||
stack.push_int(td::make_refint(tmp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -607,15 +607,15 @@ bool parse_maybe_anycast(CellSlice& cs, StackEntry& res) {
|
|||
bool parse_message_addr(CellSlice& cs, std::vector<StackEntry>& res) {
|
||||
res.clear();
|
||||
switch ((unsigned)cs.fetch_ulong(2)) {
|
||||
case 0: // addr_none$00 = MsgAddressExt;
|
||||
res.emplace_back(td::RefInt256{true, 0}); // -> (0)
|
||||
case 0: // addr_none$00 = MsgAddressExt;
|
||||
res.emplace_back(td::zero_refint()); // -> (0)
|
||||
return true;
|
||||
case 1: { // addr_extern$01
|
||||
unsigned len;
|
||||
Ref<CellSlice> addr;
|
||||
if (cs.fetch_uint_to(9, len) // len:(## 9)
|
||||
&& cs.fetch_subslice_to(len, addr)) { // external_address:(bits len) = MsgAddressExt;
|
||||
res.emplace_back(td::RefInt256{true, 1});
|
||||
res.emplace_back(td::make_refint(1));
|
||||
res.emplace_back(std::move(addr));
|
||||
return true;
|
||||
}
|
||||
|
@ -628,9 +628,9 @@ bool parse_message_addr(CellSlice& cs, std::vector<StackEntry>& res) {
|
|||
if (parse_maybe_anycast(cs, v) // anycast:(Maybe Anycast)
|
||||
&& cs.fetch_int_to(8, workchain) // workchain_id:int8
|
||||
&& cs.fetch_subslice_to(256, addr)) { // address:bits256 = MsgAddressInt;
|
||||
res.emplace_back(td::RefInt256{true, 2});
|
||||
res.emplace_back(td::make_refint(2));
|
||||
res.emplace_back(std::move(v));
|
||||
res.emplace_back(td::RefInt256{true, workchain});
|
||||
res.emplace_back(td::make_refint(workchain));
|
||||
res.emplace_back(std::move(addr));
|
||||
return true;
|
||||
}
|
||||
|
@ -644,9 +644,9 @@ bool parse_message_addr(CellSlice& cs, std::vector<StackEntry>& res) {
|
|||
&& cs.fetch_uint_to(9, len) // addr_len:(## 9)
|
||||
&& cs.fetch_int_to(32, workchain) // workchain_id:int32
|
||||
&& cs.fetch_subslice_to(len, addr)) { // address:(bits addr_len) = MsgAddressInt;
|
||||
res.emplace_back(td::RefInt256{true, 3});
|
||||
res.emplace_back(td::make_refint(3));
|
||||
res.emplace_back(std::move(v));
|
||||
res.emplace_back(td::RefInt256{true, workchain});
|
||||
res.emplace_back(td::make_refint(workchain));
|
||||
res.emplace_back(std::move(addr));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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 2019-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "utils.h"
|
||||
|
||||
namespace vm {
|
||||
|
@ -88,7 +106,7 @@ td::Result<vm::StackEntry> convert_stack_entry(td::Slice str) {
|
|||
return vm::StackEntry{
|
||||
Ref<vm::CellSlice>{true, vm::CellBuilder().store_bits(td::ConstBitPtr{buff}, bits).finalize()}};
|
||||
}
|
||||
auto num = td::RefInt256{true};
|
||||
auto num = td::make_refint();
|
||||
auto& x = num.unique_write();
|
||||
if (l >= 3 && str[0] == '0' && str[1] == 'x') {
|
||||
if (x.parse_hex(str.data() + 2, l - 2) != l - 2) {
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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 2019-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "stack.hpp"
|
||||
|
||||
|
|
|
@ -385,11 +385,13 @@ int VmState::step() {
|
|||
if (code->size()) {
|
||||
return dispatch->dispatch(this, code.write());
|
||||
} else if (code->size_refs()) {
|
||||
VM_LOG(this) << "execute implicit JMPREF\n";
|
||||
VM_LOG(this) << "execute implicit JMPREF";
|
||||
gas.consume_chk(implicit_jmpref_gas_price);
|
||||
Ref<Continuation> cont = Ref<OrdCont>{true, load_cell_slice_ref(code->prefetch_ref()), get_cp()};
|
||||
return jump(std::move(cont));
|
||||
} else {
|
||||
VM_LOG(this) << "execute implicit RET\n";
|
||||
VM_LOG(this) << "execute implicit RET";
|
||||
gas.consume_chk(implicit_ret_gas_price);
|
||||
return ret();
|
||||
}
|
||||
}
|
||||
|
@ -404,25 +406,27 @@ int VmState::run() {
|
|||
// LOG(INFO) << "[BS] data cells: " << DataCell::get_total_data_cells();
|
||||
try {
|
||||
try {
|
||||
res = step();
|
||||
gas.check();
|
||||
} catch (vm::CellBuilder::CellWriteError) {
|
||||
throw VmError{Excno::cell_ov};
|
||||
} catch (vm::CellBuilder::CellCreateError) {
|
||||
throw VmError{Excno::cell_ov};
|
||||
} catch (vm::CellSlice::CellReadError) {
|
||||
throw VmError{Excno::cell_und};
|
||||
}
|
||||
} 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();
|
||||
try {
|
||||
res = step();
|
||||
gas.check();
|
||||
} catch (vm::CellBuilder::CellWriteError) {
|
||||
throw VmError{Excno::cell_ov};
|
||||
} catch (vm::CellBuilder::CellCreateError) {
|
||||
throw VmError{Excno::cell_ov};
|
||||
} catch (vm::CellSlice::CellReadError) {
|
||||
throw VmError{Excno::cell_und};
|
||||
}
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
} catch (VmNoGas vmoog) {
|
||||
++steps;
|
||||
|
|
|
@ -104,6 +104,8 @@ class VmState final : public VmStateInterface {
|
|||
cell_create_gas_price = 500,
|
||||
exception_gas_price = 50,
|
||||
tuple_entry_gas_price = 1,
|
||||
implicit_jmpref_gas_price = 10,
|
||||
implicit_ret_gas_price = 5,
|
||||
max_data_depth = 512
|
||||
};
|
||||
VmState();
|
||||
|
|
|
@ -49,8 +49,8 @@ class TonTest {
|
|||
"workchain": -1,
|
||||
"shard": -9223372036854775808,
|
||||
"seqno": 0,
|
||||
"root_hash": "VCSXxDHhTALFxReyTZRd8E4Ya3ySOmpOWAS4rBX9XBY=",
|
||||
"file_hash": "eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo="
|
||||
"root_hash": "F6OpKZKqvqeFp6CQmFomXNMfMj2EnaUSOXN+Mh+wVWk=",
|
||||
"file_hash": "XplPz01CXAps5qeSWUtxcyBfdAo5zVb1N979KLSKD24="
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
@ -58,29 +58,27 @@ class TonTest {
|
|||
fun createTestWallet() {
|
||||
val client = ClientKotlin()
|
||||
val dir = getContext().getExternalFilesDir(null).toString() + "/";
|
||||
val words = getContext().getString(R.string.wallet_mnemonic_words).split(" ").toTypedArray();
|
||||
runBlocking {
|
||||
client.send(TonApi.Init(TonApi.Options(TonApi.Config(config, "", false, false), dir)))
|
||||
val info = client.send(TonApi.Init(TonApi.Options(TonApi.Config(config, "", false, false), TonApi.KeyStoreTypeDirectory(dir)))) as TonApi.OptionsInfo;
|
||||
val key = client.send(TonApi.CreateNewKey("local password".toByteArray(), "mnemonic password".toByteArray(), "".toByteArray())) as TonApi.Key
|
||||
val walletAddress = client.send(TonApi.TestWalletGetAccountAddress(TonApi.TestWalletInitialAccountState(key.publicKey))) as TonApi.AccountAddress;
|
||||
val testGiverState = client.send(TonApi.TestGiverGetAccountState()) as TonApi.TestGiverAccountState
|
||||
val inputKey = TonApi.InputKeyRegular(key, "local password".toByteArray())
|
||||
val walletAddress = client.send(TonApi.GetAccountAddress(TonApi.WalletV3InitialAccountState(key.publicKey, info.configInfo.defaultWalletId), 1)) as TonApi.AccountAddress
|
||||
|
||||
client.send(TonApi.TestGiverSendGrams(walletAddress, testGiverState.seqno, 6660000000, "".toByteArray())) as TonApi.Ok
|
||||
val giverKey = client.send(TonApi.ImportKey("local password".toByteArray(), "".toByteArray(), TonApi.ExportedKey(words))) as TonApi.Key
|
||||
val giverInputKey = TonApi.InputKeyRegular(giverKey, "local password".toByteArray())
|
||||
val giverAddress = client.send(TonApi.GetAccountAddress(TonApi.WalletV3InitialAccountState(giverKey.publicKey, info.configInfo.defaultWalletId), 1)) as TonApi.AccountAddress;
|
||||
|
||||
while ((client.send(TonApi.GenericGetAccountState(walletAddress)) as TonApi.GenericAccountStateUninited).accountState.balance <= 0L) {
|
||||
val queryInfo = client.send(TonApi.CreateQuery(giverInputKey, giverAddress, 60, TonApi.ActionMsg(arrayOf(TonApi.MsgMessage(walletAddress, 6660000000, TonApi.MsgDataText("Helo") )), true))) as TonApi.QueryInfo;
|
||||
client.send(TonApi.QuerySend(queryInfo.id)) as TonApi.Ok;
|
||||
|
||||
while ((client.send(TonApi.GetAccountState(walletAddress)) as TonApi.FullAccountState).balance <= 0L) {
|
||||
delay(1000L)
|
||||
}
|
||||
|
||||
val inputKey = TonApi.InputKey(key, "local password".toByteArray());
|
||||
client.send(TonApi.TestWalletInit(inputKey)) as TonApi.Ok
|
||||
|
||||
while (client.send(TonApi.GenericGetAccountState(walletAddress)) !is TonApi.GenericAccountStateTestWallet) {
|
||||
delay(1000L)
|
||||
}
|
||||
|
||||
val state = client.send(TonApi.GenericGetAccountState(walletAddress)) as TonApi.GenericAccountStateTestWallet
|
||||
val balance = state.accountState.balance
|
||||
client.send(TonApi.GenericSendGrams(inputKey, walletAddress, walletAddress, 10, 0, true, "hello".toByteArray())) as TonApi.Ok
|
||||
while ((client.send(TonApi.GenericGetAccountState(walletAddress)) as TonApi.GenericAccountStateTestWallet).accountState.balance == balance) {
|
||||
val queryInfo2 = client.send(TonApi.CreateQuery(inputKey, walletAddress, 60, TonApi.ActionMsg(arrayOf(), true))) as TonApi.QueryInfo;
|
||||
client.send(TonApi.QuerySend(queryInfo2.id)) as TonApi.Ok;
|
||||
while ((client.send(TonApi.GetAccountState(walletAddress)) as TonApi.FullAccountState).accountState !is TonApi.WalletV3AccountState) {
|
||||
delay(1000L)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,29 +53,28 @@ public class TonTestJava {
|
|||
return result[0];
|
||||
}
|
||||
}
|
||||
|
||||
String config = "{\n" +
|
||||
" \"liteservers\": [\n" +
|
||||
" {\n" +
|
||||
" \"ip\": 1137658550,\n" +
|
||||
" \"port\": 4924,\n" +
|
||||
" \"id\": {\n" +
|
||||
" \"@type\": \"pub.ed25519\",\n" +
|
||||
" \"key\": \"peJTw/arlRfssgTuf9BMypJzqOi7SXEqSPSWiEw2U1M=\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"validator\": {\n" +
|
||||
" \"@type\": \"validator.config.global\",\n" +
|
||||
" \"zero_state\": {\n" +
|
||||
" \"workchain\": -1,\n" +
|
||||
" \"shard\": -9223372036854775808,\n" +
|
||||
" \"seqno\": 0,\n" +
|
||||
" \"root_hash\": \"VCSXxDHhTALFxReyTZRd8E4Ya3ySOmpOWAS4rBX9XBY=\",\n" +
|
||||
" \"file_hash\": \"eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo=\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
String config = "{\n"+
|
||||
" \"liteservers\": [\n"+
|
||||
" {\n"+
|
||||
" \"ip\": 1137658550,\n"+
|
||||
" \"port\": 4924,\n"+
|
||||
" \"id\": {\n"+
|
||||
" \"@type\": \"pub.ed25519\",\n"+
|
||||
" \"key\": \"peJTw/arlRfssgTuf9BMypJzqOi7SXEqSPSWiEw2U1M=\"\n"+
|
||||
" }\n"+
|
||||
" }\n"+
|
||||
" ],\n"+
|
||||
" \"validator\": {\n"+
|
||||
" \"@type\": \"validator.config.global\",\n"+
|
||||
" \"zero_state\": {\n"+
|
||||
" \"workchain\": -1,\n"+
|
||||
" \"shard\": -9223372036854775808,\n"+
|
||||
" \"seqno\": 0,\n"+
|
||||
" \"root_hash\": \"F6OpKZKqvqeFp6CQmFomXNMfMj2EnaUSOXN+Mh+wVWk=\",\n"+
|
||||
" \"file_hash\": \"XplPz01CXAps5qeSWUtxcyBfdAo5zVb1N979KLSKD24=\"\n"+
|
||||
" }\n"+
|
||||
" }\n"+
|
||||
"}";
|
||||
|
||||
private void appendLog(String log) {
|
||||
Log.w("XX", log);
|
||||
|
@ -84,85 +83,45 @@ public class TonTestJava {
|
|||
@Test
|
||||
public void createTestWallet() {
|
||||
appendLog("start...");
|
||||
String dir = getContext().getExternalFilesDir(null) + "/";
|
||||
String[] words = getContext().getString(R.string.wallet_mnemonic_words).split(" ");
|
||||
JavaClient client = new JavaClient();
|
||||
Object result = client.send(new TonApi.Init(new TonApi.Options(new TonApi.Config(config, "", false, false), new TonApi.KeyStoreTypeDirectory((dir)))));
|
||||
if (!(result instanceof TonApi.OptionsInfo)) {
|
||||
appendLog("failed to set config");
|
||||
return;
|
||||
}
|
||||
appendLog("config set ok");
|
||||
TonApi.OptionsInfo info = (TonApi.OptionsInfo)result;
|
||||
TonApi.Key key = (TonApi.Key) client.send(new TonApi.CreateNewKey("local password".getBytes(), "mnemonic password".getBytes(), "".getBytes()));
|
||||
TonApi.InputKey inputKey = new TonApi.InputKeyRegular(key, "local password".getBytes());
|
||||
TonApi.AccountAddress walletAddress = (TonApi.AccountAddress)client.send(new TonApi.GetAccountAddress(new TonApi.WalletV3InitialAccountState(key.publicKey, info.configInfo.defaultWalletId), 1));
|
||||
|
||||
JavaClient client = new JavaClient();
|
||||
Object result = client.send(new TonApi.Init(new TonApi.Options(new TonApi.Config(config, "", false, false), getContext().getExternalFilesDir(null) + "/")));
|
||||
if (!(result instanceof TonApi.Ok)) {
|
||||
appendLog("failed to set config");
|
||||
return;
|
||||
}
|
||||
appendLog("config set ok");
|
||||
TonApi.Key key = (TonApi.Key) client.send(new TonApi.CreateNewKey("local password".getBytes(), "mnemonic password".getBytes(), "".getBytes()));
|
||||
appendLog("got private key");
|
||||
TonApi.AccountAddress walletAddress = (TonApi.AccountAddress) client.send(new TonApi.TestWalletGetAccountAddress(new TonApi.TestWalletInitialAccountState(key.publicKey)));
|
||||
appendLog("got account address");
|
||||
appendLog("sending grams...");
|
||||
TonApi.TestGiverAccountState testGiverState = (TonApi.TestGiverAccountState) client.send(new TonApi.TestGiverGetAccountState());
|
||||
result = client.send(new TonApi.TestGiverSendGrams(walletAddress, testGiverState.seqno, 6660000000L, "".getBytes()));
|
||||
if (!(result instanceof TonApi.Ok)) {
|
||||
appendLog("failed to send grams");
|
||||
return;
|
||||
}
|
||||
appendLog("grams sent, getting balance");
|
||||
TonApi.Key giverKey = (TonApi.Key)client.send(new TonApi.ImportKey("local password".getBytes(), "".getBytes(), new TonApi.ExportedKey(words))) ;
|
||||
TonApi.InputKey giverInputKey = new TonApi.InputKeyRegular(giverKey, "local password".getBytes());
|
||||
TonApi.AccountAddress giverAddress = (TonApi.AccountAddress)client.send(new TonApi.GetAccountAddress(new TonApi.WalletV3InitialAccountState(giverKey.publicKey, info.configInfo.defaultWalletId), 1));
|
||||
|
||||
while (true) {
|
||||
TonApi.GenericAccountStateUninited accountStateUninited = (TonApi.GenericAccountStateUninited) client.send(new TonApi.GenericGetAccountState(walletAddress));
|
||||
if (accountStateUninited == null || accountStateUninited.accountState.balance <= 0L) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Throwable e) {
|
||||
appendLog(e.toString());
|
||||
}
|
||||
} else {
|
||||
appendLog(String.format("balance = %d", accountStateUninited.accountState.balance));
|
||||
break;
|
||||
appendLog("sending grams...");
|
||||
TonApi.QueryInfo queryInfo = (TonApi.QueryInfo)client.send(new TonApi.CreateQuery(giverInputKey, giverAddress, 60, new TonApi.ActionMsg(new TonApi.MsgMessage[]{new TonApi.MsgMessage(walletAddress, 6660000000L, new TonApi.MsgDataText("Helo") )}, true)));
|
||||
result = client.send(new TonApi.QuerySend(queryInfo.id));
|
||||
if (!(result instanceof TonApi.Ok)) {
|
||||
appendLog("failed to send grams");
|
||||
return;
|
||||
}
|
||||
appendLog("grams sent, getting balance");
|
||||
|
||||
while (true) {
|
||||
TonApi.FullAccountState state = (TonApi.FullAccountState) client.send(new TonApi.GetAccountState(walletAddress));
|
||||
if (state.balance <= 0L) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Throwable e) {
|
||||
appendLog(e.toString());
|
||||
}
|
||||
} else {
|
||||
appendLog(String.format("balance = %d", state.balance));
|
||||
break;
|
||||
}
|
||||
|
||||
TonApi.InputKey inputKey = new TonApi.InputKey(key, "local password".getBytes());
|
||||
result = client.send(new TonApi.TestWalletInit(inputKey));
|
||||
if (!(result instanceof TonApi.Ok)) {
|
||||
return;
|
||||
}
|
||||
appendLog("init test wallet ok, getting state...");
|
||||
|
||||
while (true) {
|
||||
TonApi.GenericAccountState accountState = (TonApi.GenericAccountState) client.send(new TonApi.GenericGetAccountState(walletAddress));
|
||||
if (!(accountState instanceof TonApi.GenericAccountStateTestWallet)) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Throwable e) {
|
||||
appendLog(e.toString());
|
||||
}
|
||||
} else {
|
||||
appendLog("got account state");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
appendLog("sending grams...");
|
||||
TonApi.GenericAccountStateTestWallet state = (TonApi.GenericAccountStateTestWallet) client.send(new TonApi.GenericGetAccountState(walletAddress));
|
||||
long balance = state.accountState.balance;
|
||||
result = client.send(new TonApi.GenericSendGrams(inputKey, walletAddress, walletAddress, 10, 0, true, "hello".getBytes()));
|
||||
if (!(result instanceof TonApi.Ok)) {
|
||||
return;
|
||||
}
|
||||
appendLog(String.format("grams sent, current balance %d, receving...", balance));
|
||||
|
||||
while (true) {
|
||||
TonApi.GenericAccountStateTestWallet wallet = (TonApi.GenericAccountStateTestWallet) client.send(new TonApi.GenericGetAccountState(walletAddress));
|
||||
if (wallet == null || wallet.accountState.balance == balance) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (Throwable e) {
|
||||
appendLog(e.toString());
|
||||
}
|
||||
} else {
|
||||
appendLog(String.format("grams received, balance = %d", balance));
|
||||
break;
|
||||
}
|
||||
}
|
||||
appendLog("OK");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<resources>
|
||||
<string name="app_name">tonlib</string>
|
||||
<!-- add your wallet mnemonic word. By default it is wallet.v3 with revision=1 -->
|
||||
<!-- <string name="wallet_mnemonic_words">...</string> -->
|
||||
</resources>
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "lite-client-common.h"
|
||||
|
||||
#include "auto/tl/lite_api.hpp"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "crypto/block/block.h"
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "ton/ton-shard.h"
|
||||
#include "openssl/rand.hpp"
|
||||
#include "crypto/vm/utils.h"
|
||||
#include "crypto/common/util.h"
|
||||
|
||||
#if TD_DARWIN || TD_LINUX
|
||||
#include <unistd.h>
|
||||
|
@ -142,6 +143,8 @@ void TestNode::got_result() {
|
|||
parse_line(std::move(data));
|
||||
}
|
||||
if (ex_mode_ && !running_queries_ && ex_queries_.size() == 0) {
|
||||
std::cout.flush();
|
||||
std::cerr.flush();
|
||||
std::_Exit(0);
|
||||
}
|
||||
}
|
||||
|
@ -179,6 +182,14 @@ bool TestNode::envelope_send_query(td::BufferSlice query, td::Promise<td::Buffer
|
|||
return true;
|
||||
}
|
||||
|
||||
td::Promise<td::Unit> TestNode::trivial_promise() {
|
||||
return td::PromiseCreator::lambda([Self = actor_id(this)](td::Result<td::Unit> res) {
|
||||
if (res.is_error()) {
|
||||
LOG(ERROR) << "error: " << res.move_as_error();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool TestNode::register_blkid(const ton::BlockIdExt& blkid) {
|
||||
for (const auto& id : known_blk_ids_) {
|
||||
if (id == blkid) {
|
||||
|
@ -570,8 +581,13 @@ bool TestNode::seekeoln() {
|
|||
return eoln();
|
||||
}
|
||||
|
||||
bool TestNode::parse_account_addr(ton::WorkchainId& wc, ton::StdSmcAddress& addr) {
|
||||
return block::parse_std_account_addr(get_word(), wc, addr) || set_error("cannot parse account address");
|
||||
bool TestNode::parse_account_addr(ton::WorkchainId& wc, ton::StdSmcAddress& addr, bool allow_none) {
|
||||
auto word = get_word();
|
||||
if (allow_none && (word == "none" || word == "root")) {
|
||||
wc = ton::workchainInvalid;
|
||||
return true;
|
||||
}
|
||||
return block::parse_std_account_addr(word, wc, addr) || set_error("cannot parse account address");
|
||||
}
|
||||
|
||||
bool TestNode::convert_uint64(td::Slice word, td::uint64& val) {
|
||||
|
@ -634,6 +650,14 @@ bool TestNode::parse_uint32(td::uint32& val) {
|
|||
return convert_uint32(get_word(), val) || set_error("cannot parse 32-bit unsigned integer");
|
||||
}
|
||||
|
||||
bool TestNode::parse_int32(td::int32& val) {
|
||||
return convert_int32(get_word(), val) || set_error("cannot parse 32-bit integer");
|
||||
}
|
||||
|
||||
bool TestNode::parse_int16(int& val) {
|
||||
return (convert_int32(get_word(), val) && val == (td::int16)val) || set_error("cannot parse 16-bit integer");
|
||||
}
|
||||
|
||||
bool TestNode::set_error(td::Status error) {
|
||||
if (error.is_ok()) {
|
||||
return true;
|
||||
|
@ -801,8 +825,12 @@ bool TestNode::show_help(std::string command) {
|
|||
"saveaccount[code|data] <filename> <addr> [<block-id-ext>]\tSaves into specified file the most recent state "
|
||||
"(StateInit) or just the code or data of specified account; <addr> is in "
|
||||
"[<workchain>:]<hex-or-base64-addr> format\n"
|
||||
"runmethod[x] <addr> [<block-id-ext>] <method-id> <params>...\tRuns GET method <method-id> of account <addr> "
|
||||
"runmethod[full] <addr> [<block-id-ext>] <method-id> <params>...\tRuns GET method <method-id> of account "
|
||||
"<addr> "
|
||||
"with specified parameters\n"
|
||||
"dnsresolve [<block-id-ext>] <domain> [<category>]\tResolves a domain starting from root dns smart contract\n"
|
||||
"dnsresolvestep <addr> [<block-id-ext>] <domain> [<category>]\tResolves a subdomain using dns smart contract "
|
||||
"<addr>\n"
|
||||
"allshards [<block-id-ext>]\tShows shard configuration from the most recent masterchain "
|
||||
"state or from masterchain state corresponding to <block-id-ext>\n"
|
||||
"getconfig [<param>...]\tShows specified or all configuration parameters from the latest masterchain state\n"
|
||||
|
@ -872,21 +900,30 @@ bool TestNode::do_parse_line() {
|
|||
(seekeoln()
|
||||
? get_account_state(workchain, addr, mc_last_id_, filename, mode)
|
||||
: parse_block_id_ext(blkid) && seekeoln() && get_account_state(workchain, addr, blkid, filename, mode));
|
||||
} else if (word == "runmethod" || word == "runmethodx") {
|
||||
} else if (word == "runmethod" || word == "runmethodx" || word == "runmethodfull") {
|
||||
std::string method;
|
||||
return parse_account_addr(workchain, addr) && get_word_to(method) &&
|
||||
(parse_block_id_ext(method, blkid) ? get_word_to(method) : (blkid = mc_last_id_).is_valid()) &&
|
||||
parse_run_method(workchain, addr, blkid, method, word.size() > 9);
|
||||
parse_run_method(workchain, addr, blkid, method, word.size() <= 10);
|
||||
} else if (word == "dnsresolve" || word == "dnsresolvestep") {
|
||||
workchain = ton::workchainInvalid;
|
||||
bool step = (word.size() > 10);
|
||||
std::string domain;
|
||||
int cat = 0;
|
||||
return (!step || parse_account_addr(workchain, addr)) && get_word_to(domain) &&
|
||||
(parse_block_id_ext(domain, blkid) ? get_word_to(domain) : (blkid = mc_last_id_).is_valid()) &&
|
||||
(seekeoln() || parse_int16(cat)) && seekeoln() &&
|
||||
dns_resolve_start(workchain, addr, blkid, domain, cat, step);
|
||||
} else if (word == "allshards") {
|
||||
return eoln() ? get_all_shards() : (parse_block_id_ext(blkid) && seekeoln() && get_all_shards(false, blkid));
|
||||
} else if (word == "saveconfig") {
|
||||
blkid = mc_last_id_;
|
||||
std::string filename;
|
||||
return get_word_to(filename) && (seekeoln() || parse_block_id_ext(blkid)) && seekeoln() &&
|
||||
get_config_params(blkid, -1, filename);
|
||||
get_config_params(blkid, trivial_promise(), -1, filename);
|
||||
} else if (word == "getconfig" || word == "getconfigfrom") {
|
||||
blkid = mc_last_id_;
|
||||
return (word == "getconfig" || parse_block_id_ext(blkid)) && get_config_params(blkid, 0);
|
||||
return (word == "getconfig" || parse_block_id_ext(blkid)) && get_config_params(blkid, trivial_promise(), 0);
|
||||
} else if (word == "getblock") {
|
||||
return parse_block_id_ext(blkid) && seekeoln() && get_block(blkid, false);
|
||||
} else if (word == "dumpblock") {
|
||||
|
@ -1031,7 +1068,17 @@ bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
|
|||
return set_error(R.move_as_error().to_string());
|
||||
}
|
||||
parse_ptr_ = parse_end_;
|
||||
auto params = R.move_as_ok();
|
||||
auto P = td::PromiseCreator::lambda([](td::Result<std::vector<vm::StackEntry>> R) {
|
||||
if (R.is_error()) {
|
||||
LOG(ERROR) << R.move_as_error();
|
||||
}
|
||||
});
|
||||
return start_run_method(workchain, addr, ref_blkid, method_name, R.move_as_ok(), ext_mode ? 0x1f : 0, std::move(P));
|
||||
}
|
||||
|
||||
bool TestNode::start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
|
||||
std::string method_name, std::vector<vm::StackEntry> params, int mode,
|
||||
td::Promise<std::vector<vm::StackEntry>> promise) {
|
||||
if (!ref_blkid.is_valid()) {
|
||||
return set_error("must obtain last block information before making other queries");
|
||||
}
|
||||
|
@ -1039,31 +1086,33 @@ bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
|
|||
return set_error("server connection not ready");
|
||||
}
|
||||
auto a = ton::create_tl_object<ton::lite_api::liteServer_accountId>(workchain, addr);
|
||||
int mode = (ext_mode ? 0x1f : 0);
|
||||
if (!mode) {
|
||||
auto b = ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getAccountState>(
|
||||
ton::create_tl_lite_block_id(ref_blkid), std::move(a)),
|
||||
true);
|
||||
LOG(INFO) << "requesting account state for " << workchain << ":" << addr.to_hex() << " with respect to "
|
||||
<< ref_blkid.to_str() << " to run method " << method_name << " with " << params.size() << " parameters";
|
||||
return envelope_send_query(
|
||||
std::move(b), [ Self = actor_id(this), workchain, addr, ref_blkid, method_name,
|
||||
params = std::move(params) ](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
return;
|
||||
}
|
||||
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_accountState>(R.move_as_ok(), true);
|
||||
if (F.is_error()) {
|
||||
LOG(ERROR) << "cannot parse answer to liteServer.getAccountState";
|
||||
} else {
|
||||
auto f = F.move_as_ok();
|
||||
td::actor::send_closure_later(Self, &TestNode::run_smc_method, 0, ref_blkid, ton::create_block_id(f->id_),
|
||||
ton::create_block_id(f->shardblk_), std::move(f->shard_proof_),
|
||||
std::move(f->proof_), std::move(f->state_), workchain, addr, method_name,
|
||||
std::move(params), td::BufferSlice(), td::BufferSlice(), td::BufferSlice(),
|
||||
-0x10000);
|
||||
}
|
||||
});
|
||||
return envelope_send_query(std::move(b), [
|
||||
Self = actor_id(this), workchain, addr, ref_blkid, method_name, params = std::move(params),
|
||||
promise = std::move(promise)
|
||||
](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
return;
|
||||
}
|
||||
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_accountState>(R.move_as_ok(), true);
|
||||
if (F.is_error()) {
|
||||
LOG(ERROR) << "cannot parse answer to liteServer.getAccountState";
|
||||
promise.set_error(td::Status::Error("cannot parse answer to liteServer.getAccountState"));
|
||||
} else {
|
||||
auto f = F.move_as_ok();
|
||||
td::actor::send_closure_later(Self, &TestNode::run_smc_method, 0, ref_blkid, ton::create_block_id(f->id_),
|
||||
ton::create_block_id(f->shardblk_), std::move(f->shard_proof_),
|
||||
std::move(f->proof_), std::move(f->state_), workchain, addr, method_name,
|
||||
std::move(params), td::BufferSlice(), td::BufferSlice(), td::BufferSlice(),
|
||||
-0x10000, std::move(promise));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
td::int64 method_id = compute_method_id(method_name);
|
||||
// set serialization limits
|
||||
|
@ -1087,26 +1136,260 @@ bool TestNode::parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress a
|
|||
<< " with respect to " << ref_blkid.to_str() << " to run method " << method_name << " with "
|
||||
<< params.size() << " parameters";
|
||||
return envelope_send_query(std::move(b), [
|
||||
Self = actor_id(this), workchain, addr, ref_blkid, method_name, mode, params = std::move(params)
|
||||
Self = actor_id(this), workchain, addr, ref_blkid, method_name, mode, params = std::move(params),
|
||||
promise = std::move(promise)
|
||||
](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
promise.set_error(R.move_as_error());
|
||||
return;
|
||||
}
|
||||
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_runMethodResult>(R.move_as_ok(), true);
|
||||
if (F.is_error()) {
|
||||
LOG(ERROR) << "cannot parse answer to liteServer.runSmcMethod";
|
||||
promise.set_error(td::Status::Error("cannot parse answer to liteServer.runSmcMethod"));
|
||||
} else {
|
||||
auto f = F.move_as_ok();
|
||||
td::actor::send_closure_later(Self, &TestNode::run_smc_method, mode, ref_blkid, ton::create_block_id(f->id_),
|
||||
ton::create_block_id(f->shardblk_), std::move(f->shard_proof_),
|
||||
std::move(f->proof_), std::move(f->state_proof_), workchain, addr, method_name,
|
||||
std::move(params), std::move(f->init_c7_), std::move(f->lib_extras_),
|
||||
std::move(f->result_), f->exit_code_);
|
||||
std::move(f->result_), f->exit_code_, std::move(promise));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool TestNode::dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
|
||||
std::string domain, int cat, int mode) {
|
||||
if (domain.size() > 1023) {
|
||||
return set_error("domain name too long");
|
||||
}
|
||||
if (domain.size() >= 2 && domain[0] == '"' && domain.back() == '"') {
|
||||
domain.erase(0, 1);
|
||||
domain.pop_back();
|
||||
}
|
||||
std::vector<std::string> components;
|
||||
std::size_t i, p = 0;
|
||||
for (i = 0; i < domain.size(); i++) {
|
||||
if (!domain[i] || (unsigned char)domain[i] >= 0xfe || (unsigned char)domain[i] <= ' ') {
|
||||
return set_error("invalid characters in a domain name");
|
||||
}
|
||||
if (domain[i] == '.') {
|
||||
if (i == p) {
|
||||
return set_error("domain name cannot have an empty component");
|
||||
}
|
||||
components.emplace_back(domain, p, i - p);
|
||||
p = i + 1;
|
||||
}
|
||||
}
|
||||
if (i > p) {
|
||||
components.emplace_back(domain, p, i - p);
|
||||
}
|
||||
std::string qdomain, qdomain0;
|
||||
while (!components.empty()) {
|
||||
qdomain += components.back();
|
||||
qdomain += '\0';
|
||||
components.pop_back();
|
||||
}
|
||||
|
||||
if (!(ready_ && !client_.empty())) {
|
||||
return set_error("server connection not ready");
|
||||
}
|
||||
|
||||
if (workchain == ton::workchainInvalid) {
|
||||
if (dns_root_queried_) {
|
||||
workchain = ton::masterchainId;
|
||||
addr = dns_root_;
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda([this, blkid, domain, cat, mode](td::Result<td::Unit> R) {
|
||||
if (R.is_error()) {
|
||||
LOG(ERROR) << "cannot obtain root dns address from configuration: " << R.move_as_error();
|
||||
} else if (dns_root_queried_) {
|
||||
dns_resolve_start(ton::masterchainId, dns_root_, blkid, domain, cat, mode);
|
||||
} else {
|
||||
LOG(ERROR) << "cannot obtain root dns address from configuration parameter #4";
|
||||
}
|
||||
});
|
||||
return get_config_params(mc_last_id_, std::move(P), 0x5000, "", {4});
|
||||
}
|
||||
}
|
||||
return dns_resolve_send(workchain, addr, blkid, domain, qdomain, cat, mode);
|
||||
}
|
||||
|
||||
bool TestNode::dns_resolve_send(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
|
||||
std::string domain, std::string qdomain, int cat, int mode) {
|
||||
LOG(INFO) << "dns_resolve for '" << domain << "' category=" << cat << " mode=" << mode
|
||||
<< " starting from smart contract " << workchain << ":" << addr.to_hex() << " with respect to block "
|
||||
<< blkid.to_str();
|
||||
std::string qdomain0;
|
||||
if (qdomain.size() <= 127) {
|
||||
qdomain0 = qdomain;
|
||||
} else {
|
||||
qdomain0 = std::string{qdomain, 0, 127};
|
||||
qdomain[125] = '\xff';
|
||||
qdomain[126] = '\x0';
|
||||
}
|
||||
vm::CellBuilder cb;
|
||||
Ref<vm::Cell> cell;
|
||||
if (!(cb.store_bytes_bool(td::Slice(qdomain0)) && cb.finalize_to(cell))) {
|
||||
return set_error("cannot store domain name into slice");
|
||||
}
|
||||
std::vector<vm::StackEntry> params;
|
||||
params.emplace_back(vm::load_cell_slice_ref(std::move(cell)));
|
||||
params.emplace_back(td::make_refint(cat));
|
||||
auto P = td::PromiseCreator::lambda([this, workchain, addr, blkid, domain, qdomain, cat,
|
||||
mode](td::Result<std::vector<vm::StackEntry>> R) {
|
||||
if (R.is_error()) {
|
||||
LOG(ERROR) << R.move_as_error();
|
||||
return;
|
||||
}
|
||||
auto S = R.move_as_ok();
|
||||
if (S.size() < 2 || !S[S.size() - 2].is_int() || !(S.back().is_cell() || S.back().is_null())) {
|
||||
LOG(ERROR) << "dnsresolve did not return a value of type (int,cell)";
|
||||
return;
|
||||
}
|
||||
auto cell = S.back().as_cell();
|
||||
S.pop_back();
|
||||
auto x = S.back().as_int();
|
||||
S.clear();
|
||||
if (!x->signed_fits_bits(32)) {
|
||||
LOG(ERROR) << "invalid integer result of dnsresolve (" << x << ")";
|
||||
return;
|
||||
}
|
||||
return dns_resolve_finish(workchain, addr, blkid, domain, qdomain, cat, mode, (int)x->to_long(), std::move(cell));
|
||||
});
|
||||
return start_run_method(workchain, addr, blkid, "dnsresolve", std::move(params), 0x1f, std::move(P));
|
||||
}
|
||||
|
||||
bool TestNode::show_dns_record(std::ostream& os, int cat, Ref<vm::Cell> value, bool raw_dump) {
|
||||
if (raw_dump) {
|
||||
bool ok = show_dns_record(os, cat, value, false);
|
||||
if (!ok) {
|
||||
os << "cannot parse dns record; raw value: ";
|
||||
vm::load_cell_slice(value).print_rec(print_limit_, os);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
if (value.is_null()) {
|
||||
os << "(null)";
|
||||
return true;
|
||||
}
|
||||
// block::gen::t_DNSRecord.print_ref(print_limit_, os, value);
|
||||
if (!block::gen::t_DNSRecord.validate_ref(value)) {
|
||||
return false;
|
||||
}
|
||||
block::gen::t_DNSRecord.print_ref(print_limit_, os, value);
|
||||
auto cs = vm::load_cell_slice(value);
|
||||
auto tag = block::gen::t_DNSRecord.get_tag(cs);
|
||||
ton::WorkchainId wc;
|
||||
ton::StdSmcAddress addr;
|
||||
switch (tag) {
|
||||
case block::gen::DNSRecord::dns_adnl_address: {
|
||||
block::gen::DNSRecord::Record_dns_adnl_address rec;
|
||||
if (tlb::unpack_exact(cs, rec)) {
|
||||
os << "\n\tadnl address " << rec.adnl_addr.to_hex() << " = " << td::adnl_id_encode(rec.adnl_addr, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case block::gen::DNSRecord::dns_smc_address: {
|
||||
block::gen::DNSRecord::Record_dns_smc_address rec;
|
||||
if (tlb::unpack_exact(cs, rec) && block::tlb::t_MsgAddressInt.extract_std_address(rec.smc_addr, wc, addr)) {
|
||||
os << "\tsmart contract " << wc << ":" << addr.to_hex() << " = " << block::StdAddress{wc, addr}.rserialize(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case block::gen::DNSRecord::dns_next_resolver: {
|
||||
block::gen::DNSRecord::Record_dns_next_resolver rec;
|
||||
if (tlb::unpack_exact(cs, rec) && block::tlb::t_MsgAddressInt.extract_std_address(rec.resolver, wc, addr)) {
|
||||
os << "\tnext resolver " << wc << ":" << addr.to_hex() << " = " << block::StdAddress{wc, addr}.rserialize(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestNode::dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
|
||||
std::string domain, std::string qdomain, int cat, int mode, int used_bits,
|
||||
Ref<vm::Cell> value) {
|
||||
if (used_bits <= 0) {
|
||||
td::TerminalIO::out() << "domain '" << domain << "' not found" << std::endl;
|
||||
return;
|
||||
}
|
||||
if ((used_bits & 7) || (unsigned)used_bits > 8 * std::min<std::size_t>(qdomain.size(), 126)) {
|
||||
LOG(ERROR) << "too many bits used (" << used_bits << " out of " << qdomain.size() * 8 << ")";
|
||||
return;
|
||||
}
|
||||
int pos = (used_bits >> 3);
|
||||
if (qdomain[pos - 1]) {
|
||||
LOG(ERROR) << "domain split not at a component boundary";
|
||||
return;
|
||||
}
|
||||
bool end = ((std::size_t)pos == qdomain.size());
|
||||
if (!end) {
|
||||
LOG(INFO) << "partial information obtained";
|
||||
if (value.is_null()) {
|
||||
td::TerminalIO::out() << "domain '" << domain << "' not found: no next resolver" << std::endl;
|
||||
return;
|
||||
}
|
||||
Ref<vm::CellSlice> nx_address;
|
||||
ton::WorkchainId nx_wc;
|
||||
ton::StdSmcAddress nx_addr;
|
||||
if (!(block::gen::t_DNSRecord.cell_unpack_dns_next_resolver(value, nx_address) &&
|
||||
block::tlb::t_MsgAddressInt.extract_std_address(std::move(nx_address), nx_wc, nx_addr))) {
|
||||
LOG(ERROR) << "cannot parse next resolver info for " << domain.substr(qdomain.size() - pos);
|
||||
std::ostringstream out;
|
||||
vm::load_cell_slice(value).print_rec(print_limit_, out);
|
||||
td::TerminalIO::err() << out.str() << std::endl;
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "next resolver is " << nx_wc << ":" << nx_addr.to_hex();
|
||||
if ((mode & 1)) {
|
||||
return; // no recursive resolving
|
||||
}
|
||||
if (!(dns_resolve_send(nx_wc, nx_addr, blkid, domain, qdomain.substr(pos), cat, mode))) {
|
||||
LOG(ERROR) << "cannot send next dns query";
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "recursive dns query to '" << domain.substr(qdomain.size() - pos) << "' sent";
|
||||
return;
|
||||
}
|
||||
auto out = td::TerminalIO::out();
|
||||
out << "Result for domain '" << domain << "' category " << cat << (cat ? "" : " (all categories)") << std::endl;
|
||||
try {
|
||||
if (value.not_null()) {
|
||||
std::ostringstream os0;
|
||||
vm::load_cell_slice(value).print_rec(print_limit_, os0);
|
||||
out << "raw data: " << os0.str() << std::endl;
|
||||
}
|
||||
if (!cat) {
|
||||
vm::Dictionary dict{value, 16};
|
||||
if (!dict.check_for_each([this, &out](Ref<vm::CellSlice> cs, td::ConstBitPtr key, int n) {
|
||||
CHECK(n == 16);
|
||||
int x = (int)key.get_int(16);
|
||||
if (cs.is_null() || cs->size_ext() != 0x10000) {
|
||||
out << "category #" << x << " : value is not a reference" << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::ostringstream os;
|
||||
(void)show_dns_record(os, x, cs->prefetch_ref(), true);
|
||||
out << "category #" << x << " : " << os.str() << std::endl;
|
||||
return true;
|
||||
})) {
|
||||
out << "invalid dns record dictionary" << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::ostringstream os;
|
||||
(void)show_dns_record(os, cat, value, true);
|
||||
out << "category #" << cat << " : " << os.str() << std::endl;
|
||||
}
|
||||
} catch (vm::VmError& err) {
|
||||
LOG(ERROR) << "vm error while traversing dns resolve result: " << err.get_msg();
|
||||
} catch (vm::VmVirtError& err) {
|
||||
LOG(ERROR) << "vm virtualization error while traversing dns resolve result: " << err.get_msg();
|
||||
}
|
||||
}
|
||||
|
||||
bool TestNode::get_one_transaction(ton::BlockIdExt blkid, ton::WorkchainId workchain, ton::StdSmcAddress addr,
|
||||
ton::LogicalTime lt, bool dump) {
|
||||
if (!blkid.is_valid_full()) {
|
||||
|
@ -1192,8 +1475,8 @@ void TestNode::got_account_state(ton::BlockIdExt ref_blk, ton::BlockIdExt blk, t
|
|||
if (info.root.not_null()) {
|
||||
out << "account state is ";
|
||||
std::ostringstream outp;
|
||||
block::gen::t_Account.print_ref(outp, info.root);
|
||||
vm::load_cell_slice(info.root).print_rec(outp);
|
||||
block::gen::t_Account.print_ref(print_limit_, outp, info.root);
|
||||
vm::load_cell_slice(info.root).print_rec(print_limit_, outp);
|
||||
out << outp.str();
|
||||
out << "last transaction lt = " << info.last_trans_lt << " hash = " << info.last_trans_hash.to_hex() << std::endl;
|
||||
block::gen::Account::Record_account acc;
|
||||
|
@ -1269,7 +1552,8 @@ void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt
|
|||
td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state,
|
||||
ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string method,
|
||||
std::vector<vm::StackEntry> params, td::BufferSlice remote_c7,
|
||||
td::BufferSlice remote_libs, td::BufferSlice remote_result, int remote_exit_code) {
|
||||
td::BufferSlice remote_libs, td::BufferSlice remote_result, int remote_exit_code,
|
||||
td::Promise<std::vector<vm::StackEntry>> promise) {
|
||||
LOG(INFO) << "got (partial) account state with mode=" << mode << " for " << workchain << ":" << addr.to_hex()
|
||||
<< " with respect to blocks " << blk.to_str()
|
||||
<< (shard_blk == blk ? "" : std::string{" and "} + shard_blk.to_str());
|
||||
|
@ -1287,6 +1571,7 @@ void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt
|
|||
auto r_info = account_state.validate(ref_blk, block::StdAddress(workchain, addr));
|
||||
if (r_info.is_error()) {
|
||||
LOG(ERROR) << r_info.error().message();
|
||||
promise.set_error(r_info.move_as_error());
|
||||
return;
|
||||
}
|
||||
auto out = td::TerminalIO::out();
|
||||
|
@ -1294,12 +1579,14 @@ void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt
|
|||
if (info.root.is_null()) {
|
||||
LOG(ERROR) << "account state of " << workchain << ":" << addr.to_hex() << " is empty (cannot run method `"
|
||||
<< method << "`)";
|
||||
promise.set_error(td::Status::Error(PSLICE() << "account state of " << workchain << ":" << addr.to_hex()
|
||||
<< " is empty (cannot run method `" << method << "`)"));
|
||||
return;
|
||||
}
|
||||
if (false) {
|
||||
// DEBUG (dump state)
|
||||
std::ostringstream os;
|
||||
vm::CellSlice{vm::NoVm(), info.true_root}.print_rec(os);
|
||||
vm::CellSlice{vm::NoVm(), info.true_root}.print_rec(print_limit_, os);
|
||||
out << "dump of account state (proof): " << os.str() << std::endl;
|
||||
}
|
||||
// set deserialization limits
|
||||
|
@ -1313,9 +1600,9 @@ void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt
|
|||
bool ok = val.deserialize(r_c7);
|
||||
val.dump(os);
|
||||
// os << std::endl;
|
||||
// block::gen::t_VmStackValue.print_ref(os, r_c7);
|
||||
// block::gen::t_VmStackValue.print_ref(print_limit_, os, r_c7);
|
||||
// os << std::endl;
|
||||
// vm::CellSlice{vm::NoVmOrd(), r_c7}.print_rec(os);
|
||||
// vm::CellSlice{vm::NoVmOrd(), r_c7}.print_rec(print_limit_, os);
|
||||
out << "remote_c7 (deserialized=" << ok << "): " << os.str() << std::endl;
|
||||
}
|
||||
block::gen::Account::Record_account acc;
|
||||
|
@ -1324,6 +1611,7 @@ void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt
|
|||
if (!(tlb::unpack_cell(info.root, acc) && tlb::csr_unpack(acc.storage, store) &&
|
||||
balance.validate_unpack(store.balance))) {
|
||||
LOG(ERROR) << "error unpacking account state";
|
||||
promise.set_error(td::Status::Error("error unpacking account state"));
|
||||
return;
|
||||
}
|
||||
int tag = block::gen::t_AccountState.get_tag(*store.state);
|
||||
|
@ -1369,6 +1657,7 @@ void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt
|
|||
if (exit_code != 0) {
|
||||
LOG(ERROR) << "VM terminated with error code " << exit_code;
|
||||
out << "result: error " << exit_code << std::endl;
|
||||
promise.set_error(td::Status::Error(PSLICE() << "VM terminated with non-zero exit code " << exit_code));
|
||||
return;
|
||||
}
|
||||
stack = vm.get_stack_ref();
|
||||
|
@ -1399,6 +1688,8 @@ void TestNode::run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt
|
|||
out << os.str();
|
||||
}
|
||||
}
|
||||
out.flush();
|
||||
promise.set_result(stack->extract_contents());
|
||||
} catch (vm::VmVirtError& err) {
|
||||
out << "virtualization error while parsing runSmcMethod result: " << err.get_msg();
|
||||
} catch (vm::VmError& err) {
|
||||
|
@ -1485,8 +1776,8 @@ void TestNode::got_one_transaction(ton::BlockIdExt req_blkid, ton::BlockIdExt bl
|
|||
} else {
|
||||
out << "transaction is ";
|
||||
std::ostringstream outp;
|
||||
block::gen::t_Transaction.print_ref(outp, root);
|
||||
vm::load_cell_slice(root).print_rec(outp);
|
||||
block::gen::t_Transaction.print_ref(print_limit_, outp, root, 0);
|
||||
vm::load_cell_slice(root).print_rec(print_limit_, outp);
|
||||
out << outp.str();
|
||||
}
|
||||
}
|
||||
|
@ -1611,8 +1902,8 @@ void TestNode::got_last_transactions(std::vector<ton::BlockIdExt> blkids, td::Bu
|
|||
out << "transaction #" << c << " from block " << blkid.to_str() << (dump ? " is " : "\n");
|
||||
if (dump) {
|
||||
std::ostringstream outp;
|
||||
block::gen::t_Transaction.print_ref(outp, info.transaction);
|
||||
vm::load_cell_slice(info.transaction).print_rec(outp);
|
||||
block::gen::t_Transaction.print_ref(print_limit_, outp, info.transaction);
|
||||
vm::load_cell_slice(info.transaction).print_rec(print_limit_, outp);
|
||||
out << outp.str();
|
||||
}
|
||||
block::gen::Transaction::Record trans;
|
||||
|
@ -1740,8 +2031,8 @@ void TestNode::got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::Bu
|
|||
auto out = td::TerminalIO::out();
|
||||
out << "shard configuration is ";
|
||||
std::ostringstream outp;
|
||||
block::gen::t_ShardHashes.print_ref(outp, root);
|
||||
vm::load_cell_slice(root).print_rec(outp);
|
||||
block::gen::t_ShardHashes.print_ref(print_limit_, outp, root);
|
||||
vm::load_cell_slice(root).print_rec(print_limit_, outp);
|
||||
out << outp.str();
|
||||
block::ShardConfig sh_conf;
|
||||
if (!sh_conf.unpack(vm::load_cell_slice_ref(root))) {
|
||||
|
@ -1764,26 +2055,35 @@ void TestNode::got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::Bu
|
|||
show_new_blkids();
|
||||
}
|
||||
|
||||
bool TestNode::get_config_params(ton::BlockIdExt blkid, int mode, std::string filename) {
|
||||
std::vector<int> params;
|
||||
if (mode >= 0 && !seekeoln()) {
|
||||
bool TestNode::get_config_params(ton::BlockIdExt blkid, td::Promise<td::Unit> do_after, int mode, std::string filename,
|
||||
std::vector<int> params) {
|
||||
if (mode < 0) {
|
||||
mode = 0x8000;
|
||||
}
|
||||
if (!(mode & 0x9000) && !seekeoln()) {
|
||||
mode |= 0x1000;
|
||||
while (!seekeoln()) {
|
||||
int x;
|
||||
if (!convert_int32(get_word(), x)) {
|
||||
do_after.set_error(td::Status::Error("integer configuration parameter id expected"));
|
||||
return set_error("integer configuration parameter id expected");
|
||||
}
|
||||
params.push_back(x);
|
||||
}
|
||||
}
|
||||
if (!(ready_ && !client_.empty())) {
|
||||
do_after.set_error(td::Status::Error("integer configuration parameter id expected"));
|
||||
return set_error("server connection not ready");
|
||||
}
|
||||
if (!blkid.is_masterchain_ext()) {
|
||||
do_after.set_error(td::Status::Error("integer configuration parameter id expected"));
|
||||
return set_error("only masterchain blocks contain configuration");
|
||||
}
|
||||
if (blkid == mc_last_id_) {
|
||||
mode |= 0x2000;
|
||||
}
|
||||
auto params_copy = params;
|
||||
auto b = (mode & 0x3000) == 0x1000
|
||||
auto b = (mode & 0x1000)
|
||||
? ton::serialize_tl_object(ton::create_tl_object<ton::lite_api::liteServer_getConfigParams>(
|
||||
0, ton::create_tl_lite_block_id(blkid), std::move(params_copy)),
|
||||
true)
|
||||
|
@ -1792,9 +2092,11 @@ bool TestNode::get_config_params(ton::BlockIdExt blkid, int mode, std::string fi
|
|||
true);
|
||||
LOG(INFO) << "requesting " << params.size() << " configuration parameters with respect to masterchain block "
|
||||
<< blkid.to_str();
|
||||
return envelope_send_query(std::move(b), [ Self = actor_id(this), mode, filename, blkid,
|
||||
params = std::move(params) ](td::Result<td::BufferSlice> R) mutable {
|
||||
return envelope_send_query(std::move(b), [
|
||||
Self = actor_id(this), mode, filename, blkid, params = std::move(params), do_after = std::move(do_after)
|
||||
](td::Result<td::BufferSlice> R) mutable {
|
||||
if (R.is_error()) {
|
||||
do_after.set_error(R.move_as_error());
|
||||
return;
|
||||
}
|
||||
auto F = ton::fetch_tl_object<ton::lite_api::liteServer_configInfo>(R.move_as_ok(), true);
|
||||
|
@ -1804,13 +2106,14 @@ bool TestNode::get_config_params(ton::BlockIdExt blkid, int mode, std::string fi
|
|||
auto f = F.move_as_ok();
|
||||
td::actor::send_closure_later(Self, &TestNode::got_config_params, blkid, ton::create_block_id(f->id_),
|
||||
std::move(f->state_proof_), std::move(f->config_proof_), mode, filename,
|
||||
std::move(params));
|
||||
std::move(params), std::move(do_after));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TestNode::got_config_params(ton::BlockIdExt req_blkid, ton::BlockIdExt blkid, td::BufferSlice state_proof,
|
||||
td::BufferSlice cfg_proof, int mode, std::string filename, std::vector<int> params) {
|
||||
td::BufferSlice cfg_proof, int mode, std::string filename, std::vector<int> params,
|
||||
td::Promise<td::Unit> do_after) {
|
||||
LOG(INFO) << "got configuration parameters";
|
||||
if (!blkid.is_masterchain_ext()) {
|
||||
LOG(ERROR) << "reference block " << blkid.to_str() << " for the configuration is not a valid masterchain block";
|
||||
|
@ -1833,7 +2136,7 @@ void TestNode::got_config_params(ton::BlockIdExt req_blkid, ton::BlockIdExt blki
|
|||
return;
|
||||
}
|
||||
auto config = res.move_as_ok();
|
||||
if (mode < 0) {
|
||||
if (mode & 0x8000) {
|
||||
auto F = vm::std_boc_serialize(config->get_root_cell(), 2);
|
||||
if (F.is_error()) {
|
||||
LOG(ERROR) << "cannot serialize configuration: " << F.move_as_error().to_string();
|
||||
|
@ -1859,26 +2162,32 @@ void TestNode::got_config_params(ton::BlockIdExt req_blkid, ton::BlockIdExt blki
|
|||
} else {
|
||||
std::ostringstream os;
|
||||
if (i >= 0) {
|
||||
block::gen::ConfigParam{i}.print_ref(os, value);
|
||||
block::gen::ConfigParam{i}.print_ref(print_limit_, os, value);
|
||||
os << std::endl;
|
||||
}
|
||||
vm::load_cell_slice(value).print_rec(os);
|
||||
vm::load_cell_slice(value).print_rec(print_limit_, os);
|
||||
out << os.str() << std::endl;
|
||||
if (i == 4 && (mode & 0x2000)) {
|
||||
register_config_param4(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
config->foreach_config_param([&out](int i, Ref<vm::Cell> value) {
|
||||
config->foreach_config_param([this, &out, mode](int i, Ref<vm::Cell> value) {
|
||||
out << "ConfigParam(" << i << ") = ";
|
||||
if (value.is_null()) {
|
||||
out << "(null)\n";
|
||||
} else {
|
||||
std::ostringstream os;
|
||||
if (i >= 0) {
|
||||
block::gen::ConfigParam{i}.print_ref(os, value);
|
||||
block::gen::ConfigParam{i}.print_ref(print_limit_, os, value);
|
||||
os << std::endl;
|
||||
}
|
||||
vm::load_cell_slice(value).print_rec(os);
|
||||
vm::load_cell_slice(value).print_rec(print_limit_, os);
|
||||
out << os.str() << std::endl;
|
||||
if (i == 4 && (mode & 0x2000)) {
|
||||
register_config_param4(value);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
@ -1888,6 +2197,25 @@ void TestNode::got_config_params(ton::BlockIdExt req_blkid, ton::BlockIdExt blki
|
|||
} catch (vm::VmVirtError& err) {
|
||||
LOG(ERROR) << "virtualization error while traversing configuration: " << err.get_msg();
|
||||
}
|
||||
do_after.set_result(td::Unit());
|
||||
}
|
||||
|
||||
bool TestNode::register_config_param4(Ref<vm::Cell> value) {
|
||||
if (value.is_null()) {
|
||||
return false;
|
||||
}
|
||||
vm::CellSlice cs{vm::NoVmOrd(), std::move(value)};
|
||||
ton::StdSmcAddress addr;
|
||||
if (cs.size_ext() == 256 && cs.fetch_bits_to(addr)) {
|
||||
dns_root_queried_ = true;
|
||||
if (dns_root_ != addr) {
|
||||
dns_root_ = addr;
|
||||
LOG(INFO) << "dns root set to -1:" << addr.to_hex();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TestNode::get_block(ton::BlockIdExt blkid, bool dump) {
|
||||
|
@ -1981,8 +2309,8 @@ void TestNode::got_block(ton::BlockIdExt blkid, td::BufferSlice data, bool dump)
|
|||
auto out = td::TerminalIO::out();
|
||||
out << "block contents is ";
|
||||
std::ostringstream outp;
|
||||
block::gen::t_Block.print_ref(outp, root);
|
||||
vm::load_cell_slice(root).print_rec(outp);
|
||||
block::gen::t_Block.print_ref(print_limit_, outp, root);
|
||||
vm::load_cell_slice(root).print_rec(print_limit_, outp);
|
||||
out << outp.str();
|
||||
show_block_header(blkid, std::move(root), 0xffff);
|
||||
} else {
|
||||
|
@ -2037,8 +2365,8 @@ void TestNode::got_state(ton::BlockIdExt blkid, ton::RootHash root_hash, ton::Fi
|
|||
auto out = td::TerminalIO::out();
|
||||
out << "shard state contents is ";
|
||||
std::ostringstream outp;
|
||||
block::gen::t_ShardState.print_ref(outp, root);
|
||||
vm::load_cell_slice(root).print_rec(outp);
|
||||
block::gen::t_ShardState.print_ref(print_limit_, outp, root);
|
||||
vm::load_cell_slice(root).print_rec(print_limit_, outp);
|
||||
out << outp.str();
|
||||
show_state_header(blkid, std::move(root), 0xffff);
|
||||
} else {
|
||||
|
@ -2173,7 +2501,7 @@ void TestNode::got_block_header(ton::BlockIdExt blkid, td::BufferSlice data, int
|
|||
auto root = res.move_as_ok();
|
||||
std::ostringstream outp;
|
||||
vm::CellSlice cs{vm::NoVm(), root};
|
||||
cs.print_rec(outp);
|
||||
cs.print_rec(print_limit_, outp);
|
||||
td::TerminalIO::out() << outp.str();
|
||||
try {
|
||||
auto virt_root = vm::MerkleProof::virtualize(root, 1);
|
||||
|
@ -2405,6 +2733,11 @@ int main(int argc, char* argv[]) {
|
|||
td::actor::send_closure(x, &TestNode::set_db_root, fname.str());
|
||||
return td::Status::OK();
|
||||
});
|
||||
p.add_option('L', "print-limit", "sets maximum count of recursively printed objects", [&](td::Slice arg) {
|
||||
auto plimit = td::to_integer<int>(arg);
|
||||
td::actor::send_closure(x, &TestNode::set_print_limit, plimit);
|
||||
return plimit >= 0 ? td::Status::OK() : td::Status::Error("printing limit must be non-negative");
|
||||
});
|
||||
p.add_option('v', "verbosity", "set verbosity level", [&](td::Slice arg) {
|
||||
verbosity = td::to_integer<int>(arg);
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL) + verbosity);
|
||||
|
|
|
@ -50,6 +50,7 @@ class TestNode : public td::actor::Actor {
|
|||
bool readline_enabled_ = true;
|
||||
bool server_ok_ = false;
|
||||
td::int32 liteserver_idx_ = -1;
|
||||
int print_limit_ = 1024;
|
||||
|
||||
bool ready_ = false;
|
||||
bool inited_ = false;
|
||||
|
@ -66,6 +67,9 @@ class TestNode : public td::actor::Actor {
|
|||
ton::BlockIdExt last_block_id_, last_state_id_;
|
||||
td::BufferSlice last_block_data_, last_state_data_;
|
||||
|
||||
ton::StdSmcAddress dns_root_;
|
||||
bool dns_root_queried_{false};
|
||||
|
||||
std::string line_;
|
||||
const char *parse_ptr_, *parse_end_;
|
||||
td::Status error_;
|
||||
|
@ -118,16 +122,31 @@ class TestNode : public td::actor::Actor {
|
|||
ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string filename, int mode);
|
||||
bool parse_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
|
||||
std::string method_name, bool ext_mode);
|
||||
bool start_run_method(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt ref_blkid,
|
||||
std::string method_name, std::vector<vm::StackEntry> params, int mode,
|
||||
td::Promise<std::vector<vm::StackEntry>> promise);
|
||||
void run_smc_method(int mode, ton::BlockIdExt ref_blk, ton::BlockIdExt blk, ton::BlockIdExt shard_blk,
|
||||
td::BufferSlice shard_proof, td::BufferSlice proof, td::BufferSlice state,
|
||||
ton::WorkchainId workchain, ton::StdSmcAddress addr, std::string method,
|
||||
std::vector<vm::StackEntry> params, td::BufferSlice remote_c7, td::BufferSlice remote_libs,
|
||||
td::BufferSlice remote_result, int remote_exit_code);
|
||||
td::BufferSlice remote_result, int remote_exit_code,
|
||||
td::Promise<std::vector<vm::StackEntry>> promise);
|
||||
bool register_config_param4(Ref<vm::Cell> value);
|
||||
bool dns_resolve_start(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, std::string domain,
|
||||
int cat, int mode);
|
||||
bool dns_resolve_send(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid, std::string domain,
|
||||
std::string qdomain, int cat, int mode);
|
||||
void dns_resolve_finish(ton::WorkchainId workchain, ton::StdSmcAddress addr, ton::BlockIdExt blkid,
|
||||
std::string domain, std::string qdomain, int cat, int mode, int used_bits,
|
||||
Ref<vm::Cell> value);
|
||||
bool show_dns_record(std::ostream& os, int cat, Ref<vm::Cell> value, bool raw_dump);
|
||||
bool get_all_shards(bool use_last = true, ton::BlockIdExt blkid = {});
|
||||
void got_all_shards(ton::BlockIdExt blk, td::BufferSlice proof, td::BufferSlice data);
|
||||
bool get_config_params(ton::BlockIdExt blkid, int mode = 0, std::string filename = "");
|
||||
bool get_config_params(ton::BlockIdExt blkid, td::Promise<td::Unit> do_after, int mode = 0, std::string filename = "",
|
||||
std::vector<int> params = {});
|
||||
void got_config_params(ton::BlockIdExt req_blkid, ton::BlockIdExt blkid, td::BufferSlice state_proof,
|
||||
td::BufferSlice cfg_proof, int mode, std::string filename, std::vector<int> params);
|
||||
td::BufferSlice cfg_proof, int mode, std::string filename, std::vector<int> params,
|
||||
td::Promise<td::Unit> do_after);
|
||||
bool get_block(ton::BlockIdExt blk, bool dump = false);
|
||||
void got_block(ton::BlockIdExt blkid, td::BufferSlice data, bool dump);
|
||||
bool get_state(ton::BlockIdExt blk, bool dump = false);
|
||||
|
@ -173,7 +192,7 @@ class TestNode : public td::actor::Actor {
|
|||
bool set_error(td::Status error);
|
||||
bool set_error(std::string err_msg);
|
||||
void show_context() const;
|
||||
bool parse_account_addr(ton::WorkchainId& wc, ton::StdSmcAddress& addr);
|
||||
bool parse_account_addr(ton::WorkchainId& wc, ton::StdSmcAddress& addr, bool allow_none = false);
|
||||
static int parse_hex_digit(int c);
|
||||
static bool parse_hash(const char* str, ton::Bits256& hash);
|
||||
static bool parse_hash(td::Slice str, ton::Bits256& hash);
|
||||
|
@ -186,6 +205,8 @@ class TestNode : public td::actor::Actor {
|
|||
bool parse_hash(ton::Bits256& hash);
|
||||
bool parse_lt(ton::LogicalTime& lt);
|
||||
bool parse_uint32(td::uint32& val);
|
||||
bool parse_int32(td::int32& val);
|
||||
bool parse_int16(int& val);
|
||||
bool parse_shard_id(ton::ShardIdFull& shard);
|
||||
bool parse_block_id_ext(ton::BlockIdExt& blkid, bool allow_incomplete = false);
|
||||
bool parse_block_id_ext(std::string blk_id_string, ton::BlockIdExt& blkid, bool allow_incomplete = false) const;
|
||||
|
@ -195,6 +216,7 @@ class TestNode : public td::actor::Actor {
|
|||
bool register_blkid(const ton::BlockIdExt& blkid);
|
||||
bool show_new_blkids(bool all = false);
|
||||
bool complete_blkid(ton::BlockId partial_blkid, ton::BlockIdExt& complete_blkid) const;
|
||||
td::Promise<td::Unit> trivial_promise();
|
||||
|
||||
public:
|
||||
void conn_ready() {
|
||||
|
@ -237,6 +259,11 @@ class TestNode : public td::actor::Actor {
|
|||
fail_timeout_ = ts;
|
||||
alarm_timestamp().relax(fail_timeout_);
|
||||
}
|
||||
void set_print_limit(int plimit) {
|
||||
if (plimit >= 0) {
|
||||
print_limit_ = plimit;
|
||||
}
|
||||
}
|
||||
void add_cmd(td::BufferSlice data) {
|
||||
ex_mode_ = true;
|
||||
ex_queries_.push_back(std::move(data));
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "third_party/FAAArrayQueue.h"
|
||||
#include "third_party/HazardPointers.h"
|
||||
|
@ -56,7 +56,10 @@ extern "C" {
|
|||
#include "td/utils/Random.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/StealingQueue.h"
|
||||
#include "td/utils/ThreadSafeCounter.h"
|
||||
#include "td/utils/UInt.h"
|
||||
#include "td/utils/VectorQueue.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
@ -796,10 +799,13 @@ class MpmcQueueBenchmark : public td::Benchmark {
|
|||
std::vector<td::thread> m_threads(m_);
|
||||
auto impl = std::make_unique<Impl>(n_ + m_ + 1);
|
||||
size_t thread_id = 0;
|
||||
td::ThreadSafeCounter counter;
|
||||
CHECK(counter.sum() == 0);
|
||||
for (auto &thread : m_threads) {
|
||||
thread = td::thread([&, thread_id] {
|
||||
while (true) {
|
||||
size_t value = impl->pop(thread_id);
|
||||
counter.add(-static_cast<td::int64>(value));
|
||||
if (!value) {
|
||||
break;
|
||||
}
|
||||
|
@ -811,6 +817,7 @@ class MpmcQueueBenchmark : public td::Benchmark {
|
|||
thread = td::thread([&, thread_id] {
|
||||
for (int i = 0; i < n / n_; i++) {
|
||||
impl->push(static_cast<size_t>(i + 1), thread_id);
|
||||
counter.add(i + 1);
|
||||
}
|
||||
});
|
||||
thread_id++;
|
||||
|
@ -818,7 +825,10 @@ class MpmcQueueBenchmark : public td::Benchmark {
|
|||
for (auto &thread : n_threads) {
|
||||
thread.join();
|
||||
}
|
||||
for (int i = 0; i < m_; i++) {
|
||||
while (counter.sum() != 0) {
|
||||
td::this_thread::yield();
|
||||
}
|
||||
for (int i = 0; i < m_ + n_ + 1; i++) {
|
||||
impl->push(0, thread_id);
|
||||
}
|
||||
for (auto &thread : m_threads) {
|
||||
|
@ -832,6 +842,62 @@ class MpmcQueueBenchmark : public td::Benchmark {
|
|||
int m_;
|
||||
};
|
||||
|
||||
template <class Impl>
|
||||
class MpmcQueueBenchmark2 : public td::Benchmark {
|
||||
public:
|
||||
MpmcQueueBenchmark2(int n, int k) : n_(n), k_(k) {
|
||||
}
|
||||
std::string get_description() const override {
|
||||
return PSTRING() << "MpmcQueueBenchmark2 " << n_ << " " << k_ << " " << Impl::get_description();
|
||||
}
|
||||
|
||||
void run(int n) override {
|
||||
std::vector<td::thread> n_threads(n_);
|
||||
auto impl = std::make_unique<Impl>(n_ + 1);
|
||||
size_t thread_id = 0;
|
||||
std::atomic<int> left{k_};
|
||||
|
||||
for (int i = 0; i < k_; i++) {
|
||||
impl->push(n, thread_id);
|
||||
}
|
||||
|
||||
for (auto &thread : n_threads) {
|
||||
thread = td::thread([&, thread_id] {
|
||||
while (true) {
|
||||
size_t value = impl->pop(thread_id);
|
||||
if (value > 1) {
|
||||
impl->push(value - 1, thread_id);
|
||||
}
|
||||
if (value == 1) {
|
||||
left--;
|
||||
}
|
||||
if (!value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
thread_id++;
|
||||
}
|
||||
|
||||
while (left.load() != 0) {
|
||||
td::this_thread::yield();
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_ + 1; i++) {
|
||||
impl->push(0, thread_id);
|
||||
}
|
||||
|
||||
for (auto &thread : n_threads) {
|
||||
thread.join();
|
||||
}
|
||||
impl.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
int n_;
|
||||
int k_;
|
||||
};
|
||||
|
||||
class Cheat {
|
||||
public:
|
||||
explicit Cheat(size_t thread_n) : impl_(static_cast<int>(thread_n)) {
|
||||
|
@ -959,26 +1025,95 @@ std::string CfQueueT<FAAArrayQueue<Cell>, Cell>::get_description() {
|
|||
template <class Value>
|
||||
class MoodyQueue {
|
||||
public:
|
||||
explicit MoodyQueue(size_t) {
|
||||
explicit MoodyQueue(size_t n) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
p.push_back(moodycamel::ProducerToken(q));
|
||||
c.push_back(moodycamel::ConsumerToken(q));
|
||||
}
|
||||
}
|
||||
static std::string get_description() {
|
||||
return "moodycamel queue";
|
||||
}
|
||||
void push(Value v, size_t) {
|
||||
q.enqueue(v);
|
||||
void push(Value v, size_t tid) {
|
||||
q.enqueue(p[tid], v);
|
||||
}
|
||||
Value pop(size_t) {
|
||||
Value pop(size_t tid) {
|
||||
Value res;
|
||||
while (!q.try_dequeue(res)) {
|
||||
while (!q.try_dequeue(c[tid], res)) {
|
||||
}
|
||||
//q.wait_dequeue(c[tid], res);
|
||||
return res;
|
||||
}
|
||||
bool try_pop(Value &value, size_t) {
|
||||
return q.try_dequeue(value);
|
||||
bool try_pop(Value &value, size_t tid) {
|
||||
return q.try_dequeue(c[tid], value);
|
||||
}
|
||||
|
||||
private:
|
||||
moodycamel::ConcurrentQueue<Value> q;
|
||||
std::vector<moodycamel::ProducerToken> p;
|
||||
std::vector<moodycamel::ConsumerToken> c;
|
||||
};
|
||||
|
||||
struct Sem {
|
||||
public:
|
||||
void post() {
|
||||
if (++cnt_ == 0) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(mutex_);
|
||||
}
|
||||
cnd_.notify_one();
|
||||
}
|
||||
}
|
||||
void wait(int cnt = 1) {
|
||||
auto was = cnt_.fetch_sub(cnt);
|
||||
if (was >= cnt) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock<std::mutex> lk(mutex_);
|
||||
cnd_.wait(lk, [&] { return cnt_ >= 0; });
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cnd_;
|
||||
std::atomic<int> cnt_{0};
|
||||
};
|
||||
|
||||
template <class Value>
|
||||
class MagicQueue {
|
||||
public:
|
||||
explicit MagicQueue(size_t n) : n_(n), qs_(n_ - 1), pos_{0} {
|
||||
}
|
||||
static std::string get_description() {
|
||||
return "magic queue";
|
||||
}
|
||||
void push(Value v, size_t tid) {
|
||||
if (v == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tid + 1 == n_) {
|
||||
qs_[pos_].push(v);
|
||||
pos_ = (pos_ + 1) % (n_ - 1);
|
||||
} else {
|
||||
qs_[tid].push(v);
|
||||
}
|
||||
}
|
||||
Value pop(size_t tid) {
|
||||
CHECK(tid + 1 != n_);
|
||||
if (qs_[tid].empty()) {
|
||||
return 0;
|
||||
}
|
||||
return qs_[tid].pop();
|
||||
}
|
||||
bool try_pop(Value &value, size_t) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t n_;
|
||||
std::vector<td::VectorQueue<Value>> qs_;
|
||||
size_t pos_;
|
||||
};
|
||||
|
||||
#if TG_LCR_QUEUE
|
||||
|
@ -1110,65 +1245,155 @@ class WaitQueue {
|
|||
static std::string get_description() {
|
||||
return "Wait + " + Q::get_description();
|
||||
}
|
||||
explicit WaitQueue(size_t threads_n) : impl(threads_n) {
|
||||
|
||||
explicit WaitQueue(size_t threads_n) : impl(threads_n), slots(threads_n) {
|
||||
for (size_t i = 0; i < threads_n; i++) {
|
||||
waiter.init_slot(slots[i].slot, static_cast<int>(i));
|
||||
}
|
||||
}
|
||||
|
||||
T pop(size_t thread_id) {
|
||||
T res;
|
||||
int yields = 0;
|
||||
while (!impl.try_pop(res, thread_id)) {
|
||||
yields = waiter.wait(yields, static_cast<uint32>(thread_id));
|
||||
while (true) {
|
||||
if (slots[thread_id].local_queue.try_pop(res)) {
|
||||
break;
|
||||
}
|
||||
if (impl.try_pop(res, thread_id)) {
|
||||
break;
|
||||
}
|
||||
waiter.wait(slots[thread_id].slot);
|
||||
}
|
||||
waiter.stop_wait(yields, static_cast<uint32>(thread_id));
|
||||
waiter.stop_wait(slots[thread_id].slot);
|
||||
//LOG(ERROR) << "GOT";
|
||||
return res;
|
||||
}
|
||||
|
||||
void push_local(T value, size_t thread_id) {
|
||||
auto o_value = slots[thread_id].local_queue.push(value);
|
||||
if (o_value) {
|
||||
push(o_value.unwrap, thread_id);
|
||||
}
|
||||
}
|
||||
|
||||
void push(T value, size_t thread_id) {
|
||||
impl.push(std::move(value), static_cast<uint32>(thread_id));
|
||||
impl.push(value, static_cast<uint32>(thread_id));
|
||||
waiter.notify();
|
||||
}
|
||||
|
||||
private:
|
||||
W waiter;
|
||||
Q impl;
|
||||
struct Slot {
|
||||
typename W::Slot slot;
|
||||
td::actor::core::LocalQueue<T> local_queue;
|
||||
};
|
||||
std::vector<Slot> slots;
|
||||
};
|
||||
template <class Q, class W, class T>
|
||||
class StealingWaitQueue {
|
||||
public:
|
||||
static std::string get_description() {
|
||||
return "StealWait + " + Q::get_description();
|
||||
}
|
||||
|
||||
explicit StealingWaitQueue(size_t threads_n) : impl(threads_n), slots(threads_n) {
|
||||
for (size_t i = 0; i < threads_n; i++) {
|
||||
waiter.init_slot(slots[i].slot, static_cast<int>(i));
|
||||
}
|
||||
}
|
||||
|
||||
T pop(size_t thread_id) {
|
||||
T res;
|
||||
while (true) {
|
||||
if (slots[thread_id].stealing_queue.local_pop(res)) {
|
||||
break;
|
||||
}
|
||||
if (slots[thread_id].local_queue.try_pop(res)) {
|
||||
break;
|
||||
}
|
||||
if (impl.try_pop(res, thread_id)) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
for (size_t i = 1; i < slots.size(); i++) {
|
||||
auto pos = (i + thread_id) % slots.size();
|
||||
if (slots[thread_id].stealing_queue.steal(res, slots[pos].stealing_queue)) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
break;
|
||||
}
|
||||
waiter.wait(slots[thread_id].slot);
|
||||
}
|
||||
waiter.stop_wait(slots[thread_id].slot);
|
||||
//LOG(ERROR) << "GOT";
|
||||
return res;
|
||||
}
|
||||
|
||||
void push_local(T value, size_t thread_id) {
|
||||
auto o_value = slots[thread_id].local_queue.push(value);
|
||||
if (o_value) {
|
||||
push(o_value.unwrap, thread_id);
|
||||
}
|
||||
}
|
||||
|
||||
void push(T value, size_t thread_id) {
|
||||
slots[thread_id].stealing_queue.local_push(value,
|
||||
[&](auto value) { impl.push(value, static_cast<uint32>(thread_id)); });
|
||||
waiter.notify();
|
||||
}
|
||||
|
||||
private:
|
||||
W waiter;
|
||||
Q impl;
|
||||
struct Slot {
|
||||
typename W::Slot slot;
|
||||
td::actor::core::LocalQueue<T> local_queue;
|
||||
td::StealingQueue<T> stealing_queue;
|
||||
};
|
||||
std::vector<Slot> slots;
|
||||
};
|
||||
|
||||
void run_queue_bench(int n, int m) {
|
||||
bench(MpmcQueueBenchmark<WaitQueue<td::MpmcQueue<size_t>, td::MpmcWaiter, size_t>>(n, m), 2);
|
||||
bench(MpmcQueueBenchmark<td::MpmcQueue<size_t>>(n, m), 2);
|
||||
bench(MpmcQueueBenchmark<td::MpmcQueueOld<size_t>>(n, m), 2);
|
||||
bench(MpmcQueueBenchmark<Cheat>(n, m), 2);
|
||||
bench(MpmcQueueBenchmark<CfQueue<FAAArrayQueue<size_t>>>(n, m), 2);
|
||||
bench(MpmcQueueBenchmark<CfQueue<LazyIndexArrayQueue<size_t>>>(n, m), 2);
|
||||
bench(MpmcQueueBenchmark<StupidQueue<size_t>>(n, m), 2);
|
||||
bench(MpmcQueueBenchmark<MoodyQueue<size_t>>(n, m), 2);
|
||||
bench(MpmcQueueBenchmark<StealingWaitQueue<td::MpmcQueue<size_t>, td::MpmcEagerWaiter, size_t>>(n, m), 2);
|
||||
bench(MpmcQueueBenchmark<StealingWaitQueue<td::MpmcQueue<size_t>, td::MpmcSleepyWaiter, size_t>>(n, m), 2);
|
||||
bench(MpmcQueueBenchmark<WaitQueue<td::MpmcQueue<size_t>, td::MpmcEagerWaiter, size_t>>(n, m), 2);
|
||||
bench(MpmcQueueBenchmark<WaitQueue<td::MpmcQueue<size_t>, td::MpmcSleepyWaiter, size_t>>(n, m), 2);
|
||||
//bench(MpmcQueueBenchmark<td::MpmcQueue<size_t>>(n, m), 2);
|
||||
//bench(MpmcQueueBenchmark<td::MpmcQueueOld<size_t>>(n, m), 2);
|
||||
//bench(MpmcQueueBenchmark<Cheat>(n, m), 2);
|
||||
//bench(MpmcQueueBenchmark<CfQueue<FAAArrayQueue<size_t>>>(n, m), 2);
|
||||
//bench(MpmcQueueBenchmark<CfQueue<LazyIndexArrayQueue<size_t>>>(n, m), 2);
|
||||
//bench(MpmcQueueBenchmark<StupidQueue<size_t>>(n, m), 2);
|
||||
|
||||
//bench(MpmcQueueBenchmark<MpQueue>(n, m), 2);
|
||||
#if TG_LCR_QUEUE
|
||||
bench(MpmcQueueBenchmark<CfQueue<LCRQueue<size_t>>>(n, m), 2);
|
||||
#endif
|
||||
}
|
||||
void run_queue_bench2(int n, int k) {
|
||||
bench(MpmcQueueBenchmark2<StealingWaitQueue<td::MpmcQueue<size_t>, td::MpmcSleepyWaiter, size_t>>(n, k), 2);
|
||||
bench(MpmcQueueBenchmark2<StealingWaitQueue<td::MpmcQueue<size_t>, td::MpmcEagerWaiter, size_t>>(n, k), 2);
|
||||
bench(MpmcQueueBenchmark2<MagicQueue<size_t>>(n, k), 2);
|
||||
bench(MpmcQueueBenchmark2<MoodyQueue<size_t>>(n, k), 2);
|
||||
bench(MpmcQueueBenchmark2<WaitQueue<td::MpmcQueue<size_t>, td::MpmcEagerWaiter, size_t>>(n, k), 2);
|
||||
bench(MpmcQueueBenchmark2<WaitQueue<td::MpmcQueue<size_t>, td::MpmcSleepyWaiter, size_t>>(n, k), 2);
|
||||
//bench(MpmcQueueBenchmark2<td::MpmcQueue<size_t>>(n, k), 2);
|
||||
//bench(MpmcQueueBenchmark2<td::MpmcQueueOld<size_t>>(n, k), 2);
|
||||
//bench(MpmcQueueBenchmark2<Cheat>(n, k), 2);
|
||||
//bench(MpmcQueueBenchmark2<CfQueue<FAAArrayQueue<size_t>>>(n, k), 2);
|
||||
//bench(MpmcQueueBenchmark2<CfQueue<LazyIndexArrayQueue<size_t>>>(n, k), 2);
|
||||
//bench(MpmcQueueBenchmark2<StupidQueue<size_t>>(n, k), 2);
|
||||
|
||||
struct Sem {
|
||||
public:
|
||||
void post() {
|
||||
if (++cnt_ == 0) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(mutex_);
|
||||
}
|
||||
cnd_.notify_one();
|
||||
}
|
||||
}
|
||||
void wait(int cnt = 1) {
|
||||
auto was = cnt_.fetch_sub(cnt);
|
||||
if (was >= cnt) {
|
||||
return;
|
||||
}
|
||||
std::unique_lock<std::mutex> lk(mutex_);
|
||||
cnd_.wait(lk, [&] { return cnt_ >= 0; });
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cnd_;
|
||||
std::atomic<int> cnt_{0};
|
||||
};
|
||||
//bench(MpmcQueueBenchmark<MpQueue>(n, m), 2);
|
||||
#if TG_LCR_QUEUE
|
||||
bench(MpmcQueueBenchmark2<CfQueue<LCRQueue<size_t>>>(n, k), 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
class ChainedSpawn : public td::Benchmark {
|
||||
public:
|
||||
|
@ -1415,17 +1640,18 @@ class YieldMany : public td::Benchmark {
|
|||
int main(int argc, char **argv) {
|
||||
if (argc > 1) {
|
||||
if (argv[1][0] == 'a') {
|
||||
bench_n(MpmcQueueBenchmark<td::MpmcQueue<size_t>>(1, 1), 1 << 26);
|
||||
bench_n(MpmcQueueBenchmark2<WaitQueue<td::MpmcQueue<size_t>, td::MpmcEagerWaiter, size_t>>(50, 1), 1 << 26);
|
||||
//bench_n(MpmcQueueBenchmark<td::MpmcQueue<size_t>>(1, 1), 1 << 26);
|
||||
//bench_n(MpmcQueueBenchmark<MpQueue>(1, 40), 1 << 20);
|
||||
//bench_n(MpmcQueueBenchmark<CfQueue<LCRQueue<size_t>>>(1, 40), 1 << 20);
|
||||
} else {
|
||||
bench_n(MpmcQueueBenchmark<td::MpmcQueueOld<size_t>>(1, 1), 1 << 26);
|
||||
bench_n(MpmcQueueBenchmark2<WaitQueue<td::MpmcQueue<size_t>, td::MpmcSleepyWaiter, size_t>>(50, 1), 1 << 26);
|
||||
//bench_n(MpmcQueueBenchmark<td::MpmcQueueOld<size_t>>(1, 1), 1 << 26);
|
||||
//bench_n(MpmcQueueBenchmark<CfQueue<LCRQueue<size_t>>>(1, 40), 1 << 20);
|
||||
//bench_n(MpmcQueueBenchmark<CfQueue<FAAArrayQueue<size_t>>>(1, 1), 1 << 26);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bench(YieldMany(false));
|
||||
bench(YieldMany(true));
|
||||
bench(SpawnMany(false));
|
||||
|
@ -1436,6 +1662,22 @@ int main(int argc, char **argv) {
|
|||
bench(ChainedSpawnInplace(true));
|
||||
bench(ChainedSpawn(false));
|
||||
bench(ChainedSpawn(true));
|
||||
|
||||
run_queue_bench(10, 10);
|
||||
run_queue_bench(10, 1);
|
||||
run_queue_bench(1, 10);
|
||||
run_queue_bench(1, 1);
|
||||
run_queue_bench(2, 10);
|
||||
run_queue_bench(2, 2);
|
||||
run_queue_bench(10, 1);
|
||||
|
||||
run_queue_bench2(50, 1);
|
||||
run_queue_bench2(50, 2);
|
||||
run_queue_bench2(1, 100);
|
||||
run_queue_bench2(1, 1000);
|
||||
run_queue_bench2(10, 2);
|
||||
run_queue_bench2(10, 1000);
|
||||
|
||||
return 0;
|
||||
|
||||
bench(ActorDummyQuery());
|
||||
|
@ -1466,16 +1708,5 @@ int main(int argc, char **argv) {
|
|||
bench(CalcHashSha256Benchmark<BlockSha256MpmcQueue<BoundedMpmcQueue<std::function<void()>>>>());
|
||||
bench(CalcHashSha256Benchmark<BlockSha256MpmcQueue<td::MpmcQueue<std::function<void()>>>>());
|
||||
|
||||
run_queue_bench(1, 10);
|
||||
run_queue_bench(1, 1);
|
||||
run_queue_bench(2, 10);
|
||||
run_queue_bench(2, 2);
|
||||
run_queue_bench(10, 10);
|
||||
|
||||
run_queue_bench(2, 2);
|
||||
run_queue_bench(1, 10);
|
||||
run_queue_bench(10, 1);
|
||||
run_queue_bench(10, 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
136
tdactor/benchmark/third_party/MoodyCamelQueue.h
vendored
136
tdactor/benchmark/third_party/MoodyCamelQueue.h
vendored
|
@ -269,17 +269,17 @@ static inline thread_id_t thread_id() {
|
|||
namespace moodycamel {
|
||||
namespace details {
|
||||
#if defined(__GNUC__)
|
||||
inline bool likely(bool x) {
|
||||
static inline bool(likely)(bool x) {
|
||||
return __builtin_expect((x), true);
|
||||
}
|
||||
inline bool unlikely(bool x) {
|
||||
static inline bool(unlikely)(bool x) {
|
||||
return __builtin_expect((x), false);
|
||||
}
|
||||
#else
|
||||
inline bool likely(bool x) {
|
||||
static inline bool(likely)(bool x) {
|
||||
return x;
|
||||
}
|
||||
inline bool unlikely(bool x) {
|
||||
static inline bool(unlikely)(bool x) {
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
@ -300,8 +300,8 @@ struct const_numeric_max {
|
|||
: static_cast<T>(-1);
|
||||
};
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
typedef ::max_align_t std_max_align_t; // GCC forgot to add it to std:: for a while
|
||||
#if defined(__GLIBCXX__)
|
||||
typedef ::max_align_t std_max_align_t; // libstdc++ forgot to add it to std:: for a while
|
||||
#else
|
||||
typedef std::max_align_t std_max_align_t; // Others (e.g. MSVC) insist it can *only* be accessed via std::
|
||||
#endif
|
||||
|
@ -377,8 +377,8 @@ struct ConcurrentQueueDefaultTraits {
|
|||
static const size_t MAX_SUBQUEUE_SIZE = details::const_numeric_max<size_t>::value;
|
||||
|
||||
#ifndef MCDBGQ_USE_RELACY
|
||||
// Memory allocation can be customized if needed.
|
||||
// malloc should return nullptr on failure, and handle alignment like std::malloc.
|
||||
// Memory allocation can be customized if needed.
|
||||
// malloc should return nullptr on failure, and handle alignment like std::malloc.
|
||||
#if defined(malloc) || defined(free)
|
||||
// Gah, this is 2015, stop defining macros that break standard code already!
|
||||
// Work around malloc/free being special macros:
|
||||
|
@ -1140,7 +1140,7 @@ class ConcurrentQueue {
|
|||
// If there was at least one non-empty queue but it appears empty at the time
|
||||
// we try to dequeue from it, we need to make sure every queue's been tried
|
||||
if (nonEmptyCount > 0) {
|
||||
if (details::likely(best->dequeue(item))) {
|
||||
if ((details::likely)(best->dequeue(item))) {
|
||||
return true;
|
||||
}
|
||||
for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {
|
||||
|
@ -1335,7 +1335,10 @@ class ConcurrentQueue {
|
|||
private:
|
||||
friend struct ProducerToken;
|
||||
friend struct ConsumerToken;
|
||||
struct ExplicitProducer;
|
||||
friend struct ExplicitProducer;
|
||||
struct ImplicitProducer;
|
||||
friend struct ImplicitProducer;
|
||||
friend class ConcurrentQueueTests;
|
||||
|
||||
enum AllocationMode { CanAlloc, CannotAlloc };
|
||||
|
@ -1380,7 +1383,7 @@ class ConcurrentQueue {
|
|||
}
|
||||
auto prodCount = producerCount.load(std::memory_order_relaxed);
|
||||
auto globalOffset = globalExplicitConsumerOffset.load(std::memory_order_relaxed);
|
||||
if (details::unlikely(token.desiredProducer == nullptr)) {
|
||||
if ((details::unlikely)(token.desiredProducer == nullptr)) {
|
||||
// Aha, first time we're dequeueing anything.
|
||||
// Figure out our local position
|
||||
// Note: offset is from start, not end, but we're traversing from end -- subtract from count first
|
||||
|
@ -1442,7 +1445,7 @@ class ConcurrentQueue {
|
|||
FreeList& operator=(FreeList const&) MOODYCAMEL_DELETE_FUNCTION;
|
||||
|
||||
inline void add(N* node) {
|
||||
#if MCDBGQ_NOLOCKFREE_FREELIST
|
||||
#ifdef MCDBGQ_NOLOCKFREE_FREELIST
|
||||
debug::DebugLock lock(mutex);
|
||||
#endif
|
||||
// We know that the should-be-on-freelist bit is 0 at this point, so it's safe to
|
||||
|
@ -1455,7 +1458,7 @@ class ConcurrentQueue {
|
|||
}
|
||||
|
||||
inline N* try_get() {
|
||||
#if MCDBGQ_NOLOCKFREE_FREELIST
|
||||
#ifdef MCDBGQ_NOLOCKFREE_FREELIST
|
||||
debug::DebugLock lock(mutex);
|
||||
#endif
|
||||
auto head = freeListHead.load(std::memory_order_acquire);
|
||||
|
@ -1529,7 +1532,7 @@ class ConcurrentQueue {
|
|||
static const std::uint32_t REFS_MASK = 0x7FFFFFFF;
|
||||
static const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000;
|
||||
|
||||
#if MCDBGQ_NOLOCKFREE_FREELIST
|
||||
#ifdef MCDBGQ_NOLOCKFREE_FREELIST
|
||||
debug::DebugMutex mutex;
|
||||
#endif
|
||||
};
|
||||
|
@ -1548,7 +1551,7 @@ class ConcurrentQueue {
|
|||
, freeListNext(nullptr)
|
||||
, shouldBeOnFreeList(false)
|
||||
, dynamicallyAllocated(true) {
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
owner = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
@ -1679,14 +1682,14 @@ class ConcurrentQueue {
|
|||
std::atomic<bool> shouldBeOnFreeList;
|
||||
bool dynamicallyAllocated; // Perhaps a better name for this would be 'isNotPartOfInitialBlockPool'
|
||||
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
void* owner;
|
||||
#endif
|
||||
};
|
||||
static_assert(std::alignment_of<Block>::value >= std::alignment_of<details::max_align_t>::value,
|
||||
"Internal error: Blocks must be at least as aligned as the type they are wrapping");
|
||||
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
public:
|
||||
struct MemStats;
|
||||
|
||||
|
@ -1756,7 +1759,7 @@ class ConcurrentQueue {
|
|||
ConcurrentQueue* parent;
|
||||
|
||||
protected:
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
friend struct MemStats;
|
||||
#endif
|
||||
};
|
||||
|
@ -1902,7 +1905,7 @@ class ConcurrentQueue {
|
|||
if (newBlock == nullptr) {
|
||||
return false;
|
||||
}
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
newBlock->owner = this;
|
||||
#endif
|
||||
newBlock->ConcurrentQueue::Block::template reset_empty<explicit_context>();
|
||||
|
@ -1916,7 +1919,7 @@ class ConcurrentQueue {
|
|||
++pr_blockIndexSlotsUsed;
|
||||
}
|
||||
|
||||
if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward<U>(element)))) {
|
||||
if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward<U>(element)))) {
|
||||
// The constructor may throw. We want the element not to appear in the queue in
|
||||
// that case (without corrupting the queue):
|
||||
MOODYCAMEL_TRY {
|
||||
|
@ -1941,7 +1944,7 @@ class ConcurrentQueue {
|
|||
blockIndex.load(std::memory_order_relaxed)->front.store(pr_blockIndexFront, std::memory_order_release);
|
||||
pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1);
|
||||
|
||||
if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward<U>(element)))) {
|
||||
if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward<U>(element)))) {
|
||||
this->tailIndex.store(newTailIndex, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
@ -1985,13 +1988,14 @@ class ConcurrentQueue {
|
|||
// incremented after dequeueOptimisticCount -- this is enforced in the `else` block below), and since we now
|
||||
// have a version of dequeueOptimisticCount that is at least as recent as overcommit (due to the release upon
|
||||
// incrementing dequeueOvercommit and the acquire above that synchronizes with it), overcommit <= myDequeueCount.
|
||||
assert(overcommit <= myDequeueCount);
|
||||
// However, we can't assert this since both dequeueOptimisticCount and dequeueOvercommit may (independently)
|
||||
// overflow; in such a case, though, the logic still holds since the difference between the two is maintained.
|
||||
|
||||
// Note that we reload tail here in case it changed; it will be the same value as before or greater, since
|
||||
// this load is sequenced after (happens after) the earlier load above. This is supported by read-read
|
||||
// coherency (as defined in the standard), explained here: http://en.cppreference.com/w/cpp/atomic/memory_order
|
||||
tail = this->tailIndex.load(std::memory_order_acquire);
|
||||
if (details::likely(details::circular_less_than<index_t>(myDequeueCount - overcommit, tail))) {
|
||||
if ((details::likely)(details::circular_less_than<index_t>(myDequeueCount - overcommit, tail))) {
|
||||
// Guaranteed to be at least one element to dequeue!
|
||||
|
||||
// Get the index. Note that since there's guaranteed to be at least one element, this
|
||||
|
@ -2033,10 +2037,10 @@ class ConcurrentQueue {
|
|||
}
|
||||
} guard = {block, index};
|
||||
|
||||
element = std::move(el);
|
||||
element = std::move(el); // NOLINT
|
||||
} else {
|
||||
element = std::move(el);
|
||||
el.~T();
|
||||
element = std::move(el); // NOLINT
|
||||
el.~T(); // NOLINT
|
||||
block->ConcurrentQueue::Block::template set_empty<explicit_context>(index);
|
||||
}
|
||||
|
||||
|
@ -2119,7 +2123,7 @@ class ConcurrentQueue {
|
|||
return false;
|
||||
}
|
||||
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
newBlock->owner = this;
|
||||
#endif
|
||||
newBlock->ConcurrentQueue::Block::template set_all_empty<explicit_context>();
|
||||
|
@ -2151,7 +2155,8 @@ class ConcurrentQueue {
|
|||
block = block->next;
|
||||
}
|
||||
|
||||
if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))) {
|
||||
if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst),
|
||||
new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))) {
|
||||
blockIndex.load(std::memory_order_relaxed)
|
||||
->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release);
|
||||
}
|
||||
|
@ -2172,7 +2177,8 @@ class ConcurrentQueue {
|
|||
if (details::circular_less_than<index_t>(newTailIndex, stopIndex)) {
|
||||
stopIndex = newTailIndex;
|
||||
}
|
||||
if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))) {
|
||||
if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst),
|
||||
new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))) {
|
||||
while (currentTailIndex != stopIndex) {
|
||||
new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++);
|
||||
}
|
||||
|
@ -2186,9 +2192,10 @@ class ConcurrentQueue {
|
|||
// may only define a (noexcept) move constructor, and so calls to the
|
||||
// cctor will not compile, even if they are in an if branch that will never
|
||||
// be executed
|
||||
new ((*this->tailBlock)[currentTailIndex]) T(
|
||||
details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR(
|
||||
T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst));
|
||||
new ((*this->tailBlock)[currentTailIndex])
|
||||
T(details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR(
|
||||
T, decltype(*itemFirst),
|
||||
new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst));
|
||||
++currentTailIndex;
|
||||
++itemFirst;
|
||||
}
|
||||
|
@ -2236,7 +2243,7 @@ class ConcurrentQueue {
|
|||
this->tailBlock = this->tailBlock->next;
|
||||
}
|
||||
|
||||
if (!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst))) &&
|
||||
if (!MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new ((T*)nullptr) T(details::deref_noexcept(itemFirst))) &&
|
||||
firstAllocatedBlock != nullptr) {
|
||||
blockIndex.load(std::memory_order_relaxed)
|
||||
->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release);
|
||||
|
@ -2257,7 +2264,7 @@ class ConcurrentQueue {
|
|||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed);
|
||||
assert(overcommit <= myDequeueCount);
|
||||
;
|
||||
|
||||
tail = this->tailIndex.load(std::memory_order_acquire);
|
||||
auto actualCount = static_cast<size_t>(tail - (myDequeueCount - overcommit));
|
||||
|
@ -2418,7 +2425,7 @@ class ConcurrentQueue {
|
|||
private:
|
||||
#endif
|
||||
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
friend struct MemStats;
|
||||
#endif
|
||||
};
|
||||
|
@ -2500,7 +2507,7 @@ class ConcurrentQueue {
|
|||
(MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) {
|
||||
return false;
|
||||
}
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
debug::DebugLock lock(mutex);
|
||||
#endif
|
||||
// Find out where we'll be inserting this block in the block index
|
||||
|
@ -2516,12 +2523,12 @@ class ConcurrentQueue {
|
|||
idxEntry->value.store(nullptr, std::memory_order_relaxed);
|
||||
return false;
|
||||
}
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
newBlock->owner = this;
|
||||
#endif
|
||||
newBlock->ConcurrentQueue::Block::template reset_empty<implicit_context>();
|
||||
|
||||
if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward<U>(element)))) {
|
||||
if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward<U>(element)))) {
|
||||
// May throw, try to insert now before we publish the fact that we have this new block
|
||||
MOODYCAMEL_TRY {
|
||||
new ((*newBlock)[currentTailIndex]) T(std::forward<U>(element));
|
||||
|
@ -2539,7 +2546,7 @@ class ConcurrentQueue {
|
|||
|
||||
this->tailBlock = newBlock;
|
||||
|
||||
if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new (nullptr) T(std::forward<U>(element)))) {
|
||||
if (!MOODYCAMEL_NOEXCEPT_CTOR(T, U, new ((T*)nullptr) T(std::forward<U>(element)))) {
|
||||
this->tailIndex.store(newTailIndex, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
@ -2562,9 +2569,8 @@ class ConcurrentQueue {
|
|||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
index_t myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed);
|
||||
assert(overcommit <= myDequeueCount);
|
||||
tail = this->tailIndex.load(std::memory_order_acquire);
|
||||
if (details::likely(details::circular_less_than<index_t>(myDequeueCount - overcommit, tail))) {
|
||||
if ((details::likely)(details::circular_less_than<index_t>(myDequeueCount - overcommit, tail))) {
|
||||
index_t index = this->headIndex.fetch_add(1, std::memory_order_acq_rel);
|
||||
|
||||
// Determine which block the element is in
|
||||
|
@ -2575,7 +2581,7 @@ class ConcurrentQueue {
|
|||
auto& el = *((*block)[index]);
|
||||
|
||||
if (!MOODYCAMEL_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) {
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
// Note: Acquiring the mutex with every dequeue instead of only when a block
|
||||
// is released is very sub-optimal, but it is, after all, purely debug code.
|
||||
debug::DebugLock lock(producer->mutex);
|
||||
|
@ -2595,14 +2601,14 @@ class ConcurrentQueue {
|
|||
}
|
||||
} guard = {block, index, entry, this->parent};
|
||||
|
||||
element = std::move(el);
|
||||
element = std::move(el); // NOLINT
|
||||
} else {
|
||||
element = std::move(el);
|
||||
el.~T();
|
||||
element = std::move(el); // NOLINT
|
||||
el.~T(); // NOLINT
|
||||
|
||||
if (block->ConcurrentQueue::Block::template set_empty<implicit_context>(index)) {
|
||||
{
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
debug::DebugLock lock(mutex);
|
||||
#endif
|
||||
// Add the block back into the global free pool (and remove from block index)
|
||||
|
@ -2642,7 +2648,7 @@ class ConcurrentQueue {
|
|||
((startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1));
|
||||
index_t currentTailIndex = (startTailIndex - 1) & ~static_cast<index_t>(BLOCK_SIZE - 1);
|
||||
if (blockBaseDiff > 0) {
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
debug::DebugLock lock(mutex);
|
||||
#endif
|
||||
do {
|
||||
|
@ -2679,7 +2685,7 @@ class ConcurrentQueue {
|
|||
return false;
|
||||
}
|
||||
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
newBlock->owner = this;
|
||||
#endif
|
||||
newBlock->ConcurrentQueue::Block::template reset_empty<implicit_context>();
|
||||
|
@ -2714,16 +2720,18 @@ class ConcurrentQueue {
|
|||
if (details::circular_less_than<index_t>(newTailIndex, stopIndex)) {
|
||||
stopIndex = newTailIndex;
|
||||
}
|
||||
if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))) {
|
||||
if (MOODYCAMEL_NOEXCEPT_CTOR(T, decltype(*itemFirst),
|
||||
new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))) {
|
||||
while (currentTailIndex != stopIndex) {
|
||||
new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++);
|
||||
}
|
||||
} else {
|
||||
MOODYCAMEL_TRY {
|
||||
while (currentTailIndex != stopIndex) {
|
||||
new ((*this->tailBlock)[currentTailIndex]) T(
|
||||
details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR(
|
||||
T, decltype(*itemFirst), new (nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst));
|
||||
new ((*this->tailBlock)[currentTailIndex])
|
||||
T(details::nomove_if<(bool)!MOODYCAMEL_NOEXCEPT_CTOR(
|
||||
T, decltype(*itemFirst),
|
||||
new ((T*)nullptr) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst));
|
||||
++currentTailIndex;
|
||||
++itemFirst;
|
||||
}
|
||||
|
@ -2788,7 +2796,6 @@ class ConcurrentQueue {
|
|||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed);
|
||||
assert(overcommit <= myDequeueCount);
|
||||
|
||||
tail = this->tailIndex.load(std::memory_order_acquire);
|
||||
auto actualCount = static_cast<size_t>(tail - (myDequeueCount - overcommit));
|
||||
|
@ -2843,7 +2850,7 @@ class ConcurrentQueue {
|
|||
|
||||
if (block->ConcurrentQueue::Block::template set_many_empty<implicit_context>(
|
||||
blockStartIndex, static_cast<size_t>(endIndex - blockStartIndex))) {
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
debug::DebugLock lock(mutex);
|
||||
#endif
|
||||
entry->value.store(nullptr, std::memory_order_relaxed);
|
||||
|
@ -2865,7 +2872,7 @@ class ConcurrentQueue {
|
|||
if (block->ConcurrentQueue::Block::template set_many_empty<implicit_context>(
|
||||
blockStartIndex, static_cast<size_t>(endIndex - blockStartIndex))) {
|
||||
{
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
debug::DebugLock lock(mutex);
|
||||
#endif
|
||||
// Note that the set_many_empty above did a release, meaning that anybody who acquires the block
|
||||
|
@ -2945,7 +2952,7 @@ class ConcurrentQueue {
|
|||
}
|
||||
|
||||
inline size_t get_block_index_index_for_index(index_t index, BlockIndexHeader*& localBlockIndex) const {
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
debug::DebugLock lock(mutex);
|
||||
#endif
|
||||
index &= ~static_cast<index_t>(BLOCK_SIZE - 1);
|
||||
|
@ -3026,10 +3033,10 @@ class ConcurrentQueue {
|
|||
private:
|
||||
#endif
|
||||
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX
|
||||
mutable debug::DebugMutex mutex;
|
||||
#endif
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
friend struct MemStats;
|
||||
#endif
|
||||
};
|
||||
|
@ -3065,7 +3072,7 @@ class ConcurrentQueue {
|
|||
}
|
||||
|
||||
inline void add_block_to_free_list(Block* block) {
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
block->owner = nullptr;
|
||||
#endif
|
||||
freeList.add(block);
|
||||
|
@ -3103,7 +3110,7 @@ class ConcurrentQueue {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
#if MCDBGQ_TRACKMEM
|
||||
#ifdef MCDBGQ_TRACKMEM
|
||||
public:
|
||||
struct MemStats {
|
||||
size_t allocatedBlocks;
|
||||
|
@ -3221,7 +3228,7 @@ class ConcurrentQueue {
|
|||
}
|
||||
|
||||
ProducerBase* recycle_or_create_producer(bool isExplicit, bool& recycled) {
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
|
||||
debug::DebugLock lock(implicitProdMutex);
|
||||
#endif
|
||||
// Try to re-use one first
|
||||
|
@ -3386,7 +3393,7 @@ class ConcurrentQueue {
|
|||
|
||||
// Code and algorithm adapted from http://preshing.com/20130605/the-worlds-simplest-lock-free-hash-table
|
||||
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
|
||||
debug::DebugLock lock(implicitProdMutex);
|
||||
#endif
|
||||
|
||||
|
@ -3443,6 +3450,7 @@ class ConcurrentQueue {
|
|||
// Insert!
|
||||
auto newCount = 1 + implicitProducerHashCount.fetch_add(1, std::memory_order_relaxed);
|
||||
while (true) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.NullDereference)
|
||||
if (newCount >= (mainHash->capacity >> 1) &&
|
||||
!implicitProducerHashResizeInProgress.test_and_set(std::memory_order_acquire)) {
|
||||
// We've acquired the resize lock, try to allocate a bigger hash table.
|
||||
|
@ -3538,8 +3546,8 @@ class ConcurrentQueue {
|
|||
// Remove from thread exit listeners
|
||||
details::ThreadExitNotifier::unsubscribe(&producer->threadExitListener);
|
||||
|
||||
// Remove from hash
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
|
||||
// Remove from hash
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
|
||||
debug::DebugLock lock(implicitProdMutex);
|
||||
#endif
|
||||
auto hash = implicitProducerHash.load(std::memory_order_acquire);
|
||||
|
@ -3650,7 +3658,7 @@ class ConcurrentQueue {
|
|||
std::atomic<std::uint32_t> nextExplicitConsumerId;
|
||||
std::atomic<std::uint32_t> globalExplicitConsumerOffset;
|
||||
|
||||
#if MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
|
||||
#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH
|
||||
debug::DebugMutex implicitProdMutex;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -41,6 +41,7 @@ class ActorInfo : private HeapNode, private ListNode {
|
|||
}
|
||||
~ActorInfo() {
|
||||
VLOG(actor) << "Destroy actor [" << name_ << "]";
|
||||
CHECK(!actor_);
|
||||
}
|
||||
|
||||
bool is_alive() const {
|
||||
|
|
|
@ -14,13 +14,15 @@
|
|||
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 "td/actor/core/CpuWorker.h"
|
||||
|
||||
#include "td/actor/core/ActorExecutor.h"
|
||||
#include "td/actor/core/SchedulerContext.h"
|
||||
|
||||
#include "td/actor/core/Scheduler.h" // FIXME: afer LocalQueue is in a separate file
|
||||
|
||||
namespace td {
|
||||
namespace actor {
|
||||
namespace core {
|
||||
|
@ -28,20 +30,64 @@ void CpuWorker::run() {
|
|||
auto thread_id = get_thread_id();
|
||||
auto &dispatcher = *SchedulerContext::get();
|
||||
|
||||
int yields = 0;
|
||||
MpmcWaiter::Slot slot;
|
||||
waiter_.init_slot(slot, thread_id);
|
||||
while (true) {
|
||||
SchedulerMessage message;
|
||||
if (queue_.try_pop(message, thread_id)) {
|
||||
if (try_pop(message, thread_id)) {
|
||||
waiter_.stop_wait(slot);
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
ActorExecutor executor(*message, dispatcher, ActorExecutor::Options().with_from_queue());
|
||||
yields = waiter_.stop_wait(yields, thread_id);
|
||||
} else {
|
||||
yields = waiter_.wait(yields, thread_id);
|
||||
waiter_.wait(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CpuWorker::try_pop_local(SchedulerMessage &message) {
|
||||
SchedulerMessage::Raw *raw_message;
|
||||
if (local_queues_[id_].try_pop(raw_message)) {
|
||||
message = SchedulerMessage(SchedulerMessage::acquire_t{}, raw_message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CpuWorker::try_pop_global(SchedulerMessage &message, size_t thread_id) {
|
||||
SchedulerMessage::Raw *raw_message;
|
||||
if (queue_.try_pop(raw_message, thread_id)) {
|
||||
message = SchedulerMessage(SchedulerMessage::acquire_t{}, raw_message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CpuWorker::try_pop(SchedulerMessage &message, size_t thread_id) {
|
||||
if (++cnt_ == 51) {
|
||||
cnt_ = 0;
|
||||
if (try_pop_global(message, thread_id) || try_pop_local(message)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (try_pop_local(message) || try_pop_global(message, thread_id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < local_queues_.size(); i++) {
|
||||
size_t pos = (i + id_) % local_queues_.size();
|
||||
SchedulerMessage::Raw *raw_message;
|
||||
if (local_queues_[id_].steal(raw_message, local_queues_[pos])) {
|
||||
message = SchedulerMessage(SchedulerMessage::acquire_t{}, raw_message);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace core
|
||||
} // namespace actor
|
||||
} // namespace td
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -22,19 +22,32 @@
|
|||
|
||||
#include "td/utils/MpmcQueue.h"
|
||||
#include "td/utils/MpmcWaiter.h"
|
||||
#include "td/utils/Span.h"
|
||||
|
||||
namespace td {
|
||||
namespace actor {
|
||||
namespace core {
|
||||
template <class T>
|
||||
struct LocalQueue;
|
||||
class CpuWorker {
|
||||
public:
|
||||
CpuWorker(MpmcQueue<SchedulerMessage> &queue, MpmcWaiter &waiter) : queue_(queue), waiter_(waiter) {
|
||||
CpuWorker(MpmcQueue<SchedulerMessage::Raw *> &queue, MpmcWaiter &waiter, size_t id,
|
||||
MutableSpan<LocalQueue<SchedulerMessage::Raw *>> local_queues)
|
||||
: queue_(queue), waiter_(waiter), id_(id), local_queues_(local_queues) {
|
||||
}
|
||||
void run();
|
||||
|
||||
private:
|
||||
MpmcQueue<SchedulerMessage> &queue_;
|
||||
MpmcQueue<SchedulerMessage::Raw *> &queue_;
|
||||
MpmcWaiter &waiter_;
|
||||
size_t id_;
|
||||
MutableSpan<LocalQueue<SchedulerMessage::Raw *>> local_queues_;
|
||||
size_t cnt_{0};
|
||||
|
||||
bool try_pop(SchedulerMessage &message, size_t thread_id);
|
||||
|
||||
bool try_pop_local(SchedulerMessage &message);
|
||||
bool try_pop_global(SchedulerMessage &message, size_t thread_id);
|
||||
};
|
||||
} // namespace core
|
||||
} // namespace actor
|
||||
|
|
|
@ -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 "td/actor/core/Scheduler.h"
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
|||
namespace td {
|
||||
namespace actor {
|
||||
namespace core {
|
||||
|
||||
Scheduler::Scheduler(std::shared_ptr<SchedulerGroupInfo> scheduler_group_info, SchedulerId id, size_t cpu_threads_count)
|
||||
: scheduler_group_info_(std::move(scheduler_group_info)), cpu_threads_(cpu_threads_count) {
|
||||
scheduler_group_info_->active_scheduler_count++;
|
||||
|
@ -31,17 +32,21 @@ Scheduler::Scheduler(std::shared_ptr<SchedulerGroupInfo> scheduler_group_info, S
|
|||
info_->id = id;
|
||||
if (cpu_threads_count != 0) {
|
||||
info_->cpu_threads_count = cpu_threads_count;
|
||||
info_->cpu_queue = std::make_unique<MpmcQueue<SchedulerMessage>>(1024, max_thread_count());
|
||||
info_->cpu_queue = std::make_unique<MpmcQueue<SchedulerMessage::Raw *>>(1024, max_thread_count());
|
||||
info_->cpu_queue_waiter = std::make_unique<MpmcWaiter>();
|
||||
|
||||
info_->cpu_local_queue = std::vector<LocalQueue<SchedulerMessage::Raw *>>(cpu_threads_count);
|
||||
}
|
||||
info_->io_queue = std::make_unique<MpscPollableQueue<SchedulerMessage>>();
|
||||
info_->io_queue->init();
|
||||
|
||||
info_->cpu_workers.resize(cpu_threads_count);
|
||||
td::uint8 cpu_worker_id = 0;
|
||||
for (auto &worker : info_->cpu_workers) {
|
||||
worker = std::make_unique<WorkerInfo>(WorkerInfo::Type::Cpu, true);
|
||||
worker = std::make_unique<WorkerInfo>(WorkerInfo::Type::Cpu, true, CpuWorkerId{cpu_worker_id});
|
||||
cpu_worker_id++;
|
||||
}
|
||||
info_->io_worker = std::make_unique<WorkerInfo>(WorkerInfo::Type::Io, !info_->cpu_workers.empty());
|
||||
info_->io_worker = std::make_unique<WorkerInfo>(WorkerInfo::Type::Io, !info_->cpu_workers.empty(), CpuWorkerId{});
|
||||
|
||||
poll_.init();
|
||||
io_worker_ = std::make_unique<IoWorker>(*info_->io_queue);
|
||||
|
@ -62,8 +67,9 @@ Scheduler::~Scheduler() {
|
|||
void Scheduler::start() {
|
||||
for (size_t i = 0; i < cpu_threads_.size(); i++) {
|
||||
cpu_threads_[i] = td::thread([this, i] {
|
||||
this->run_in_context_impl(*this->info_->cpu_workers[i],
|
||||
[this] { CpuWorker(*info_->cpu_queue, *info_->cpu_queue_waiter).run(); });
|
||||
this->run_in_context_impl(*this->info_->cpu_workers[i], [this, i] {
|
||||
CpuWorker(*info_->cpu_queue, *info_->cpu_queue_waiter, i, info_->cpu_local_queue).run();
|
||||
});
|
||||
});
|
||||
cpu_threads_[i].set_name(PSLICE() << "#" << info_->id.value() << ":cpu#" << i);
|
||||
}
|
||||
|
@ -121,9 +127,14 @@ void Scheduler::do_stop() {
|
|||
scheduler_group_info_->active_scheduler_count_condition_variable.notify_all();
|
||||
}
|
||||
|
||||
Scheduler::ContextImpl::ContextImpl(ActorInfoCreator *creator, SchedulerId scheduler_id,
|
||||
Scheduler::ContextImpl::ContextImpl(ActorInfoCreator *creator, SchedulerId scheduler_id, CpuWorkerId cpu_worker_id,
|
||||
SchedulerGroupInfo *scheduler_group, Poll *poll, KHeap<double> *heap)
|
||||
: creator_(creator), scheduler_id_(scheduler_id), scheduler_group_(scheduler_group), poll_(poll), heap_(heap) {
|
||||
: creator_(creator)
|
||||
, scheduler_id_(scheduler_id)
|
||||
, cpu_worker_id_(cpu_worker_id)
|
||||
, scheduler_group_(scheduler_group)
|
||||
, poll_(poll)
|
||||
, heap_(heap) {
|
||||
}
|
||||
|
||||
SchedulerId Scheduler::ContextImpl::get_scheduler_id() const {
|
||||
|
@ -138,7 +149,18 @@ void Scheduler::ContextImpl::add_to_queue(ActorInfoPtr actor_info_ptr, Scheduler
|
|||
if (need_poll || !info.cpu_queue) {
|
||||
info.io_queue->writer_put(std::move(actor_info_ptr));
|
||||
} else {
|
||||
info.cpu_queue->push(std::move(actor_info_ptr), get_thread_id());
|
||||
if (scheduler_id == get_scheduler_id() && cpu_worker_id_.is_valid()) {
|
||||
// may push local
|
||||
CHECK(actor_info_ptr);
|
||||
auto raw = actor_info_ptr.release();
|
||||
auto should_notify = info.cpu_local_queue[cpu_worker_id_.value()].push(
|
||||
raw, [&](auto value) { info.cpu_queue->push(value, get_thread_id()); });
|
||||
if (should_notify) {
|
||||
info.cpu_queue_waiter->notify();
|
||||
}
|
||||
return;
|
||||
}
|
||||
info.cpu_queue->push(actor_info_ptr.release(), get_thread_id());
|
||||
info.cpu_queue_waiter->notify();
|
||||
}
|
||||
}
|
||||
|
@ -254,13 +276,26 @@ void Scheduler::close_scheduler_group(SchedulerGroupInfo &group_info) {
|
|||
}
|
||||
|
||||
// Drain cpu queue
|
||||
for (auto &q : scheduler_info.cpu_local_queue) {
|
||||
auto &cpu_queue = q;
|
||||
while (true) {
|
||||
SchedulerMessage::Raw *raw_message;
|
||||
if (!cpu_queue.try_pop(raw_message)) {
|
||||
break;
|
||||
}
|
||||
SchedulerMessage(SchedulerMessage::acquire_t{}, raw_message);
|
||||
// message's destructor is called
|
||||
queues_are_empty = false;
|
||||
}
|
||||
}
|
||||
if (scheduler_info.cpu_queue) {
|
||||
auto &cpu_queue = *scheduler_info.cpu_queue;
|
||||
while (true) {
|
||||
SchedulerMessage message;
|
||||
if (!cpu_queue.try_pop(message, get_thread_id())) {
|
||||
SchedulerMessage::Raw *raw_message;
|
||||
if (!cpu_queue.try_pop(raw_message, get_thread_id())) {
|
||||
break;
|
||||
}
|
||||
SchedulerMessage(SchedulerMessage::acquire_t{}, raw_message);
|
||||
// message's destructor is called
|
||||
queues_are_empty = false;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -38,9 +38,11 @@
|
|||
#include "td/utils/List.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/MpmcQueue.h"
|
||||
#include "td/utils/StealingQueue.h"
|
||||
#include "td/utils/MpmcWaiter.h"
|
||||
#include "td/utils/MpscLinkQueue.h"
|
||||
#include "td/utils/MpscPollableQueue.h"
|
||||
#include "td/utils/optional.h"
|
||||
#include "td/utils/port/Poll.h"
|
||||
#include "td/utils/port/detail/Iocp.h"
|
||||
#include "td/utils/port/thread.h"
|
||||
|
@ -66,16 +68,52 @@ class IoWorker;
|
|||
struct WorkerInfo {
|
||||
enum class Type { Io, Cpu } type{Type::Io};
|
||||
WorkerInfo() = default;
|
||||
explicit WorkerInfo(Type type, bool allow_shared) : type(type), actor_info_creator(allow_shared) {
|
||||
explicit WorkerInfo(Type type, bool allow_shared, CpuWorkerId cpu_worker_id)
|
||||
: type(type), actor_info_creator(allow_shared), cpu_worker_id(cpu_worker_id) {
|
||||
}
|
||||
ActorInfoCreator actor_info_creator;
|
||||
CpuWorkerId cpu_worker_id;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct LocalQueue {
|
||||
public:
|
||||
template <class F>
|
||||
bool push(T value, F &&overflow_f) {
|
||||
auto res = std::move(next_);
|
||||
next_ = std::move(value);
|
||||
if (res) {
|
||||
queue_.local_push(res.unwrap(), overflow_f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool try_pop(T &message) {
|
||||
if (!next_) {
|
||||
return queue_.local_pop(message);
|
||||
}
|
||||
message = next_.unwrap();
|
||||
return true;
|
||||
}
|
||||
bool steal(T &message, LocalQueue<T> &other) {
|
||||
return queue_.steal(message, other.queue_);
|
||||
}
|
||||
|
||||
private:
|
||||
td::optional<T> next_;
|
||||
StealingQueue<T> queue_;
|
||||
char pad[TD_CONCURRENCY_PAD - sizeof(optional<T>)];
|
||||
};
|
||||
|
||||
struct SchedulerInfo {
|
||||
SchedulerId id;
|
||||
// will be read by all workers is any thread
|
||||
std::unique_ptr<MpmcQueue<SchedulerMessage>> cpu_queue;
|
||||
std::unique_ptr<MpmcQueue<SchedulerMessage::Raw *>> cpu_queue;
|
||||
std::unique_ptr<MpmcWaiter> cpu_queue_waiter;
|
||||
|
||||
std::vector<LocalQueue<SchedulerMessage::Raw *>> cpu_local_queue;
|
||||
//std::vector<td::StealingQueue<SchedulerMessage>> cpu_stealing_queue;
|
||||
|
||||
// only scheduler itself may read from io_queue_
|
||||
std::unique_ptr<MpscPollableQueue<SchedulerMessage>> io_queue;
|
||||
size_t cpu_threads_count{0};
|
||||
|
@ -156,11 +194,12 @@ class Scheduler {
|
|||
|
||||
class ContextImpl : public SchedulerContext {
|
||||
public:
|
||||
ContextImpl(ActorInfoCreator *creator, SchedulerId scheduler_id, SchedulerGroupInfo *scheduler_group, Poll *poll,
|
||||
KHeap<double> *heap);
|
||||
ContextImpl(ActorInfoCreator *creator, SchedulerId scheduler_id, CpuWorkerId cpu_worker_id,
|
||||
SchedulerGroupInfo *scheduler_group, Poll *poll, KHeap<double> *heap);
|
||||
|
||||
SchedulerId get_scheduler_id() const override;
|
||||
void add_to_queue(ActorInfoPtr actor_info_ptr, SchedulerId scheduler_id, bool need_poll) override;
|
||||
|
||||
ActorInfoCreator &get_actor_info_creator() override;
|
||||
|
||||
bool has_poll() override;
|
||||
|
@ -181,6 +220,7 @@ class Scheduler {
|
|||
|
||||
ActorInfoCreator *creator_;
|
||||
SchedulerId scheduler_id_;
|
||||
CpuWorkerId cpu_worker_id_;
|
||||
SchedulerGroupInfo *scheduler_group_;
|
||||
Poll *poll_;
|
||||
|
||||
|
@ -193,8 +233,8 @@ class Scheduler {
|
|||
td::detail::Iocp::Guard iocp_guard(&scheduler_group_info_->iocp);
|
||||
#endif
|
||||
bool is_io_worker = worker_info.type == WorkerInfo::Type::Io;
|
||||
ContextImpl context(&worker_info.actor_info_creator, info_->id, scheduler_group_info_.get(),
|
||||
is_io_worker ? &poll_ : nullptr, is_io_worker ? &heap_ : nullptr);
|
||||
ContextImpl context(&worker_info.actor_info_creator, info_->id, worker_info.cpu_worker_id,
|
||||
scheduler_group_info_.get(), is_io_worker ? &poll_ : nullptr, is_io_worker ? &heap_ : nullptr);
|
||||
SchedulerContext::Guard guard(&context);
|
||||
f();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -26,8 +26,7 @@ namespace actor {
|
|||
namespace core {
|
||||
class SchedulerId {
|
||||
public:
|
||||
SchedulerId() : id_(-1) {
|
||||
}
|
||||
SchedulerId() = default;
|
||||
explicit SchedulerId(uint8 id) : id_(id) {
|
||||
}
|
||||
bool is_valid() const {
|
||||
|
@ -42,7 +41,27 @@ class SchedulerId {
|
|||
}
|
||||
|
||||
private:
|
||||
int32 id_{0};
|
||||
int32 id_{-1};
|
||||
};
|
||||
|
||||
class CpuWorkerId {
|
||||
public:
|
||||
CpuWorkerId() = default;
|
||||
explicit CpuWorkerId(uint8 id) : id_(id) {
|
||||
}
|
||||
bool is_valid() const {
|
||||
return id_ >= 0;
|
||||
}
|
||||
uint8 value() const {
|
||||
CHECK(is_valid());
|
||||
return static_cast<uint8>(id_);
|
||||
}
|
||||
bool operator==(CpuWorkerId other) const {
|
||||
return id_ == other.id_;
|
||||
}
|
||||
|
||||
private:
|
||||
int32 id_{-1};
|
||||
};
|
||||
} // namespace core
|
||||
} // namespace actor
|
||||
|
|
|
@ -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 "td/actor/core/ActorLocker.h"
|
||||
#include "td/actor/actor.h"
|
||||
|
@ -410,7 +410,7 @@ class Master : public Actor {
|
|||
|
||||
private:
|
||||
uint32 l = 0;
|
||||
uint32 r = 100000;
|
||||
uint32 r = 1000;
|
||||
core::ActorInfoPtr worker;
|
||||
void start_up() override {
|
||||
worker = detail::create_actor<Worker>(ActorOptions().with_name("Master"));
|
||||
|
@ -444,8 +444,8 @@ TEST(Actor2, scheduler_simple) {
|
|||
core::Scheduler scheduler{group_info, SchedulerId{0}, 2};
|
||||
scheduler.start();
|
||||
scheduler.run_in_context([] {
|
||||
global_cnt = 10;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
global_cnt = 1000;
|
||||
for (int i = 0; i < global_cnt; i++) {
|
||||
detail::create_actor<Master>(ActorOptions().with_name("Master"));
|
||||
}
|
||||
});
|
||||
|
@ -734,7 +734,7 @@ TEST(Actor2, actor_ping_pong) {
|
|||
return;
|
||||
}
|
||||
auto dest = td::Random::fast(0, (int)next_.size() - 1);
|
||||
if (td::Random::fast(0, 1) == 0 && 0) {
|
||||
if (td::Random::fast(0, 1) == 0) {
|
||||
send_closure(next_[dest], &PingPong::query, left - 1, std::move(data));
|
||||
} else {
|
||||
send_closure_later(next_[dest], &PingPong::query, left - 1, std::move(data));
|
||||
|
@ -755,7 +755,7 @@ TEST(Actor2, actor_ping_pong) {
|
|||
std::shared_ptr<td::Destructor> watcher_;
|
||||
};
|
||||
|
||||
int N = td::Random::fast(2, 10);
|
||||
int N = td::Random::fast(2, 100);
|
||||
//N = 2;
|
||||
std::vector<ActorOwn<PingPong>> actors;
|
||||
for (int i = 0; i < N; i++) {
|
||||
|
|
|
@ -230,6 +230,7 @@ set(TDUTILS_SOURCE
|
|||
td/utils/SpinLock.h
|
||||
td/utils/StackAllocator.h
|
||||
td/utils/Status.h
|
||||
td/utils/StealingQueue.h
|
||||
td/utils/Storer.h
|
||||
td/utils/StorerBase.h
|
||||
td/utils/StringBuilder.h
|
||||
|
@ -281,6 +282,7 @@ set(TDUTILS_TEST_SOURCE
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/test/pq.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/SharedObjectPool.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/SharedSlice.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/StealingQueue.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/variant.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -117,24 +117,28 @@ template <class T>
|
|||
class OneValue<T *> {
|
||||
public:
|
||||
bool set_value(T *value) {
|
||||
T *was = nullptr;
|
||||
T *was = Empty();
|
||||
return state_.compare_exchange_strong(was, value, std::memory_order_acq_rel);
|
||||
}
|
||||
bool get_value(T *&value) {
|
||||
value = state_.exchange(Taken(), std::memory_order_acq_rel);
|
||||
return value != nullptr;
|
||||
return value != Empty();
|
||||
}
|
||||
void reset() {
|
||||
state_ = nullptr;
|
||||
state_ = Empty();
|
||||
}
|
||||
OneValue() {
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<T *> state_{nullptr};
|
||||
T *Taken() {
|
||||
static T xxx;
|
||||
return &xxx;
|
||||
std::atomic<T *> state_{Empty()};
|
||||
static T *Empty() {
|
||||
static int64 xxx;
|
||||
return reinterpret_cast<T *>(&xxx);
|
||||
}
|
||||
static T *Taken() {
|
||||
static int64 xxx;
|
||||
return reinterpret_cast<T *>(&xxx);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,63 +14,86 @@
|
|||
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 "td/utils/common.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/thread.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
namespace td {
|
||||
|
||||
class MpmcWaiter {
|
||||
class MpmcEagerWaiter {
|
||||
public:
|
||||
int wait(int yields, uint32 worker_id) {
|
||||
if (yields < RoundsTillSleepy) {
|
||||
struct Slot {
|
||||
private:
|
||||
friend class MpmcEagerWaiter;
|
||||
int yields;
|
||||
uint32 worker_id;
|
||||
};
|
||||
void init_slot(Slot &slot, uint32 worker_id) {
|
||||
slot.yields = 0;
|
||||
slot.worker_id = worker_id;
|
||||
}
|
||||
void wait(Slot &slot) {
|
||||
if (slot.yields < RoundsTillSleepy) {
|
||||
td::this_thread::yield();
|
||||
return yields + 1;
|
||||
} else if (yields == RoundsTillSleepy) {
|
||||
slot.yields++;
|
||||
return;
|
||||
} else if (slot.yields == RoundsTillSleepy) {
|
||||
auto state = state_.load(std::memory_order_relaxed);
|
||||
if (!State::has_worker(state)) {
|
||||
auto new_state = State::with_worker(state, worker_id);
|
||||
auto new_state = State::with_worker(state, slot.worker_id);
|
||||
if (state_.compare_exchange_strong(state, new_state, std::memory_order_acq_rel)) {
|
||||
td::this_thread::yield();
|
||||
return yields + 1;
|
||||
slot.yields++;
|
||||
return;
|
||||
}
|
||||
if (state == State::awake()) {
|
||||
return 0;
|
||||
slot.yields = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
td::this_thread::yield();
|
||||
return 0;
|
||||
} else if (yields < RoundsTillAsleep) {
|
||||
slot.yields = 0;
|
||||
return;
|
||||
} else if (slot.yields < RoundsTillAsleep) {
|
||||
auto state = state_.load(std::memory_order_acquire);
|
||||
if (State::still_sleepy(state, worker_id)) {
|
||||
if (State::still_sleepy(state, slot.worker_id)) {
|
||||
td::this_thread::yield();
|
||||
return yields + 1;
|
||||
slot.yields++;
|
||||
return;
|
||||
}
|
||||
return 0;
|
||||
slot.yields = 0;
|
||||
return;
|
||||
} else {
|
||||
auto state = state_.load(std::memory_order_acquire);
|
||||
if (State::still_sleepy(state, worker_id)) {
|
||||
if (State::still_sleepy(state, slot.worker_id)) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (state_.compare_exchange_strong(state, State::asleep(), std::memory_order_acq_rel)) {
|
||||
condition_variable_.wait(lock);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
slot.yields = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int stop_wait(int yields, uint32 worker_id) {
|
||||
if (yields > RoundsTillSleepy) {
|
||||
void stop_wait(Slot &slot) {
|
||||
if (slot.yields > RoundsTillSleepy) {
|
||||
notify_cold();
|
||||
}
|
||||
return 0;
|
||||
slot.yields = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
void close() {
|
||||
}
|
||||
|
||||
void notify() {
|
||||
|
@ -102,8 +125,8 @@ class MpmcWaiter {
|
|||
return (state >> 1) == (worker + 1);
|
||||
}
|
||||
};
|
||||
//enum { RoundsTillSleepy = 32, RoundsTillAsleep = 64 };
|
||||
enum { RoundsTillSleepy = 1, RoundsTillAsleep = 2 };
|
||||
enum { RoundsTillSleepy = 32, RoundsTillAsleep = 64 };
|
||||
// enum { RoundsTillSleepy = 1, RoundsTillAsleep = 2 };
|
||||
std::atomic<uint32> state_{State::awake()};
|
||||
std::mutex mutex_;
|
||||
std::condition_variable condition_variable_;
|
||||
|
@ -117,4 +140,208 @@ class MpmcWaiter {
|
|||
}
|
||||
};
|
||||
|
||||
class MpmcSleepyWaiter {
|
||||
public:
|
||||
struct Slot {
|
||||
private:
|
||||
friend class MpmcSleepyWaiter;
|
||||
|
||||
enum State { Search, Work, Sleep } state_{Work};
|
||||
|
||||
void park() {
|
||||
std::unique_lock<std::mutex> guard(mutex_);
|
||||
condition_variable_.wait(guard, [&] { return unpark_flag_; });
|
||||
unpark_flag_ = false;
|
||||
}
|
||||
|
||||
bool cancel_park() {
|
||||
auto res = unpark_flag_;
|
||||
unpark_flag_ = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
void unpark() {
|
||||
//TODO: try unlock guard before notify_all
|
||||
std::unique_lock<std::mutex> guard(mutex_);
|
||||
unpark_flag_ = true;
|
||||
condition_variable_.notify_all();
|
||||
}
|
||||
|
||||
std::mutex mutex_;
|
||||
std::condition_variable condition_variable_;
|
||||
bool unpark_flag_{false}; // TODO: move out of lock
|
||||
int yield_cnt{0};
|
||||
int32 worker_id{0};
|
||||
char padding[128];
|
||||
};
|
||||
|
||||
// There are a lot of workers
|
||||
// Each has a slot
|
||||
//
|
||||
// States of a worker:
|
||||
// - searching for work | Search
|
||||
// - processing work | Work
|
||||
// - sleeping | Sleep
|
||||
//
|
||||
// When somebody adds a work it calls notify
|
||||
//
|
||||
// notify
|
||||
// if there are workers in search phase do nothing.
|
||||
// if all workers are awake do nothing
|
||||
// otherwise wake some random worker
|
||||
//
|
||||
// Initially all workers are in Search mode.
|
||||
//
|
||||
// When worker found nothing it may try to call wait.
|
||||
// This may put it in a Sleep for some time.
|
||||
// After wait return worker will be in Search state again.
|
||||
//
|
||||
// Suppose worker found a work and ready to process it.
|
||||
// Than it may call stop_wait. This will cause transition from
|
||||
// Search to Work state.
|
||||
//
|
||||
// Main invariant:
|
||||
// After notify is called there should be at least on worker in Search or Work state.
|
||||
// If possible - in Search state
|
||||
//
|
||||
|
||||
void init_slot(Slot &slot, int32 worker_id) {
|
||||
slot.state_ = Slot::State::Work;
|
||||
slot.unpark_flag_ = false;
|
||||
slot.worker_id = worker_id;
|
||||
VLOG(waiter) << "Init slot " << worker_id;
|
||||
}
|
||||
|
||||
int VERBOSITY_NAME(waiter) = VERBOSITY_NAME(DEBUG) + 10;
|
||||
void wait(Slot &slot) {
|
||||
if (slot.state_ == Slot::State::Work) {
|
||||
VLOG(waiter) << "Work -> Search";
|
||||
state_++;
|
||||
slot.state_ = Slot::State::Search;
|
||||
slot.yield_cnt = 0;
|
||||
return;
|
||||
}
|
||||
if (slot.state_ == Slot::Search) {
|
||||
if (slot.yield_cnt++ < 10 && false) {
|
||||
td::this_thread::yield();
|
||||
return;
|
||||
}
|
||||
|
||||
slot.state_ = Slot::State::Sleep;
|
||||
std::unique_lock<std::mutex> guard(sleepers_mutex_);
|
||||
auto state_view = StateView(state_.fetch_add((1 << PARKING_SHIFT) - 1));
|
||||
CHECK(state_view.searching_count != 0);
|
||||
bool should_search = state_view.searching_count == 1;
|
||||
if (closed_) {
|
||||
return;
|
||||
}
|
||||
sleepers_.push_back(&slot);
|
||||
LOG_CHECK(slot.unpark_flag_ == false) << slot.worker_id;
|
||||
VLOG(waiter) << "add to sleepers " << slot.worker_id;
|
||||
//guard.unlock();
|
||||
if (should_search) {
|
||||
VLOG(waiter) << "Search -> Search once then Sleep ";
|
||||
return;
|
||||
}
|
||||
VLOG(waiter) << "Search -> Sleep " << state_view.searching_count << " " << state_view.parked_count;
|
||||
}
|
||||
|
||||
CHECK(slot.state_ == Slot::State::Sleep);
|
||||
VLOG(waiter) << "Park " << slot.worker_id;
|
||||
slot.park();
|
||||
VLOG(waiter) << "Resume " << slot.worker_id;
|
||||
slot.state_ = Slot::State::Search;
|
||||
slot.yield_cnt = 0;
|
||||
}
|
||||
|
||||
void stop_wait(Slot &slot) {
|
||||
if (slot.state_ == Slot::State::Work) {
|
||||
return;
|
||||
}
|
||||
if (slot.state_ == Slot::State::Sleep) {
|
||||
VLOG(waiter) << "Search once then Sleep -> Work/Search " << slot.worker_id;
|
||||
slot.state_ = Slot::State::Work;
|
||||
std::unique_lock<std::mutex> guard(sleepers_mutex_);
|
||||
auto it = std::find(sleepers_.begin(), sleepers_.end(), &slot);
|
||||
if (it != sleepers_.end()) {
|
||||
sleepers_.erase(it);
|
||||
VLOG(waiter) << "remove from sleepers " << slot.worker_id;
|
||||
state_.fetch_sub((1 << PARKING_SHIFT) - 1);
|
||||
guard.unlock();
|
||||
} else {
|
||||
guard.unlock();
|
||||
VLOG(waiter) << "not in sleepers" << slot.worker_id;
|
||||
CHECK(slot.cancel_park());
|
||||
}
|
||||
}
|
||||
VLOG(waiter) << "Search once then Sleep -> Work " << slot.worker_id;
|
||||
slot.state_ = Slot::State::Search;
|
||||
auto state_view = StateView(state_.fetch_sub(1));
|
||||
CHECK(state_view.searching_count != 0);
|
||||
CHECK(state_view.searching_count < 1000);
|
||||
bool should_notify = state_view.searching_count == 1;
|
||||
if (should_notify) {
|
||||
VLOG(waiter) << "Notify others";
|
||||
notify();
|
||||
}
|
||||
VLOG(waiter) << "Search -> Work ";
|
||||
slot.state_ = Slot::State::Work;
|
||||
}
|
||||
|
||||
void notify() {
|
||||
auto view = StateView(state_.load());
|
||||
//LOG(ERROR) << view.parked_count;
|
||||
if (view.searching_count > 0 || view.parked_count == 0) {
|
||||
VLOG(waiter) << "Ingore notify: " << view.searching_count << " " << view.parked_count;
|
||||
return;
|
||||
}
|
||||
|
||||
VLOG(waiter) << "Notify: " << view.searching_count << " " << view.parked_count;
|
||||
std::unique_lock<std::mutex> guard(sleepers_mutex_);
|
||||
|
||||
view = StateView(state_.load());
|
||||
if (view.searching_count > 0) {
|
||||
VLOG(waiter) << "Skip notify: got searching";
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(view.parked_count == static_cast<int>(sleepers_.size()));
|
||||
if (sleepers_.empty()) {
|
||||
VLOG(waiter) << "Skip notify: no sleepers";
|
||||
return;
|
||||
}
|
||||
|
||||
auto sleeper = sleepers_.back();
|
||||
sleepers_.pop_back();
|
||||
state_.fetch_sub((1 << PARKING_SHIFT) - 1);
|
||||
VLOG(waiter) << "Unpark " << sleeper->worker_id;
|
||||
sleeper->unpark();
|
||||
}
|
||||
|
||||
void close() {
|
||||
StateView state(state_.load());
|
||||
LOG_CHECK(state.parked_count == 0) << state.parked_count;
|
||||
LOG_CHECK(state.searching_count == 0) << state.searching_count;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr td::int32 PARKING_SHIFT = 16;
|
||||
struct StateView {
|
||||
td::int32 parked_count;
|
||||
td::int32 searching_count;
|
||||
explicit StateView(int32 x) {
|
||||
parked_count = x >> PARKING_SHIFT;
|
||||
searching_count = x & ((1 << PARKING_SHIFT) - 1);
|
||||
}
|
||||
};
|
||||
std::atomic<td::int32> state_{0};
|
||||
|
||||
std::mutex sleepers_mutex_;
|
||||
std::vector<Slot *> sleepers_;
|
||||
|
||||
bool closed_ = false;
|
||||
};
|
||||
|
||||
using MpmcWaiter = MpmcSleepyWaiter;
|
||||
|
||||
} // namespace td
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -49,9 +49,7 @@ class AtomicRefCnt {
|
|||
};
|
||||
|
||||
template <class DataT, class DeleterT>
|
||||
class SharedPtrRaw
|
||||
: public DeleterT
|
||||
, private MpscLinkQueueImpl::Node {
|
||||
class SharedPtrRaw : public DeleterT, private MpscLinkQueueImpl::Node {
|
||||
public:
|
||||
explicit SharedPtrRaw(DeleterT deleter) : DeleterT(std::move(deleter)), ref_cnt_{0}, option_magic_(Magic) {
|
||||
}
|
||||
|
@ -100,6 +98,7 @@ template <class T, class DeleterT = std::default_delete<T>>
|
|||
class SharedPtr {
|
||||
public:
|
||||
using Raw = detail::SharedPtrRaw<T, DeleterT>;
|
||||
struct acquire_t {};
|
||||
SharedPtr() = default;
|
||||
~SharedPtr() {
|
||||
if (!raw_) {
|
||||
|
@ -112,6 +111,8 @@ class SharedPtr {
|
|||
raw_->inc();
|
||||
}
|
||||
}
|
||||
SharedPtr(acquire_t, Raw *raw) : raw_(raw) {
|
||||
}
|
||||
SharedPtr(const SharedPtr &other) : SharedPtr(other.raw_) {
|
||||
}
|
||||
SharedPtr &operator=(const SharedPtr &other) {
|
||||
|
|
124
tdutils/td/utils/StealingQueue.h
Normal file
124
tdutils/td/utils/StealingQueue.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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 2019-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/Span.h"
|
||||
namespace td {
|
||||
template <class T, size_t N = 256 /*must be a power of two*/>
|
||||
class StealingQueue {
|
||||
public:
|
||||
// tries to put a value
|
||||
// returns if succeeded
|
||||
// only owner is alowed to to do this
|
||||
template <class F>
|
||||
void local_push(T value, F&& overflow_f) {
|
||||
while (true) {
|
||||
auto tail = tail_.load(std::memory_order_relaxed);
|
||||
auto head = head_.load(); //TODO: memory order
|
||||
|
||||
if (static_cast<size_t>(tail - head) < N) {
|
||||
buf_[tail & MASK].store(value, std::memory_order_relaxed);
|
||||
tail_.store(tail + 1, std::memory_order_release);
|
||||
return;
|
||||
}
|
||||
|
||||
// queue is full
|
||||
// TODO: batch insert into global queue?
|
||||
auto n = N / 2 + 1;
|
||||
auto new_head = head + n;
|
||||
if (!head_.compare_exchange_strong(head, new_head)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
overflow_f(buf_[(i + head) & MASK].load(std::memory_order_relaxed));
|
||||
}
|
||||
overflow_f(value);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// tries to pop a value
|
||||
// returns if succeeded
|
||||
// only owner is alowed to to do this
|
||||
bool local_pop(T& value) {
|
||||
auto tail = tail_.load(std::memory_order_relaxed);
|
||||
auto head = head_.load();
|
||||
|
||||
if (head == tail) {
|
||||
return false;
|
||||
}
|
||||
|
||||
value = buf_[head & MASK].load(std::memory_order_relaxed);
|
||||
return head_.compare_exchange_strong(head, head + 1);
|
||||
}
|
||||
|
||||
bool steal(T& value, StealingQueue<T, N>& other) {
|
||||
while (true) {
|
||||
auto tail = tail_.load(std::memory_order_relaxed);
|
||||
auto head = head_.load(); //TODO: memory order
|
||||
|
||||
auto other_head = other.head_.load();
|
||||
auto other_tail = other.tail_.load(std::memory_order_acquire);
|
||||
|
||||
if (other_tail < other_head) {
|
||||
continue;
|
||||
}
|
||||
size_t n = other_tail - other_head;
|
||||
if (n > N) {
|
||||
continue;
|
||||
}
|
||||
n -= n / 2;
|
||||
n = td::min(n, static_cast<size_t>(head + N - tail));
|
||||
if (n == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
buf_[(i + tail) & MASK].store(other.buf_[(i + other_head) & MASK].load(std::memory_order_relaxed),
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
if (!other.head_.compare_exchange_strong(other_head, other_head + n)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
n--;
|
||||
value = buf_[(tail + n) & MASK].load(std::memory_order_relaxed);
|
||||
tail_.store(tail + n, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
StealingQueue() {
|
||||
for (auto& x : buf_) {
|
||||
x.store(T{}, std::memory_order_relaxed);
|
||||
}
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<td::int64> head_{0};
|
||||
std::atomic<td::int64> tail_{0};
|
||||
static constexpr size_t MASK{N - 1};
|
||||
std::array<std::atomic<T>, N> buf_;
|
||||
};
|
||||
}; // namespace td
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 "TsFileLog.h"
|
||||
|
||||
|
@ -24,8 +24,10 @@ namespace td {
|
|||
namespace detail {
|
||||
class TsFileLog : public LogInterface {
|
||||
public:
|
||||
Status init(string path) {
|
||||
Status init(string path, td::int64 rotate_threshold, bool redirect_stderr) {
|
||||
path_ = std::move(path);
|
||||
rotate_threshold_ = rotate_threshold;
|
||||
redirect_stderr_ = redirect_stderr;
|
||||
for (int i = 0; i < (int)logs_.size(); i++) {
|
||||
logs_[i].id = i;
|
||||
}
|
||||
|
@ -54,6 +56,8 @@ class TsFileLog : public LogInterface {
|
|||
int id;
|
||||
};
|
||||
static constexpr int MAX_THREAD_ID = 128;
|
||||
td::int64 rotate_threshold_;
|
||||
bool redirect_stderr_;
|
||||
std::string path_;
|
||||
std::array<Info, MAX_THREAD_ID> logs_;
|
||||
|
||||
|
@ -70,7 +74,7 @@ class TsFileLog : public LogInterface {
|
|||
}
|
||||
|
||||
Status init_info(Info *info) {
|
||||
TRY_STATUS(info->log.init(get_path(info), std::numeric_limits<int64>::max(), info->id == 0));
|
||||
TRY_STATUS(info->log.init(get_path(info), std::numeric_limits<int64>::max(), info->id == 0 && redirect_stderr_));
|
||||
info->is_inited = true;
|
||||
return Status::OK();
|
||||
}
|
||||
|
@ -92,9 +96,9 @@ class TsFileLog : public LogInterface {
|
|||
};
|
||||
} // namespace detail
|
||||
|
||||
Result<td::unique_ptr<LogInterface>> TsFileLog::create(string path) {
|
||||
Result<td::unique_ptr<LogInterface>> TsFileLog::create(string path, td::int64 rotate_threshold, bool redirect_stderr) {
|
||||
auto res = td::make_unique<detail::TsFileLog>();
|
||||
TRY_STATUS(res->init(path));
|
||||
TRY_STATUS(res->init(path, rotate_threshold, redirect_stderr));
|
||||
return std::move(res);
|
||||
}
|
||||
} // namespace td
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -22,7 +22,10 @@
|
|||
|
||||
namespace td {
|
||||
class TsFileLog {
|
||||
static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20);
|
||||
|
||||
public:
|
||||
static Result<td::unique_ptr<LogInterface>> create(string path);
|
||||
static Result<td::unique_ptr<LogInterface>> create(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD,
|
||||
bool redirect_stderr = true);
|
||||
};
|
||||
} // namespace td
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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 2019-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "rlimit.h"
|
||||
#if TD_LINUX || TD_ANDROID
|
||||
#include <unistd.h>
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/port/config.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "user.h"
|
||||
#if TD_LINUX
|
||||
#include <unistd.h>
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/port/config.h"
|
||||
|
|
|
@ -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 "td/utils/MpmcWaiter.h"
|
||||
#include "td/utils/port/sleep.h"
|
||||
|
@ -25,21 +25,22 @@
|
|||
#include <atomic>
|
||||
|
||||
#if !TD_THREAD_UNSUPPORTED
|
||||
TEST(MpmcWaiter, stress_one_one) {
|
||||
template <class W>
|
||||
void test_waiter_stress_one_one() {
|
||||
td::Stage run;
|
||||
td::Stage check;
|
||||
|
||||
std::vector<td::thread> threads;
|
||||
std::atomic<size_t> value{0};
|
||||
size_t write_cnt = 10;
|
||||
td::unique_ptr<td::MpmcWaiter> waiter;
|
||||
td::unique_ptr<W> waiter;
|
||||
size_t threads_n = 2;
|
||||
for (size_t i = 0; i < threads_n; i++) {
|
||||
threads.push_back(td::thread([&, id = static_cast<td::uint32>(i)] {
|
||||
for (td::uint64 round = 1; round < 100000; round++) {
|
||||
if (id == 0) {
|
||||
value = 0;
|
||||
waiter = td::make_unique<td::MpmcWaiter>();
|
||||
waiter = td::make_unique<W>();
|
||||
write_cnt = td::Random::fast(1, 10);
|
||||
}
|
||||
run.wait(round * threads_n);
|
||||
|
@ -49,17 +50,19 @@ TEST(MpmcWaiter, stress_one_one) {
|
|||
waiter->notify();
|
||||
}
|
||||
} else {
|
||||
int yields = 0;
|
||||
typename W::Slot slot;
|
||||
waiter->init_slot(slot, id);
|
||||
for (size_t i = 1; i <= write_cnt; i++) {
|
||||
while (true) {
|
||||
auto x = value.load(std::memory_order_relaxed);
|
||||
if (x >= i) {
|
||||
break;
|
||||
}
|
||||
yields = waiter->wait(yields, id);
|
||||
waiter->wait(slot);
|
||||
}
|
||||
yields = waiter->stop_wait(yields, id);
|
||||
waiter->stop_wait(slot);
|
||||
}
|
||||
waiter->stop_wait(slot);
|
||||
}
|
||||
check.wait(round * threads_n);
|
||||
}
|
||||
|
@ -69,7 +72,15 @@ TEST(MpmcWaiter, stress_one_one) {
|
|||
thread.join();
|
||||
}
|
||||
}
|
||||
TEST(MpmcWaiter, stress) {
|
||||
TEST(MpmcEagerWaiter, stress_one_one) {
|
||||
test_waiter_stress_one_one<td::MpmcEagerWaiter>();
|
||||
}
|
||||
TEST(MpmcSleepyWaiter, stress_one_one) {
|
||||
test_waiter_stress_one_one<td::MpmcSleepyWaiter>();
|
||||
}
|
||||
|
||||
template <class W>
|
||||
void test_waiter_stress() {
|
||||
td::Stage run;
|
||||
td::Stage check;
|
||||
|
||||
|
@ -81,7 +92,7 @@ TEST(MpmcWaiter, stress) {
|
|||
size_t end_pos;
|
||||
size_t write_cnt;
|
||||
size_t threads_n = 20;
|
||||
td::unique_ptr<td::MpmcWaiter> waiter;
|
||||
td::unique_ptr<W> waiter;
|
||||
for (size_t i = 0; i < threads_n; i++) {
|
||||
threads.push_back(td::thread([&, id = static_cast<td::uint32>(i)] {
|
||||
for (td::uint64 round = 1; round < 1000; round++) {
|
||||
|
@ -92,7 +103,7 @@ TEST(MpmcWaiter, stress) {
|
|||
end_pos = write_n * write_cnt;
|
||||
write_pos = 0;
|
||||
read_pos = 0;
|
||||
waiter = td::make_unique<td::MpmcWaiter>();
|
||||
waiter = td::make_unique<W>();
|
||||
}
|
||||
run.wait(round * threads_n);
|
||||
if (id <= write_n) {
|
||||
|
@ -104,21 +115,26 @@ TEST(MpmcWaiter, stress) {
|
|||
waiter->notify();
|
||||
}
|
||||
} else if (id > 10 && id - 10 <= read_n) {
|
||||
int yields = 0;
|
||||
typename W::Slot slot;
|
||||
waiter->init_slot(slot, id);
|
||||
while (true) {
|
||||
auto x = read_pos.load(std::memory_order_relaxed);
|
||||
if (x == end_pos) {
|
||||
waiter->stop_wait(slot);
|
||||
break;
|
||||
}
|
||||
if (x == write_pos.load(std::memory_order_relaxed)) {
|
||||
yields = waiter->wait(yields, id);
|
||||
waiter->wait(slot);
|
||||
continue;
|
||||
}
|
||||
yields = waiter->stop_wait(yields, id);
|
||||
waiter->stop_wait(slot);
|
||||
read_pos.compare_exchange_strong(x, x + 1, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
check.wait(round * threads_n);
|
||||
if (id == 0) {
|
||||
waiter->close();
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -126,4 +142,10 @@ TEST(MpmcWaiter, stress) {
|
|||
thread.join();
|
||||
}
|
||||
}
|
||||
TEST(MpmcEagerWaiter, stress_multi) {
|
||||
test_waiter_stress<td::MpmcEagerWaiter>();
|
||||
}
|
||||
TEST(MpmcSleepyWaiter, stress_multi) {
|
||||
test_waiter_stress<td::MpmcSleepyWaiter>();
|
||||
}
|
||||
#endif // !TD_THREAD_UNSUPPORTED
|
||||
|
|
153
tdutils/test/StealingQueue.cpp
Normal file
153
tdutils/test/StealingQueue.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
This file is part of TON Blockchain source code.
|
||||
|
||||
TON Blockchain is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
TON Blockchain is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with TON Blockchain. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
You must obey the GNU General Public License in all respects for all
|
||||
of the code used other than OpenSSL. If you modify file(s) with this
|
||||
exception, you may extend this exception to your version of the file(s),
|
||||
but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. If you delete this exception statement
|
||||
from all source files in the program, then also delete it here.
|
||||
|
||||
Copyright 2019-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "td/utils/tests.h"
|
||||
#include "td/utils/benchmark.h"
|
||||
|
||||
#include "td/utils/StealingQueue.h"
|
||||
#include "td/utils/MpmcQueue.h"
|
||||
|
||||
namespace td {
|
||||
TEST(StealingQueue, very_simple) {
|
||||
StealingQueue<int, 8> q;
|
||||
q.local_push(1, [](auto x) { UNREACHABLE(); });
|
||||
int x;
|
||||
CHECK(q.local_pop(x));
|
||||
ASSERT_EQ(1, x);
|
||||
}
|
||||
TEST(AtomicRead, simple) {
|
||||
td::Stage run;
|
||||
td::Stage check;
|
||||
|
||||
size_t threads_n = 10;
|
||||
std::vector<td::thread> threads;
|
||||
|
||||
int x{0};
|
||||
std::atomic<int> version{0};
|
||||
|
||||
int64 res = 0;
|
||||
for (size_t i = 0; i < threads_n; i++) {
|
||||
threads.push_back(td::thread([&, id = static_cast<uint32>(i)] {
|
||||
for (uint64 round = 1; round < 10000; round++) {
|
||||
if (id == 0) {
|
||||
}
|
||||
run.wait(round * threads_n);
|
||||
if (id == 0) {
|
||||
version++;
|
||||
x++;
|
||||
version++;
|
||||
} else {
|
||||
int y = 0;
|
||||
auto v1 = version.load();
|
||||
y = x;
|
||||
auto v2 = version.load();
|
||||
if (v1 == v2 && v1 % 2 == 0) {
|
||||
res += y;
|
||||
}
|
||||
}
|
||||
|
||||
check.wait(round * threads_n);
|
||||
}
|
||||
}));
|
||||
}
|
||||
td::do_not_optimize_away(res);
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
TEST(StealingQueue, simple) {
|
||||
uint64 sum;
|
||||
std::atomic<uint64> got_sum;
|
||||
|
||||
td::Stage run;
|
||||
td::Stage check;
|
||||
|
||||
size_t threads_n = 10;
|
||||
std::vector<td::thread> threads;
|
||||
std::vector<StealingQueue<int, 8>> lq(threads_n);
|
||||
MpmcQueue<int> gq(threads_n);
|
||||
|
||||
constexpr uint64 XN = 20;
|
||||
uint64 x_sum[XN];
|
||||
x_sum[0] = 0;
|
||||
x_sum[1] = 1;
|
||||
for (uint64 i = 2; i < XN; i++) {
|
||||
x_sum[i] = i + x_sum[i - 1] + x_sum[i - 2];
|
||||
}
|
||||
|
||||
td::Random::Xorshift128plus rnd(123);
|
||||
for (size_t i = 0; i < threads_n; i++) {
|
||||
threads.push_back(td::thread([&, id = static_cast<uint32>(i)] {
|
||||
for (uint64 round = 1; round < 10000; round++) {
|
||||
if (id == 0) {
|
||||
sum = 0;
|
||||
int n = rnd() % 5;
|
||||
for (int j = 0; j < n; j++) {
|
||||
int x = rand() % XN;
|
||||
sum += x_sum[x];
|
||||
gq.push(x, id);
|
||||
}
|
||||
got_sum = 0;
|
||||
}
|
||||
run.wait(round * threads_n);
|
||||
while (got_sum.load() != sum) {
|
||||
auto x = [&] {
|
||||
int res;
|
||||
if (lq[id].local_pop(res)) {
|
||||
return res;
|
||||
}
|
||||
if (gq.try_pop(res, id)) {
|
||||
return res;
|
||||
}
|
||||
if (lq[id].steal(res, lq[rand() % threads_n])) {
|
||||
//LOG(ERROR) << "STEAL";
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}();
|
||||
if (x == 0) {
|
||||
continue;
|
||||
}
|
||||
//LOG(ERROR) << x << " " << got_sum.load() << " " << sum;
|
||||
got_sum.fetch_add(x, std::memory_order_relaxed);
|
||||
lq[id].local_push(x - 1, [&](auto y) {
|
||||
//LOG(ERROR) << "OVERFLOW";
|
||||
gq.push(y, id);
|
||||
});
|
||||
if (x > 1) {
|
||||
lq[id].local_push(x - 2, [&](auto y) { gq.push(y, id); });
|
||||
}
|
||||
}
|
||||
check.wait(round * threads_n);
|
||||
}
|
||||
}));
|
||||
}
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
} // namespace td
|
|
@ -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 "td/utils/tests.h"
|
||||
#include "td/utils/FileLog.h"
|
||||
|
@ -80,7 +80,8 @@ void bench_log(std::string name, int threads_n, F &&f) {
|
|||
};
|
||||
|
||||
TEST(Log, TsLogger) {
|
||||
bench_log("NewTsFileLog", 4, [] { return td::TsFileLog::create("tmplog").move_as_ok(); });
|
||||
bench_log("NewTsFileLog", 4,
|
||||
[] { return td::TsFileLog::create("tmplog", std::numeric_limits<td::int64>::max(), false).move_as_ok(); });
|
||||
bench_log("TsFileLog", 8, [] {
|
||||
class FileLog : public td::LogInterface {
|
||||
public:
|
||||
|
|
|
@ -250,7 +250,7 @@ void TerminalIOImpl::line_cb(std::string cmd) {
|
|||
cmd_queue_.push(td::BufferSlice{std::move(cmd)});
|
||||
}
|
||||
|
||||
void TerminalIO::output_stdout(td::Slice slice) {
|
||||
void TerminalIO::output_stdout(td::Slice slice, double max_wait) {
|
||||
auto &fd = td::Stdout();
|
||||
if (fd.empty()) {
|
||||
return;
|
||||
|
@ -264,7 +264,7 @@ void TerminalIO::output_stdout(td::Slice slice) {
|
|||
}
|
||||
// Resource temporary unavailable
|
||||
if (end_time == 0) {
|
||||
end_time = Time::now() + 0.01;
|
||||
end_time = Time::now() + max_wait;
|
||||
} else if (Time::now() > end_time) {
|
||||
break;
|
||||
}
|
||||
|
@ -281,10 +281,10 @@ void TerminalIO::output(std::string line) {
|
|||
void TerminalIO::output(td::Slice line) {
|
||||
auto instance = TerminalIOImpl::instance();
|
||||
if (!instance) {
|
||||
output_stdout(line);
|
||||
output_stdout(line, 10.0);
|
||||
} else {
|
||||
instance->deactivate_readline();
|
||||
output_stdout(line);
|
||||
output_stdout(line, 10.0);
|
||||
instance->reactivate_readline();
|
||||
}
|
||||
}
|
||||
|
@ -298,23 +298,33 @@ void TerminalIO::output_stderr(td::Slice line) {
|
|||
if (!instance) {
|
||||
td::TsCerr() << line;
|
||||
} else {
|
||||
instance->deactivate_readline();
|
||||
if (instance->readline_used()) {
|
||||
output_stdout(line);
|
||||
instance->deactivate_readline();
|
||||
output_stdout(line, 0.01);
|
||||
instance->reactivate_readline();
|
||||
} else {
|
||||
td::TsCerr() << line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TerminalIOOutputter::~TerminalIOOutputter() {
|
||||
void TerminalIOOutputter::flush() {
|
||||
if (buffer_) {
|
||||
CHECK(sb_);
|
||||
if (is_err_) {
|
||||
TerminalIO::output_stderr(sb_->as_cslice());
|
||||
} else {
|
||||
TerminalIO::output(sb_->as_cslice());
|
||||
if (!sb_->as_cslice().empty()) {
|
||||
if (is_err_) {
|
||||
TerminalIO::output_stderr(sb_->as_cslice());
|
||||
} else {
|
||||
TerminalIO::output(sb_->as_cslice());
|
||||
}
|
||||
}
|
||||
sb_->clear();
|
||||
}
|
||||
}
|
||||
|
||||
TerminalIOOutputter::~TerminalIOOutputter() {
|
||||
if (buffer_) {
|
||||
flush();
|
||||
delete[] buffer_;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class TerminalIOOutputter {
|
|||
TerminalIOOutputter(bool is_err)
|
||||
: buffer_(new char[BUFFER_SIZE])
|
||||
, is_err_(is_err)
|
||||
, sb_(std::make_unique<StringBuilder>(td::MutableSlice{buffer_, BUFFER_SIZE})) {
|
||||
, sb_(std::make_unique<StringBuilder>(td::MutableSlice{buffer_, BUFFER_SIZE}, true)) {
|
||||
}
|
||||
TerminalIOOutputter(TerminalIOOutputter &&X) = default;
|
||||
|
||||
|
@ -56,6 +56,7 @@ class TerminalIOOutputter {
|
|||
bool is_error() const {
|
||||
return sb_->is_error();
|
||||
}
|
||||
void flush();
|
||||
~TerminalIOOutputter();
|
||||
|
||||
private:
|
||||
|
@ -80,7 +81,7 @@ class TerminalIO : public actor::Actor {
|
|||
static void output(td::Slice slice);
|
||||
static void output_stderr(std::string line);
|
||||
static void output_stderr(td::Slice slice);
|
||||
static void output_stdout(td::Slice line);
|
||||
static void output_stdout(td::Slice line, double max_wait);
|
||||
static TerminalIOOutputter out() {
|
||||
return TerminalIOOutputter{false};
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ ton.blockId workchain:int32 shard:int64 seqno:int32 = internal.BlockId;
|
|||
ton.blockIdExt workchain:int32 shard:int64 seqno:int32 root_hash:bytes file_hash:bytes = ton.BlockIdExt;
|
||||
|
||||
raw.fullAccountState balance:int64 code:bytes data:bytes last_transaction_id:internal.transactionId block_id:ton.blockIdExt frozen_hash:bytes sync_utime:int53 = raw.FullAccountState;
|
||||
raw.message source:string destination:string value:int64 fwd_fee:int64 ihr_fee:int64 created_lt:int64 body_hash:bytes message:bytes is_message_encrypted:Bool = raw.Message;
|
||||
raw.message source:string destination:string value:int64 fwd_fee:int64 ihr_fee:int64 created_lt:int64 body_hash:bytes msg_data:msg.Data = raw.Message;
|
||||
raw.transaction utime:int53 data:bytes transaction_id:internal.transactionId fee:int64 storage_fee:int64 other_fee:int64 in_msg:raw.message out_msgs:vector<raw.message> = raw.Transaction;
|
||||
raw.transactions transactions:vector<raw.transaction> previous_transaction_id:internal.transactionId = raw.Transactions;
|
||||
|
||||
|
@ -83,8 +83,13 @@ syncStateInProgress from_seqno:int32 to_seqno:int32 current_seqno:int32 = SyncSt
|
|||
// MSG
|
||||
//
|
||||
|
||||
msg.dataText text:string = msg.Data;
|
||||
msg.dataEncryptedText text:string = msg.Data;
|
||||
msg.dataRaw body:bytes = msg.Data;
|
||||
msg.dataText text:bytes = msg.Data;
|
||||
msg.dataDecryptedText text:bytes = msg.Data;
|
||||
msg.dataEncryptedText text:bytes = msg.Data;
|
||||
|
||||
msg.dataArray elements:vector<msg.Data> = msg.DataArray;
|
||||
|
||||
msg.message destination:accountAddress amount:int64 data:msg.Data = msg.Message;
|
||||
|
||||
//
|
||||
|
@ -111,7 +116,7 @@ dns.resolved entries:vector<dns.entry> = dns.Resolved;
|
|||
//
|
||||
|
||||
actionNoop = Action;
|
||||
actionMsg messages:vector<msg.Message> allow_send_to_uninited:Bool = Action;
|
||||
actionMsg messages:vector<msg.message> allow_send_to_uninited:Bool = Action;
|
||||
actionDns actions:vector<dns.Action> = Action;
|
||||
//actionMultisig actions:vector<multisig.order> = Action;
|
||||
|
||||
|
@ -205,11 +210,14 @@ sync = ton.BlockIdExt;
|
|||
|
||||
// revision = 0 -- use default revision
|
||||
// revision = x (x > 0) -- use revision x
|
||||
// revision = -1 -- use experimental (newest) revision. Only for debug purpose
|
||||
getAccountAddress initial_account_state:InitialAccountState revision:int32 = AccountAddress;
|
||||
guessAccountRevision initial_account_state:InitialAccountState = AccountRevisionList;
|
||||
getAccountState account_address:accountAddress = FullAccountState;
|
||||
createQuery private_key:InputKey address:accountAddress timeout:int32 action:Action = query.Info;
|
||||
|
||||
msg.decrypt input_key:InputKey data:msg.dataArray = msg.DataArray;
|
||||
|
||||
query.send id:int53 = Ok;
|
||||
query.forget id:int53 = Ok;
|
||||
query.estimateFees id:int53 ignore_chksig:Bool = query.Fees;
|
||||
|
|
Binary file not shown.
|
@ -35,6 +35,7 @@
|
|||
#include "td/utils/benchmark.h"
|
||||
#include "td/utils/filesystem.h"
|
||||
#include "td/utils/optional.h"
|
||||
#include "td/utils/overloaded.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/PathView.h"
|
||||
#include "td/utils/tests.h"
|
||||
|
@ -70,7 +71,7 @@ TEST(Tonlib, Text) {
|
|||
auto cs = vm::load_cell_slice(cb.finalize());
|
||||
auto cs2 = cs;
|
||||
cs.print_rec(std::cerr);
|
||||
CHECK(block::gen::t_Text.validate_exact(cs2));
|
||||
CHECK(block::gen::t_Text.validate_exact_upto(1024, cs2));
|
||||
auto got_str = vm::CellText::load(cs).move_as_ok();
|
||||
ASSERT_EQ(str, got_str);
|
||||
}
|
||||
|
@ -506,12 +507,32 @@ TEST(Tonlib, KeysApi) {
|
|||
sync_send(client, make_object<tonlib_api::deleteKey>(
|
||||
make_object<tonlib_api::key>(new_imported_key->public_key_, new_imported_key->secret_.copy())))
|
||||
.move_as_ok();
|
||||
td::Ed25519::PrivateKey pkey(exported_raw_key->data_.copy());
|
||||
auto raw_imported_key = sync_send(client, make_object<tonlib_api::importUnencryptedKey>(new_local_password.copy(),
|
||||
std::move(exported_raw_key)))
|
||||
.move_as_ok();
|
||||
|
||||
CHECK(raw_imported_key->public_key_ == key->public_key_);
|
||||
CHECK(raw_imported_key->secret_ != key->secret_);
|
||||
|
||||
auto other_public_key = td::Ed25519::generate_private_key().move_as_ok().get_public_key().move_as_ok();
|
||||
std::string text = "hello world";
|
||||
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::msg_Data>> elements;
|
||||
elements.push_back(make_object<tonlib_api::msg_dataEncryptedText>(
|
||||
SimpleEncryptionV2::encrypt_data(text, other_public_key, pkey).move_as_ok().as_slice().str()));
|
||||
|
||||
auto decrypted =
|
||||
sync_send(client, make_object<tonlib_api::msg_decrypt>(
|
||||
make_object<tonlib_api::inputKeyRegular>(
|
||||
make_object<tonlib_api::key>(key->public_key_, raw_imported_key->secret_.copy()),
|
||||
new_local_password.copy()),
|
||||
make_object<tonlib_api::msg_dataArray>(std::move(elements))))
|
||||
.move_as_ok();
|
||||
|
||||
downcast_call(*decrypted->elements_[0],
|
||||
td::overloaded([](auto &) { UNREACHABLE(); },
|
||||
[&](tonlib_api::msg_dataDecryptedText &decrypted) { CHECK(decrypted.text_ == text); }));
|
||||
}
|
||||
|
||||
TEST(Tonlib, ConfigCache) {
|
||||
|
|
|
@ -234,7 +234,7 @@ td::Result<QueryId> create_send_grams_query(Client& client, const Wallet& source
|
|||
std::vector<tonlib_api::object_ptr<tonlib_api::msg_message>> msgs;
|
||||
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
|
||||
if (encrypted) {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataEncryptedText>(std::move(message));
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(std::move(message));
|
||||
} else {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataText>(std::move(message));
|
||||
}
|
||||
|
@ -310,6 +310,13 @@ td::Result<tonlib_api::object_ptr<tonlib_api::raw_transactions>> get_transaction
|
|||
return std::move(got_transactions);
|
||||
}
|
||||
|
||||
std::string read_text(tonlib_api::msg_Data& data) {
|
||||
std::string text;
|
||||
downcast_call(data, td::overloaded([](auto& other) {}, [&](tonlib_api::msg_dataText& data) { text = data.text_; },
|
||||
[&](tonlib_api::msg_dataDecryptedText& data) { text = data.text_; }));
|
||||
return text;
|
||||
}
|
||||
|
||||
td::Status transfer_grams(Client& client, const Wallet& wallet, std::string address, td::int64 amount,
|
||||
bool fast = false) {
|
||||
auto src_state = get_account_state(client, wallet.address);
|
||||
|
@ -320,7 +327,7 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
|
|||
bool encrypt = true;
|
||||
auto r_query_id = create_send_grams_query(client, wallet, address, amount, encrypt, message, fast);
|
||||
if (r_query_id.is_error()) {
|
||||
LOG(INFO) << "Send query WITHOUT message encryption";
|
||||
LOG(INFO) << "Send query WITHOUT message encryption " << r_query_id.error();
|
||||
encrypt = false;
|
||||
r_query_id = create_send_grams_query(client, wallet, address, amount, encrypt, message, fast);
|
||||
} else {
|
||||
|
@ -363,7 +370,7 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
|
|||
const auto& txn = tr->transactions_[0];
|
||||
CHECK(txn->in_msg_->body_hash_ == query_info.body_hash);
|
||||
ASSERT_EQ(1u, txn->out_msgs_.size());
|
||||
ASSERT_EQ(message, txn->out_msgs_[0]->message_);
|
||||
ASSERT_EQ(message, read_text(*txn->out_msgs_[0]->msg_data_));
|
||||
lt = txn->out_msgs_[0]->created_lt_;
|
||||
auto fee_difference = fees.first.sum() - txn->fee_;
|
||||
first_fee = txn->fee_;
|
||||
|
@ -389,7 +396,7 @@ td::Status transfer_grams(Client& client, const Wallet& wallet, std::string addr
|
|||
}
|
||||
ASSERT_EQ(new_src_state.address, txn->in_msg_->source_);
|
||||
if (!encrypt) {
|
||||
ASSERT_EQ(message, txn->in_msg_->message_);
|
||||
ASSERT_EQ(message, read_text(*txn->in_msg_->msg_data_));
|
||||
}
|
||||
auto fee_difference = fees.second.sum() - txn->fee_;
|
||||
auto desc = PSTRING() << fee_difference << " storage:[" << fees.second.storage_fee << " vs " << txn->storage_fee_
|
||||
|
@ -550,19 +557,11 @@ void test_multisig(Client& client, const Wallet& giver_wallet) {
|
|||
void dns_resolve(Client& client, const Wallet& dns, std::string name) {
|
||||
using namespace ton::tonlib_api;
|
||||
auto address = dns.get_address();
|
||||
while (true) {
|
||||
auto resolved =
|
||||
sync_send(client, make_object<::ton::tonlib_api::dns_resolve>(std::move(address), name, 1, 0)).move_as_ok();
|
||||
CHECK(resolved->entries_.size() == 1);
|
||||
LOG(INFO) << to_string(resolved);
|
||||
if (resolved->entries_[0]->category_ == -1) {
|
||||
auto entry = ton::move_tl_object_as<dns_entryDataNextResolver>(resolved->entries_[0]->entry_);
|
||||
address = std::move(entry->resolver_);
|
||||
continue;
|
||||
}
|
||||
LOG(INFO) << "OK";
|
||||
break;
|
||||
}
|
||||
auto resolved =
|
||||
sync_send(client, make_object<::ton::tonlib_api::dns_resolve>(std::move(address), name, 1, 4)).move_as_ok();
|
||||
CHECK(resolved->entries_.size() == 1);
|
||||
LOG(INFO) << to_string(resolved);
|
||||
LOG(INFO) << "OK";
|
||||
}
|
||||
|
||||
void test_dns(Client& client, const Wallet& giver_wallet) {
|
||||
|
@ -580,10 +579,10 @@ void test_dns(Client& client, const Wallet& giver_wallet) {
|
|||
make_object<dns_entry>("A", -1, make_object<dns_entryDataNextResolver>(A_B.get_address()))));
|
||||
auto init_A = create_update_dns_query(client, A, std::move(actions)).move_as_ok();
|
||||
actions.push_back(make_object<dns_actionSet>(
|
||||
make_object<dns_entry>("B.A", -1, make_object<dns_entryDataNextResolver>(A_B_C.get_address()))));
|
||||
make_object<dns_entry>("B", -1, make_object<dns_entryDataNextResolver>(A_B_C.get_address()))));
|
||||
auto init_A_B = create_update_dns_query(client, A_B, std::move(actions)).move_as_ok();
|
||||
actions.push_back(
|
||||
make_object<dns_actionSet>(make_object<dns_entry>("C.B.A", 1, make_object<dns_entryDataText>("Hello dns"))));
|
||||
make_object<dns_actionSet>(make_object<dns_entry>("C", 1, make_object<dns_entryDataText>("Hello dns"))));
|
||||
auto init_A_B_C = create_update_dns_query(client, A_B_C, std::move(actions)).move_as_ok();
|
||||
|
||||
LOG(INFO) << "Send dns init queries";
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "KeyValue.h"
|
||||
|
||||
#include "td/utils/filesystem.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include "td/utils/SharedSlice.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
|
|
@ -63,6 +63,24 @@ struct GetAccountState {
|
|||
td::optional<ton::BlockIdExt> block_id;
|
||||
using ReturnType = td::unique_ptr<AccountState>;
|
||||
};
|
||||
|
||||
struct RemoteRunSmcMethod {
|
||||
block::StdAddress address;
|
||||
td::optional<ton::BlockIdExt> block_id;
|
||||
ton::SmartContract::Args args;
|
||||
bool need_result{false};
|
||||
|
||||
using ReturnType = RemoteRunSmcMethodReturnType;
|
||||
};
|
||||
|
||||
struct RemoteRunSmcMethodReturnType {
|
||||
ton::SmartContract::State smc_state;
|
||||
ton::BlockIdExt block_id;
|
||||
// result
|
||||
// c7
|
||||
// libs
|
||||
};
|
||||
|
||||
struct GetPrivateKey {
|
||||
KeyStorage::InputKey input_key;
|
||||
using ReturnType = KeyStorage::PrivateKey;
|
||||
|
@ -120,6 +138,16 @@ static block::AccountState create_account_state(ton::tl_object_ptr<ton::lite_api
|
|||
res.state = std::move(from->state_);
|
||||
return res;
|
||||
}
|
||||
static block::AccountState create_account_state(ton::tl_object_ptr<ton::lite_api::liteServer_runMethodResult>& from) {
|
||||
block::AccountState res;
|
||||
res.blk = ton::create_block_id(from->id_);
|
||||
res.shard_blk = ton::create_block_id(from->shardblk_);
|
||||
res.shard_proof = std::move(from->shard_proof_);
|
||||
res.proof = std::move(from->proof_);
|
||||
res.state = std::move(from->state_proof_);
|
||||
res.is_virtualized = from->mode_ > 0;
|
||||
return res;
|
||||
}
|
||||
struct RawAccountState {
|
||||
td::int64 balance = -1;
|
||||
|
||||
|
@ -373,7 +401,6 @@ class AccountState {
|
|||
if (o_revision) {
|
||||
wallet_type_ = WalletType::WalletV3;
|
||||
wallet_revision_ = o_revision.value();
|
||||
LOG(ERROR) << "!!!" << wallet_revision_;
|
||||
set_new_state({ton::WalletV3::get_init_code(wallet_revision_), ton::WalletV3::get_init_data(key, wallet_id_)});
|
||||
return wallet_type_;
|
||||
}
|
||||
|
@ -381,7 +408,6 @@ class AccountState {
|
|||
if (o_revision) {
|
||||
wallet_type_ = WalletType::HighloadWalletV2;
|
||||
wallet_revision_ = o_revision.value();
|
||||
LOG(ERROR) << "!!!" << wallet_revision_;
|
||||
set_new_state(
|
||||
{ton::HighloadWalletV2::get_init_code(wallet_revision_), ton::WalletV3::get_init_data(key, wallet_id_)});
|
||||
return wallet_type_;
|
||||
|
@ -390,7 +416,6 @@ class AccountState {
|
|||
if (o_revision) {
|
||||
wallet_type_ = WalletType::ManualDns;
|
||||
wallet_revision_ = o_revision.value();
|
||||
LOG(ERROR) << "!!!" << wallet_revision_;
|
||||
auto dns = ton::ManualDns::create(key, wallet_id_, wallet_revision_);
|
||||
set_new_state(dns->get_state());
|
||||
return wallet_type_;
|
||||
|
@ -841,6 +866,119 @@ class GetTransactionHistory : public td::actor::Actor {
|
|||
}
|
||||
};
|
||||
|
||||
class RemoteRunSmcMethod : public td::actor::Actor {
|
||||
public:
|
||||
RemoteRunSmcMethod(ExtClientRef ext_client_ref, int_api::RemoteRunSmcMethod query, td::actor::ActorShared<> parent,
|
||||
td::Promise<int_api::RemoteRunSmcMethod::ReturnType>&& promise)
|
||||
: query_(std::move(query)), promise_(std::move(promise)), parent_(std::move(parent)) {
|
||||
client_.set_client(ext_client_ref);
|
||||
}
|
||||
|
||||
private:
|
||||
int_api::RemoteRunSmcMethod query_;
|
||||
td::Promise<int_api::RemoteRunSmcMethod::ReturnType> promise_;
|
||||
td::actor::ActorShared<> parent_;
|
||||
ExtClient client_;
|
||||
|
||||
void with_run_method_result(
|
||||
td::Result<ton::tl_object_ptr<ton::lite_api::liteServer_runMethodResult>> r_run_method_result) {
|
||||
check(do_with_run_method_result(std::move(r_run_method_result)));
|
||||
}
|
||||
|
||||
td::Status do_with_run_method_result(
|
||||
td::Result<ton::tl_object_ptr<ton::lite_api::liteServer_runMethodResult>> r_run_method_result) {
|
||||
TRY_RESULT(run_method_result, std::move(r_run_method_result));
|
||||
TRY_RESULT_PREFIX(state, TRY_VM(do_with_run_method_result(std::move(run_method_result))),
|
||||
TonlibError::ValidateAccountState());
|
||||
promise_.set_value(std::move(state));
|
||||
stop();
|
||||
return td::Status::OK();
|
||||
}
|
||||
td::Result<int_api::RemoteRunSmcMethod::ReturnType> do_with_run_method_result(
|
||||
ton::tl_object_ptr<ton::lite_api::liteServer_runMethodResult> run_method_result) {
|
||||
auto account_state = create_account_state(run_method_result);
|
||||
TRY_RESULT(info, account_state.validate(query_.block_id.value(), query_.address));
|
||||
auto serialized_state = account_state.state.clone();
|
||||
int_api::RemoteRunSmcMethod::ReturnType res;
|
||||
res.block_id = query_.block_id.value();
|
||||
auto cell = info.root;
|
||||
if (cell.is_null()) {
|
||||
return res;
|
||||
}
|
||||
block::gen::Account::Record_account account;
|
||||
if (!tlb::unpack_cell(cell, account)) {
|
||||
return td::Status::Error("Failed to unpack Account");
|
||||
}
|
||||
|
||||
block::gen::AccountStorage::Record storage;
|
||||
if (!tlb::csr_unpack(account.storage, storage)) {
|
||||
return td::Status::Error("Failed to unpack AccountStorage");
|
||||
}
|
||||
auto state_tag = block::gen::t_AccountState.get_tag(*storage.state);
|
||||
if (state_tag < 0) {
|
||||
return td::Status::Error("Failed to parse AccountState tag");
|
||||
}
|
||||
if (state_tag != block::gen::AccountState::account_active) {
|
||||
return td::Status::Error("Account is not active");
|
||||
}
|
||||
block::gen::AccountState::Record_account_active state;
|
||||
if (!tlb::csr_unpack(storage.state, state)) {
|
||||
return td::Status::Error("Failed to parse AccountState");
|
||||
}
|
||||
block::gen::StateInit::Record state_init;
|
||||
if (!tlb::csr_unpack(state.x, state_init)) {
|
||||
return td::Status::Error("Failed to parse StateInit");
|
||||
}
|
||||
state_init.code->prefetch_maybe_ref(res.smc_state.code);
|
||||
state_init.data->prefetch_maybe_ref(res.smc_state.data);
|
||||
return res;
|
||||
}
|
||||
|
||||
void with_last_block(td::Result<LastBlockState> r_last_block) {
|
||||
check(do_with_last_block(std::move(r_last_block)));
|
||||
}
|
||||
|
||||
td::Status with_block_id() {
|
||||
TRY_RESULT(method_id, query_.args.get_method_id());
|
||||
TRY_RESULT(serialized_stack, query_.args.get_serialized_stack());
|
||||
client_.send_query(
|
||||
//liteServer.runSmcMethod mode:# id:tonNode.blockIdExt account:liteServer.accountId method_id:long params:bytes = liteServer.RunMethodResult;
|
||||
ton::lite_api::liteServer_runSmcMethod(
|
||||
0x1f, ton::create_tl_lite_block_id(query_.block_id.value()),
|
||||
ton::create_tl_object<ton::lite_api::liteServer_accountId>(query_.address.workchain, query_.address.addr),
|
||||
method_id, std::move(serialized_stack)),
|
||||
[self = this](auto r_state) { self->with_run_method_result(std::move(r_state)); },
|
||||
query_.block_id.value().id.seqno);
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status do_with_last_block(td::Result<LastBlockState> r_last_block) {
|
||||
TRY_RESULT(last_block, std::move(r_last_block));
|
||||
query_.block_id = std::move(last_block.last_block_id);
|
||||
with_block_id();
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
void start_up() override {
|
||||
if (query_.block_id) {
|
||||
check(with_block_id());
|
||||
} else {
|
||||
client_.with_last_block(
|
||||
[self = this](td::Result<LastBlockState> r_last_block) { self->with_last_block(std::move(r_last_block)); });
|
||||
}
|
||||
}
|
||||
|
||||
void check(td::Status status) {
|
||||
if (status.is_error()) {
|
||||
promise_.set_error(std::move(status));
|
||||
stop();
|
||||
}
|
||||
}
|
||||
void hangup() override {
|
||||
check(TonlibError::Cancelled());
|
||||
}
|
||||
};
|
||||
|
||||
class GetRawAccountState : public td::actor::Actor {
|
||||
public:
|
||||
GetRawAccountState(ExtClientRef ext_client_ref, block::StdAddress address, td::optional<ton::BlockIdExt> block_id,
|
||||
|
@ -882,8 +1020,8 @@ class GetRawAccountState : public td::actor::Actor {
|
|||
res.block_id = block_id_.value();
|
||||
res.info = std::move(info);
|
||||
auto cell = res.info.root;
|
||||
std::ostringstream outp;
|
||||
block::gen::t_Account.print_ref(outp, cell);
|
||||
//std::ostringstream outp;
|
||||
//block::gen::t_Account.print_ref(outp, cell);
|
||||
//LOG(INFO) << outp.str();
|
||||
if (cell.is_null()) {
|
||||
return res;
|
||||
|
@ -1693,6 +1831,50 @@ struct ToRawTransactions {
|
|||
return td::Status::Error("Failed to unpack Message");
|
||||
}
|
||||
|
||||
td::Ref<vm::CellSlice> body;
|
||||
if (message.body->prefetch_long(1) == 0) {
|
||||
body = std::move(message.body);
|
||||
body.write().advance(1);
|
||||
} else {
|
||||
body = vm::load_cell_slice_ref(message.body->prefetch_ref());
|
||||
}
|
||||
auto body_cell = vm::CellBuilder().append_cellslice(*body).finalize();
|
||||
auto body_hash = body_cell->get_hash().as_slice().str();
|
||||
|
||||
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
|
||||
if (body->size() >= 32 && static_cast<td::uint32>(body->prefetch_long(32)) <= 1) {
|
||||
auto type = body.write().fetch_long(32);
|
||||
td::Status status;
|
||||
|
||||
auto r_body_message = vm::CellString::load(body.write());
|
||||
LOG_IF(WARNING, r_body_message.is_error()) << "Failed to parse a message: " << r_body_message.error();
|
||||
|
||||
if (r_body_message.is_ok()) {
|
||||
if (type == 0) {
|
||||
LOG(ERROR) << "OK " << r_body_message.ok();
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataText>(r_body_message.move_as_ok());
|
||||
} else {
|
||||
LOG(ERROR) << "TRY DECRYPT";
|
||||
auto encrypted_message = r_body_message.move_as_ok();
|
||||
auto r_decrypted_message = [&]() -> td::Result<std::string> {
|
||||
if (!private_key_) {
|
||||
return TonlibError::EmptyField("private_key");
|
||||
}
|
||||
TRY_RESULT(decrypted, SimpleEncryptionV2::decrypt_data(encrypted_message, private_key_.value()));
|
||||
return decrypted.as_slice().str();
|
||||
}();
|
||||
if (r_decrypted_message.is_ok()) {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(r_decrypted_message.move_as_ok());
|
||||
} else {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataEncryptedText>(encrypted_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!data) {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataRaw>(to_bytes(std::move(body_cell)));
|
||||
}
|
||||
|
||||
auto tag = block::gen::CommonMsgInfo().get_tag(*message.info);
|
||||
if (tag < 0) {
|
||||
return td::Status::Error("Failed to read CommonMsgInfo tag");
|
||||
|
@ -1710,41 +1892,10 @@ struct ToRawTransactions {
|
|||
TRY_RESULT(fwd_fee, to_balance(msg_info.fwd_fee));
|
||||
TRY_RESULT(ihr_fee, to_balance(msg_info.ihr_fee));
|
||||
auto created_lt = static_cast<td::int64>(msg_info.created_lt);
|
||||
td::Ref<vm::CellSlice> body;
|
||||
if (message.body->prefetch_long(1) == 0) {
|
||||
body = std::move(message.body);
|
||||
body.write().advance(1);
|
||||
} else {
|
||||
body = vm::load_cell_slice_ref(message.body->prefetch_ref());
|
||||
}
|
||||
auto body_hash = vm::CellBuilder().append_cellslice(*body).finalize()->get_hash().as_slice().str();
|
||||
std::string body_message;
|
||||
bool is_encrypted = false;
|
||||
if (body->size() >= 32 && body->prefetch_long(32) <= 1) {
|
||||
auto type = body.write().fetch_long(32);
|
||||
auto r_body_message = vm::CellString::load(body.write());
|
||||
if (type == 1) {
|
||||
LOG(ERROR) << "TRY DECRYPT";
|
||||
r_body_message = [&]() -> td::Result<std::string> {
|
||||
TRY_RESULT(message, std::move(r_body_message));
|
||||
if (!private_key_) {
|
||||
return TonlibError::EmptyField("private_key");
|
||||
}
|
||||
TRY_RESULT(decrypted, SimpleEncryptionV2::decrypt_data(message, private_key_.value()));
|
||||
is_encrypted = true;
|
||||
return decrypted.as_slice().str();
|
||||
}();
|
||||
}
|
||||
if (r_body_message.is_ok()) {
|
||||
body_message = r_body_message.move_as_ok();
|
||||
} else {
|
||||
LOG(WARNING) << "Failed to parse a message: " << r_body_message.error();
|
||||
}
|
||||
}
|
||||
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), std::move(dest), balance, fwd_fee,
|
||||
ihr_fee, created_lt, std::move(body_hash),
|
||||
std::move(body_message), is_encrypted);
|
||||
std::move(data));
|
||||
}
|
||||
case block::gen::CommonMsgInfo::ext_in_msg_info: {
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info;
|
||||
|
@ -1752,16 +1903,8 @@ struct ToRawTransactions {
|
|||
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_in_msg_info");
|
||||
}
|
||||
TRY_RESULT(dest, to_std_address(msg_info.dest));
|
||||
td::Ref<vm::CellSlice> body;
|
||||
if (message.body->prefetch_long(1) == 0) {
|
||||
body = std::move(message.body);
|
||||
body.write().advance(1);
|
||||
} else {
|
||||
body = vm::load_cell_slice_ref(message.body->prefetch_ref());
|
||||
}
|
||||
auto body_hash = vm::CellBuilder().append_cellslice(*body).finalize()->get_hash().as_slice().str();
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>("", std::move(dest), 0, 0, 0, 0, std::move(body_hash),
|
||||
"", false);
|
||||
std::move(data));
|
||||
}
|
||||
case block::gen::CommonMsgInfo::ext_out_msg_info: {
|
||||
block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info;
|
||||
|
@ -1769,7 +1912,8 @@ struct ToRawTransactions {
|
|||
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info");
|
||||
}
|
||||
TRY_RESULT(src, to_std_address(msg_info.src));
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), "", 0, 0, 0, 0, "", "", false);
|
||||
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), "", 0, 0, 0, 0, std::move(body_hash),
|
||||
std::move(data));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2027,8 +2171,12 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
struct Action {
|
||||
block::StdAddress destination;
|
||||
td::int64 amount;
|
||||
|
||||
bool is_encrypted{false};
|
||||
bool should_encrypt;
|
||||
std::string message;
|
||||
|
||||
td::Ref<vm::Cell> body;
|
||||
};
|
||||
bool allow_send_to_uninited_{false};
|
||||
std::vector<Action> actions_;
|
||||
|
@ -2064,27 +2212,36 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
res.amount = message.amount_;
|
||||
auto status =
|
||||
downcast_call2<td::Status>(*message.data_, td::overloaded(
|
||||
[&](tonlib_api::msg_dataText& text) {
|
||||
// Use this limit as a preventive check
|
||||
if (text.text_.size() > ton::Wallet::max_message_size) {
|
||||
return TonlibError::MessageTooLong();
|
||||
}
|
||||
res.message = text.text_;
|
||||
res.should_encrypt = false;
|
||||
[&](tonlib_api::msg_dataRaw& text) {
|
||||
TRY_RESULT(body, vm::std_boc_deserialize(text.body_));
|
||||
res.body = std::move(body);
|
||||
return td::Status::OK();
|
||||
},
|
||||
[&](tonlib_api::msg_dataEncryptedText& text) {
|
||||
// Use this limit as a preventive check
|
||||
if (text.text_.size() > ton::Wallet::max_message_size) {
|
||||
return TonlibError::MessageTooLong();
|
||||
}
|
||||
[&](tonlib_api::msg_dataText& text) {
|
||||
res.message = text.text_;
|
||||
res.should_encrypt = false;
|
||||
res.is_encrypted = false;
|
||||
return td::Status::OK();
|
||||
},
|
||||
[&](tonlib_api::msg_dataDecryptedText& text) {
|
||||
res.message = text.text_;
|
||||
if (!has_private_key_) {
|
||||
return TonlibError::EmptyField("input_key");
|
||||
}
|
||||
res.should_encrypt = true;
|
||||
res.is_encrypted = true;
|
||||
return td::Status::OK();
|
||||
},
|
||||
[&](tonlib_api::msg_dataEncryptedText& text) {
|
||||
res.message = text.text_;
|
||||
res.should_encrypt = false;
|
||||
res.is_encrypted = true;
|
||||
return td::Status::OK();
|
||||
}));
|
||||
// Use this limit as a preventive check
|
||||
if (res.message.size() > ton::Wallet::max_message_size) {
|
||||
return TonlibError::MessageTooLong();
|
||||
}
|
||||
TRY_STATUS(std::move(status));
|
||||
return res;
|
||||
}
|
||||
|
@ -2301,7 +2458,9 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
if (action.amount == source_->get_balance()) {
|
||||
gift.gramms = -1;
|
||||
}
|
||||
if (action.should_encrypt) {
|
||||
if (action.body.not_null()) {
|
||||
gift.body = action.body;
|
||||
} else if (action.should_encrypt) {
|
||||
LOG(ERROR) << "TRY ENCRYPT";
|
||||
if (!private_key_) {
|
||||
return TonlibError::EmptyField("private_key");
|
||||
|
@ -2311,7 +2470,8 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
}
|
||||
auto wallet = destination->get_wallet();
|
||||
TRY_RESULT_PREFIX(public_key, wallet->get_public_key(),
|
||||
TonlibError::AccountActionUnsupported("Get public key (in destination)"));
|
||||
TonlibError::AccountActionUnsupported(PSLICE() << "Get public key (in destination) : "
|
||||
<< destination->get_wallet_type()));
|
||||
TRY_RESULT_PREFIX(encrypted_message,
|
||||
SimpleEncryptionV2::encrypt_data(action.message, public_key, private_key_.value()),
|
||||
TonlibError::Internal());
|
||||
|
@ -2319,7 +2479,7 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
gift.is_encrypted = true;
|
||||
} else {
|
||||
gift.message = action.message;
|
||||
gift.is_encrypted = false;
|
||||
gift.is_encrypted = action.is_encrypted;
|
||||
}
|
||||
i++;
|
||||
gifts.push_back(gift);
|
||||
|
@ -2349,7 +2509,7 @@ class GenericCreateSendGrams : public TonlibQueryActor {
|
|||
|
||||
if (source_->get_wallet_type() == AccountState::Giver) {
|
||||
valid_until = 0;
|
||||
private_key_ = td::Ed25519::PrivateKey(td::SecureString(std::string('\0', 32)));
|
||||
private_key_ = td::Ed25519::PrivateKey(td::SecureString(std::string(32, '\0')));
|
||||
}
|
||||
|
||||
return with_wallet(*source_->get_wallet());
|
||||
|
@ -2387,6 +2547,40 @@ td::Status TonlibClient::do_request(tonlib_api::createQuery& request,
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(tonlib_api::msg_decrypt& request,
|
||||
td::Promise<object_ptr<tonlib_api::msg_dataArray>>&& promise) {
|
||||
if (!request.input_key_) {
|
||||
return TonlibError::EmptyField("input_key");
|
||||
}
|
||||
if (!request.data_) {
|
||||
return TonlibError::EmptyField("data");
|
||||
}
|
||||
TRY_RESULT(input_key, from_tonlib(*request.input_key_));
|
||||
make_request(
|
||||
int_api::GetPrivateKey{std::move(input_key)},
|
||||
promise.wrap([elements = std::move(request.data_)](auto key) mutable {
|
||||
auto private_key = td::Ed25519::PrivateKey(std::move(key.private_key));
|
||||
elements->elements_ = td::transform(std::move(elements->elements_), [&private_key](auto msg) {
|
||||
if (!msg) {
|
||||
return std::move(msg);
|
||||
}
|
||||
using ReturnType = tonlib_api::object_ptr<tonlib_api::msg_Data>;
|
||||
return downcast_call2<ReturnType>(
|
||||
*msg, td::overloaded([&msg](auto&) { return std::move(msg); },
|
||||
[&msg, &private_key](tonlib_api::msg_dataEncryptedText& encrypted) -> ReturnType {
|
||||
auto r_decrypted = SimpleEncryptionV2::decrypt_data(encrypted.text_, private_key);
|
||||
if (r_decrypted.is_error()) {
|
||||
return std::move(msg);
|
||||
}
|
||||
return tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(
|
||||
r_decrypted.move_as_ok().as_slice().str());
|
||||
}));
|
||||
});
|
||||
return std::move(elements);
|
||||
}));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::raw_createQuery& request,
|
||||
td::Promise<object_ptr<tonlib_api::query_info>>&& promise) {
|
||||
if (!request.destination_) {
|
||||
|
@ -2698,19 +2892,32 @@ td::Result<tonlib_api::object_ptr<tonlib_api::dns_EntryData>> to_tonlib_api(
|
|||
}
|
||||
|
||||
void TonlibClient::finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl,
|
||||
td::optional<ton::BlockIdExt> block_id, td::unique_ptr<AccountState> smc,
|
||||
td::optional<ton::BlockIdExt> block_id, DnsFinishData dns_finish_data,
|
||||
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
|
||||
if (smc->get_wallet_type() != AccountState::WalletType::ManualDns) {
|
||||
return promise.set_error(TonlibError::AccountTypeUnexpected("ManualDns"));
|
||||
}
|
||||
block_id = smc->get_block_id();
|
||||
auto dns = ton::ManualDns::create(smc->get_smc_state());
|
||||
block_id = dns_finish_data.block_id;
|
||||
// TODO: check if the smartcontract supports Dns interface
|
||||
// TODO: should we use some DnsInterface instead of ManualDns?
|
||||
auto dns = ton::ManualDns::create(dns_finish_data.smc_state);
|
||||
TRY_RESULT_PROMISE(promise, entries, dns->resolve(name, category));
|
||||
|
||||
if (entries.size() == 1 && entries[0].category == -1 && entries[0].name != name && ttl > 0 &&
|
||||
entries[0].data.type == ton::ManualDns::EntryData::Type::NextResolver) {
|
||||
td::Slice got_name = entries[0].name;
|
||||
if (got_name.size() >= name.size()) {
|
||||
TRY_STATUS_PROMISE(promise, TonlibError::Internal("domain is too long"));
|
||||
}
|
||||
auto dot_position = name.size() - got_name.size() - 1;
|
||||
auto suffix = name.substr(dot_position + 1);
|
||||
auto prefix = name.substr(0, dot_position);
|
||||
if (name[dot_position] != '.') {
|
||||
TRY_STATUS_PROMISE(promise, td::Status::Error("next resolver error: domain split not at a component boundary "));
|
||||
}
|
||||
if (suffix != got_name) {
|
||||
TRY_STATUS_PROMISE(promise, TonlibError::Internal("domain is not a suffix of the query"));
|
||||
}
|
||||
|
||||
auto address = entries[0].data.data.get<ton::ManualDns::EntryDataNextResolver>().resolver;
|
||||
return do_dns_request(name, category, ttl - 1, std::move(block_id), address, std::move(promise));
|
||||
return do_dns_request(prefix, category, ttl - 1, std::move(block_id), address, std::move(promise));
|
||||
}
|
||||
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::dns_entry>> api_entries;
|
||||
|
@ -2726,9 +2933,29 @@ void TonlibClient::do_dns_request(std::string name, td::int32 category, td::int3
|
|||
td::optional<ton::BlockIdExt> block_id, block::StdAddress address,
|
||||
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
|
||||
auto block_id_copy = block_id.copy();
|
||||
make_request(int_api::GetAccountState{address, std::move(block_id_copy)},
|
||||
promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name, category, ttl,
|
||||
std::move(block_id)));
|
||||
td::Promise<DnsFinishData> new_promise =
|
||||
promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name, category, ttl, std::move(block_id));
|
||||
|
||||
if (0) {
|
||||
make_request(int_api::GetAccountState{address, std::move(block_id_copy)},
|
||||
new_promise.wrap([](auto&& account_state) {
|
||||
return DnsFinishData{account_state->get_block_id(), account_state->get_smc_state()};
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
TRY_RESULT_PROMISE(promise, args, ton::DnsInterface::resolve_args(name, category));
|
||||
int_api::RemoteRunSmcMethod query;
|
||||
query.address = std::move(address);
|
||||
query.args = std::move(args);
|
||||
query.block_id = std::move(block_id_copy);
|
||||
query.need_result = false;
|
||||
|
||||
make_request(std::move(query), new_promise.wrap([](auto&& run_method) {
|
||||
return DnsFinishData{run_method.block_id, run_method.smc_state};
|
||||
}));
|
||||
;
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(const tonlib_api::dns_resolve& request,
|
||||
|
@ -3015,6 +3242,14 @@ td::Status TonlibClient::do_request(int_api::GetAccountState request,
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(int_api::RemoteRunSmcMethod request,
|
||||
td::Promise<int_api::RemoteRunSmcMethod::ReturnType>&& promise) {
|
||||
auto actor_id = actor_id_++;
|
||||
actors_[actor_id] = td::actor::create_actor<RemoteRunSmcMethod>(
|
||||
"RemoteRunSmcMethod", client_.get_client(), std::move(request), actor_shared(this, actor_id), std::move(promise));
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(int_api::GetPrivateKey request, td::Promise<KeyStorage::PrivateKey>&& promise) {
|
||||
TRY_RESULT(pk, key_storage_.load_private_key(std::move(request.input_key)));
|
||||
promise.set_value(std::move(pk));
|
||||
|
|
|
@ -42,6 +42,9 @@ struct GetAccountState;
|
|||
struct GetPrivateKey;
|
||||
struct GetDnsResolver;
|
||||
struct SendMessage;
|
||||
struct RemoteRunSmcMethod;
|
||||
struct RemoteRunSmcMethodReturnType;
|
||||
|
||||
inline std::string to_string(const int_api::SendMessage&) {
|
||||
return "Send message";
|
||||
}
|
||||
|
@ -278,6 +281,8 @@ class TonlibClient : public td::actor::Actor {
|
|||
|
||||
td::Status do_request(tonlib_api::createQuery& request, td::Promise<object_ptr<tonlib_api::query_info>>&& promise);
|
||||
|
||||
td::Status do_request(tonlib_api::msg_decrypt& request, td::Promise<object_ptr<tonlib_api::msg_dataArray>>&& promise);
|
||||
|
||||
td::int64 next_smc_id_{0};
|
||||
std::map<td::int64, td::unique_ptr<AccountState>> smcs_;
|
||||
|
||||
|
@ -299,13 +304,18 @@ class TonlibClient : public td::actor::Actor {
|
|||
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
|
||||
void do_dns_request(std::string name, td::int32 category, td::int32 ttl, td::optional<ton::BlockIdExt> block_id,
|
||||
block::StdAddress address, td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
|
||||
struct DnsFinishData {
|
||||
ton::BlockIdExt block_id;
|
||||
ton::SmartContract::State smc_state;
|
||||
};
|
||||
void finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl, td::optional<ton::BlockIdExt> block_id,
|
||||
td::unique_ptr<AccountState> smc,
|
||||
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
|
||||
DnsFinishData dns_finish_data, td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
|
||||
|
||||
td::Status do_request(int_api::GetAccountState request, td::Promise<td::unique_ptr<AccountState>>&&);
|
||||
td::Status do_request(int_api::GetPrivateKey request, td::Promise<KeyStorage::PrivateKey>&&);
|
||||
td::Status do_request(int_api::GetDnsResolver request, td::Promise<block::StdAddress>&&);
|
||||
td::Status do_request(int_api::RemoteRunSmcMethod request,
|
||||
td::Promise<int_api::RemoteRunSmcMethodReturnType>&& promise);
|
||||
td::Status do_request(int_api::SendMessage request, td::Promise<td::Unit>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::liteServer_getInfo& request,
|
||||
|
|
|
@ -345,10 +345,14 @@ class TonlibCli : public td::actor::Actor {
|
|||
td::TerminalIO::out()
|
||||
<< "gethistory <key_id> - get history fo simple wallet with requested key (last 10 transactions)\n";
|
||||
td::TerminalIO::out() << "init <key_id> - init simple wallet with requested key\n";
|
||||
td::TerminalIO::out() << "transfer[f] <from_key_id> <to_key_id> <amount> - transfer <amount> of grams from "
|
||||
"<from_key_id> to <to_key_id>.\n"
|
||||
<< "\t<from_key_id> could also be 'giver'\n"
|
||||
<< "\t<to_key_id> could also be 'giver' or smartcontract address\n";
|
||||
td::TerminalIO::out() << "transfer[f][F][e][k][c] <from_key_id> (<to_key_id> <value> <message>|<file_name>) - "
|
||||
"make transfer from <from_key_id>\n"
|
||||
<< "\t 'f' modifier - allow send to uninited account\n"
|
||||
<< "\t 'F' modifier - read list of messages from <file_name> (in same format <to_key_id> "
|
||||
"<value> <message>, one per line)\n"
|
||||
<< "\t 'e' modifier - encrypt all messages\n"
|
||||
<< "\t 'k' modifier - use fake key\n"
|
||||
<< "\t 'c' modifier - just esmitate fees\n";
|
||||
} else if (cmd == "genkey") {
|
||||
generate_key();
|
||||
} else if (cmd == "exit" || cmd == "quit") {
|
||||
|
@ -445,15 +449,6 @@ class TonlibCli : public td::actor::Actor {
|
|||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
if (resolved->entries_[0]->name_ == name) {
|
||||
td::TerminalIO::out() << "Done\n";
|
||||
for (auto& entry : resolved->entries_) {
|
||||
td::TerminalIO::out() << " " << entry->name_ << " " << entry->category_ << " "
|
||||
<< tonlib::to_dns_entry_data(*entry->entry_).move_as_ok() << "\n";
|
||||
}
|
||||
promise.set_value(td::Unit());
|
||||
return;
|
||||
}
|
||||
if (resolved->entries_[0]->entry_->get_id() == tonlib_api::dns_entryDataNextResolver::ID && ttl != 0) {
|
||||
td::TerminalIO::out() << "Redirect resolver\n";
|
||||
auto entry = tonlib_api::move_object_as<tonlib_api::dns_entryDataNextResolver>(resolved->entries_[0]->entry_);
|
||||
|
@ -461,7 +456,12 @@ class TonlibCli : public td::actor::Actor {
|
|||
promise.send_closure(actor_id(this), &TonlibCli::do_dns_resolve, name, category, 0));
|
||||
return;
|
||||
}
|
||||
promise.set_error(td::Status::Error("Failed to resolve"));
|
||||
td::TerminalIO::out() << "Done\n";
|
||||
for (auto& entry : resolved->entries_) {
|
||||
td::TerminalIO::out() << " " << entry->name_ << " " << entry->category_ << " "
|
||||
<< tonlib::to_dns_entry_data(*entry->entry_).move_as_ok() << "\n";
|
||||
}
|
||||
promise.set_value(td::Unit());
|
||||
}
|
||||
|
||||
void dns_resolve(td::ConstParser& parser, td::Promise<td::Unit> promise) {
|
||||
|
@ -531,7 +531,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
: nullptr;
|
||||
send_query(tonlib_api::make_object<tonlib_api::createQuery>(std::move(key), std::move(address.address), 60,
|
||||
std::move(action)),
|
||||
promise.send_closure(actor_id(this), &TonlibCli::transfer2));
|
||||
promise.send_closure(actor_id(this), &TonlibCli::transfer2, false));
|
||||
}
|
||||
|
||||
void remote_time(td::Promise<td::Unit> promise) {
|
||||
|
@ -1389,13 +1389,21 @@ class TonlibCli : public td::actor::Actor {
|
|||
} else {
|
||||
sb << " From " << t->in_msg_->source_;
|
||||
}
|
||||
if (!t->in_msg_->message_.empty()) {
|
||||
sb << " ";
|
||||
if (t->in_msg_->is_message_encrypted_) {
|
||||
sb << "e";
|
||||
auto print_msg_data = [](td::StringBuilder& sb,
|
||||
tonlib_api::object_ptr<tonlib_api::msg_Data>& msg_data) {
|
||||
if (!msg_data) {
|
||||
return;
|
||||
}
|
||||
sb << "msg{" << t->in_msg_->message_ << "}";
|
||||
}
|
||||
sb << " ";
|
||||
downcast_call(*msg_data,
|
||||
td::overloaded([&](tonlib_api::msg_dataRaw& raw) { sb << "<unknown message>"; },
|
||||
[&](tonlib_api::msg_dataText& raw) { sb << "{" << raw.text_ << "}"; },
|
||||
[&](tonlib_api::msg_dataEncryptedText& raw) { sb << "<encrypted>"; },
|
||||
[&](tonlib_api::msg_dataDecryptedText& raw) {
|
||||
sb << "decrypted{" << raw.text_ << "}";
|
||||
}));
|
||||
};
|
||||
print_msg_data(sb, t->in_msg_->msg_data_);
|
||||
for (auto& ot : t->out_msgs_) {
|
||||
sb << "\n\t";
|
||||
if (ot->destination_.empty()) {
|
||||
|
@ -1404,13 +1412,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
sb << " To " << ot->destination_;
|
||||
}
|
||||
sb << " " << Grams{td::uint64(ot->value_)};
|
||||
if (!ot->message_.empty()) {
|
||||
sb << " ";
|
||||
if (ot->is_message_encrypted_) {
|
||||
sb << "e";
|
||||
}
|
||||
sb << "msg{" << ot->message_ << "}";
|
||||
}
|
||||
print_msg_data(sb, ot->msg_data_);
|
||||
}
|
||||
sb << "\n";
|
||||
}
|
||||
|
@ -1423,6 +1425,8 @@ class TonlibCli : public td::actor::Actor {
|
|||
bool from_file = false;
|
||||
bool force = false;
|
||||
bool use_encryption = false;
|
||||
bool use_fake_key = false;
|
||||
bool estimate_fees = false;
|
||||
if (cmd != "init") {
|
||||
td::ConstParser cmd_parser(cmd);
|
||||
cmd_parser.advance(td::Slice("transfer").size());
|
||||
|
@ -1435,6 +1439,10 @@ class TonlibCli : public td::actor::Actor {
|
|||
force = true;
|
||||
} else if (c == 'e') {
|
||||
use_encryption = true;
|
||||
} else if (c == 'k') {
|
||||
use_fake_key = true;
|
||||
} else if (c == 'c') {
|
||||
estimate_fees = true;
|
||||
} else {
|
||||
cmd_promise.set_error(td::Status::Error(PSLICE() << "Unknown suffix '" << c << "'"));
|
||||
return;
|
||||
|
@ -1464,7 +1472,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
|
||||
|
||||
if (use_encryption) {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataEncryptedText>(message.str());
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataDecryptedText>(message.str());
|
||||
} else {
|
||||
data = tonlib_api::make_object<tonlib_api::msg_dataText>(message.str());
|
||||
}
|
||||
|
@ -1495,25 +1503,38 @@ class TonlibCli : public td::actor::Actor {
|
|||
|
||||
td::Slice password; // empty by default
|
||||
using tonlib_api::make_object;
|
||||
auto key = !from_address.secret.empty()
|
||||
? make_object<tonlib_api::inputKeyRegular>(
|
||||
make_object<tonlib_api::key>(from_address.public_key, from_address.secret.copy()),
|
||||
td::SecureString(password))
|
||||
: nullptr;
|
||||
tonlib_api::object_ptr<tonlib_api::InputKey> key =
|
||||
!from_address.secret.empty()
|
||||
? make_object<tonlib_api::inputKeyRegular>(
|
||||
make_object<tonlib_api::key>(from_address.public_key, from_address.secret.copy()),
|
||||
td::SecureString(password))
|
||||
: nullptr;
|
||||
if (use_fake_key) {
|
||||
key = make_object<tonlib_api::inputKeyFake>();
|
||||
}
|
||||
|
||||
bool allow_send_to_uninited = force;
|
||||
|
||||
send_query(make_object<tonlib_api::createQuery>(
|
||||
std::move(key), std::move(from_address.address), 60,
|
||||
make_object<tonlib_api::actionMsg>(std::move(messages), allow_send_to_uninited)),
|
||||
cmd_promise.send_closure(actor_id(this), &TonlibCli::transfer2));
|
||||
cmd_promise.send_closure(actor_id(this), &TonlibCli::transfer2, estimate_fees));
|
||||
}
|
||||
|
||||
void transfer2(td::Result<tonlib_api::object_ptr<tonlib_api::query_info>> r_info, td::Promise<td::Unit> cmd_promise) {
|
||||
send_query(tonlib_api::make_object<tonlib_api::query_send>(r_info.ok()->id_), cmd_promise.wrap([](auto&& info) {
|
||||
td::TerminalIO::out() << "Transfer sent!\n";
|
||||
return td::Unit();
|
||||
}));
|
||||
void transfer2(bool estimate_fees, td::Result<tonlib_api::object_ptr<tonlib_api::query_info>> r_info,
|
||||
td::Promise<td::Unit> cmd_promise) {
|
||||
if (estimate_fees) {
|
||||
send_query(tonlib_api::make_object<tonlib_api::query_estimateFees>(r_info.ok()->id_, true),
|
||||
cmd_promise.wrap([](auto&& info) {
|
||||
td::TerminalIO::out() << "Extimated fees: " << to_string(info);
|
||||
return td::Unit();
|
||||
}));
|
||||
} else {
|
||||
send_query(tonlib_api::make_object<tonlib_api::query_send>(r_info.ok()->id_), cmd_promise.wrap([](auto&& info) {
|
||||
td::TerminalIO::out() << "Transfer sent: " << to_string(info);
|
||||
return td::Unit();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
void get_hints(td::Slice prefix) {
|
||||
|
|
|
@ -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 "apply-block.hpp"
|
||||
#include "adnl/utils.hpp"
|
||||
|
@ -79,8 +79,8 @@ void ApplyBlock::got_block_handle(BlockHandle handle) {
|
|||
}
|
||||
|
||||
if (handle_->is_applied()) {
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([SelfId = actor_id(this), seqno = handle_->id().id.seqno](td::Result<BlockIdExt> R) {
|
||||
auto P = td::PromiseCreator::lambda(
|
||||
[ SelfId = actor_id(this), seqno = handle_->id().id.seqno ](td::Result<BlockIdExt> R) {
|
||||
R.ensure();
|
||||
auto h = R.move_as_ok();
|
||||
if (h.id.seqno < seqno) {
|
||||
|
@ -119,14 +119,15 @@ void ApplyBlock::got_block_handle(BlockHandle handle) {
|
|||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::set_block_data, handle_, block_, std::move(P));
|
||||
} else {
|
||||
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this), handle = handle_](td::Result<td::Ref<BlockData>> R) {
|
||||
CHECK(handle->received());
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::written_block_data);
|
||||
}
|
||||
});
|
||||
auto P =
|
||||
td::PromiseCreator::lambda([ SelfId = actor_id(this), handle = handle_ ](td::Result<td::Ref<BlockData>> R) {
|
||||
CHECK(handle->received());
|
||||
if (R.is_error()) {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::abort_query, R.move_as_error());
|
||||
} else {
|
||||
td::actor::send_closure(SelfId, &ApplyBlock::written_block_data);
|
||||
}
|
||||
});
|
||||
|
||||
td::actor::send_closure(manager_, &ValidatorManager::wait_block_data, handle_, apply_block_priority(), timeout_,
|
||||
std::move(P));
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "archive-mover.hpp"
|
||||
#include "td/actor/MultiPromise.h"
|
||||
#include "validator/fabric.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/interfaces/db.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "fileref.hpp"
|
||||
#include "auto/tl/ton_api.hpp"
|
||||
#include "td/utils/overloaded.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "validator/validator.h"
|
||||
|
|
|
@ -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 "collator-impl.h"
|
||||
#include "vm/boc.h"
|
||||
|
@ -589,9 +589,9 @@ void Collator::got_neighbor_out_queue(int i, td::Result<Ref<MessageQueue>> res)
|
|||
return;
|
||||
}
|
||||
descr.set_queue_root(qinfo.out_queue->prefetch_ref(0));
|
||||
// TODO: comment the next two lines in the future when the output queues become huge
|
||||
CHECK(block::gen::t_OutMsgQueueInfo.validate_ref(outq_descr->root_cell()));
|
||||
CHECK(block::tlb::t_OutMsgQueueInfo.validate_ref(outq_descr->root_cell()));
|
||||
// comment the next two lines in the future when the output queues become huge
|
||||
// CHECK(block::gen::t_OutMsgQueueInfo.validate_ref(1000000, outq_descr->root_cell()));
|
||||
// CHECK(block::tlb::t_OutMsgQueueInfo.validate_ref(1000000, outq_descr->root_cell()));
|
||||
// unpack ProcessedUpto
|
||||
LOG(DEBUG) << "unpacking ProcessedUpto of neighbor " << descr.blk_.to_str();
|
||||
if (verbosity >= 2) {
|
||||
|
@ -1506,7 +1506,7 @@ bool Collator::fetch_config_params() {
|
|||
// fetch block_grams_created
|
||||
auto cell = config_->get_config_param(14);
|
||||
if (cell.is_null()) {
|
||||
basechain_create_fee_ = masterchain_create_fee_ = td::RefInt256{true, 0};
|
||||
basechain_create_fee_ = masterchain_create_fee_ = td::zero_refint();
|
||||
} else {
|
||||
block::gen::BlockCreateFees::Record create_fees;
|
||||
if (!(tlb::unpack_cell(cell, create_fees) &&
|
||||
|
@ -1781,7 +1781,7 @@ bool Collator::out_msg_queue_cleanup() {
|
|||
block::gen::t_OutMsgQueue.print(std::cerr, *rt);
|
||||
rt->print_rec(std::cerr);
|
||||
}
|
||||
CHECK(block::gen::t_OutMsgQueue.validate(*rt)); // DEBUG, comment later if SLOW
|
||||
// CHECK(block::gen::t_OutMsgQueue.validate_upto(100000, *rt)); // DEBUG, comment later if SLOW
|
||||
return register_out_msg_queue_op(true);
|
||||
}
|
||||
|
||||
|
@ -1853,13 +1853,13 @@ bool Collator::combine_account_transactions() {
|
|||
block::gen::t_AccountBlock.print_ref(std::cerr, cell);
|
||||
csr->print_rec(std::cerr);
|
||||
}
|
||||
if (!block::gen::t_AccountBlock.validate_ref(cell)) {
|
||||
if (!block::gen::t_AccountBlock.validate_ref(100000, cell)) {
|
||||
block::gen::t_AccountBlock.print_ref(std::cerr, cell);
|
||||
csr->print_rec(std::cerr);
|
||||
return fatal_error(std::string{"new AccountBlock for "} + z.first.to_hex() +
|
||||
" failed to pass automatic validation tests");
|
||||
}
|
||||
if (!block::tlb::t_AccountBlock.validate_ref(cell)) {
|
||||
if (!block::tlb::t_AccountBlock.validate_ref(100000, cell)) {
|
||||
block::gen::t_AccountBlock.print_ref(std::cerr, cell);
|
||||
csr->print_rec(std::cerr);
|
||||
return fatal_error(std::string{"new AccountBlock for "} + z.first.to_hex() +
|
||||
|
@ -1923,10 +1923,10 @@ bool Collator::combine_account_transactions() {
|
|||
block::gen::t_ShardAccountBlocks.print_ref(std::cerr, shard_account_blocks_);
|
||||
vm::load_cell_slice(shard_account_blocks_).print_rec(std::cerr);
|
||||
}
|
||||
if (!block::gen::t_ShardAccountBlocks.validate_ref(shard_account_blocks_)) {
|
||||
if (!block::gen::t_ShardAccountBlocks.validate_ref(100000, shard_account_blocks_)) {
|
||||
return fatal_error("new ShardAccountBlocks failed to pass automatic validity tests");
|
||||
}
|
||||
if (!block::tlb::t_ShardAccountBlocks.validate_ref(shard_account_blocks_)) {
|
||||
if (!block::tlb::t_ShardAccountBlocks.validate_ref(100000, shard_account_blocks_)) {
|
||||
return fatal_error("new ShardAccountBlocks failed to pass handwritten validity tests");
|
||||
}
|
||||
auto shard_accounts = account_dict->get_root();
|
||||
|
@ -1937,10 +1937,10 @@ bool Collator::combine_account_transactions() {
|
|||
}
|
||||
if (verify >= 2) {
|
||||
LOG(INFO) << "verifying new ShardAccounts";
|
||||
if (!block::gen::t_ShardAccounts.validate(*shard_accounts)) {
|
||||
if (!block::gen::t_ShardAccounts.validate_upto(100000, *shard_accounts)) {
|
||||
return fatal_error("new ShardAccounts failed to pass automatic validity tests");
|
||||
}
|
||||
if (!block::tlb::t_ShardAccounts.validate(*shard_accounts)) {
|
||||
if (!block::tlb::t_ShardAccounts.validate_upto(100000, *shard_accounts)) {
|
||||
return fatal_error("new ShardAccounts failed to pass handwritten validity tests");
|
||||
}
|
||||
}
|
||||
|
@ -3012,7 +3012,7 @@ bool Collator::create_mc_state_extra() {
|
|||
std::cerr << "updated shard configuration to ";
|
||||
block::gen::t_ShardHashes.print(std::cerr, *state_extra.shard_hashes);
|
||||
}
|
||||
if (!block::gen::t_ShardHashes.validate(*state_extra.shard_hashes)) {
|
||||
if (!block::gen::t_ShardHashes.validate_upto(10000, *state_extra.shard_hashes)) {
|
||||
return fatal_error("new ShardHashes is invalid");
|
||||
}
|
||||
// 4. check extension flags
|
||||
|
@ -3110,7 +3110,7 @@ bool Collator::create_mc_state_extra() {
|
|||
state_extra.r1.block_create_stats = cs;
|
||||
if (verify >= 2) {
|
||||
LOG(INFO) << "verifying new BlockCreateStats";
|
||||
if (!block::gen::t_BlockCreateStats.validate_csr(cs)) {
|
||||
if (!block::gen::t_BlockCreateStats.validate_csr(100000, cs)) {
|
||||
cs->print_rec(std::cerr);
|
||||
block::gen::t_BlockCreateStats.print(std::cerr, *cs);
|
||||
return fatal_error("BlockCreateStats in the new masterchain state failed to pass automated validity checks");
|
||||
|
@ -3128,8 +3128,8 @@ bool Collator::create_mc_state_extra() {
|
|||
}
|
||||
if (verify >= 2) {
|
||||
LOG(INFO) << "verifying new McStateExtra";
|
||||
CHECK(block::gen::t_McStateExtra.validate_ref(mc_state_extra_));
|
||||
CHECK(block::tlb::t_McStateExtra.validate_ref(mc_state_extra_));
|
||||
CHECK(block::gen::t_McStateExtra.validate_ref(1000000, mc_state_extra_));
|
||||
CHECK(block::tlb::t_McStateExtra.validate_ref(1000000, mc_state_extra_));
|
||||
}
|
||||
LOG(INFO) << "McStateExtra created";
|
||||
return true;
|
||||
|
@ -3467,8 +3467,8 @@ bool Collator::create_shard_state() {
|
|||
}
|
||||
if (verify >= 2) {
|
||||
LOG(INFO) << "verifying new ShardState";
|
||||
CHECK(block::gen::t_ShardState.validate_ref(state_root));
|
||||
CHECK(block::tlb::t_ShardState.validate_ref(state_root));
|
||||
CHECK(block::gen::t_ShardState.validate_ref(1000000, state_root));
|
||||
CHECK(block::tlb::t_ShardState.validate_ref(1000000, state_root));
|
||||
}
|
||||
LOG(INFO) << "creating Merkle update for the ShardState";
|
||||
state_update = vm::MerkleUpdate::generate(prev_state_root_, state_root, state_usage_tree_.get());
|
||||
|
@ -3688,7 +3688,7 @@ bool Collator::create_block() {
|
|||
}
|
||||
if (verify >= 1) {
|
||||
LOG(INFO) << "verifying new Block";
|
||||
if (!block::gen::t_Block.validate_ref(new_block)) {
|
||||
if (!block::gen::t_Block.validate_ref(1000000, new_block)) {
|
||||
return fatal_error("new Block failed to pass automatic validity tests");
|
||||
}
|
||||
}
|
||||
|
@ -3836,10 +3836,10 @@ td::Result<bool> Collator::register_external_message_cell(Ref<vm::Cell> ext_msg,
|
|||
return td::Status::Error("external message has been rejected before");
|
||||
}
|
||||
}
|
||||
if (!block::gen::t_Message_Any.validate_ref(ext_msg)) {
|
||||
if (!block::gen::t_Message_Any.validate_ref(256, ext_msg)) {
|
||||
return td::Status::Error("external message is not a (Message Any) according to automated checks");
|
||||
}
|
||||
if (!block::tlb::t_Message.validate_ref(ext_msg)) {
|
||||
if (!block::tlb::t_Message.validate_ref(256, ext_msg)) {
|
||||
return td::Status::Error("external message is not a (Message Any) according to hand-written checks");
|
||||
}
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
|
||||
|
|
|
@ -56,10 +56,10 @@ td::Result<Ref<ExtMessageQ>> ExtMessageQ::create_ext_message(td::BufferSlice dat
|
|||
return td::Status::Error("external message must begin with ext_in_msg_info$10");
|
||||
}
|
||||
ton::Bits256 hash{ext_msg->get_hash().bits()};
|
||||
if (!block::gen::t_Message_Any.validate_ref(ext_msg)) {
|
||||
if (!block::gen::t_Message_Any.validate_ref(128, ext_msg)) {
|
||||
return td::Status::Error("external message is not a (Message Any) according to automated checks");
|
||||
}
|
||||
if (!block::tlb::t_Message.validate_ref(ext_msg)) {
|
||||
if (!block::tlb::t_Message.validate_ref(128, ext_msg)) {
|
||||
return td::Status::Error("external message is not a (Message Any) according to hand-written checks");
|
||||
}
|
||||
block::gen::CommonMsgInfo::Record_ext_in_msg_info info;
|
||||
|
|
|
@ -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 "validate-query.hpp"
|
||||
#include "top-shard-descr.hpp"
|
||||
|
@ -499,7 +499,7 @@ bool ValidateQuery::extract_collated_data_from(Ref<vm::Cell> croot, int idx) {
|
|||
}
|
||||
if (block::gen::t_TopBlockDescrSet.has_valid_tag(cs)) {
|
||||
LOG(DEBUG) << "collated datum # " << idx << " is a TopBlockDescrSet";
|
||||
if (!block::gen::t_TopBlockDescrSet.validate(cs)) {
|
||||
if (!block::gen::t_TopBlockDescrSet.validate_upto(10000, cs)) {
|
||||
return reject_query("invalid TopBlockDescrSet");
|
||||
}
|
||||
if (top_shard_descr_dict_) {
|
||||
|
@ -776,7 +776,7 @@ bool ValidateQuery::fetch_config_params() {
|
|||
// fetch block_grams_created
|
||||
auto cell = config_->get_config_param(14);
|
||||
if (cell.is_null()) {
|
||||
basechain_create_fee_ = masterchain_create_fee_ = td::RefInt256{true, 0};
|
||||
basechain_create_fee_ = masterchain_create_fee_ = td::zero_refint();
|
||||
} else {
|
||||
block::gen::BlockCreateFees::Record create_fees;
|
||||
if (!(tlb::unpack_cell(cell, create_fees) &&
|
||||
|
@ -1229,8 +1229,8 @@ void ValidateQuery::got_neighbor_out_queue(int i, td::Result<Ref<MessageQueue>>
|
|||
descr.set_queue_root(qinfo.out_queue->prefetch_ref(0));
|
||||
// TODO: comment the next two lines in the future when the output queues become huge
|
||||
// (do this carefully)
|
||||
CHECK(block::gen::t_OutMsgQueueInfo.validate_ref(outq_descr->root_cell()));
|
||||
CHECK(block::tlb::t_OutMsgQueueInfo.validate_ref(outq_descr->root_cell()));
|
||||
CHECK(block::gen::t_OutMsgQueueInfo.validate_ref(1000000, outq_descr->root_cell()));
|
||||
CHECK(block::tlb::t_OutMsgQueueInfo.validate_ref(1000000, outq_descr->root_cell()));
|
||||
// unpack ProcessedUpto
|
||||
LOG(DEBUG) << "unpacking ProcessedUpto of neighbor " << descr.blk_.to_str();
|
||||
if (verbosity >= 2) {
|
||||
|
@ -2049,13 +2049,13 @@ bool ValidateQuery::unpack_block_data() {
|
|||
auto outmsg_cs = vm::load_cell_slice_ref(std::move(extra.out_msg_descr));
|
||||
// run some hand-written checks from block::tlb::
|
||||
// (automatic tests from block::gen:: have been already run for the entire block)
|
||||
if (!block::tlb::t_InMsgDescr.validate(*inmsg_cs)) {
|
||||
if (!block::tlb::t_InMsgDescr.validate_upto(1000000, *inmsg_cs)) {
|
||||
return reject_query("InMsgDescr of the new block failed to pass handwritten validity tests");
|
||||
}
|
||||
if (!block::tlb::t_OutMsgDescr.validate(*outmsg_cs)) {
|
||||
if (!block::tlb::t_OutMsgDescr.validate_upto(1000000, *outmsg_cs)) {
|
||||
return reject_query("OutMsgDescr of the new block failed to pass handwritten validity tests");
|
||||
}
|
||||
if (!block::tlb::t_ShardAccountBlocks.validate_ref(extra.account_blocks)) {
|
||||
if (!block::tlb::t_ShardAccountBlocks.validate_ref(1000000, extra.account_blocks)) {
|
||||
return reject_query("ShardAccountBlocks of the new block failed to pass handwritten validity tests");
|
||||
}
|
||||
in_msg_dict_ = std::make_unique<vm::AugmentedDictionary>(std::move(inmsg_cs), 256, block::tlb::aug_InMsgDescr);
|
||||
|
@ -2274,11 +2274,11 @@ bool ValidateQuery::precheck_one_account_update(td::ConstBitPtr acc_id, Ref<vm::
|
|||
"AccountBlock for this account");
|
||||
}
|
||||
if (new_value.not_null()) {
|
||||
if (!block::gen::t_ShardAccount.validate_csr(new_value)) {
|
||||
if (!block::gen::t_ShardAccount.validate_csr(10000, new_value)) {
|
||||
return reject_query("new state of account "s + acc_id.to_hex(256) +
|
||||
" failed to pass automated validity checks for ShardAccount");
|
||||
}
|
||||
if (!block::tlb::t_ShardAccount.validate_csr(new_value)) {
|
||||
if (!block::tlb::t_ShardAccount.validate_csr(10000, new_value)) {
|
||||
return reject_query("new state of account "s + acc_id.to_hex(256) +
|
||||
" failed to pass hand-written validity checks for ShardAccount");
|
||||
}
|
||||
|
@ -2428,10 +2428,10 @@ bool ValidateQuery::precheck_one_account_block(td::ConstBitPtr acc_id, Ref<vm::C
|
|||
return reject_query("(HASH_UPDATE Account) from the AccountBlock of "s + acc_id.to_hex(256) +
|
||||
" has incorrect new hash");
|
||||
}
|
||||
if (!block::gen::t_AccountBlock.validate(*acc_blk_root)) {
|
||||
if (!block::gen::t_AccountBlock.validate_upto(1000000, *acc_blk_root)) {
|
||||
return reject_query("AccountBlock of "s + acc_id.to_hex(256) + " failed to pass automated validity checks");
|
||||
}
|
||||
if (!block::tlb::t_AccountBlock.validate(*acc_blk_root)) {
|
||||
if (!block::tlb::t_AccountBlock.validate_upto(1000000, *acc_blk_root)) {
|
||||
return reject_query("AccountBlock of "s + acc_id.to_hex(256) + " failed to pass hand-written validity checks");
|
||||
}
|
||||
unsigned last_trans_lt_len = 1;
|
||||
|
@ -4794,10 +4794,10 @@ bool ValidateQuery::check_new_state() {
|
|||
}
|
||||
|
||||
bool ValidateQuery::check_config_update(Ref<vm::CellSlice> old_conf_params, Ref<vm::CellSlice> new_conf_params) {
|
||||
if (!block::gen::t_ConfigParams.validate_csr(new_conf_params)) {
|
||||
if (!block::gen::t_ConfigParams.validate_csr(10000, new_conf_params)) {
|
||||
return reject_query("new configuration failed to pass automated validity checks");
|
||||
}
|
||||
if (!block::gen::t_ConfigParams.validate_csr(old_conf_params)) {
|
||||
if (!block::gen::t_ConfigParams.validate_csr(10000, old_conf_params)) {
|
||||
return fatal_error("old configuration failed to pass automated validity checks");
|
||||
}
|
||||
td::Bits256 old_cfg_addr, new_cfg_addr;
|
||||
|
@ -4908,7 +4908,8 @@ bool ValidateQuery::check_one_prev_dict_update(ton::BlockSeqno seqno, Ref<vm::Ce
|
|||
}
|
||||
CHECK(new_val_extra.not_null());
|
||||
vm::CellSlice cs{*new_val_extra};
|
||||
if (!(block::gen::t_KeyMaxLt.validate_skip(cs) && block::gen::t_KeyExtBlkRef.validate_skip(cs) && cs.empty_ext())) {
|
||||
if (!(block::gen::t_KeyMaxLt.validate_skip_upto(16, cs) && block::gen::t_KeyExtBlkRef.validate_skip_upto(16, cs) &&
|
||||
cs.empty_ext())) {
|
||||
return reject_query(PSTRING() << "entry with seqno " << seqno
|
||||
<< " in the new previous blocks dictionary failed to pass automated validity checks "
|
||||
"form KeyMaxLt + KeyExtBlkRef");
|
||||
|
@ -5039,7 +5040,7 @@ bool ValidateQuery::check_mc_state_extra() {
|
|||
<< " while the block header claims is_key_block=" << is_key_block_);
|
||||
}
|
||||
// last_key_block:(Maybe ExtBlkRef)
|
||||
if (!block::gen::t_Maybe_ExtBlkRef.validate_csr(new_extra.r1.last_key_block)) {
|
||||
if (!block::gen::t_Maybe_ExtBlkRef.validate_csr(16, new_extra.r1.last_key_block)) {
|
||||
return reject_query(
|
||||
"last_key_block:(Maybe ExtBlkRef) in the new masterchain state failed to pass automated validity checks");
|
||||
}
|
||||
|
@ -5360,7 +5361,7 @@ bool ValidateQuery::try_validate() {
|
|||
}
|
||||
}
|
||||
LOG(INFO) << "running automated validity checks for block candidate " << id_.to_str();
|
||||
if (!block::gen::t_Block.validate_ref(block_root_)) {
|
||||
if (!block::gen::t_Block.validate_ref(1000000, block_root_)) {
|
||||
return reject_query("block "s + id_.to_str() + " failed to pass automated validity checks");
|
||||
}
|
||||
if (!fix_all_processed_upto()) {
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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 2019-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "import-db-slice.hpp"
|
||||
#include "validator/db/fileref.hpp"
|
||||
#include "td/utils/overloaded.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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 2019-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "download-archive-slice.hpp"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/overloaded.h"
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
This file is part of TON Blockchain Library.
|
||||
|
||||
TON Blockchain Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
TON Blockchain Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
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-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/int_types.h"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue