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

[FunC] Deprecate method_id specifier, introduce get keyword

`get` keyword behaves exactly like `method_id` (auto-calc hash),
but it's placed on the left, similar to Tact: `get T name()`.

`method_id(n)` is still valid, considering it can't be invoked by name,
since a client will compute another hash.
It's supposed it will be still used in tests and in low-level code
(not to be called externally, but to be called after replacing c3).

`get(hash)` is invalid, this keyword does not accept anything.
This commit is contained in:
Aleksandr Kirsanov 2024-05-21 15:34:37 +03:00
parent 7afa9292c3
commit 7b8268d99f
No known key found for this signature in database
GPG key ID: B758BBAA01FFB3D3
16 changed files with 103 additions and 72 deletions

View file

@ -103,7 +103,7 @@ cell loadData() {
}
}
(tuple) get_external_voting_data(int voting_id) method_id {
get (tuple) get_external_voting_data(int voting_id) {
cell external_votings = loadData();
(slice voting_data, int found?) = external_votings.udict_get?(256, voting_id);
throw_unless(309, found?);

View file

@ -106,22 +106,22 @@ slice calculate_nft_item_address(int wc, cell state_init) {
;; Get methods
(int, cell, slice) get_collection_data() method_id {
get (int, cell, slice) get_collection_data() {
var (content, nft_item_code) = load_data();
return (-1, content, zero_address());
}
slice get_nft_address_by_index(int index) method_id {
get slice get_nft_address_by_index(int index) {
var (content, nft_item_code) = load_data();
cell state_init = calculate_nft_item_state_init(index, nft_item_code);
return calculate_nft_item_address(workchain(), state_init);
}
cell get_nft_content(int index, cell individual_nft_content) method_id {
get cell get_nft_content(int index, cell individual_nft_content) {
return individual_nft_content;
}
(int, cell) dnsresolve(slice subdomain, int category) method_id {
get (int, cell) dnsresolve(slice subdomain, int category) {
throw_unless(70, mod(slice_bits(subdomain), 8) == 0);
int starts_with_zero_byte = subdomain.preload_int(8) == 0;

View file

@ -248,7 +248,7 @@ _ unpack_owner_info(slice cs) inline_ref {
;; Get methods
;; returns -1 for processed queries, 0 for unprocessed, 1 for unknown (forgotten)
(int, int) get_query_state(int query_id) method_id {
get (int, int) get_query_state(int query_id) {
(_, int n, _, int last_cleaned, _, cell pending_queries, _) = unpack_state();
(slice cs, var found) = pending_queries.udict_get?(64, query_id);
if (found) {
@ -263,12 +263,12 @@ _ unpack_owner_info(slice cs) inline_ref {
}
}
int processed?(int query_id) method_id {
get int processed?(int query_id) {
(int x, _) = get_query_state(query_id);
return x;
}
cell create_init_state(int wallet_id, int n, int k, cell owners_info, int spend_delay) method_id {
get cell create_init_state(int wallet_id, int n, int k, cell owners_info, int spend_delay) {
return pack_state(new_dict(), owners_info, 0, k, n, wallet_id, spend_delay);
}
@ -291,7 +291,7 @@ cell merge_list(cell a, cell b) {
}
cell get_public_keys() method_id {
get cell get_public_keys() {
(_, _, _, _, cell public_keys, _, _) = unpack_state();
return public_keys;
}

View file

@ -111,12 +111,12 @@
throw(0xffff);
}
(int, int, slice, cell, cell) get_jetton_data() method_id {
get (int, int, slice, cell, cell) get_jetton_data() {
(int total_supply, slice admin_address, cell content, cell jetton_wallet_code) = load_data();
return (total_supply, -1, admin_address, content, jetton_wallet_code);
}
slice get_wallet_address(slice owner_address) method_id {
get slice get_wallet_address(slice owner_address) {
(int total_supply, slice admin_address, cell content, cell jetton_wallet_code) = load_data();
return calculate_user_jetton_wallet_address(owner_address, my_address(), jetton_wallet_code);
}

View file

@ -674,16 +674,16 @@ cell distribute_share(int reward, cell nominators) inline_ref {
;; Get methods
_ get_pool_data() method_id {
get _ get_pool_data() {
return load_data();
}
int has_withdraw_requests() method_id {
get int has_withdraw_requests() {
(int state, int nominators_count, int stake_amount_sent, int validator_amount, (int validator_address, int validator_reward_share, int max_nominators_count, int min_validator_stake, int min_nominator_stake), cell nominators, cell withdraw_requests, int stake_at, int saved_validator_set_hash, int validator_set_changes_count, int validator_set_change_time, int stake_held_for, cell config_proposal_votings) = load_data();
return ~ cell_null?(withdraw_requests);
}
(int, int, int) get_nominator_data(int nominator_address) method_id {
get (int, int, int) get_nominator_data(int nominator_address) {
(int state, int nominators_count, int stake_amount_sent, int validator_amount, (int validator_address, int validator_reward_share, int max_nominators_count, int min_validator_stake, int min_nominator_stake), cell nominators, cell withdraw_requests, int stake_at, int saved_validator_set_hash, int validator_set_changes_count, int validator_set_change_time, int stake_held_for, cell config_proposal_votings) = load_data();
(slice nominator, int found) = nominators.udict_get?(ADDR_SIZE(), nominator_address);
@ -694,11 +694,11 @@ int has_withdraw_requests() method_id {
return (amount, pending_deposit_amount, withdraw_found);
}
int get_max_punishment(int stake) method_id {
get int get_max_punishment(int stake) {
return max_recommended_punishment_for_validator_misbehaviour(stake);
}
tuple list_nominators() method_id {
get tuple list_nominators() {
(int state, int nominators_count, int stake_amount_sent, int validator_amount, (int validator_address, int validator_reward_share, int max_nominators_count, int min_validator_stake, int min_nominator_stake), cell nominators, cell withdraw_requests, int stake_at, int saved_validator_set_hash, int validator_set_changes_count, int validator_set_change_time, int stake_held_for, cell config_proposal_votings) = load_data();
var list = null();
int address = -1;
@ -713,7 +713,7 @@ tuple list_nominators() method_id {
return list;
}
tuple list_votes() method_id {
get tuple list_votes() {
(int state, int nominators_count, int stake_amount_sent, int validator_amount, (int validator_address, int validator_reward_share, int max_nominators_count, int min_validator_stake, int min_nominator_stake), cell nominators, cell withdraw_requests, int stake_at, int saved_validator_set_hash, int validator_set_changes_count, int validator_set_change_time, int stake_held_for, cell config_proposal_votings) = load_data();
var list = null();
int proposal_hash = -1;
@ -727,7 +727,7 @@ tuple list_votes() method_id {
return list;
}
tuple list_voters(int proposal_hash) method_id {
get tuple list_voters(int proposal_hash) {
(int state, int nominators_count, int stake_amount_sent, int validator_amount, (int validator_address, int validator_reward_share, int max_nominators_count, int min_validator_stake, int min_nominator_stake), cell nominators, cell withdraw_requests, int stake_at, int saved_validator_set_hash, int validator_set_changes_count, int validator_set_change_time, int stake_held_for, cell config_proposal_votings) = load_data();
var list = null();
(slice votes_slice, int found) = config_proposal_votings.udict_get?(256, proposal_hash);

View file

@ -283,7 +283,7 @@ cell change_dns_record(cell dns, slice in_msg_body) {
;; GET Methods
;;
(int, int, slice, slice, cell) get_nft_data() method_id {
get (int, int, slice, slice, cell) get_nft_data() {
(cell config, cell state) = unpack_item_data();
(int item_index, slice collection_address) = unpack_item_config(config);
if (cell_null?(state)) {
@ -294,7 +294,7 @@ cell change_dns_record(cell dns, slice in_msg_body) {
return (-1, item_index, collection_address, owner_address, nft_content);
}
slice get_full_domain() method_id {
get slice get_full_domain() {
(cell config, cell state) = unpack_item_data();
(slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state);
(cell nft_content, cell dns, cell token_info) = unpack_item_content(content);
@ -302,7 +302,7 @@ slice get_full_domain() method_id {
return begin_cell().store_slice(domain).store_slice(token_name).store_int(0, 8).end_cell().begin_parse();
}
slice get_telemint_token_name() method_id {
get slice get_telemint_token_name() {
(cell config, cell state) = unpack_item_data();
(slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state);
(cell nft_content, cell dns, cell token_info) = unpack_item_content(content);
@ -310,7 +310,7 @@ slice get_telemint_token_name() method_id {
return token_name;
}
(slice, int, int, int, int) get_telemint_auction_state() method_id {
get (slice, int, int, int, int) get_telemint_auction_state() {
(cell config, cell state) = unpack_item_data();
(slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state);
throw_if (err::no_auction, cell_null?(auction));
@ -323,7 +323,7 @@ slice get_telemint_token_name() method_id {
return (bidder_address, bid, bid_ts, min_bid, end_time);
}
(slice, int, int, int, int, int) get_telemint_auction_config() method_id {
get (slice, int, int, int, int, int) get_telemint_auction_config() {
(cell config, cell state) = unpack_item_data();
(slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state);
if (cell_null?(auction)) {
@ -336,14 +336,14 @@ slice get_telemint_token_name() method_id {
return (beneficiary_address, initial_min_bid, max_bid, min_bid_step, min_extend_time, duration);
}
(int, int, slice) royalty_params() method_id {
get (int, int, slice) royalty_params() {
(cell config, cell state) = unpack_item_data();
(slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state);
(int numerator, int denominator, slice destination) = unpack_nft_royalty_params(royalty_params);
return (numerator, denominator, destination);
}
(int, cell) dnsresolve(slice subdomain, int category) method_id {
get (int, cell) dnsresolve(slice subdomain, int category) {
(cell config, cell state) = unpack_item_data();
(slice owner_address, cell content, cell auction, cell royalty_params) = unpack_item_state(state);
(cell nft_content, cell dns, cell token_info) = unpack_item_content(content);

View file

@ -168,27 +168,27 @@ _ skipBits(slice s, int len) { return skip_bits(s, len); }
;; Get methods
int seqno() method_id {
get int seqno() {
return get_data().begin_parse().preload_uint(32);
}
int get_subwallet_id() method_id {
get int get_subwallet_id() {
return get_data().begin_parse().skip_bits(32).preload_uint(32);
}
int get_public_key() method_id {
get int get_public_key() {
var cs = get_data().begin_parse().skip_bits(64);
return cs.preload_uint(256);
}
int is_plugin_installed(int wc, int addr_hash) method_id {
get int is_plugin_installed(int wc, int addr_hash) {
var ds = get_data().begin_parse().skipBits(32 + 32 + 256);
var plugins = ds~load_dict();
var (_, success?) = plugins.dict_get?(8 + 256, begin_cell().store_int(wc, 8).store_uint(addr_hash, 256).end_cell().begin_parse());
return success?;
}
tuple get_plugin_list() method_id {
get tuple get_plugin_list() {
var list = null();
var ds = get_data().begin_parse().skip_bits(32 + 32 + 256);
var plugins = ds~load_dict();

View file

@ -2,17 +2,17 @@
;; Related contracts
;;
_ get_proxy() method_id {
get _ get_proxy() {
load_base_data();
return ctx_proxy;
}
_ get_owner() method_id {
get _ get_owner() {
load_base_data();
return ctx_owner;
}
_ get_controller() method_id {
get _ get_controller() {
load_base_data();
return ctx_controller;
}
@ -21,13 +21,13 @@ _ get_controller() method_id {
;; Balances for controller
;;
_ get_unowned() method_id {
get _ get_unowned() {
load_base_data();
var [balance, extra] = get_balance();
return max(balance - owned_balance(), 0);
}
_ get_available() method_id {
get _ get_available() {
load_base_data();
return ctx_balance - ctx_balance_sent;
}
@ -36,7 +36,7 @@ _ get_available() method_id {
;; Pool and staking status
;;
_ get_staking_status() method_id {
get _ get_staking_status() {
load_base_data();
load_validator_data();
@ -50,7 +50,7 @@ _ get_staking_status() method_id {
return (proxy_stake_at, until_val, proxy_stake_sent, querySent, unlocked, ctx_locked);
}
_ get_pool_status() method_id {
get _ get_pool_status() {
load_base_data();
load_member(owner_id());
return (ctx_balance, ctx_balance_sent, ctx_balance_pending_deposits, ctx_balance_pending_withdraw, ctx_balance_withdraw);
@ -59,7 +59,7 @@ _ get_pool_status() method_id {
;;
;; Params
;;
_ get_params() method_id {
get _ get_params() {
load_base_data();
var (enabled, udpates_enabled, min_stake, deposit_fee, withdraw_fee, pool_fee, receipt_price) = ctx_extras;
return (enabled, udpates_enabled, min_stake, deposit_fee, withdraw_fee, pool_fee, receipt_price);
@ -69,7 +69,7 @@ _ get_params() method_id {
;; Members
;;
_ get_member_balance(slice address) method_id {
get _ get_member_balance(slice address) {
load_base_data();
load_member(parse_work_addr(address));
@ -77,12 +77,12 @@ _ get_member_balance(slice address) method_id {
return (ctx_member_balance, ctx_member_pending_deposit, ctx_member_pending_withdraw, ctx_member_withdraw);
}
_ get_members_raw() method_id {
get _ get_members_raw() {
load_base_data();
return ctx_nominators;
}
_ get_members() method_id {
get _ get_members() {
load_base_data();
;; Init with owner
@ -110,16 +110,16 @@ _ get_members() method_id {
return list;
}
_ get_member(slice address) method_id {
get _ get_member(slice address) {
load_base_data();
load_member(parse_work_addr(address));
member_update_balance();
return (ctx_member_balance, ctx_member_pending_deposit, ctx_member_pending_withdraw, ctx_member_withdraw);
}
_ supported_interfaces() method_id {
get _ supported_interfaces() {
return (
123515602279859691144772641439386770278, ;; org.ton.introspection.v0
256184278959413194623484780286929323492 ;; com.tonwhales.nominators:v0
);
}
}

View file

@ -40,7 +40,7 @@ int test1() method_id(101) {
return s~load_uint(32);
}
int test2(int ret) method_id {
get int test2(int ret) {
return setAndGetDataWrapper(ret);
}

View file

@ -0,0 +1,8 @@
get (int, int) hello(int x, int y) method_id(123) {
return (x, y);
}
{-
@compilation_should_fail
@stderr both `get` and `method_id` are not allowed
-}

View file

@ -1,28 +1,28 @@
slice ascii_slice() method_id {
get slice ascii_slice() {
return "string";
}
slice raw_slice() method_id {
get slice raw_slice() {
return "abcdef"s;
}
slice addr_slice() method_id {
get slice addr_slice() {
return "Ef8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM0vF"a;
}
int string_hex() method_id {
get int string_hex() {
return "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"u;
}
int string_minihash() method_id {
get int string_minihash() {
return "transfer(slice, int)"h;
}
int string_maxihash() method_id {
get int string_maxihash() {
return "transfer(slice, int)"H;
}
int string_crc32() method_id {
get int string_crc32() {
return "transfer(slice, int)"c;
}

View file

@ -116,6 +116,7 @@ enum Keyword {
_Builtin,
_AutoApply,
_MethodId,
_Get,
_Operator,
_Infix,
_Infixl,
@ -769,6 +770,7 @@ struct SymValFunc : SymVal {
flagUsedAsNonCall = 8, // used not only as `f()`, but as a 1-st class function (assigned to var, pushed to tuple, etc.)
flagMarkedAsPure = 16, // declared as `pure`, can't call impure and access globals, unused invocations are optimized out
flagBuiltinFunction = 32, // was created via `define_builtin_func()`, not from source code
flagGetMethod = 64, // was declared via `get T func()`, method_id is auto-assigned
};
td::RefInt256 method_id; // todo why int256? it's small
@ -807,6 +809,9 @@ struct SymValFunc : SymVal {
bool is_builtin() const {
return flags & flagBuiltinFunction;
}
bool is_get_method() const {
return flags & flagGetMethod;
}
};
struct SymValCodeFunc : SymValFunc {

View file

@ -126,6 +126,7 @@ void define_keywords() {
.add_keyword("builtin", Kw::_Builtin)
.add_keyword("auto_apply", Kw::_AutoApply)
.add_keyword("method_id", Kw::_MethodId)
.add_keyword("get", Kw::_Get)
.add_keyword("operator", Kw::_Operator)
.add_keyword("infix", Kw::_Infix)
.add_keyword("infixl", Kw::_Infixl)

View file

@ -1509,12 +1509,22 @@ void detect_if_function_just_wraps_another(SymValCodeFunc* v_current, const td::
}
}
static td::RefInt256 calculate_method_id_by_func_name(const std::string &func_name) {
unsigned int crc = td::crc16(func_name);
return td::make_refint((crc & 0xffff) | 0x10000);
}
// todo rewrite function declaration parsing completely, it's weird
void parse_func_def(Lexer& lex) {
SrcLocation loc{lex.cur().loc};
sym::open_scope(lex);
std::vector<TypeExpr*> type_vars;
bool is_get_method = false;
if (lex.tp() == _Forall) {
type_vars = parse_type_var_list(lex);
} else if (lex.tp() == _Get) {
is_get_method = true;
lex.next();
}
auto ret_type = parse_type(lex);
if (lex.tp() != _Ident) {
@ -1544,32 +1554,32 @@ void parse_func_def(Lexer& lex) {
lex.next();
}
td::RefInt256 method_id;
std::string method_name;
if (lex.tp() == _MethodId) {
if (is_get_method) {
lex.cur().error("both `get` and `method_id` are not allowed");
}
lex.next();
if (lex.tp() == '(') {
if (lex.tp() == '(') { // method_id(N)
lex.expect('(');
if (lex.tp() == Lexem::String) {
method_name = lex.cur().str;
} else if (lex.tp() == Lexem::Number) {
method_name = lex.cur().str;
method_id = td::string_to_int256(method_name);
if (method_id.is_null()) {
lex.cur().error_at("invalid integer constant `", "`");
}
} else {
throw src::ParseError{lex.cur().loc, "integer or string method identifier expected"};
method_id = td::string_to_int256(lex.cur().str);
lex.expect(Lexem::Number);
if (method_id.is_null()) {
lex.cur().error_at("invalid integer constant `", "`");
}
lex.next();
lex.expect(')');
} else {
method_name = func_name.str;
}
if (method_id.is_null()) {
unsigned crc = td::crc16(method_name);
method_id = td::make_refint((crc & 0xffff) | 0x10000);
static bool warning_shown = false;
if (!warning_shown) {
lex.cur().loc.show_warning("`method_id` specifier is deprecated, use `get` keyword.\nExample: `get int seqno() { ... }`");
warning_shown = true;
}
method_id = calculate_method_id_by_func_name(func_name.str);
}
}
if (is_get_method) {
func_assert(method_id.is_null());
method_id = calculate_method_id_by_func_name(func_name.str);
}
TypeExpr* func_type = TypeExpr::new_map(extract_total_arg_type(arg_list), ret_type);
func_type = compute_type_closure(func_type, type_vars);
if (lex.tp() == _Builtin) {
@ -1682,6 +1692,13 @@ void parse_func_def(Lexer& lex) {
lex.cur().error("inline mode for `"s + func_name.str + "` changed with respect to a previous declaration");
}
}
if (is_get_method) {
auto val = dynamic_cast<SymValFunc*>(func_sym->value);
if (!val) {
lex.cur().error("cannot set unknown function `"s + func_name.str + "` as a get method");
}
val->flags |= SymValFunc::flagGetMethod;
}
if (verbosity >= 1) {
std::cerr << "new type of function " << func_name.str << " : " << func_type << std::endl;
}

View file

@ -926,7 +926,7 @@ bool TestNode::show_help(std::string command) {
"saveaccount[code|data] <filename> <addr> [<block-id-ext>]\tSaves into specified file the most recent state "
"(StateInit) or just the code or data of specified account; <addr> is in "
"[<workchain>:]<hex-or-base64-addr> format\n"
"runmethod[full] <addr> [<block-id-ext>] <method-id> <params>...\tRuns GET method <method-id> of account "
"runmethod[full] <addr> [<block-id-ext>] <name> <params>...\tRuns GET method <name> of account "
"<addr> "
"with specified parameters\n"
"dnsresolve [<block-id-ext>] <domain> [<category>]\tResolves a domain starting from root dns smart contract\n"

View file

@ -386,7 +386,7 @@ class TonlibCli : public td::actor::Actor {
td::TerminalIO::out() << "sendfile <filename>\tLoad a serialized message from <filename> and send it to server\n";
td::TerminalIO::out() << "setconfig|validateconfig <path> [<name>] [<use_callback>] [<force>] - set or validate "
"lite server config\n";
td::TerminalIO::out() << "runmethod <addr> <method-id> <params>...\tRuns GET method <method-id> of account "
td::TerminalIO::out() << "runmethod <addr> <name> <params>...\tRuns GET method <name> of account "
"<addr> with specified parameters\n";
td::TerminalIO::out() << "getstate <key_id>\tget state of wallet with requested key\n";
td::TerminalIO::out() << "getstatebytransaction <key_id> <lt> <hash>\tget state of wallet with requested key after transaction with local time <lt> and hash <hash> (base64url)\n";