1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

Merge branch 'ton-blockchain:testnet' into testnet

This commit is contained in:
Andrey Pfau 2023-12-02 17:04:02 +07:00 committed by GitHub
commit 52ad17406e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
153 changed files with 3777 additions and 4279 deletions

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
if (NOT OPENSSL_FOUND)
find_package(OpenSSL REQUIRED)
@ -236,6 +236,7 @@ set(SMC_ENVELOPE_SOURCE
smc-envelope/SmartContractCode.cpp
smc-envelope/WalletInterface.cpp
smc-envelope/WalletV3.cpp
smc-envelope/WalletV4.cpp
smc-envelope/GenericAccount.h
smc-envelope/HighloadWallet.h
@ -246,6 +247,7 @@ set(SMC_ENVELOPE_SOURCE
smc-envelope/SmartContractCode.h
smc-envelope/WalletInterface.h
smc-envelope/WalletV3.h
smc-envelope/WalletV4.h
)
set(ED25519_TEST_SOURCE
@ -373,10 +375,10 @@ add_library(src_parser ${PARSER_SOURCE})
target_include_directories(src_parser PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
target_link_libraries(src_parser PUBLIC ton_crypto_core)
add_library(ton_block ${BLOCK_SOURCE})
add_library(ton_block STATIC ${BLOCK_SOURCE})
target_include_directories(ton_block PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/block> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(ton_block PUBLIC ton_crypto_core tdutils tdactor tl_api)
target_link_libraries(ton_block PUBLIC ton_crypto tdutils tdactor tl_api)
add_executable(func func/func-main.cpp ${FUNC_LIB_SOURCE})
target_include_directories(func PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)

View file

@ -715,7 +715,7 @@ td::uint64 BlockLimitStatus::estimate_block_size(const vm::NewCellStorageStat::S
sum += *extra;
}
return 2000 + (sum.bits >> 3) + sum.cells * 12 + sum.internal_refs * 3 + sum.external_refs * 40 + accounts * 200 +
transactions * 200 + (extra ? 200 : 0) + extra_out_msgs * 300;
transactions * 200 + (extra ? 200 : 0) + extra_out_msgs * 300 + extra_library_diff * 700;
}
int BlockLimitStatus::classify() const {

View file

@ -262,6 +262,7 @@ struct BlockLimitStatus {
td::uint64 gas_used{};
vm::NewCellStorageStat st_stat;
unsigned accounts{}, transactions{}, extra_out_msgs{};
unsigned extra_library_diff{}; // Number of public libraries in deleted/frozen accounts
BlockLimitStatus(const BlockLimits& limits_, ton::LogicalTime lt = 0)
: limits(limits_), cur_lt(std::max(limits_.start_lt, lt)) {
}
@ -271,6 +272,7 @@ struct BlockLimitStatus {
transactions = accounts = 0;
gas_used = 0;
extra_out_msgs = 0;
extra_library_diff = 0;
}
td::uint64 estimate_block_size(const vm::NewCellStorageStat::Stat* extra = nullptr) const;
int classify() const;

View file

@ -780,7 +780,8 @@ _ MisbehaviourPunishmentConfig = ConfigParam 40;
size_limits_config#01 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 = SizeLimitsConfig;
size_limits_config_v2#02 max_msg_bits:uint32 max_msg_cells:uint32 max_library_cells:uint32 max_vm_data_depth:uint16
max_ext_msg_size:uint32 max_ext_msg_depth:uint16 max_acc_state_cells:uint32 max_acc_state_bits:uint32 = SizeLimitsConfig;
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 = SizeLimitsConfig;
_ SizeLimitsConfig = ConfigParam 43;
// key is [ wc:int32 addr:uint256 ]

View file

@ -1934,6 +1934,7 @@ td::Result<SizeLimitsConfig> Config::get_size_limits_config() const {
unpack_v1(rec);
limits.max_acc_state_bits = rec.max_acc_state_bits;
limits.max_acc_state_cells = rec.max_acc_state_cells;
limits.max_acc_public_libraries = rec.max_acc_public_libraries;
};
gen::SizeLimitsConfig::Record_size_limits_config rec_v1;
gen::SizeLimitsConfig::Record_size_limits_config_v2 rec_v2;

View file

@ -389,6 +389,7 @@ struct SizeLimitsConfig {
ExtMsgLimits ext_msg_limits;
td::uint32 max_acc_state_cells = 1 << 16;
td::uint32 max_acc_state_bits = (1 << 16) * 1023;
td::uint32 max_acc_public_libraries = 256;
};
struct CatchainValidatorsConfig {

File diff suppressed because it is too large Load diff

View file

@ -116,6 +116,7 @@ struct ComputePhaseConfig {
int global_version = 0;
Ref<vm::Tuple> prev_blocks_info;
std::unique_ptr<vm::Dictionary> suspended_addresses;
SizeLimitsConfig size_limits;
int vm_log_verbosity = 0;
ComputePhaseConfig(td::uint64 _gas_price = 0, td::uint64 _gas_limit = 0, td::uint64 _gas_credit = 0)
@ -270,7 +271,7 @@ struct Account {
return balance;
}
bool set_address(ton::WorkchainId wc, td::ConstBitPtr new_addr);
bool unpack(Ref<vm::CellSlice> account, Ref<vm::CellSlice> extra, ton::UnixTime now, bool special = false);
bool unpack(Ref<vm::CellSlice> account, ton::UnixTime now, bool special);
bool init_new(ton::UnixTime now);
bool deactivate();
bool recompute_tmp_addr(Ref<vm::CellSlice>& tmp_addr, int split_depth, td::ConstBitPtr orig_addr_rewrite) const;
@ -372,7 +373,7 @@ struct Transaction {
std::vector<Ref<vm::Cell>> compute_vm_libraries(const ComputePhaseConfig& cfg);
bool prepare_compute_phase(const ComputePhaseConfig& cfg);
bool prepare_action_phase(const ActionPhaseConfig& cfg);
td::Status check_state_limits(const ActionPhaseConfig& cfg);
td::Status check_state_limits(const SizeLimitsConfig& size_limits, bool update_storage_stat = true);
bool prepare_bounce_phase(const ActionPhaseConfig& cfg);
bool compute_state();
bool serialize();
@ -382,8 +383,6 @@ struct Transaction {
td::Result<vm::NewCellStorageStat::Stat> estimate_block_storage_profile_incr(
const vm::NewCellStorageStat& store_stat, const vm::CellUsageTree* usage_tree) const;
bool update_block_storage_profile(vm::NewCellStorageStat& store_stat, const vm::CellUsageTree* usage_tree) const;
bool would_fit(unsigned cls, const block::BlockLimitStatus& blk_lim_st) const;
bool update_limits(block::BlockLimitStatus& blk_lim_st, bool with_size = true) const;
Ref<vm::Cell> commit(Account& _account); // _account should point to the same account
@ -406,7 +405,7 @@ struct Transaction {
bool serialize_compute_phase(vm::CellBuilder& cb);
bool serialize_action_phase(vm::CellBuilder& cb);
bool serialize_bounce_phase(vm::CellBuilder& cb);
bool unpack_msg_state(bool lib_only = false);
bool unpack_msg_state(const ComputePhaseConfig& cfg, bool lib_only = false, bool forbid_public_libs = false);
};
} // namespace transaction

View file

@ -130,7 +130,7 @@ void bits_memcpy(unsigned char* to, int to_offs, const unsigned char* from, int
from_offs &= 7;
to_offs &= 7;
//fprintf(stderr, "bits_memcpy: from=%p (%02x) to=%p (%02x) from_offs=%d to_offs=%d count=%lu\n", from, *from, to, *to, from_offs, to_offs, bit_count);
int sz = (int)bit_count;
int sz = static_cast<int>(bit_count);
bit_count += from_offs;
if (from_offs == to_offs) {
if (bit_count < 8) {
@ -206,7 +206,7 @@ void bits_memset(unsigned char* to, int to_offs, bool val, std::size_t bit_count
}
to += (to_offs >> 3);
to_offs &= 7;
int sz = (int)bit_count;
int sz = static_cast<int>(bit_count);
bit_count += to_offs;
int c = *to;
if (bit_count <= 8) {
@ -596,7 +596,7 @@ long parse_bitstring_hex_literal(unsigned char* buff, std::size_t buff_size, con
unsigned char* ptr = buff;
const char* rptr = str;
while (rptr < str_end) {
int c = *rptr++;
char c = *rptr++;
if (c == ' ' || c == '\t') {
continue;
}
@ -627,14 +627,14 @@ long parse_bitstring_hex_literal(unsigned char* buff, std::size_t buff_size, con
if (cmpl && bits) {
int t = (hex_digits_count & 1) ? (0x100 + *ptr) >> 4 : (0x100 + *--ptr);
while (bits > 0) {
if (t == 1) {
t = 0x100 + *--ptr;
}
--bits;
if (t & 1) {
break;
}
t >>= 1;
if (t == 1) {
t = 0x100 + *--ptr;
}
}
}
return bits;

View file

@ -461,19 +461,109 @@ x{B7A3} @Defop QNEGATE
x{B7A4} @Defop QINC
x{B7A5} @Defop QDEC
x{B7A8} @Defop QMUL
x{B7A904} @Defop QDIV
x{B7A905} @Defop QDIVR
x{B7A906} @Defop QDIVC
x{B7A908} @Defop QMOD
x{B7A909} @Defop QMODR
x{B7A90A} @Defop QMODC
x{B7A90C} @Defop QDIVMOD
x{B7A90D} @Defop QDIVMODR
x{B7A90E} @Defop QDIVMODC
x{B7A900} @Defop QADDDIVMOD
x{B7A901} @Defop QADDDIVMODR
x{B7A902} @Defop QADDDIVMODC
x{B7A925} @Defop QRSHIFTR
x{B7A926} @Defop QRSHIFTC
x{B7A928} @Defop QMODPOW2
x{B7A929} @Defop QMODPOW2R
x{B7A92A} @Defop QMODPOW2C
x{B7A92C} @Defop QRSHIFTMOD
x{B7A92D} @Defop QRSHIFTMODR
x{B7A92E} @Defop QRSHIFTMODC
x{B7A920} @Defop QADDRSHIFTMOD
x{B7A921} @Defop QADDRSHIFTMODR
x{B7A922} @Defop QADDRSHIFTMODC
x{B7A935} @Defop(8u+1) QRSHIFTR#
x{B7A936} @Defop(8u+1) QRSHIFTC#
x{B7A938} @Defop(8u+1) QMODPOW2#
x{B7A939} @Defop(8u+1) QMODPOW2R#
x{B7A93A} @Defop(8u+1) QMODPOW2C#
x{B7A93C} @Defop(8u+1) QRSHIFT#MOD
x{B7A93D} @Defop(8u+1) QRSHIFTR#MOD
x{B7A93E} @Defop(8u+1) QRSHIFTC#MOD
x{B7A930} @Defop(8u+1) QADDRSHIFT#MOD
x{B7A931} @Defop(8u+1) QADDRSHIFTR#MOD
x{B7A932} @Defop(8u+1) QADDRSHIFTC#MOD
x{B7A984} @Defop QMULDIV
x{B7A985} @Defop QMULDIVR
x{B7A986} @Defop QMULDIVC
x{B7A988} @Defop QMULMOD
x{B7A989} @Defop QMULMODR
x{B7A98A} @Defop QMULMODC
x{B7A98C} @Defop QMULDIVMOD
x{B7A980} @Defop QADDMULDIVMOD
x{B7A98D} @Defop QMULDIVMODR
x{B7A98E} @Defop QMULDIVMODC
x{B7A980} @Defop QMULADDDIVMOD
x{B7A981} @Defop QMULADDDIVMODR
x{B7A982} @Defop QMULADDDIVMODC
x{B7A9A4} @Defop QMULRSHIFT
x{B7A9A5} @Defop QMULRSHIFTR
x{B7A9A6} @Defop QMULRSHIFTC
x{B7A9A8} @Defop QMULMODPOW2
x{B7A9A9} @Defop QMULMODPOW2R
x{B7A9AA} @Defop QMULMODPOW2C
x{B7A9AC} @Defop QMULRSHIFTMOD
x{B7A9AD} @Defop QMULRSHIFTRMOD
x{B7A9AE} @Defop QMULRSHIFTCMOD
x{B7A9A0} @Defop QMULADDRSHIFTMOD
x{B7A9A1} @Defop QMULADDRSHIFTRMOD
x{B7A9A2} @Defop QMULADDRSHIFTCMOD
x{B7A9B4} @Defop(8u+1) QMULRSHIFT#
x{B7A9B5} @Defop(8u+1) QMULRSHIFTR#
x{B7A9B6} @Defop(8u+1) QMULRSHIFTC#
x{B7A9B8} @Defop(8u+1) QMULMODPOW2#
x{B7A9B9} @Defop(8u+1) QMULMODPOW2R#
x{B7A9BA} @Defop(8u+1) QMULMODPOW2C#
x{B7A9BC} @Defop(8u+1) QMULRSHIFT#MOD
x{B7A9BD} @Defop(8u+1) QMULRSHIFTR#MOD
x{B7A9BE} @Defop(8u+1) QMULRSHIFTC#MOD
x{B7A9B0} @Defop(8u+1) QMULADDRSHIFT#MOD
x{B7A9B1} @Defop(8u+1) QMULADDRSHIFTR#MOD
x{B7A9B2} @Defop(8u+1) QMULADDRSHIFTC#MOD
x{B7A9C4} @Defop QLSHIFTDIV
x{B7A9C5} @Defop QLSHIFTDIVR
x{B7A9C6} @Defop QLSHIFTDIVC
x{B7A9C8} @Defop QLSHIFTMOD
x{B7A9C9} @Defop QLSHIFTMODR
x{B7A9CA} @Defop QLSHIFTMODC
x{B7A9CC} @Defop QLSHIFTDIVMOD
x{B7A9CD} @Defop QLSHIFTDIVMODR
x{B7A9CE} @Defop QLSHIFTDIVMODC
x{B7A9C0} @Defop QLSHIFTADDDIVMOD
x{B7A9C1} @Defop QLSHIFTADDDIVMODR
x{B7A9C2} @Defop QLSHIFTADDDIVMODC
x{B7A9D4} @Defop(8u+1) QLSHIFT#DIV
x{B7A9D5} @Defop(8u+1) QLSHIFT#DIVR
x{B7A9D6} @Defop(8u+1) QLSHIFT#DIVC
x{B7A9D8} @Defop(8u+1) QLSHIFT#MOD
x{B7A9D9} @Defop(8u+1) QLSHIFT#MODR
x{B7A9DA} @Defop(8u+1) QLSHIFT#MODC
x{B7A9DC} @Defop(8u+1) QLSHIFT#DIVMOD
x{B7A9DD} @Defop(8u+1) QLSHIFT#DIVMODR
x{B7A9DE} @Defop(8u+1) QLSHIFT#DIVMODC
x{B7A9D0} @Defop(8u+1) QLSHIFT#ADDDIVMOD
x{B7A9D1} @Defop(8u+1) QLSHIFT#ADDDIVMODR
x{B7A9D2} @Defop(8u+1) QLSHIFT#ADDDIVMODC
x{B7AC} @Defop QLSHIFT
x{B7AD} @Defop QRSHIFT
x{B7AE} @Defop QPOW2
@ -1185,7 +1275,7 @@ x{F4BF} @Defop DICTUGETEXECZ
x{F800} @Defop ACCEPT
x{F801} @Defop SETGASLIMIT
x{F802} @Defop GASCONSUMED
x{F807} @Defop GASCONSUMED
x{F80F} @Defop COMMIT
x{F810} @Defop RANDU256

View file

@ -3512,7 +3512,7 @@ void init_words_ton(Dictionary& d) {
void init_words_vm(Dictionary& d, bool enable_debug) {
using namespace std::placeholders;
vm::init_op_cp0(enable_debug);
vm::init_vm(enable_debug).ensure();
// vm run
d.def_word("vmlibs ", LitCont::literal(vm_libraries));
// d.def_ctx_word("runvmcode ", std::bind(interpret_run_vm, _1, 0x40));

View file

@ -8,37 +8,37 @@ 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],
# 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],
["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],
# 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],
["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],
["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):
@ -51,7 +51,6 @@ def getenv(name, default=None):
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")
@ -63,49 +62,49 @@ 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)
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)
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()
# 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")
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)
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
post_process_func(f)
raise e
else:
post_process_func(f)
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)
res = subprocess.run([FIFT_EXECUTABLE, RUNNER_FIF], capture_output=True, timeout=10)
if res.returncode != 0:
raise ExecutionError(str(res.stderr, "utf-8"))
s = str(res.stdout, "utf-8")
@ -138,16 +137,15 @@ for ti, t in enumerate(tests):
try:
func_out = run_runner()
if func_out != th:
raise ExecutionError("Error : expected '%d', found '%d'" % (th, func_out))
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("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(get_version())
print("Done: Success %d, Error: %d"%(success, len(tests)-success), file=sys.stderr)
print("Done: Success %d, Error: %d"%(success, len(tests)-success), file=sys.stderr)

View file

@ -4,6 +4,7 @@ import subprocess
import sys
import tempfile
def getenv(name, default=None):
if name in os.environ:
return os.environ[name]
@ -12,10 +13,9 @@ def getenv(name, default=None):
exit(1)
return default
FUNC_EXECUTABLE = getenv("FUNC_EXECUTABLE", "func")
FIFT_EXECUTABLE = getenv("FIFT_EXECUTABLE", "fift")
#FUNC_STDLIB = getenv("FUNC_STDLIB")
FIFT_LIBS = getenv("FIFT_LIBS")
TMP_DIR = tempfile.mkdtemp()
COMPILED_FIF = os.path.join(TMP_DIR, "compiled.fif")
RUNNER_FIF = os.path.join(TMP_DIR, "runner.fif")
@ -25,22 +25,26 @@ if len(sys.argv) != 2:
exit(1)
TESTS_DIR = sys.argv[1]
class ExecutionError(Exception):
pass
def compile_func(f):
res = subprocess.run([FUNC_EXECUTABLE, "-o", COMPILED_FIF, "-SPA", f], capture_output=True, timeout=10)
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)
res = subprocess.run([FIFT_EXECUTABLE, 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 = [x.strip() for x in s.split("\n")]
return [x for x in s if x != ""]
tests = [s for s in os.listdir(TESTS_DIR) if s.endswith(".fc")]
tests.sort()
print("Found", len(tests), "tests", file=sys.stderr)
@ -68,18 +72,18 @@ for ti, tf in enumerate(tests):
# preprocess arithmetics in input
for i in range(len(cases)):
inputs = cases[i][1].split(" ")
processed_inputs = ""
for in_arg in inputs:
if "x{" in in_arg:
processed_inputs += in_arg
continue
# filter and execute
# is it safe enough?
filtered_in = "".join(filter(lambda x: x in "0x123456789()+-*/<>", in_arg))
if(filtered_in):
processed_inputs += str(eval(filtered_in)) + " ";
cases[i][1] = processed_inputs.strip()
inputs = cases[i][1].split(" ")
processed_inputs = ""
for in_arg in inputs:
if "x{" in in_arg:
processed_inputs += in_arg
continue
# filter and execute
# is it safe enough?
filtered_in = "".join(filter(lambda x: x in "0x123456789()+-*/<>", in_arg))
if filtered_in:
processed_inputs += str(eval(filtered_in)) + " "
cases[i][1] = processed_inputs.strip()
with open(RUNNER_FIF, "w") as f:
print("\"%s\" include <s constant code" % COMPILED_FIF, file=f)
@ -103,4 +107,4 @@ for ti, tf in enumerate(tests):
exit(2)
print(" OK, %d cases" % len(cases), file=sys.stderr)
print("Done", file=sys.stderr)
print("Done", file=sys.stderr)

View file

@ -232,6 +232,7 @@ Bignum& Bignum::import_lsb(const unsigned char* buffer, std::size_t size) {
std::string Bignum::to_str() const {
char* ptr = BN_bn2dec(val);
CHECK(ptr);
std::string z(ptr);
OPENSSL_free(ptr);
return z;
@ -239,6 +240,7 @@ std::string Bignum::to_str() const {
std::string Bignum::to_hex() const {
char* ptr = BN_bn2hex(val);
CHECK(ptr);
std::string z(ptr);
OPENSSL_free(ptr);
return z;
@ -255,7 +257,13 @@ std::istream& operator>>(std::istream& is, Bignum& x) {
return is;
}
bool is_prime(const Bignum& p, int nchecks, bool trial_div) {
return BN_is_prime_fasttest_ex(p.bn_ptr(), BN_prime_checks, get_ctx(), trial_div, 0);
bool is_prime(const Bignum& p) {
#if OPENSSL_VERSION_MAJOR >= 3
int result = BN_check_prime(p.bn_ptr(), get_ctx(), nullptr);
LOG_IF(FATAL, result == -1);
return result;
#else
return BN_is_prime_fasttest_ex(p.bn_ptr(), BN_prime_checks, get_ctx(), true, 0);
#endif
}
} // namespace arith

View file

@ -335,7 +335,7 @@ const Bignum sqr(const Bignum& x);
std::ostream& operator<<(std::ostream& os, const Bignum& x);
std::istream& operator>>(std::istream& is, Bignum& x);
bool is_prime(const Bignum& p, int nchecks = 64, bool trial_div = true);
bool is_prime(const Bignum& p);
inline int cmp(const Bignum& x, const Bignum& y) {
return BN_cmp(x.bn_ptr(), y.bn_ptr());

View file

@ -250,7 +250,6 @@ const Lexem& Lexer::next() {
}
if (is_multiline_quote(src.get_ptr(), src.get_end_ptr())) {
src.advance(multiline_quote.size());
const char* begin = src.get_ptr();
const char* end = nullptr;
SrcLocation here = src.here();
std::string body;

View file

@ -155,7 +155,7 @@ td::Result<td::uint32> GenericAccount::get_wallet_id(const SmartContract& sc) {
return TRY_VM([&]() -> td::Result<td::uint32> {
auto answer = sc.run_get_method("wallet_id");
if (!answer.success) {
return td::Status::Error("seqno get method failed");
return td::Status::Error("wallet_id get method failed");
}
return static_cast<td::uint32>(answer.stack.write().pop_long_range(std::numeric_limits<td::uint32>::max()));
}());

View file

@ -305,7 +305,7 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
if (!info.known_category.insert(action.category).second) {
continue;
}
if (action.category == 0) {
if (action.category.is_zero()) {
info.closed = true;
auto old_actions = std::move(info.actions);
bool is_empty = true;
@ -327,7 +327,7 @@ class ManualDns : public ton::SmartContract, public DnsInterface {
if (info.closed) {
CombinedActions<ActionT> ca;
ca.name = it.first;
ca.category = 0;
ca.category = td::Bits256::zero();
if (!info.actions.empty() || info.non_empty) {
ca.actions = std::move(info.actions);
}

View file

@ -181,7 +181,7 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
int vm_log_verbosity, bool debug_enabled,
std::shared_ptr<const block::Config> config) {
auto gas_credit = gas.gas_credit;
vm::init_op_cp0(debug_enabled);
vm::init_vm(debug_enabled).ensure();
vm::DictionaryBase::get_empty_dictionary();
class Logger : public td::LogInterface {
@ -246,10 +246,10 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
LOG(DEBUG) << "VM accepted: " << res.accepted;
LOG(DEBUG) << "VM success: " << res.success;
}
td::ConstBitPtr mlib = vm.get_missing_library();
if (!mlib.is_null()) {
LOG(DEBUG) << "Missing library: " << mlib.to_hex(256);
res.missing_library = mlib;
auto mlib = vm.get_missing_library();
if (mlib) {
LOG(DEBUG) << "Missing library: " << mlib.value().to_hex();
res.missing_library = mlib.value();
}
if (res.success) {
res.new_state.data = vm.get_c4();
@ -257,7 +257,7 @@ SmartContract::Answer run_smartcont(SmartContract::State state, td::Ref<vm::Stac
LOG(DEBUG) << "output actions:\n"
<< block::gen::OutList{res.output_actions_count(res.actions)}.as_string_ref(res.actions);
}
LOG_IF(ERROR, gas_credit != 0 && (res.accepted && !res.success) && mlib.is_null())
LOG_IF(ERROR, gas_credit != 0 && (res.accepted && !res.success) && !mlib)
<< "Accepted but failed with code " << res.code << "\n"
<< res.gas_used << "\n";
return res;

View file

@ -49,7 +49,7 @@ class SmartContract : public td::CntObject {
td::Ref<vm::Cell> actions;
td::int32 code;
td::int64 gas_used;
td::ConstBitPtr missing_library{0};
td::optional<td::Bits256> missing_library;
std::string vm_log;
static int output_actions_count(td::Ref<vm::Cell> list);
};

View file

@ -28,6 +28,7 @@ namespace {
// WALLET_REVISION = 2;
// WALLET2_REVISION = 2;
// WALLET3_REVISION = 2;
// WALLET4_REVISION = 2;
// HIGHLOAD_WALLET_REVISION = 2;
// HIGHLOAD_WALLET2_REVISION = 2;
// DNS_REVISION = 1;
@ -92,6 +93,20 @@ const auto& get_map() {
"AAXrc52omhpn5jrhf/AABesePaiaGmPmOuFj8ABDbbYHwR7Z5AOAQm1B1tnkA4BTu1E0IEBQNch0x/"
"0BNEC2zz4J28QAoAg9HtvpTGX+gAwoXC2CZEw4g8AOiGOETGA8/gzIG6SMHCU0NcLH+IB3yGSAaGSW3/iAAzTB9QC+wAAHssfFMsfEsv/yx/"
"0AMntVA==");
with_tvm_code(
"wallet-v4-r2",
"te6cckECFAEAAtQAART/APSkE/S88sgLAQIBIAIDAgFIBAUE+PKDCNcYINMf0x/THwL4I7vyZO1E0NMf0x/T//"
"QE0VFDuvKhUVG68qIF+QFUEGT5EPKj+AAkpMjLH1JAyx9SMMv/"
"UhD0AMntVPgPAdMHIcAAn2xRkyDXSpbTB9QC+wDoMOAhwAHjACHAAuMAAcADkTDjDQOkyMsfEssfy/"
"8QERITAubQAdDTAyFxsJJfBOAi10nBIJJfBOAC0x8hghBwbHVnvSKCEGRzdHK9sJJfBeAD+kAwIPpEAcjKB8v/"
"ydDtRNCBAUDXIfQEMFyBAQj0Cm+hMbOSXwfgBdM/"
"yCWCEHBsdWe6kjgw4w0DghBkc3RyupJfBuMNBgcCASAICQB4AfoA9AQw+CdvIjBQCqEhvvLgUIIQcGx1Z4MesXCAGFAEywUmzxZY+"
"gIZ9ADLaRfLH1Jgyz8gyYBA+wAGAIpQBIEBCPRZMO1E0IEBQNcgyAHPFvQAye1UAXKwjiOCEGRzdHKDHrFwgBhQBcsFUAPPFiP6AhPLassfyz/"
"JgED7AJJfA+ICASAKCwBZvSQrb2omhAgKBrkPoCGEcNQICEekk30pkQzmkD6f+YN4EoAbeBAUiYcVnzGEAgFYDA0AEbjJftRNDXCx+"
"AA9sp37UTQgQFA1yH0BDACyMoHy//J0AGBAQj0Cm+hMYAIBIA4PABmtznaiaEAga5Drhf/AABmvHfaiaEAQa5DrhY/AAG7SB/"
"oA1NQi+QAFyMoHFcv/ydB3dIAYyMsFywIizxZQBfoCFMtrEszMyXP7AMhAFIEBCPRR8qcCAHCBAQjXGPoA0z/"
"IVCBHgQEI9FHyp4IQbm90ZXB0gBjIywXLAlAGzxZQBPoCFMtqEssfyz/Jc/sAAgBsgQEI1xj6ANM/"
"MFIkgQEI9Fnyp4IQZHN0cnB0gBjIywXLAlAFzxZQA/oCE8tqyx8Syz/Jc/sAAAr0AMntVGliJeU=");
return map;
}();
return map;
@ -137,9 +152,12 @@ td::Span<int> SmartContractCode::get_revisions(Type type) {
static int res[] = {1};
return res;
}
case Type::WalletV4: {
static int res[] = {2};
return res;
}
}
UNREACHABLE();
return {};
}
td::Result<int> SmartContractCode::validate_revision(Type type, int revision) {
@ -179,9 +197,10 @@ td::Ref<vm::Cell> SmartContractCode::get_code(Type type, int ext_revision) {
return "payment-channel";
case Type::RestrictedWallet:
return "restricted-wallet3";
case Type::WalletV4:
return "wallet-v4";
}
UNREACHABLE();
return "";
}(type);
if (revision == -1) {
return load(basename).move_as_ok();

View file

@ -26,7 +26,16 @@ class SmartContractCode {
public:
static td::Result<td::Ref<vm::Cell>> load(td::Slice name);
enum Type { WalletV3 = 4, HighloadWalletV1, HighloadWalletV2, ManualDns, Multisig, PaymentChannel, RestrictedWallet };
enum Type {
WalletV3 = 4,
HighloadWalletV1,
HighloadWalletV2,
ManualDns,
Multisig,
PaymentChannel,
RestrictedWallet,
WalletV4
};
static td::Span<int> get_revisions(Type type);
static td::Result<int> validate_revision(Type type, int revision);
static td::Ref<vm::Cell> get_code(Type type, int revision = 0);

View file

@ -55,18 +55,21 @@ td::Ref<vm::Cell> WalletInterface::create_int_message(const Gift &gift) {
} else {
cbi.store_zeroes(1);
}
cbi.store_zeroes(1);
store_gift_message(cbi, gift);
return cbi.finalize();
}
void WalletInterface::store_gift_message(vm::CellBuilder &cb, const Gift &gift) {
if (gift.body.not_null()) {
auto body = vm::load_cell_slice(gift.body);
//TODO: handle error
CHECK(cb.append_cellslice_bool(body));
if (cb.can_extend_by(1 + body.size(), body.size_refs())) {
CHECK(cb.store_zeroes_bool(1) && cb.append_cellslice_bool(body));
} else {
CHECK(cb.store_ones_bool(1) && cb.store_ref_bool(gift.body));
}
return;
}
cb.store_zeroes(1);
if (gift.is_encrypted) {
cb.store_long(0x2167da4b, 32);
} else {

View file

@ -73,6 +73,8 @@ class WalletInterface : public SmartContract {
td::uint32 valid_until = std::numeric_limits<td::uint32>::max()) const;
static td::Ref<vm::Cell> create_int_message(const Gift &gift);
private:
static void store_gift_message(vm::CellBuilder &cb, const Gift &gift);
};

View file

@ -0,0 +1,71 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WalletV4.h"
#include "GenericAccount.h"
#include "SmartContractCode.h"
#include "vm/boc.h"
#include "vm/cells/CellString.h"
#include "td/utils/base64.h"
#include <limits>
namespace ton {
td::Result<td::Ref<vm::Cell>> WalletV4::make_a_gift_message(const td::Ed25519::PrivateKey& private_key,
td::uint32 valid_until, td::Span<Gift> gifts) const {
CHECK(gifts.size() <= get_max_gifts_size());
TRY_RESULT(seqno, get_seqno());
TRY_RESULT(wallet_id, get_wallet_id());
vm::CellBuilder cb;
cb.store_long(wallet_id, 32).store_long(valid_until, 32).store_long(seqno, 32);
cb.store_long(0, 8); // The only difference with wallet-v3
for (auto& gift : gifts) {
td::int32 send_mode = 3;
if (gift.gramms == -1) {
send_mode += 128;
}
if (gift.send_mode > -1) {
send_mode = gift.send_mode;
}
cb.store_long(send_mode, 8).store_ref(create_int_message(gift));
}
auto message_outer = cb.finalize();
auto signature = private_key.sign(message_outer->get_hash().as_slice()).move_as_ok();
return vm::CellBuilder().store_bytes(signature).append_cellslice(vm::load_cell_slice(message_outer)).finalize();
}
td::Ref<vm::Cell> WalletV4::get_init_data(const InitData& init_data) noexcept {
return vm::CellBuilder()
.store_long(init_data.seqno, 32)
.store_long(init_data.wallet_id, 32)
.store_bytes(init_data.public_key)
.store_zeroes(1) // plugins dict
.finalize();
}
td::Result<td::uint32> WalletV4::get_wallet_id() const {
return TRY_VM([&]() -> td::Result<td::uint32> {
auto answer = run_get_method("get_subwallet_id");
if (!answer.success) {
return td::Status::Error("get_subwallet_id get method failed");
}
return static_cast<td::uint32>(answer.stack.write().pop_long_range(std::numeric_limits<td::uint32>::max()));
}());
}
} // namespace ton

View file

@ -0,0 +1,46 @@
/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "smc-envelope/SmartContract.h"
#include "smc-envelope/WalletInterface.h"
#include "vm/cells.h"
#include "Ed25519.h"
#include "block/block.h"
#include "vm/cells/CellString.h"
namespace ton {
struct WalletV4Traits {
using InitData = WalletInterface::DefaultInitData;
static constexpr unsigned max_message_size = vm::CellString::max_bytes;
static constexpr unsigned max_gifts_size = 4;
static constexpr auto code_type = SmartContractCode::WalletV4;
};
class WalletV4 : public WalletBase<WalletV4, WalletV4Traits> {
public:
explicit WalletV4(State state) : WalletBase(std::move(state)) {
}
td::Result<td::Ref<vm::Cell>> make_a_gift_message(const td::Ed25519::PrivateKey& private_key, td::uint32 valid_until,
td::Span<Gift> gifts) const override;
static td::Ref<vm::Cell> get_init_data(const InitData& init_data) noexcept;
td::Result<td::uint32> get_wallet_id() const override;
};
} // namespace ton

View file

@ -33,7 +33,7 @@ std::string load_test(std::string name) {
return td::read_file_str(current_dir() + "fift/" + name).move_as_ok();
}
td::Status run_fift(std::string name, bool expect_error = false, bool preload_fift = true) {
td::Status run_fift(std::string name, bool expect_error = false) {
auto res = fift::mem_run_fift(load_test(name));
if (expect_error) {
res.ensure_error();

View file

@ -9,6 +9,9 @@
[[ <{ RIST255_MULBASE DUP RIST255_VALIDATE }>s ]] 0 runvmx abort"Exitcode != 0"
@' n . dup (x.) type cr
@' ans <> abort"Invalid result"
@' n
[[ <{ 1 INT RIST255_MULBASE SWAP RIST255_MUL DUP RIST255_VALIDATE }>s ]] 0 runvmx abort"Exitcode != 0"
@' ans <> abort"Invalid result"
} : test-basepoint
0 0x0000000000000000000000000000000000000000000000000000000000000000 test-basepoint

View file

@ -180,7 +180,7 @@ struct MixedRadix {
template <int M>
const MixedRadix<M>& as_shorter() const {
static_assert(M <= N);
static_assert(M <= N,"error");
return *reinterpret_cast<const MixedRadix<M>*>(this);
}
@ -458,7 +458,7 @@ struct ModArray {
}
template <int M>
ModArray(const ModArray<M>& other) {
static_assert(M >= N);
static_assert(M >= N,"error");
std::copy(other.a, other.a + N, a);
}
ModArray(const int* p) : a(p) {
@ -819,7 +819,7 @@ struct ModArray {
template <int M>
const ModArray<M>& as_shorter() const {
static_assert(M <= N);
static_assert(M <= N,"error");
return *reinterpret_cast<const ModArray<M>*>(this);
}

View file

@ -16,12 +16,12 @@
*/
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <array>
#include <string>
#include <iostream>
#include <sstream>
#include <random>
#include <getopt.h>
#include "common/refcnt.hpp"
#include "common/bigint.hpp"
#include "common/refint.h"
@ -211,7 +211,7 @@ bool coin() {
// returns 0 with probability 1/2, 1 with prob. 1/4, ..., k with prob. 1/2^(k+1)
int randexp(int max = 63, int min = 0) {
return min + __builtin_clzll(Random() | (1ULL << (63 - max + min)));
return min + td::count_leading_zeroes64(Random() | (1ULL << (63 - max + min)));
}
void bin_add_small(unsigned char bin[64], long long val, int shift = 0) {
@ -363,7 +363,7 @@ void check_one_int_repr(td::RefInt256 x, int mode, int in_range, const BInt* val
if (is_small) {
// special check for small (64-bit) values
CHECK(x->to_long() == xval);
CHECK((long long)__builtin_bswap64(*(long long*)(bytes + 64 - 8)) == xval);
CHECK((long long)td::bswap64(*(long long*)(bytes + 64 - 8)) == xval);
CHECK(in_range);
// check sign
CHECK(x->sgn() == (xval > 0 ? 1 : (xval < 0 ? -1 : 0)));

View file

@ -127,12 +127,12 @@ class BenchSha256Low : public td::Benchmark {
void run(int n) override {
int res = 0;
SHA256_CTX ctx;
td::Sha256State ctx;
for (int i = 0; i < n; i++) {
SHA256_Init(&ctx);
SHA256_Update(&ctx, "abcd", 4);
ctx.init();
ctx.feed("abcd");
unsigned char buf[32];
SHA256_Final(buf, &ctx);
ctx.extract(td::MutableSlice{buf, 32});
res += buf[0];
}
td::do_not_optimize_away(res);

View file

@ -35,6 +35,7 @@
#include "smc-envelope/SmartContract.h"
#include "smc-envelope/SmartContractCode.h"
#include "smc-envelope/WalletV3.h"
#include "smc-envelope/WalletV4.h"
#include "smc-envelope/HighloadWallet.h"
#include "smc-envelope/HighloadWalletV2.h"
#include "smc-envelope/PaymentChannel.h"
@ -526,6 +527,7 @@ void do_test_wallet() {
TEST(Tonlib, Wallet) {
do_test_wallet<ton::WalletV3>();
do_test_wallet<ton::WalletV4>();
do_test_wallet<ton::HighloadWallet>();
do_test_wallet<ton::HighloadWalletV2>();
do_test_wallet<ton::RestrictedWallet>();
@ -956,7 +958,7 @@ class MapDns {
}
return;
}
if (!actions.category.is_zero()) {
if (actions.category.is_zero()) {
entries_.erase(actions.name);
LOG(ERROR) << "CLEAR " << actions.name;
if (!actions.actions) {
@ -1001,7 +1003,7 @@ class CheckedDns {
explicit CheckedDns(bool check_smc = true, bool check_combine = true) {
if (check_smc) {
key_ = td::Ed25519::generate_private_key().move_as_ok();
dns_ = ManualDns::create(ManualDns::create_init_data_fast(key_.value().get_public_key().move_as_ok(), 123));
dns_ = ManualDns::create(ManualDns::create_init_data_fast(key_.value().get_public_key().move_as_ok(), 123), -1);
}
if (check_combine) {
combined_map_dns_ = MapDns();
@ -1092,9 +1094,10 @@ class CheckedDns {
}
};
static td::Bits256 intToCat(int x) {
td::Bits256 cat = td::Bits256::zero();
cat.as_slice().copy_from(td::Slice((char*)&x, sizeof(x)));
static td::Bits256 intToCat(td::uint32 x) {
auto y = td::make_refint(x);
td::Bits256 cat;
y->export_bytes(cat.data(), 32, false);
return cat;
}
@ -1180,7 +1183,7 @@ TEST(Smartcont, DnsManual) {
auto key = td::Ed25519::generate_private_key().move_as_ok();
auto manual = ManualDns::create(ManualDns::create_init_data_fast(key.get_public_key().move_as_ok(), 123));
auto manual = ManualDns::create(ManualDns::create_init_data_fast(key.get_public_key().move_as_ok(), 123), -1);
CHECK(manual->get_wallet_id().move_as_ok() == 123);
auto init_query = manual->create_init_query(key).move_as_ok();
LOG(ERROR) << "A";

View file

@ -28,7 +28,7 @@
#include "td/utils/StringBuilder.h"
std::string run_vm(td::Ref<vm::Cell> cell) {
vm::init_op_cp0();
vm::init_vm().ensure();
vm::DictionaryBase::get_empty_dictionary();
class Logger : public td::LogInterface {

View file

@ -159,7 +159,6 @@ std::string CppIdentSet::compute_cpp_ident(std::string orig_ident, int count) {
}
if (!cnt) {
os << '_';
prev_skip = true;
}
if (count) {
os << count;

View file

@ -2252,11 +2252,9 @@ TypeExpr* parse_expr10(Lexer& lex, Constructor& cs, int mode) {
}
if (op == '>') {
std::swap(expr, expr2);
op = '<';
op_name = Less_name;
} else if (op == src::_Geq) {
std::swap(expr, expr2);
op = src::_Leq;
op_name = Leq_name;
}
auto sym_def = sym::lookup_symbol(op_name, 2);

View file

@ -285,8 +285,11 @@ int exec_divmod(VmState* st, unsigned args, int quiet) {
typename td::BigInt256::DoubleInt tmp{*x}, quot;
tmp += *w;
tmp.mod_div(*y, quot, round_mode);
stack.push_int_quiet(td::make_refint(quot), quiet);
stack.push_int_quiet(td::make_refint(tmp), quiet);
auto q = td::make_refint(quot), r = td::make_refint(tmp);
q.write().normalize();
r.write().normalize();
stack.push_int_quiet(std::move(q), quiet);
stack.push_int_quiet(std::move(r), quiet);
} else {
switch (d) {
case 1:
@ -399,6 +402,7 @@ std::string dump_shrmod(CellSlice&, unsigned args, int mode) {
if (mode & 1) {
os << 'Q';
}
std::string end;
switch (args & 12) {
case 4:
os << "RSHIFT";
@ -407,17 +411,22 @@ std::string dump_shrmod(CellSlice&, unsigned args, int mode) {
os << "MODPOW2";
break;
case 12:
os << "RSHIFTMOD";
os << "RSHIFT";
end = "MOD";
break;
case 0:
os << "ADDRSHIFTMOD";
os << "ADDRSHIFT";
end = "MOD";
break;
}
if (!(mode & 2)) {
os << end;
}
if (round_mode) {
os << "FRC"[round_mode];
}
if (mode & 2) {
os << ' ' << y;
os << "#" << end << ' ' << y;
}
return os.str();
}
@ -519,7 +528,7 @@ int exec_mulshrmod(VmState* st, unsigned args, int mode) {
if (add) {
tmp = *w;
}
tmp.add_mul(*x, *y);
tmp.add_mul(*x, *y).normalize();
switch (d) {
case 1:
tmp.rshift(z, round_mode).normalize();
@ -553,6 +562,7 @@ std::string dump_mulshrmod(CellSlice&, unsigned args, int mode) {
if (mode & 1) {
os << 'Q';
}
std::string end;
switch (args & 12) {
case 4:
os << "MULRSHIFT";
@ -561,15 +571,21 @@ std::string dump_mulshrmod(CellSlice&, unsigned args, int mode) {
os << "MULMODPOW2";
break;
case 12:
os << "MULRSHIFTMOD";
os << "MULRSHIFT";
end = "MOD";
break;
case 0:
os << "MULADDRSHIFTMOD";
os << "MULADDRSHIFT";
end = "MOD";
break;
}
if (round_mode) {
os << "FRC"[round_mode];
}
if (mode & 2) {
os << "#";
}
os << end;
if (mode & 2) {
os << ' ' << y;
}
@ -644,18 +660,22 @@ std::string dump_shldivmod(CellSlice&, unsigned args, int mode) {
if (mode & 1) {
os << "Q";
}
os << "LSHIFT";
if (mode & 2) {
os << "#";
}
switch (args & 12) {
case 4:
os << "LSHIFTDIV";
os << "DIV";
break;
case 8:
os << "LSHIFTMOD";
os << "MOD";
break;
case 12:
os << "LSHIFTDIVMOD";
os << "DIVMOD";
break;
case 0:
os << "LSHIFTADDDIVMOD";
os << "ADDDIVMOD";
break;
}
if (round_mode) {

View file

@ -142,28 +142,57 @@ td::Ref<vm::Cell> CellText::do_store(td::BitSlice slice) {
}
template <class F>
void CellText::for_each(F &&f, CellSlice cs) {
td::Status CellText::for_each(F &&f, CellSlice cs) {
if (!cs.have(8)) {
return td::Status::Error("Cell underflow");
}
auto depth = cs.fetch_ulong(8);
if (depth > max_chain_length) {
return td::Status::Error("Too deep string");
}
for (td::uint32 i = 0; i < depth; i++) {
auto size = cs.fetch_ulong(8);
f(cs.fetch_bits(td::narrow_cast<int>(size) * 8));
if (!cs.have(8)) {
return td::Status::Error("Cell underflow");
}
auto size = td::narrow_cast<int>(cs.fetch_ulong(8));
if (!cs.have(size * 8)) {
return td::Status::Error("Cell underflow");
}
TRY_STATUS(f(cs.fetch_bits(size * 8)));
if (i + 1 < depth) {
if (!cs.have_refs()) {
return td::Status::Error("Cell underflow");
}
cs = vm::load_cell_slice(cs.prefetch_ref());
}
}
return td::Status::OK();
}
td::Result<td::string> CellText::load(CellSlice &cs) {
unsigned int size = 0;
for_each([&](auto slice) { size += slice.size(); }, cs);
TRY_STATUS(for_each(
[&](auto slice) {
size += slice.size();
if (size > max_bytes * 8) {
return td::Status::Error("String is too long");
}
return td::Status::OK();
},
cs));
if (size % 8 != 0) {
return td::Status::Error("Size is not divisible by 8");
}
std::string res(size / 8, 0);
td::BitPtr to(td::MutableSlice(res).ubegin());
for_each([&](auto slice) { to.concat(slice); }, cs);
TRY_STATUS(for_each(
[&](auto slice) {
to.concat(slice);
return td::Status::OK();
},
cs));
CHECK(to.offs == (int)size);
return res;
}

View file

@ -52,7 +52,7 @@ class CellText {
private:
template <class F>
static void for_each(F &&f, CellSlice cs);
static td::Status for_each(F &&f, CellSlice cs);
static td::Ref<vm::Cell> do_store(td::BitSlice slice);
};

View file

@ -101,7 +101,7 @@ void register_basic_gas_ops(OpcodeTable& cp0) {
using namespace std::placeholders;
cp0.insert(OpcodeInstr::mksimple(0xf800, 16, "ACCEPT", exec_accept))
.insert(OpcodeInstr::mksimple(0xf801, 16, "SETGASLIMIT", exec_set_gas_limit))
.insert(OpcodeInstr::mksimple(0xf802, 16, "GASCONSUMED", exec_gas_consumed)->require_version(4))
.insert(OpcodeInstr::mksimple(0xf807, 16, "GASCONSUMED", exec_gas_consumed)->require_version(4))
.insert(OpcodeInstr::mksimple(0xf80f, 16, "COMMIT", exec_commit));
}
@ -620,7 +620,6 @@ int exec_ristretto255_from_hash(VmState* st) {
if (!x2->export_bytes(xb + 32, 32, false)) {
throw VmError{Excno::range_chk, "x2 must fit in an unsigned 256-bit integer"};
}
CHECK(sodium_init() >= 0);
crypto_core_ristretto255_from_hash(rb, xb);
td::RefInt256 r{true};
CHECK(r.write().import_bytes(rb, 32, false));
@ -633,8 +632,7 @@ int exec_ristretto255_validate(VmState* st, bool quiet) {
Stack& stack = st->get_stack();
auto x = stack.pop_int();
st->consume_gas(VmState::rist255_validate_gas_price);
unsigned char xb[64];
CHECK(sodium_init() >= 0);
unsigned char xb[32];
if (!x->export_bytes(xb, 32, false) || !crypto_core_ristretto255_is_valid_point(xb)) {
if (quiet) {
stack.push_bool(false);
@ -656,7 +654,6 @@ int exec_ristretto255_add(VmState* st, bool quiet) {
auto x = stack.pop_int();
st->consume_gas(VmState::rist255_add_gas_price);
unsigned char xb[32], yb[32], rb[32];
CHECK(sodium_init() >= 0);
if (!x->export_bytes(xb, 32, false) || !y->export_bytes(yb, 32, false) || crypto_core_ristretto255_add(rb, xb, yb)) {
if (quiet) {
stack.push_bool(false);
@ -681,7 +678,6 @@ int exec_ristretto255_sub(VmState* st, bool quiet) {
auto x = stack.pop_int();
st->consume_gas(VmState::rist255_add_gas_price);
unsigned char xb[32], yb[32], rb[32];
CHECK(sodium_init() >= 0);
if (!x->export_bytes(xb, 32, false) || !y->export_bytes(yb, 32, false) || crypto_core_ristretto255_sub(rb, xb, yb)) {
if (quiet) {
stack.push_bool(false);
@ -719,17 +715,20 @@ int exec_ristretto255_mul(VmState* st, bool quiet) {
auto n = stack.pop_int() % get_ristretto256_l();
auto x = stack.pop_int();
st->consume_gas(VmState::rist255_mul_gas_price);
unsigned char xb[32], nb[32], rb[32];
memset(rb, 255, sizeof(rb));
CHECK(sodium_init() >= 0);
if (!x->export_bytes(xb, 32, false) || !export_bytes_little(n, nb) || crypto_scalarmult_ristretto255(rb, nb, xb)) {
if (std::all_of(rb, rb + 32, [](unsigned char c) { return c == 255; })) {
if (quiet) {
stack.push_bool(false);
return 0;
}
throw VmError{Excno::range_chk, "invalid x or n"};
if (n->sgn() == 0) {
stack.push_smallint(0);
if (quiet) {
stack.push_bool(true);
}
return 0;
}
unsigned char xb[32], nb[32], rb[32];
if (!x->export_bytes(xb, 32, false) || !export_bytes_little(n, nb) || crypto_scalarmult_ristretto255(rb, nb, xb)) {
if (quiet) {
stack.push_bool(false);
return 0;
}
throw VmError{Excno::range_chk, "invalid x or n"};
}
td::RefInt256 r{true};
CHECK(r.write().import_bytes(rb, 32, false));
@ -747,7 +746,6 @@ int exec_ristretto255_mul_base(VmState* st, bool quiet) {
st->consume_gas(VmState::rist255_mulbase_gas_price);
unsigned char nb[32], rb[32];
memset(rb, 255, sizeof(rb));
CHECK(sodium_init() >= 0);
if (!export_bytes_little(n, nb) || crypto_scalarmult_ristretto255_base(rb, nb)) {
if (std::all_of(rb, rb + 32, [](unsigned char c) { return c == 255; })) {
if (quiet) {
@ -833,7 +831,7 @@ int exec_bls_verify(VmState* st) {
VM_LOG(st) << "execute BLS_VERIFY";
Stack& stack = st->get_stack();
stack.check_underflow(3);
st->consume_gas(st->bls_verify_gas_price);
st->consume_gas(VmState::bls_verify_gas_price);
bls::P2 sig = slice_to_bls_p2(*stack.pop_cellslice());
td::BufferSlice msg = slice_to_bls_msg(*stack.pop_cellslice());
bls::P1 pub = slice_to_bls_p1(*stack.pop_cellslice());
@ -845,8 +843,7 @@ int exec_bls_aggregate(VmState* st) {
VM_LOG(st) << "execute BLS_AGGREGATE";
Stack& stack = st->get_stack();
int n = stack.pop_smallint_range(stack.depth() - 1, 1);
st->consume_gas(
std::max(0LL, VmState::bls_aggregate_base_gas_price + (long long)n * VmState::bls_aggregate_element_gas_price));
st->consume_gas(VmState::bls_aggregate_base_gas_price + (long long)n * VmState::bls_aggregate_element_gas_price);
std::vector<bls::P2> sigs(n);
for (int i = n - 1; i >= 0; --i) {
sigs[i] = slice_to_bls_p2(*stack.pop_cellslice());

View file

@ -21,6 +21,8 @@
#include "vm/dict.h"
#include "vm/log.h"
#include "vm/vm.h"
#include "cp0.h"
#include <sodium.h>
namespace vm {
@ -633,7 +635,7 @@ Ref<Cell> VmState::load_library(td::ConstBitPtr hash) {
return lib;
}
}
missing_library = hash;
missing_library = td::Bits256{hash};
return {};
}
@ -770,4 +772,15 @@ void VmState::restore_parent_vm(int res) {
}
}
td::Status init_vm(bool enable_debug) {
if (!init_op_cp0(enable_debug)) {
return td::Status::Error("Failed to init TVM: failed to init cp0");
}
auto code = sodium_init();
if (code < 0) {
return td::Status::Error(PSTRING() << "Failed to init TVM: sodium_init, code=" << code);
}
return td::Status::OK();
}
} // namespace vm

View file

@ -25,6 +25,7 @@
#include "vm/log.h"
#include "vm/continuation.h"
#include "td/utils/HashSet.h"
#include "td/utils/optional.h"
namespace vm {
@ -97,7 +98,7 @@ class VmState final : public VmStateInterface {
td::HashSet<CellHash> loaded_cells;
int stack_trace{0}, debug_off{0};
bool chksig_always_succeed{false};
td::ConstBitPtr missing_library{0};
td::optional<td::Bits256> missing_library;
td::uint16 max_data_depth = 512; // Default value
int global_version{0};
size_t chksgn_counter = 0;
@ -383,7 +384,7 @@ class VmState final : public VmStateInterface {
Ref<OrdCont> ref_to_cont(Ref<Cell> cell) const {
return td::make_ref<OrdCont>(load_cell_slice_ref(std::move(cell)), get_cp());
}
td::ConstBitPtr get_missing_library() const {
td::optional<td::Bits256> get_missing_library() const {
return missing_library;
}
void set_max_data_depth(td::uint16 depth) {
@ -422,4 +423,6 @@ int run_vm_code(Ref<CellSlice> _code, Stack& _stack, int flags = 0, Ref<Cell>* d
Ref<vm::Cell> lookup_library_in(td::ConstBitPtr key, Ref<vm::Cell> lib_root);
td::Status init_vm(bool enable_debug = false);
} // namespace vm