1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 11:12:16 +00:00

Merge branch 'testnet' into tvm-v9

This commit is contained in:
SpyCheese 2025-01-17 12:32:09 +03:00
commit 77e5a2f4a2
24 changed files with 169 additions and 76 deletions

View file

@ -31,7 +31,7 @@ Besides the work of the core team, this update is based on the efforts of @krigg
## 2024.08 Update ## 2024.08 Update
1. Introduction of dispatch queues, message envelopes with transaction chain metadata, and explicitly stored msg_queue size, which will be activated by `Config8.version >= 8` and new `Config8.capabilities` bits: `capStoreOutMsgQueueSize`, `capMsgMetadata`, `capDeferMessages`. 1. Introduction of dispatch queues, message envelopes with transaction chain metadata, and explicitly stored msg_queue size, which will be activated by `Config8.version >= 8` and new `Config8.capabilities` bits: `capStoreOutMsgQueueSize`, `capMsgMetadata`, `capDeferMessages`.
2. A number of changes to transcation executor which will activated for `Config8.version >= 8`: 2. A number of changes to transaction executor which will activated for `Config8.version >= 8`:
- Check mode on invalid `action_send_msg`. Ignore action if `IGNORE_ERROR` (+2) bit is set, bounce if `BOUNCE_ON_FAIL` (+16) bit is set. - Check mode on invalid `action_send_msg`. Ignore action if `IGNORE_ERROR` (+2) bit is set, bounce if `BOUNCE_ON_FAIL` (+16) bit is set.
- Slightly change random seed generation to fix mix of `addr_rewrite` and `addr`. - Slightly change random seed generation to fix mix of `addr_rewrite` and `addr`.
- Fill in `skipped_actions` for both invalid and valid messages with `IGNORE_ERROR` mode that can't be sent. - Fill in `skipped_actions` for both invalid and valid messages with `IGNORE_ERROR` mode that can't be sent.
@ -103,7 +103,7 @@ Besides the work of the core team, this update is based on the efforts of @akifo
* Fix error in proof generation for blocks after merge * Fix error in proof generation for blocks after merge
* Fix most of `block is not applied` issues related to sending too recent block in Proofs * Fix most of `block is not applied` issues related to sending too recent block in Proofs
* LS now check external messages till `accept_message` (`set_gas`). * LS now check external messages till `accept_message` (`set_gas`).
3. Improvements in DHT work and storage, CellDb, config.json ammendment, peer misbehavior detection, validator session stats collection, emulator. 3. Improvements in DHT work and storage, CellDb, config.json amendment, peer misbehavior detection, validator session stats collection, emulator.
4. Change in CTOS and XLOAD behavior activated through setting `version >= 5` in `ConfigParam 8;`: 4. Change in CTOS and XLOAD behavior activated through setting `version >= 5` in `ConfigParam 8;`:
* Loading "nested libraries" (i.e. a library cell that points to another library cell) throws an exception. * Loading "nested libraries" (i.e. a library cell that points to another library cell) throws an exception.
* Loading a library consumes gas for cell load only once (for the library cell), not twice (both for the library cell and the cell in the library). * Loading a library consumes gas for cell load only once (for the library cell), not twice (both for the library cell and the cell in the library).
@ -114,7 +114,7 @@ Besides the work of the Core team, this update is based on the efforts of @XaBbl
## 2023.12 Update ## 2023.12 Update
1. Optimized message queue handling, now queue cleaning speed doesn't depend on total queue size 1. Optimized message queue handling, now queue cleaning speed doesn't depend on total queue size
* Cleaning delivered messages using lt augmentation instead of random search / consequtive walk * Cleaning delivered messages using lt augmentation instead of random search / consecutive walk
* Keeping root cell of queue message in memory until outdated (caching) * Keeping root cell of queue message in memory until outdated (caching)
2. Changes to block collation/validation limits 2. Changes to block collation/validation limits
3. Stop accepting new external message if message queue is overloaded 3. Stop accepting new external message if message queue is overloaded
@ -206,7 +206,7 @@ Besides the work of the core team, this update is based on the efforts of @vtama
Besides the work of the core team, this update is based on the efforts of @tvorogme (debug improvements), @AlexeyFSL (WASM builds) and third-party security auditors. Besides the work of the core team, this update is based on the efforts of @tvorogme (debug improvements), @AlexeyFSL (WASM builds) and third-party security auditors.
## 2022.08 Update ## 2022.08 Update
* Blockchain state serialization now works via separate db-handler which simplfies memory clearing after serialization * Blockchain state serialization now works via separate db-handler which simplifies memory clearing after serialization
* CellDB now works asynchronously which substantially increase database access throughput * CellDB now works asynchronously which substantially increase database access throughput
* Abseil-cpp and crc32 updated: solve issues with compilation on recent OS distributives * Abseil-cpp and crc32 updated: solve issues with compilation on recent OS distributives
* Fixed a series of UBs and issues for exotic endianness hosts * Fixed a series of UBs and issues for exotic endianness hosts

View file

@ -119,6 +119,7 @@ void AdnlPeerPairImpl::discover() {
void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) { void AdnlPeerPairImpl::receive_packet_checked(AdnlPacket packet) {
last_received_packet_ = td::Timestamp::now(); last_received_packet_ = td::Timestamp::now();
try_reinit_at_ = td::Timestamp::never(); try_reinit_at_ = td::Timestamp::never();
drop_addr_list_at_ = td::Timestamp::never();
request_reverse_ping_after_ = td::Timestamp::in(15.0); request_reverse_ping_after_ = td::Timestamp::in(15.0);
auto d = Adnl::adnl_start_time(); auto d = Adnl::adnl_start_time();
if (packet.dst_reinit_date() > d) { if (packet.dst_reinit_date() > d) {
@ -415,6 +416,9 @@ void AdnlPeerPairImpl::send_packet_continue(AdnlPacket packet, td::actor::ActorI
if (!try_reinit_at_ && last_received_packet_ < td::Timestamp::in(-5.0)) { if (!try_reinit_at_ && last_received_packet_ < td::Timestamp::in(-5.0)) {
try_reinit_at_ = td::Timestamp::in(10.0); try_reinit_at_ = td::Timestamp::in(10.0);
} }
if (!drop_addr_list_at_ && last_received_packet_ < td::Timestamp::in(-60.0 * 9.0)) {
drop_addr_list_at_ = td::Timestamp::in(60.0);
}
packet.run_basic_checks().ensure(); packet.run_basic_checks().ensure();
auto B = serialize_tl_object(packet.tl(), true); auto B = serialize_tl_object(packet.tl(), true);
if (via_channel) { if (via_channel) {
@ -692,6 +696,16 @@ void AdnlPeerPairImpl::reinit(td::int32 date) {
} }
td::Result<std::pair<td::actor::ActorId<AdnlNetworkConnection>, bool>> AdnlPeerPairImpl::get_conn() { td::Result<std::pair<td::actor::ActorId<AdnlNetworkConnection>, bool>> AdnlPeerPairImpl::get_conn() {
if (drop_addr_list_at_ && drop_addr_list_at_.is_in_past()) {
drop_addr_list_at_ = td::Timestamp::never();
priority_addr_list_ = AdnlAddressList{};
priority_conns_.clear();
addr_list_ = AdnlAddressList{};
conns_.clear();
has_reverse_addr_ = false;
return td::Status::Error(ErrorCode::notready, "no active connections");
}
if (!priority_addr_list_.empty() && priority_addr_list_.expire_at() < td::Clocks::system()) { if (!priority_addr_list_.empty() && priority_addr_list_.expire_at() < td::Clocks::system()) {
priority_addr_list_ = AdnlAddressList{}; priority_addr_list_ = AdnlAddressList{};
priority_conns_.clear(); priority_conns_.clear();

View file

@ -266,6 +266,7 @@ class AdnlPeerPairImpl : public AdnlPeerPair {
td::Timestamp last_received_packet_ = td::Timestamp::never(); td::Timestamp last_received_packet_ = td::Timestamp::never();
td::Timestamp try_reinit_at_ = td::Timestamp::never(); td::Timestamp try_reinit_at_ = td::Timestamp::never();
td::Timestamp drop_addr_list_at_ = td::Timestamp::never();
bool has_reverse_addr_ = false; bool has_reverse_addr_ = false;
td::Timestamp request_reverse_ping_after_ = td::Timestamp::now(); td::Timestamp request_reverse_ping_after_ = td::Timestamp::now();

View file

@ -1319,6 +1319,36 @@ CurrencyCollection CurrencyCollection::operator-(td::RefInt256 other_grams) cons
} }
} }
bool CurrencyCollection::clamp(const CurrencyCollection& other) {
if (!is_valid() || !other.is_valid()) {
return invalidate();
}
grams = std::min(grams, other.grams);
vm::Dictionary dict1{extra, 32}, dict2(other.extra, 32);
bool ok = dict1.check_for_each([&](td::Ref<vm::CellSlice> cs1, td::ConstBitPtr key, int n) {
CHECK(n == 32);
td::Ref<vm::CellSlice> cs2 = dict2.lookup(key, 32);
td::RefInt256 val1 = tlb::t_VarUIntegerPos_32.as_integer(cs1);
if (val1.is_null()) {
return false;
}
td::RefInt256 val2 = cs2.is_null() ? td::zero_refint() : tlb::t_VarUIntegerPos_32.as_integer(cs2);
if (val2.is_null()) {
return false;
}
if (val1 > val2) {
if (val2->sgn() == 0) {
dict1.lookup_delete(key, 32);
} else {
dict1.set(key, 32, cs2);
}
}
return true;
});
extra = dict1.get_root_cell();
return ok || invalidate();
}
bool CurrencyCollection::operator==(const CurrencyCollection& other) const { bool CurrencyCollection::operator==(const CurrencyCollection& other) const {
return is_valid() && other.is_valid() && !td::cmp(grams, other.grams) && return is_valid() && other.is_valid() && !td::cmp(grams, other.grams) &&
(extra.not_null() == other.extra.not_null()) && (extra.not_null() == other.extra.not_null()) &&

View file

@ -390,6 +390,7 @@ struct CurrencyCollection {
CurrencyCollection operator-(const CurrencyCollection& other) const; CurrencyCollection operator-(const CurrencyCollection& other) const;
CurrencyCollection operator-(CurrencyCollection&& other) const; CurrencyCollection operator-(CurrencyCollection&& other) const;
CurrencyCollection operator-(td::RefInt256 other_grams) const; CurrencyCollection operator-(td::RefInt256 other_grams) const;
bool clamp(const CurrencyCollection& other);
bool store(vm::CellBuilder& cb) const; bool store(vm::CellBuilder& cb) const;
bool store_or_zero(vm::CellBuilder& cb) const; bool store_or_zero(vm::CellBuilder& cb) const;
bool fetch(vm::CellSlice& cs); bool fetch(vm::CellSlice& cs);

View file

@ -296,7 +296,7 @@ transaction$0111 account_addr:bits256 lt:uint64
total_fees:CurrencyCollection state_update:^(HASH_UPDATE Account) total_fees:CurrencyCollection state_update:^(HASH_UPDATE Account)
description:^TransactionDescr = Transaction; description:^TransactionDescr = Transaction;
!merkle_update#02 {X:Type} old_hash:bits256 new_hash:bits256 !merkle_update#04 {X:Type} old_hash:bits256 new_hash:bits256 old_depth:uint16 new_depth:uint16
old:^X new:^X = MERKLE_UPDATE X; old:^X new:^X = MERKLE_UPDATE X;
update_hashes#72 {X:Type} old_hash:bits256 new_hash:bits256 update_hashes#72 {X:Type} old_hash:bits256 new_hash:bits256
= HASH_UPDATE X; = HASH_UPDATE X;

View file

@ -2795,22 +2795,25 @@ int Transaction::try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap,
LOG(DEBUG) << "cannot reserve a negative amount: " << reserve.to_str(); LOG(DEBUG) << "cannot reserve a negative amount: " << reserve.to_str();
return -1; return -1;
} }
if (reserve.grams > ap.remaining_balance.grams) {
if (mode & 2) { if (mode & 2) {
reserve.grams = ap.remaining_balance.grams; if (cfg.reserve_extra_enabled) {
if (!reserve.clamp(ap.remaining_balance)) {
LOG(DEBUG) << "failed to clamp reserve amount" << mode;
return -1;
}
} else { } else {
reserve.grams = std::min(reserve.grams, ap.remaining_balance.grams);
}
}
if (reserve.grams > ap.remaining_balance.grams) {
LOG(DEBUG) << "cannot reserve " << reserve.grams << " nanograms : only " << ap.remaining_balance.grams LOG(DEBUG) << "cannot reserve " << reserve.grams << " nanograms : only " << ap.remaining_balance.grams
<< " available"; << " available";
return 37; // not enough grams return 37; // not enough grams
} }
}
if (!block::sub_extra_currency(ap.remaining_balance.extra, reserve.extra, newc.extra)) { if (!block::sub_extra_currency(ap.remaining_balance.extra, reserve.extra, newc.extra)) {
LOG(DEBUG) << "not enough extra currency to reserve: " << block::CurrencyCollection{0, reserve.extra}.to_str() LOG(DEBUG) << "not enough extra currency to reserve: " << block::CurrencyCollection{0, reserve.extra}.to_str()
<< " required, only " << block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str() << " required, only " << block::CurrencyCollection{0, ap.remaining_balance.extra}.to_str()
<< " available"; << " available";
if (mode & 2) {
// TODO: process (mode & 2) correctly by setting res_extra := inf (reserve.extra, ap.remaining_balance.extra)
}
return 38; // not enough (extra) funds return 38; // not enough (extra) funds
} }
newc.grams = ap.remaining_balance.grams - reserve.grams; newc.grams = ap.remaining_balance.grams - reserve.grams;
@ -3813,6 +3816,7 @@ td::Status FetchConfigParams::fetch_config_params(
action_phase_cfg->bounce_on_fail_enabled = config.get_global_version() >= 4; action_phase_cfg->bounce_on_fail_enabled = config.get_global_version() >= 4;
action_phase_cfg->message_skip_enabled = config.get_global_version() >= 8; action_phase_cfg->message_skip_enabled = config.get_global_version() >= 8;
action_phase_cfg->disable_custom_fess = config.get_global_version() >= 8; action_phase_cfg->disable_custom_fess = config.get_global_version() >= 8;
action_phase_cfg->reserve_extra_enabled = config.get_global_version() >= 9;
action_phase_cfg->mc_blackhole_addr = config.get_burning_config().blackhole_addr; action_phase_cfg->mc_blackhole_addr = config.get_burning_config().blackhole_addr;
} }
{ {

View file

@ -169,6 +169,7 @@ struct ActionPhaseConfig {
bool bounce_on_fail_enabled{false}; bool bounce_on_fail_enabled{false};
bool message_skip_enabled{false}; bool message_skip_enabled{false};
bool disable_custom_fess{false}; bool disable_custom_fess{false};
bool reserve_extra_enabled{false};
td::optional<td::Bits256> mc_blackhole_addr; td::optional<td::Bits256> mc_blackhole_addr;
const MsgPrices& fetch_msg_prices(bool is_masterchain) const { const MsgPrices& fetch_msg_prices(bool is_masterchain) const {
return is_masterchain ? fwd_mc : fwd_std; return is_masterchain ? fwd_mc : fwd_std;

View file

@ -153,10 +153,11 @@ td::Ref<vm::Tuple> prepare_vm_c7(SmartContract::Args args, td::Ref<vm::Cell> cod
td::make_refint(0), // actions:Integer td::make_refint(0), // actions:Integer
td::make_refint(0), // msgs_sent:Integer td::make_refint(0), // msgs_sent:Integer
td::make_refint(now), // unixtime:Integer td::make_refint(now), // unixtime:Integer
td::make_refint(0), //TODO: // block_lt:Integer td::make_refint(0), // block_lt:Integer (TODO)
td::make_refint(0), //TODO: // trans_lt:Integer td::make_refint(0), // trans_lt:Integer (TODO)
std::move(rand_seed_int), // rand_seed:Integer std::move(rand_seed_int), // rand_seed:Integer
block::CurrencyCollection(args.balance).as_vm_tuple(), // balance_remaining:[Integer (Maybe Cell)] block::CurrencyCollection(args.balance, args.extra_currencies)
.as_vm_tuple(), // balance_remaining:[Integer (Maybe Cell)]
vm::load_cell_slice_ref(address), // myself:MsgAddressInt vm::load_cell_slice_ref(address), // myself:MsgAddressInt
vm::StackEntry::maybe(config) // vm::StackEntry::maybe(td::Ref<vm::Cell>()) vm::StackEntry::maybe(config) // vm::StackEntry::maybe(td::Ref<vm::Cell>())
}; };

View file

@ -64,6 +64,7 @@ class SmartContract : public td::CntObject {
bool ignore_chksig{false}; bool ignore_chksig{false};
td::uint64 amount{0}; td::uint64 amount{0};
td::uint64 balance{0}; td::uint64 balance{0};
td::Ref<vm::Cell> extra_currencies;
int vm_log_verbosity_level{0}; int vm_log_verbosity_level{0};
bool debug_enabled{false}; bool debug_enabled{false};
@ -121,6 +122,10 @@ class SmartContract : public td::CntObject {
this->balance = balance; this->balance = balance;
return std::move(*this); return std::move(*this);
} }
Args&& set_extra_currencies(td::Ref<vm::Cell> extra_currencies) {
this->extra_currencies = std::move(extra_currencies);
return std::move(*this);
}
Args&& set_address(block::StdAddress address) { Args&& set_address(block::StdAddress address) {
this->address = address; this->address = address;
return std::move(*this); return std::move(*this);

View file

@ -2074,7 +2074,7 @@ void CppTypeCode::generate_skip_field(const Constructor& constr, const Field& fi
output_cpp_expr(ss, expr, 100); output_cpp_expr(ss, expr, 100);
ss << '.'; ss << '.';
} }
ss << "validate_skip_ref(ops, cs, weak)" << tail; ss << "validate_skip_ref(ops, cs, " << (constr.is_special ? "true" : "weak") << ")" << tail;
actions += Action{ss.str()}; actions += Action{ss.str()};
} }

View file

@ -1800,9 +1800,6 @@ void Constructor::show(std::ostream& os, int mode) const {
} }
for (int i = 0; i < type_arity; i++) { for (int i = 0; i < type_arity; i++) {
os << ' '; os << ' ';
if (param_negated.at(i)) {
os << '~';
}
params.at(i)->show(os, this, 100, mode | 1); params.at(i)->show(os, this, 100, mode | 1);
} }
if (!(mode & 2)) { if (!(mode & 2)) {

View file

@ -133,7 +133,13 @@ bool TLB::validate_ref_internal(int* ops, Ref<vm::Cell> cell_ref, bool weak) con
} }
bool is_special; bool is_special;
auto cs = load_cell_slice_special(std::move(cell_ref), is_special); auto cs = load_cell_slice_special(std::move(cell_ref), is_special);
return always_special() ? is_special : (is_special ? weak : (validate_skip(ops, cs) && cs.empty_ext())); if (cs.special_type() == vm::Cell::SpecialType::PrunnedBranch && weak) {
return true;
}
if (always_special() != is_special) {
return false;
}
return validate_skip(ops, cs, weak) && cs.empty_ext();
} }
bool TLB::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const { bool TLB::print_skip(PrettyPrinter& pp, vm::CellSlice& cs) const {

View file

@ -100,9 +100,19 @@ class DynamicBagOfCellsDbImpl : public DynamicBagOfCellsDb, private ExtCellCreat
return get_cell_info_lazy(level_mask, hash, depth).cell; return get_cell_info_lazy(level_mask, hash, depth).cell;
} }
td::Result<Ref<DataCell>> load_cell(td::Slice hash) override { td::Result<Ref<DataCell>> load_cell(td::Slice hash) override {
TRY_RESULT(loaded_cell, get_cell_info_force(hash).cell->load_cell()); auto info = hash_table_.get_if_exists(hash);
if (info && info->sync_with_db) {
TRY_RESULT(loaded_cell, info->cell->load_cell());
return std::move(loaded_cell.data_cell); return std::move(loaded_cell.data_cell);
} }
TRY_RESULT(res, loader_->load(hash, true, *this));
if (res.status != CellLoader::LoadResult::Ok) {
return td::Status::Error("cell not found");
}
Ref<DataCell> cell = res.cell();
hash_table_.apply(hash, [&](CellInfo &info) { update_cell_info_loaded(info, hash, std::move(res)); });
return cell;
}
td::Result<Ref<DataCell>> load_root(td::Slice hash) override { td::Result<Ref<DataCell>> load_root(td::Slice hash) override {
return load_cell(hash); return load_cell(hash);
} }
@ -145,9 +155,6 @@ class DynamicBagOfCellsDbImpl : public DynamicBagOfCellsDb, private ExtCellCreat
promise->set_result(std::move(cell)); promise->set_result(std::move(cell));
}); });
} }
CellInfo &get_cell_info_force(td::Slice hash) {
return hash_table_.apply(hash, [&](CellInfo &info) { update_cell_info_force(info, hash); });
}
CellInfo &get_cell_info_lazy(Cell::LevelMask level_mask, td::Slice hash, td::Slice depth) { CellInfo &get_cell_info_lazy(Cell::LevelMask level_mask, td::Slice hash, td::Slice depth) {
return hash_table_.apply(hash.substr(hash.size() - Cell::hash_bytes), return hash_table_.apply(hash.substr(hash.size() - Cell::hash_bytes),
[&](CellInfo &info) { update_cell_info_lazy(info, level_mask, hash, depth); }); [&](CellInfo &info) { update_cell_info_lazy(info, level_mask, hash, depth); });

View file

@ -1301,7 +1301,7 @@ void register_ton_crypto_ops(OpcodeTable& cp0) {
} }
int exec_compute_data_size(VmState* st, int mode) { int exec_compute_data_size(VmState* st, int mode) {
VM_LOG(st) << (mode & 2 ? 'S' : 'C') << "DATASIZE" << (mode & 1 ? "Q" : ""); VM_LOG(st) << "execute " << (mode & 2 ? 'S' : 'C') << "DATASIZE" << (mode & 1 ? "Q" : "");
Stack& stack = st->get_stack(); Stack& stack = st->get_stack();
stack.check_underflow(2); stack.check_underflow(2);
auto bound = stack.pop_int(); auto bound = stack.pop_int();

View file

@ -129,6 +129,7 @@ Example: if the last masterchain block seqno is `19071` then the list contains b
- Fix `RAWRESERVE` action with flag `4` (use original balance of the account) by explicitly setting `original_balance` to `balance - msg_balance_remaining`. - Fix `RAWRESERVE` action with flag `4` (use original balance of the account) by explicitly setting `original_balance` to `balance - msg_balance_remaining`.
- Previously it did not work if storage fee was greater than the original balance. - Previously it did not work if storage fee was greater than the original balance.
- Jumps to nested continuations of depth more than 8 consume 1 gas for eact subsequent continuation (this does not affect most of TVM code). - Jumps to nested continuations of depth more than 8 consume 1 gas for eact subsequent continuation (this does not affect most of TVM code).
- Support extra currencies in reserve action with `+2` mode.
- Fix exception code in some TVM instructions: now `stk_und` has priority over other error codes. - Fix exception code in some TVM instructions: now `stk_und` has priority over other error codes.
- `PFXDICTADD`, `PFXDICTSET`, `PFXDICTREPLACE`, `PFXDICTDEL`, `GETGASFEE`, `GETSTORAGEFEE`, `GETFORWARDFEE`, `GETORIGINALFWDFEE`, `GETGASFEESIMPLE`, `GETFORWARDFEESIMPLE`, `HASHEXT` - `PFXDICTADD`, `PFXDICTSET`, `PFXDICTREPLACE`, `PFXDICTDEL`, `GETGASFEE`, `GETSTORAGEFEE`, `GETFORWARDFEE`, `GETORIGINALFWDFEE`, `GETGASFEESIMPLE`, `GETFORWARDFEESIMPLE`, `HASHEXT`
- Now setting the contract code to a library cell does not consume additional gas on execution of the code. - Now setting the contract code to a library cell does not consume additional gas on execution of the code.

View file

@ -615,7 +615,7 @@ const char *tvm_emulator_emulate_run_method(uint32_t len, const char *params_boc
emulator->set_vm_verbosity_level(0); emulator->set_vm_verbosity_level(0);
emulator->set_gas_limit(gas_limit); emulator->set_gas_limit(gas_limit);
emulator->set_c7_raw(c7->fetch(0).as_tuple()); emulator->set_c7_raw(c7->fetch(0).as_tuple());
if (libs.is_empty()) { if (!libs.is_empty()) {
emulator->set_libraries(std::move(libs)); emulator->set_libraries(std::move(libs));
} }
auto result = emulator->run_get_method(int(method_id), stack); auto result = emulator->run_get_method(int(method_id), stack);

View file

@ -115,8 +115,9 @@ static size_t get_utf8_from_utf16_length(const jchar *p, jsize len) {
for (jsize i = 0; i < len; i++) { for (jsize i = 0; i < len; i++) {
unsigned int cur = p[i]; unsigned int cur = p[i];
if ((cur & 0xF800) == 0xD800) { if ((cur & 0xF800) == 0xD800) {
++i;
if (i < len) { if (i < len) {
unsigned int next = p[++i]; unsigned int next = p[i];
if ((next & 0xFC00) == 0xDC00 && (cur & 0x400) == 0) { if ((next & 0xFC00) == 0xDC00 && (cur & 0x400) == 0) {
result += 4; result += 4;
continue; continue;

View file

@ -1050,9 +1050,11 @@ class Query {
} }
vm::GasLimits gas_limits = compute_gas_limits(td::make_refint(raw_.source->get_balance()), gas_limits_prices); vm::GasLimits gas_limits = compute_gas_limits(td::make_refint(raw_.source->get_balance()), gas_limits_prices);
auto res = smc.write().send_external_message(raw_.message_body, ton::SmartContract::Args() auto res = smc.write().send_external_message(raw_.message_body,
ton::SmartContract::Args()
.set_limits(gas_limits) .set_limits(gas_limits)
.set_balance(raw_.source->get_balance()) .set_balance(raw_.source->get_balance())
.set_extra_currencies(raw_.source->get_extra_currencies())
.set_now(raw_.source->get_sync_time()) .set_now(raw_.source->get_sync_time())
.set_ignore_chksig(ignore_chksig) .set_ignore_chksig(ignore_chksig)
.set_address(raw_.source->get_address()) .set_address(raw_.source->get_address())
@ -4790,6 +4792,7 @@ td::Status TonlibClient::do_request(const tonlib_api::smc_runGetMethod& request,
} }
args.set_stack(std::move(stack)); args.set_stack(std::move(stack));
args.set_balance(it->second->get_balance()); args.set_balance(it->second->get_balance());
args.set_extra_currencies(it->second->get_extra_currencies());
args.set_now(it->second->get_sync_time()); args.set_now(it->second->get_sync_time());
args.set_address(it->second->get_address()); args.set_address(it->second->get_address());

View file

@ -84,6 +84,19 @@ int main(int argc, char *argv[]) {
TRY_RESULT_PREFIX_ASSIGN(addr_list, ton::adnl::AdnlAddressList::create(addr_list_tl), "bad addr list: "); TRY_RESULT_PREFIX_ASSIGN(addr_list, ton::adnl::AdnlAddressList::create(addr_list_tl), "bad addr list: ");
return td::Status::OK(); return td::Status::OK();
}); });
p.add_checked_option('f', "path to file with addr-list", "addr list to sign", [&](td::Slice key) {
if (addr_list) {
return td::Status::Error("duplicate '-f' option");
}
td::BufferSlice bs(key);
TRY_RESULT_PREFIX(data, td::read_file(key.str()), "failed to read addr-list: ");
TRY_RESULT_PREFIX(as_json_value, td::json_decode(data.as_slice()), "bad addr list JSON: ");
ton::tl_object_ptr<ton::ton_api::adnl_addressList> addr_list_tl;
TRY_STATUS_PREFIX(td::from_json(addr_list_tl, std::move(as_json_value)), "bad addr list TL: ");
TRY_RESULT_PREFIX_ASSIGN(addr_list, ton::adnl::AdnlAddressList::create(addr_list_tl), "bad addr list: ");
return td::Status::OK();
});
p.add_checked_option('i', "network-id", "dht network id (default: -1)", [&](td::Slice key) { p.add_checked_option('i', "network-id", "dht network id (default: -1)", [&](td::Slice key) {
if (network_id_opt) { if (network_id_opt) {
return td::Status::Error("duplicate '-i' option"); return td::Status::Error("duplicate '-i' option");

View file

@ -67,7 +67,8 @@ void WaitBlockState::start() {
if (reading_from_db_) { if (reading_from_db_) {
return; return;
} }
if (handle_->received_state()) { bool inited_proof = handle_->id().is_masterchain() ? handle_->inited_proof() : handle_->inited_proof_link();
if (handle_->received_state() && inited_proof) {
reading_from_db_ = true; reading_from_db_ = true;
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) { auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
@ -107,7 +108,7 @@ void WaitBlockState::start() {
}); });
td::actor::send_closure(manager_, &ValidatorManager::send_get_zero_state_request, handle_->id(), priority_, td::actor::send_closure(manager_, &ValidatorManager::send_get_zero_state_request, handle_->id(), priority_,
std::move(P)); std::move(P));
} else if (check_persistent_state_desc()) { } else if (check_persistent_state_desc() && !handle_->received_state()) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) { auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Ref<ShardState>> R) {
if (R.is_error()) { if (R.is_error()) {
LOG(WARNING) << "failed to get persistent state: " << R.move_as_error(); LOG(WARNING) << "failed to get persistent state: " << R.move_as_error();

View file

@ -346,16 +346,7 @@ void ValidateQuery::start_up() {
// return; // return;
} }
} }
// 2. learn latest masterchain state and block id // 2. load state(s) corresponding to previous block(s)
LOG(DEBUG) << "sending get_top_masterchain_state_block() to Manager";
++pending;
td::actor::send_closure_later(manager, &ValidatorManager::get_top_masterchain_state_block,
[self = get_self()](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
LOG(DEBUG) << "got answer to get_top_masterchain_state_block";
td::actor::send_closure_later(
std::move(self), &ValidateQuery::after_get_latest_mc_state, std::move(res));
});
// 3. load state(s) corresponding to previous block(s)
prev_states.resize(prev_blocks.size()); prev_states.resize(prev_blocks.size());
for (int i = 0; (unsigned)i < prev_blocks.size(); i++) { for (int i = 0; (unsigned)i < prev_blocks.size(); i++) {
// 3.1. load state // 3.1. load state
@ -368,21 +359,13 @@ void ValidateQuery::start_up() {
std::move(self), &ValidateQuery::after_get_shard_state, i, std::move(res)); std::move(self), &ValidateQuery::after_get_shard_state, i, std::move(res));
}); });
} }
// 4. unpack block candidate (while necessary data is being loaded) // 3. unpack block candidate (while necessary data is being loaded)
if (!unpack_block_candidate()) { if (!unpack_block_candidate()) {
reject_query("error unpacking block candidate"); reject_query("error unpacking block candidate");
return; return;
} }
// 5. request masterchain state referred to in the block // 4. request masterchain handle and state referred to in the block
if (!is_masterchain()) { if (!is_masterchain()) {
++pending;
td::actor::send_closure_later(manager, &ValidatorManager::wait_block_state_short, mc_blkid_, priority(), timeout,
[self = get_self()](td::Result<Ref<ShardState>> res) {
LOG(DEBUG) << "got answer to wait_block_state() query for masterchain block";
td::actor::send_closure_later(std::move(self), &ValidateQuery::after_get_mc_state,
std::move(res));
});
// 5.1. request corresponding block handle
++pending; ++pending;
td::actor::send_closure_later(manager, &ValidatorManager::get_block_handle, mc_blkid_, true, td::actor::send_closure_later(manager, &ValidatorManager::get_block_handle, mc_blkid_, true,
[self = get_self()](td::Result<BlockHandle> res) { [self = get_self()](td::Result<BlockHandle> res) {
@ -663,6 +646,19 @@ bool ValidateQuery::extract_collated_data() {
return true; return true;
} }
/**
* Send get_top_masterchain_state_block to manager, call after_get_latest_mc_state afterwards
*/
void ValidateQuery::request_latest_mc_state() {
++pending;
td::actor::send_closure_later(manager, &ValidatorManager::get_top_masterchain_state_block,
[self = get_self()](td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res) {
LOG(DEBUG) << "got answer to get_top_masterchain_state_block";
td::actor::send_closure_later(
std::move(self), &ValidateQuery::after_get_latest_mc_state, std::move(res));
});
}
/** /**
* Callback function called after retrieving the latest masterchain state. * Callback function called after retrieving the latest masterchain state.
* *
@ -710,6 +706,7 @@ void ValidateQuery::after_get_latest_mc_state(td::Result<std::pair<Ref<Mastercha
* @param res The result of the masterchain state retrieval. * @param res The result of the masterchain state retrieval.
*/ */
void ValidateQuery::after_get_mc_state(td::Result<Ref<ShardState>> res) { void ValidateQuery::after_get_mc_state(td::Result<Ref<ShardState>> res) {
CHECK(!is_masterchain());
LOG(WARNING) << "in ValidateQuery::after_get_mc_state() for " << mc_blkid_.to_str(); LOG(WARNING) << "in ValidateQuery::after_get_mc_state() for " << mc_blkid_.to_str();
--pending; --pending;
if (res.is_error()) { if (res.is_error()) {
@ -720,6 +717,7 @@ void ValidateQuery::after_get_mc_state(td::Result<Ref<ShardState>> res) {
fatal_error("cannot process masterchain state for "s + mc_blkid_.to_str()); fatal_error("cannot process masterchain state for "s + mc_blkid_.to_str());
return; return;
} }
request_latest_mc_state();
if (!pending) { if (!pending) {
if (!try_validate()) { if (!try_validate()) {
fatal_error("cannot validate new block"); fatal_error("cannot validate new block");
@ -734,17 +732,21 @@ void ValidateQuery::after_get_mc_state(td::Result<Ref<ShardState>> res) {
*/ */
void ValidateQuery::got_mc_handle(td::Result<BlockHandle> res) { void ValidateQuery::got_mc_handle(td::Result<BlockHandle> res) {
LOG(DEBUG) << "in ValidateQuery::got_mc_handle() for " << mc_blkid_.to_str(); LOG(DEBUG) << "in ValidateQuery::got_mc_handle() for " << mc_blkid_.to_str();
--pending;
if (res.is_error()) { if (res.is_error()) {
fatal_error(res.move_as_error()); fatal_error(res.move_as_error());
return; return;
} }
auto handle = res.move_as_ok(); auto mc_handle = res.move_as_ok();
if (!handle->inited_proof() && mc_blkid_.seqno()) { td::actor::send_closure_later(
fatal_error(-666, "reference masterchain block "s + mc_blkid_.to_str() + " for block " + id_.to_str() + manager, &ValidatorManager::wait_block_state, mc_handle, priority(), timeout,
" does not have a valid proof"); [self = get_self(), id = id_, mc_handle](td::Result<Ref<ShardState>> res) {
return; LOG(DEBUG) << "got answer to wait_block_state() query for masterchain block";
if (res.is_ok() && mc_handle->id().seqno() > 0 && !mc_handle->inited_proof()) {
res = td::Status::Error(-666, "reference masterchain block "s + mc_handle->id().to_str() + " for block " +
id.to_str() + " does not have a valid proof");
} }
td::actor::send_closure_later(std::move(self), &ValidateQuery::after_get_mc_state, std::move(res));
});
} }
/** /**
@ -778,6 +780,9 @@ void ValidateQuery::after_get_shard_state(int idx, td::Result<Ref<ShardState>> r
return; return;
} }
} }
if (is_masterchain()) {
request_latest_mc_state();
}
if (!pending) { if (!pending) {
if (!try_validate()) { if (!try_validate()) {
fatal_error("cannot validate new block"); fatal_error("cannot validate new block");
@ -997,6 +1002,7 @@ bool ValidateQuery::fetch_config_params() {
action_phase_cfg_.bounce_on_fail_enabled = config_->get_global_version() >= 4; action_phase_cfg_.bounce_on_fail_enabled = config_->get_global_version() >= 4;
action_phase_cfg_.message_skip_enabled = config_->get_global_version() >= 8; action_phase_cfg_.message_skip_enabled = config_->get_global_version() >= 8;
action_phase_cfg_.disable_custom_fess = config_->get_global_version() >= 8; action_phase_cfg_.disable_custom_fess = config_->get_global_version() >= 8;
action_phase_cfg_.reserve_extra_enabled = config_->get_global_version() >= 9;
action_phase_cfg_.mc_blackhole_addr = config_->get_burning_config().blackhole_addr; action_phase_cfg_.mc_blackhole_addr = config_->get_burning_config().blackhole_addr;
} }
{ {

View file

@ -284,6 +284,7 @@ class ValidateQuery : public td::actor::Actor {
return actor_id(this); return actor_id(this);
} }
void request_latest_mc_state();
void after_get_latest_mc_state(td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res); void after_get_latest_mc_state(td::Result<std::pair<Ref<MasterchainState>, BlockIdExt>> res);
void after_get_mc_state(td::Result<Ref<ShardState>> res); void after_get_mc_state(td::Result<Ref<ShardState>> res);
void got_mc_handle(td::Result<BlockHandle> res); void got_mc_handle(td::Result<BlockHandle> res);

View file

@ -1343,7 +1343,7 @@ void ValidatorManagerImpl::written_handle(BlockHandle handle, td::Promise<td::Un
td::actor::send_closure(it->second.actor_, &WaitBlockData::force_read_from_db); td::actor::send_closure(it->second.actor_, &WaitBlockData::force_read_from_db);
} }
} }
if (inited_state) { if (inited_state && inited_proof) {
auto it = wait_state_.find(handle->id()); auto it = wait_state_.find(handle->id());
if (it != wait_state_.end()) { if (it != wait_state_.end()) {
td::actor::send_closure(it->second.actor_, &WaitBlockState::force_read_from_db); td::actor::send_closure(it->second.actor_, &WaitBlockState::force_read_from_db);