mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Disable anycast address, allow deploying with "fixed prefix length"
This commit is contained in:
parent
44e7e091b2
commit
61862c07c5
11 changed files with 241 additions and 157 deletions
|
@ -738,7 +738,7 @@ const TickTock t_TickTock;
|
||||||
const RefAnything t_RefCell;
|
const RefAnything t_RefCell;
|
||||||
|
|
||||||
bool StateInit::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
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))
|
return Maybe<UInt>{5}.validate_skip(ops, cs, weak) // fixed_prefix_length:(Maybe (## 5))
|
||||||
&& Maybe<TickTock>{}.validate_skip(ops, cs, weak) // special:(Maybe TickTock)
|
&& 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) // code:(Maybe ^Cell)
|
||||||
&& Maybe<RefAnything>{}.validate_skip(ops, cs, weak) // data:(Maybe ^Cell)
|
&& Maybe<RefAnything>{}.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:
|
case account:
|
||||||
return cs.advance(1) // account$1
|
return cs.advance(1) // account$1
|
||||||
&& t_MsgAddressInt.skip_get_depth(cs, depth) // addr:MsgAddressInt
|
&& 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_StorageInfo.skip(cs) // storage_stat:StorageInfo
|
||||||
&& t_AccountStorage.skip_copy_balance(cb, cs); // storage:AccountStorage
|
&& 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 {
|
bool DepthBalanceInfo::skip(vm::CellSlice& cs) const {
|
||||||
return cs.advance(5) &&
|
return cs.advance(5) &&
|
||||||
t_CurrencyCollection.skip(
|
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 {
|
bool DepthBalanceInfo::validate_skip(int* ops, vm::CellSlice& cs, bool weak) const {
|
||||||
return cs.fetch_ulong(5) <= 30 &&
|
return cs.fetch_ulong(5) <= 30 &&
|
||||||
t_CurrencyCollection.validate_skip(ops, cs,
|
t_CurrencyCollection.validate_skip(
|
||||||
weak); // depth_balance$_ split_depth:(#<= 30) balance:CurrencyCollection
|
ops, cs,
|
||||||
|
weak); // depth_balance$_ fixed_prefix_length:(#<= 30) balance:CurrencyCollection
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DepthBalanceInfo::null_value(vm::CellBuilder& cb) const {
|
bool DepthBalanceInfo::null_value(vm::CellBuilder& cb) const {
|
||||||
|
|
|
@ -141,12 +141,12 @@ ext_out_msg_info$11 src:MsgAddress dest:MsgAddressExt
|
||||||
|
|
||||||
tick_tock$_ tick:Bool tock:Bool = TickTock;
|
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)
|
code:(Maybe ^Cell) data:(Maybe ^Cell)
|
||||||
library:(Maybe ^Cell) = StateInit;
|
library:(Maybe ^Cell) = StateInit;
|
||||||
|
|
||||||
// StateInitWithLibs is used to validate sent and received messages
|
// 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)
|
code:(Maybe ^Cell) data:(Maybe ^Cell)
|
||||||
library:(HashmapE 256 SimpleLib) = StateInitWithLibs;
|
library:(HashmapE 256 SimpleLib) = StateInitWithLibs;
|
||||||
|
|
||||||
|
@ -273,14 +273,6 @@ acc_state_frozen$01 = AccountStatus;
|
||||||
acc_state_active$10 = AccountStatus;
|
acc_state_active$10 = AccountStatus;
|
||||||
acc_state_nonexist$11 = 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
|
account_descr$_ account:^Account last_trans_hash:bits256
|
||||||
last_trans_lt:uint64 = ShardAccount;
|
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;
|
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
|
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_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;
|
_ SizeLimitsConfig = ConfigParam 43;
|
||||||
|
|
||||||
// key is [ wc:int32 addr:uint256 ]
|
// key is [ wc:int32 addr:uint256 ]
|
||||||
|
|
|
@ -94,12 +94,12 @@ typedef td::BitArray<256> hash_t;
|
||||||
|
|
||||||
struct SmcDescr {
|
struct SmcDescr {
|
||||||
hash_t addr;
|
hash_t addr;
|
||||||
int split_depth;
|
int fixed_prefix_length;
|
||||||
bool preinit_only;
|
bool preinit_only;
|
||||||
td::RefInt256 gram_balance;
|
td::RefInt256 gram_balance;
|
||||||
Ref<vm::DataCell> state_init; // StateInit
|
Ref<vm::DataCell> state_init; // StateInit
|
||||||
Ref<vm::DataCell> account; // Account
|
Ref<vm::DataCell> 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;
|
ton::UnixTime now;
|
||||||
|
|
||||||
bool set_config_smc(const SmcDescr& smc) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
vm::CellSlice cs = load_cell_slice(smc.state_init);
|
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<vm::Cell> lib_root
|
||||||
}
|
}
|
||||||
|
|
||||||
td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref<vm::Cell> code, Ref<vm::Cell> data,
|
td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref<vm::Cell> code, Ref<vm::Cell> data,
|
||||||
Ref<vm::Cell> library, td::RefInt256 balance, int special, int split_depth,
|
Ref<vm::Cell> library, td::RefInt256 balance, int special, int fixed_prefix_length,
|
||||||
int mode) {
|
int mode) {
|
||||||
if (is_empty_cell(code)) {
|
if (is_empty_cell(code)) {
|
||||||
code.clear();
|
code.clear();
|
||||||
|
@ -238,12 +238,12 @@ td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref<vm::Cell> code, R
|
||||||
THRERR("not a valid library collection");
|
THRERR("not a valid library collection");
|
||||||
}
|
}
|
||||||
vm::CellBuilder cb;
|
vm::CellBuilder cb;
|
||||||
if (!split_depth) {
|
if (!fixed_prefix_length) {
|
||||||
PDO(cb.store_long_bool(0, 1));
|
PDO(cb.store_long_bool(0, 1));
|
||||||
} else {
|
} 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) {
|
if (!special) {
|
||||||
PDO(cb.store_long_bool(0, 1));
|
PDO(cb.store_long_bool(0, 1));
|
||||||
} else {
|
} else {
|
||||||
|
@ -287,7 +287,7 @@ td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref<vm::Cell> code, R
|
||||||
auto ins = smart_contracts.emplace(addr, addr);
|
auto ins = smart_contracts.emplace(addr, addr);
|
||||||
assert(ins.second);
|
assert(ins.second);
|
||||||
SmcDescr& smc = ins.first->second;
|
SmcDescr& smc = ins.first->second;
|
||||||
smc.split_depth = split_depth;
|
smc.fixed_prefix_length = fixed_prefix_length;
|
||||||
smc.preinit_only = (mode == 1);
|
smc.preinit_only = (mode == 1);
|
||||||
smc.gram_balance = balance;
|
smc.gram_balance = balance;
|
||||||
total_smc_balance += balance;
|
total_smc_balance += balance;
|
||||||
|
@ -328,10 +328,10 @@ td::RefInt256 create_smartcontract(td::RefInt256 smc_addr, Ref<vm::Cell> code, R
|
||||||
ctor = 2; // addr_std$10
|
ctor = 2; // addr_std$10
|
||||||
}
|
}
|
||||||
PDO(cb.store_long_bool(ctor, 2)); // addr_std$10 or addr_var$11
|
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
|
PDO(cb.store_long_bool(1, 1) // just$1
|
||||||
&& cb.store_ulong_rchk_bool(split_depth, 5) // depth:(## 5)
|
&& cb.store_ulong_rchk_bool(fixed_prefix_length, 5) // depth:(## 5)
|
||||||
&& cb.store_bits_bool(addr.cbits(), split_depth)); // rewrite pfx:(depth * Bit)
|
&& cb.store_bits_bool(addr.cbits(), fixed_prefix_length)); // rewrite pfx:(depth * Bit)
|
||||||
} else {
|
} else {
|
||||||
PDO(cb.store_long_bool(0, 1)); // nothing$0
|
PDO(cb.store_long_bool(0, 1)); // nothing$0
|
||||||
}
|
}
|
||||||
|
@ -514,7 +514,7 @@ Ref<vm::Cell> create_state() {
|
||||||
// data (cell)
|
// data (cell)
|
||||||
// library (cell)
|
// library (cell)
|
||||||
// balance (int)
|
// balance (int)
|
||||||
// split_depth (int 0..32)
|
// fixed_prefix_length (int 0..32)
|
||||||
// special (int 0..3, +2 = tick, +1 = tock)
|
// special (int 0..3, +2 = tick, +1 = tock)
|
||||||
// [ address (uint256) ]
|
// [ address (uint256) ]
|
||||||
// mode (0 = compute address only, 1 = create uninit, 2 = create complete; +4 = with specified address)
|
// 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) {
|
if (special && workchain_id != wc_master) {
|
||||||
throw fift::IntError{"cannot create special smartcontracts outside of the masterchain"};
|
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();
|
td::RefInt256 balance = stack.pop_int_finite();
|
||||||
if (sgn(balance) < 0) {
|
if (sgn(balance) < 0) {
|
||||||
throw fift::IntError{"initial balance of a smartcontract cannot be negative"};
|
throw fift::IntError{"initial balance of a smartcontract cannot be negative"};
|
||||||
|
@ -548,7 +548,7 @@ void interpret_register_smartcontract(vm::Stack& stack) {
|
||||||
Ref<vm::Cell> data = stack.pop_cell();
|
Ref<vm::Cell> data = stack.pop_cell();
|
||||||
Ref<vm::Cell> code = stack.pop_cell();
|
Ref<vm::Cell> code = stack.pop_cell();
|
||||||
td::RefInt256 addr = create_smartcontract(std::move(spec_addr), std::move(code), std::move(data), std::move(library),
|
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()) {
|
if (addr.is_null()) {
|
||||||
throw fift::IntError{"internal error while creating smartcontract"};
|
throw fift::IntError{"internal error while creating smartcontract"};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1961,6 +1961,7 @@ td::Result<SizeLimitsConfig> Config::do_get_size_limits_config(td::Ref<vm::CellS
|
||||||
limits.max_acc_public_libraries = rec.max_acc_public_libraries;
|
limits.max_acc_public_libraries = rec.max_acc_public_libraries;
|
||||||
limits.defer_out_queue_size_limit = rec.defer_out_queue_size_limit;
|
limits.defer_out_queue_size_limit = rec.defer_out_queue_size_limit;
|
||||||
limits.max_msg_extra_currencies = rec.max_msg_extra_currencies;
|
limits.max_msg_extra_currencies = rec.max_msg_extra_currencies;
|
||||||
|
limits.max_acc_fixed_prefix_length = rec.max_acc_fixed_prefix_length;
|
||||||
};
|
};
|
||||||
gen::SizeLimitsConfig::Record_size_limits_config rec_v1;
|
gen::SizeLimitsConfig::Record_size_limits_config rec_v1;
|
||||||
gen::SizeLimitsConfig::Record_size_limits_config_v2 rec_v2;
|
gen::SizeLimitsConfig::Record_size_limits_config_v2 rec_v2;
|
||||||
|
|
|
@ -398,6 +398,7 @@ struct SizeLimitsConfig {
|
||||||
td::uint32 max_acc_public_libraries = 256;
|
td::uint32 max_acc_public_libraries = 256;
|
||||||
td::uint32 defer_out_queue_size_limit = 256;
|
td::uint32 defer_out_queue_size_limit = 256;
|
||||||
td::uint32 max_msg_extra_currencies = 2;
|
td::uint32 max_msg_extra_currencies = 2;
|
||||||
|
td::uint32 max_acc_fixed_prefix_length = 8;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CatchainValidatorsConfig {
|
struct CatchainValidatorsConfig {
|
||||||
|
|
|
@ -115,42 +115,42 @@ bool Account::set_address(ton::WorkchainId wc, td::ConstBitPtr new_addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the split depth of the account.
|
* Sets the length of anycast prefix length in the account address.
|
||||||
*
|
*
|
||||||
* @param new_split_depth The new split depth value to be set.
|
* @param new_length The new rewrite lingth.
|
||||||
*
|
*
|
||||||
* @returns True if the split depth was successfully set, False otherwise.
|
* @returns True if the length was successfully set, False otherwise.
|
||||||
*/
|
*/
|
||||||
bool Account::set_split_depth(int new_split_depth) {
|
bool Account::set_addr_rewrite_length(int new_length) {
|
||||||
if (new_split_depth < 0 || new_split_depth > 30) {
|
if (new_length < 0 || new_length > 30) {
|
||||||
return false; // invalid value for split_depth
|
return false; // invalid value
|
||||||
}
|
}
|
||||||
if (split_depth_set_) {
|
if (addr_rewrite_length_set) {
|
||||||
return split_depth_ == new_split_depth;
|
return addr_rewrite_length == new_length;
|
||||||
} else {
|
} else {
|
||||||
split_depth_ = (unsigned char)new_split_depth;
|
addr_rewrite_length = (unsigned char)new_length;
|
||||||
split_depth_set_ = true;
|
addr_rewrite_length_set = true;
|
||||||
return 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 {
|
bool Account::check_addr_rewrite_length(int length) const {
|
||||||
return split_depth_set_ ? (split_depth == split_depth_) : (split_depth >= 0 && split_depth <= 30);
|
return addr_rewrite_length_set ? (length == addr_rewrite_length) : (length >= 0 && length <= 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses anycast data of the account address.
|
* 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.
|
* @returns True if parsing was successful, false otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -159,13 +159,13 @@ bool Account::parse_maybe_anycast(vm::CellSlice& cs) {
|
||||||
if (t < 0) {
|
if (t < 0) {
|
||||||
return false;
|
return false;
|
||||||
} else if (!t) {
|
} else if (!t) {
|
||||||
return set_split_depth(0);
|
return set_addr_rewrite_length(0);
|
||||||
}
|
}
|
||||||
int depth;
|
int depth;
|
||||||
return cs.fetch_uint_leq(30, depth) // anycast_info$_ depth:(#<= 30)
|
return cs.fetch_uint_leq(30, depth) // anycast_info$_ depth:(#<= 30)
|
||||||
&& depth // { depth >= 1 }
|
&& depth // { depth >= 1 }
|
||||||
&& cs.fetch_bits_to(addr_rewrite.bits(), depth) // rewrite_pfx:(bits depth)
|
&& 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.
|
* @returns True if the anycast information was successfully stored, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool Account::store_maybe_anycast(vm::CellBuilder& cb) const {
|
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(false);
|
||||||
}
|
}
|
||||||
return cb.store_bool_bool(true) // just$1
|
return cb.store_bool_bool(true) // just$1
|
||||||
&& cb.store_uint_leq(30, split_depth_) // depth:(#<= 30)
|
&& cb.store_uint_leq(30, addr_rewrite_length) // depth:(#<= 30)
|
||||||
&& cb.store_bits_bool(addr_rewrite.cbits(), split_depth_); // rewrite_pfx:(bits depth)
|
&& 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) {
|
if (workchain == ton::workchainInvalid) {
|
||||||
workchain = new_wc;
|
workchain = new_wc;
|
||||||
addr = addr_orig;
|
addr = addr_orig;
|
||||||
addr.bits().copy_from(addr_rewrite.cbits(), split_depth_);
|
addr.bits().copy_from(addr_rewrite.cbits(), addr_rewrite_length);
|
||||||
} else if (split_depth_) {
|
} else if (addr_rewrite_length) {
|
||||||
ton::StdSmcAddress new_addr = addr_orig;
|
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) {
|
if (new_addr != addr) {
|
||||||
LOG(ERROR) << "error unpacking account " << workchain << ":" << addr.to_hex()
|
LOG(ERROR) << "error unpacking account " << workchain << ":" << addr.to_hex()
|
||||||
<< " : account header contains different address " << new_addr.to_hex() << " (with splitting depth "
|
<< " : account header contains different address " << new_addr.to_hex() << " (with splitting depth "
|
||||||
<< (int)split_depth_ << ")";
|
<< (int)addr_rewrite_length << ")";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (addr != addr_orig) {
|
} else if (addr != addr_orig) {
|
||||||
|
@ -235,7 +235,7 @@ bool Account::unpack_address(vm::CellSlice& addr_cs) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
addr_rewrite = addr.bits(); // initialize all 32 bits of addr_rewrite
|
addr_rewrite = addr.bits(); // initialize all 32 bits of addr_rewrite
|
||||||
if (!split_depth_) {
|
if (!addr_rewrite_length) {
|
||||||
my_addr_exact = my_addr;
|
my_addr_exact = my_addr;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -280,7 +280,7 @@ bool Account::unpack_storage_info(vm::CellSlice& cs) {
|
||||||
* Unpacks the state of an Account from a CellSlice.
|
* Unpacks the state of an Account from a CellSlice.
|
||||||
*
|
*
|
||||||
* State is serialized using StateInit TLB-scheme.
|
* 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.
|
* @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)) {
|
if (!tlb::unpack_exact(cs, state)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int sd = 0;
|
fixed_prefix_length = 0;
|
||||||
if (state.split_depth->size() == 6) {
|
if (state.fixed_prefix_length->size() == 6) {
|
||||||
sd = (int)state.split_depth->prefetch_ulong(6) - 32;
|
fixed_prefix_length = (int)state.fixed_prefix_length->prefetch_ulong(6) - 32;
|
||||||
}
|
|
||||||
if (!set_split_depth(sd)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (state.special->size() > 1) {
|
if (state.special->size() > 1) {
|
||||||
int z = (int)state.special->prefetch_ulong(3);
|
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.
|
* 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 tmp_addr A reference to the CellSlice for the result.
|
||||||
* @param split_depth The split depth for the address.
|
* @param fixed_prefix_length The fixed prefix length for the address.
|
||||||
* @param orig_addr_rewrite Address prefox of length split_depth.
|
* @param orig_addr_rewrite Address prefix of length fixed_prefix_length.
|
||||||
*
|
*
|
||||||
* @returns True if the address was successfully computed, false otherwise.
|
* @returns True if the address was successfully computed, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool Account::recompute_tmp_addr(Ref<vm::CellSlice>& tmp_addr, int split_depth,
|
bool Account::recompute_tmp_addr(Ref<vm::CellSlice>& tmp_addr, int fixed_prefix_length,
|
||||||
td::ConstBitPtr orig_addr_rewrite) const {
|
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;
|
tmp_addr = my_addr_exact;
|
||||||
return true;
|
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;
|
tmp_addr = my_addr;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (split_depth < 0 || split_depth > 30) {
|
if (fixed_prefix_length < 0 || fixed_prefix_length > 30) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
vm::CellBuilder cb;
|
vm::CellBuilder cb;
|
||||||
|
@ -387,13 +386,13 @@ bool Account::recompute_tmp_addr(Ref<vm::CellSlice>& tmp_addr, int split_depth,
|
||||||
if (!cb.store_long_bool(std ? 2 : 3, 2)) { // addr_std$10 or addr_var$11
|
if (!cb.store_long_bool(std ? 2 : 3, 2)) { // addr_std$10 or addr_var$11
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!split_depth) {
|
if (!fixed_prefix_length) {
|
||||||
if (!cb.store_bool_bool(false)) { // anycast:(Maybe Anycast)
|
if (!cb.store_bool_bool(false)) { // anycast:(Maybe Anycast)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!(cb.store_bool_bool(true) // just$1
|
} else if (!(cb.store_bool_bool(true) // just$1
|
||||||
&& cb.store_long_bool(split_depth, 5) // depth:(#<= 30)
|
&& cb.store_long_bool(fixed_prefix_length, 5) // depth:(#<= 30)
|
||||||
&& cb.store_bits_bool(addr.bits(), split_depth))) { // rewrite_pfx:(bits depth)
|
&& cb.store_bits_bool(addr.bits(), fixed_prefix_length))) { // rewrite_pfx:(bits depth)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (std) {
|
if (std) {
|
||||||
|
@ -405,26 +404,26 @@ bool Account::recompute_tmp_addr(Ref<vm::CellSlice>& tmp_addr, int split_depth,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Ref<vm::Cell> cell;
|
Ref<vm::Cell> cell;
|
||||||
return cb.store_bits_bool(orig_addr_rewrite, split_depth) // address:(bits addr_len) or bits256
|
return cb.store_bits_bool(orig_addr_rewrite, fixed_prefix_length) // address:(bits addr_len) or bits256
|
||||||
&& cb.store_bits_bool(addr.bits() + split_depth, 256 - split_depth) && cb.finalize_to(cell) &&
|
&& 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();
|
(tmp_addr = vm::load_cell_slice_ref(std::move(cell))).not_null();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets address rewriting info for a newly-activated account.
|
* Sets address rewriting info for a newly-activated account.
|
||||||
*
|
*
|
||||||
* @param split_depth The split depth for the account address.
|
* @param rewrite_length The fixed prefix length for the account address.
|
||||||
* @param orig_addr_rewrite Address frepix of length split_depth.
|
* @param orig_addr_rewrite Address prefix of length fixed_prefix_length.
|
||||||
*
|
*
|
||||||
* @returns True if the rewriting info was successfully set, false otherwise.
|
* @returns True if the rewriting info was successfully set, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool Account::init_rewrite_addr(int split_depth, td::ConstBitPtr orig_addr_rewrite) {
|
bool Account::init_rewrite_addr(int rewrite_length, td::ConstBitPtr orig_addr_rewrite) {
|
||||||
if (split_depth_set_ || !set_split_depth(split_depth)) {
|
if (addr_rewrite_length_set || !set_addr_rewrite_length(rewrite_length)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
addr_orig = addr;
|
addr_orig = addr;
|
||||||
addr_rewrite = addr.bits();
|
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);
|
return compute_my_addr(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,7 +479,7 @@ bool Account::unpack(Ref<vm::CellSlice> shard_account, ton::UnixTime now, bool s
|
||||||
case block::gen::AccountState::account_uninit:
|
case block::gen::AccountState::account_uninit:
|
||||||
status = orig_status = acc_uninit;
|
status = orig_status = acc_uninit;
|
||||||
state_hash = addr;
|
state_hash = addr;
|
||||||
forget_split_depth();
|
forget_addr_rewrite_length();
|
||||||
break;
|
break;
|
||||||
case block::gen::AccountState::account_frozen:
|
case block::gen::AccountState::account_frozen:
|
||||||
status = orig_status = acc_frozen;
|
status = orig_status = acc_frozen;
|
||||||
|
@ -554,18 +553,18 @@ bool Account::init_new(ton::UnixTime now) {
|
||||||
}
|
}
|
||||||
state_hash = addr_orig;
|
state_hash = addr_orig;
|
||||||
status = orig_status = acc_nonexist;
|
status = orig_status = acc_nonexist;
|
||||||
split_depth_set_ = false;
|
addr_rewrite_length_set = false;
|
||||||
return true;
|
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() {
|
bool Account::forget_addr_rewrite_length() {
|
||||||
split_depth_set_ = false;
|
addr_rewrite_length_set = false;
|
||||||
split_depth_ = 0;
|
addr_rewrite_length = 0;
|
||||||
addr_orig = addr;
|
addr_orig = addr;
|
||||||
my_addr = my_addr_exact;
|
my_addr = my_addr_exact;
|
||||||
addr_rewrite = addr.bits();
|
addr_rewrite = addr.bits();
|
||||||
|
@ -583,9 +582,10 @@ bool Account::deactivate() {
|
||||||
}
|
}
|
||||||
// forget special (tick/tock) info
|
// forget special (tick/tock) info
|
||||||
tick = tock = false;
|
tick = tock = false;
|
||||||
|
fixed_prefix_length = 0;
|
||||||
if (status == acc_nonexist || status == acc_uninit) {
|
if (status == acc_nonexist || status == acc_uninit) {
|
||||||
// forget split depth and address rewriting info
|
// forget fixed prefix length and address rewriting info
|
||||||
forget_split_depth();
|
forget_addr_rewrite_length();
|
||||||
// forget specific state hash for deleted or uninitialized accounts (revert to addr)
|
// forget specific state hash for deleted or uninitialized accounts (revert to addr)
|
||||||
state_hash = addr;
|
state_hash = addr;
|
||||||
}
|
}
|
||||||
|
@ -706,6 +706,7 @@ Transaction::Transaction(const Account& _account, int ttype, ton::LogicalTime re
|
||||||
, is_first(_account.transactions.empty())
|
, is_first(_account.transactions.empty())
|
||||||
, new_tick(_account.tick)
|
, new_tick(_account.tick)
|
||||||
, new_tock(_account.tock)
|
, new_tock(_account.tock)
|
||||||
|
, new_fixed_prefix_length(_account.fixed_prefix_length)
|
||||||
, now(_now)
|
, now(_now)
|
||||||
, account(_account)
|
, account(_account)
|
||||||
, my_addr(_account.my_addr)
|
, 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);
|
src_addr = std::move(info.src);
|
||||||
dest_addr = std::move(info.dest);
|
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_type = 2;
|
||||||
in_msg_extern = true;
|
in_msg_extern = true;
|
||||||
// compute forwarding fees for this external message
|
// 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();
|
in_msg_library = state.library->prefetch_ref();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (state.split_depth->size() == 6) {
|
if (state.fixed_prefix_length->size() == 6) {
|
||||||
new_split_depth = (signed char)(state.split_depth->prefetch_ulong(6) - 32);
|
new_fixed_prefix_length = (signed char)(state.fixed_prefix_length->prefetch_ulong(6) - 32);
|
||||||
} else {
|
} 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) {
|
if (state.special->size() > 1) {
|
||||||
int z = (int)state.special->prefetch_ulong(3);
|
int z = (int)state.special->prefetch_ulong(3);
|
||||||
|
@ -1496,19 +1512,26 @@ std::vector<Ref<vm::Cell>> Transaction::compute_vm_libraries(const ComputePhaseC
|
||||||
/**
|
/**
|
||||||
* Checks if the input message StateInit hash corresponds to the account address.
|
* 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.
|
* @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(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();
|
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)) {
|
if ((in_state_hash.bits() + d).compare(account.addr.bits() + d, 256 - d)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
orig_addr_rewrite = in_state_hash.bits();
|
orig_addr_rewrite = in_state_hash.bits();
|
||||||
orig_addr_rewrite_set = true;
|
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;
|
use_msg_state = true;
|
||||||
bool forbid_public_libs =
|
bool forbid_public_libs =
|
||||||
acc_status == Account::acc_uninit && account.is_masterchain(); // Forbid for deploying, allow for unfreezing
|
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))) {
|
if (!(unpack_msg_state(cfg, false, forbid_public_libs) &&
|
||||||
LOG(DEBUG) << "cannot unpack in_msg_state, or it has bad split_depth; cannot init account state";
|
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;
|
cp.skip_reason = ComputePhase::sk_bad_state;
|
||||||
return true;
|
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";
|
LOG(DEBUG) << "in_msg_state hash mismatch, cannot init account state";
|
||||||
cp.skip_reason = ComputePhase::sk_bad_state;
|
cp.skip_reason = ComputePhase::sk_bad_state;
|
||||||
return true;
|
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) {
|
} else if (acc_status != Account::acc_active) {
|
||||||
// no state, cannot perform transactions
|
// no state, cannot perform transactions
|
||||||
cp.skip_reason = in_msg_state.not_null() ? ComputePhase::sk_bad_state : ComputePhase::sk_no_state;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (cfg.disable_anycast) {
|
||||||
|
my_addr = my_addr_exact;
|
||||||
|
new_addr_rewrite_length = 0;
|
||||||
|
force_remove_anycast_address = true;
|
||||||
|
}
|
||||||
|
|
||||||
td::optional<PrecompiledContractsConfig::Contract> precompiled;
|
td::optional<PrecompiledContractsConfig::Contract> precompiled;
|
||||||
if (new_code.not_null() && trans_type == tr_ord) {
|
if (new_code.not_null() && trans_type == tr_ord) {
|
||||||
|
@ -2237,11 +2273,12 @@ bool Transaction::check_replace_src_addr(Ref<vm::CellSlice>& src_addr) const {
|
||||||
* @param dest_addr A reference to the destination address of the transaction.
|
* @param dest_addr A reference to the destination address of the transaction.
|
||||||
* @param cfg The configuration for the action phase.
|
* @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 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.
|
* @returns True if the destination address is valid, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool Transaction::check_rewrite_dest_addr(Ref<vm::CellSlice>& dest_addr, const ActionPhaseConfig& cfg,
|
bool Transaction::check_rewrite_dest_addr(Ref<vm::CellSlice>& dest_addr, const ActionPhaseConfig& cfg,
|
||||||
bool* is_mc) const {
|
bool* is_mc, bool allow_anycast) const {
|
||||||
if (!dest_addr->prefetch_ulong(1)) {
|
if (!dest_addr->prefetch_ulong(1)) {
|
||||||
// all external addresses allowed
|
// all external addresses allowed
|
||||||
if (is_mc) {
|
if (is_mc) {
|
||||||
|
@ -2301,6 +2338,9 @@ bool Transaction::check_rewrite_dest_addr(Ref<vm::CellSlice>& dest_addr, const A
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rec.anycast->size() > 1) {
|
if (rec.anycast->size() > 1) {
|
||||||
|
if (!allow_anycast) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// destination address is an anycast
|
// destination address is an anycast
|
||||||
vm::CellSlice cs{*rec.anycast};
|
vm::CellSlice cs{*rec.anycast};
|
||||||
int d = (int)cs.fetch_ulong(6) - 32;
|
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
|
return 35; // invalid source address
|
||||||
}
|
}
|
||||||
bool to_mc = false;
|
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";
|
LOG(DEBUG) << "invalid destination address in a proposed outbound message";
|
||||||
return check_skip_invalid(36); // invalid destination address
|
return check_skip_invalid(36); // invalid destination address
|
||||||
}
|
}
|
||||||
|
@ -3240,13 +3280,14 @@ bool Transaction::compute_state(const SerializeConfig& cfg) {
|
||||||
&& balance.store(cb)); // balance:CurrencyCollection
|
&& balance.store(cb)); // balance:CurrencyCollection
|
||||||
int ticktock = new_tick * 2 + new_tock;
|
int ticktock = new_tick * 2 + new_tock;
|
||||||
unsigned si_pos = 0;
|
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) {
|
if (acc_status == Account::acc_uninit) {
|
||||||
CHECK(cb.store_long_bool(0, 2)); // account_uninit$00 = AccountState
|
CHECK(cb.store_long_bool(0, 2)); // account_uninit$00 = AccountState
|
||||||
} else if (acc_status == Account::acc_frozen) {
|
} else if (acc_status == Account::acc_frozen) {
|
||||||
if (was_frozen) {
|
if (was_frozen) {
|
||||||
vm::CellBuilder cb2;
|
vm::CellBuilder cb2;
|
||||||
CHECK(account.split_depth_ ? cb2.store_long_bool(account.split_depth_ + 32, 6) // _ ... = StateInit
|
CHECK(fixed_prefix_length ? cb2.store_long_bool(fixed_prefix_length + 32, 6) // _ ... = StateInit
|
||||||
: cb2.store_long_bool(0, 1)); // ... split_depth:(Maybe (## 5))
|
: 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(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));
|
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)
|
// code:(Maybe ^Cell) data:(Maybe ^Cell) library:(HashmapE 256 SimpleLib)
|
||||||
|
@ -3275,8 +3316,8 @@ bool Transaction::compute_state(const SerializeConfig& cfg) {
|
||||||
} else {
|
} else {
|
||||||
CHECK(acc_status == Account::acc_active && !was_frozen && !was_deleted);
|
CHECK(acc_status == Account::acc_active && !was_frozen && !was_deleted);
|
||||||
si_pos = cb.size_ext() + 1;
|
si_pos = cb.size_ext() + 1;
|
||||||
CHECK(account.split_depth_ ? cb.store_long_bool(account.split_depth_ + 96, 7) // account_active$1 _:StateInit
|
CHECK(fixed_prefix_length ? cb.store_long_bool(fixed_prefix_length + 96, 7) // account_active$1 _:StateInit
|
||||||
: cb.store_long_bool(2, 2)); // ... split_depth:(Maybe (## 5))
|
: 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(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));
|
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)
|
// 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";
|
LOG(INFO) << "Compute used storage took " << timer.elapsed() << "s";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CHECK(cb.store_long_bool(1, 1) // account$1
|
CHECK(cb.store_long_bool(1, 1) // account$1
|
||||||
&& cb.append_cellslice_bool(account.my_addr) // addr:MsgAddressInt
|
&& 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.cells) // storage_used$_ cells:(VarUInteger 7)
|
||||||
&& block::store_UInt7(cb, stats.bits) // bits:(VarUInteger 7)
|
&& block::store_UInt7(cb, stats.bits) // bits:(VarUInteger 7)
|
||||||
&& block::store_UInt7(cb, stats.public_cells) // public_cells:(VarUInteger 7)
|
&& block::store_UInt7(cb, stats.public_cells) // public_cells:(VarUInteger 7)
|
||||||
|
@ -3676,12 +3717,14 @@ Ref<vm::Cell> Transaction::commit(Account& acc) {
|
||||||
CHECK((const void*)&acc == (const void*)&account);
|
CHECK((const void*)&acc == (const void*)&account);
|
||||||
// export all fields modified by the Transaction into original account
|
// export all fields modified by the Transaction into original account
|
||||||
// NB: this is the only method that modifies 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) {
|
acc_status == Account::acc_active) {
|
||||||
LOG(DEBUG) << "setting address rewriting info for newly-activated account " << acc.addr.to_hex()
|
LOG(DEBUG) << "setting address rewriting info for newly-activated account " << acc.addr.to_hex()
|
||||||
<< " with split_depth=" << new_split_depth
|
<< " with addr_rewrite_length=" << new_addr_rewrite_length
|
||||||
<< ", orig_addr_rewrite=" << orig_addr_rewrite.bits().to_hex(new_split_depth);
|
<< ", orig_addr_rewrite=" << orig_addr_rewrite.bits().to_hex(new_addr_rewrite_length);
|
||||||
CHECK(acc.init_rewrite_addr(new_split_depth, orig_addr_rewrite.bits()));
|
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.status = (acc_status == Account::acc_deleted ? Account::acc_nonexist : acc_status);
|
||||||
acc.last_trans_lt_ = start_lt;
|
acc.last_trans_lt_ = start_lt;
|
||||||
|
@ -3705,6 +3748,7 @@ Ref<vm::Cell> Transaction::commit(Account& acc) {
|
||||||
if (acc.status == Account::acc_active) {
|
if (acc.status == Account::acc_active) {
|
||||||
acc.tick = new_tick;
|
acc.tick = new_tick;
|
||||||
acc.tock = new_tock;
|
acc.tock = new_tock;
|
||||||
|
acc.fixed_prefix_length = new_fixed_prefix_length;
|
||||||
} else {
|
} else {
|
||||||
CHECK(acc.deactivate());
|
CHECK(acc.deactivate());
|
||||||
}
|
}
|
||||||
|
@ -3905,6 +3949,7 @@ td::Status FetchConfigParams::fetch_config_params(
|
||||||
compute_phase_cfg->size_limits = size_limits;
|
compute_phase_cfg->size_limits = size_limits;
|
||||||
compute_phase_cfg->precompiled_contracts = config.get_precompiled_contracts_config();
|
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->allow_external_unfreeze = compute_phase_cfg->global_version >= 8;
|
||||||
|
compute_phase_cfg->disable_anycast = config.get_global_version() >= 10;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// compute action_phase_cfg
|
// 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->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;
|
||||||
action_phase_cfg->extra_currency_v2 = config.get_global_version() >= 10;
|
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->extra_currency_v2 = config.get_global_version() >= 10;
|
||||||
|
serialize_cfg->disable_anycast = config.get_global_version() >= 10;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// fetch block_grams_created
|
// fetch block_grams_created
|
||||||
|
|
|
@ -130,6 +130,7 @@ struct ComputePhaseConfig {
|
||||||
PrecompiledContractsConfig precompiled_contracts;
|
PrecompiledContractsConfig precompiled_contracts;
|
||||||
bool dont_run_precompiled_ = false;
|
bool dont_run_precompiled_ = false;
|
||||||
bool allow_external_unfreeze{false};
|
bool allow_external_unfreeze{false};
|
||||||
|
bool disable_anycast{false};
|
||||||
|
|
||||||
ComputePhaseConfig() : gas_price(0), gas_limit(0), special_gas_limit(0), gas_credit(0) {
|
ComputePhaseConfig() : gas_price(0), gas_limit(0), special_gas_limit(0), gas_credit(0) {
|
||||||
compute_threshold();
|
compute_threshold();
|
||||||
|
@ -172,6 +173,7 @@ struct ActionPhaseConfig {
|
||||||
bool reserve_extra_enabled{false};
|
bool reserve_extra_enabled{false};
|
||||||
bool extra_currency_v2{false};
|
bool extra_currency_v2{false};
|
||||||
td::optional<td::Bits256> mc_blackhole_addr;
|
td::optional<td::Bits256> mc_blackhole_addr;
|
||||||
|
bool disable_anycast{false};
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -179,6 +181,7 @@ struct ActionPhaseConfig {
|
||||||
|
|
||||||
struct SerializeConfig {
|
struct SerializeConfig {
|
||||||
bool extra_currency_v2{false};
|
bool extra_currency_v2{false};
|
||||||
|
bool disable_anycast{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CreditPhase {
|
struct CreditPhase {
|
||||||
|
@ -252,12 +255,13 @@ struct Account {
|
||||||
bool is_special{false};
|
bool is_special{false};
|
||||||
bool tick{false};
|
bool tick{false};
|
||||||
bool tock{false};
|
bool tock{false};
|
||||||
bool split_depth_set_{false};
|
int fixed_prefix_length{0};
|
||||||
unsigned char split_depth_{0};
|
|
||||||
int verbosity{3 * 0};
|
int verbosity{3 * 0};
|
||||||
ton::UnixTime now_{0};
|
ton::UnixTime now_{0};
|
||||||
ton::WorkchainId workchain{ton::workchainInvalid};
|
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; // 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)
|
ton::StdSmcAddress addr_orig; // address indicated in smart-contract data (must coincide with hash of StateInit)
|
||||||
Ref<vm::CellSlice> my_addr; // address as stored in the smart contract (MsgAddressInt); corresponds to `addr_orig` + anycast info
|
Ref<vm::CellSlice> 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() = default;
|
||||||
Account(ton::WorkchainId wc, td::ConstBitPtr _addr) : workchain(wc), addr(_addr) {
|
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 {
|
block::CurrencyCollection get_balance() const {
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
|
@ -290,7 +291,7 @@ struct Account {
|
||||||
bool unpack(Ref<vm::CellSlice> account, ton::UnixTime now, bool special);
|
bool unpack(Ref<vm::CellSlice> account, ton::UnixTime now, bool special);
|
||||||
bool init_new(ton::UnixTime now);
|
bool init_new(ton::UnixTime now);
|
||||||
bool deactivate();
|
bool deactivate();
|
||||||
bool recompute_tmp_addr(Ref<vm::CellSlice>& tmp_addr, int split_depth, td::ConstBitPtr orig_addr_rewrite) const;
|
bool recompute_tmp_addr(Ref<vm::CellSlice>& tmp_addr, int fixed_prefix_length, td::ConstBitPtr orig_addr_rewrite) const;
|
||||||
td::RefInt256 compute_storage_fees(ton::UnixTime now, const std::vector<block::StoragePrices>& pricing) const;
|
td::RefInt256 compute_storage_fees(ton::UnixTime now, const std::vector<block::StoragePrices>& pricing) const;
|
||||||
bool is_masterchain() const {
|
bool is_masterchain() const {
|
||||||
return workchain == ton::masterchainId;
|
return workchain == ton::masterchainId;
|
||||||
|
@ -306,10 +307,10 @@ struct Account {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend struct transaction::Transaction;
|
friend struct transaction::Transaction;
|
||||||
bool set_split_depth(int split_depth);
|
bool set_addr_rewrite_length(int new_length);
|
||||||
bool check_split_depth(int split_depth) const;
|
bool check_addr_rewrite_length(int length) const;
|
||||||
bool forget_split_depth();
|
bool forget_addr_rewrite_length();
|
||||||
bool init_rewrite_addr(int split_depth, td::ConstBitPtr orig_addr_rewrite);
|
bool init_rewrite_addr(int rewrite_length, td::ConstBitPtr orig_addr_rewrite);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool unpack_address(vm::CellSlice& addr_cs);
|
bool unpack_address(vm::CellSlice& addr_cs);
|
||||||
|
@ -346,7 +347,9 @@ struct Transaction {
|
||||||
bool orig_addr_rewrite_set{false};
|
bool orig_addr_rewrite_set{false};
|
||||||
bool new_tick;
|
bool new_tick;
|
||||||
bool new_tock;
|
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;
|
ton::UnixTime now;
|
||||||
int acc_status;
|
int acc_status;
|
||||||
int verbosity{3 * 0};
|
int verbosity{3 * 0};
|
||||||
|
@ -382,7 +385,7 @@ struct Transaction {
|
||||||
Transaction(const Account& _account, int ttype, ton::LogicalTime req_start_lt, ton::UnixTime _now,
|
Transaction(const Account& _account, int ttype, ton::LogicalTime req_start_lt, ton::UnixTime _now,
|
||||||
Ref<vm::Cell> _inmsg = {});
|
Ref<vm::Cell> _inmsg = {});
|
||||||
bool unpack_input_msg(bool ihr_delivered, const ActionPhaseConfig* cfg);
|
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_storage_phase(const StoragePhaseConfig& cfg, bool force_collect = true, bool adjust_msg_value = false);
|
||||||
bool prepare_credit_phase();
|
bool prepare_credit_phase();
|
||||||
td::uint64 gas_bought_for(const ComputePhaseConfig& cfg, td::RefInt256 nanograms);
|
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);
|
int try_action_reserve_currency(vm::CellSlice& cs, ActionPhase& ap, const ActionPhaseConfig& cfg);
|
||||||
bool check_replace_src_addr(Ref<vm::CellSlice>& src_addr) const;
|
bool check_replace_src_addr(Ref<vm::CellSlice>& src_addr) const;
|
||||||
bool check_rewrite_dest_addr(Ref<vm::CellSlice>& dest_addr, const ActionPhaseConfig& cfg,
|
bool check_rewrite_dest_addr(Ref<vm::CellSlice>& 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_storage_phase(vm::CellBuilder& cb);
|
||||||
bool serialize_credit_phase(vm::CellBuilder& cb);
|
bool serialize_credit_phase(vm::CellBuilder& cb);
|
||||||
bool serialize_compute_phase(vm::CellBuilder& cb);
|
bool serialize_compute_phase(vm::CellBuilder& cb);
|
||||||
|
|
|
@ -1380,10 +1380,13 @@ int exec_store_var_integer(VmState* st, int len_bits, bool sgnd, bool quiet) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool skip_maybe_anycast(CellSlice& cs) {
|
bool skip_maybe_anycast(CellSlice& cs, int global_version) {
|
||||||
if (cs.prefetch_ulong(1) != 1) {
|
if (cs.prefetch_ulong(1) != 1) {
|
||||||
return cs.advance(1);
|
return cs.advance(1);
|
||||||
}
|
}
|
||||||
|
if (global_version >= 10) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
unsigned depth;
|
unsigned depth;
|
||||||
return cs.advance(1) // just$1
|
return cs.advance(1) // just$1
|
||||||
&& cs.fetch_uint_leq(30, depth) // anycast_info$_ depth:(#<= 30)
|
&& 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;
|
&& 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)) {
|
switch ((unsigned)cs.fetch_ulong(2)) {
|
||||||
case 0: // addr_none$00 = MsgAddressExt;
|
case 0: // addr_none$00 = MsgAddressExt;
|
||||||
return true;
|
return true;
|
||||||
|
@ -1400,15 +1403,18 @@ bool skip_message_addr(CellSlice& cs) {
|
||||||
return cs.fetch_uint_to(9, len) // len:(## 9)
|
return cs.fetch_uint_to(9, len) // len:(## 9)
|
||||||
&& cs.advance(len); // external_address:(bits len) = MsgAddressExt;
|
&& cs.advance(len); // external_address:(bits len) = MsgAddressExt;
|
||||||
}
|
}
|
||||||
case 2: { // addr_std$10
|
case 2: { // addr_std$10
|
||||||
return skip_maybe_anycast(cs) // anycast:(Maybe Anycast)
|
return skip_maybe_anycast(cs, global_version) // anycast:(Maybe Anycast)
|
||||||
&& cs.advance(8 + 256); // workchain_id:int8 address:bits256 = MsgAddressInt;
|
&& cs.advance(8 + 256); // workchain_id:int8 address:bits256 = MsgAddressInt;
|
||||||
}
|
}
|
||||||
case 3: { // addr_var$11
|
case 3: { // addr_var$11
|
||||||
|
if (global_version >= 10) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
unsigned len;
|
unsigned len;
|
||||||
return skip_maybe_anycast(cs) // anycast:(Maybe Anycast)
|
return skip_maybe_anycast(cs, global_version) // anycast:(Maybe Anycast)
|
||||||
&& cs.fetch_uint_to(9, len) // addr_len:(## 9)
|
&& cs.fetch_uint_to(9, len) // addr_len:(## 9)
|
||||||
&& cs.advance(32 + len); // workchain_id:int32 address:(bits addr_len) = MsgAddressInt;
|
&& cs.advance(32 + len); // workchain_id:int32 address:(bits addr_len) = MsgAddressInt;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -1420,7 +1426,7 @@ int exec_load_message_addr(VmState* st, bool quiet) {
|
||||||
Stack& stack = st->get_stack();
|
Stack& stack = st->get_stack();
|
||||||
auto csr = stack.pop_cellslice();
|
auto csr = stack.pop_cellslice();
|
||||||
td::Ref<CellSlice> addr{true};
|
td::Ref<CellSlice> 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(addr));
|
||||||
stack.push_cellslice(std::move(csr));
|
stack.push_cellslice(std::move(csr));
|
||||||
if (quiet) {
|
if (quiet) {
|
||||||
|
@ -1433,11 +1439,14 @@ int exec_load_message_addr(VmState* st, bool quiet) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_maybe_anycast(CellSlice& cs, StackEntry& res) {
|
bool parse_maybe_anycast(CellSlice& cs, StackEntry& res, int global_version) {
|
||||||
res = StackEntry{};
|
res = StackEntry{};
|
||||||
if (cs.prefetch_ulong(1) != 1) {
|
if (cs.prefetch_ulong(1) != 1) {
|
||||||
return cs.advance(1);
|
return cs.advance(1);
|
||||||
}
|
}
|
||||||
|
if (global_version >= 10) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
unsigned depth;
|
unsigned depth;
|
||||||
Ref<CellSlice> pfx;
|
Ref<CellSlice> pfx;
|
||||||
if (cs.advance(1) // just$1
|
if (cs.advance(1) // just$1
|
||||||
|
@ -1450,7 +1459,7 @@ bool parse_maybe_anycast(CellSlice& cs, StackEntry& res) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_message_addr(CellSlice& cs, std::vector<StackEntry>& res) {
|
bool parse_message_addr(CellSlice& cs, std::vector<StackEntry>& res, int global_version) {
|
||||||
res.clear();
|
res.clear();
|
||||||
switch ((unsigned)cs.fetch_ulong(2)) {
|
switch ((unsigned)cs.fetch_ulong(2)) {
|
||||||
case 0: // addr_none$00 = MsgAddressExt;
|
case 0: // addr_none$00 = MsgAddressExt;
|
||||||
|
@ -1471,9 +1480,9 @@ bool parse_message_addr(CellSlice& cs, std::vector<StackEntry>& res) {
|
||||||
StackEntry v;
|
StackEntry v;
|
||||||
int workchain;
|
int workchain;
|
||||||
Ref<CellSlice> addr;
|
Ref<CellSlice> addr;
|
||||||
if (parse_maybe_anycast(cs, v) // anycast:(Maybe Anycast)
|
if (parse_maybe_anycast(cs, v, global_version) // anycast:(Maybe Anycast)
|
||||||
&& cs.fetch_int_to(8, workchain) // workchain_id:int8
|
&& cs.fetch_int_to(8, workchain) // workchain_id:int8
|
||||||
&& cs.fetch_subslice_to(256, addr)) { // address:bits256 = MsgAddressInt;
|
&& cs.fetch_subslice_to(256, addr)) { // address:bits256 = MsgAddressInt;
|
||||||
res.emplace_back(td::make_refint(2));
|
res.emplace_back(td::make_refint(2));
|
||||||
res.emplace_back(std::move(v));
|
res.emplace_back(std::move(v));
|
||||||
res.emplace_back(td::make_refint(workchain));
|
res.emplace_back(td::make_refint(workchain));
|
||||||
|
@ -1483,13 +1492,16 @@ bool parse_message_addr(CellSlice& cs, std::vector<StackEntry>& res) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3: { // addr_var$11
|
case 3: { // addr_var$11
|
||||||
|
if (global_version >= 10) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
StackEntry v;
|
StackEntry v;
|
||||||
int len, workchain;
|
int len, workchain;
|
||||||
Ref<CellSlice> addr;
|
Ref<CellSlice> addr;
|
||||||
if (parse_maybe_anycast(cs, v) // anycast:(Maybe Anycast)
|
if (parse_maybe_anycast(cs, v, global_version) // anycast:(Maybe Anycast)
|
||||||
&& cs.fetch_uint_to(9, len) // addr_len:(## 9)
|
&& cs.fetch_uint_to(9, len) // addr_len:(## 9)
|
||||||
&& cs.fetch_int_to(32, workchain) // workchain_id:int32
|
&& cs.fetch_int_to(32, workchain) // workchain_id:int32
|
||||||
&& cs.fetch_subslice_to(len, addr)) { // address:(bits addr_len) = MsgAddressInt;
|
&& cs.fetch_subslice_to(len, addr)) { // address:(bits addr_len) = MsgAddressInt;
|
||||||
res.emplace_back(td::make_refint(3));
|
res.emplace_back(td::make_refint(3));
|
||||||
res.emplace_back(std::move(v));
|
res.emplace_back(std::move(v));
|
||||||
res.emplace_back(td::make_refint(workchain));
|
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 csr = stack.pop_cellslice();
|
||||||
auto& cs = csr.write();
|
auto& cs = csr.write();
|
||||||
std::vector<StackEntry> res;
|
std::vector<StackEntry> 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) {
|
if (quiet) {
|
||||||
stack.push_bool(false);
|
stack.push_bool(false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1548,7 +1560,7 @@ int exec_rewrite_message_addr(VmState* st, bool allow_var_addr, bool quiet) {
|
||||||
auto csr = stack.pop_cellslice();
|
auto csr = stack.pop_cellslice();
|
||||||
auto& cs = csr.write();
|
auto& cs = csr.write();
|
||||||
std::vector<StackEntry> tuple;
|
std::vector<StackEntry> 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) {
|
if (quiet) {
|
||||||
stack.push_bool(false);
|
stack.push_bool(false);
|
||||||
return 0;
|
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) {
|
bool load_coins_q(CellSlice& cs, td::RefInt256& res, bool quiet) {
|
||||||
return load_var_integer_q(cs, res, 4, false, 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;
|
res = cs;
|
||||||
if (!skip_message_addr(cs)) {
|
if (!skip_message_addr(cs, global_version)) {
|
||||||
cs = res;
|
cs = res;
|
||||||
if (quiet) {
|
if (quiet) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2038,10 +2050,11 @@ bool load_msg_addr_q(CellSlice& cs, CellSlice& res, bool quiet) {
|
||||||
res.cut_tail(cs);
|
res.cut_tail(cs);
|
||||||
return true;
|
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
|
// Like exec_rewrite_message_addr, but for std address case
|
||||||
std::vector<StackEntry> tuple;
|
std::vector<StackEntry> tuple;
|
||||||
if (!(parse_message_addr(cs, tuple) && cs.empty_ext())) {
|
if (!(parse_message_addr(cs, tuple, global_version) && cs.empty_ext())) {
|
||||||
if (quiet) {
|
if (quiet) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2076,14 +2089,14 @@ td::RefInt256 load_var_integer(CellSlice& cs, int len_bits, bool sgnd) {
|
||||||
td::RefInt256 load_coins(CellSlice& cs) {
|
td::RefInt256 load_coins(CellSlice& cs) {
|
||||||
return load_var_integer(cs, 4, false);
|
return load_var_integer(cs, 4, false);
|
||||||
}
|
}
|
||||||
CellSlice load_msg_addr(CellSlice& cs) {
|
CellSlice load_msg_addr(CellSlice& cs, int global_version) {
|
||||||
CellSlice addr;
|
CellSlice addr;
|
||||||
load_msg_addr_q(cs, addr, false);
|
load_msg_addr_q(cs, addr, global_version, false);
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
std::pair<ton::WorkchainId, ton::StdSmcAddress> parse_std_addr(CellSlice cs) {
|
std::pair<ton::WorkchainId, ton::StdSmcAddress> parse_std_addr(CellSlice cs, int global_version) {
|
||||||
std::pair<ton::WorkchainId, ton::StdSmcAddress> res;
|
std::pair<ton::WorkchainId, ton::StdSmcAddress> 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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,14 +32,15 @@ namespace util {
|
||||||
// "_q" functions throw on error if not quiet, return false if quiet (leaving cs unchanged)
|
// "_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_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_coins_q(CellSlice& cs, td::RefInt256& res, bool 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);
|
||||||
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);
|
||||||
|
|
||||||
// Non-"_q" functions throw on error
|
// Non-"_q" functions throw on error
|
||||||
td::RefInt256 load_var_integer(CellSlice& cs, int len_bits, bool sgnd);
|
td::RefInt256 load_var_integer(CellSlice& cs, int len_bits, bool sgnd);
|
||||||
td::RefInt256 load_coins(CellSlice& cs);
|
td::RefInt256 load_coins(CellSlice& cs);
|
||||||
CellSlice load_msg_addr(CellSlice& cs);
|
CellSlice load_msg_addr(CellSlice& cs, int global_version);
|
||||||
std::pair<ton::WorkchainId, ton::StdSmcAddress> parse_std_addr(CellSlice cs);
|
std::pair<ton::WorkchainId, ton::StdSmcAddress> parse_std_addr(CellSlice cs, int global_version);
|
||||||
|
|
||||||
// store_... functions throw on error if not quiet, return false if quiet (leaving cb unchanged)
|
// 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);
|
bool store_var_integer(CellBuilder& cb, const td::RefInt256& x, int len_bits, bool sgnd, bool quiet = false);
|
||||||
|
|
|
@ -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.
|
Various features are enabled depending on the global version.
|
||||||
|
|
||||||
## Version 4
|
## 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 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
|
### 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`
|
* Unpaid storage fee is now saved to `due_payment`
|
||||||
|
|
||||||
## Version 5
|
## Version 5
|
||||||
|
__Enabled in mainnet on 2024-02-03__
|
||||||
|
|
||||||
### Gas limits
|
### Gas limits
|
||||||
Version 5 enables higher gas limits for special contracts.
|
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.
|
* `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
|
## Version 6
|
||||||
|
__Enabled in mainnet on 2024-03-16__
|
||||||
|
|
||||||
### c7 tuple
|
### c7 tuple
|
||||||
**c7** tuple extended from 14 to 17 elements:
|
**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
|
## 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.
|
[Explicitly nullify](https://github.com/ton-blockchain/ton/pull/957/files) `due_payment` after due reimbursment.
|
||||||
|
|
||||||
## Version 8
|
## 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.
|
- 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`.
|
||||||
|
@ -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.
|
- Don't use user-provided `fwd_fee` and `ihr_fee` for internal messages.
|
||||||
|
|
||||||
## Version 9
|
## Version 9
|
||||||
|
__Enabled in mainnet on 2025-02-13__
|
||||||
|
|
||||||
### c7 tuple
|
### 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.
|
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.
|
- 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`.
|
- 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
|
### TVM changes
|
||||||
- `SENDMSG` calculates messages size and fees without extra currencies, uses new +64 and +128 mode behavior.
|
- `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.
|
- `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`.
|
||||||
|
|
|
@ -977,6 +977,7 @@ bool ValidateQuery::fetch_config_params() {
|
||||||
compute_phase_cfg_.size_limits = size_limits;
|
compute_phase_cfg_.size_limits = size_limits;
|
||||||
compute_phase_cfg_.precompiled_contracts = config_->get_precompiled_contracts_config();
|
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_.allow_external_unfreeze = compute_phase_cfg_.global_version >= 8;
|
||||||
|
compute_phase_cfg_.disable_anycast = config_->get_global_version() >= 10;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// compute action_phase_cfg
|
// 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_.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;
|
||||||
action_phase_cfg_.extra_currency_v2 = config_->get_global_version() >= 10;
|
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_.extra_currency_v2 = config_->get_global_version() >= 10;
|
||||||
|
serialize_cfg_.disable_anycast = config_->get_global_version() >= 10;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// fetch block_grams_created
|
// fetch block_grams_created
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue