Цель этого документа — дать краткое введение в TON DNS, сервис для перевода понятных человеку доменных имен (таких как test.ton
илиmysite.temp.ton
) в адреса смарт-контрактов TON, адреса ADNL, используемые службами, работающими в сети TON (например, узлами TON) и т. д.
1. Доменные имена
TON DNS использует читабельные доменные имена, состоящие из строки в кодировке UTF-8 длиной до 126 байт, с несколькими секциями доменного имени, разделенными точками (.
). Нулевые символы (то есть нулевые байты) и в целом, байты в диапазоне 0..32 не допускаются в доменных именах. Например, test.ton
иmysite.temp.ton
являются допустимыми доменами TON DNS.
Основное отличие от обычных доменных имен состоит в том, что домены TON DNS чувствительны к регистру; при желании можно преобразовать все домены в нижний регистр перед выполнением поиска TON DNS, чтобы получить нечувствительность к регистру.
В настоящее время только домены, оканчивающиеся на .ton
, распознаются как допустимые домены TON DNS. Это может измениться в будущем. Однако обратите внимание, что будет плохой идеей определять домены первого уровня совпадающими с доменами первого уровня, уже существующими в Интернете, такими как .com
или.to
. Потому что в таком случае можно зарегистрировать
TON-домен google.com
, развернуть там сайт TON, создать скрытую ссылку на страницу этого сайта TON со своего другого сайта TON, выглядящего безобидно, и украсть cookie-файлы google.com
у ничего не подозревающих посетителей.
TON DNS преобразует доменные имена следующим образом. Во-первых, доменное имя разбивается на компоненты, разделенные символами точки .
. Затем к каждому компоненту добавляются нулевые символы, и все компоненты объединяются в обратном порядке. Например, google.com
становитсяcom\0google\0
.
2. Преобразование доменов TON DNS
Домен TON DNS преобразуется следующим образом. Во-первых, корневой смарт-контракт DNS определяется путем проверки значения параметра конфигурации #4 в последнем состоянии мастер-цепочки. Этот параметр содержит 256-битный адрес корневого смарт-контракта DNS внутри мастер-цепочки.
Затем для корневого смарт-контракта DNS вызывается специальный get-метод dnsresolve
(id метода 123660) с двумя параметрами. Первый параметр — это CellSlice с *8n* битами данных, содержащими внутреннее представление запрашиваемого домена, где *n* — длина внутреннего представления в байтах (не более 127). Второй параметр — это 16-разрядное целое число со знаком, содержащее обязательную *категорию*. Если категория равна нулю, то запрашиваются все категории.
Если get-метод завершится неудачно, то поиск TON DNS будет неудачным. В противном случае get-метод возвращает два значения. Первый — *8m*, длина префикса внутреннего представления запрашиваемого домена (в битах), 0 <m <= n. Второй — это ячейка с записью TON DNS для требуемого домена в требуемой категории или корневой словарь с 16-разрядными целочисленными ключами (категориями) со знаком и значениями, равными сериализации соответствующих записей TON DNS. Если домен не дает отклика с корневым смарт-контрактом DNS, то есть, если непустой префикс не является действующим доменом, то возвращается (0, null). Другими словами, m = 0 означает, что поиск TON DNS не нашел данных для требуемого домена. В этом случае поиск TON DNS также не будет успешным.
Если m = n, то вторым компонентом результата является либо ячейка с допустимой записью TON DNS для требуемого домена и категории, либо значение Null, если для этого домена с этой категорией нет записи TON DNS. В любом случае процесс разрешения останавливается, и полученная таким образом запись TON DNS десериализуется и запрашивается информация (например, тип записи и ее параметры, такие как адрес смарт-контракта или адрес ADNL).
Наконец, если m < n, то поиск успешен, но для префикса m-byte исходного внутреннего представления домена доступен только частичный результат. Возвращается самый длинный из всех таких префиксов, известных смарт-контракту DNS. Например, попытка поиска mysite.test.ton
(то естьton\0test\0mysite\0
во внутреннем представлении) в корневом смарт-контракте DNS может вернуть 8m = 72, что соответствует префиксу ton\0test\0
, то есть поддомен «test.ton» в обычном доменном представлении. В этом случае dnsresolve() возвращает значение для категории -1 для этого префикса независимо от категории, первоначально запрошенной клиентом.
Обусловлено, что категория -1 обычно содержит запись TON DNS типа *dns_next_resolver*, содержащую адрес следующего смарт-контракта резолвера (распознавателя), который может находиться в любой другой рабочей цепочке, например в базовой цепочке. Если это действительно так, процесс разрешения продолжается, выполняя get-метод dnsresolve
для следующего резолвера с внутренним представлением доменного имени, содержащим только его часть, до сих пор не преобразованную (если мы искали ton\0test\0mysite\0
и префикс ton\0test\0
был найден в корневом смарт-контракте DNS, то следующий dnsresolve
будет вызываться с mysite\0
в качестве первого аргумента).
Затем, либо смарт-контракт следующего резолвера сообщает об ошибке или об отсутствии каких-либо записей для требуемого домена / любого из его префиксов, либо получается окончательный результат, либо возвращается другой префикс и смарт-контракт следующего резолвера. В последнем случае процесс продолжается таким же образом, пока не будет преобразован весь исходный домен.
3. Использование LiteClient и TonLib для преобразования доменов TON DNS
Вышеуказанный процесс может быть вызван автоматически с помощью TON LiteClient или TONLib. Например, можно вызвать команду dnsresolve test.ton 1
в LiteClient, чтобы преобразовать «test.ton» с категорией 1 и получить следующий результат:
> dnsresolve test.ton
...
Result for domain 'test.ton' category 1
raw data: x{AD011B3CBBE404F47FFEF92D0D7894C5C6F215F677732A49E544F16D1E75643D46AB00}
category #1 : (dns_adnl_address adnl_addr:x1B3CBBE404F47FFEF92D0D7894C5C6F215F677732A49E544F16D1E75643D46AB flags:0)
adnl address 1B3CBBE404F47FFEF92D0D7894C5C6F215F677732A49E544F16D1E75643D46AB = UNTZO7EAT2H77XZFUGXRFGFY3ZBL5TXOMVETZKE6FWR45LEHVDKXAUY
В этом случае запись TON DNS для «test.ton» представляет собой запись dns_adnl_address
, содержащую адрес ADNL UNTZO7EAT2H77XZFUGXRFGFY3ZBL5TXOMVETZKE6FWR45LEHVDKXAUY
В качестве альтернативы можно вызвать tonlib-cli
и ввести следующую команду:
> dns resolve root test.ton 1
Redirect resolver
...
Done
test.ton 1 ADNL:untzo7eat2h77xzfugxrfgfy3zbl5txomvetzke6fwr45lehvdkxauy
Это более компактное представление того же результата.
Наконец, если использовать прокси-сервер RLDP-HTTP в клиентском режиме для доступа к TON-сайтам из браузера, как описано в Инструкции по созданию TON Sites, автоматически запускается преобразователь TONLib для преобразования всех доменов, введенных конечным пользователем, так что HTTP-запрос к http://test.ton/testnet/last
автоматически перенаправляется на ADNL-адрес untzo7eat2h77xzfugxrfgfy3zbl5txomvetzke6fwr45lehvdkxauy
через RLDP.
4. Регистрация новых доменов
Предположим, что у вас есть новый TON сайт с недавно сгенерированным адресом ADNL, например, vcqmha5j3ceve35ammfrhqty46rkhi455otydstv66pk2tmf7rl25f3
. Безусловно, конечный пользователь может набрать http://vcqmha5j3ceve35ammfrhqty46rkhi455otydstv66pk2tmf7rl25f3.adnl/
, чтобы зайти на ваш TON сайт из браузера с помощью прокси-сервера RLDP-HTTP в режиме клиента, но это не очень удобно. Вместо этого вы можете зарегистрировать новый домен, скажем, mysite.temp.ton
с записью dns_adnl_address
в категории 1, содержащей адрес ADNL vcq … 25f3 вашего сайта TON. Тогда пользователь сможет получить доступ к вашему сайту, просто набрав mysite.temp.ton
в браузере.
Как правило, обычно необходимо связаться с владельцем домена более высокого уровня и попросить его добавить запись для вашего субдомена в смарт-контракт его DNS-резолвера. Тем не менее, TestNet блокчейна TON имеет специальный преобразователь для temp.ton
, который позволяет любому автоматически регистрировать любые субдомены temp.ton
, которые еще не заняты, при условии, что по этому смарт-контракту выплачивается небольшая плата (в тестовых Граммах). В нашем случае сначала нужно узнать адрес этого смарт-контракта, например, с помощью Lite Client:
> dnsresolve temp.ton -1
...
category #-1 : (dns_next_resolver
resolver:(addr_std
anycast:nothing workchain_id:0 address:x190BD756F6C0E7948DC26CB47968323177FB20344F8F9A50918CAF87ECB34B79))
next resolver 0:190BD756F6C0E7948DC26CB47968323177FB20344F8F9A50918CAF87ECB34B79 = EQAZC9dW9sDnlI3CbLR5aDIxd_sgNE-PmlCRjK-H7LNLeUXN
Мы видим, что адрес этого автоматического DNS смарт-контракта — EQAZC9dW9sDnlI3CbLR5aDIxd_sgNE-PmlCRjK-H7LNLeUXN
. Мы можем запустить несколько методов get, чтобы вычислить требуемую цену для регистрации субдомена и узнать период, за который субдомен будет зарегистрирован:
> runmethod EQAZC9dW9sDnlI3CbLR5aDIxd_sgNE-PmlCRjK-H7LNLeUXN getstdperiod
...
arguments: [ 67418 ]
result: [ 700000 ]
remote result (not to be trusted): [ 700000 ]
> runmethod EQAZC9dW9sDnlI3CbLR5aDIxd_sgNE-PmlCRjK-H7LNLeUXN getppr
...
arguments: [ 109522 ]
result: [ 100000000 ]
remote result (not to be trusted): [ 100000000 ]
Мы видим, что субдомены регистрируются в течение 700000 секунд (около восьми дней), и что цена регистрации составляет 100000000ng = 0,1 тестового Грамма на домен, плюс цена за каждый бит и ячейку хранимых данных, которые можно узнать с помощью get-методов getppb
иgetppc
.
Теперь мы хотим, чтобы этот смарт-контракт зарегистрировал наш поддомен. Чтобы сделать это, мы должны создать специальное сообщение из своего кошелька для автоматического DNS смарт-контракта. Предположим, что у нас есть кошелек my_new_wallet
с адресомkQABzslAMKOVwkSkkWfelS1pYSDOSyTcgn0yY_loQvyo_ZgI
. Затем мы запускаем следующий скрипт Fift (из подкаталога crypto/smartcont
исходного дерева):
fift -s auto-dns.fif <auto-dns-smc-addr> add <my-subdomain> <expire-time> owner <my-wallet-addr> cat 1 adnl <my-site-adnl-address>
Например:
$ fift -s auto-dns.fif EQAZC9dW9sDnlI3CbLR5aDIxd_sgNE-PmlCRjK-H7LNLeUXN add 'mysite' 700000 owner kQABzslAMKOVwkSkkWfelS1pYSDOSyTcgn0yY_loQvyo_ZgI cat 1 adnl vcqmha5j3ceve35ammfrhqty46rkhi455otydstv66pk2tmf7rl25f3
Automatic DNS smart contract address = 0:190bd756f6c0e7948dc26cb47968323177fb20344f8f9a50918caf87ecb34b79
kQAZC9dW9sDnlI3CbLR5aDIxd_sgNE-PmlCRjK-H7LNLef5H
Action: add mysite 1583865040
Operation code: 0x72656764
Value: x{2_}
x{BC000C_}
x{AD0145061C1D4EC44A937D0318589E13C73D151D1CEF5D3C0E53AFBCF56A6C2FE2BD00}
x{BFFFF4_}
x{9FD3800039D928061472B84894922CFBD2A5AD2C2419C9649B904FA64C7F2D085F951FA01_}
Internal message body is: x{726567645E5D2E700481CE3F0EDAF2E6D2E8CA00BCCFB9A1_}
x{2_}
x{BC000C_}
x{AD0145061C1D4EC44A937D0318589E13C73D151D1CEF5D3C0E53AFBCF56A6C2FE2BD00}
x{BFFFF4_}
x{9FD3800039D928061472B84894922CFBD2A5AD2C2419C9649B904FA64C7F2D085F951FA01_}
B5EE9C7241010601007800012F726567645E5D2E700481CE3F0EDAF2E6D2E8CA00BCCFB9A10102012002030105BC000C040105BFFFF4050046AD0145061C1D4EC44A937D0318589E13C73D151D1CEF5D3C0E53AFBCF56A6C2FE2BD0000499FD3800039D928061472B84894922CFBD2A5AD2C2419C9649B904FA64C7F2D085F951FA01070E6337D
Query_id is 6799642071046147647 = 0x5E5D2E700481CE3F
(Saved to file dns-msg-body.boc)
Мы видим, что тело сообщения для этого запроса было создано и сохранено в файле dns-msg-body.boc
. Теперь вам нужно отправить платеж с вашего кошелька kQAB..ZgI на автоматический смарт-контракт EQA..UXN вместе с телом сообщения из файла dns-msg-body.boc
, чтобы автоматический смарт-контракт знал, что Вы хотите это сделать. Если ваш кошелек был создан с помощью new-wallet.fif
, вы можете просто использовать аргумент командной строки-B
для wallet.fif
при выполнении этой передачи:
$ fift -s wallet.fif my_new_wallet EQAZC9dW9sDnlI3CbLR5aDIxd_sgNE-PmlCRjK-H7LNLeUXN 1 1.7 -B dns-msg-body.boc
Source wallet address = 0:01cec94030a395c244a49167de952d696120ce4b24dc827d3263f96842fca8fd
kQABzslAMKOVwkSkkWfelS1pYSDOSyTcgn0yY_loQvyo_ZgI
Loading private key from file my_new_wallet.pk
Transferring GR$1.7 to account kQAZC9dW9sDnlI3CbLR5aDIxd_sgNE-PmlCRjK-H7LNLef5H = 0:190bd756f6c0e7948dc26cb47968323177fb20344f8f9a50918caf87ecb34b79 seqno=0x1 bounce=-1
Body of transfer message is x{726567645E5D2E700481CE3F0EDAF2E6D2E8CA00BCCFB9A1_}
x{2_}
x{BC000C_}
x{AD0145061C1D4EC44A937D0318589E13C73D151D1CEF5D3C0E53AFBCF56A6C2FE2BD00}
x{BFFFF4_}
x{9FD3800039D928061472B84894922CFBD2A5AD2C2419C9649B904FA64C7F2D085F951FA01_}
signing message: x{0000000103}
x{62000C85EBAB7B6073CA46E1365A3CB41918BBFD901A27C7CD2848C657C3F659A5BCA32A9F880000000000000000000000000000726567645E5D2E700481CE3F0EDAF2E6D2E8CA00BCCFB9A1_}
x{2_}
x{BC000C_}
x{AD0145061C1D4EC44A937D0318589E13C73D151D1CEF5D3C0E53AFBCF56A6C2FE2BD00}
x{BFFFF4_}
x{9FD3800039D928061472B84894922CFBD2A5AD2C2419C9649B904FA64C7F2D085F951FA01_}
resulting external message: x{8800039D928061472B84894922CFBD2A5AD2C2419C9649B904FA64C7F2D085F951FA050E3817FC01F564AECE810B8077D72E3EE15C81392E8B4AE9CDD0D6575821481C996AE8FFBABA0513F131E10E27C006C6544E99D71E0A6AACF7D02C677342B040000000081C_}
x{62000C85EBAB7B6073CA46E1365A3CB41918BBFD901A27C7CD2848C657C3F659A5BCA32A9F880000000000000000000000000000726567645E5D2E700481CE3F0EDAF2E6D2E8CA00BCCFB9A1_}
x{2_}
x{BC000C_}
x{AD0145061C1D4EC44A937D0318589E13C73D151D1CEF5D3C0E53AFBCF56A6C2FE2BD00}
x{BFFFF4_}
x{9FD3800039D928061472B84894922CFBD2A5AD2C2419C9649B904FA64C7F2D085F951FA01_}
B5EE9C72410207010001170001CF8800039D928061472B84894922CFBD2A5AD2C2419C9649B904FA64C7F2D085F951FA050E3817FC01F564AECE810B8077D72E3EE15C81392E8B4AE9CDD0D6575821481C996AE8FFBABA0513F131E10E27C006C6544E99D71E0A6AACF7D02C677342B040000000081C01019762000C85EBAB7B6073CA46E1365A3CB41918BBFD901A27C7CD2848C657C3F659A5BCA32A9F880000000000000000000000000000726567645E5D2E700481CE3F0EDAF2E6D2E8CA00BCCFB9A10202012003040105BC000C050105BFFFF4060046AD0145061C1D4EC44A937D0318589E13C73D151D1CEF5D3C0E53AFBCF56A6C2FE2BD0000499FD3800039D928061472B84894922CFBD2A5AD2C2419C9649B904FA64C7F2D085F951FA01031E3A74C
(Saved to file wallet-query.boc)
Вы должны заменить «1» на правильный порядковый номер вашего кошелька. После того, как вы получите подписанное входящее сообщение в wallet-query.boc
, адресованное вашему кошельку и дающее указание передать 1,7 тестовых Граммов в автоматический смарт-контракт вместе с описанием вашего нового домена, который нужно зарегистрировать, вы можете загрузить это сообщение с помощью LiteClient, набрав:
> sendfile wallet-query.boc
[ 1][t 1][!testnode] sending query from file wallet-query.boc
[ 3][t 1][!query] external message status is 1
Если все работает правильно, вам придут некоторые изменения из автоматического смарт-контракта в сообщении-подтверждении (плата будет взиматься только за хранение вашего субдомена, за обработку смарт-контракта и отправку сообщений, а остаток будет возвращен), и ваш новый домен будет зарегистрирован:
> last
...
> dnsresolve mysite.temp.ton 1
...
Result for domain 'mysite.temp.ton' category 1
category #1 : (dns_adnl_address adnl_addr:x45061C1D4EC44A937D0318589E13C73D151D1CEF5D3C0E53AFBCF56A6C2FE2BD flags:0)
adnl address 45061C1D4EC44A937D0318589E13C73D151D1CEF5D3C0E53AFBCF56A6C2FE2BD = vcqmha5j3ceve35ammfrhqty46rkhi455otydstv66pk2tmf7rl25f3
Вы можете изменить или продлить этот домен практически таким же образом, сначала создав запрос в файле dns-msg-body.boc
с помощьюauto-dns.fif
, используя такие действия, как update
или prolong
, а затем встроить этот запрос в сообщение из вашего кошелька в автоматический DNS смарт-контракт, используяwallet.fif
или аналогичный скрипт с аргументом командной строки -B dns-msg-body.boc
.