Sigurno ste čuli da Telegram . No, mogli ste propustiti vijest da je Telegram za implementaciju jednog ili više pametnih ugovora za ovu platformu.
Tim Serokell s bogatim iskustvom u razvoju velikih blockchain projekata nije mogao ostati po strani. Delegirali smo pet zaposlenika na natječaj, a već nakon dva tjedna osvojili su prvo mjesto pod (ne)skromnim lažnim imenom Sexy Chameleon. U ovom članku ću vam ispričati kako su to uspjeli. Nadamo se da ćete u sljedećih deset minuta pročitati zanimljivu priču, a u najboljem slučaju pronaći nešto korisno što možete primijeniti u svom radu.
No, počnimo s malim uronjenjem u kontekst.
Natječaj i njegovi uvjeti
Dakle, osnovni zadaci sudionika bili su implementacija jednog ili više predloženih pametnih ugovora, kao i davanje prijedloga za poboljšanje ekosustava TON. Natječaj se održavao od 24. rujna do 15. listopada, a rezultati su objavljeni tek 15. studenog. Prilično dugo, s obzirom na to da je Telegram tijekom tog vremena uspio provesti i objaviti rezultate natječaja za dizajn i za razvoj aplikacija u C++ za testiranje i ocjenjivanje kvalitete VoIP poziva u Telegramu.
Odabrali smo dva pametna ugovora s popisa koji su predložili organizatori. Za jedan od njih koristili smo alate koji se distribuiraju zajedno s TON, a drugi smo implementirali na novom jeziku, koje su naši inženjeri razvili posebno za TON i ugrađen je u Haskell.
Izbor funkcionalnog programskog jezika nije slučajan. U našem često objašnjavamo zašto smatramo složenost funkcionalnih jezika velikim pretjerivanjem i zašto u cjelini više volimo njih u odnosu na objektno orijentirane. Usput, tu se može pronaći i .
Zašto smo uopće odlučili sudjelovati
Ukratko, zato što je naša specijalizacija neobični i složeni projekti, koji zahtijevaju posebne vještine i često predstavljaju znanstvenu vrijednost za IT zajednicu. Toplo podržavamo open-source razvoj i bavimo se njegovom popularizacijom, kao i suradnjom s vodećim sveučilištima u Rusiji u području računalnih znanosti i matematike.
Zanimljive zadaće natjecanja i povezanost s nama dragim projektom Telegram same po sebi su bile odlična motivacija, a nagradni fond je bio dodatni podsticaj. 🙂
Istraživanje blockchaina TON
Pomno pratimo nova dostignuća u blockchainu, umjetnoj inteligenciji i strojnom učenju te se trudimo ne propustiti nijedno značajno izdanje u svakoj od oblasti u kojima radimo. Stoga je do trenutka početka natjecanja naš tim već bio upoznat s idejama iz . Međutim, prije nego što smo počeli raditi s TON-om, nismo analizirali tehničku dokumentaciju i stvarni izvorni kod platforme, pa je prvi korak bio prilično očit — temeljito istraživanje službene dokumentacije na i u .
Do početka natjecanja kod je već bio objavljen, pa smo, da bismo uštedjeli vrijeme, odlučili potražiti vodič ili sažetak koji su napisali korisnici. Nažalost, to nije dalo rezultate — osim upute za izgradnju platforme na Ubuntu, nismo pronašli druge materijale.
Istražena dokumentacija bila je temeljito obrađena, ali je bilo teško čitati je u nekim trenucima. Prilično često smo se morali vraćati određenim točkama i prelaziti iz visokoapstraktnih opisa na nisko razine detalja implementacije.
Bilo bi jednostavnije da specifikacija uopće nije imala detaljna objašnjenja implementacije. Informacije o tome kako virtualna mašina predstavlja svoju stogove više zbunjuju programere koji kreiraju pametne ugovore za platformu TON nego što im pomažu.
Nix: okupljamo projekt
U Serokellu smo veliki obožavatelji . Gradimo naše projekte i implementiramo ih uz pomoć , a na svim našim poslužiteljima je instaliran . Zbog toga su sve naše gradnje reproducibilne i rade na bilo kojem operativnom sustavu na kojem se može instalirati Nix.
Stoga smo započeli s kreiranjem . Uz njegovu pomoć, kompilacija TON-a je maksimalno jednostavna:
$ cd ~/.config/nixpkgs/overlays && git clone https://github.com/serokell/ton.nix
$ cd /path/to/ton/repo && nix-shell
[nix-shell]$ cmakeConfigurePhase && makePrimijetite, ne trebate instalirati nikakve ovisnosti. Nix će čarobno obaviti sve za vas bez obzira na to koristite li NixOS, Ubuntu ili macOS.
Programiranje za TON
Kod pametnih ugovora u TON Network radi na TON Virtual Machine (TVM). TVM je složenija od većine drugih virtualnih mašina i ima vrlo zanimljive funkcionalnosti, na primjer, može raditi s nastavcima (continuations) i referencama na podatke.
Štoviše, ekipa iz TON-a stvorila je tri nova programska jezika:
(očigledno, od broja — univerzalni stogovski programski jezik sličan . Njegova supermoć je mogućnost interakcije s TVM-om.
FunC — jezik za pametne ugovore koji nalikuje i prevodi se u još jedan jezik — Fift Assembler.
Fift Assembler — Fift knjižnica za generiranje binarnog izvršnog koda za TVM. Fift Assembler nema prevoditelj. To je .
Naši natjecateljski radovi
Napokon, došlo je vrijeme da pogledamo rezultate našeg truda.
Asinkroni platni kanal
Platni kanal (payment channel) — pametni ugovor koji omogućava dvjema korisnicima slanje uplata izvan blockchaina. Na taj način se štede ne samo novci (nema naknade), već i vrijeme (ne morate čekati da se obradi sljedeći blok). Uplate mogu biti bilo kakve male i događati se koliko god često je potrebno. Pri tome stranke ne moraju međusobno vjerovati jer pravednost konačnog obračuna jamči pametni ugovor.
Pronašli smo prilično jednostavno rješenje za problem. Dvije strane mogu razmjenjivati potpisane poruke, od kojih svaka sadrži dva broja — ukupni iznos koji su platili svaki od sudionika. Ova dva broja djeluju kao u tradicionalnim distribuiranim sustavima i određuju redoslijed 'dogodilo se prije' na transakcijama. Koristeći ove podatke, ugovor će moći riješiti svaki mogući sukob.
Zapravo, za implementaciju ove ideje dovoljno je i jedan broj, no ostavili smo oba, jer smo tako mogli stvoriti korisničko sučelje koje je lakše koristiti. Osim toga, odlučili smo uključiti u svaku poruku veličinu uplate. Bez nje, ako se poruka iz nekog razloga izgubi, tada, iako su svi iznosi i konačni obračun točni, korisnik možda neće primijetiti gubitak.
Kako bismo provjerili našu ideju, tražili smo primjere korištenja tako jednostavnog i sažetog protokola za platne kanale. Na naše iznenađenje, pronašli smo samo dva:
- sličnog pristupa, samo za slučaj jednostranog kanala.
- , u kojem je opisana ista ideja kao i kod nas, samo bez objašnjenja mnogih važnih detalja, kao što su opća ispravnost i postupak rješavanja sukoba.
Postalo je jasno da ima smisla detaljno opisati naš protokol, s posebnim naglaskom na njegovu ispravnost. Nakon nekoliko iteracija, specifikacija je bila gotova, a sada je možete .
Implementirali smo ugovor na FunC, a alat za korištenje naredbenog retka za interakciju s našim ugovorom potpuno smo napisali na Fiftu, kako su preporučili organizatori. Mogli smo odabrati bilo koji drugi jezik za naš CLI, ali nas je zanimalo isprobati upravo Fift, kako bismo vidjeli kako će se pokazati na djelu.
Iskreno, radeći s Fiftom, nismo vidjeli uvjerljive razloge za preferirati ovaj jezik u odnosu na popularne i aktivno korištene jezike s razvijenim alatima i bibliotekama. Programiranje na staklenom jeziku prilično je neugodno, jer morate stalno imati na umu što se nalazi u stogu, a kompajler s tim nikako ne pomaže.
Stoga je jedino opravdanje za postojanje Fita, prema našem mišljenju, njegova uloga kao jezika domaćina za Fift Assembler. No nije li bilo bolje ugraditi TVM assembler u neki postojeći jezik, a ne izmišljati novi za ovu, u suštini jedinu, svrhu?
TVM Haskell eDSL
Sada je došlo vrijeme da pričamo o našem drugom pametnom ugovoru. Odlučili smo razviti novčanik s višestrukim potpisivanjem, ali bi pisanje još jednog pametnog ugovora na FunC bilo previše dosadno. Željeli smo dodati neku posebnu značajku, a to je bio naš vlastiti assembler jezik za TVM.
Baš kao i Fift Assembler, naš novi jezik je ugrađen, samo što smo za domaćina umjesto Fifta odabrali Haskell, što nam je omogućilo da maksimalno iskoristimo njegov napredni sustav tipova. Kada radite s pametnim ugovorima, gdje cijena i najmanje greške može biti vrlo visoka, statička tipizacija, prema našem mišljenju, predstavlja veliku prednost.
Kako bismo prikazali kako izgleda TVM assembler integriran u Haskell, implementirali smo standardni novčanik. Evo nekoliko stvari na koje treba obratiti pažnju:
- Ova funkcija se sastoji od jedne funkcije, ali možete koristiti koliko god želite. Kada definirate novu funkciju na jeziku domaćina (tj. Haskell), naš eDSL vam omogućuje da odaberete želite li da ona postane posebna podprograma u TVM-u ili da se jednostavno integriše na mjesto poziva.
- Kao i u Haskellu, funkcije imaju tipove koji se provjeravaju tijekom kompajliranja. U našem eDSL tipu ulaza funkcije je tip stoga koji funkcija očekuje, a tip rezultata je tip stoga koji će nastati nakon poziva.
- U kodu postoje anotacije
stacktype, koje opisuju očekivani tip stoga na mjestu poziva. U originalnom ugovoru novčanika to su bili samo komentari, ali u našem eDSL-u oni su zapravo dio koda i provjeravaju se tijekom kompajliranja. Mogu poslužiti kao dokumentacija ili tvrdnje koje pomažu programeru da pronađe problem ako se tip stoga promijeni tijekom izmjene koda. Naravno, takve anotacije ne utječu na performanse tijekom izvođenja, jer se za njih ne generira nikakav TVM kod. - Ovo je i dalje prototip napisan za dvije sedmice, stoga još puno posla ostaje na projektu. Na primjer, svi primjeri klasa koje vidite u donjem kodu trebaju se generirati automatski.
Evo kako izgleda implementacija multisig novčanika u našem eDSL-u:
main :: IO ()
main = putText $ pretty $ declProgram procedures methods
where
procedures =
[ ("recv_external", decl recvExternal)
, ("recv_internal", decl recvInternal)
]
methods =
[ ("seqno", declMethod getSeqno)
]
data Storage = Storage
{ sCnt :: Word32
, sPubKey :: PublicKey
}
instance DecodeSlice Storage where
type DecodeSliceFields Storage = [PublicKey, Word32]
decodeFromSliceImpl = do
decodeFromSliceImpl @Word32
decodeFromSliceImpl @PublicKey
instance EncodeBuilder Storage where
encodeToBuilder = do
encodeToBuilder @Word32
encodeToBuilder @PublicKey
data WalletError
= SeqNoMismatch
| SignatureMismatch
deriving (Eq, Ord, Show, Generic)
instance Exception WalletError
instance Enum WalletError where
toEnum 33 = SeqNoMismatch
toEnum 34 = SignatureMismatch
toEnum _ = error "Uknown MultiSigError id"
fromEnum SeqNoMismatch = 33
fromEnum SignatureMismatch = 34
recvInternal :: '[Slice] :-> '[]
recvInternal = drop
recvExternal :: '[Slice] :-> '[]
recvExternal = do
decodeFromSlice @Signature
dup
preloadFromSlice @Word32
stacktype @[Word32, Slice, Signature]
-- cnt cs sign
pushRoot
decodeFromCell @Storage
stacktype @[PublicKey, Word32, Word32, Slice, Signature]
-- pk cnt' cnt cs sign
xcpu @1 @2
stacktype @[Word32, Word32, PublicKey, Word32, Slice, Signature]
-- cnt cnt' pk cnt cs sign
equalInt >> throwIfNot SeqNoMismatch
push @2
sliceHash
stacktype @[Hash Slice, PublicKey, Word32, Slice, Signature]
-- hash pk cnt cs sign
xc2pu @0 @4 @4
stacktype @[PublicKey, Signature, Hash Slice, Word32, Slice, PublicKey]
-- pubk sign hash cnt cs pubk
chkSignU
stacktype @[Bool, Word32, Slice, PublicKey]
-- ? cnt cs pubk
throwIfNot SignatureMismatch
accept
swap
decodeFromSlice @Word32
nip
dup
srefs @Word8
pushInt 0
if IsEq
then ignore
else do
decodeFromSlice @Word8
decodeFromSlice @(Cell MessageObject)
stacktype @[Slice, Cell MessageObject, Word8, Word32, PublicKey]
xchg @2
sendRawMsg
stacktype @[Slice, Word32, PublicKey]
endS
inc
encodeToCell @Storage
popRoot
getSeqno :: '[] :-> '[Word32]
getSeqno = do
pushRoot
cToS
preloadFromSlice @Word32Potpuni izvorni kod našeg eDSL-a i ugovora o novčaniku s višesigurnošću možete pronaći u A detaljnije o ugrađenim jezicima naš kolega Georgij Agapov.
Zaključci o natjecanju i TON
Ukupno naše je radilo 380 sati (uključujući upoznavanje s dokumentacijom, sastancima i samim razvojem). U natjecateljskom projektu sudjelovalo je pet programera: CTO, tim lider, stručnjaci za blokchain platforme i programeri softvera na Haskellu.
Resursi za sudjelovanje u natjecanju pronašli smo lako, jer duh hackathona, bliska timska suradnja i potreba za brzim uranjanjem u aspekte novih tehnologija - uvijek je uzbudljivo. Nekoliko neprospavanih noći u potrazi za postizanjem maksimalnog rezultata unutar ograničenih resursa nadoknađuje se neprocjenjivim iskustvom i izvrsnim uspomenama. Osim toga, rad na sličnim zadacima uvijek je dobar test procesa unutar tvrtke, jer je izuzetno teško postići zaista dostojne rezultate bez savršeno usklađene unutarnje suradnje.
Osim lirskih aspekata: bili smo impresionirani radom tima TON. Uspjeli su izgraditi složen, lijep i, što je najvažnije, funkcionalan sustav. TON se pokazao kao platforma s velikim potencijalom. Međutim, da bi se ovaj ekosustav razvijao, potrebno je učiniti još mnogo, kako s gledišta korištenja u blockchain projektima, tako i s gledišta unapređenja razvojnih alata. Ponosni smo što smo sada dio ovog procesa.
Ako ste nakon čitanja ovog članka ostali s pitanjima ili ste dobili ideje o tome kako primijeniti TON za rješavanje vaših zadataka, — rado ćemo podijeliti iskustvo.
Izvor: habr.com
