Тестирајте клијента ТОН (Телеграм Опен Нетворк) и нови језик Фифт за паметне уговоре

Пре више од годину дана, постало је познато о плановима Телеграм мессенгер-а да пусти сопствену децентрализовану мрежу Телеграм Отворена мрежа. Тада је постао доступан обимни технички документ, који је наводно написао Николај Дуров и описао структуру будуће мреже. За оне који су пропустили, препоручујем да прочитају моје препричавање овог документа (Део КСНУМКС, Део КСНУМКС; трећи део, авај, још скупља прашину на промаји).

Од тада до пре пар дана није било значајнијих вести о статусу развоја ТОН-а (у једном од незванични канали) веза до странице се није појавила https://test.ton.org/download.htmlгде се налазе:
тон-тест-литецлиент-фулл.тар.кз — извори светлих клијената за ТОН тестну мрежу;
тон-лите-цлиент-тест1.цонфиг.јсон — конфигурациони фајл за повезивање на тестну мрежу;
РЕАДМЕ - информације о монтажи и покретању клијента;
КАКО ДА — упутства корак по корак како да направите паметни уговор користећи клијента;
тон.пдф — ажуриран документ (од 2. марта 2019. године) са техничким прегледом мреже ТОН;
твм.пдф — технички опис ТВМ (ТОН виртуелна машина, ТОН виртуелна машина);
тблкцх.пдф — технички опис блокчејна ТОН;
фифтбасе.пдф — опис новог језика Фифт, дизајнираног за креирање паметних уговора у ТОН-у.

Понављам, није било званичне потврде странице и свих ових докумената из Телеграма, али обим ових материјала их чини прилично вероватним. Покрените објављени клијент на сопствени ризик.

Изградња тестног клијента

Прво, хајде да покушамо да направимо и покренемо тест клијента - на срећу, РЕАДМЕ детаљно описује овај једноставан процес. Урадићу ово користећи мацОС 10.14.5 као пример; не могу да гарантујем за успех изградње на другим системима.

  1. Преузмите и распакујте изворна архива. Важно је да преузмете најновију верзију јер у овој фази није загарантована компатибилност уназад.

  2. Уверите се да су најновије верзије маке, цмаке (верзија 3.0.2 или новија), ОпенССЛ (укључујући Ц датотеке заглавља), г++ или цланг инсталиране на систему. Нисам морао ништа да инсталирам, све се одмах спојило.

  3. Претпоставимо да су извори распаковани у фасциклу ~/lite-client. Одвојено од њега, направите празну фасциклу за састављени пројекат (нпр. ~/liteclient-build), а од њега (cd ~/liteclient-build) позовите команде:

    cmake ~/lite-client
    cmake --build . --target test-lite-client

    Тестирајте клијента ТОН (Телеграм Опен Нетворк) и нови језик Фифт за паметне уговоре

    Да бисмо направили тумач за језик Фифт за паметне уговоре (више о томе у наставку), такође позивамо

    cmake --build . --target fift

  4. Преузмите тренутни конфигурациони фајл да се повеже на тестну мрежу и стави у фасциклу са склопљеним клијентом.

  5. Завршити, можете покренути клијента:

    ./test-lite-client -C ton-lite-client-test1.config.json

Ако је све урађено исправно, требало би да видите нешто овако:

Тестирајте клијента ТОН (Телеграм Опен Нетворк) и нови језик Фифт за паметне уговоре

Као што видимо, постоји неколико доступних команди:
help — приказати ову листу команди;
quit - Изаћи;
time — приказати тренутно време на серверу;
status — приказати статус везе и локалне базе података;
last — ажурирање стања блокчејна (преузмите последњи блок). Важно је да покренете ову наредбу пре било каквих захтева да бисте били сигурни да видите тренутно стање мреже.
sendfile <filename> — отпремите локалну датотеку на ТОН мрежу. Тако долази до интеракције са мрежом – укључујући, на пример, креирање нових паметних уговора и захтеве за трансфер средстава између налога;
getaccount <address> — прикажи тренутни (у време извршења наредбе) last) статус рачуна са наведеном адресом;
privkey <filename> — учитајте приватни кључ из локалне датотеке.

Ако при покретању клијента проследите фасциклу користећи опцију -D, онда ће додати последњи блок мастер ланца у њега:

./test-lite-client -C ton-lite-client-test1.config.json -D ~/ton-db-dir

