Skip to content

Commit

Permalink
Merge pull request #606 from ton-blockchain/testnet
Browse files Browse the repository at this point in the history
Merge 01.2023 update
  • Loading branch information
EmelyanenkoK authored Jan 31, 2023
2 parents f59c363 + 9835ac8 commit fc9542f
Show file tree
Hide file tree
Showing 92 changed files with 14,962 additions and 96 deletions.
7 changes: 7 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,10 @@ Node update:
10. TON Storage: added storage-daemon (create, download bag of Files, storage-provider staff), added storage-daemon-cli

Besides the work of the core team, this update is based on the efforts of @vtamara (help with abseil-cpp upgrade), @krigga(in-place modification of global variables) and third-party security auditors.

## 01.2023 Update
1. Added ConfigParam 44: `SuspendedAddressList`. Upon being set this config suspends initialisation of **uninit** addresses from the list for given time.
2. FunC: `v0.4.1` added pragmas for precise control of computation order
3. FunC: fixed compiler crashes for some exotic inputs
4. FunC: added legacy tester, a collection of smart-contracts which is used to check whether compilator update change compilation result
5. Improved archive manager: proper handling of recently garbage-collected blocks
12 changes: 8 additions & 4 deletions crypto/block/block-parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -653,16 +653,20 @@ struct TrComputeInternal1 final : TLB_Complex {
};

struct ComputeSkipReason final : TLB {
enum { cskip_no_state = 0, cskip_bad_state = 1, cskip_no_gas = 2 };
enum { cskip_no_state = 0, cskip_bad_state = 1, cskip_no_gas = 2, cskip_suspended = 3 };
int get_size(const vm::CellSlice& cs) const override {
return 2;
return cs.prefetch_ulong(2) == 3 ? 3 : 2;
}
bool validate_skip(int* ops, vm::CellSlice& cs, bool weak = false) const override {
return get_tag(cs) >= 0 && cs.advance(2);
int tag = get_tag(cs);
return tag >= 0 && cs.advance(tag == 3 ? 3 : 2);
}
int get_tag(const vm::CellSlice& cs) const override {
int t = (int)cs.prefetch_ulong(2);
return t < 3 ? t : -1;
if (t == 3 && cs.prefetch_ulong(3) != 0b110) {
return -1;
}
return t;
}
};

Expand Down
5 changes: 5 additions & 0 deletions crypto/block/block.tlb
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ tr_phase_compute_vm$1 success:Bool msg_state_used:Bool
cskip_no_state$00 = ComputeSkipReason;
cskip_bad_state$01 = ComputeSkipReason;
cskip_no_gas$10 = ComputeSkipReason;
cskip_suspended$110 = ComputeSkipReason;

tr_phase_action$_ success:Bool valid:Bool no_funds:Bool
status_change:AccStatusChange
Expand Down Expand Up @@ -757,6 +758,10 @@ size_limits_config_v2#02 max_msg_bits:uint32 max_msg_cells:uint32 max_library_ce
max_ext_msg_size:uint32 max_ext_msg_depth:uint16 max_acc_state_cells:uint32 max_acc_state_bits:uint32 = SizeLimitsConfig;
_ SizeLimitsConfig = ConfigParam 43;

// key is [ wc:int32 addr:uint256 ]
suspended_address_list#00 addresses:(HashmapE 288 Unit) suspended_until:uint32 = SuspendedAddressList;
_ SuspendedAddressList = ConfigParam 44;

oracle_bridge_params#_ bridge_address:bits256 oracle_mutlisig_address:bits256 oracles:(HashmapE 256 uint256) external_chain_address:bits256 = OracleBridgeParams;
_ OracleBridgeParams = ConfigParam 71; // Ethereum bridge
_ OracleBridgeParams = ConfigParam 72; // Binance Smart Chain bridge
Expand Down
9 changes: 9 additions & 0 deletions crypto/block/mc-config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1945,6 +1945,15 @@ td::Result<SizeLimitsConfig> Config::get_size_limits_config() const {
return limits;
}

std::unique_ptr<vm::Dictionary> Config::get_suspended_addresses(ton::UnixTime now) const {
td::Ref<vm::Cell> param = get_config_param(44);
gen::SuspendedAddressList::Record rec;
if (param.is_null() || !tlb::unpack_cell(param, rec) || rec.suspended_until <= now) {
return {};
}
return std::make_unique<vm::Dictionary>(rec.addresses->prefetch_ref(), 288);
}

