diff --git a/crypto/smartcont/auto-dns.fif b/crypto/smartcont/auto-dns.fif index 6ef2ef0e..21420d1e 100644 --- a/crypto/smartcont/auto-dns.fif +++ b/crypto/smartcont/auto-dns.fif @@ -43,12 +43,12 @@ $# 4 > need-params <> abort"extra parameters, or no parameters for chosen main o variable Values dictnew Values ! // ( i c -- ) { over 0= abort"category cannot be zero" - idict!+ not abort"duplicate category id" + udict!+ not abort"duplicate category id" Values ! } : register-value { @end? abort"category number expected" @next (number) 1 <> abort"category must be integer" - dup 16 fits not abort"category does not fit into 16 bit integer" + dup 256 fits not abort"category does not fit into 256 bit integer" dup 0= abort"category must be non-zero" } : parse-cat-num { @end? abort"smart contract address expected" diff --git a/crypto/smartcont/dns-auto-code.fc b/crypto/smartcont/dns-auto-code.fc index e548a70a..949f1571 100644 --- a/crypto/smartcont/dns-auto-code.fc +++ b/crypto/smartcont/dns-auto-code.fc @@ -7,8 +7,15 @@ | Author: Oleksandr Murzin (tg: @skydev / em: alexhacker64@gmail.com) | | October 2019 | \------------------------------------------------------------------------/ + Updated to actual DNS standard version by starlightduck in 2022 -} +;;===========================================================================;; +;; Custom ASM instructions ;; +;;===========================================================================;; + +cell udict_get_ref_(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETOPTREF"; + ;;===========================================================================;; ;; Utility functions ;; ;;===========================================================================;; @@ -19,7 +26,7 @@ [OptRef<1b+1r?>:Hashmap(Time|Hash128)->Slice(DomName)>:gc] [UInt<32b>:stdperiod] [Gram:PPReg] [Gram:PPCell] [Gram:PPBit] [UInt<32b>:lasthousekeeping] - := HashmapE 16 ^DNSRecord + := HashmapE 256 (~~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 @@ -189,6 +196,7 @@ int check_owner(cell cat_table, cell owner_info, int src_wc, int src_addr, int s store_data(ctl, domdata, gc, [stdper, ppr, ppc, ppb], nhk, lhk); return send_ok(0); } + var (addr, query_id, op) = query_info; if (op == 0x4344656c) { ;; CDel = destroy smart contract ifnot (domdata.null?()) { ;; domain dictionary not empty, force gc @@ -199,9 +207,12 @@ int check_owner(cell cat_table, cell owner_info, int src_wc, int src_addr, int s ;; domain dictionary still not empty, error return send_error(0xee74656d); } - var (addr, query_id, op) = query_info; return send_message(addr, 0xef6b6179, query_id, op, 0, 128 + 32); } + if (op == 0x54616b65) { ;; Take = take grams from the contract + var amount = in_msg~load_grams(); + return send_message(addr, 0xef6b6179, query_id, op, amount, 64); + } return send_error(0xffffffff); } @@ -289,7 +300,8 @@ int check_owner(cell cat_table, cell owner_info, int src_wc, int src_addr, int s if (exp >= n) { ;; entry not expired cell cat_table = val~load_ref(); val.end_parse(); - var (cown, ok) = cat_table.idict_get_ref?(16, -2); + ;; update: category length now u256 instead of i16, owner index is now 0 instead of -2 + var (cown, ok) = cat_table.udict_get_ref?(256, 0); if (ok) { owner_info = cown; } @@ -318,14 +330,15 @@ int check_owner(cell cat_table, cell owner_info, int src_wc, int src_addr, int s data = in_msg~load_ref(); ;; basic integrity check of (client-provided) dictionary ifnot (data.dict_empty?()) { ;; 1000 gas! - var (oinfo, ok) = data.idict_get_ref?(16, -2); + ;; update: category length now u256 instead of i16, owner index is now 0 instead of -2 + var (oinfo, ok) = data.udict_get_ref?(256, 0); if (ok) { var cs = oinfo.begin_parse(); throw_unless(31, cs.slice_bits() >= 16 + 3 + 8 + 256); throw_unless(31, cs.preload_uint(19) == 0x9fd3 * 8 + 4); } - (_, _, int minok) = data.idict_get_min?(16); - (_, _, int maxok) = data.idict_get_max?(16); + (_, _, int minok) = data.udict_get_min?(256); ;; update: category length now u256 instead of i16 + (_, _, int maxok) = data.udict_get_max?(256); ;; update: category length now u256 instead of i16 throw_unless(31, minok & maxok); } } else { @@ -410,7 +423,8 @@ int check_owner(cell cat_table, cell owner_info, int src_wc, int src_addr, int s (int bits, int refs) = domain.slice_bits_refs(); throw_if(30, refs | (bits & 7)); ;; malformed input (~ 8n-bit) ifnot (bits) { - return (0, null(), 0, null()); ;; zero-length input + ;; return (0, null(), 0, null()); ;; zero-length input + throw(30); ;; update: throw exception for empty input } int domain_last_byte = domain.slice_last(8).preload_uint(8); @@ -420,7 +434,14 @@ int check_owner(cell cat_table, cell owner_info, int src_wc, int src_addr, int s bits += 8; } if (bits == 8) { - return (0, null(), 0, null()); ;; zero-length input, but with zero byte + return (0, null(), 8, null()); ;; zero-length input, but with zero byte + ;; update: return 8 as resolved, but with no data + } + int domain_first_byte = domain.preload_uint(8); + if (domain_first_byte == 0) { + ;; update: remove prefix \0 + domain~load_uint(8); + bits -= 8; } var ds = get_data().begin_parse(); (_, cell root) = (ds~load_ref(), ds~load_dict()); @@ -453,10 +474,11 @@ int check_owner(cell cat_table, cell owner_info, int src_wc, int src_addr, int s (int, cell) dnsresolve(slice domain, int category) method_id { (int exp, cell cat_table, int exact?, slice pfx) = dnsdictlookup(domain, now()); ifnot (exp) { - return (0, null()); + return (exact?, null()); ;; update: reuse exact? to return 8 for \0 } ifnot (exact?) { ;; incomplete subdomain found, must return next resolver (-1) - category = -1; + category = "dns_next_resolver"H; ;; 0x19f02441ee588fdb26ee24b2568dd035c3c9206e11ab979be62e55558a1d17ff + ;; update: next resolver is now sha256("dns_next_resolver") instead of -1 } int pfx_bits = pfx.slice_bits(); @@ -467,7 +489,7 @@ int check_owner(cell cat_table, cell owner_info, int src_wc, int src_addr, int s ifnot (category) { return (pfx_bits, cat_table); ;; return cell with entire dictionary for 0 } else { - cell cat_found = cat_table.idict_get_ref(16, category); + cell cat_found = cat_table.udict_get_ref_(256, category); ;; update: category length now u256 instead of i16 return (pfx_bits, cat_found); } } diff --git a/crypto/smartcont/dns-manual-code.fc b/crypto/smartcont/dns-manual-code.fc index 890d5d86..555e5952 100644 --- a/crypto/smartcont/dns-manual-code.fc +++ b/crypto/smartcont/dns-manual-code.fc @@ -7,12 +7,15 @@ | Author: Oleksandr Murzin (tg: @skydev / em: alexhacker64@gmail.com) | | October 2019 | \------------------------------------------------------------------------/ + Updated to actual DNS standard version by starlightduck in 2022 -} ;;===========================================================================;; ;; Custom ASM instructions ;; ;;===========================================================================;; +cell udict_get_ref_(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETOPTREF"; + (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, ()); @@ -67,9 +70,9 @@ Operations (continuation of message): 00 Contract initialization message (only if seqno = 0) (x=-) 11 VSet: set specified value to specified subdomain->category (x=2) - [Int<16b>:category] [Name:subdomain] [Cell<1r>:value] + [UInt<256b>:category] [Name:subdomain] [Cell<1r>:value] 12 VDel: delete specified subdomain->category (x=2) - [Int<16b>:category] [Name:subdomain] + [UInt<256b>:category] [Name:subdomain] 21 DSet: replace entire category dictionary of domain with provided (x=0) [Name:subdomain] [Cell<1r>:new_cat_table] 22 DDel: delete entire category dictionary of specified domain (x=0) @@ -112,7 +115,7 @@ int cat = 0; if (op < 20) { ;; for operations with codes 10..19 category is required - cat = ops~load_int(16); + cat = ops~load_uint(256); ;; update: category length now u256 instead of i16 } slice name = null(); ;; any slice value cell cat_table = null(); @@ -159,13 +162,13 @@ ;; 11 VSet: set specified value to specified subdomain->category if (op == 11) { cell new_value = ops~load_maybe_ref(); - cat_table~idict_set_get_ref(16, cat, new_value); + cat_table~udict_set_get_ref(256, cat, new_value); ;; update: category length now u256 instead of i16 root~pfxdict_set_ref(1023, name, cat_table); return (root, ops); } ;; 12 VDel: delete specified subdomain->category value if (op == 12) { - if (cat_table~idict_delete?(16, cat)) { + if (cat_table~udict_delete?(256, cat)) { ;; update: category length now u256 instead of i16 root~pfxdict_set_ref(1023, name, cat_table); } return (root, ops); @@ -261,7 +264,7 @@ cell process_ops(cell root, slice ops) inline_ref { Data structure: Root cell: [UInt<32b>:seqno] [UInt<256b>:owner_public_key] [OptRef<1b+1r?>:HashmapCatTable>:domains] - := HashmapE 16 ^DNSRecord + := HashmapE 256 (~~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 @@ -291,7 +294,8 @@ int get_public_key() method_id { (int, cell) dnsresolve(slice subdomain, int category) method_id { int bits = subdomain.slice_bits(); ifnot (bits) { - return (0, null()); ;; zero-length input + ;; return (0, null()); ;; zero-length input + throw(30); ;; update: throw exception for empty input } throw_if(30, bits & 7); ;; malformed input (~ 8n-bit) @@ -302,7 +306,14 @@ int get_public_key() method_id { bits += 8; } if (bits == 8) { - return (0, null()); ;; zero-length input, but with zero byte + return (8, null()); ;; zero-length input, but with zero byte + ;; update: return 8 as resolved, but with no data + } + int name_first_byte = subdomain.preload_uint(8); + if (name_first_byte == 0) { + ;; update: remove prefix \0 + subdomain~load_uint(8); + bits -= 8; } (_, _, _, cell root, _) = load_data(); @@ -332,7 +343,9 @@ int get_public_key() method_id { zeros = - zeros; ifnot (tail.slice_empty?()) { ;; if we have tail then len(pfx) < len(subdomain) - category = -1; ;; incomplete subdomain found, must return next resolver (-1) + ;; incomplete subdomain found, must return next resolver + category = "dns_next_resolver"H; ;; 0x19f02441ee588fdb26ee24b2568dd035c3c9206e11ab979be62e55558a1d17ff + ;; update: next resolver is now sha256("dns_next_resolver") instead of -1 } int pfx_bits = pfx.slice_bits() - 7; cell cat_table = val; @@ -342,7 +355,7 @@ int get_public_key() method_id { 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); + cell cat_found = cat_table.udict_get_ref_(256, category); ;; update: category length now u256 instead of i16 return (pfx_bits, cat_found); } } diff --git a/crypto/smartcont/manual-dns-manage.fif b/crypto/smartcont/manual-dns-manage.fif index ef18127c..98559da9 100644 --- a/crypto/smartcont/manual-dns-manage.fif +++ b/crypto/smartcont/manual-dns-manage.fif @@ -42,7 +42,7 @@ variable Actions { @end? abort"subdomain name expected" @next dup $len 127 > abort"subdomain name too long" } : parse-domain { @end? abort"category number expected" @next (number) 1 <> abort"category must be integer" - dup 16 fits not abort"category does not fit into 16 bit integer" + dup 256 fits not abort"category does not fit into 256 bit integer" dup 0= abort"category must be non-zero" } : parse-cat-num { @end? abort"`cat` expected" @next "cat" $= not abort"`cat` expected" parse-cat-num @@ -107,11 +107,11 @@ file-base +"-dns" +contractid +".addr" load-address { dup first dup `add eq? { drop 4 untuple -rot -