Сада можемо да пређемо на занимљивије ствари - научите језик Фифт, покушајте да саставите паметни уговор (на пример, направите пробни новчаник), отпремите га на мрежу и покушајте да пребаците средства између налога.

Лангуаге Фифт

Из документа фифтбасе.пдф можете сазнати да је Телеграм тим креирао нови стек језик за креирање паметних уговора Пето (очигледно из броја пети, слично Фортху, језику са којим Фифтх има много заједничког).

Документ је прилично обимни, 87 страница, и нећу га детаљно препричавати у оквиру овог чланка (барем зато што га сам још нисам прочитао :). Фокусираћу се на главне тачке и дати неколико примера кода на овом језику.

На основном нивоу, Фифтова синтакса је прилично једноставна: њен код се састоји од речи, обично одвојене размацима или преломима реда (посебан случај: неке речи не захтевају сепаратор иза себе). Било који реч је низ знакова који се разликује од великих и малих слова који одговара одређеном одређивање (отприлике, шта преводилац треба да уради када наиђе на ову реч). Ако не постоји дефиниција речи, тумач покушава да је рашчлани као број и стави на стек. Узгред, бројеви су овде - одједном - 257-битни цели бројеви, а разломака уопште нема - тачније, одмах се претварају у пар целих бројева, чинећи бројилац и именилац рационалног разломка.

Речи имају тенденцију да комуницирају са вредностима на врху гомиле. Посебна врста речи - префикс — не користи стек, већ следеће знакове из изворне датотеке. На пример, овако се имплементирају литерали стрингова - знак наводника (") је реч префикса која тражи следећи (завршни) наводник и гура низ између њих на стек. Једнолинијски се понашају на исти начин (//) и вишелинијски (/*) коментари.

Ту се завршава готово целокупна унутрашња структура језика. Све остало (укључујући контролне конструкције) је дефинисано као речи (било интерне, као што су аритметичке операције и дефиниција нових речи; или дефинисано у „стандардној библиотеци“ Fift.fif, који се налази у фасцикли crypto/fift у изворима).

Једноставан пример програма у Фифту:

{ dup =: x dup * =: y } : setxy
3 setxy x . y . x y + .
7 setxy x . y . x y + .

Први ред дефинише нову реч setxy (обратите пажњу на префикс {, који ствара блок пре завршног } и префикс :, што заправо дефинише реч). setxy узима број са врха стека, дефинише га (или редефинише) као глобалног константан x, а квадрат овог броја као константа y (С обзиром на то да се вредности константи могу редефинисати, радије бих их назвао променљивим, али следим конвенцију именовања у језику).

Следећа два реда стављају број на стек и позивају setxy, тада се приказују вредности константи x, y (реч се користи за излаз .), обе константе се стављају на стек, сабирају, а резултат се такође штампа. Као резултат видећемо:

3 9 12 ok
7 49 56 ok

(Лину „ок“ преводилац штампа када заврши обраду текуће линије у режиму интерактивног уноса)

Па, комплетан пример кода:

"Asm.fif" include

-1 constant wc  // create a wallet in workchain -1 (masterchain)

// Create new simple wallet
<{  SETCP0 DUP IFNOTRET INC 32 THROWIF  // return if recv_internal, fail unless recv_external
    512 INT LDSLICEX DUP 32 PLDU   // sign cs cnt
    c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS  // sign cs cnt cnt' pubk
    s1 s2 XCPU            // sign cs cnt pubk cnt' cnt
    EQUAL 33 THROWIFNOT   // ( seqno mismatch? )
    s2 PUSH HASHSU        // sign cs cnt pubk hash
    s0 s4 s4 XC2PU        // pubk cs cnt hash sign pubk
    CHKSIGNU              // pubk cs cnt ?
    34 THROWIFNOT         // signature mismatch
    ACCEPT
    SWAP 32 LDU NIP 
    DUP SREFS IF:<{
      8 LDU LDREF         // pubk cnt mode msg cs
      s0 s2 XCHG SENDRAWMSG  // pubk cnt cs ; ( message sent )
    }>
    ENDS
    INC NEWC 32 STU 256 STU ENDC c4 POPCTR
}>c
// code
<b 0 32 u, 
   newkeypair swap dup constant wallet_pk 
   "new-wallet.pk" B>file
   B, 
b> // data
// no libraries
<b b{00110} s, rot ref, swap ref, b>  // create StateInit
dup ."StateInit: " <s csr. cr
dup hash dup constant wallet_addr
."new wallet address = " wc . .": " dup x. cr
wc over 7 smca>$ type cr
256 u>B "new-wallet.addr" B>file
<b 0 32 u, b>
dup ."signing message: " <s csr. cr
dup hash wallet_pk ed25519_sign_uint rot
<b b{1000100} s, wc 8 i, wallet_addr 256 u, 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
"new-wallet-query.boc" tuck B>file
."(Saved to file " type .")" cr

Ова датотека застрашујућег изгледа је за креирање паметног уговора - биће смештена у датотеку new-wallet-query.boc после извршења. Имајте на уму да се овде користи други асемблерски језик за ТОН виртуелну машину (нећу се детаљније задржавати на томе), чија упутства ће бити постављена на блок ланцу.

Дакле, асемблер за ТВМ је написан у Фифт-у - извори овог асемблера су у датотеци crypto/fift/Asm.fif и повезани су на почетку горњег дела кода.

Шта да кажем, очигледно Николај Дуров једноставно воли да ствара нове програмске језике :)

