diff --git a/crypto/block/block-parse.cpp b/crypto/block/block-parse.cpp index 50851c79..7eb74101 100644 --- a/crypto/block/block-parse.cpp +++ b/crypto/block/block-parse.cpp @@ -738,7 +738,7 @@ const TickTock t_TickTock; const RefAnything t_RefCell; bool StateInit::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const { - return Maybe{5}.validate_skip(ops, cs, weak) // split_depth:(Maybe (## 5)) + return Maybe{5}.validate_skip(ops, cs, weak) // fixed_prefix_length:(Maybe (## 5)) && Maybe{}.validate_skip(ops, cs, weak) // special:(Maybe TickTock) && Maybe{}.validate_skip(ops, cs, weak) // code:(Maybe ^Cell) && Maybe{}.validate_skip(ops, cs, weak) // data:(Maybe ^Cell) @@ -1085,7 +1085,7 @@ bool Account::skip_copy_depth_balance(vm::CellBuilder& cb, vm::CellSlice& cs) co case account: return cs.advance(1) // account$1 && t_MsgAddressInt.skip_get_depth(cs, depth) // addr:MsgAddressInt - && cb.store_uint_leq(30, depth) // -> store split_depth:(#<= 30) + && cb.store_uint_leq(30, depth) // -> store fixed_prefix_length:(#<= 30) && t_StorageInfo.skip(cs) // storage_stat:StorageInfo && t_AccountStorage.skip_copy_balance(cb, cs); // storage:AccountStorage } @@ -1230,13 +1230,14 @@ bool HashmapAugE::extract_extra(vm::CellSlice& cs) const { bool DepthBalanceInfo::skip(vm::CellSlice& cs) const { return cs.advance(5) && t_CurrencyCollection.skip( - cs); // depth_balance$_ split_depth:(#<= 30) balance:CurrencyCollection = DepthBalanceInfo; + cs); // depth_balance$_ fixed_prefix_length:(#<= 30) balance:CurrencyCollection = DepthBalanceInfo; } 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 + t_CurrencyCollection.validate_skip( + ops, cs, + weak); // depth_balance$_ fixed_prefix_length:(#<= 30) balance:CurrencyCollection } bool DepthBalanceInfo::null_value(vm::CellBuilder& cb) const { diff --git a/crypto/block/block.tlb b/crypto/block/block.tlb index 4a8bbc06..583ac599 100644 --- a/crypto/block/block.tlb +++ b/crypto/block/block.tlb @@ -141,12 +141,12 @@ ext_out_msg_info$11 src:MsgAddress dest:MsgAddressExt tick_tock$_ tick:Bool tock:Bool = TickTock; -_ split_depth:(Maybe (## 5)) special:(Maybe TickTock) +_ fixed_prefix_length:(Maybe (## 5)) special:(Maybe TickTock) code:(Maybe ^Cell) data:(Maybe ^Cell) library:(Maybe ^Cell) = StateInit; // StateInitWithLibs is used to validate sent and received messages -_ split_depth:(Maybe (## 5)) special:(Maybe TickTock) +_ fixed_prefix_length:(Maybe (## 5)) special:(Maybe TickTock) code:(Maybe ^Cell) data:(Maybe ^Cell) library:(HashmapE 256 SimpleLib) = StateInitWithLibs; @@ -273,14 +273,6 @@ acc_state_frozen$01 = AccountStatus; acc_state_active$10 = AccountStatus; acc_state_nonexist$11 = AccountStatus; -/* duplicates -tick_tock$_ tick:Bool tock:Bool = TickTock; - -_ split_depth:(Maybe (## 5)) special:(Maybe TickTock) - code:(Maybe ^Cell) data:(Maybe ^Cell) - library:(Maybe ^Cell) = StateInit; -*/ - account_descr$_ account:^Account last_trans_hash:bits256 last_trans_lt:uint64 = ShardAccount; @@ -801,7 +793,8 @@ size_limits_config#01 max_msg_bits:uint32 max_msg_cells:uint32 max_library_cells max_ext_msg_size:uint32 max_ext_msg_depth:uint16 = SizeLimitsConfig; size_limits_config_v2#02 max_msg_bits:uint32 max_msg_cells:uint32 max_library_cells:uint32 max_vm_data_depth:uint16 max_ext_msg_size:uint32 max_ext_msg_depth:uint16 max_acc_state_cells:uint32 max_acc_state_bits:uint32 - max_acc_public_libraries:uint32 defer_out_queue_size_limit:uint32 max_msg_extra_currencies:uint32 = SizeLimitsConfig; + max_acc_public_libraries:uint32 defer_out_queue_size_limit:uint32 max_msg_extra_currencies:uint32 + max_acc_fixed_prefix_length:uint8 = SizeLimitsConfig; _ SizeLimitsConfig = ConfigParam 43; // key is [ wc:int32 addr:uint256 ] diff --git a/crypto/block/create-state.cpp b/crypto/block/create-state.cpp index c8c8b970..962d98b8 100644 --- a/crypto/block/create-state.cpp +++ b/crypto/block/create-state.cpp @@ -94,12 +94,12 @@ typedef td::BitArray<256> hash_t; struct SmcDescr { hash_t addr; - int split_depth; + int fixed_prefix_length; bool preinit_only; td::RefInt256 gram_balance; Ref state_init; // StateInit Ref account; // Account - SmcDescr(const hash_t& _addr) : addr(_addr), split_depth(0), preinit_only(false) { + SmcDescr(const hash_t& _addr) : addr(_addr), fixed_prefix_length(0), preinit_only(false) { } }; @@ -123,7 +123,7 @@ vm::Dictionary config_dict{32}; ton::UnixTime now; bool set_config_smc(const SmcDescr& smc) { - if (config_addr_set || smc.preinit_only || workchain_id != wc_master || smc.split_depth) { + if (config_addr_set || smc.preinit_only || workchain_id != wc_master || smc.fixed_prefix_length) { return false; } vm::CellSlice cs = load_cell_slice(smc.state_init); @@ -221,7 +221,7 @@ bool add_public_library(hash_t lib_addr, hash_t smc_addr, Ref lib_root } td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref code, Ref data, - Ref library, td::RefInt256 balance, int special, int split_depth, + Ref library, td::RefInt256 balance, int special, int fixed_prefix_length, int mode) { if (is_empty_cell(code)) { code.clear(); @@ -238,12 +238,12 @@ td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref code, R THRERR("not a valid library collection"); } vm::CellBuilder cb; - if (!split_depth) { + if (!fixed_prefix_length) { PDO(cb.store_long_bool(0, 1)); } else { - PDO(cb.store_long_bool(1, 1) && cb.store_ulong_rchk_bool(split_depth, 5)); + PDO(cb.store_long_bool(1, 1) && cb.store_ulong_rchk_bool(fixed_prefix_length, 5)); } - THRERR("invalid split_depth for a smart contract"); + THRERR("invalid fixed_prefix_length for a smart contract"); if (!special) { PDO(cb.store_long_bool(0, 1)); } else { @@ -287,7 +287,7 @@ td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref code, R auto ins = smart_contracts.emplace(addr, addr); assert(ins.second); SmcDescr& smc = ins.first->second; - smc.split_depth = split_depth; + smc.fixed_prefix_length = fixed_prefix_length; smc.preinit_only = (mode == 1); smc.gram_balance = balance; total_smc_balance += balance; @@ -328,10 +328,10 @@ td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref code, R ctor = 2; // addr_std$10 } PDO(cb.store_long_bool(ctor, 2)); // addr_std$10 or addr_var$11 - if (split_depth) { + if (fixed_prefix_length) { PDO(cb.store_long_bool(1, 1) // just$1 - && cb.store_ulong_rchk_bool(split_depth, 5) // depth:(## 5) - && cb.store_bits_bool(addr.cbits(), split_depth)); // rewrite pfx:(depth * Bit) + && cb.store_ulong_rchk_bool(fixed_prefix_length, 5) // depth:(## 5) + && cb.store_bits_bool(addr.cbits(), fixed_prefix_length)); // rewrite pfx:(depth * Bit) } else { PDO(cb.store_long_bool(0, 1)); // nothing$0 } @@ -514,7 +514,7 @@ Ref create_state() { // data (cell) // library (cell) // balance (int) -// split_depth (int 0..32) +// fixed_prefix_length (int 0..32) // special (int 0..3, +2 = tick, +1 = tock) // [ address (uint256) ] // mode (0 = compute address only, 1 = create uninit, 2 = create complete; +4 = with specified address) @@ -536,7 +536,7 @@ void interpret_register_smartcontract(vm::Stack& stack) { if (special && workchain_id != wc_master) { throw fift::IntError{"cannot create special smartcontracts outside of the masterchain"}; } - int split_depth = stack.pop_smallint_range(32); + int fixed_prefix_length = stack.pop_smallint_range(32); td::RefInt256 balance = stack.pop_int_finite(); if (sgn(balance) < 0) { throw fift::IntError{"initial balance of a smartcontract cannot be negative"}; @@ -548,7 +548,7 @@ void interpret_register_smartcontract(vm::Stack& stack) { Ref data = stack.pop_cell(); Ref code = stack.pop_cell(); td::RefInt256 addr = create_smartcontract(std::move(spec_addr), std::move(code), std::move(data), std::move(library), - std::move(balance), special, split_depth, mode); + std::move(balance), special, fixed_prefix_length, mode); if (addr.is_null()) { throw fift::IntError{"internal error while creating smartcontract"}; } diff --git a/crypto/block/mc-config.cpp b/crypto/block/mc-config.cpp index 0f019b06..e98c1071 100644 --- a/crypto/block/mc-config.cpp +++ b/crypto/block/mc-config.cpp @@ -1961,6 +1961,7 @@ td::Result Config::do_get_size_limits_config(td::Ref 30) { - return false; // invalid value for split_depth +bool Account::set_addr_rewrite_length(int new_length) { + if (new_length < 0 || new_length > 30) { + return false; // invalid value } - if (split_depth_set_) { - return split_depth_ == new_split_depth; + if (addr_rewrite_length_set) { + return addr_rewrite_length == new_length; } else { - split_depth_ = (unsigned char)new_split_depth; - split_depth_set_ = true; + addr_rewrite_length = (unsigned char)new_length; + addr_rewrite_length_set = true; return true; } } /** - * Checks if the given split depth is valid for the Account. + * Checks if the given addr rewrite length is valid for the Account. * - * @param split_depth The split depth to be checked. + * @param length The addr rewrite length to be checked. * - * @returns True if the split depth is valid, False otherwise. + * @returns True if the addr rewrite length is valid, False otherwise. */ -bool Account::check_split_depth(int split_depth) const { - return split_depth_set_ ? (split_depth == split_depth_) : (split_depth >= 0 && split_depth <= 30); +bool Account::check_addr_rewrite_length(int length) const { + return addr_rewrite_length_set ? (length == addr_rewrite_length) : (length >= 0 && length <= 30); } /** * Parses anycast data of the account address. * - * Initializes split_depth and addr_rewrite. + * Initializes addr_rewrite. * - * @param cs The cell slice containing partially-parsed account addressa. + * @param cs The cell slice containing partially-parsed account address. * * @returns True if parsing was successful, false otherwise. */ @@ -159,13 +159,13 @@ bool Account::parse_maybe_anycast(vm::CellSlice& cs) { if (t < 0) { return false; } else if (!t) { - return set_split_depth(0); + return set_addr_rewrite_length(0); } int depth; return cs.fetch_uint_leq(30, depth) // anycast_info$_ depth:(#<= 30) && depth // { depth >= 1 } && cs.fetch_bits_to(addr_rewrite.bits(), depth) // rewrite_pfx:(bits depth) - && set_split_depth(depth); + && set_addr_rewrite_length(depth); } /** @@ -176,12 +176,12 @@ bool Account::parse_maybe_anycast(vm::CellSlice& cs) { * @returns True if the anycast information was successfully stored, false otherwise. */ bool Account::store_maybe_anycast(vm::CellBuilder& cb) const { - if (!split_depth_set_ || !split_depth_) { + if (!addr_rewrite_length_set || !addr_rewrite_length) { return cb.store_bool_bool(false); } return cb.store_bool_bool(true) // just$1 - && cb.store_uint_leq(30, split_depth_) // depth:(#<= 30) - && cb.store_bits_bool(addr_rewrite.cbits(), split_depth_); // rewrite_pfx:(bits depth) + && cb.store_uint_leq(30, addr_rewrite_length) // depth:(#<= 30) + && cb.store_bits_bool(addr_rewrite.cbits(), addr_rewrite_length); // rewrite_pfx:(bits depth) } /** @@ -214,14 +214,14 @@ bool Account::unpack_address(vm::CellSlice& addr_cs) { if (workchain == ton::workchainInvalid) { workchain = new_wc; addr = addr_orig; - addr.bits().copy_from(addr_rewrite.cbits(), split_depth_); - } else if (split_depth_) { + addr.bits().copy_from(addr_rewrite.cbits(), addr_rewrite_length); + } else if (addr_rewrite_length) { ton::StdSmcAddress new_addr = addr_orig; - new_addr.bits().copy_from(addr_rewrite.cbits(), split_depth_); + new_addr.bits().copy_from(addr_rewrite.cbits(), addr_rewrite_length); if (new_addr != addr) { LOG(ERROR) << "error unpacking account " << workchain << ":" << addr.to_hex() << " : account header contains different address " << new_addr.to_hex() << " (with splitting depth " - << (int)split_depth_ << ")"; + << (int)addr_rewrite_length << ")"; return false; } } else if (addr != addr_orig) { @@ -235,7 +235,7 @@ bool Account::unpack_address(vm::CellSlice& addr_cs) { return false; } addr_rewrite = addr.bits(); // initialize all 32 bits of addr_rewrite - if (!split_depth_) { + if (!addr_rewrite_length) { my_addr_exact = my_addr; } return true; @@ -280,7 +280,7 @@ bool Account::unpack_storage_info(vm::CellSlice& cs) { * Unpacks the state of an Account from a CellSlice. * * State is serialized using StateInit TLB-scheme. - * Initializes split_depth (from account state - StateInit) + * Initializes fixed_prefix_length (from account state - StateInit) * * @param cs The CellSlice containing the serialized state. * @@ -291,12 +291,9 @@ bool Account::unpack_state(vm::CellSlice& cs) { if (!tlb::unpack_exact(cs, state)) { return false; } - int sd = 0; - if (state.split_depth->size() == 6) { - sd = (int)state.split_depth->prefetch_ulong(6) - 32; - } - if (!set_split_depth(sd)) { - return false; + fixed_prefix_length = 0; + if (state.fixed_prefix_length->size() == 6) { + fixed_prefix_length = (int)state.fixed_prefix_length->prefetch_ulong(6) - 32; } if (state.special->size() > 1) { int z = (int)state.special->prefetch_ulong(3); @@ -363,23 +360,25 @@ bool Account::compute_my_addr(bool force) { /** * Computes the address of the Account. * + * Legacy (used only if global_version < 10). + * * @param tmp_addr A reference to the CellSlice for the result. - * @param split_depth The split depth for the address. - * @param orig_addr_rewrite Address prefox of length split_depth. + * @param fixed_prefix_length The fixed prefix length for the address. + * @param orig_addr_rewrite Address prefix of length fixed_prefix_length. * * @returns True if the address was successfully computed, false otherwise. */ -bool Account::recompute_tmp_addr(Ref& tmp_addr, int split_depth, +bool Account::recompute_tmp_addr(Ref& tmp_addr, int fixed_prefix_length, td::ConstBitPtr orig_addr_rewrite) const { - if (!split_depth && my_addr_exact.not_null()) { + if (!fixed_prefix_length && my_addr_exact.not_null()) { tmp_addr = my_addr_exact; return true; } - if (split_depth == split_depth_ && my_addr.not_null()) { + if (fixed_prefix_length == addr_rewrite_length && my_addr.not_null()) { tmp_addr = my_addr; return true; } - if (split_depth < 0 || split_depth > 30) { + if (fixed_prefix_length < 0 || fixed_prefix_length > 30) { return false; } vm::CellBuilder cb; @@ -387,13 +386,13 @@ bool Account::recompute_tmp_addr(Ref& tmp_addr, int split_depth, if (!cb.store_long_bool(std ? 2 : 3, 2)) { // addr_std$10 or addr_var$11 return false; } - if (!split_depth) { + if (!fixed_prefix_length) { if (!cb.store_bool_bool(false)) { // anycast:(Maybe Anycast) return false; } } else if (!(cb.store_bool_bool(true) // just$1 - && cb.store_long_bool(split_depth, 5) // depth:(#<= 30) - && cb.store_bits_bool(addr.bits(), split_depth))) { // rewrite_pfx:(bits depth) + && cb.store_long_bool(fixed_prefix_length, 5) // depth:(#<= 30) + && cb.store_bits_bool(addr.bits(), fixed_prefix_length))) { // rewrite_pfx:(bits depth) return false; } if (std) { @@ -405,26 +404,26 @@ bool Account::recompute_tmp_addr(Ref& tmp_addr, int split_depth, return false; } Ref cell; - return cb.store_bits_bool(orig_addr_rewrite, split_depth) // address:(bits addr_len) or bits256 - && cb.store_bits_bool(addr.bits() + split_depth, 256 - split_depth) && cb.finalize_to(cell) && + return cb.store_bits_bool(orig_addr_rewrite, fixed_prefix_length) // address:(bits addr_len) or bits256 + && cb.store_bits_bool(addr.bits() + fixed_prefix_length, 256 - fixed_prefix_length) && cb.finalize_to(cell) && (tmp_addr = vm::load_cell_slice_ref(std::move(cell))).not_null(); } /** * Sets address rewriting info for a newly-activated account. * - * @param split_depth The split depth for the account address. - * @param orig_addr_rewrite Address frepix of length split_depth. + * @param rewrite_length The fixed prefix length for the account address. + * @param orig_addr_rewrite Address prefix of length fixed_prefix_length. * * @returns True if the rewriting info was successfully set, false otherwise. */ -bool Account::init_rewrite_addr(int split_depth, td::ConstBitPtr orig_addr_rewrite) { - if (split_depth_set_ || !set_split_depth(split_depth)) { +bool Account::init_rewrite_addr(int rewrite_length, td::ConstBitPtr orig_addr_rewrite) { + if (addr_rewrite_length_set || !set_addr_rewrite_length(rewrite_length)) { return false; } addr_orig = addr; addr_rewrite = addr.bits(); - addr_orig.bits().copy_from(orig_addr_rewrite, split_depth); + addr_orig.bits().copy_from(orig_addr_rewrite, rewrite_length); return compute_my_addr(true); } @@ -480,7 +479,7 @@ bool Account::unpack(Ref shard_account, ton::UnixTime now, bool s case block::gen::AccountState::account_uninit: status = orig_status = acc_uninit; state_hash = addr; - forget_split_depth(); + forget_addr_rewrite_length(); break; case block::gen::AccountState::account_frozen: status = orig_status = acc_frozen; @@ -554,18 +553,18 @@ bool Account::init_new(ton::UnixTime now) { } state_hash = addr_orig; status = orig_status = acc_nonexist; - split_depth_set_ = false; + addr_rewrite_length_set = false; return true; } /** - * Resets the split depth of the account. + * Resets the fixed prefix length of the account. * - * @returns True if the split depth was successfully reset, false otherwise. + * @returns True if the fixed prefix length was successfully reset, false otherwise. */ -bool Account::forget_split_depth() { - split_depth_set_ = false; - split_depth_ = 0; +bool Account::forget_addr_rewrite_length() { + addr_rewrite_length_set = false; + addr_rewrite_length = 0; addr_orig = addr; my_addr = my_addr_exact; addr_rewrite = addr.bits(); @@ -583,9 +582,10 @@ bool Account::deactivate() { } // forget special (tick/tock) info tick = tock = false; + fixed_prefix_length = 0; if (status == acc_nonexist || status == acc_uninit) { - // forget split depth and address rewriting info - forget_split_depth(); + // forget fixed prefix length and address rewriting info + forget_addr_rewrite_length(); // forget specific state hash for deleted or uninitialized accounts (revert to addr) state_hash = addr; } @@ -706,6 +706,7 @@ Transaction::Transaction(const Account& _account, int ttype, ton::LogicalTime re , is_first(_account.transactions.empty()) , new_tick(_account.tick) , new_tock(_account.tock) + , new_fixed_prefix_length(_account.fixed_prefix_length) , now(_now) , account(_account) , my_addr(_account.my_addr) @@ -782,6 +783,18 @@ bool Transaction::unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* } src_addr = std::move(info.src); dest_addr = std::move(info.dest); + if (cfg->disable_anycast) { + // Check that dest is addr_std without anycast + block::gen::MsgAddressInt::Record_addr_std rec; + if (!block::gen::csr_unpack(dest_addr, rec)) { + LOG(DEBUG) << "destination address of the external message is not a valid addr_std"; + return false; + } + if (rec.anycast->size() > 1) { + LOG(DEBUG) << "destination address of the external message is an anycast address"; + return false; + } + } in_msg_type = 2; in_msg_extern = true; // compute forwarding fees for this external message @@ -1438,10 +1451,13 @@ bool Transaction::unpack_msg_state(const ComputePhaseConfig& cfg, bool lib_only, in_msg_library = state.library->prefetch_ref(); return true; } - if (state.split_depth->size() == 6) { - new_split_depth = (signed char)(state.split_depth->prefetch_ulong(6) - 32); + if (state.fixed_prefix_length->size() == 6) { + new_fixed_prefix_length = (signed char)(state.fixed_prefix_length->prefetch_ulong(6) - 32); } else { - new_split_depth = 0; + new_fixed_prefix_length = 0; + } + if (!cfg.disable_anycast) { + new_addr_rewrite_length = new_fixed_prefix_length; } if (state.special->size() > 1) { int z = (int)state.special->prefetch_ulong(3); @@ -1496,19 +1512,26 @@ std::vector> Transaction::compute_vm_libraries(const ComputePhaseC /** * Checks if the input message StateInit hash corresponds to the account address. * + * @param cfg The configuration for the compute phase. + * * @returns True if the input message state hash is valid, False otherwise. */ -bool Transaction::check_in_msg_state_hash() { +bool Transaction::check_in_msg_state_hash(const ComputePhaseConfig& cfg) { CHECK(in_msg_state.not_null()); - CHECK(new_split_depth >= 0 && new_split_depth < 32); + CHECK(new_fixed_prefix_length >= 0 && new_fixed_prefix_length < 32); td::Bits256 in_state_hash = in_msg_state->get_hash().bits(); - int d = new_split_depth; + int d = new_fixed_prefix_length; if ((in_state_hash.bits() + d).compare(account.addr.bits() + d, 256 - d)) { return false; } orig_addr_rewrite = in_state_hash.bits(); orig_addr_rewrite_set = true; - return account.recompute_tmp_addr(my_addr, d, orig_addr_rewrite.bits()); + if (cfg.disable_anycast) { + my_addr = my_addr_exact; + return true; + } else { + return account.recompute_tmp_addr(my_addr, d, orig_addr_rewrite.bits()); + } } /** @@ -1639,16 +1662,24 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) { use_msg_state = true; bool forbid_public_libs = acc_status == Account::acc_uninit && account.is_masterchain(); // Forbid for deploying, allow for unfreezing - if (!(unpack_msg_state(cfg, false, forbid_public_libs) && account.check_split_depth(new_split_depth))) { - LOG(DEBUG) << "cannot unpack in_msg_state, or it has bad split_depth; cannot init account state"; + if (!(unpack_msg_state(cfg, false, forbid_public_libs) && + account.check_addr_rewrite_length(new_fixed_prefix_length))) { + LOG(DEBUG) << "cannot unpack in_msg_state, or it has bad fixed_prefix_length; cannot init account state"; cp.skip_reason = ComputePhase::sk_bad_state; return true; } - if (acc_status == Account::acc_uninit && !check_in_msg_state_hash()) { + if (acc_status == Account::acc_uninit && !check_in_msg_state_hash(cfg)) { LOG(DEBUG) << "in_msg_state hash mismatch, cannot init account state"; cp.skip_reason = ComputePhase::sk_bad_state; return true; } + if (cfg.disable_anycast && acc_status == Account::acc_uninit && + new_fixed_prefix_length > cfg.size_limits.max_acc_fixed_prefix_length) { + LOG(DEBUG) << "cannot init account state: too big fixed prefix length (" << new_fixed_prefix_length << ", max " + << cfg.size_limits.max_acc_fixed_prefix_length << ")"; + cp.skip_reason = ComputePhase::sk_bad_state; + return true; + } } else if (acc_status != Account::acc_active) { // no state, cannot perform transactions cp.skip_reason = in_msg_state.not_null() ? ComputePhase::sk_bad_state : ComputePhase::sk_no_state; @@ -1671,6 +1702,11 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) { return true; } } + if (cfg.disable_anycast) { + my_addr = my_addr_exact; + new_addr_rewrite_length = 0; + force_remove_anycast_address = true; + } td::optional precompiled; if (new_code.not_null() && trans_type == tr_ord) { @@ -2237,11 +2273,12 @@ bool Transaction::check_replace_src_addr(Ref& src_addr) const { * @param dest_addr A reference to the destination address of the transaction. * @param cfg The configuration for the action phase. * @param is_mc A pointer to a boolean where it will be stored whether the destination is in the masterchain. + * @param allow_anycast Allow anycast the address. * * @returns True if the destination address is valid, false otherwise. */ bool Transaction::check_rewrite_dest_addr(Ref& dest_addr, const ActionPhaseConfig& cfg, - bool* is_mc) const { + bool* is_mc, bool allow_anycast) const { if (!dest_addr->prefetch_ulong(1)) { // all external addresses allowed if (is_mc) { @@ -2301,6 +2338,9 @@ bool Transaction::check_rewrite_dest_addr(Ref& dest_addr, const A } } if (rec.anycast->size() > 1) { + if (!allow_anycast) { + return false; + } // destination address is an anycast vm::CellSlice cs{*rec.anycast}; int d = (int)cs.fetch_ulong(6) - 32; @@ -2468,7 +2508,7 @@ int Transaction::try_action_send_msg(const vm::CellSlice& cs0, ActionPhase& ap, return 35; // invalid source address } bool to_mc = false; - if (!check_rewrite_dest_addr(info.dest, cfg, &to_mc)) { + if (!check_rewrite_dest_addr(info.dest, cfg, &to_mc, !cfg.disable_anycast)) { LOG(DEBUG) << "invalid destination address in a proposed outbound message"; return check_skip_invalid(36); // invalid destination address } @@ -3240,13 +3280,14 @@ bool Transaction::compute_state(const SerializeConfig& cfg) { && balance.store(cb)); // balance:CurrencyCollection int ticktock = new_tick * 2 + new_tock; unsigned si_pos = 0; + int fixed_prefix_length = cfg.disable_anycast ? new_fixed_prefix_length : account.addr_rewrite_length; if (acc_status == Account::acc_uninit) { CHECK(cb.store_long_bool(0, 2)); // account_uninit$00 = AccountState } else if (acc_status == Account::acc_frozen) { if (was_frozen) { vm::CellBuilder cb2; - CHECK(account.split_depth_ ? cb2.store_long_bool(account.split_depth_ + 32, 6) // _ ... = StateInit - : cb2.store_long_bool(0, 1)); // ... split_depth:(Maybe (## 5)) + CHECK(fixed_prefix_length ? cb2.store_long_bool(fixed_prefix_length + 32, 6) // _ ... = StateInit + : cb2.store_long_bool(0, 1)); // ... fixed_prefix_length:(Maybe (## 5)) CHECK(ticktock ? cb2.store_long_bool(ticktock | 4, 3) : cb2.store_long_bool(0, 1)); // special:(Maybe TickTock) CHECK(cb2.store_maybe_ref(new_code) && cb2.store_maybe_ref(new_data) && cb2.store_maybe_ref(new_library)); // code:(Maybe ^Cell) data:(Maybe ^Cell) library:(HashmapE 256 SimpleLib) @@ -3275,8 +3316,8 @@ bool Transaction::compute_state(const SerializeConfig& cfg) { } else { CHECK(acc_status == Account::acc_active && !was_frozen && !was_deleted); si_pos = cb.size_ext() + 1; - CHECK(account.split_depth_ ? cb.store_long_bool(account.split_depth_ + 96, 7) // account_active$1 _:StateInit - : cb.store_long_bool(2, 2)); // ... split_depth:(Maybe (## 5)) + CHECK(fixed_prefix_length ? cb.store_long_bool(fixed_prefix_length + 96, 7) // account_active$1 _:StateInit + : cb.store_long_bool(2, 2)); // ... fixed_prefix_length:(Maybe (## 5)) CHECK(ticktock ? cb.store_long_bool(ticktock | 4, 3) : cb.store_long_bool(0, 1)); // special:(Maybe TickTock) CHECK(cb.store_maybe_ref(new_code) && cb.store_maybe_ref(new_data) && cb.store_maybe_ref(new_library)); // code:(Maybe ^Cell) data:(Maybe ^Cell) library:(HashmapE 256 SimpleLib) @@ -3316,8 +3357,8 @@ bool Transaction::compute_state(const SerializeConfig& cfg) { LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s"; } } - CHECK(cb.store_long_bool(1, 1) // account$1 - && cb.append_cellslice_bool(account.my_addr) // addr:MsgAddressInt + CHECK(cb.store_long_bool(1, 1) // account$1 + && cb.append_cellslice_bool(cfg.disable_anycast ? my_addr : account.my_addr) // addr:MsgAddressInt && block::store_UInt7(cb, stats.cells) // storage_used$_ cells:(VarUInteger 7) && block::store_UInt7(cb, stats.bits) // bits:(VarUInteger 7) && block::store_UInt7(cb, stats.public_cells) // public_cells:(VarUInteger 7) @@ -3676,12 +3717,14 @@ Ref Transaction::commit(Account& acc) { CHECK((const void*)&acc == (const void*)&account); // export all fields modified by the Transaction into original account // NB: this is the only method that modifies account - if (orig_addr_rewrite_set && new_split_depth >= 0 && acc.status != Account::acc_active && + if (force_remove_anycast_address) { + CHECK(acc.forget_addr_rewrite_length()); + } else if (orig_addr_rewrite_set && new_addr_rewrite_length >= 0 && acc.status != Account::acc_active && acc_status == Account::acc_active) { LOG(DEBUG) << "setting address rewriting info for newly-activated account " << acc.addr.to_hex() - << " with split_depth=" << new_split_depth - << ", orig_addr_rewrite=" << orig_addr_rewrite.bits().to_hex(new_split_depth); - CHECK(acc.init_rewrite_addr(new_split_depth, orig_addr_rewrite.bits())); + << " with addr_rewrite_length=" << new_addr_rewrite_length + << ", orig_addr_rewrite=" << orig_addr_rewrite.bits().to_hex(new_addr_rewrite_length); + CHECK(acc.init_rewrite_addr(new_addr_rewrite_length, orig_addr_rewrite.bits())); } acc.status = (acc_status == Account::acc_deleted ? Account::acc_nonexist : acc_status); acc.last_trans_lt_ = start_lt; @@ -3705,6 +3748,7 @@ Ref Transaction::commit(Account& acc) { if (acc.status == Account::acc_active) { acc.tick = new_tick; acc.tock = new_tock; + acc.fixed_prefix_length = new_fixed_prefix_length; } else { CHECK(acc.deactivate()); } @@ -3905,6 +3949,7 @@ td::Status FetchConfigParams::fetch_config_params( compute_phase_cfg->size_limits = size_limits; compute_phase_cfg->precompiled_contracts = config.get_precompiled_contracts_config(); compute_phase_cfg->allow_external_unfreeze = compute_phase_cfg->global_version >= 8; + compute_phase_cfg->disable_anycast = config.get_global_version() >= 10; } { // compute action_phase_cfg @@ -3933,9 +3978,11 @@ td::Status FetchConfigParams::fetch_config_params( 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->extra_currency_v2 = config.get_global_version() >= 10; + action_phase_cfg->disable_anycast = config.get_global_version() >= 10; } { serialize_cfg->extra_currency_v2 = config.get_global_version() >= 10; + serialize_cfg->disable_anycast = config.get_global_version() >= 10; } { // fetch block_grams_created diff --git a/crypto/block/transaction.h b/crypto/block/transaction.h index 8e612e6a..a1f597b0 100644 --- a/crypto/block/transaction.h +++ b/crypto/block/transaction.h @@ -130,6 +130,7 @@ struct ComputePhaseConfig { PrecompiledContractsConfig precompiled_contracts; bool dont_run_precompiled_ = false; bool allow_external_unfreeze{false}; + bool disable_anycast{false}; ComputePhaseConfig() : gas_price(0), gas_limit(0), special_gas_limit(0), gas_credit(0) { compute_threshold(); @@ -172,6 +173,7 @@ struct ActionPhaseConfig { bool reserve_extra_enabled{false}; bool extra_currency_v2{false}; td::optional mc_blackhole_addr; + bool disable_anycast{false}; const MsgPrices& fetch_msg_prices(bool is_masterchain) const { return is_masterchain ? fwd_mc : fwd_std; } @@ -179,6 +181,7 @@ struct ActionPhaseConfig { struct SerializeConfig { bool extra_currency_v2{false}; + bool disable_anycast{false}; }; struct CreditPhase { @@ -252,12 +255,13 @@ struct Account { bool is_special{false}; bool tick{false}; bool tock{false}; - bool split_depth_set_{false}; - unsigned char split_depth_{0}; + int fixed_prefix_length{0}; int verbosity{3 * 0}; ton::UnixTime now_{0}; ton::WorkchainId workchain{ton::workchainInvalid}; - td::BitArray<32> addr_rewrite; // rewrite (anycast) data, split_depth bits + td::BitArray<32> addr_rewrite; // rewrite (anycast) data, addr_rewrite_length bits + bool addr_rewrite_length_set{false}; + unsigned char addr_rewrite_length{0}; ton::StdSmcAddress addr; // rewritten address (by replacing a prefix of `addr_orig` with `addr_rewrite`); it is the key in ShardAccounts ton::StdSmcAddress addr_orig; // address indicated in smart-contract data (must coincide with hash of StateInit) Ref my_addr; // address as stored in the smart contract (MsgAddressInt); corresponds to `addr_orig` + anycast info @@ -280,9 +284,6 @@ struct Account { Account() = default; Account(ton::WorkchainId wc, td::ConstBitPtr _addr) : workchain(wc), addr(_addr) { } - Account(ton::WorkchainId wc, td::ConstBitPtr _addr, int depth) - : split_depth_set_(true), split_depth_((unsigned char)depth), workchain(wc), addr(_addr) { - } block::CurrencyCollection get_balance() const { return balance; } @@ -290,7 +291,7 @@ struct Account { bool unpack(Ref account, ton::UnixTime now, bool special); bool init_new(ton::UnixTime now); bool deactivate(); - bool recompute_tmp_addr(Ref& tmp_addr, int split_depth, td::ConstBitPtr orig_addr_rewrite) const; + bool recompute_tmp_addr(Ref& tmp_addr, int fixed_prefix_length, td::ConstBitPtr orig_addr_rewrite) const; td::RefInt256 compute_storage_fees(ton::UnixTime now, const std::vector& pricing) const; bool is_masterchain() const { return workchain == ton::masterchainId; @@ -306,10 +307,10 @@ struct Account { protected: friend struct transaction::Transaction; - bool set_split_depth(int split_depth); - bool check_split_depth(int split_depth) const; - bool forget_split_depth(); - bool init_rewrite_addr(int split_depth, td::ConstBitPtr orig_addr_rewrite); + bool set_addr_rewrite_length(int new_length); + bool check_addr_rewrite_length(int length) const; + bool forget_addr_rewrite_length(); + bool init_rewrite_addr(int rewrite_length, td::ConstBitPtr orig_addr_rewrite); private: bool unpack_address(vm::CellSlice& addr_cs); @@ -346,7 +347,9 @@ struct Transaction { bool orig_addr_rewrite_set{false}; bool new_tick; bool new_tock; - signed char new_split_depth{-1}; + int new_fixed_prefix_length{-1}; + int new_addr_rewrite_length{-1}; + bool force_remove_anycast_address = false; ton::UnixTime now; int acc_status; int verbosity{3 * 0}; @@ -382,7 +385,7 @@ struct Transaction { Transaction(const Account& _account, int ttype, ton::LogicalTime req_start_lt, ton::UnixTime _now, Ref _inmsg = {}); bool unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* cfg); - bool check_in_msg_state_hash(); + bool check_in_msg_state_hash(const ComputePhaseConfig& cfg); bool prepare_storage_phase(const StoragePhaseConfig& cfg, bool force_collect = true, bool adjust_msg_value = false); bool prepare_credit_phase(); td::uint64 gas_bought_for(const ComputePhaseConfig& cfg, td::RefInt256 nanograms); @@ -418,7 +421,7 @@ struct Transaction { int try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg); bool check_replace_src_addr(Ref& src_addr) const; bool check_rewrite_dest_addr(Ref& dest_addr, const ActionPhaseConfig& cfg, - bool* is_mc = nullptr) const; + bool* is_mc = nullptr, bool allow_anycast = true) const; bool serialize_storage_phase(vm::CellBuilder& cb); bool serialize_credit_phase(vm::CellBuilder& cb); bool serialize_compute_phase(vm::CellBuilder& cb); diff --git a/crypto/vm/tonops.cpp b/crypto/vm/tonops.cpp index aab1711f..89749a4b 100644 --- a/crypto/vm/tonops.cpp +++ b/crypto/vm/tonops.cpp @@ -1380,10 +1380,13 @@ int exec_store_var_integer(VmState* st, int len_bits, bool sgnd, bool quiet) { return 0; } -bool skip_maybe_anycast(CellSlice& cs) { +bool skip_maybe_anycast(CellSlice& cs, int global_version) { if (cs.prefetch_ulong(1) != 1) { return cs.advance(1); } + if (global_version >= 10) { + return false; + } unsigned depth; return cs.advance(1) // just$1 && cs.fetch_uint_leq(30, depth) // anycast_info$_ depth:(#<= 30) @@ -1391,7 +1394,7 @@ bool skip_maybe_anycast(CellSlice& cs) { && cs.advance(depth); // rewrite_pfx:(bits depth) = Anycast; } -bool skip_message_addr(CellSlice& cs) { +bool skip_message_addr(CellSlice& cs, int global_version) { switch ((unsigned)cs.fetch_ulong(2)) { case 0: // addr_none$00 = MsgAddressExt; return true; @@ -1400,15 +1403,18 @@ bool skip_message_addr(CellSlice& cs) { return cs.fetch_uint_to(9, len) // len:(## 9) && cs.advance(len); // external_address:(bits len) = MsgAddressExt; } - case 2: { // addr_std$10 - return skip_maybe_anycast(cs) // anycast:(Maybe Anycast) - && cs.advance(8 + 256); // workchain_id:int8 address:bits256 = MsgAddressInt; + case 2: { // addr_std$10 + return skip_maybe_anycast(cs, global_version) // anycast:(Maybe Anycast) + && cs.advance(8 + 256); // workchain_id:int8 address:bits256 = MsgAddressInt; } case 3: { // addr_var$11 + if (global_version >= 10) { + return false; + } unsigned len; - return skip_maybe_anycast(cs) // anycast:(Maybe Anycast) - && cs.fetch_uint_to(9, len) // addr_len:(## 9) - && cs.advance(32 + len); // workchain_id:int32 address:(bits addr_len) = MsgAddressInt; + return skip_maybe_anycast(cs, global_version) // anycast:(Maybe Anycast) + && cs.fetch_uint_to(9, len) // addr_len:(## 9) + && cs.advance(32 + len); // workchain_id:int32 address:(bits addr_len) = MsgAddressInt; } default: return false; @@ -1420,7 +1426,7 @@ int exec_load_message_addr(VmState* st, bool quiet) { Stack& stack = st->get_stack(); auto csr = stack.pop_cellslice(); td::Ref addr{true}; - if (util::load_msg_addr_q(csr.write(), addr.write(), quiet)) { + if (util::load_msg_addr_q(csr.write(), addr.write(), st->get_global_version(), quiet)) { stack.push_cellslice(std::move(addr)); stack.push_cellslice(std::move(csr)); if (quiet) { @@ -1433,11 +1439,14 @@ int exec_load_message_addr(VmState* st, bool quiet) { return 0; } -bool parse_maybe_anycast(CellSlice& cs, StackEntry& res) { +bool parse_maybe_anycast(CellSlice& cs, StackEntry& res, int global_version) { res = StackEntry{}; if (cs.prefetch_ulong(1) != 1) { return cs.advance(1); } + if (global_version >= 10) { + return false; + } unsigned depth; Ref pfx; if (cs.advance(1) // just$1 @@ -1450,7 +1459,7 @@ bool parse_maybe_anycast(CellSlice& cs, StackEntry& res) { return false; } -bool parse_message_addr(CellSlice& cs, std::vector& res) { +bool parse_message_addr(CellSlice& cs, std::vector& res, int global_version) { res.clear(); switch ((unsigned)cs.fetch_ulong(2)) { case 0: // addr_none$00 = MsgAddressExt; @@ -1471,9 +1480,9 @@ bool parse_message_addr(CellSlice& cs, std::vector& res) { StackEntry v; int workchain; Ref addr; - 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; + if (parse_maybe_anycast(cs, v, global_version) // 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::make_refint(2)); res.emplace_back(std::move(v)); res.emplace_back(td::make_refint(workchain)); @@ -1483,13 +1492,16 @@ bool parse_message_addr(CellSlice& cs, std::vector& res) { break; } case 3: { // addr_var$11 + if (global_version >= 10) { + return false; + } StackEntry v; int len, workchain; Ref addr; - if (parse_maybe_anycast(cs, v) // anycast:(Maybe Anycast) - && 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; + if (parse_maybe_anycast(cs, v, global_version) // anycast:(Maybe Anycast) + && 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::make_refint(3)); res.emplace_back(std::move(v)); res.emplace_back(td::make_refint(workchain)); @@ -1508,7 +1520,7 @@ int exec_parse_message_addr(VmState* st, bool quiet) { auto csr = stack.pop_cellslice(); auto& cs = csr.write(); std::vector res; - if (!(parse_message_addr(cs, res) && cs.empty_ext())) { + if (!(parse_message_addr(cs, res, st->get_global_version()) && cs.empty_ext())) { if (quiet) { stack.push_bool(false); } else { @@ -1548,7 +1560,7 @@ int exec_rewrite_message_addr(VmState* st, bool allow_var_addr, bool quiet) { auto csr = stack.pop_cellslice(); auto& cs = csr.write(); std::vector tuple; - if (!(parse_message_addr(cs, tuple) && cs.empty_ext())) { + if (!(parse_message_addr(cs, tuple, st->get_global_version()) && cs.empty_ext())) { if (quiet) { stack.push_bool(false); return 0; @@ -2026,9 +2038,9 @@ bool load_var_integer_q(CellSlice& cs, td::RefInt256& res, int len_bits, bool sg bool load_coins_q(CellSlice& cs, td::RefInt256& res, bool quiet) { return load_var_integer_q(cs, res, 4, false, quiet); } -bool load_msg_addr_q(CellSlice& cs, CellSlice& res, bool quiet) { +bool load_msg_addr_q(CellSlice& cs, CellSlice& res, int global_version, bool quiet) { res = cs; - if (!skip_message_addr(cs)) { + if (!skip_message_addr(cs, global_version)) { cs = res; if (quiet) { return false; @@ -2038,10 +2050,11 @@ bool load_msg_addr_q(CellSlice& cs, CellSlice& res, bool quiet) { res.cut_tail(cs); return true; } -bool parse_std_addr_q(CellSlice cs, ton::WorkchainId& res_wc, ton::StdSmcAddress& res_addr, bool quiet) { +bool parse_std_addr_q(CellSlice cs, ton::WorkchainId& res_wc, ton::StdSmcAddress& res_addr, int global_version, + bool quiet) { // Like exec_rewrite_message_addr, but for std address case std::vector tuple; - if (!(parse_message_addr(cs, tuple) && cs.empty_ext())) { + if (!(parse_message_addr(cs, tuple, global_version) && cs.empty_ext())) { if (quiet) { return false; } @@ -2076,14 +2089,14 @@ td::RefInt256 load_var_integer(CellSlice& cs, int len_bits, bool sgnd) { td::RefInt256 load_coins(CellSlice& cs) { return load_var_integer(cs, 4, false); } -CellSlice load_msg_addr(CellSlice& cs) { +CellSlice load_msg_addr(CellSlice& cs, int global_version) { CellSlice addr; - load_msg_addr_q(cs, addr, false); + load_msg_addr_q(cs, addr, global_version, false); return addr; } -std::pair parse_std_addr(CellSlice cs) { +std::pair parse_std_addr(CellSlice cs, int global_version) { std::pair res; - parse_std_addr_q(std::move(cs), res.first, res.second, false); + parse_std_addr_q(std::move(cs), res.first, res.second, global_version, false); return res; } diff --git a/crypto/vm/tonops.h b/crypto/vm/tonops.h index bbac078f..d3350508 100644 --- a/crypto/vm/tonops.h +++ b/crypto/vm/tonops.h @@ -32,14 +32,15 @@ namespace util { // "_q" functions throw on error if not quiet, return false if quiet (leaving cs unchanged) bool load_var_integer_q(CellSlice& cs, td::RefInt256& res, int len_bits, bool sgnd, bool quiet); bool load_coins_q(CellSlice& cs, td::RefInt256& res, bool quiet); -bool load_msg_addr_q(CellSlice& cs, CellSlice& res, bool quiet); -bool parse_std_addr_q(CellSlice cs, ton::WorkchainId& res_wc, ton::StdSmcAddress& res_addr, bool quiet); +bool load_msg_addr_q(CellSlice& cs, CellSlice& res, int global_version, bool quiet); +bool parse_std_addr_q(CellSlice cs, ton::WorkchainId& res_wc, ton::StdSmcAddress& res_addr, int global_version, + bool quiet); // Non-"_q" functions throw on error td::RefInt256 load_var_integer(CellSlice& cs, int len_bits, bool sgnd); td::RefInt256 load_coins(CellSlice& cs); -CellSlice load_msg_addr(CellSlice& cs); -std::pair parse_std_addr(CellSlice cs); +CellSlice load_msg_addr(CellSlice& cs, int global_version); +std::pair parse_std_addr(CellSlice cs, int global_version); // store_... functions throw on error if not quiet, return false if quiet (leaving cb unchanged) bool store_var_integer(CellBuilder& cb, const td::RefInt256& x, int len_bits, bool sgnd, bool quiet = false); diff --git a/doc/GlobalVersions.md b/doc/GlobalVersions.md index 77963e95..df12e2c7 100644 --- a/doc/GlobalVersions.md +++ b/doc/GlobalVersions.md @@ -3,6 +3,8 @@ Global version is a parameter specified in `ConfigParam 8` ([block.tlb](https:// Various features are enabled depending on the global version. ## Version 4 +__Enabled in mainnet on 2023-12-20__ + New features of version 4 are desctibed in detail in [the documentation](https://docs.ton.org/v3/documentation/tvm/changelog/tvm-upgrade-2023-07). ### New TVM instructions @@ -40,6 +42,7 @@ intermediate value before division (e.g. `(xy+w)/z`). * Unpaid storage fee is now saved to `due_payment` ## Version 5 +__Enabled in mainnet on 2024-02-03__ ### Gas limits Version 5 enables higher gas limits for special contracts. @@ -57,6 +60,7 @@ See [this post](https://t.me/tonstatus/88) for details. * `XLOAD` now works differently. When it takes a library cell, it returns the cell that it points to. This allows loading "nested libraries", if needed. ## Version 6 +__Enabled in mainnet on 2024-03-16__ ### c7 tuple **c7** tuple extended from 14 to 17 elements: @@ -101,10 +105,12 @@ Operations for working with Merkle proofs, where cells can have non-zero level a ## Version 7 +__Enabled in mainnet on 2024-04-18__ [Explicitly nullify](https://github.com/ton-blockchain/ton/pull/957/files) `due_payment` after due reimbursment. ## Version 8 +__Enabled in mainnet on 2024-08-25__ - 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`. @@ -113,6 +119,7 @@ Operations for working with Merkle proofs, where cells can have non-zero level a - Don't use user-provided `fwd_fee` and `ihr_fee` for internal messages. ## Version 9 +__Enabled in mainnet on 2025-02-13__ ### c7 tuple c7 tuple parameter number **13** (previous blocks info tuple) now has the third element. It contains ids of the 16 last masterchain blocks with seqno divisible by 100. @@ -153,6 +160,20 @@ Example: if the last masterchain block seqno is `19071` then the list contains b - Extra currency dictionary is not counted in the account size and does not affect storage fees. - Accounts with already existing extra currencies will get their sizes recomputed without EC only after modifying `AccountState`. +### Anycast addresses and address rewrite +- Anycast addresses are not allowed in `dest` of internal and external messages. +- `addr_var` are not allowed in `dest` of external messages. + - Note: as before, `addr_var` in `dest` of internal messages are automatically replaced with `addr_std`. +- TVM instructions `LDMSGADDR(Q)`, `PARSEMSGADDR(Q)`, `REWRITESTDADDR(Q)`, `REWRITEVARADDR(Q)` no more support anycast addresses and `addr_var`. +- `addr:MsgAddressInt` in `Account` cannot be an anycast address. + - Therefore, `src` of outbound messages cannot be an anycast address. + - Existing accounts with anycast addresses change to non-anycast addresses in the first transaction. +- When deploying an account with `fixed_prefix_length` in `StateInit` of the message (it was called `split_depth` before), the first `fixed_prefix_length` bits of the address are not compared against the state hash. + - This allows deploying an account to an arbitrary shard regardless of the hash of state init. + - `fixed_prefix_length` remains in the account state. + - `fixed_prefix_length` of the account can be at most 8. The limit can be changed in size limits config (`ConfigParam 43`). + ### TVM changes - `SENDMSG` calculates messages size and fees without extra currencies, uses new +64 and +128 mode behavior. - `SENDMSG` does not check the number of extra currencies. +- `LDMSGADDR(Q)`, `PARSEMSGADDR(Q)`, `REWRITESTDADDR(Q)`, `REWRITEVARADDR(Q)` no more support anycast addresses and `addr_var`. diff --git a/validator/impl/validate-query.cpp b/validator/impl/validate-query.cpp index 90966d82..167d6d73 100644 --- a/validator/impl/validate-query.cpp +++ b/validator/impl/validate-query.cpp @@ -977,6 +977,7 @@ bool ValidateQuery::fetch_config_params() { compute_phase_cfg_.size_limits = size_limits; compute_phase_cfg_.precompiled_contracts = config_->get_precompiled_contracts_config(); compute_phase_cfg_.allow_external_unfreeze = compute_phase_cfg_.global_version >= 8; + compute_phase_cfg_.disable_anycast = config_->get_global_version() >= 10; } { // compute action_phase_cfg @@ -1005,9 +1006,11 @@ bool ValidateQuery::fetch_config_params() { 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_.extra_currency_v2 = config_->get_global_version() >= 10; + action_phase_cfg_.disable_anycast = config_->get_global_version() >= 10; } { serialize_cfg_.extra_currency_v2 = config_->get_global_version() >= 10; + serialize_cfg_.disable_anycast = config_->get_global_version() >= 10; } { // fetch block_grams_created