td::Result<std::pair<ton::UnixTime, ton::UnixTime>> Config::unpack_validator_set_start_stop(Ref<vm::Cell> vset_root) {
if (vset_root.is_null()) {
return td::Status::Error("validator set absent");
Expand Down
1 change: 1 addition & 0 deletions crypto/block/mc-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,7 @@ class Config {
ton::CatchainSeqno cc_seqno) const;
std::vector<ton::ValidatorDescr> compute_total_validator_set(int next) const;
td::Result<SizeLimitsConfig> get_size_limits_config() const;
std::unique_ptr<vm::Dictionary> get_suspended_addresses(ton::UnixTime now) const;
static std::vector<ton::ValidatorDescr> do_compute_validator_set(const block::CatchainValidatorsConfig& ccv_conf,
ton::ShardIdFull shard,
const block::ValidatorSet& vset, ton::UnixTime time,
Expand Down
21 changes: 21 additions & 0 deletions crypto/block/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,20 @@ bool ComputePhaseConfig::parse_GasLimitsPrices_internal(Ref<vm::CellSlice> cs, t
return true;
}

bool ComputePhaseConfig::is_address_suspended(ton::WorkchainId wc, td::Bits256 addr) const {
if (!suspended_addresses) {
return false;
}
try {
vm::CellBuilder key;
key.store_long_bool(wc, 32);
key.store_bits_bool(addr);
return !suspended_addresses->lookup(key.data_bits(), 288).is_null();
} catch (vm::VmError) {
return false;
}
}

void ComputePhaseConfig::compute_threshold() {
gas_price256 = td::make_refint(gas_price);
if (gas_limit > flat_gas_limit) {
Expand Down Expand Up @@ -1006,6 +1020,11 @@ bool Transaction::prepare_compute_phase(const ComputePhaseConfig& cfg) {
if (in_msg_state.not_null() &&
(acc_status == Account::acc_uninit ||
(acc_status == Account::acc_frozen && account.state_hash == in_msg_state->get_hash().bits()))) {
if (acc_status == Account::acc_uninit && cfg.is_address_suspended(account.workchain, account.addr)) {
LOG(DEBUG) << "address is suspended, skipping compute phase";
cp.skip_reason = ComputePhase::sk_suspended;
return true;
}
use_msg_state = true;
if (!(unpack_msg_state() && account.check_split_depth(new_split_depth))) {
LOG(DEBUG) << "cannot unpack in_msg_state, or it has bad split_depth; cannot init account state";
Expand Down Expand Up @@ -2263,6 +2282,8 @@ bool Transaction::serialize_compute_phase(vm::CellBuilder& cb) {
return cb.store_long_bool(1, 3); // cskip_bad_state$01 = ComputeSkipReason;
case ComputePhase::sk_no_gas:
return cb.store_long_bool(2, 3); // cskip_no_gas$10 = ComputeSkipReason;
case ComputePhase::sk_suspended:
return cb.store_long_bool(0b0110, 4); // cskip_suspended$110 = ComputeSkipReason;
case ComputePhase::sk_none:
break;
default:
Expand Down
4 changes: 3 additions & 1 deletion crypto/block/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ struct ComputePhaseConfig {
td::BitArray<256> block_rand_seed;
bool with_vm_log{false};
td::uint16 max_vm_data_depth = 512;
std::unique_ptr<vm::Dictionary> suspended_addresses;
ComputePhaseConfig(td::uint64 _gas_price = 0, td::uint64 _gas_limit = 0, td::uint64 _gas_credit = 0)
: gas_price(_gas_price), gas_limit(_gas_limit), special_gas_limit(_gas_limit), gas_credit(_gas_credit) {
compute_threshold();
Expand All @@ -132,6 +133,7 @@ struct ComputePhaseConfig {
}
bool parse_GasLimitsPrices(Ref<vm::CellSlice> cs, td::RefInt256& freeze_due_limit, td::RefInt256& delete_due_limit);
bool parse_GasLimitsPrices(Ref<vm::Cell> cell, td::RefInt256& freeze_due_limit, td::RefInt256& delete_due_limit);
bool is_address_suspended(ton::WorkchainId wc, td::Bits256 addr) const;

private:
bool parse_GasLimitsPrices_internal(Ref<vm::CellSlice> cs, td::RefInt256& freeze_due_limit,
Expand All @@ -157,7 +159,7 @@ struct CreditPhase {
};

struct ComputePhase {
enum { sk_none, sk_no_state, sk_bad_state, sk_no_gas };
enum { sk_none, sk_no_state, sk_bad_state, sk_no_gas, sk_suspended };
int skip_reason{sk_none};
bool success{false};
bool msg_state_used{false};
Expand Down
12 changes: 9 additions & 3 deletions crypto/fift/lib/Asm.fif
Original file line number Diff line number Diff line change
Expand Up @@ -875,9 +875,15 @@ x{EDFB} @Defop SAMEALTSAVE
} dup : PREPARE : PREPAREDICT
//
// inline support
{ dup sbits { @addop } {
dup srefs 1- abort"exactly one reference expected in inline"
ref@ CALLREF } cond
{ dup sbits
{ @addop }
{
dup srefs //
{ ref@ CALLREF }
{ drop }
cond
}
cond
} : INLINE
//
// throwing and handling exceptions
Expand Down
145 changes: 145 additions & 0 deletions crypto/func/auto-tests/legacy_tester.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import os
import os.path
import subprocess
import sys
import tempfile
import shutil

add_pragmas = [] #["allow-post-modification", "compute-asm-ltr"];

tests = [
# note, that deployed version of elector,config and multisig differ since it is compilled with func-0.1.0.
# Newer compillators optimize arithmetic and logic expression that can be calculated at the compile time
["elector/elector-code.fc", 115226404411715505328583639896096915745686314074575650766750648324043316883483],
["config/config-code.fc", 10913070768607625342121305745084703121685937915388357634624451844356456145601],
["eth-bridge-multisig/multisig-code.fc", 101509909129354488841890823627011033360100627957439967918234053299675481277954],

["bsc-bridge-collector/votes-collector.fc", 62190447221288642706570413295807615918589884489514159926097051017036969900417],
["uni-lock-wallet/uni-lockup-wallet.fc", 61959738324779104851267145467044677651344601417998258530238254441977103654381],
["nft-collection/nft-collection-editable.fc", 45561997735512210616567774035540357815786262097548276229169737015839077731274],
["dns-collection/nft-collection.fc", 107999822699841936063083742021519765435859194241091312445235370766165379261859],


# note, that deployed version of tele-nft-item differs since it is compilled with func-0.3.0.
# After introducing of try/catch construction, c2 register is not always the default one.
# Thus it is necessary to save it upon jumps, differences of deployed and below compilled is that
# "c2 SAVE" is added to the beginning of recv_internal. It does not change behavior.
["tele-nft-item/nft-item.fc", 69777543125381987786450436977742010705076866061362104025338034583422166453344],

["storage/storage-contract.fc", 91377830060355733016937375216020277778264560226873154627574229667513068328151],
["storage/storage-provider.fc", 13618336676213331164384407184540461509022654507176709588621016553953760588122],
["nominator-pool/pool.fc", 69767057279163099864792356875696330339149706521019810113334238732928422055375],
["jetton-minter/jetton-minter.fc", 9028309926287301331466371999814928201427184114165428257502393474125007156494],
["gg-marketplace/nft-marketplace-v2.fc", 92199806964112524639740773542356508485601908152150843819273107618799016205930],
["jetton-wallet/jetton-wallet.fc", 86251125787443633057458168028617933212663498001665054651523310772884328206542],
["whales-nominators/nominators.fc", 8941364499854379927692172316865293429893094891593442801401542636695127885153],


["tact-examples/treasure_Treasure.code.fc", 13962538639825790677138656603323869918938565499584297120566680287245364723897],
["tact-examples/jetton_SampleJetton.code.fc", 94076762218493729104783735200107713211245710256802265203823917715299139499110],
["tact-examples/jetton_JettonDefaultWallet.code.fc", 29421313492520031238091587108198906058157443241743283101866538036369069620563],
["tact-examples/maps_MapTestContract.code.fc", 22556550222249123835909180266811414538971143565993192846012583552876721649744],
]

def getenv(name, default=None):
if name in os.environ:
return os.environ[name]
if default is None:
print("Environment variable", name, "is not set", file=sys.stderr)
exit(1)
return default

FUNC_EXECUTABLE = getenv("FUNC_EXECUTABLE", "func")
FIFT_EXECUTABLE = getenv("FIFT_EXECUTABLE", "fift")
FIFT_LIBS = getenv("FIFTPATH")
TMP_DIR = tempfile.mkdtemp()

COMPILED_FIF = os.path.join(TMP_DIR, "compiled.fif")
RUNNER_FIF = os.path.join(TMP_DIR, "runner.fif")

TESTS_DIR = "legacy_tests"

class ExecutionError(Exception):
pass

def pre_process_func(f):
shutil.copyfile(f, f+"_backup")
with open(f, "r") as src:
sources = src.read()
with open(f, "w") as src:
for pragma in add_pragmas:
src.write("#pragma %s;\n"%pragma)
src.write(sources)

def post_process_func(f):
shutil.move(f+"_backup", f)

def compile_func(f):
res = None
try:
pre_process_func(f)
if "storage-provider.fc" in f :
# This contract requires building of storage-contract to include it as ref
with open(f, "r") as src:
sources = src.read()
COMPILED_ST_BOC = os.path.join(TMP_DIR, "storage-contract-code.boc")
sources = sources.replace("storage-contract-code.boc", COMPILED_ST_BOC)
with open(f, "w") as src:
src.write(sources)
COMPILED_ST_FIF = os.path.join(TMP_DIR, "storage-contract.fif")
COMPILED_ST_BOC = os.path.join(TMP_DIR, "storage-contract-code.boc")
COMPILED_BUILD_BOC = os.path.join(TMP_DIR, "build-boc.fif")
res = subprocess.run([FUNC_EXECUTABLE, "-o", COMPILED_ST_FIF, "-SPA", f.replace("storage-provider.fc","storage-contract.fc")], capture_output=False, timeout=10)
with open(COMPILED_BUILD_BOC, "w") as scr:
scr.write("\"%s\" include boc>B \"%s\" B>file "%(COMPILED_ST_FIF, COMPILED_ST_BOC))
res = subprocess.run([FIFT_EXECUTABLE, COMPILED_BUILD_BOC ], capture_output=True, timeout=10)


res = subprocess.run([FUNC_EXECUTABLE, "-o", COMPILED_FIF, "-SPA", f], capture_output=True, timeout=10)
except Exception as e:
post_process_func(f)
raise e
else:
post_process_func(f)
if res.returncode != 0:
raise ExecutionError(str(res.stderr, "utf-8"))

def run_runner():
res = subprocess.run([FIFT_EXECUTABLE, "-I", FIFT_LIBS, RUNNER_FIF], capture_output=True, timeout=10)
if res.returncode != 0:
raise ExecutionError(str(res.stderr, "utf-8"))
s = str(res.stdout, "utf-8")
s = s.strip()
return int(s)


success = 0
for ti, t in enumerate(tests):
tf, th = t
print(" Running test %d/%d: %s" % (ti + 1, len(tests), tf), file=sys.stderr)
tf = os.path.join(TESTS_DIR, tf)
try:
compile_func(tf)
except ExecutionError as e:
print(file=sys.stderr)
print("Compilation error", file=sys.stderr)
print(e, file=sys.stderr)
exit(2)

with open(RUNNER_FIF, "w") as f:
print("\"%s\" include hash .s" % COMPILED_FIF , file=f)

try:
func_out = run_runner()
if func_out != th:
raise ExecutionError("Error : expected '%d', found '%d'" % (th, func_out))
success += 1
except ExecutionError as e:
print(e, file=sys.stderr)
#print("Compiled:", file=sys.stderr)
#with open(COMPILED_FIF, "r") as f:
# print(f.read(), file=sys.stderr)
#exit(2)
print(" OK ", file=sys.stderr)

print("Done: Success %d, Error: %d"%(success, len(tests)-success), file=sys.stderr)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(int, int, cell) get_bridge_config() impure inline_ref {
cell bridge_config = config_param(72);
if (bridge_config.cell_null?()) {
bridge_config = config_param(-72);
}
throw_if(666, bridge_config.cell_null?());
slice ds = bridge_config.begin_parse();
;; wc always equals to -1
int bridge_address = ds~load_uint(256);
int oracles_address = ds~load_uint(256);
cell oracles = ds~load_dict();
return (bridge_address, oracles_address, oracles);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
() send_receipt_message(addr, ans_tag, query_id, body, grams, mode) impure inline_ref {
;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 011000
var msg = begin_cell()
.store_uint(0x18, 6)
.store_slice(addr)
.store_grams(grams)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_uint(ans_tag, 32)
.store_uint(query_id, 64);
if (body >= 0) {
msg~store_uint(body, 256);
}
send_raw_message(msg.end_cell(), mode);
}

() send_text_receipt_message(addr, grams, mode) impure inline_ref {
;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 011000
var msg = begin_cell()
.store_uint(0x18, 6)
.store_slice(addr)
.store_grams(grams)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_uint(0, 32)
.store_uint(0x4f4b, 16); ;; "OK"
send_raw_message(msg.end_cell(), mode);
}

() emit_log_simple (int event_id, slice data) impure inline {
var msg = begin_cell()
.store_uint (12, 4) ;; ext_out_msg_info$11 src:MsgAddressInt ()
.store_uint (1, 2)
.store_uint (256, 9)
.store_uint(event_id, 256)
.store_uint(0, 64 + 32 + 2) ;; created_lt, created_at, init:Maybe, body:Either
.store_slice(data)
.end_cell();
send_raw_message(msg, 0);
}
Loading

0 comments on commit fc9542f

Please sign in to comment.