mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Add legacy_tester for existing funC contracts (#588)
* Add legacy_tester for existing funC contracts * Add storage-contracts and pragma options
This commit is contained in:
parent
13b9f460af
commit
6b49d6a382
70 changed files with 14495 additions and 0 deletions
643
crypto/func/auto-tests/legacy_tests/config/config-code.fc
Normal file
643
crypto/func/auto-tests/legacy_tests/config/config-code.fc
Normal file
|
@ -0,0 +1,643 @@
|
|||
;; Simple configuration smart contract
|
||||
|
||||
#include "stdlib.fc";
|
||||
|
||||
() set_conf_param(int index, cell value) impure {
|
||||
var cs = get_data().begin_parse();
|
||||
var cfg_dict = cs~load_ref();
|
||||
cfg_dict~idict_set_ref(32, index, value);
|
||||
set_data(begin_cell().store_ref(cfg_dict).store_slice(cs).end_cell());
|
||||
}
|
||||
|
||||
(cell, int, int, cell) load_data() inline {
|
||||
var cs = get_data().begin_parse();
|
||||
var res = (cs~load_ref(), cs~load_uint(32), cs~load_uint(256), cs~load_dict());
|
||||
cs.end_parse();
|
||||
return res;
|
||||
}
|
||||
|
||||
() store_data(cfg_dict, stored_seqno, public_key, vote_dict) impure inline {
|
||||
set_data(begin_cell()
|
||||
.store_ref(cfg_dict)
|
||||
.store_uint(stored_seqno, 32)
|
||||
.store_uint(public_key, 256)
|
||||
.store_dict(vote_dict)
|
||||
.end_cell());
|
||||
}
|
||||
|
||||
;; (min_tot_rounds, max_tot_rounds, min_wins, max_losses, min_store_sec, max_store_sec, bit_price, cell_price)
|
||||
_ parse_vote_config(cell c) inline {
|
||||
var cs = c.begin_parse();
|
||||
throw_unless(44, cs~load_uint(8) == 0x36);
|
||||
var res = (cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(8), cs~load_uint(32), cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
|
||||
cs.end_parse();
|
||||
return res;
|
||||
}
|
||||
|
||||
;; cfg_vote_setup#91 normal_params:^ConfigProposalSetup critical_params:^ConfigProposalSetup = ConfigVotingSetup;
|
||||
_ get_vote_config_internal(int critical?, cell cparam11) inline_ref {
|
||||
var cs = cparam11.begin_parse();
|
||||
throw_unless(44, cs~load_uint(8) == 0x91);
|
||||
if (critical?) {
|
||||
cs~load_ref();
|
||||
}
|
||||
return parse_vote_config(cs.preload_ref());
|
||||
}
|
||||
|
||||
_ get_vote_config(int critical?) inline {
|
||||
return get_vote_config_internal(critical?, config_param(11));
|
||||
}
|
||||
|
||||
(int, int) check_validator_set(cell vset) {
|
||||
var cs = vset.begin_parse();
|
||||
throw_unless(9, cs~load_uint(8) == 0x12); ;; validators_ext#12 only
|
||||
int utime_since = cs~load_uint(32);
|
||||
int utime_until = cs~load_uint(32);
|
||||
int total = cs~load_uint(16);
|
||||
int main = cs~load_uint(16);
|
||||
throw_unless(9, main > 0);
|
||||
throw_unless(9, total >= main);
|
||||
return (utime_since, utime_until);
|
||||
}
|
||||
|
||||
() send_answer(addr, query_id, ans_tag, mode) impure {
|
||||
;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 011000
|
||||
send_raw_message(begin_cell()
|
||||
.store_uint(0x18, 6)
|
||||
.store_slice(addr)
|
||||
.store_uint(0, 5 + 4 + 4 + 64 + 32 + 1 + 1)
|
||||
.store_uint(ans_tag, 32)
|
||||
.store_uint(query_id, 64)
|
||||
.end_cell(), mode);
|
||||
}
|
||||
|
||||
() send_confirmation(addr, query_id, ans_tag) impure inline {
|
||||
return send_answer(addr, query_id, ans_tag, 64);
|
||||
}
|
||||
|
||||
() send_error(addr, query_id, ans_tag) impure inline {
|
||||
return send_answer(addr, query_id, ans_tag, 64);
|
||||
}
|
||||
|
||||
;; forward a message to elector smart contract to make it upgrade its code
|
||||
() change_elector_code(slice cs) impure {
|
||||
var dest_addr = config_param(1).begin_parse().preload_uint(256);
|
||||
var query_id = now();
|
||||
send_raw_message(begin_cell()
|
||||
.store_uint(0xc4ff, 17)
|
||||
.store_uint(dest_addr, 256)
|
||||
.store_grams(1 << 30) ;; ~ 1 Gram (will be returned back)
|
||||
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
|
||||
.store_uint(0x4e436f64, 32) ;; action
|
||||
.store_uint(query_id, 64)
|
||||
.store_slice(cs)
|
||||
.end_cell(), 0);
|
||||
}
|
||||
|
||||
() after_code_upgrade(slice param, cont old_code) impure method_id(1666) {
|
||||
}
|
||||
|
||||
_ perform_action(cfg_dict, public_key, action, cs) inline_ref {
|
||||
if (action == 0x43665021) {
|
||||
;; change one configuration parameter
|
||||
var param_index = cs~load_int(32);
|
||||
var param_value = cs~load_ref();
|
||||
cs.end_parse();
|
||||
cfg_dict~idict_set_ref(32, param_index, param_value);
|
||||
return (cfg_dict, public_key);
|
||||
} elseif (action == 0x4e436f64) {
|
||||
;; change configuration smart contract code
|
||||
var new_code = cs~load_ref();
|
||||
set_code(new_code);
|
||||
var old_code = get_c3();
|
||||
set_c3(new_code.begin_parse().bless());
|
||||
after_code_upgrade(cs, old_code);
|
||||
throw(0);
|
||||
return (cfg_dict, public_key);
|
||||
} elseif (action == 0x50624b21) {
|
||||
;; change configuration master public key
|
||||
public_key = cs~load_uint(256);
|
||||
cs.end_parse();
|
||||
return (cfg_dict, public_key);
|
||||
} elseif (action == 0x4e43ef05) {
|
||||
;; change election smart contract code
|
||||
change_elector_code(cs);
|
||||
return (cfg_dict, public_key);
|
||||
} else {
|
||||
throw_if(32, action);
|
||||
return (cfg_dict, public_key);
|
||||
}
|
||||
}
|
||||
|
||||
(cell, int, cell) get_current_vset() inline_ref {
|
||||
var vset = config_param(34);
|
||||
var cs = begin_parse(vset);
|
||||
;; validators_ext#12 utime_since:uint32 utime_until:uint32
|
||||
;; total:(## 16) main:(## 16) { main <= total } { main >= 1 }
|
||||
;; total_weight:uint64
|
||||
throw_unless(40, cs~load_uint(8) == 0x12);
|
||||
cs~skip_bits(32 + 32 + 16 + 16);
|
||||
var (total_weight, dict) = (cs~load_uint(64), cs~load_dict());
|
||||
cs.end_parse();
|
||||
return (vset, total_weight, dict);
|
||||
}
|
||||
|
||||
(slice, int) get_validator_descr(int idx) inline_ref {
|
||||
var (vset, total_weight, dict) = get_current_vset();
|
||||
var (value, _) = dict.udict_get?(16, idx);
|
||||
return (value, total_weight);
|
||||
}
|
||||
|
||||
(int, int) unpack_validator_descr(slice cs) inline {
|
||||
;; ed25519_pubkey#8e81278a pubkey:bits256 = SigPubKey;
|
||||
;; validator#53 public_key:SigPubKey weight:uint64 = ValidatorDescr;
|
||||
;; validator_addr#73 public_key:SigPubKey weight:uint64 adnl_addr:bits256 = ValidatorDescr;
|
||||
throw_unless(41, (cs~load_uint(8) & ~ 0x20) == 0x53);
|
||||
throw_unless(41, cs~load_uint(32) == 0x8e81278a);
|
||||
return (cs~load_uint(256), cs~load_uint(64));
|
||||
}
|
||||
|
||||
;; cfg_proposal#f3 param_id:int32 param_value:(Maybe ^Cell) if_hash_equal:(Maybe uint256)
|
||||
;; c -> (param-id param-cell maybe-hash)
|
||||
(int, cell, int) parse_config_proposal(cell c) inline_ref {
|
||||
var cs = c.begin_parse();
|
||||
throw_unless(44, cs~load_int(8) == 0xf3 - 0x100);
|
||||
var (id, val, hash) = (cs~load_int(32), cs~load_maybe_ref(), cs~load_int(1));
|
||||
if (hash) {
|
||||
hash = cs~load_uint(256);
|
||||
} else {
|
||||
hash = -1;
|
||||
}
|
||||
cs.end_parse();
|
||||
return (id, val, hash);
|
||||
}
|
||||
|
||||
(cell, int, cell) accept_proposal(cell cfg_dict, cell proposal, int critical?) inline_ref {
|
||||
var (param_id, param_val, req_hash) = parse_config_proposal(proposal);
|
||||
cell cur_val = cfg_dict.idict_get_ref(32, param_id);
|
||||
int cur_hash = null?(cur_val) ? 0 : cell_hash(cur_val);
|
||||
if ((cur_hash != req_hash) & (req_hash >= 0)) {
|
||||
;; current value has incorrect hash, do not apply changes
|
||||
return (cfg_dict, 0, null());
|
||||
}
|
||||
cell mparams = cfg_dict.idict_get_ref(32, 9); ;; mandatory parameters
|
||||
var (_, found?) = mparams.idict_get?(32, param_id);
|
||||
if (found? & param_val.null?()) {
|
||||
;; cannot set a mandatory parameter to (null)
|
||||
return (cfg_dict, 0, null());
|
||||
}
|
||||
cell cparams = cfg_dict.idict_get_ref(32, 10); ;; critical parameters
|
||||
(_, found?) = cparams.idict_get?(32, param_id);
|
||||
if (found? < critical?) {
|
||||
;; trying to set a critical parameter after a non-critical voting
|
||||
return (cfg_dict, 0, null());
|
||||
}
|
||||
;; CHANGE ONE CONFIGURATION PARAMETER (!)
|
||||
cfg_dict~idict_set_ref(32, param_id, param_val);
|
||||
return (cfg_dict, param_id, param_val);
|
||||
}
|
||||
|
||||
(cell, int) perform_proposed_action(cell cfg_dict, int public_key, int param_id, cell param_val) inline_ref {
|
||||
if (param_id == -999) {
|
||||
;; appoint or depose dictator
|
||||
return (cfg_dict, param_val.null?() ? 0 : param_val.begin_parse().preload_uint(256));
|
||||
}
|
||||
if (param_val.null?()) {
|
||||
return (cfg_dict, public_key);
|
||||
}
|
||||
if (param_id == -1000) {
|
||||
;; upgrade code
|
||||
var cs = param_val.begin_parse();
|
||||
var new_code = cs~load_ref();
|
||||
set_code(new_code);
|
||||
var old_code = get_c3();
|
||||
set_c3(new_code.begin_parse().bless());
|
||||
after_code_upgrade(cs, old_code);
|
||||
throw(0);
|
||||
return (cfg_dict, public_key);
|
||||
}
|
||||
if (param_id == -1001) {
|
||||
;; update elector code
|
||||
var cs = param_val.begin_parse();
|
||||
change_elector_code(cs);
|
||||
}
|
||||
return (cfg_dict, public_key);
|
||||
}
|
||||
|
||||
;; cfg_proposal_status#ce expires:uint32 proposal:^ConfigProposal is_critical:Bool
|
||||
;; voters:(HashmapE 16 True) remaining_weight:int64 validator_set_id:uint256
|
||||
;; rounds_remaining:uint8 wins:uint8 losses:uint8 = ConfigProposalStatus;
|
||||
(int, cell, int, cell, int, int, slice) unpack_proposal_status(slice cs) inline_ref {
|
||||
throw_unless(44, cs~load_int(8) == 0xce - 0x100);
|
||||
return (cs~load_uint(32), cs~load_ref(), cs~load_int(1), cs~load_dict(), cs~load_int(64), cs~load_uint(256), cs);
|
||||
}
|
||||
|
||||
slice update_proposal_status(slice rest, int weight_remaining, int critical?) inline_ref {
|
||||
var (min_tot_rounds, max_tot_rounds, min_wins, max_losses, _, _, _, _) = get_vote_config(critical?);
|
||||
var (rounds_remaining, wins, losses) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8));
|
||||
losses -= (weight_remaining >= 0);
|
||||
if (losses > max_losses) {
|
||||
;; lost too many times
|
||||
return null();
|
||||
}
|
||||
rounds_remaining -= 1;
|
||||
if (rounds_remaining < 0) {
|
||||
;; existed for too many rounds
|
||||
return null();
|
||||
}
|
||||
return begin_cell()
|
||||
.store_uint(rounds_remaining, 8)
|
||||
.store_uint(wins, 8)
|
||||
.store_uint(losses, 8)
|
||||
.end_cell().begin_parse();
|
||||
}
|
||||
|
||||
builder begin_pack_proposal_status(int expires, cell proposal, int critical?, cell voters, int weight_remaining, int vset_id) inline {
|
||||
return begin_cell()
|
||||
.store_int(0xce - 0x100, 8)
|
||||
.store_uint(expires, 32)
|
||||
.store_ref(proposal)
|
||||
.store_int(critical?, 1)
|
||||
.store_dict(voters)
|
||||
.store_int(weight_remaining, 64)
|
||||
.store_uint(vset_id, 256);
|
||||
}
|
||||
|
||||
(cell, cell, int) register_vote(vote_dict, phash, idx, weight) inline_ref {
|
||||
var (pstatus, found?) = vote_dict.udict_get?(256, phash);
|
||||
ifnot (found?) {
|
||||
;; config proposal not found
|
||||
return (vote_dict, null(), -1);
|
||||
}
|
||||
var (cur_vset, total_weight, _) = get_current_vset();
|
||||
int cur_vset_id = cur_vset.cell_hash();
|
||||
var (expires, proposal, critical?, voters, weight_remaining, vset_id, rest) = unpack_proposal_status(pstatus);
|
||||
if (expires <= now()) {
|
||||
;; config proposal expired, delete and report not found
|
||||
vote_dict~udict_delete?(256, phash);
|
||||
return (vote_dict, null(), -1);
|
||||
}
|
||||
if (vset_id != cur_vset_id) {
|
||||
;; config proposal belongs to a previous validator set
|
||||
vset_id = cur_vset_id;
|
||||
rest = update_proposal_status(rest, weight_remaining, critical?);
|
||||
voters = null();
|
||||
weight_remaining = muldiv(total_weight, 3, 4);
|
||||
}
|
||||
if (rest.null?()) {
|
||||
;; discard proposal (existed for too many rounds, or too many losses)
|
||||
vote_dict~udict_delete?(256, phash);
|
||||
return (vote_dict, null(), -1);
|
||||
}
|
||||
var (_, found?) = voters.udict_get?(16, idx);
|
||||
if (found?) {
|
||||
;; already voted for this proposal, ignore vote
|
||||
return (vote_dict, null(), -2);
|
||||
}
|
||||
;; register vote
|
||||
voters~udict_set_builder(16, idx, begin_cell().store_uint(now(), 32));
|
||||
int old_wr = weight_remaining;
|
||||
weight_remaining -= weight;
|
||||
if ((weight_remaining ^ old_wr) >= 0) {
|
||||
;; not enough votes, or proposal already accepted in this round
|
||||
;; simply update weight_remaining
|
||||
vote_dict~udict_set_builder(256, phash, begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id).store_slice(rest));
|
||||
return (vote_dict, null(), 2);
|
||||
}
|
||||
;; proposal wins in this round
|
||||
var (min_tot_rounds, max_tot_rounds, min_wins, max_losses, _, _, _, _) = get_vote_config(critical?);
|
||||
var (rounds_remaining, wins, losses) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8));
|
||||
wins += 1;
|
||||
if (wins >= min_wins) {
|
||||
;; proposal is accepted, remove and process
|
||||
vote_dict~udict_delete?(256, phash);
|
||||
return (vote_dict, proposal, 6 - critical?);
|
||||
}
|
||||
;; update proposal info
|
||||
vote_dict~udict_set_builder(256, phash,
|
||||
begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id)
|
||||
.store_uint(rounds_remaining, 8)
|
||||
.store_uint(wins, 8)
|
||||
.store_uint(losses, 8));
|
||||
return (vote_dict, null(), 2);
|
||||
}
|
||||
|
||||
int proceed_register_vote(phash, idx, weight) impure inline_ref {
|
||||
var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
|
||||
(vote_dict, var accepted_proposal, var status) = register_vote(vote_dict, phash, idx, weight);
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
ifnot (accepted_proposal.null?()) {
|
||||
var critical? = 6 - status;
|
||||
(cfg_dict, var param_id, var param_val) = accept_proposal(cfg_dict, accepted_proposal, critical?);
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
if (param_id) {
|
||||
commit();
|
||||
(cfg_dict, public_key) = perform_proposed_action(cfg_dict, public_key, param_id, param_val);
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
(slice, int) scan_proposal(int phash, slice pstatus) inline_ref {
|
||||
var (cur_vset, total_weight, _) = get_current_vset();
|
||||
int cur_vset_id = cur_vset.cell_hash();
|
||||
var (expires, proposal, critical?, voters, weight_remaining, vset_id, rest) = unpack_proposal_status(pstatus);
|
||||
if (expires <= now()) {
|
||||
;; config proposal expired, delete
|
||||
return (null(), true);
|
||||
}
|
||||
if (vset_id == cur_vset_id) {
|
||||
;; config proposal already processed or voted for in this round, change nothing
|
||||
return (pstatus, false);
|
||||
}
|
||||
;; config proposal belongs to a previous validator set
|
||||
vset_id = cur_vset_id;
|
||||
rest = update_proposal_status(rest, weight_remaining, critical?);
|
||||
voters = null();
|
||||
weight_remaining = muldiv(total_weight, 3, 4);
|
||||
if (rest.null?()) {
|
||||
;; discard proposal (existed for too many rounds, or too many losses)
|
||||
return (null(), true);
|
||||
}
|
||||
;; return updated proposal
|
||||
return (begin_pack_proposal_status(expires, proposal, critical?, voters, weight_remaining, vset_id).store_slice(rest).end_cell().begin_parse(), true);
|
||||
}
|
||||
|
||||
cell scan_random_proposal(cell vote_dict) inline_ref {
|
||||
var (phash, pstatus, found?) = vote_dict.udict_get_nexteq?(256, random());
|
||||
ifnot (found?) {
|
||||
return vote_dict;
|
||||
}
|
||||
(pstatus, var changed?) = scan_proposal(phash, pstatus);
|
||||
if (changed?) {
|
||||
if (pstatus.null?()) {
|
||||
vote_dict~udict_delete?(256, phash);
|
||||
} else {
|
||||
vote_dict~udict_set(256, phash, pstatus);
|
||||
}
|
||||
}
|
||||
return vote_dict;
|
||||
}
|
||||
|
||||
int register_voting_proposal(slice cs, int msg_value) impure inline_ref {
|
||||
var (expire_at, proposal, critical?) = (cs~load_uint(32), cs~load_ref(), cs~load_int(1));
|
||||
if (expire_at >> 30) {
|
||||
expire_at -= now();
|
||||
}
|
||||
var (param_id, param_val, hash) = parse_config_proposal(proposal);
|
||||
if (hash >= 0) {
|
||||
cell cur_val = config_param(param_id);
|
||||
int cur_hash = null?(cur_val) ? 0 : cell_hash(cur_val);
|
||||
if (cur_hash != hash) {
|
||||
hash = -0xe2646356; ;; bad current value
|
||||
}
|
||||
} else {
|
||||
var m_params = config_param(9);
|
||||
var (_, found?) = m_params.idict_get?(32, param_id);
|
||||
if (found?) {
|
||||
hash = -0xcd506e6c; ;; cannot set mandatory parameter to null
|
||||
}
|
||||
}
|
||||
if (param_val.cell_depth() >= 256) {
|
||||
hash = -0xc2616456; ;; bad value
|
||||
}
|
||||
if (hash < -1) {
|
||||
return hash; ;; return error if any
|
||||
}
|
||||
ifnot (critical?) {
|
||||
var crit_params = config_param(10);
|
||||
var (_, found?) = crit_params.idict_get?(32, param_id);
|
||||
if (found?) {
|
||||
hash = -0xc3726954; ;; trying to set a critical parameter without critical flag
|
||||
}
|
||||
}
|
||||
if (hash < -1) {
|
||||
return hash;
|
||||
}
|
||||
;; obtain vote proposal configuration
|
||||
var vote_cfg = get_vote_config(critical?);
|
||||
var (min_tot_rounds, max_tot_rounds, min_wins, max_losses, min_store_sec, max_store_sec, bit_price, cell_price) = vote_cfg;
|
||||
if (expire_at < min_store_sec) {
|
||||
return -0xc5787069; ;; expired
|
||||
}
|
||||
expire_at = min(expire_at, max_store_sec);
|
||||
;; compute price
|
||||
var (_, bits, refs) = compute_data_size(param_val, 1024);
|
||||
var pps = bit_price * (bits + 1024) + cell_price * (refs + 2);
|
||||
var price = pps * expire_at;
|
||||
expire_at += now();
|
||||
var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
|
||||
int phash = proposal.cell_hash();
|
||||
var (pstatus, found?) = vote_dict.udict_get?(256, phash);
|
||||
if (found?) {
|
||||
;; proposal already exists; we can only extend it
|
||||
var (expires, r_proposal, r_critical?, voters, weight_remaining, vset_id, rest) = unpack_proposal_status(pstatus);
|
||||
if (r_critical? != critical?) {
|
||||
return -0xc3726955; ;; cannot upgrade critical parameter to non-critical...
|
||||
}
|
||||
if (expires >= expire_at) {
|
||||
return -0xc16c7245; ;; proposal already exists
|
||||
}
|
||||
;; recompute price
|
||||
price = pps * (expire_at - expires + 16384);
|
||||
if (msg_value - price < (1 << 30)) {
|
||||
return -0xf0617924; ;; need more money
|
||||
}
|
||||
;; update expiration time
|
||||
vote_dict~udict_set_builder(256, phash, begin_pack_proposal_status(expire_at, r_proposal, r_critical?, voters, weight_remaining, vset_id).store_slice(rest));
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
return price;
|
||||
}
|
||||
if (msg_value - price < (1 << 30)) {
|
||||
return -0xf0617924; ;; need more money
|
||||
}
|
||||
;; obtain current validator set data
|
||||
var (vset, total_weight, _) = get_current_vset();
|
||||
int weight_remaining = muldiv(total_weight, 3, 4);
|
||||
;; create new proposal
|
||||
vote_dict~udict_set_builder(256, phash,
|
||||
begin_pack_proposal_status(expire_at, proposal, critical?, null(), weight_remaining, vset.cell_hash())
|
||||
.store_uint(max_tot_rounds, 8).store_uint(0, 16));
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
return price;
|
||||
}
|
||||
|
||||
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
|
||||
var cs = in_msg_cell.begin_parse();
|
||||
var flags = cs~load_uint(4); ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
|
||||
var s_addr = cs~load_msg_addr();
|
||||
(int src_wc, int src_addr) = s_addr.parse_std_addr();
|
||||
if ((src_wc + 1) | (flags & 1) | in_msg.slice_empty?()) {
|
||||
;; source not in masterchain, or a bounced message, or a simple transfer
|
||||
return ();
|
||||
}
|
||||
int tag = in_msg~load_uint(32);
|
||||
int query_id = in_msg~load_uint(64);
|
||||
if (tag == 0x4e565354) {
|
||||
;; set next validator set
|
||||
var vset = in_msg~load_ref();
|
||||
in_msg.end_parse();
|
||||
var elector_param = config_param(1);
|
||||
var elector_addr = cell_null?(elector_param) ? -1 : elector_param.begin_parse().preload_uint(256);
|
||||
var ok = false;
|
||||
if (src_addr == elector_addr) {
|
||||
;; message from elector smart contract
|
||||
;; set next validator set
|
||||
(var t_since, var t_until) = check_validator_set(vset);
|
||||
var t = now();
|
||||
ok = (t_since > t) & (t_until > t_since);
|
||||
}
|
||||
if (ok) {
|
||||
set_conf_param(36, vset);
|
||||
;; send confirmation
|
||||
return send_confirmation(s_addr, query_id, 0xee764f4b);
|
||||
} else {
|
||||
return send_error(s_addr, query_id, 0xee764f6f);
|
||||
}
|
||||
}
|
||||
if (tag == 0x6e565052) {
|
||||
;; new voting proposal
|
||||
var price = register_voting_proposal(in_msg, msg_value);
|
||||
int mode = 64;
|
||||
int ans_tag = - price;
|
||||
if (price >= 0) {
|
||||
;; ok, debit price
|
||||
raw_reserve(price, 4);
|
||||
ans_tag = 0xee565052;
|
||||
mode = 128;
|
||||
}
|
||||
return send_answer(s_addr, query_id, ans_tag, mode);
|
||||
}
|
||||
if (tag == 0x566f7465) {
|
||||
;; vote for a configuration proposal
|
||||
var signature = in_msg~load_bits(512);
|
||||
var msg_body = in_msg;
|
||||
var (sign_tag, idx, phash) = (in_msg~load_uint(32), in_msg~load_uint(16), in_msg~load_uint(256));
|
||||
in_msg.end_parse();
|
||||
throw_unless(37, sign_tag == 0x566f7445);
|
||||
var (vdescr, total_weight) = get_validator_descr(idx);
|
||||
var (val_pubkey, weight) = unpack_validator_descr(vdescr);
|
||||
throw_unless(34, check_data_signature(msg_body, signature, val_pubkey));
|
||||
int res = proceed_register_vote(phash, idx, weight);
|
||||
return send_confirmation(s_addr, query_id, res + 0xd6745240);
|
||||
}
|
||||
;; if tag is non-zero and its higher bit is zero, throw an exception (the message is an unsupported query)
|
||||
;; to bounce message back to sender
|
||||
throw_unless(37, (tag == 0) | (tag & (1 << 31)));
|
||||
;; do nothing for other internal messages
|
||||
}
|
||||
|
||||
() recv_external(slice in_msg) impure {
|
||||
var signature = in_msg~load_bits(512);
|
||||
var cs = in_msg;
|
||||
int action = cs~load_uint(32);
|
||||
int msg_seqno = cs~load_uint(32);
|
||||
var valid_until = cs~load_uint(32);
|
||||
throw_if(35, valid_until < now());
|
||||
throw_if(39, slice_depth(cs) > 128);
|
||||
var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
|
||||
throw_unless(33, msg_seqno == stored_seqno);
|
||||
if (action == 0x566f7465) {
|
||||
;; vote for a configuration proposal
|
||||
var (idx, phash) = (cs~load_uint(16), cs~load_uint(256));
|
||||
cs.end_parse();
|
||||
var (vdescr, total_weight) = get_validator_descr(idx);
|
||||
var (val_pubkey, weight) = unpack_validator_descr(vdescr);
|
||||
throw_unless(34, check_data_signature(in_msg, signature, val_pubkey));
|
||||
accept_message();
|
||||
stored_seqno = (stored_seqno + 1) % (1 << 32);
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
commit();
|
||||
proceed_register_vote(phash, idx, weight);
|
||||
return ();
|
||||
}
|
||||
throw_unless(34, check_signature(slice_hash(in_msg), signature, public_key));
|
||||
accept_message();
|
||||
stored_seqno = (stored_seqno + 1) % (1 << 32);
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
commit();
|
||||
(cfg_dict, public_key) = perform_action(cfg_dict, public_key, action, cs);
|
||||
store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
}
|
||||
|
||||
() run_ticktock(int is_tock) impure {
|
||||
var (cfg_dict, stored_seqno, public_key, vote_dict) = load_data();
|
||||
int kl = 32;
|
||||
var next_vset = cfg_dict.idict_get_ref(kl, 36);
|
||||
var updated? = false;
|
||||
ifnot (next_vset.null?()) {
|
||||
;; check whether we have to set next_vset as the current validator set
|
||||
var ds = next_vset.begin_parse();
|
||||
if (ds.slice_bits() >= 40) {
|
||||
var tag = ds~load_uint(8);
|
||||
var since = ds.preload_uint(32);
|
||||
if ((since <= now()) & (tag == 0x12)) {
|
||||
;; next validator set becomes active!
|
||||
var cur_vset = cfg_dict~idict_set_get_ref(kl, 34, next_vset); ;; next_vset -> cur_vset
|
||||
cfg_dict~idict_set_get_ref(kl, 32, cur_vset); ;; cur_vset -> prev_vset
|
||||
cfg_dict~idict_delete?(kl, 36); ;; (null) -> next_vset
|
||||
updated? = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ifnot (updated?) {
|
||||
;; if nothing has been done so far, scan a random voting proposal instead
|
||||
vote_dict = scan_random_proposal(vote_dict);
|
||||
}
|
||||
;; save data and return
|
||||
return store_data(cfg_dict, stored_seqno, public_key, vote_dict);
|
||||
}
|
||||
|
||||
int seqno() method_id {
|
||||
return get_data().begin_parse().preload_uint(32);
|
||||
}
|
||||
|
||||
_ unpack_proposal(slice pstatus) inline_ref {
|
||||
(int expires, cell proposal, int critical?, cell voters, int weight_remaining, int vset_id, slice rest) = unpack_proposal_status(pstatus);
|
||||
var voters_list = null();
|
||||
var voter_id = (1 << 32);
|
||||
do {
|
||||
(voter_id, _, var f) = voters.udict_get_prev?(16, voter_id);
|
||||
if (f) {
|
||||
voters_list = cons(voter_id, voters_list);
|
||||
}
|
||||
} until (~ f);
|
||||
var (rounds_remaining, losses, wins) = (rest~load_uint(8), rest~load_uint(8), rest~load_uint(8));
|
||||
rest.end_parse();
|
||||
var (param_id, param_val, param_hash) = parse_config_proposal(proposal);
|
||||
return [expires, critical?, [param_id, param_val, param_hash], vset_id, voters_list, weight_remaining, rounds_remaining, losses, wins];
|
||||
}
|
||||
|
||||
_ get_proposal(int phash) method_id {
|
||||
(_, _, _, var vote_dict) = load_data();
|
||||
var (pstatus, found?) = vote_dict.udict_get?(256, phash);
|
||||
ifnot (found?) {
|
||||
return null();
|
||||
}
|
||||
return unpack_proposal(pstatus);
|
||||
}
|
||||
|
||||
_ list_proposals() method_id {
|
||||
(_, _, _, var vote_dict) = load_data();
|
||||
var phash = (1 << 255) + ((1 << 255) - 1);
|
||||
var list = null();
|
||||
do {
|
||||
(phash, var pstatus, var f) = vote_dict.udict_get_prev?(256, phash);
|
||||
if (f) {
|
||||
list = cons([phash, unpack_proposal(pstatus)], list);
|
||||
}
|
||||
} until (~ f);
|
||||
return list;
|
||||
}
|
||||
|
||||
_ proposal_storage_price(int critical?, int seconds, int bits, int refs) method_id {
|
||||
var cfg_dict = get_data().begin_parse().preload_ref();
|
||||
var cparam11 = cfg_dict.idict_get_ref(32, 11);
|
||||
var (min_tot_rounds, max_tot_rounds, min_wins, max_losses, min_store_sec, max_store_sec, bit_price, cell_price) = get_vote_config_internal(critical?, cparam11);
|
||||
if (seconds < min_store_sec) {
|
||||
return -1;
|
||||
}
|
||||
seconds = min(seconds, max_store_sec);
|
||||
return (bit_price * (bits + 1024) + cell_price * (refs + 2)) * seconds;
|
||||
}
|
208
crypto/func/auto-tests/legacy_tests/config/stdlib.fc
Normal file
208
crypto/func/auto-tests/legacy_tests/config/stdlib.fc
Normal file
|
@ -0,0 +1,208 @@
|
|||
;; Standard library for funC
|
||||
;;
|
||||
|
||||
forall X -> tuple cons(X head, tuple tail) asm "CONS";
|
||||
forall X -> (X, tuple) uncons(tuple list) asm "UNCONS";
|
||||
forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS";
|
||||
forall X -> X car(tuple list) asm "CAR";
|
||||
tuple cdr(tuple list) asm "CDR";
|
||||
tuple empty_tuple() asm "NIL";
|
||||
forall X -> tuple tpush(tuple t, X value) asm "TPUSH";
|
||||
forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH";
|
||||
forall X -> [X] single(X x) asm "SINGLE";
|
||||
forall X -> X unsingle([X] t) asm "UNSINGLE";
|
||||
forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR";
|
||||
forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR";
|
||||
forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE";
|
||||
forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE";
|
||||
forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE";
|
||||
forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE";
|
||||
forall X -> X first(tuple t) asm "FIRST";
|
||||
forall X -> X second(tuple t) asm "SECOND";
|
||||
forall X -> X third(tuple t) asm "THIRD";
|
||||
forall X -> X fourth(tuple t) asm "3 INDEX";
|
||||
forall X, Y -> X pair_first([X, Y] p) asm "FIRST";
|
||||
forall X, Y -> Y pair_second([X, Y] p) asm "SECOND";
|
||||
forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST";
|
||||
forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND";
|
||||
forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD";
|
||||
forall X -> X null() asm "PUSHNULL";
|
||||
forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP";
|
||||
|
||||
int now() asm "NOW";
|
||||
slice my_address() asm "MYADDR";
|
||||
[int, cell] get_balance() asm "BALANCE";
|
||||
int cur_lt() asm "LTIME";
|
||||
int block_lt() asm "BLOCKLT";
|
||||
|
||||
int cell_hash(cell c) asm "HASHCU";
|
||||
int slice_hash(slice s) asm "HASHSU";
|
||||
int string_hash(slice s) asm "SHA256U";
|
||||
|
||||
int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU";
|
||||
int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS";
|
||||
|
||||
(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE";
|
||||
(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE";
|
||||
(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
||||
(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
||||
|
||||
;; () throw_if(int excno, int cond) impure asm "THROWARGIF";
|
||||
|
||||
() dump_stack() impure asm "DUMPSTK";
|
||||
|
||||
cell get_data() asm "c4 PUSH";
|
||||
() set_data(cell c) impure asm "c4 POP";
|
||||
cont get_c3() impure asm "c3 PUSH";
|
||||
() set_c3(cont c) impure asm "c3 POP";
|
||||
cont bless(slice s) impure asm "BLESS";
|
||||
|
||||
() accept_message() impure asm "ACCEPT";
|
||||
() set_gas_limit(int limit) impure asm "SETGASLIMIT";
|
||||
() commit() impure asm "COMMIT";
|
||||
() buy_gas(int gram) impure asm "BUYGAS";
|
||||
|
||||
int min(int x, int y) asm "MIN";
|
||||
int max(int x, int y) asm "MAX";
|
||||
(int, int) minmax(int x, int y) asm "MINMAX";
|
||||
int abs(int x) asm "ABS";
|
||||
|
||||
slice begin_parse(cell c) asm "CTOS";
|
||||
() end_parse(slice s) impure asm "ENDS";
|
||||
(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF";
|
||||
cell preload_ref(slice s) asm "PLDREF";
|
||||
;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX";
|
||||
;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX";
|
||||
;; int preload_int(slice s, int len) asm "PLDIX";
|
||||
;; int preload_uint(slice s, int len) asm "PLDUX";
|
||||
;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX";
|
||||
;; slice preload_bits(slice s, int len) asm "PLDSLICEX";
|
||||
(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS";
|
||||
slice skip_bits(slice s, int len) asm "SDSKIPFIRST";
|
||||
(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST";
|
||||
slice first_bits(slice s, int len) asm "SDCUTFIRST";
|
||||
slice skip_last_bits(slice s, int len) asm "SDSKIPLAST";
|
||||
(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST";
|
||||
slice slice_last(slice s, int len) asm "SDCUTLAST";
|
||||
(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT";
|
||||
cell preload_dict(slice s) asm "PLDDICT";
|
||||
slice skip_dict(slice s) asm "SKIPDICT";
|
||||
|
||||
(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF";
|
||||
cell preload_maybe_ref(slice s) asm "PLDOPTREF";
|
||||
builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF";
|
||||
|
||||
int cell_depth(cell c) asm "CDEPTH";
|
||||
|
||||
int slice_refs(slice s) asm "SREFS";
|
||||
int slice_bits(slice s) asm "SBITS";
|
||||
(int, int) slice_bits_refs(slice s) asm "SBITREFS";
|
||||
int slice_empty?(slice s) asm "SEMPTY";
|
||||
int slice_data_empty?(slice s) asm "SDEMPTY";
|
||||
int slice_refs_empty?(slice s) asm "SREMPTY";
|
||||
int slice_depth(slice s) asm "SDEPTH";
|
||||
|
||||
int builder_refs(builder b) asm "BREFS";
|
||||
int builder_bits(builder b) asm "BBITS";
|
||||
int builder_depth(builder b) asm "BDEPTH";
|
||||
|
||||
builder begin_cell() asm "NEWC";
|
||||
cell end_cell(builder b) asm "ENDC";
|
||||
builder store_ref(builder b, cell c) asm(c b) "STREF";
|
||||
;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX";
|
||||
;; builder store_int(builder b, int x, int len) asm(x b len) "STIX";
|
||||
builder store_slice(builder b, slice s) asm "STSLICER";
|
||||
builder store_grams(builder b, int x) asm "STGRAMS";
|
||||
builder store_dict(builder b, cell c) asm(c b) "STDICT";
|
||||
|
||||
(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR";
|
||||
tuple parse_addr(slice s) asm "PARSEMSGADDR";
|
||||
(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR";
|
||||
(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR";
|
||||
|
||||
cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF";
|
||||
(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF";
|
||||
cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF";
|
||||
(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF";
|
||||
cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF";
|
||||
(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF";
|
||||
(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF";
|
||||
(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF";
|
||||
(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF";
|
||||
(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL";
|
||||
(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL";
|
||||
(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT";
|
||||
(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT";
|
||||
(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT";
|
||||
(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT";
|
||||
(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT";
|
||||
(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT";
|
||||
cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET";
|
||||
(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET";
|
||||
cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET";
|
||||
(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET";
|
||||
cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET";
|
||||
(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET";
|
||||
(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD";
|
||||
(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE";
|
||||
(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD";
|
||||
(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE";
|
||||
cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB";
|
||||
(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB";
|
||||
cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB";
|
||||
(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB";
|
||||
cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB";
|
||||
(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB";
|
||||
(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB";
|
||||
(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB";
|
||||
(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB";
|
||||
(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB";
|
||||
(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2";
|
||||
(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2";
|
||||
(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2";
|
||||
(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2";
|
||||
(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2";
|
||||
(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2";
|
||||
(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2";
|
||||
(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2";
|
||||
(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2";
|
||||
(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2";
|
||||
(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2";
|
||||
(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2";
|
||||
cell new_dict() asm "NEWDICT";
|
||||
int dict_empty?(cell c) asm "DICTEMPTY";
|
||||
|
||||
(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2";
|
||||
(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET";
|
||||
(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL";
|
||||
|
||||
cell config_param(int x) asm "CONFIGOPTPARAM";
|
||||
int cell_null?(cell c) asm "ISNULL";
|
||||
|
||||
() raw_reserve(int amount, int mode) impure asm "RAWRESERVE";
|
||||
() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX";
|
||||
() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG";
|
||||
() set_code(cell new_code) impure asm "SETCODE";
|
||||
|
||||
int random() impure asm "RANDU256";
|
||||
int rand(int range) impure asm "RAND";
|
||||
int get_seed() impure asm "RANDSEED";
|
||||
int set_seed() impure asm "SETRAND";
|
||||
() randomize(int x) impure asm "ADDRAND";
|
||||
() randomize_lt() impure asm "LTIME" "ADDRAND";
|
Loading…
Add table
Add a link
Reference in a new issue