Креирање паметног уговора и интеракција са ТОН-ом

Дакле, претпоставимо да смо саставили ТОН клијента и Фифт тумача као што је горе описано и да смо се упознали са језиком. Како сада направити паметни уговор? Ово је описано у датотеци КАКО ДА, у прилогу извора.

Рачуни у ТОН

Као што сам описао у ТОН рецензија, ова мрежа садржи више од једног блокчејна – постоји један заједнички, тзв. „главни ланац“, као и произвољан број додатних „радних ланаца“, идентификованих 32-битним бројем. Главни ланац има идентификатор -1; поред њега, може се користити и „основни“ радни ланац са идентификатором 0. Сваки радни ланац може имати сопствену конфигурацију. Интерно, сваки радни ланац је подељен на шардланове, али ово је детаљ имплементације који не треба имати на уму.

У оквиру једног радног ланца се чувају многи налози који имају сопствене идентификаторе аццоунт_ид. За главни ланац и нулти радни ланац, они су дуги 256 бита. Дакле, идентификатор налога је написан, на пример, овако:

-1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d

Ово је „сирови“ формат: прво ИД радног ланца, затим двотачка и ИД налога у хексадецималном запису.

Поред тога, постоји скраћени формат - број радног ланца и адреса налога су кодирани у бинарном облику, додаје им се контролни збир, а све ово је кодирано у Басе64:

Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb

Познавајући овај формат записа, можемо затражити тренутно стање налога преко тестног клијента користећи команду

getaccount -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d

Добићемо нешто овако:

[ 3][t 2][1558746708.815218925][test-lite-client.cpp:631][!testnode]    requesting account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D
[ 3][t 2][1558746708.858564138][test-lite-client.cpp:652][!testnode]    got account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D with respect to blocks (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F and (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F
account state is (account
  addr:(addr_std
    anycast:nothing workchain_id:-1 address:x8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D)
  storage_stat:(storage_info
    used:(storage_used
      cells:(var_uint len:1 value:3)
      bits:(var_uint len:2 value:539)
      public_cells:(var_uint len:0 value:0)) last_paid:0
    due_payment:nothing)
  storage:(account_storage last_trans_lt:74208000003
    balance:(currencies
      grams:(nanograms
        amount:(var_uint len:7 value:999928362430000))
      other:(extra_currencies
        dict:hme_empty))
    state:(account_active
      (
        split_depth:nothing
        special:nothing
        code:(just
          value:(raw@^Cell 
            x{}
             x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54}
            ))
        data:(just
          value:(raw@^Cell 
            x{}
             x{0000000D}
            ))
        library:hme_empty))))
x{CFF8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D2068086C000000000000000451C90E00DC0E35B7DB5FB8C134_}
 x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54}
 x{0000000D}

Видимо структуру која је ускладиштена у ДХТ-у наведеног радног ланца. На пример, на терену storage.balance је стање текућег рачуна, у storage.state.code - код паметног уговора, и у storage.state.data - њене тренутне податке. Имајте на уму да је ТОН складиште података - Ћелија, ћелије - налик стаблу, свака ћелија може имати и своје податке и подређене ћелије. Ово је приказано као увлачење у последњим редовима.

Изградња паметног уговора

Сада хајде да сами направимо такву структуру (зове се БОЦ - врећа ћелија) користећи језик Фифт. На срећу, не морате сами да пишете паметни уговор - у фасцикли crypto/block постоји датотека из изворне архиве new-wallet.fif, што ће нам помоћи да направимо нови новчаник. Копирајмо га у фасциклу са састављеним клијентом (~/liteclient-build, ако сте следили упутства изнад). Навео сам њен садржај изнад као пример кода на Фифту.

Извршите ову датотеку на следећи начин:

./crypto/fift -I"<source-directory>/crypto/fift" new-wallet.fif

Овде <source-directory> мора бити замењен путањом до распакованих извора (симбол „~“ се, нажалост, овде не може користити, потребна је пуна путања). Уместо да користите кључ -I можете дефинисати променљиву окружења FIFTPATH и стави овај пут у њега.

Пошто смо покренули Фифт са именом датотеке new-wallet.fif, извршиће га и изаћи. Ако изоставите име датотеке, можете играти са интерпретатором интерактивно.

Након извршења, нешто попут овога би требало да се прикаже у конзоли:

StateInit: x{34_}
 x{FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54}
 x{0000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B}

new wallet address = -1 : 4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 
0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ
signing message: x{00000000}

External message for initialization is x{89FEE120E20C7E953E31546F64C23CD654002C1AA919ADD24DB12DDF85C6F3B58AE41198A28AD8DAF3B9588E7A629252BA3DB88F030D00BC1016110B2073359EAC3C13823C53245B65D056F2C070B940CDA09789585935C7ABA4D2AD4BED139281CFA1200000001_}
 x{FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54}
 x{0000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B}

B5EE9C724104030100000000D60002CF89FEE120E20C7E953E31546F64C23CD654002C1AA919ADD24DB12DDF85C6F3B58AE41198A28AD8DAF3B9588E7A629252BA3DB88F030D00BC1016110B2073359EAC3C13823C53245B65D056F2C070B940CDA09789585935C7ABA4D2AD4BED139281CFA1200000001001020084FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED5400480000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B6290698B
(Saved to file new-wallet-query.boc)

То значи да је новчаник са ИД -1:4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 (или, шта је исто, 0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ) успешно креиран. Одговарајући код ће бити у датотеци new-wallet-query.boc, његова адреса је у new-wallet.addr, а приватни кључ је унутра new-wallet.pk (будите опрезни - поновно покретање скрипте ће преписати ове датотеке).

Наравно, мрежа ТОН још не зна за овај новчаник, он се чува само у облику ових датотека. Сада га треба учитати на мрежу. Међутим, проблем је у томе што за креирање паметног уговора морате платити провизију, а стање на вашем рачуну је и даље нула.

У радном режиму, овај проблем ће се решити куповином грама на берзи (или пребацивањем из другог новчаника). Па, у тренутном режиму тестирања, направљен је посебан паметни уговор од којег можете само тако да тражите до 20 грама.

Генерисање захтева за туђи паметни уговор

Дајемо захтев паметном уговору који овако распоређује граме лево и десно. У истом фолдеру crypto/block пронађи датотеку testgiver.fif:

// "testgiver.addr" file>B 256 B>u@ 
0x8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d
dup constant wallet_addr ."Test giver address = " x. cr

0x4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2
constant dest_addr

-1 constant wc
0x00000011 constant seqno

1000000000 constant Gram
{ Gram swap */ } : Gram*/

6.666 Gram*/ constant amount

// b x --> b'  ( serializes a Gram amount )
{ -1 { 1+ 2dup 8 * ufits } until
  rot over 4 u, -rot 8 * u, } : Gram, 

// create a message (NB: 01b00.., b = bounce)
<b b{010000100} s, wc 8 i, dest_addr 256 u, amount Gram, 0 9 64 32 + + 1+ 1+ u, "GIFT" $, b>
<b seqno 32 u, 1 8 u, swap ref, b>
dup ."enveloping message: " <s csr. cr
<b b{1000100} s, wc 8 i, wallet_addr 256 u, 0 Gram, b{00} s,
   swap <s s, b>
dup ."resulting external message: " <s csr. cr
2 boc+>B dup Bx. cr
"wallet-query.boc" B>file

