mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated func and tonlib
This commit is contained in:
parent
493ae2410c
commit
a73d202ba2
50 changed files with 1340 additions and 271 deletions
474
crypto/smartcont/dns-auto-code.fc
Normal file
474
crypto/smartcont/dns-auto-code.fc
Normal file
|
@ -0,0 +1,474 @@
|
|||
{-
|
||||
Adapted from original version written by:
|
||||
/------------------------------------------------------------------------\
|
||||
| Created for: Telegram (Open Network) Blockchain Contest |
|
||||
| Task 2: DNS Resolver (Automatically registering) |
|
||||
>------------------------------------------------------------------------<
|
||||
| Author: Oleksandr Murzin (tg: @skydev / em: alexhacker64@gmail.com) |
|
||||
| October 2019 |
|
||||
\------------------------------------------------------------------------/
|
||||
-}
|
||||
|
||||
;;===========================================================================;;
|
||||
;; Utility functions ;;
|
||||
;;===========================================================================;;
|
||||
|
||||
{-
|
||||
Data structure:
|
||||
Root cell: [OptRef<1b+1r?>:Hashmap<PfxDict:Slice->UInt<32b>,CatTable>:domains]
|
||||
[OptRef<1b+1r?>:Hashmap<UInt<64b>(Time|Hash32)->Slice(DomName)>:gc]
|
||||
[UInt<32b>:stdperiod] [Gram:PPReg] [Gram:PPCell] [Gram:PPBit]
|
||||
[UInt<32b>:lasthousekeeping]
|
||||
<CatTable> := HashmapE 16 ^DNSRecord
|
||||
|
||||
STORED DOMAIN NAME SLICE FORMAT: (#ZeroChars<7b>) (Domain name value)
|
||||
#Zeros allows to simultaneously store, for example, com\0 and com\0google\0
|
||||
That will be stored as \1com\0 and \2com\0google\0 (pfx tree has restricitons)
|
||||
This will allow to resolve more specific requests to subdomains, and resort
|
||||
to parent domain next resolver lookup if subdomain is not found
|
||||
com\0goo\0 lookup will, for example look up \2com\0goo\0 and then
|
||||
\1com\0goo\0 which will return \1com\0 (as per pfx tree) with -1 cat
|
||||
-}
|
||||
|
||||
(cell, cell, [int, int, int, int], int, int) load_data() inline_ref {
|
||||
slice cs = get_data().begin_parse();
|
||||
return (
|
||||
cs~load_dict(), ;; pfx tree: domains data and exp
|
||||
cs~load_dict(), ;; gc auxillary with expiry and 32 bit hash slice
|
||||
[ cs~load_uint(32), ;; length of this period of time in seconds
|
||||
cs~load_grams(), ;; standard payment for registering a new subdomain
|
||||
cs~load_grams(), ;; price paid for each cell (PPC)
|
||||
cs~load_grams() ], ;; and bit (PPB)
|
||||
cs~load_uint(32), ;; next housekeeping to be done at
|
||||
cs~load_uint(32) ;; last housekeeping done at
|
||||
);
|
||||
}
|
||||
|
||||
(int, int, int, int) load_prices() inline_ref {
|
||||
slice cs = get_data().begin_parse();
|
||||
(cs~load_dict(), cs~load_dict());
|
||||
return (cs~load_uint(32), cs~load_grams(), cs~load_grams(), cs~load_grams());
|
||||
}
|
||||
|
||||
() store_data(cell dd, cell gc, prices, int nhk, int lhk) impure {
|
||||
var [sp, ppr, ppc, ppb] = prices;
|
||||
set_data(begin_cell()
|
||||
.store_dict(dd) ;; domains data and exp
|
||||
.store_dict(gc) ;; keyed expiration time and 32 bit hash slice
|
||||
.store_int(sp, 32) ;; standard period
|
||||
.store_grams(ppr) ;; price per registration
|
||||
.store_grams(ppc) ;; price per cell
|
||||
.store_grams(ppb) ;; price per bit
|
||||
.store_uint(nhk, 32) ;; next housekeeping
|
||||
.store_uint(lhk, 32) ;; last housekeeping
|
||||
.end_cell());
|
||||
}
|
||||
|
||||
global var query_info;
|
||||
|
||||
() send_message(slice addr, int tag, int query_id,
|
||||
int body, int grams, int mode) impure {
|
||||
;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
|
||||
;; src:MsgAddress -> 011000 0x18
|
||||
var msg = begin_cell()
|
||||
.store_uint (0x18, 6)
|
||||
.store_slice(addr)
|
||||
.store_grams(grams)
|
||||
.store_uint (0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
|
||||
.store_uint (tag, 32)
|
||||
.store_uint (query_id, 64);
|
||||
if (body >= 0) {
|
||||
msg~store_uint(body, 32);
|
||||
}
|
||||
send_raw_message(msg.end_cell(), mode);
|
||||
}
|
||||
|
||||
() send_error(int error_code) impure {
|
||||
var (addr, query_id, op) = query_info;
|
||||
return send_message(addr, error_code, query_id, op, 0, 64);
|
||||
}
|
||||
|
||||
() send_ok(int price) impure {
|
||||
raw_reserve(price, 4);
|
||||
var (addr, query_id, op) = query_info;
|
||||
return send_message(addr, 0xef6b6179, query_id, op, 0, 128);
|
||||
}
|
||||
|
||||
() housekeeping(cell dd, cell gc, prices, int nhk, int lhk) impure {
|
||||
int n = now();
|
||||
if (n < max(nhk, lhk + 60)) { ;; housekeeping cooldown: 1 minute
|
||||
;; if housekeeping was done recently, or if next housekeeping is in the future, just save
|
||||
return store_data(dd, gc, prices, nhk, lhk);
|
||||
}
|
||||
;; need to do some housekeeping - maybe remove entry with
|
||||
;; least expiration but only if it is already expired
|
||||
;; no iterating and deleting all to not put too much gas gc
|
||||
;; burden on any random specific user request
|
||||
;; over time it will do the garbage collection required
|
||||
(int mkey, cell name, int found?) = gc.udict_get_min_ref?(64);
|
||||
if (found?) { ;; no short circuit optimization, two nested ifs
|
||||
nhk = (mkey >> 32);
|
||||
if (nhk < n) {
|
||||
slice sname = name.begin_parse();
|
||||
(_, slice val, _, found?) = dd.pfxdict_get?(1023, sname);
|
||||
if (found?) {
|
||||
int exp = val.preload_uint(32);
|
||||
if (exp <= n) {
|
||||
dd~pfxdict_delete?(1023, sname);
|
||||
}
|
||||
}
|
||||
gc~udict_delete?(64, mkey);
|
||||
(mkey, _, found?) = gc.udict_get_min_ref?(64);
|
||||
nhk = (found? ? mkey >> 32 : 0xffffffff);
|
||||
}
|
||||
}
|
||||
store_data(dd, gc, prices, nhk, n);
|
||||
}
|
||||
|
||||
int _calcprice(cell data, ppc, ppb) inline_ref { ;; only for internal calcs
|
||||
var (_, bits, refs) = compute_data_size(data, 100); ;; 100 cells max
|
||||
return ppc * refs + ppb * bits;
|
||||
}
|
||||
|
||||
int check_owner(cell cat_table, int src_wc, int src_addr) inline_ref {
|
||||
if (cat_table.null?()) { ;; domain not found: return notf | 2^31
|
||||
return 0xee6f7466;
|
||||
}
|
||||
cell cown = cat_table.idict_get_ref(16, -2);
|
||||
if (cown.null?()) { ;; no owner on this domain: no-2
|
||||
return 0xee6f2d32;
|
||||
}
|
||||
var ERR_BAD2 = 0xe2616432;
|
||||
slice sown = cown.begin_parse();
|
||||
if (sown.slice_bits() < 16 + 3 + 8 + 256) { ;; bad owner record: bad2
|
||||
return ERR_BAD2;
|
||||
}
|
||||
if (sown~load_uint(16 + 3) != 0x9fd3 * 8 + 4) {
|
||||
return ERR_BAD2;
|
||||
}
|
||||
(int owner_wc, int owner_addr) = (sown~load_int(8), sown.preload_uint(256));
|
||||
if ((owner_wc != src_wc) | (owner_addr != src_addr)) { ;; not owner: nown
|
||||
return 0xee6f776e;
|
||||
}
|
||||
return 0; ;; ok
|
||||
}
|
||||
|
||||
;;===========================================================================;;
|
||||
;; Internal message handler (Code 0) ;;
|
||||
;;===========================================================================;;
|
||||
|
||||
{-
|
||||
Internal message cell structure:
|
||||
8 4 2 1
|
||||
int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
|
||||
src:MsgAddressInt dest:MsgAddressInt
|
||||
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
|
||||
created_lt:uint64 created_at:uint32
|
||||
Internal message data structure:
|
||||
[UInt<32b>:op] [UInt<64b>:query_id] [Ref<1r>:name]
|
||||
(if not prolong: [Ref<1r>:value->CatTable])
|
||||
|
||||
-}
|
||||
|
||||
;; Must send at least GR$1 more for possible gas fees!
|
||||
() recv_internal(int ct_bal, int msg_value, cell in_msg_cell, slice in_msg) impure {
|
||||
;; this time very interested in internal messages
|
||||
if (in_msg.slice_bits() < 32) {
|
||||
return (); ;; simple transfer or short
|
||||
}
|
||||
slice cs = in_msg_cell.begin_parse();
|
||||
int flags = cs~load_uint(4);
|
||||
if (flags & 1) {
|
||||
return (); ;; bounced messages
|
||||
}
|
||||
slice s_addr = cs~load_msg_addr();
|
||||
(int src_wc, int src_addr) = s_addr.parse_std_addr();
|
||||
int op = in_msg~load_uint(32);
|
||||
ifnot (op) {
|
||||
return (); ;; simple transfer with comment
|
||||
}
|
||||
int query_id = 0;
|
||||
if (in_msg.slice_bits() >= 64) {
|
||||
query_id = in_msg~load_uint(64);
|
||||
}
|
||||
|
||||
query_info = (s_addr, query_id, op);
|
||||
|
||||
if (op & (1 << 31)) {
|
||||
return (); ;; an answer to our query
|
||||
}
|
||||
int qt = (op == 0x72656764) * 1 + (op == 0x70726f6c) * 2 + (op == 0x75706464) * 4 + (op == 0x676f6763) * 8;
|
||||
ifnot (qt) { ;; unknown query, return error
|
||||
return send_error(0xffffffff);
|
||||
}
|
||||
qt = - qt;
|
||||
|
||||
(cell domdata, cell gc, [int, int, int, int] prices, int nhk, int lhk) = load_data();
|
||||
|
||||
if (qt == 8) { ;; 0x676f6763 -> GO, GC! go!!!
|
||||
;; Manual garbage collection iteration
|
||||
housekeeping(domdata, gc, prices, nhk, 1); ;; forced
|
||||
return send_error(0xef6b6179);
|
||||
}
|
||||
|
||||
slice name = null();
|
||||
cell name_cell = in_msg~load_maybe_ref();
|
||||
if (name_cell.null?()) {
|
||||
int bytes = in_msg~load_uint(6);
|
||||
name = in_msg~load_bits(bytes * 8);
|
||||
} else {
|
||||
name = name_cell.begin_parse();
|
||||
}
|
||||
|
||||
(_, int name_last_byte) = name.slice_last(8).load_uint(8);
|
||||
if (name_last_byte != 0) { ;; name must end with \0! no\0 error
|
||||
return send_error(0xee6f5c30);
|
||||
}
|
||||
|
||||
int zeros = 0;
|
||||
slice cname = name;
|
||||
repeat (cname.slice_bits() ^>> 3) {
|
||||
int c = cname~load_uint(8);
|
||||
zeros -= (c == 0);
|
||||
}
|
||||
|
||||
;; if (zeros != 1) { ;; too much zero chars (overflow): ov\0
|
||||
;; return send_error(0xef765c30); }
|
||||
|
||||
name = begin_cell().store_uint(zeros, 7).store_slice(name).end_cell().begin_parse();
|
||||
|
||||
(slice pfx, slice val, slice tail, int found?) = domdata.pfxdict_get?(1023, name);
|
||||
int n = now();
|
||||
cell cat_table = null();
|
||||
int exp = 0;
|
||||
|
||||
if (found?) {
|
||||
exp = val~load_uint(32);
|
||||
if (n > exp) { ;; expired domains behave as not registered
|
||||
found? = false;
|
||||
} else {
|
||||
cat_table = val.preload_ref();
|
||||
}
|
||||
}
|
||||
|
||||
;; ##########################################################################
|
||||
|
||||
int err = 0;
|
||||
if (qt != 1) { ;; not a "register", check that domain exists and is controlled by correct smc
|
||||
err = check_owner(cat_table, src_wc, src_addr);
|
||||
}
|
||||
if (err) {
|
||||
return send_error(err);
|
||||
}
|
||||
|
||||
;; ##########################################################################
|
||||
|
||||
;; load desired data (reuse old for a "prolong" operation)
|
||||
cell data = null();
|
||||
|
||||
if (qt != 2) { ;; not a "prolong", load data dictionary
|
||||
data = in_msg~load_ref();
|
||||
;; basic integrity check of (client-provided) dictionary
|
||||
ifnot (data.dict_empty?()) { ;; 1000 gas!
|
||||
(int dmin, _, int minok) = idict_get_min?(data, 16);
|
||||
(int dmax, _, int maxok) = idict_get_max?(data, 16);
|
||||
throw_unless(31, minok & maxok & (dmin <= dmax));
|
||||
}
|
||||
} else {
|
||||
data = cat_table;
|
||||
}
|
||||
|
||||
;; compute action price
|
||||
var [stdper, ppr, ppc, ppb] = prices;
|
||||
int price = _calcprice(data, ppc, ppb) + (ppr & (qt != 4));
|
||||
if (msg_value - (1 << 30) < price) { ;; gr<p: grams - GR$1 < price
|
||||
return send_error(0xe7723c70);
|
||||
}
|
||||
|
||||
;; load desired expiration unixtime
|
||||
int req_expires_at = in_msg~load_uint(32);
|
||||
|
||||
;; ##########################################################################
|
||||
if (qt == 2) { ;; 0x70726f6c -> prol | prolong domain
|
||||
slice value = begin_cell().store_uint(exp + stdper, 32).store_ref(data).end_cell().begin_parse();
|
||||
|
||||
ifnot (domdata~pfxdict_set?(1023, name, value)) { ;; Set ERR | 2^31
|
||||
return send_error(0xf3657272);
|
||||
}
|
||||
|
||||
int sh_low = name.slice_hash() & ((1 << 32) - 1);
|
||||
int gckeyO = (exp << 32) + sh_low;
|
||||
int gckeyN = gckeyO + (stdper << 32);
|
||||
gc~udict_delete?(64, gckeyO); ;; delete old gc entry, add new
|
||||
gc~udict_set_ref(64, gckeyN, begin_cell().store_slice(name).end_cell());
|
||||
|
||||
housekeeping(domdata, gc, prices, nhk, lhk);
|
||||
return send_ok(price);
|
||||
}
|
||||
|
||||
;; ##########################################################################
|
||||
if (qt == 1) { ;; 0x72656764 -> regd | register domain
|
||||
if (found?) { ;; domain already exists: return alre | 2^31
|
||||
return send_error(0xe16c7265);
|
||||
}
|
||||
int expires_at = n + stdper;
|
||||
slice value = begin_cell().store_uint(expires_at, 32).store_ref(data).end_cell().begin_parse();
|
||||
ifnot (domdata~pfxdict_set?(1023, name, value)) { ;; Set ERR | 2^31
|
||||
return send_error(0xf3657272);
|
||||
}
|
||||
int gckey = (expires_at << 32) | (name.slice_hash() & ((1 << 32) - 1));
|
||||
gc~udict_set_ref(64, gckey, begin_cell().store_slice(name).end_cell());
|
||||
;; using ref requires additional cell, but using value (DICTUSET) may
|
||||
;; cause problems with very long names or complex dictionaries
|
||||
housekeeping(domdata, gc, prices, min(nhk, expires_at), lhk);
|
||||
return send_ok(price);
|
||||
}
|
||||
|
||||
;; ##########################################################################
|
||||
if (qt == 4) { ;; 0x75706464 -> updd | update domain (data)
|
||||
slice value = begin_cell().store_uint(exp, 32).store_ref(data).end_cell().begin_parse();
|
||||
|
||||
ifnot (domdata~pfxdict_set?(1023, name, value)) { ;; Set ERR | 2^31
|
||||
return send_error(0xf3657272);
|
||||
}
|
||||
;; no need to update gc here
|
||||
housekeeping(domdata, gc, prices, nhk, lhk);
|
||||
return send_ok(price);
|
||||
}
|
||||
;; ##########################################################################
|
||||
|
||||
return (); ;; should NEVER reach this part of code!
|
||||
}
|
||||
|
||||
;;===========================================================================;;
|
||||
;; External message handler (Code -1) ;;
|
||||
;;===========================================================================;;
|
||||
|
||||
() recv_external(slice in_msg) impure {
|
||||
;; not interested at all! but need to init!
|
||||
(cell dd, cell gc, var prices, int nhk, int lhk) = load_data();
|
||||
ifnot (lhk) {
|
||||
accept_message();
|
||||
store_data(dd, gc, prices, 0, now());
|
||||
}
|
||||
}
|
||||
|
||||
;;===========================================================================;;
|
||||
;; Getter methods ;;
|
||||
;;===========================================================================;;
|
||||
|
||||
(int, cell, int, slice) dnsdictlookup(slice subdomain, int nowtime) inline_ref {
|
||||
int bits = subdomain.slice_bits();
|
||||
ifnot (bits) {
|
||||
return (0, null(), 0, null()); ;; zero-length input
|
||||
}
|
||||
throw_if(30, bits & 7); ;; malformed input (~ 8n-bit)
|
||||
|
||||
int name_last_byte = subdomain.slice_last(8).preload_uint(8);
|
||||
if (name_last_byte) {
|
||||
subdomain = begin_cell().store_slice(subdomain) ;; append zero byte
|
||||
.store_uint(0, 8).end_cell().begin_parse();
|
||||
bits += 8;
|
||||
}
|
||||
if (bits == 8) {
|
||||
return (0, null(), 0, null()); ;; zero-length input, but with zero byte
|
||||
}
|
||||
(_, cell root) = get_data().begin_parse().load_dict();
|
||||
|
||||
slice cname = subdomain;
|
||||
int zeros = 0;
|
||||
repeat (bits >> 3) {
|
||||
int c = cname~load_uint(8);
|
||||
zeros -= (c == 0);
|
||||
}
|
||||
|
||||
;; can't move these declarations lower, will cause errors!
|
||||
slice pfx = cname;
|
||||
slice val = null();
|
||||
slice tail = cname;
|
||||
int exp = 0;
|
||||
|
||||
do {
|
||||
slice pfxname = begin_cell().store_uint(zeros, 7)
|
||||
.store_slice(subdomain).end_cell().begin_parse();
|
||||
(pfx, val, tail, int succ) = root.pfxdict_get?(1023, pfxname);
|
||||
if (succ) {
|
||||
int exp = val~load_uint(32);
|
||||
if (nowtime > exp) { ;; entry expired, skip
|
||||
succ = false;
|
||||
}
|
||||
}
|
||||
zeros = succ ^ (zeros - 1); ;; break on success
|
||||
} until (zeros <= 0);
|
||||
|
||||
ifnot (zeros) {
|
||||
return (0, null(), 0, null()); ;; failed to find entry in prefix dictionary
|
||||
}
|
||||
|
||||
zeros = - zeros;
|
||||
return (exp, val.preload_ref(), tail.slice_empty?(), pfx);
|
||||
}
|
||||
|
||||
;;8m dns-record-value
|
||||
(int, cell) dnsresolve(slice subdomain, int category) method_id {
|
||||
(int exp, cell cat_table, int exact?, slice pfx) = dnsdictlookup(subdomain, now());
|
||||
ifnot (exp) {
|
||||
return (0, null());
|
||||
}
|
||||
ifnot (exact?) { ;; incomplete subdomain found, must return next resolver (-1)
|
||||
category = -1;
|
||||
}
|
||||
|
||||
int pfx_bits = pfx.slice_bits() - 7;
|
||||
|
||||
;; pfx.slice_bits() will contain 8m, where m is number of bytes in subdomain
|
||||
;; COUNTING the zero byte (if structurally correct: no multiple-ZB keys)
|
||||
;; which corresponds to 8m, m=one plus the number of bytes in the subdomain found)
|
||||
if (category == 0) {
|
||||
return (pfx_bits, cat_table); ;; return cell with entire dictionary for 0
|
||||
} else {
|
||||
cell cat_found = cat_table.idict_get_ref(16, category);
|
||||
return (pfx_bits, cat_found);
|
||||
}
|
||||
}
|
||||
|
||||
;; getexpiration needs to know the current time to skip any possible expired
|
||||
;; subdomains in the chain. it will return 0 if not found or expired.
|
||||
int getexpirationx(slice subdomain, int nowtime) inline method_id {
|
||||
(int exp, _, _, _) = dnsdictlookup(subdomain, nowtime);
|
||||
return exp;
|
||||
}
|
||||
|
||||
int getexpiration(slice subdomain) method_id {
|
||||
return getexpirationx(subdomain, now());
|
||||
}
|
||||
|
||||
int getstdperiod() method_id {
|
||||
(int stdper, _, _, _) = load_prices();
|
||||
return stdper;
|
||||
}
|
||||
|
||||
int getppr() method_id {
|
||||
(_, int ppr, _, _) = load_prices();
|
||||
return ppr;
|
||||
}
|
||||
|
||||
int getppc() method_id {
|
||||
(_, _, int ppc, _) = load_prices();
|
||||
return ppc;
|
||||
}
|
||||
|
||||
int getppb() method_id {
|
||||
( _, _, _, int ppb) = load_prices();
|
||||
return ppb;
|
||||
}
|
||||
|
||||
int calcprice(cell val) method_id { ;; only for external gets (not efficient)
|
||||
(_, _, int ppc, int ppb) = load_prices();
|
||||
return _calcprice(val, ppc, ppb);
|
||||
}
|
||||
|
||||
int calcregprice(cell val) method_id { ;; only for external gets (not efficient)
|
||||
(_, int ppr, int ppc, int ppb) = load_prices();
|
||||
return ppr + _calcprice(val, ppc, ppb);
|
||||
}
|
|
@ -13,25 +13,7 @@
|
|||
;; Custom ASM instructions ;;
|
||||
;;===========================================================================;;
|
||||
|
||||
;; Args: s D n | Success: s' x s'' -1 | Failure: s 0 -> s N N 0
|
||||
(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key)
|
||||
asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2";
|
||||
|
||||
;; Args: x k D n | Success: D' -1 | Failure: D 0
|
||||
(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value)
|
||||
asm(value key dict key_len) "PFXDICTSET";
|
||||
|
||||
;; Args: k D n | Success: D' -1 | Failure: D 0
|
||||
(cell, int) pfxdict_delete?(cell dict, int key_len, slice key)
|
||||
asm(key dict key_len) "PFXDICTDEL";
|
||||
|
||||
slice slice_last(slice s, int len) asm "SDCUTLAST";
|
||||
|
||||
;; Actually, equivalent to dictionaries, provided for clarity
|
||||
(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) "LDOPTREF";
|
||||
builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF";
|
||||
|
||||
(cell, ()) pfxdict_set_ref(cell dict, int key_len, slice key, cell value) {
|
||||
(cell, ()) pfxdict_set_ref(cell dict, int key_len, slice key, cell value) {
|
||||
throw_unless(33, dict~pfxdict_set?(key_len, key, begin_cell().store_maybe_ref(value).end_cell().begin_parse()));
|
||||
return (dict, ());
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ _ ~credit_to(credits, addr, amount) {
|
|||
}
|
||||
;; parse current election data
|
||||
var (elect_at, elect_close, min_stake, total_stake, members, failed, finished) = elect.unpack_elect();
|
||||
elect_at~dump();
|
||||
;; elect_at~dump();
|
||||
msg_value -= 1000000000; ;; deduct GR$1 for sending confirmation
|
||||
if ((msg_value << 12) < total_stake) {
|
||||
;; stake smaller than 1/4096 of the total accumulated stakes, return
|
||||
|
@ -443,7 +443,7 @@ _ compute_total_stake(l, n, m_stake) {
|
|||
if (f) {
|
||||
var (stake, _, pubkey) = (min(key~load_uint(128), max_stake), key~load_uint(32), key.preload_uint(256));
|
||||
var (max_f, _, adnl_addr) = (cs~load_uint(32), cs~load_uint(256), cs.preload_uint(256));
|
||||
l = cons(tuple4(stake, max_f, pubkey, adnl_addr), l);
|
||||
l = cons([stake, max_f, pubkey, adnl_addr], l);
|
||||
}
|
||||
} until (~ f);
|
||||
;; l is the list of all stakes in decreasing order
|
||||
|
@ -468,7 +468,7 @@ _ compute_total_stake(l, n, m_stake) {
|
|||
}
|
||||
;; we have to select first m validators from list l
|
||||
l1 = touch(l);
|
||||
l1~dump(); ;; DEBUG
|
||||
;; l1~dump(); ;; DEBUG
|
||||
repeat (m - 1) {
|
||||
l1 = cdr(l1);
|
||||
}
|
||||
|
@ -480,7 +480,7 @@ _ compute_total_stake(l, n, m_stake) {
|
|||
var vset = new_dict();
|
||||
var frozen = new_dict();
|
||||
do {
|
||||
var (stake, max_f, pubkey, adnl_addr) = l~list_next().untuple4();
|
||||
var [stake, max_f, pubkey, adnl_addr] = l~list_next();
|
||||
;; lookup source address first
|
||||
var (val, f) = members.udict_get?(256, pubkey);
|
||||
throw_unless(61, f);
|
||||
|
@ -733,7 +733,7 @@ int announce_new_elections(ds, elect, credits) {
|
|||
(_, var min_stake) = config_param(17).begin_parse().load_grams();
|
||||
;; announce new elections
|
||||
var elect_at = t + elect_begin_before;
|
||||
elect_at~dump();
|
||||
;; elect_at~dump();
|
||||
var elect_close = elect_at - elect_end_before;
|
||||
elect = pack_elect(elect_at, elect_close, min_stake, 0, new_dict(), false, false);
|
||||
set_data(begin_cell().store_dict(elect).store_dict(credits).store_slice(ds).end_cell());
|
||||
|
@ -786,7 +786,7 @@ _ participant_list() method_id {
|
|||
do {
|
||||
(id, var fs, var f) = members.udict_get_prev?(256, id);
|
||||
if (f) {
|
||||
l = cons(pair(id, fs~load_grams()), l);
|
||||
l = cons([id, fs~load_grams()], l);
|
||||
}
|
||||
} until (~ f);
|
||||
return l;
|
||||
|
@ -806,7 +806,7 @@ _ participant_list_extended() method_id {
|
|||
if (f) {
|
||||
var (stake, time, max_factor, addr, adnl_addr) = (cs~load_grams(), cs~load_uint(32), cs~load_uint(32), cs~load_uint(256), cs~load_uint(256));
|
||||
cs.end_parse();
|
||||
l = cons(pair(id, tuple4(stake, max_factor, addr, adnl_addr)), l);
|
||||
l = cons([id, [stake, max_factor, addr, adnl_addr]], l);
|
||||
}
|
||||
} until (~ f);
|
||||
return (elect_at, elect_close, min_stake, total_stake, l, failed, finished);
|
||||
|
|
|
@ -93,8 +93,8 @@ file-base +"-dns" +contractid +".addr" load-address
|
|||
} : subdomain>s
|
||||
// ( b V -- b' )
|
||||
{ dup first
|
||||
dup `smc eq? { drop untriple rot nip rot x{9fd3} s, -rot Addr, 0 8 u, } {
|
||||
dup `next eq? { drop untriple rot nip rot x{ba93} s, -rot Addr, 0 8 u, } {
|
||||
dup `smc eq? { drop untriple 2swap drop x{9fd3} s, -rot Addr, 0 8 u, } {
|
||||
dup `next eq? { drop untriple 2swap drop x{ba93} s, -rot Addr, 0 8 u, } {
|
||||
dup `adnl eq? { drop second swap x{ad01} s, swap 256 u, } {
|
||||
dup `text eq? { drop second swap x{1eda01} s, over $len 8 u, swap $, } {
|
||||
abort"unknown value type"
|
||||
|
|
|
@ -69,5 +69,5 @@ int get_public_key() method_id {
|
|||
}
|
||||
|
||||
int balance() method_id {
|
||||
return restricted?() ? 0 : get_balance().first();
|
||||
return restricted?() ? 0 : get_balance().pair_first();
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ int balance() method_id {
|
|||
var rdict = ds~load_dict();
|
||||
ds.end_parse();
|
||||
var ts = days_passed();
|
||||
var balance = get_balance().first();
|
||||
var balance = get_balance().pair_first();
|
||||
var (_, value, found) = rdict.idict_get_preveq?(16, ts);
|
||||
if (found) {
|
||||
balance = max(balance - value~load_grams(), 0);
|
||||
|
|
|
@ -6,21 +6,26 @@ 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";
|
||||
forall X, Y -> tuple pair(X x, Y y) asm "PAIR";
|
||||
forall X, Y -> (X, Y) unpair(tuple t) asm "UNPAIR";
|
||||
forall X, Y, Z -> tuple triple(X x, Y y, Z z) asm "TRIPLE";
|
||||
forall X, Y, Z -> (X, Y, Z) untriple(tuple t) asm "UNTRIPLE";
|
||||
forall X, Y, Z, W -> tuple tuple4(X x, Y y, Z z, W w) asm "4 TUPLE";
|
||||
forall X, Y, Z, W -> (X, Y, Z, W) untuple4(tuple t) asm "4 UNTUPLE";
|
||||
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";
|
||||
|
||||
int now() asm "NOW";
|
||||
slice my_address() asm "MYADDR";
|
||||
tuple get_balance() asm "BALANCE";
|
||||
[int, cell] get_balance() asm "BALANCE";
|
||||
int cur_lt() asm "LTIME";
|
||||
int block_lt() asm "BLOCKLT";
|
||||
|
||||
|
@ -47,6 +52,7 @@ 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";
|
||||
|
@ -67,10 +73,16 @@ 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 slice_refs(slice s) asm "SREFS";
|
||||
int slice_bits(slice s) asm "SBITS";
|
||||
(int, int) slice_bits_refs(slice s) asm "SBITREFS";
|
||||
|
@ -78,6 +90,9 @@ int slice_empty?(slice s) asm "SEMPTY";
|
|||
int slice_data_empty?(slice s) asm "SDEMPTY";
|
||||
int slice_refs_empty?(slice s) asm "SREMPTY";
|
||||
|
||||
int builder_refs(builder b) asm "BREFS";
|
||||
int builder_bits(builder b) asm "BBITS";
|
||||
|
||||
builder begin_cell() asm "NEWC";
|
||||
cell end_cell(builder b) asm "ENDC";
|
||||
builder store_ref(builder b, cell c) asm(c b) "STREF";
|
||||
|
@ -159,11 +174,15 @@ cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(va
|
|||
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(slice currencies, int mode) impure asm "RAWRESERVEX";
|
||||
() 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";
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue