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

rldp-http-proxy: use tonlib

- rldp-http-proxy used TONLib to resolve domains via DNS smartcontract
- updated tonlib
- bugfixes
This commit is contained in:
ton 2020-02-12 00:14:16 +04:00
parent 1de39f5d7c
commit 493ae2410c
34 changed files with 816 additions and 153 deletions

View file

@ -1082,6 +1082,7 @@ variable @proclist
variable @procdict
variable @procinfo
variable @gvarcnt
variable asm-mode 1 asm-mode !
19 constant @procdictkeylen
32 constant @zcount
{ pair @proclist @ cons @proclist ! } : @proclistadd
@ -1144,8 +1145,18 @@ variable @gvarcnt
{ ."Procedure `" over type ."` index=" 2 pick . ." flags=0x" dup x. cr } : @showprocinfo
// ( proc_name proc_idx f -- ) f:+1=declared, +2=defined, +4=inlined, +8=called, +16=method
{ // @showprocinfo
dup 0x1a and 2 = { 2 pick @remove-proc // over ."Removing " type cr
dup 0x1a and 2 = asm-mode @ 3 and and ?dup {
2 and {
over ."Warning: removing (inlined) procedure `" type ."` from call dictionary" cr
} if
2 pick @remove-proc
} if // remove unused procs
dup 0xc and 0xc = asm-mode @ 4 and and {
over ."Warning: inline procedure `" type ."` is not always inlined" cr
} if
dup 0x1e and 2 = asm-mode @ 8 and and {
over ."Warning: procedure `" type ."` defined but not used" cr
} if
drop 2drop
} : @chkprocdef
{ @chkmaindef
@ -1170,6 +1181,14 @@ forget @proclist forget @proccnt
-3 constant split_prepare
-4 constant split_install
{ asm-mode 0 3 ~! } : asm-no-remove-unused
{ asm-mode 1 1 ~! } : asm-remove-unused // enabled by default
{ asm-mode 3 3 ~! } : asm-warn-remove-unused
{ asm-mode 4 4 ~! } : asm-warn-inline-mix
{ asm-mode 0 4 ~! } : asm-no-warn-inline-mix // disabled by default
{ asm-mode 8 8 ~! } : asm-warn-unused
{ asm-mode 0 8 ~! } : asm-no-warn-unused // disabled by default
// ( c -- ) add vm library for later use with runvmcode
{ <b over ref, b> <s swap hash vmlibs @ 256 udict! not abort"cannot add library" vmlibs ! } : add-lib
// ( x -- c ) make library reference cell

View file

@ -79,12 +79,15 @@ variable base
{ char ) word "$" swap $+ 1 { find 0= abort"undefined parameter" execute } } ::_ $(
// b s -- ?
{ sbitrefs rot brembitrefs rot >= -rot <= and } : s-fits?
// b s x -- ?
{ swap sbitrefs -rot + rot brembitrefs -rot <= -rot <= and } : s-fits-with?
{ 0 swap ! } : 0!
{ tuck @ + swap ! } : +!
{ tuck @ swap - swap ! } : -!
{ 1 swap +! } : 1+!
{ -1 swap +! } : 1-!
{ null swap ! } : null!
{ not 2 pick @ and xor swap ! } : ~!
0 tuple constant nil
{ 1 tuple } : single
{ 2 tuple } : pair

View file

@ -69,6 +69,9 @@ library TonUtil // TON Blockchain Fift Library
// ( b wc addr -- b' ) Serializes address into Builder b
{ -rot 8 i, swap 256 u, } : addr,
{ over 8 fits { rot b{100} s, -rot addr, } {
rot b{110} s, 256 9 u, rot 32 i, swap 256 u, } cond
} : Addr,
// Gram utilities
1000000000 constant Gram
@ -171,3 +174,24 @@ recursive append-long-bytes {
{ dup $len 55 <> abort"not 55 alphanumeric characters" "F" swap $+ Base32>B
33 B| 16 B>u@ over crc16 <> abort"crc16 checksum mismatch"
8 B>u@+ 0x2D <> abort"not a valid adnl address" 256 B>u@ } : $>adnl
{ 65 - dup 0>= { -33 and 10 + dup 16 < } { 17 + dup 0>= over 10 < and } cond ?dup nip } : hex-digit?
// ( S -- x -1 or 0 ) Parses a hexadecimal integer
{ dup $len {
0 {
4 << swap 1 $| -rot (char) hex-digit? // S a d -1 or S a 0
{ + over $len 0= } { drop -1 true } cond
} until
dup 0< { 2drop false } { nip true } cond
} { drop false } cond
} : hex$>u?
// ( S -- x )
{ hex$>u? not abort"not a hexadecimal number" } : hex$>u
{ dup $len 64 = { hex$>u } {
dup $len 55 = { $>adnl } {
true abort"invalid adnl address"
} cond } cond
} : parse-adnl-addr
{ adnl>$ type } : .adnl
{ bl word parse-adnl-addr 1 'nop } ::_ adnl:

View file

@ -18,6 +18,7 @@
*/
#include "func.h"
#include "td/utils/crypto.h"
#include "common/refint.h"
#include <fstream>
namespace sym {
@ -1244,8 +1245,9 @@ void parse_func_def(Lexer& lex) {
}
if (val->method_id.is_null()) {
val->method_id = std::move(method_id);
} else if (val->method_id != method_id) {
lex.cur().error("integer method identifier for `"s + func_name.str + "` changed to a different value");
} else if (td::cmp(val->method_id, method_id) != 0) {
lex.cur().error("integer method identifier for `"s + func_name.str + "` changed from " +
val->method_id->to_dec_string() + " to a different value " + method_id->to_dec_string());
}
}
if (f) {

View file

@ -99,22 +99,44 @@ builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF";
[UInt<256b>:new_public_key]
-}
() after_code_upgrade(cell root, slice ops, cont old_code) impure method_id(1666);
(cell, slice) process_op(cell root, slice ops) inline_ref {
int op = ops~load_uint(6);
int is_name_ref = (ops~load_uint(1) == 1);
;; lets assume at this point that special operations 00..09 are handled
throw_if(45, op < 10);
slice name = ops; ;; anything! better do not begin or it costs much gas
cell cat_table = null();
if (op < 10) {
ifnot (op) {
;; 00 Noop: No operation
return (root, ops);
}
if (op == 1) {
;; 01 SMsg: Send Message
var mode = ops~load_uint(8);
send_raw_message(ops~load_ref(), mode);
return (root, ops);
}
if (op == 9) {
;; 09 CodeUpgrade
var new_code = ops~load_ref();
set_code(new_code);
var old_code = get_c3();
set_c3(new_code.begin_parse().bless());
after_code_upgrade(root, ops, old_code);
throw(0);
return (root, ops);
}
throw(45);
return (root, ops);
}
int cat = 0;
if (op < 20) {
;; for operations with codes 10..19 category is required
cat = ops~load_int(16);
}
int zeros = 0;
slice name = null(); ;; any slice value
cell cat_table = null();
if (op < 30) {
;; for operations with codes 10..29 name is required
int is_name_ref = (ops~load_uint(1) == 1);
if (is_name_ref) {
;; name is stored in separate referenced cell
name = ops~load_ref().begin_parse();
@ -129,17 +151,18 @@ builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF";
int name_last_byte = name.slice_last(8).preload_uint(8);
throw_if(40, name_last_byte);
;; count zero separators
int zeros = 0;
slice cname = name;
repeat (cname.slice_bits() ^>> 3) {
int c = cname~load_uint(8);
zeros -= (c == 0);
}
;; throw_unless(39, zeros == 1);
name = begin_cell().store_uint(zeros, 7).store_slice(name).end_cell().begin_parse();
}
;; operation with codes 10..19 manipulate category dict
;; lets try to find it and store into a variable
;; operations with codes 20..29 replace / delete dict, no need
name = begin_cell().store_uint(zeros, 7).store_slice(name).end_cell().begin_parse();
if (op < 20) {
;; lets resolve the name here so as not to duplicate the code
(slice pfx, cell val, slice tail, int succ) =
@ -187,17 +210,21 @@ builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF";
return (null(), ops);
}
throw(44); ;; invalid operation
return (root, ops);
return (null(), ops);
}
cell process_ops(cell root, slice ops) inline_ref {
var stop = false;
root~touch();
ops~touch();
do {
(root, ops) = process_op(root, ops);
if (ops.slice_refs_empty?()) {
stop = true;
} else {
ops = ops~load_ref().begin_parse();
if (ops.slice_data_empty?()) {
if (ops.slice_refs()) {
ops = ops~load_ref().begin_parse();
} else {
stop = true;
}
}
} until (stop);
return root;
@ -205,24 +232,25 @@ cell process_ops(cell root, slice ops) inline_ref {
() recv_external(slice in_msg) impure {
;; Load data
(int stored_subwalet, int last_cleaned, int public_key, cell root, cell old_queries) = load_data();
(int contract_id, int last_cleaned, int public_key, cell root, cell old_queries) = load_data();
;; validate signature and seqno
slice signature = in_msg~load_bits(512);
int shash = slice_hash(in_msg);
var (contract_id, query_id) = (in_msg~load_uint(32), in_msg~load_uint(64));
var (query_contract, query_id) = (in_msg~load_uint(32), in_msg~load_uint(64));
var bound = (now() << 32);
throw_if(35, query_id < bound);
(_, var found?) = old_queries.udict_get?(64, query_id);
throw_if(32, found?);
throw_unless(34, check_signature(shash, signature, public_key));
throw_unless(34, contract_id == query_contract);
throw_unless(35, check_signature(shash, signature, public_key));
accept_message(); ;; message is signed by owner, sanity not guaranteed yet
int op = in_msg.preload_uint(6);
if (op == 51) {
in_msg~skip_bits(6);
public_key = in_msg~load_uint(256);
} elseif (op) { ;; 00 Contract initialization message
} else {
root = process_ops(root, in_msg);
}
@ -244,6 +272,9 @@ cell process_ops(cell root, slice ops) inline_ref {
store_data(contract_id, last_cleaned, public_key, root, old_queries);
}
() after_code_upgrade(cell root, slice ops, cont old_code) impure method_id(1666) {
}
{-
Data structure:
Root cell: [UInt<32b>:seqno] [UInt<256b>:owner_public_key]
@ -268,6 +299,12 @@ int get_contract_id() method_id {
return get_data().begin_parse().preload_uint(32);
}
int get_public_key() method_id {
var cs = get_data().begin_parse();
cs~load_uint(32 + 64);
return cs.preload_uint(256);
}
;;8m dns-record-value
(int, cell) dnsresolve(slice subdomain, int category) method_id {
int bits = subdomain.slice_bits();

View file

@ -50,7 +50,7 @@ variable order# order# 0!
orders ! order# 1+!
} : add-order
// b body -- b'
{ tuck <s 2dup s-fits? not rot over 1 i, -rot
{ tuck <s 2dup 1 s-fits-with? not rot over 1 i, -rot
{ drop swap ref, } { s, nip } cond
} : append-msg-body
// ng wc addr bounce body -- c

View file

@ -51,7 +51,7 @@ variable order# order# 0!
orders ! order# 1+!
} : add-order
// b body -- b'
{ tuck <s 2dup s-fits? not rot over 1 i, -rot
{ tuck <s 2dup 1 s-fits-with? not rot over 1 i, -rot
{ drop swap ref, } { s, nip } cond
} : append-msg-body
// ng wc addr bounce body -- c

View file

@ -0,0 +1,146 @@
#!/usr/bin/fift -s
"TonUtil.fif" include
"GetOpt.fif" include
{ show-options-help 1 halt } : usage
60 =: timeout // external message expires in 60 seconds
"dns-query.boc" =: savefile
begin-options
" <filename-base> <contract-id> [-t<timeout>] [-o<savefile-boc>] <op> [<op2>...]" +cr +tab
+"Creates a request to managed DNS smart contract created by new-manual-dns.fif, with private key loaded from file <filename-base>.pk "
+"and address from <filename-base>-dns<contract-id>.addr, and saves it into <savefile-boc> ('" savefile $+ +"' by default)"
+cr +"<op> is an operation description, one of" +cr +tab
+"add <subdomain> cat <cat-id> (smc <smc-addr> | next <next-resolver-smc-addr> | adnl <adnl-addr> | text <string>)" +cr +tab
+"delete <subdomain> cat <cat-id>" +cr +tab
+"drop <subdomain>"
disable-digit-options generic-help-setopt
"t" "--timeout" { parse-int =: timeout } short-long-option-arg
"Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help
"o" "--output" { =: savefile } short-long-option-arg
"Sets output file for generated initialization message ('" savefile $+ +"' by default)" option-help
"h" "--help" { usage } short-long-option
"Shows a help message" option-help
parse-options
$# 2 < ' usage if
2 :$1..n
$1 =: file-base
$2 parse-int dup =: contract-id 32 fits ' usage ifnot
{ contract-id (.) $+ } : +contractid
{ $* @ dup null? { second $@ ! } { drop } cond } : @skip
{ $* @ null? } : @end?
{ $* @ uncons $* ! } : @next
@next @next 2drop
variable Actions
{ Actions @ cons Actions ! } : register-action
{ @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 0= abort"category must be non-zero"
} : parse-cat-num
{ @end? abort"`cat` expected" @next "cat" $= not abort"`cat` expected" parse-cat-num
} : parse-cat
{ @end? abort"smart contract address expected"
@next false parse-load-address drop triple
} : cl-parse-smc-addr
{ @end? abort"adnl address expected"
`adnl @next parse-adnl-addr pair
} : cl-parse-adnl-addr
{ @end? abort"subdomain record value expected" @next
dup "smc" $= { drop `smc cl-parse-smc-addr } {
dup "next" $= { drop `next cl-parse-smc-addr } {
dup "adnl" $= { drop cl-parse-adnl-addr } {
dup "text" $= { drop `text @next pair } {
"unknown record type "' swap $+ +"'" abort
} cond } cond } cond } cond
} : parse-value
{ ."Loading new code BoC from " dup type cr
file>B B>boc
} : load-new-code-from
{ @next dup "add" $= { drop `add parse-domain parse-cat parse-value 4 tuple register-action } {
dup "delete" $= { drop `delete parse-domain parse-cat triple register-action } {
dup "drop" $= { drop `drop parse-domain pair register-action } {
dup "upgrade" $= { drop `upgrade @next load-new-code-from pair register-action } {
"unknown action '" swap $+ +"'" abort
} cond } cond } cond } cond
} : parse-action
{ { @end? not } { parse-action } while } : parse-actions
parse-actions
file-base +".pk" load-keypair nip constant wallet_pk
file-base +"-dns" +contractid +".addr" load-address
2dup 2constant smc_addr
."Managed manual DNS smart contract address = " 2dup .addr cr 6 .Addr cr
."Actions: " Actions @ list-reverse .l cr
// ( S -- S1 .. Sn n )
{ 1 swap { dup "." $pos dup 0>= } { $| 1 $| nip rot 1+ swap } while drop swap
} : split-by-dots
// ( S -- s )
{ dup $len dup 0= abort"subdomain cannot be empty" 126 > abort"subdomain too long"
dup 0 chr $pos 1+ abort"subdomain contains null characters"
split-by-dots <b { // ... S b
swap dup $len 0= abort"empty subdomain component" $, 0 8 u,
} rot times b> <s
} : 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 `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"
} cond } cond } cond } cond
} : value,
{ subdomain>s dup sbits 3 >>
dup 63 > { drop s>c dict, } { rot swap 7 u, swap s, } cond
} : subdomain,
// ( A -- b )
{ dup first
dup `add eq? {
drop 4 untuple <b swap value, b> -rot
<b 11 6 u, swap 16 i, swap subdomain,
swap dict, nip } {
dup `delete eq? {
drop untriple rot drop
<b 12 6 u, swap 16 i, swap subdomain, } {
dup `drop eq? {
drop second <b 22 6 u, swap subdomain, } {
dup `upgrade eq? {
drop second <b 9 6 u, swap ref, } {
abort"unknown action type"
} cond } cond } cond } cond
} : action>b
// ( -- b )
{ Actions @ dup null? { drop <b 0 6 u, b> } {
uncons swap action>b { over null? not } {
b> swap uncons swap action>b rot ref,
} while nip } cond
} : serialize-actions
serialize-actions
dup brembits 888 < { b> <b 0 6 u, swap ref, } if
dup =: actions-builder b>
."Serialized actions are " <s csr. cr
// create a message
// create external message
now timeout + 32 << actions-builder b> hashu 32 1<<1- and + =: query_id
<b contract-id 32 i, query_id 64 u, actions-builder b+ b>
dup ."signing message: " <s csr. cr
dup hashu wallet_pk ed25519_sign_uint
<b b{1000100} s, smc_addr addr, 0 Gram, b{00} s,
swap B, swap <s s, b>
dup ."resulting external message: " <s csr. cr
2 boc+>B dup Bx. cr
."Query_id is " query_id dup . ."= 0x" X. cr
."Query expires in " timeout . ."seconds" cr
savefile tuck B>file
."(Saved to file " type .")" cr

View file

@ -0,0 +1,63 @@
#!/usr/bin/fift -s
"TonUtil.fif" include
"Asm.fif" include
"GetOpt.fif" include
{ show-options-help 1 halt } : usage
Basechain =: wc // create smart contract in basechain
65536 =: timeout
"new-dns-query.boc" =: savefile
variable dns-dict dictnew dns-dict !
begin-options
" <filename-base> <contract-id> [-w<workchain>] [-t<timeout>] [-o<savefile-boc>]" +cr +tab
+"Creates a new manual dns smart contract with 32-bit identifier <contract-id> managed by private key <filename-base>.pk, "
+"and saves it into <savefile-boc> ('" savefile $+ +"' by default)"
disable-digit-options generic-help-setopt
"w" "--workchain" { parse-workchain-id =: wc } short-long-option-arg
"Selects workchain to create smart contract (" wc (.) $+ +" by default)" option-help
"t" "--timeout" { parse-int =: timeout } short-long-option-arg
"Sets expiration timeout for the initialization message in seconds (" timeout (.) $+ +" by default)" option-help
"o" "--output" { =: savefile } short-long-option-arg
"Sets output file for generated initialization message ('" savefile $+ +"' by default)" option-help
"h" "--help" { usage } short-long-option
"Shows a help message" option-help
parse-options
$# 2 <> ' usage if
2 :$1..n
$1 =: file-base
$2 parse-int dup =: contract-id
32 fits ' usage ifnot
{ contract-id (.) $+ } : +contractid
."Creating new manual DNS smart contract in workchain " wc .
."with contract id " contract-id . cr
// Create new manual DNS; source code included from `auto/dns-manual-code.fif`
"auto/dns-manual-code.fif" include
// code
<b contract-id 32 i, 0 64 u,
file-base +".pk" load-generate-keypair
constant wallet_pk
B, dns-dict @ dict, false 1 i,
b> // data
null // no libraries
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
dup ."StateInit: " <s csr. cr
dup hashu wc swap 2dup 2constant wallet_addr
."new manual DNS smartcontract address = " 2dup .addr cr
2dup file-base +"-dns" +contractid +".addr" save-address-verbose
."Non-bounceable address (for init): " 2dup 7 .Addr cr
."Bounceable address (for later access): " 6 .Addr cr
now timeout + 32 << 1- dup =: query_id
."Init query_id is " dup . ."(0x" X._ .")" cr
<b contract-id 32 i, query_id 64 u, 0 6 u, b>
dup ."signing message: " <s csr. cr
dup hashu wallet_pk ed25519_sign_uint rot
<b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
dup ."External message for initialization is " <s csr. cr
2 boc+>B dup Bx. cr
savefile tuck B>file
."(Saved dns smart-contract creating query to file " type .")" cr

View file

@ -140,6 +140,14 @@ cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(va
(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";

View file

@ -55,8 +55,8 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr
."Body of transfer message is " body-cell <s csr. cr
// create a message
<b b{01} s, bounce 1 i, b{000100} s, dest_addr addr, amount Gram, 0 9 64 32 + + 1+ u,
body-cell <s 2dup s-fits? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram, 0 9 64 32 + + 1+ u,
body-cell <s 2dup 1 s-fits-with? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
b>
<b seqno 32 u, now timeout + 32 u, send-mode 8 u, swap ref, b>
dup ."signing message: " <s csr. cr

View file

@ -58,8 +58,8 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr
."Body of transfer message is " body-cell <s csr. cr
// create a message
<b b{01} s, bounce 1 i, b{000100} s, dest_addr addr, amount Gram, 0 9 64 32 + + 1+ u,
body-cell <s 2dup s-fits? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram, 0 9 64 32 + + 1+ u,
body-cell <s 2dup 1 s-fits-with? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
b>
<b subwallet_id 32 u, now timeout + 32 u, seqno 32 u, send-mode 8 u, swap ref, b>
dup ."signing message: " <s csr. cr

View file

@ -54,8 +54,8 @@ dest_addr 2dup bounce 7 + .Addr ." = " .addr
."Body of transfer message is " body-cell <s csr. cr
// create a message
<b b{01} s, bounce 1 i, b{000100} s, dest_addr addr, amount Gram, 0 9 64 32 + + 1+ u,
body-cell <s 2dup s-fits? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
<b b{01} s, bounce 1 i, b{000} s, dest_addr Addr, amount Gram, 0 9 64 32 + + 1+ u,
body-cell <s 2dup 1 s-fits-with? not rot over 1 i, -rot { drop body-cell ref, } { s, } cond
b>
<b seqno 32 u, send-mode 8 u, swap ref, b>
dup ."signing message: " <s csr. cr

View file

@ -202,13 +202,13 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_set_value_unsigned(td::int16 cat
vm::CellBuilder cb;
cb.store_long(11, 6);
if (name.size() <= 58 - 2) {
cb.store_long(0, 1);
cb.store_long(category, 16);
cb.store_long(0, 1);
cb.store_long(name.size(), 6);
cb.store_bytes(name);
} else {
cb.store_long(1, 1);
cb.store_long(category, 16);
cb.store_long(1, 1);
cb.store_ref(vm::CellBuilder().store_bytes(name).finalize());
}
cb.store_maybe_ref(std::move(data));
@ -220,16 +220,15 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_delete_value_unsigned(td::int16
vm::CellBuilder cb;
cb.store_long(12, 6);
if (name.size() <= 58 - 2) {
cb.store_long(0, 1);
cb.store_long(category, 16);
cb.store_long(0, 1);
cb.store_long(name.size(), 6);
cb.store_bytes(name);
} else {
cb.store_long(1, 1);
cb.store_long(category, 16);
cb.store_long(1, 1);
cb.store_ref(vm::CellBuilder().store_bytes(name).finalize());
}
cb.store_long(0, 1);
return cb.finalize();
}
@ -237,7 +236,6 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_delete_all_unsigned() const {
// 32 TDel: nullify ENTIRE DOMAIN TABLE (x=-)
vm::CellBuilder cb;
cb.store_long(32, 6);
cb.store_long(0, 1);
return cb.finalize();
}
@ -269,7 +267,6 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_set_all_unsigned(td::Span<Action
vm::CellBuilder cb;
cb.store_long(31, 6);
cb.store_long(1, 1);
cb.store_maybe_ref(pdict.get_root_cell());
@ -291,7 +288,6 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_delete_name_unsigned(td::Slice n
cb.store_long(1, 1);
cb.store_ref(vm::CellBuilder().store_bytes(name).finalize());
}
cb.store_long(0, 1);
return cb.finalize();
}
td::Result<td::Ref<vm::Cell>> ManualDns::create_set_name_unsigned(td::Slice name, td::Span<Action> entries) const {
@ -344,7 +340,6 @@ td::Result<td::Ref<vm::Cell>> ManualDns::create_init_query(const td::Ed25519::Pr
td::uint32 valid_until) const {
vm::CellBuilder cb;
cb.store_long(0, 6);
cb.store_long(0, 1);
TRY_RESULT(prepared, prepare(cb.finalize(), valid_until));
return sign(private_key, std::move(prepared));

View file

@ -49,19 +49,19 @@ const auto& get_map() {
"0VEyuvKhUUS68qIE+QFUEFX5EPKj9ATR+AB/jhghgBD0eG+hb6EgmALTB9QwAfsAkTLiAbPmWwGkyMsfyx/L/"
"8ntVAAE0DAAEaCZL9qJoa4WPw==");
with_tvm_code("highload-wallet-r2",
"te6ccgEBCAEAmQABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQC88oMI1xgg0x/TH9Mf+CMTu/Jj7UTQ0x/TH9P/"
"0VEyuvKhUUS68qIE+QFUEFX5EPKj9ATR+AB/jhghgBD0eG+hb6EgmALTB9QwAfsAkTLiAbPmWwGkyMsfyx/L/"
"8ntVAAE0DACAUgGBwAXuznO1E0NM/MdcL/4ABG4yX7UTQ1wsfg=");
"te6ccgEBCAEAlwABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQC48oMI1xgg0x/TH9Mf+CMTu/Jj7UTQ0x/TH9P/"
"0VEyuvKhUUS68qIE+QFUEFX5EPKj9ATR+AB/jhYhgBD0eG+lIJgC0wfUMAH7AJEy4gGz5lsBpMjLH8sfy//"
"J7VQABNAwAgFIBgcAF7s5ztRNDTPzHXC/+AARuMl+1E0NcLH4");
with_tvm_code("highload-wallet-v2-r1",
"te6ccgEBBwEA1gABFP8A9KQT9KDyyAsBAgEgAgMCAUgEBQHu8oMI1xgg0x/TP/gjqh9TILnyY+1E0NMf0z/T//"
"QE0VNggED0Dm+hMfJgUXO68qIH+QFUEIf5EPKjAvQE0fgAf44YIYAQ9HhvoW+"
"hIJgC0wfUMAH7AJEy4gGz5luDJaHIQDSAQPRDiuYxyBLLHxPLP8v/9ADJ7VQGAATQMABBoZfl2omhpj5jpn+n/"
"mPoCaKkQQCB6BzfQmMktv8ld0fFADgggED0lm+hb6EyURCUMFMDud4gkzM2AZIyMOKz");
with_tvm_code("highload-wallet-v2-r2",
"te6ccgEBCQEA6QABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQHu8oMI1xgg0x/TP/gjqh9TILnyY+1E0NMf0z/T//"
"QE0VNggED0Dm+hMfJgUXO68qIH+QFUEIf5EPKjAvQE0fgAf44YIYAQ9HhvoW+"
"hIJgC0wfUMAH7AJEy4gGz5luDJaHIQDSAQPRDiuYxyBLLHxPLP8v/9ADJ7VQIAATQMAIBIAYHABe9nOdqJoaa+Y64X/"
"wAQb5fl2omhpj5jpn+n/mPoCaKkQQCB6BzfQmMktv8ld0fFAA4IIBA9JZvoW+hMlEQlDBTA7neIJMzNgGSMjDisw==");
"te6ccgEBCQEA5QABFP8A9KQT9LzyyAsBAgEgAgMCAUgEBQHq8oMI1xgg0x/TP/gjqh9TILnyY+1E0NMf0z/T//"
"QE0VNggED0Dm+hMfJgUXO68qIH+QFUEIf5EPKjAvQE0fgAf44WIYAQ9HhvpSCYAtMH1DAB+wCRMuIBs+"
"ZbgyWhyEA0gED0Q4rmMcgSyx8Tyz/L//QAye1UCAAE0DACASAGBwAXvZznaiaGmvmOuF/8AEG+X5dqJoaY+Y6Z/p/"
"5j6AmipEEAgegc30JjJLb/JXdHxQANCCAQPSWb6UyURCUMFMDud4gkzM2AZIyMOKz");
with_tvm_code("simple-wallet-r1",
"te6ccgEEAQEAAAAAUwAAov8AIN0gggFMl7qXMO1E0NcLH+Ck8mCBAgDXGCDXCx/tRNDTH9P/"
"0VESuvKhIvkBVBBE+RDyovgAAdMfMSDXSpbTB9QC+wDe0aTIyx/L/8ntVA==");

View file

@ -26,7 +26,7 @@
namespace vm {
bool vm_debug_enabled = true;
bool vm_debug_enabled = false;
void set_debug_enabled(bool enable_debug) {
vm_debug_enabled = enable_debug;

View file

@ -22,15 +22,15 @@ in the build directory.
In order to access existing TON Sites, you need a running instance of RLDP-HTTP Proxy on your computer. It can be invoked as follows:
rldp-http-proxy/rldp-http-proxy -p 8080 -c 3333 -C ton-global.config.json
rldp-http-proxy/rldp-http-proxy -p 8080 -c 3333 -C ton-global-lite-client.config.json
or
rldp-http-proxy/rldp-http-proxy -p 8080 -a <your_public_ip>:3333 -C ton-global.config.json
rldp-http-proxy/rldp-http-proxy -p 8080 -a <your_public_ip>:3333 -C ton-global-lite-client.config.json
where <your_public_ip> is your public IPv4 address, provided you have one on your home computer. The TON Network global configuration file `ton-global.config.json` can be downloaded at https://test.ton.org/ton-global.config.json :
where <your_public_ip> is your public IPv4 address, provided you have one on your home computer. The TON Network global configuration file `ton-global-lite-client.config.json` can be downloaded at https://test.ton.org/ton-global-lite-client.config.json :
wget https://test.ton.org/ton-global.config.json
wget https://test.ton.org/ton-global-lite-client.config.json
In the above example, 8080 is the TCP port that will be listened to at localhost for incoming HTTP queries, and 3333 is the UDP port that will be used for all outbound and inbound RLDP and ADNL activity, i.e., for connecting to the TON Sites via the TON Network.
@ -56,9 +56,15 @@ attempts to download the main page of (TON) Site `test.ton` using the proxy at `
because TON Site `test.ton` is currently set up to be a mirror of Web Site https://test.ton.org.
You can also access TON Sites by means of their ADNL addresses by using fake domain `<adnl-addr>.adnl`:
curl -x 127.0.0.1:8080 http://untzo7eat2h77xzfugxrfgfy3zbl5txomvetzke6fwr45lehvdkxauy.adnl/
currently fetches the same TON Web page.
Alternatively, you can set up `localhost:8080` as a HTTP proxy in your browser. For example, if you use Firefox, visit [Setup] -> General -> Network Settings -> Settings -> Configure Proxy Access -> Manual Proxy configuration, and type "127.0.0.1" into the field "HTTP Proxy", and "8080" into the field "Port". If you don't have Firefox yet, visit https://www.getfirefox.com first.
Once you have set up `localhost:8080` as the HTTP proxy to be used in your browser, you can simply type the required URI, such as `http://test.ton`, in the navigation bar of your browser, and interact with the TON Site in the same way as with the usual Web Sites.
Once you have set up `localhost:8080` as the HTTP proxy to be used in your browser, you can simply type the required URI, such as `http://test.ton` or `http://untzo7eat2h77xzfugxrfgfy3zbl5txomvetzke6fwr45lehvdkxauy.adnl/`, in the navigation bar of your browser, and interact with the TON Site in the same way as with the usual Web Sites.
4. Creating TON Sites
~~~~~~~~~~~~~~~~~~~~~
@ -67,12 +73,29 @@ Most people will need just to access existing TON Sites, not to create new ones.
We suppose that you know already how to set up an ordinary web site, and that you have already configured one on your server, accepting incoming HTTP connections on TCP port <your-server-ip>:80, and defining the required TON Network domain name, say, `example.ton`, as the main domain name or an alias for your web site in the configuration of your web server.
After that, you first need to generate a persistent ADNL address for your server:
mkdir keyring
util/generate-random-id -m adnlid
You see something like
45061C1D4EC44A937D0318589E13C73D151D1CEF5D3C0E53AFBCF56A6C2FE2BD vcqmha5j3ceve35ammfrhqty46rkhi455otydstv66pk2tmf7rl25f3
This is your newly-generated persistent ADNL address, in hexadecimal and user-friendly form. The corresponding private key is saved into file 45061...2DB in the current directory. Move it into the keyring directory:
mv 45061C1* keyring/
After that, you execute
rldp-http-proxy -a <your-server-ip>:3333 -L example.ton -C ton-global.config.json
rldp-http-proxy -a <your-server-ip>:3333 -L '*' -C ton-global.config.json -A <your-adnl-address>
in the background (you can try this in a terminal at first, but if you want your TON Site to run permanently, you'll have to use options `-d` and `-l <log-file>` as well).
(with <your-adnl-address> equal to 'vcqm...35f3' in this example) in the background (you can try this in a terminal at first, but if you want your TON Site to run permanently, you'll have to use options `-d` and `-l <log-file>` as well).
If all works properly, the RLDP-HTTP proxy will accept incoming HTTP queries from the TON Network via RLDP/ADNL running on UDP port 3333 (of course, you can use any other UDP port if you want to) of IPv4 address <your-server-ip> (in particular, if you are using a firewall, don't forget to allow `rldp-http-proxy` to receive and send UDP packets from this port), and it will forward these HTTP queries addressed to host `example.ton` to TCP port 80 at 127.0.0.1, i.e., to your ordinary Web server.
If all works properly, the RLDP-HTTP proxy will accept incoming HTTP queries from the TON Network via RLDP/ADNL running on UDP port 3333 (of course, you can use any other UDP port if you want to) of IPv4 address <your-server-ip> (in particular, if you are using a firewall, don't forget to allow `rldp-http-proxy` to receive and send UDP packets from this port), and it will forward these HTTP queries addressed to all hosts (if you want to forward only specific hosts, change `-L '*'` to `-L <your hostname>`) to TCP port 80 at 127.0.0.1, i.e., to your ordinary Web server.
You can visit TON Site `http://<your-adnl-address>.adnl` (`http://vcqmha5j3ceve35ammfrhqty46rkhi455otydstv66pk2tmf7rl25f3.adnl` in this example) from a browser running on a client machine as explained in Sections 2 and 3 and check whether your TON Site is actually available to the public.
If you want to, you can register a TON DNS domain, such as 'example.ton', and create a record for this domain pointing to the persistent ADNL address of your TON Site. Then the RLDP-HTTP proxies running in client mode would resolve 'http://example.ton' as pointing to your ADNL address and will access your TON Site. The process of registration of TON DNS domains is described in a separate document.
You can visit TON Site `http://example.ton` from a browser running on a client machine as explained in Sections 2 and 3 and check whether your TON Site is actually available to the public.

View file

@ -133,6 +133,7 @@ class HttpConnection : public td::actor::Actor, public td::ObserverBase {
// unsubscribe from socket updates
// nb: interface will be changed
td::actor::SchedulerContext::get()->get_poll().unsubscribe(buffered_fd_.get_poll_info().get_pollable_fd_ref());
buffered_fd_.close();
}
};

View file

@ -27,25 +27,31 @@ void HttpInboundConnection::send_client_error() {
static const auto s =
"HTTP/1.0 400 Bad Request\r\n"
"Connection: Close\r\n"
"Content-length: 0\r\n"
"\r\n";
buffered_fd_.output_buffer().append(td::Slice(s, strlen(s)));
close_after_write_ = true;
loop();
}
void HttpInboundConnection::send_server_error() {
static const auto s =
"HTTP/1.1 502 Bad Gateway\r\n"
"Connection: keep-alive\r\n"
"Content-length: 0\r\n"
"\r\n";
buffered_fd_.output_buffer().append(td::Slice(s, strlen(s)));
loop();
}
void HttpInboundConnection::send_proxy_error() {
static const auto s =
"HTTP/1.1 502 Bad Gateway\r\n"
"Connection: keep-alive\r\n"
"Content-length: 0\r\n"
"\r\n";
buffered_fd_.output_buffer().append(td::Slice(s, strlen(s)));
loop();
}
td::Status HttpInboundConnection::receive(td::ChainBufferReader &input) {

View file

@ -33,6 +33,7 @@ class HttpInboundConnection : public HttpConnection {
}
td::Status receive_eof() override {
found_eof_ = true;
if (reading_payload_) {
if (reading_payload_->payload_type() != HttpPayload::PayloadType::pt_eof) {
return td::Status::Error("unexpected EOF");
@ -42,6 +43,10 @@ class HttpInboundConnection : public HttpConnection {
return td::Status::OK();
}
} else {
if (read_next_request_) {
stop();
return td::Status::OK();
}
return td::Status::OK();
}
}
@ -54,6 +59,10 @@ class HttpInboundConnection : public HttpConnection {
writing_payload_ = nullptr;
if (!close_after_write_) {
read_next_request_ = true;
if (found_eof_) {
stop();
return;
}
}
}
void payload_read() override {

View file

@ -42,6 +42,7 @@ class HttpOutboundConnection : public HttpConnection {
}
td::Status receive_eof() override {
found_eof_ = true;
if (reading_payload_) {
if (reading_payload_->payload_type() != HttpPayload::PayloadType::pt_eof) {
return td::Status::Error("unexpected EOF");

View file

@ -2,4 +2,4 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
add_executable(rldp-http-proxy rldp-http-proxy.cpp)
target_include_directories(rldp-http-proxy PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_link_libraries(rldp-http-proxy PRIVATE tonhttp rldp dht)
target_link_libraries(rldp-http-proxy PRIVATE tonhttp rldp dht tonlib)

View file

@ -33,17 +33,24 @@
#include "td/utils/FileLog.h"
#include "td/utils/Random.h"
#include "td/utils/filesystem.h"
#include "td/utils/overloaded.h"
#include "auto/tl/ton_api_json.h"
#include "auto/tl/tonlib_api.hpp"
#include "td/actor/MultiPromise.h"
#include "common/errorcode.h"
#include "tonlib/tonlib/TonlibClient.h"
#include "adnl/adnl.h"
#include "rldp/rldp.h"
#include "dht/dht.h"
#include <algorithm>
#include <list>
#include <set>
#if TD_DARWIN || TD_LINUX
#include <unistd.h>
@ -406,6 +413,8 @@ class HttpRldpPayloadSender : public td::actor::Actor {
td::Promise<td::BufferSlice> cur_query_promise_;
};
class RldpHttpProxy;
class TcpToRldpRequestSender : public td::actor::Actor {
public:
TcpToRldpRequestSender(
@ -413,7 +422,7 @@ class TcpToRldpRequestSender : public td::actor::Actor {
std::shared_ptr<ton::http::HttpPayload> request_payload,
td::Promise<std::pair<std::unique_ptr<ton::http::HttpResponse>, std::shared_ptr<ton::http::HttpPayload>>> promise,
td::actor::ActorId<ton::adnl::Adnl> adnl, td::actor::ActorId<ton::dht::Dht> dht,
td::actor::ActorId<ton::rldp::Rldp> rldp)
td::actor::ActorId<ton::rldp::Rldp> rldp, td::actor::ActorId<RldpHttpProxy> proxy)
: local_id_(local_id)
, host_(std::move(host))
, request_(std::move(request))
@ -421,29 +430,15 @@ class TcpToRldpRequestSender : public td::actor::Actor {
, promise_(std::move(promise))
, adnl_(adnl)
, dht_(dht)
, rldp_(rldp) {
, rldp_(rldp)
, proxy_(proxy) {
}
void start_up() override {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<ton::dht::DhtValue> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::abort_query, R.move_as_error());
return;
}
auto value = R.move_as_ok();
if (value.value().size() != 32) {
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::abort_query, td::Status::Error("bad value in dht"));
return;
}
ton::PublicKeyHash h{value.value().as_slice()};
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::resolved, ton::adnl::AdnlNodeIdShort{h});
});
ton::PublicKey key = ton::pubkeys::Unenc{"http." + host_};
ton::dht::DhtKey dht_key{key.compute_short_id(), "http." + host_, 0};
td::actor::send_closure(dht_, &ton::dht::Dht::get_value, std::move(dht_key), std::move(P));
resolve();
}
void resolve();
void resolved(ton::adnl::AdnlNodeIdShort id) {
dst_ = id;
td::Random::secure_bytes(id_.as_slice());
@ -533,6 +528,7 @@ class TcpToRldpRequestSender : public td::actor::Actor {
td::actor::ActorId<ton::adnl::Adnl> adnl_;
td::actor::ActorId<ton::dht::Dht> dht_;
td::actor::ActorId<ton::rldp::Rldp> rldp_;
td::actor::ActorId<RldpHttpProxy> proxy_;
std::unique_ptr<ton::http::HttpResponse> response_;
std::shared_ptr<ton::http::HttpPayload> response_payload_;
@ -634,6 +630,27 @@ class RldpHttpProxy : public td::actor::Actor {
local_hosts_.emplace_back(std::move(name), std::move(remote));
}
void receive_request_result(td::uint64 id, td::Result<tonlib_api::object_ptr<tonlib_api::Object>> R) {
if (id == 0) {
return;
}
auto it = tonlib_requests_.find(id);
CHECK(it != tonlib_requests_.end());
auto promise = std::move(it->second);
tonlib_requests_.erase(it);
promise.set_result(std::move(R));
}
void send_tonlib_request(tonlib_api::object_ptr<tonlib_api::Function> obj,
td::Promise<tonlib_api::object_ptr<tonlib_api::Object>> promise) {
auto id = next_tonlib_requests_id_++;
CHECK(tonlib_requests_.emplace(id, std::move(promise)).second);
td::actor::send_closure(tonlib_client_, &tonlib::TonlibClient::request, id, std::move(obj));
}
td::Status load_global_config() {
TRY_RESULT_PREFIX(conf_data, td::read_file(global_config_), "failed to read: ");
TRY_RESULT_PREFIX(conf_json, td::json_decode(conf_data.as_slice()), "failed to parse json: ");
@ -648,23 +665,45 @@ class RldpHttpProxy : public td::actor::Actor {
TRY_RESULT_PREFIX(dht, ton::dht::Dht::create_global_config(std::move(conf.dht_)), "bad [dht] section: ");
dht_config_ = std::move(dht);
class Cb : public tonlib::TonlibCallback {
public:
Cb(td::actor::ActorId<RldpHttpProxy> self_id) : self_id_(self_id) {
}
void on_result(std::uint64_t id, tonlib_api::object_ptr<tonlib_api::Object> result) override {
td::actor::send_closure(self_id_, &RldpHttpProxy::receive_request_result, id, std::move(result));
}
void on_error(std::uint64_t id, tonlib_api::object_ptr<tonlib_api::error> error) override {
td::actor::send_closure(self_id_, &RldpHttpProxy::receive_request_result, id,
td::Status::Error(error->code_, std::move(error->message_)));
}
private:
td::actor::ActorId<RldpHttpProxy> self_id_;
};
tonlib_client_ = td::actor::create_actor<tonlib::TonlibClient>("tonlibclient", td::make_unique<Cb>(actor_id(this)));
return td::Status::OK();
}
void store_dht() {
for (auto &serv : local_hosts_) {
ton::PublicKey key = ton::pubkeys::Unenc{"http." + serv.first};
ton::dht::DhtKey dht_key{key.compute_short_id(), "http." + serv.first, 0};
auto dht_update_rule = ton::dht::DhtUpdateRuleAnybody::create().move_as_ok();
ton::dht::DhtKeyDescription dht_key_description{std::move(dht_key), key, std::move(dht_update_rule),
td::BufferSlice()};
dht_key_description.check().ensure();
if (serv.first != "*") {
for (auto &serv_id : server_ids_) {
ton::PublicKey key = ton::pubkeys::Unenc{"http." + serv.first};
ton::dht::DhtKey dht_key{key.compute_short_id(), "http." + serv.first, 0};
auto dht_update_rule = ton::dht::DhtUpdateRuleAnybody::create().move_as_ok();
ton::dht::DhtKeyDescription dht_key_description{std::move(dht_key), key, std::move(dht_update_rule),
td::BufferSlice()};
dht_key_description.check().ensure();
auto ttl = static_cast<td::uint32>(td::Clocks::system() + 3600);
ton::dht::DhtValue dht_value{std::move(dht_key_description), td::BufferSlice{local_id_.as_slice()}, ttl,
td::BufferSlice("")};
auto ttl = static_cast<td::uint32>(td::Clocks::system() + 3600);
ton::dht::DhtValue dht_value{std::move(dht_key_description), td::BufferSlice{serv_id.as_slice()}, ttl,
td::BufferSlice("")};
td::actor::send_closure(dht_, &ton::dht::Dht::set_value, std::move(dht_value), [](td::Unit) {});
td::actor::send_closure(dht_, &ton::dht::Dht::set_value, std::move(dht_value), [](td::Unit) {});
}
}
}
alarm_timestamp() = td::Timestamp::in(60.0);
}
@ -673,7 +712,58 @@ class RldpHttpProxy : public td::actor::Actor {
store_dht();
}
void got_full_id(ton::adnl::AdnlNodeIdShort short_id, ton::adnl::AdnlNodeIdFull full_id) {
server_ids_full_[short_id] = full_id;
}
void run() {
keyring_ = ton::keyring::Keyring::create(is_client_ ? std::string("") : (db_root_ + "/keyring"));
{
auto S = load_global_config();
if (S.is_error()) {
LOG(INFO) << S;
std::_Exit(2);
}
}
if (is_client_ && server_ids_.size() > 0) {
LOG(ERROR) << "client-only node cannot be server";
std::_Exit(2);
}
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<td::Unit> R) {
R.ensure();
td::actor::send_closure(SelfId, &RldpHttpProxy::run_cont);
});
td::MultiPromise mp;
auto ig = mp.init_guard();
ig.add_promise(std::move(P));
for (auto &x : server_ids_) {
auto Q = td::PromiseCreator::lambda([promise = ig.get_promise(), SelfId = actor_id(this),
x](td::Result<ton::PublicKey> R) mutable {
if (R.is_error()) {
promise.set_error(R.move_as_error());
} else {
td::actor::send_closure(SelfId, &RldpHttpProxy::got_full_id, x, ton::adnl::AdnlNodeIdFull{R.move_as_ok()});
promise.set_value(td::Unit());
}
});
td::actor::send_closure(keyring_, &ton::keyring::Keyring::get_public_key, x.pubkey_hash(), std::move(Q));
}
auto Q = td::PromiseCreator::lambda(
[promise = ig.get_promise()](td::Result<tonlib_api::object_ptr<tonlib_api::Object>> R) mutable {
R.ensure();
promise.set_value(td::Unit());
});
auto conf_dataR = td::read_file(global_config_);
conf_dataR.ensure();
auto req = tonlib_api::make_object<tonlib_api::init>(tonlib_api::make_object<tonlib_api::options>(
tonlib_api::make_object<tonlib_api::config>(conf_dataR.move_as_ok().as_slice().str(), "", false, false),
tonlib_api::make_object<tonlib_api::keyStoreTypeInMemory>()));
send_tonlib_request(std::move(req), std::move(Q));
}
void run_cont() {
if (is_client_ && local_hosts_.size() > 0) {
LOG(ERROR) << "client-only node cannot be server";
std::_Exit(2);
@ -682,18 +772,10 @@ class RldpHttpProxy : public td::actor::Actor {
LOG(ERROR) << "client-only expects client port";
std::_Exit(2);
}
{
auto S = load_global_config();
if (S.is_error()) {
LOG(INFO) << S;
std::_Exit(2);
}
}
keyring_ = ton::keyring::Keyring::create("");
{
adnl_network_manager_ =
ton::adnl::AdnlNetworkManager::create(is_client_ ? client_port_ : static_cast<td::uint16>(addr_.get_port()));
adnl_ = ton::adnl::Adnl::create("", keyring_.get());
adnl_ = ton::adnl::Adnl::create(is_client_ ? std::string("") : (db_root_), keyring_.get());
td::actor::send_closure(adnl_, &ton::adnl::Adnl::register_network_manager, adnl_network_manager_.get());
if (is_client_) {
td::IPAddress addr;
@ -717,6 +799,10 @@ class RldpHttpProxy : public td::actor::Actor {
td::actor::send_closure(keyring_, &ton::keyring::Keyring::add_key, std::move(pk), true, [](td::Unit) {});
local_id_ = ton::adnl::AdnlNodeIdShort{pub.compute_short_id()};
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub}, addr_list);
if (server_ids_.size() == 0 && !is_client_) {
server_ids_.insert(local_id_);
}
}
{
auto pk = ton::PrivateKey{ton::privkeys::Ed25519::random()};
@ -725,6 +811,9 @@ class RldpHttpProxy : public td::actor::Actor {
dht_id_ = ton::adnl::AdnlNodeIdShort{pub.compute_short_id()};
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, ton::adnl::AdnlNodeIdFull{pub}, addr_list);
}
for (auto &serv_id : server_ids_) {
td::actor::send_closure(adnl_, &ton::adnl::Adnl::add_id, server_ids_full_[serv_id], addr_list);
}
}
{
if (is_client_) {
@ -732,7 +821,7 @@ class RldpHttpProxy : public td::actor::Actor {
D.ensure();
dht_ = D.move_as_ok();
} else {
auto D = ton::dht::Dht::create(dht_id_, "", dht_config_, keyring_.get(), adnl_.get());
auto D = ton::dht::Dht::create(dht_id_, db_root_, dht_config_, keyring_.get(), adnl_.get());
D.ensure();
dht_ = D.move_as_ok();
}
@ -758,31 +847,36 @@ class RldpHttpProxy : public td::actor::Actor {
server_ = ton::http::HttpServer::create(port_, std::make_shared<Cb>(actor_id(this)));
}
class AdnlCb : public ton::adnl::Adnl::Callback {
public:
AdnlCb(td::actor::ActorId<RldpHttpProxy> id) : self_id_(id) {
}
void receive_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst,
td::BufferSlice data) override {
}
void receive_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(self_id_, &RldpHttpProxy::receive_rldp_request, src, std::move(data),
std::move(promise));
}
for (auto &serv_id : server_ids_) {
class AdnlCb : public ton::adnl::Adnl::Callback {
public:
AdnlCb(td::actor::ActorId<RldpHttpProxy> id) : self_id_(id) {
}
void receive_message(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst,
td::BufferSlice data) override {
}
void receive_query(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) override {
td::actor::send_closure(self_id_, &RldpHttpProxy::receive_rldp_request, src, dst, std::move(data),
std::move(promise));
}
private:
td::actor::ActorId<RldpHttpProxy> self_id_;
};
td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, local_id_,
ton::adnl::Adnl::int_to_bytestring(ton::ton_api::http_request::ID),
std::make_unique<AdnlCb>(actor_id(this)));
private:
td::actor::ActorId<RldpHttpProxy> self_id_;
};
td::actor::send_closure(adnl_, &ton::adnl::Adnl::subscribe, serv_id,
ton::adnl::Adnl::int_to_bytestring(ton::ton_api::http_request::ID),
std::make_unique<AdnlCb>(actor_id(this)));
}
for (auto &serv : local_hosts_) {
servers_.emplace(serv.first, td::actor::create_actor<HttpRemote>("remote", serv.second));
}
rldp_ = ton::rldp::Rldp::create(adnl_.get());
td::actor::send_closure(rldp_, &ton::rldp::Rldp::add_id, local_id_);
for (auto &serv_id : server_ids_) {
td::actor::send_closure(rldp_, &ton::rldp::Rldp::add_id, serv_id);
}
store_dht();
}
@ -821,18 +915,19 @@ class RldpHttpProxy : public td::actor::Actor {
}
}
std::transform(host.begin(), host.end(), host.begin(), [](unsigned char c) { return std::tolower(c); });
if (host.size() < 5 || host.substr(host.size() - 4) != ".ton") {
if (!proxy_all_ &&
(host.size() < 5 || (host.substr(host.size() - 4) != ".ton" && host.substr(host.size() - 5) != ".adnl"))) {
promise.set_error(td::Status::Error(ton::ErrorCode::error, "bad server name"));
return;
}
td::actor::create_actor<TcpToRldpRequestSender>("outboundreq", local_id_, host, std::move(request),
std::move(payload), std::move(promise), adnl_.get(), dht_.get(),
rldp_.get())
rldp_.get(), actor_id(this))
.release();
}
void receive_rldp_request(ton::adnl::AdnlNodeIdShort src, td::BufferSlice data,
void receive_rldp_request(ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort dst, td::BufferSlice data,
td::Promise<td::BufferSlice> promise) {
LOG(INFO) << "got HTTP request over rldp from " << src;
TRY_RESULT_PROMISE(promise, f, ton::fetch_tl_object<ton::ton_api::http_request>(std::move(data), true));
@ -873,26 +968,37 @@ class RldpHttpProxy : public td::actor::Actor {
}
}
std::transform(host.begin(), host.end(), host.begin(), [](unsigned char c) { return std::tolower(c); });
if (host.size() < 5 || host.substr(host.size() - 4) != ".ton") {
promise.set_error(td::Status::Error(ton::ErrorCode::error, "bad server name"));
return;
}
auto it = servers_.find(host);
if (it == servers_.end()) {
promise.set_error(td::Status::Error(ton::ErrorCode::error, "unknown server name"));
return;
it = servers_.find("*");
if (it == servers_.end()) {
promise.set_error(td::Status::Error(ton::ErrorCode::error, "unknown server name"));
return;
}
}
TRY_RESULT_PROMISE(promise, payload, request->create_empty_payload());
LOG(INFO) << "starting HTTP over RLDP request";
td::actor::create_actor<RldpToTcpRequestSender>("inboundreq", f->id_, local_id_, src, std::move(request),
td::actor::create_actor<RldpToTcpRequestSender>("inboundreq", f->id_, dst, src, std::move(request),
std::move(payload), std::move(promise), adnl_.get(), rldp_.get(),
it->second.get())
.release();
}
void add_adnl_addr(ton::adnl::AdnlNodeIdShort id) {
server_ids_.insert(id);
}
void set_db_root(std::string db_root) {
db_root_ = std::move(db_root);
}
void set_proxy_all(bool value) {
proxy_all_ = value;
}
private:
td::uint16 port_;
td::IPAddress addr_;
@ -902,6 +1008,8 @@ class RldpHttpProxy : public td::actor::Actor {
bool is_client_{false};
td::uint16 client_port_{0};
std::set<ton::adnl::AdnlNodeIdShort> server_ids_;
std::map<ton::adnl::AdnlNodeIdShort, ton::adnl::AdnlNodeIdFull> server_ids_full_;
ton::adnl::AdnlNodeIdShort local_id_;
ton::adnl::AdnlNodeIdShort dht_id_;
@ -916,8 +1024,85 @@ class RldpHttpProxy : public td::actor::Actor {
td::actor::ActorOwn<ton::rldp::Rldp> rldp_;
std::shared_ptr<ton::dht::DhtGlobalConfig> dht_config_;
std::string db_root_ = ".";
bool proxy_all_ = false;
td::actor::ActorOwn<tonlib::TonlibClient> tonlib_client_;
std::map<td::uint64, td::Promise<tonlib_api::object_ptr<tonlib_api::Object>>> tonlib_requests_;
td::uint64 next_tonlib_requests_id_{1};
};
void TcpToRldpRequestSender::resolve() {
auto S = td::Slice(host_);
if (S.size() >= 5 && S.substr(S.size() - 5) == ".adnl") {
S.truncate(S.size() - 5);
auto R = ton::adnl::AdnlNodeIdShort::parse(S);
if (R.is_error()) {
abort_query(R.move_as_error_prefix("failed to parse adnl addr: "));
return;
}
resolved(R.move_as_ok());
return;
}
if (false) {
auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<ton::dht::DhtValue> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::abort_query, R.move_as_error());
return;
}
auto value = R.move_as_ok();
if (value.value().size() != 32) {
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::abort_query, td::Status::Error("bad value in dht"));
return;
}
ton::PublicKeyHash h{value.value().as_slice()};
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::resolved, ton::adnl::AdnlNodeIdShort{h});
});
ton::PublicKey key = ton::pubkeys::Unenc{"http." + host_};
ton::dht::DhtKey dht_key{key.compute_short_id(), "http." + host_, 0};
td::actor::send_closure(dht_, &ton::dht::Dht::get_value, std::move(dht_key), std::move(P));
} else {
auto obj = tonlib_api::make_object<tonlib_api::dns_resolve>(nullptr, host_, 0, 16);
auto P =
td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result<tonlib_api::object_ptr<tonlib_api::Object>> R) {
if (R.is_error()) {
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::abort_query,
R.move_as_error_prefix("failed to resolve: "));
} else {
auto v = R.move_as_ok();
auto obj = static_cast<tonlib_api::dns_resolved *>(v.get());
ton::adnl::AdnlNodeIdShort id;
td::uint32 cnt = 0;
for (auto &e : obj->entries_) {
tonlib_api::downcast_call(
*e->entry_.get(), td::overloaded(
[&](tonlib_api::dns_entryDataAdnlAddress &x) {
if (td::Random::fast(0, cnt) == 0) {
auto R = ton::adnl::AdnlNodeIdShort::parse(x.adnl_address_->adnl_address_);
if (R.is_ok()) {
id = R.move_as_ok();
cnt++;
}
}
},
[&](auto &x) {}));
}
if (cnt == 0) {
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::abort_query,
td::Status::Error(ton::ErrorCode::notready, "failed to resolve"));
} else {
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::resolved, id);
}
}
});
td::actor::send_closure(proxy_, &RldpHttpProxy::send_tonlib_request, std::move(obj), std::move(P));
}
}
int main(int argc, char *argv[]) {
SET_VERBOSITY_LEVEL(verbosity_WARNING);
@ -961,6 +1146,11 @@ int main(int argc, char *argv[]) {
td::actor::send_closure(x, &RldpHttpProxy::set_addr, addr);
return td::Status::OK();
});
p.add_option('A', "adnl", "server ADNL addr", [&](td::Slice arg) -> td::Status {
TRY_RESULT(adnl, ton::adnl::AdnlNodeIdShort::parse(arg));
td::actor::send_closure(x, &RldpHttpProxy::add_adnl_addr, adnl);
return td::Status::OK();
});
p.add_option('c', "client-port", "local <port> to use for client adnl queries", [&](td::Slice arg) -> td::Status {
TRY_RESULT(port, td::to_integer_safe<td::uint16>(arg));
td::actor::send_closure(x, &RldpHttpProxy::set_client_port, port);
@ -977,6 +1167,10 @@ int main(int argc, char *argv[]) {
td::actor::send_closure(x, &RldpHttpProxy::set_local_host, arg.str(), addr);
return td::Status::OK();
});
p.add_option('D', "db", "db root", [&](td::Slice arg) -> td::Status {
td::actor::send_closure(x, &RldpHttpProxy::set_db_root, arg.str());
return td::Status::OK();
});
p.add_option(
'R', "remote",
"<hostname>@<ip>:<port>, indicates a http hostname that will be proxied to remote http server at <ip>:<port>",
@ -999,13 +1193,23 @@ int main(int argc, char *argv[]) {
}).ensure();
return td::Status::OK();
});
#if TD_DARWIN || TD_LINUX
p.add_option('l', "logname", "log to file", [&](td::Slice fname) {
logger_ = td::FileLog::create(fname.str()).move_as_ok();
td::log_interface = logger_.get();
return td::Status::OK();
});
#endif
p.add_option('P', "proxy-all", "value=[YES|NO]. proxy all HTTP requests (default only *.ton and *.adnl)",
[&](td::Slice value) {
if (value == "YES" || value == "yes") {
td::actor::send_closure(x, &RldpHttpProxy::set_proxy_all, true);
} else if (value == "NO" || value == "no") {
td::actor::send_closure(x, &RldpHttpProxy::set_proxy_all, false);
} else {
return td::Status::Error("--proxy-all expected YES or NO");
}
return td::Status::OK();
});
td::actor::Scheduler scheduler({7});

View file

@ -34,6 +34,7 @@ inputKeyFake = InputKey;
exportedKey word_list:vector<secureString> = ExportedKey;
exportedPemKey pem:secureString = ExportedPemKey;
exportedEncryptedKey data:secureBytes = ExportedEncryptedKey;
exportedUnencryptedKey data:secureBytes = ExportedUnencryptedKey;
bip39Hints words:vector<string> = Bip39Hints;
@ -178,9 +179,11 @@ deleteAllKeys = Ok;
exportKey input_key:InputKey = ExportedKey;
exportPemKey input_key:InputKey key_password:secureBytes = ExportedPemKey;
exportEncryptedKey input_key:InputKey key_password:secureBytes = ExportedEncryptedKey;
exportUnencryptedKey input_key:InputKey = ExportedUnencryptedKey;
importKey local_password:secureBytes mnemonic_password:secureBytes exported_key:exportedKey = Key;
importPemKey local_password:secureBytes key_password:secureBytes exported_key:exportedPemKey = Key;
importEncryptedKey local_password:secureBytes key_password:secureBytes exported_encrypted_key:exportedEncryptedKey = Key;
importUnencryptedKey local_password:secureBytes exported_unencrypted_key:exportedUnencryptedKey = Key;
changeLocalPassword input_key:InputKey new_local_password:secureBytes = Key;
encrypt decrypted_data:secureBytes secret:secureBytes = Data;
@ -220,7 +223,7 @@ smc.getData id:int53 = tvm.Cell;
smc.getState id:int53 = tvm.Cell;
smc.runGetMethod id:int53 method:smc.MethodId stack:vector<tvm.StackEntry> = smc.RunResult;
dns.resolve account_address:accountAddress name:string category:int32 = dns.Resolved;
dns.resolve account_address:accountAddress name:string category:int32 ttl:int32 = dns.Resolved;
onLiteServerQueryResult id:int64 bytes:bytes = Ok;
onLiteServerQueryError id:int64 error:error = Ok;

Binary file not shown.

View file

@ -143,10 +143,9 @@ TEST(Tonlib, InitClose) {
)abc";
sync_send(client, make_object<tonlib_api::options_setConfig>(cfg(bad_config.str()))).ensure_error();
auto address =
sync_send(client,
make_object<tonlib_api::getAccountAddress>(make_object<tonlib_api::testGiver_initialAccountState>(), 0))
.move_as_ok();
auto address = sync_send(client, make_object<tonlib_api::getAccountAddress>(
make_object<tonlib_api::testGiver_initialAccountState>(), 0))
.move_as_ok();
sync_send(client, make_object<tonlib_api::getAccountState>(std::move(address))).ensure_error();
sync_send(client, make_object<tonlib_api::close>()).ensure();
sync_send(client, make_object<tonlib_api::close>()).ensure_error();
@ -490,6 +489,21 @@ TEST(Tonlib, KeysApi) {
.move_as_ok();
CHECK(new_imported_key->public_key_ == key->public_key_);
CHECK(new_imported_key->secret_ != key->secret_);
auto exported_raw_key =
sync_send(client, make_object<tonlib_api::exportUnencryptedKey>(make_object<tonlib_api::inputKeyRegular>(
make_object<tonlib_api::key>(key->public_key_, new_imported_key->secret_.copy()),
new_local_password.copy())))
.move_as_ok();
sync_send(client, make_object<tonlib_api::deleteKey>(
make_object<tonlib_api::key>(new_imported_key->public_key_, new_imported_key->secret_.copy())))
.move_as_ok();
auto raw_imported_key = sync_send(client, make_object<tonlib_api::importUnencryptedKey>(new_local_password.copy(),
std::move(exported_raw_key)))
.move_as_ok();
CHECK(raw_imported_key->public_key_ == key->public_key_);
CHECK(raw_imported_key->secret_ != key->secret_);
}
TEST(Tonlib, ConfigCache) {

View file

@ -552,7 +552,7 @@ void dns_resolve(Client& client, const Wallet& dns, std::string name) {
auto address = dns.get_address();
while (true) {
auto resolved =
sync_send(client, make_object<::ton::tonlib_api::dns_resolve>(std::move(address), name, 1)).move_as_ok();
sync_send(client, make_object<::ton::tonlib_api::dns_resolve>(std::move(address), name, 1, 0)).move_as_ok();
CHECK(resolved->entries_.size() == 1);
LOG(INFO) << to_string(resolved);
if (resolved->entries_[0]->category_ == -1) {

View file

@ -179,6 +179,11 @@ td::Result<KeyStorage::ExportedEncryptedKey> KeyStorage::export_encrypted_key(In
return ExportedEncryptedKey{std::move(res.encrypted_data)};
}
td::Result<KeyStorage::ExportedUnencryptedKey> KeyStorage::export_unencrypted_key(InputKey input_key) {
TRY_RESULT(decrypted_key, export_decrypted_key(std::move(input_key)));
return ExportedUnencryptedKey{decrypted_key.private_key.as_octet_string()};
}
td::Result<KeyStorage::Key> KeyStorage::import_encrypted_key(td::Slice local_password, td::Slice key_password,
ExportedEncryptedKey exported_key) {
EncryptedKey encrypted_key{std::move(exported_key.data), td::Ed25519::PublicKey(td::SecureString()),
@ -187,6 +192,14 @@ td::Result<KeyStorage::Key> KeyStorage::import_encrypted_key(td::Slice local_pas
return save_key(std::move(decrypted_key), local_password);
}
td::Result<KeyStorage::Key> KeyStorage::import_unencrypted_key(td::Slice local_password,
ExportedUnencryptedKey exported_key) {
RawDecryptedKey raw_key;
raw_key.private_key = std::move(exported_key.data);
DecryptedKey key(std::move(raw_key));
return save_key(std::move(key), local_password);
}
KeyStorage::PrivateKey KeyStorage::fake_private_key() {
return PrivateKey{td::SecureString(32, 0)};
}

View file

@ -46,6 +46,9 @@ class KeyStorage {
struct ExportedEncryptedKey {
td::SecureString data;
};
struct ExportedUnencryptedKey {
td::SecureString data;
};
struct PrivateKey {
td::SecureString private_key;
};
@ -57,6 +60,7 @@ class KeyStorage {
td::Result<ExportedKey> export_key(InputKey input_key);
td::Result<ExportedPemKey> export_pem_key(InputKey input_key, td::Slice key_password);
td::Result<ExportedEncryptedKey> export_encrypted_key(InputKey input_key, td::Slice key_password);
td::Result<ExportedUnencryptedKey> export_unencrypted_key(InputKey input_key);
td::Result<Key> change_local_password(InputKey input_key, td::Slice new_local_password);
td::Status delete_key(const Key& key);
@ -66,6 +70,7 @@ class KeyStorage {
td::Result<Key> import_pem_key(td::Slice local_password, td::Slice key_password, ExportedPemKey exported_key);
td::Result<Key> import_encrypted_key(td::Slice local_password, td::Slice key_password,
ExportedEncryptedKey exported_key);
td::Result<Key> import_unencrypted_key(td::Slice local_password, ExportedUnencryptedKey exported_key);
td::Result<PrivateKey> load_private_key(InputKey input_key);

View file

@ -353,6 +353,10 @@ class AccountState {
return raw_.info.gen_utime;
}
ton::BlockIdExt get_block_id() const {
return raw_.block_id;
}
td::int64 get_balance() const {
return raw_.balance;
}
@ -2593,14 +2597,22 @@ td::Result<tonlib_api::object_ptr<tonlib_api::dns_EntryData>> to_tonlib_api(
return res;
}
void TonlibClient::finish_dns_resolve(std::string name, td::int32 category, td::unique_ptr<AccountState> smc,
void TonlibClient::finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl,
td::optional<ton::BlockIdExt> block_id, td::unique_ptr<AccountState> smc,
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
if (smc->get_wallet_type() != AccountState::WalletType::ManualDns) {
return promise.set_error(TonlibError::AccountTypeUnexpected("ManualDns"));
}
block_id = smc->get_block_id();
auto dns = ton::ManualDns::create(smc->get_smc_state());
TRY_RESULT_PROMISE(promise, entries, dns->resolve(name, category));
if (entries.size() == 1 && entries[0].category == -1 && entries[0].name != name && ttl > 0 &&
entries[0].data.type == ton::ManualDns::EntryData::Type::NextResolver) {
auto address = entries[0].data.data.get<ton::ManualDns::EntryDataNextResolver>().resolver;
return do_dns_request(name, category, ttl - 1, std::move(block_id), address, std::move(promise));
}
std::vector<tonlib_api::object_ptr<tonlib_api::dns_entry>> api_entries;
for (auto& entry : entries) {
TRY_RESULT_PROMISE(promise, entry_data, to_tonlib_api(entry.data));
@ -2610,21 +2622,27 @@ void TonlibClient::finish_dns_resolve(std::string name, td::int32 category, td::
promise.set_value(tonlib_api::make_object<tonlib_api::dns_resolved>(std::move(api_entries)));
}
void TonlibClient::do_dns_request(std::string name, td::int32 category, block::StdAddress address,
void TonlibClient::do_dns_request(std::string name, td::int32 category, td::int32 ttl,
td::optional<ton::BlockIdExt> block_id, block::StdAddress address,
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
make_request(int_api::GetAccountState{address, query_context_.block_id.copy()},
promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name, category));
auto block_id_copy = block_id.copy();
make_request(int_api::GetAccountState{address, std::move(block_id_copy)},
promise.send_closure(actor_id(this), &TonlibClient::finish_dns_resolve, name, category, ttl,
std::move(block_id)));
}
td::Status TonlibClient::do_request(const tonlib_api::dns_resolve& request,
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise) {
auto block_id = query_context_.block_id.copy();
if (!request.account_address_) {
make_request(int_api::GetDnsResolver{},
promise.send_closure(actor_id(this), &TonlibClient::do_dns_request, request.name_, request.category_));
promise.send_closure(actor_id(this), &TonlibClient::do_dns_request, request.name_, request.category_,
request.ttl_, std::move(block_id)));
return td::Status::OK();
}
TRY_RESULT(account_address, get_account_address(request.account_address_->account_address_));
do_dns_request(request.name_, request.category_, account_address, std::move(promise));
do_dns_request(request.name_, request.category_, request.ttl_, std::move(block_id), account_address,
std::move(promise));
return td::Status::OK();
}
@ -2745,6 +2763,28 @@ td::Status TonlibClient::do_request(const tonlib_api::importEncryptedKey& reques
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key_bytes.serialize(true), std::move(key.secret)));
return td::Status::OK();
}
td::Status TonlibClient::do_request(const tonlib_api::exportUnencryptedKey& request,
td::Promise<object_ptr<tonlib_api::exportedUnencryptedKey>>&& promise) {
if (!request.input_key_) {
return TonlibError::EmptyField("input_key");
}
TRY_RESULT(input_key, from_tonlib(*request.input_key_));
TRY_RESULT(exported_key, key_storage_.export_unencrypted_key(std::move(input_key)));
promise.set_value(tonlib_api::make_object<tonlib_api::exportedUnencryptedKey>(std::move(exported_key.data)));
return td::Status::OK();
}
td::Status TonlibClient::do_request(const tonlib_api::importUnencryptedKey& request,
td::Promise<object_ptr<tonlib_api::key>>&& promise) {
if (!request.exported_unencrypted_key_) {
return TonlibError::EmptyField("exported_encrypted_key");
}
TRY_RESULT(key, key_storage_.import_unencrypted_key(
std::move(request.local_password_),
KeyStorage::ExportedUnencryptedKey{std::move(request.exported_unencrypted_key_->data_)}));
TRY_RESULT(key_bytes, public_key_from_bytes(key.public_key.as_slice()));
promise.set_value(tonlib_api::make_object<tonlib_api::key>(key_bytes.serialize(true), std::move(key.secret)));
return td::Status::OK();
}
td::Status TonlibClient::do_request(const tonlib_api::changeLocalPassword& request,
td::Promise<object_ptr<tonlib_api::key>>&& promise) {

View file

@ -245,6 +245,11 @@ class TonlibClient : public td::actor::Actor {
td::Status do_request(const tonlib_api::importEncryptedKey& request,
td::Promise<object_ptr<tonlib_api::key>>&& promise);
td::Status do_request(const tonlib_api::exportUnencryptedKey& request,
td::Promise<object_ptr<tonlib_api::exportedUnencryptedKey>>&& promise);
td::Status do_request(const tonlib_api::importUnencryptedKey& request,
td::Promise<object_ptr<tonlib_api::key>>&& promise);
td::Status do_request(const tonlib_api::changeLocalPassword& request,
td::Promise<object_ptr<tonlib_api::key>>&& promise);
@ -290,9 +295,10 @@ class TonlibClient : public td::actor::Actor {
td::Status do_request(const tonlib_api::dns_resolve& request,
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
void do_dns_request(std::string name, td::int32 category, block::StdAddress address,
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
void finish_dns_resolve(std::string name, td::int32 category, td::unique_ptr<AccountState> smc,
void do_dns_request(std::string name, td::int32 category, td::int32 ttl, td::optional<ton::BlockIdExt> block_id,
block::StdAddress address, td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
void finish_dns_resolve(std::string name, td::int32 category, td::int32 ttl, td::optional<ton::BlockIdExt> block_id,
td::unique_ptr<AccountState> smc,
td::Promise<object_ptr<tonlib_api::dns_resolved>>&& promise);
td::Status do_request(int_api::GetAccountState request, td::Promise<td::unique_ptr<AccountState>>&&);

View file

@ -114,6 +114,7 @@ class TonlibCli : public td::actor::Actor {
bool use_callbacks_for_network{false};
td::int32 wallet_version = 2;
td::int32 wallet_revision = 0;
td::optional<td::uint32> wallet_id;
bool ignore_cache{false};
bool one_shot{false};
@ -223,7 +224,11 @@ class TonlibCli : public td::actor::Actor {
LOG_IF(ERROR, r_ok.is_error()) << r_ok.error();
if (r_ok.is_ok()) {
if (r_ok.ok()->config_info_) {
wallet_id_ = static_cast<td::uint32>(r_ok.ok()->config_info_->default_wallet_id_);
if (options_.wallet_id) {
wallet_id_ = options_.wallet_id.value();
} else {
wallet_id_ = static_cast<td::uint32>(r_ok.ok()->config_info_->default_wallet_id_);
}
}
td::TerminalIO::out() << "Tonlib is inited\n";
if (options_.one_shot) {
@ -307,12 +312,13 @@ class TonlibCli : public td::actor::Actor {
"<addr> with specified parameters\n";
td::TerminalIO::out() << "getstate <key_id>\tget state of wallet with requested key\n";
td::TerminalIO::out() << "getaddress <key_id>\tget address of wallet with requested key\n";
td::TerminalIO::out() << "dns resove <addr> <name>\n";
td::TerminalIO::out() << "dns resolve (<addr> | root) <name> <category>\n";
td::TerminalIO::out() << "dns cmd <key_id> <dns_cmd>\n";
//td::TerminalIO::out() << "dns cmdlist <key_id> {<dns_cmd>\\n} end\n";
td::TerminalIO::out() << "dns cmdfile <key_id> <file>\n";
td::TerminalIO::out() << "\t<dns_cmd> = set <name> <category> <data> | delete.name <name> | delete.all\n";
td::TerminalIO::out() << "\t<data> = DELETED | EMPTY | TEXT:<text>\n";
td::TerminalIO::out() << "\t<data> = DELETED | EMPTY | TEXT:<text> | NEXT:<smc-address> | SMC:<smc-address> | "
"ADNL:<adnl-address>\n";
td::TerminalIO::out()
<< "blockmode auto|manual\tWith auto mode, all queries will be executed with respect to the latest block. "
@ -331,6 +337,7 @@ class TonlibCli : public td::actor::Actor {
td::TerminalIO::out() << "setbounceble <address> [<bounceble>] - change bounceble flag in address\n";
td::TerminalIO::out() << "importkey - import key\n";
td::TerminalIO::out() << "importkeypem <filename> - import key\n";
td::TerminalIO::out() << "importkeyraw <filename> - import key\n";
td::TerminalIO::out() << "deletekeys - delete ALL PRIVATE KEYS\n";
td::TerminalIO::out() << "exportkey [<key_id>] - export key\n";
td::TerminalIO::out() << "exportkeypem [<key_id>] - export key\n";
@ -403,6 +410,8 @@ class TonlibCli : public td::actor::Actor {
get_address(parser.read_word(), std::move(cmd_promise));
} else if (cmd == "importkeypem") {
import_key_pem(parser.read_word(), std::move(cmd_promise));
} else if (cmd == "importkeyraw") {
import_key_raw(parser.read_word(), std::move(cmd_promise));
} else if (cmd == "dns") {
run_dns_cmd(parser, std::move(cmd_promise));
} else if (cmd == "gethistory") {
@ -442,16 +451,21 @@ class TonlibCli : public td::actor::Actor {
promise.set_value(td::Unit());
return;
}
if (resolved->entries_[0]->entry_->get_id() == tonlib_api::dns_entryDataNextResolver::ID) {
if (resolved->entries_[0]->entry_->get_id() == tonlib_api::dns_entryDataNextResolver::ID && ttl != 0) {
td::TerminalIO::out() << "Redirect resolver\n";
auto entry = tonlib_api::move_object_as<tonlib_api::dns_entryDataNextResolver>(resolved->entries_[0]->entry_);
send_query(tonlib_api::make_object<tonlib_api::dns_resolve>(std::move(entry->resolver_), name, category),
promise.send_closure(actor_id(this), &TonlibCli::do_dns_resolve, name, category, ttl));
send_query(tonlib_api::make_object<tonlib_api::dns_resolve>(std::move(entry->resolver_), name, category, ttl),
promise.send_closure(actor_id(this), &TonlibCli::do_dns_resolve, name, category, 0));
return;
}
promise.set_error(td::Status::Error("Failed to resolve"));
}
void dns_resolve(td::ConstParser& parser, td::Promise<td::Unit> promise) {
auto key_id = parser.read_word();
if (key_id == "root") {
key_id = "none";
}
TRY_RESULT_PROMISE(promise, address, to_account_address(key_id, false));
auto name = parser.read_word();
auto category_str = parser.read_word();
@ -1198,6 +1212,22 @@ class TonlibCli : public td::actor::Actor {
return td::Unit();
}));
}
void import_key_raw(td::Slice filename, td::Promise<td::Unit> promise) {
TRY_RESULT_PROMISE(promise, data, td::read_file_secure(filename.str()));
using tonlib_api::make_object;
send_query(make_object<tonlib_api::importUnencryptedKey>(
td::SecureString(), make_object<tonlib_api::exportedUnencryptedKey>(std::move(data))),
promise.wrap([&](auto&& key) {
LOG(ERROR) << to_string(key);
KeyInfo info;
info.public_key = key->public_key_;
info.secret = std::move(key->secret_);
keys_.push_back(std::move(info));
export_key("exportkey", key->public_key_, keys_.size() - 1, td::SecureString());
store_keys();
return td::Unit();
}));
}
void export_key(std::string cmd, std::string key, size_t key_i, td::Slice password) {
using tonlib_api::make_object;
@ -1485,6 +1515,11 @@ int main(int argc, char* argv[]) {
options.use_callbacks_for_network = true;
return td::Status::OK();
});
p.add_option('w', "wallet-id", "do not use this", [&](td::Slice arg) {
TRY_RESULT(wallet_id, td::to_integer_safe<td::uint32>((arg)));
options.wallet_id = wallet_id;
return td::Status::OK();
});
p.add_option('W', "wallet-version", "do not use this (version[.revision])", [&](td::Slice arg) {
td::ConstParser parser(arg);
TRY_RESULT(version, td::to_integer_safe<td::int32>((parser.read_till_nofail('.'))));

View file

@ -5,7 +5,7 @@ if (NOT OPENSSL_FOUND)
endif()
add_executable(generate-random-id generate-random-id.cpp )
target_link_libraries(generate-random-id tl_api ton_crypto keys)
target_link_libraries(generate-random-id tl_api ton_crypto keys adnl)
target_include_directories(generate-random-id PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/..)

View file

@ -23,7 +23,7 @@
exception statement from your version. If you delete this exception statement
from all source files in the program, then also delete it here.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include <iostream>
#include <iomanip>
@ -51,11 +51,11 @@ int main(int argc, char *argv[]) {
std::string name = "id_ton";
p.add_option('m', "mode", "sets mode id/adnl/dht/keys", [&](td::Slice key) {
p.add_option('m', "mode", "sets mode (one of id/adnl/dht/keys/adnlid)", [&](td::Slice key) {
mode = key.str();
return td::Status::OK();
});
p.add_option('h', "help", "prints_help", [&]() {
p.add_option('h', "help", "prints this help", [&]() {
char b[10240];
td::StringBuilder sb(td::MutableSlice{b, 10000});
sb << p;
@ -63,11 +63,11 @@ int main(int argc, char *argv[]) {
std::exit(2);
return td::Status::OK();
});
p.add_option('n', "name", "name to keys", [&](td::Slice arg) {
p.add_option('n', "name", "path to save private keys to", [&](td::Slice arg) {
name = arg.str();
return td::Status::OK();
});
p.add_option('k', "key", "private key to import", [&](td::Slice key) {
p.add_option('k', "key", "path to private key to import", [&](td::Slice key) {
if (!pk.empty()) {
return td::Status::Error("duplicate '-k' option");
}
@ -96,7 +96,7 @@ int main(int argc, char *argv[]) {
}
if (mode.size() == 0) {
std::cerr << "'-m' option missing" << std::endl;
std::cerr << "'--mode' option missing" << std::endl;
return 2;
}
@ -143,6 +143,12 @@ int main(int argc, char *argv[]) {
td::write_file(name + ".pub", pub_key.export_as_slice().as_slice()).ensure();
std::cout << short_key.bits256_value().to_hex() << " " << td::base64_encode(short_key.as_slice()) << std::endl;
} else if (mode == "adnlid") {
auto n = pk.compute_short_id();
name = n.bits256_value().to_hex();
td::write_file(name, pk.export_as_slice()).ensure();
std::cout << name << " " << ton::adnl::AdnlNodeIdShort{n}.serialize() << std::endl;
} else {
std::cerr << "unknown mode " << mode;
return 2;