Такође ћемо га сачувати у фасцикли са састављеним клијентом, али ћемо исправити пети ред - пре реда “constant dest_addr„. Заменимо је адресом новчаника који сте раније креирали (пуна, а не скраћена). Нема потребе да пишете „-1:“ на почетку, уместо тога ставите „0к“ на почетак.

Такође можете променити линију 6.666 Gram*/ constant amount — ово је количина у грамима коју тражите (не више од 20). Чак и ако наведете цео број, оставите децимални зарез.

На крају, треба да исправите линију 0x00000011 constant seqno. Први број овде је тренутни редни број, који се чува на рачуну за издавање грама. Одакле могу да га набавим? Као што је горе наведено, покрените клијент и покрените:

last
getaccount -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d

На самом крају, подаци о паметном уговору ће садржати

...
x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54}
 x{0000000D}

Број 0000000Д (ваш ће бити већи) је редни број који се мора заменити у testgiver.fif.

То је то, сачувајте датотеку и покрените (./crypto/fift testgiver.fif). Излаз ће бити датотека wallet-query.boc. Ово је оно што се формира сообщение на туђи паметни уговор - захтев „пребаците толико грама на тај и тај налог“.

Користећи клијент, отпремамо га на мрежу:

> sendfile wallet-query.boc
[ 1][t 1][1558747399.456575155][test-lite-client.cpp:577][!testnode]    sending query from file wallet-query.boc
[ 3][t 2][1558747399.500236034][test-lite-client.cpp:587][!query]   external message status is 1

Ако сада позовете last, а затим поново затражимо статус рачуна са којег смо тражили граме, онда би требало да видимо да му је редни број повећан за један - то значи да је послао новац на наш рачун.

Остаје последњи корак - преузмите код нашег новчаника (његово стање је већ попуњено, али без кода паметног уговора нећемо моћи да управљамо њиме). Ми спроводимо sendfile new-wallet-query.boc - и то је то, имате свој новчаник у ТОН мрежи (чак и ако је за сада само пробни).

Креирање одлазних трансакција

За пренос новца са стања креираног рачуна постоји датотека crypto/block/wallet.fif, који такође треба ставити у фасциклу са склопљеним клијентом.

Слично као у претходним корацима, потребно је да прилагодите износ који преносите, адресу примаоца (дест_аддр) и секвенцу вашег новчаника (једнака је 1 након иницијализације новчаника и повећава се за 1 након сваке одлазне трансакције - можете видите тако што ћете затражити статус вашег налога) . За тестове можете користити, на пример, мој новчаник - 0x4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2.

На почетку (./crypto/fift wallet.fif) скрипта ће узети адресу вашег новчаника (одакле преносите) и његов приватни кључ из датотека new-wallet.addr и new-wallet.pk, а примљена порука ће бити написана на new-wallet-query.boc.

Као и раније, да бисте директно извршили трансакцију, позовите sendfile new-wallet-query.boc у клијенту. Након тога, не заборавите да ажурирате стање блокчејна (last) и проверите да ли су се стање и секвенца нашег новчаника променили (getaccount <account_id>).

Тестирајте клијента ТОН (Телеграм Опен Нетворк) и нови језик Фифт за паметне уговоре

То је све, сада можемо да креирамо паметне уговоре у ТОН-у и да им шаљемо захтеве. Као што видите, тренутна функционалност је већ довољна да се, на пример, направи љубазнији новчаник са графичким интерфејсом (међутим, очекује се да ће он већ постати доступан као део месинџера).

Само регистровани корисници могу учествовати у анкети. Пријавите се, Добродошао си.

Да ли сте заинтересовани да наставите чланке са анализом ТОН-а, ТВМ-а, Фифта?

  • Да, чекам завршетак серије чланака са општим прегледом ТОН-а

  • Да, занимљиво је прочитати више о језику Фифт

  • Да, желим да сазнам више о ТОН виртуелној машини и асемблеру за њу

  • Не, ништа од овога није интересантно

Гласало је 39 корисника. Уздржано је било 12 корисника.

Шта мислите о Телеграмовим плановима да покрене ТОН?

  • Полажем велике наде у овај пројекат

  • Само са интересовањем пратим њен развој.

  • Скептичан сам и сумњам у његов успех.

  • Склон сам да ову иницијативу сматрам неуспешном и непотребном за широке масе

Гласало је 47 корисника. Уздржано је било 12 корисника.

Извор: ввв.хабр.цом

Додај коментар