Tikriausiai girdėjote tą „Telegram“. . Bet galbūt praleidote naujieną, kurią neseniai gavote „Telegram“. vienos ar kelių išmaniųjų sutarčių šiai platformai įgyvendinimui.
Serokell komanda, turinti didelę patirtį kuriant didelius blockchain projektus, negalėjo likti nuošalyje. Į konkursą delegavome penkis darbuotojus, o po dviejų savaičių jie jame užėmė pirmąją vietą (ne)kukliu atsitiktiniu slapyvardžiu Sexy Chameleon. Šiame straipsnyje kalbėsiu apie tai, kaip jie tai padarė. Tikimės, kad per ateinančias dešimt minučių bent jau perskaitysite įdomią istoriją, o daugiausia joje rasite ką nors naudingo, ką galėsite pritaikyti savo darbe.
Bet pradėkime nuo konteksto.
Konkurencija ir jos sąlygos
Taigi pagrindinės dalyvių užduotys buvo vienos ar kelių siūlomų išmaniųjų sutarčių įgyvendinimas, taip pat pasiūlymų teikimas TON ekosistemai tobulinti. Konkursas vyko rugsėjo 24 – spalio 15 dienomis, o rezultatai buvo paskelbti tik lapkričio 15 dieną. Gana ilgai, turint omenyje, kad per tą laiką „Telegram“ sugebėjo surengti ir paskelbti konkursų dėl programų projektavimo ir kūrimo C++, skirtų „Telegram“ VoIP skambučių kokybei išbandyti ir įvertinti.
Iš organizatorių pasiūlyto sąrašo pasirinkome dvi išmaniąsias sutartis. Vienam iš jų naudojome su TON platinamus įrankius, o antrasis buvo įdiegtas nauja kalba, kurią mūsų inžinieriai sukūrė specialiai TON ir įmontuota į Haskell.
Funkcinė programavimo kalba pasirinkta neatsitiktinai. Mūsų Mes dažnai kalbame apie tai, kodėl manome, kad funkcinių kalbų sudėtingumas yra didžiulis perdėtas ir kodėl mes dažniausiai jas renkame, o ne į objektus orientuotas kalbas. Beje, jame taip pat yra .
Kodėl net nusprendėme dalyvauti?
Trumpai tariant, nes mūsų specializacija yra nestandartiniai ir sudėtingi projektai, reikalaujantys specialių įgūdžių ir dažnai turintys mokslinę vertę IT bendruomenei. Mes tvirtai remiame atvirojo kodo plėtrą ir užsiimame jo populiarinimu, taip pat bendradarbiaujame su pirmaujančiais Rusijos universitetais informatikos ir matematikos srityse.
Įdomios konkurso užduotys ir įsitraukimas į mūsų mylimą Telegram projektą savaime buvo puiki motyvacija, tačiau prizinis fondas tapo papildoma paskata. 🙂
TON blokų grandinės tyrimas
Atidžiai stebime naujus blockchain, dirbtinio intelekto ir mašininio mokymosi pokyčius ir stengiamės nepraleisti nė vieno reikšmingo leidinio kiekvienoje srityje, kurioje dirbame. Todėl prasidėjus konkursui mūsų komanda jau buvo susipažinusi su idėjomis iš . Tačiau prieš pradėdami dirbti su TON neanalizavome techninės dokumentacijos ir tikrojo platformos šaltinio kodo, todėl pirmasis žingsnis buvo gana akivaizdus – nuodugnus oficialios dokumentacijos apie ir .
Prasidėjus konkursui kodas jau buvo paskelbtas, todėl taupydami laiką nusprendėme paieškoti vadovo ar santraukos, kurią parašė vartotojų. Deja, tai nedavė jokių rezultatų – be Ubuntu platformos surinkimo instrukcijų, jokių kitų medžiagų neradome.
Pati dokumentacija buvo gerai ištirta, tačiau kai kuriose srityse buvo sunkiai įskaitoma. Gana dažnai tekdavo grįžti prie tam tikrų taškų ir nuo aukšto lygio abstrakčių idėjų aprašymų pereiti prie žemo lygio įgyvendinimo detalių.
Būtų lengviau, jei specifikacijoje iš viso nebūtų detalaus įgyvendinimo aprašymo. Informacija apie tai, kaip virtuali mašina reprezentuoja savo krūvą, greičiausiai atitrauks kūrėjų, kuriančių išmaniąsias sutartis TON platformai, dėmesį, nei padės jiems.
Nix: projekto sujungimas
Mes Serokell esame dideli gerbėjai . Su juo renkame savo projektus ir diegiame juos naudodami , ir įdiegta visuose mūsų serveriuose . Dėl šios priežasties visos mūsų versijos yra atkuriamos ir veikia bet kurioje operacinėje sistemoje, kurioje galima įdiegti „Nix“.
Taigi pradėjome nuo kūrimo . Su jo pagalba TON sudarymas yra kuo paprastesnis:
$ cd ~/.config/nixpkgs/overlays && git clone https://github.com/serokell/ton.nix
$ cd /path/to/ton/repo && nix-shell
[nix-shell]$ cmakeConfigurePhase && makeAtminkite, kad jums nereikia įdiegti jokių priklausomybių. „Nix“ stebuklingai padarys viską už jus, nesvarbu, ar naudojate „NixOS“, „Ubuntu“, ar „MacOS“.
Programavimas TON
Išmaniosios sutarties kodas TON tinkle veikia TON virtualioje mašinoje (TVM). TVM yra sudėtingesnė nei dauguma kitų virtualių mašinų ir turi labai įdomių funkcijų, pavyzdžiui, su ja gali dirbti tęsiniai и nuorodos į duomenis.
Be to, vaikinai iš TON sukūrė tris naujas programavimo kalbas:
Penkta yra universali programavimo kalba, kuri panaši į . Jo puikus sugebėjimas yra gebėjimas bendrauti su TVM.
FunC yra išmanioji sutartinių programavimo kalba, kuri yra panaši į ir yra sudarytas į kitą kalbą - Fift Assembler.
Penktasis surinkėjas — Fift biblioteka, skirta TVM dvejetainiam vykdomajam kodui generuoti. „Fifth Assembler“ neturi kompiliatoriaus. Tai .
Mūsų konkursas veikia
Galiausiai atėjo laikas pažvelgti į mūsų pastangų rezultatus.
Asinchroninis mokėjimo kanalas
Mokėjimo kanalas yra išmanioji sutartis, leidžianti dviem vartotojams siųsti mokėjimus už blokų grandinės ribų. Dėl to sutaupote ne tik pinigų (nėra komisinių), bet ir laiko (nereikia laukti, kol bus apdorotas kitas blokas). Mokėjimai gali būti tokie maži, kiek pageidaujama, ir taip dažnai, kaip reikia. Tokiu atveju šalys neprivalo pasitikėti viena kita, nes galutinio atsiskaitymo teisingumą garantuoja išmanioji sutartis.
Mes radome gana paprastą problemos sprendimą. Dvi šalys gali keistis pasirašytais pranešimais, kurių kiekvienoje yra du numeriai – visa kiekvienos šalies sumokėta suma. Šie du skaičiai veikia kaip tradicinėse paskirstytose sistemose ir nustatykite operacijų tvarką „atsitiko anksčiau“. Naudojant šiuos duomenis, sutartis galės išspręsti bet kokį galimą konfliktą.
Tiesą sakant, šiai idėjai įgyvendinti pakanka vieno skaičiaus, tačiau palikome abu, nes taip galėjome padaryti patogesnę vartotojo sąsają. Be to, nusprendėme į kiekvieną pranešimą įtraukti mokėjimo sumą. Be jo, jei pranešimas dėl kokių nors priežasčių būtų prarastas, tada, nors visos sumos ir galutinis skaičiavimas bus teisingi, vartotojas gali nepastebėti praradimo.
Norėdami išbandyti savo idėją, ieškojome tokio paprasto ir glausto mokėjimo kanalo protokolo naudojimo pavyzdžių. Keista, bet radome tik du:
- panašus požiūris, tik vienkrypčio kanalo atveju.
- , kuriame aprašoma ta pati idėja kaip ir mūsų, tačiau nepaaiškinta daug svarbių detalių, tokių kaip bendras teisingumas ir konfliktų sprendimo procedūros.
Tapo aišku, kad prasminga išsamiai aprašyti mūsų protokolą, ypatingą dėmesį skiriant jo teisingumui. Po kelių pakartojimų specifikacija buvo parengta, o dabar galite ir jūs. .
Sutartį įgyvendinome FunC, o komandų eilutės įrankį, skirtą sąveikai su mūsų sutartimi, parašėme tik „Fift“, kaip rekomendavo organizatoriai. Galėjome pasirinkti bet kurią kitą savo CLI kalbą, bet mums buvo įdomu išbandyti „Fit“ ir sužinoti, kaip ji veikia praktiškai.
Tiesą sakant, dirbdami su „Fift“ nematėme jokių įtikinamų priežasčių, kodėl reikėtų teikti pirmenybę šiai kalbai, o ne populiarioms ir aktyviai vartojamoms kalboms su sukurtais įrankiais ir bibliotekomis. Programavimas dėklo kalba yra gana nemalonus, nes jūs turite nuolat laikyti galvoje tai, kas yra ant krūvos, o kompiliatorius to nepadeda.
Todėl, mūsų nuomone, vienintelis Fift egzistavimo pateisinimas yra jos, kaip Fift Assembler priimančiosios kalbos, vaidmuo. Bet ar nebūtų geriau TVM asemblerį įterpti į kokią nors esamą kalbą, o ne sugalvoti naują šiam iš esmės vieninteliam tikslui?
TVM Haskell eDSL
Dabar atėjo laikas kalbėti apie antrąją išmaniąją sutartį. Nusprendėme sukurti kelių parašų piniginę, bet rašyti dar vieną išmaniąją sutartį FunC būtų pernelyg nuobodu. Norėjome pridėti šiek tiek skonio, ir tai buvo mūsų pačių TVM surinkimo kalba.
Kaip ir „Fift Assembler“, mūsų naujoji kalba yra įterpta, bet mes pasirinkome „Haskell“ kaip pagrindinį kompiuterį, o ne „Fift“, todėl galime išnaudoti visas pažangios tipo sistemos galimybes. Dirbant su išmaniosiomis sutartimis, kur net ir nedidelės klaidos kaina gali būti labai didelė, statinis spausdinimas, mūsų nuomone, yra didelis privalumas.
Norėdami parodyti, kaip atrodo TVM surinkėjas, įterptas į Haskell, įdiegėme standartinę piniginę. Štai keletas dalykų, į kuriuos reikia atkreipti dėmesį:
- Šią sutartį sudaro viena funkcija, tačiau galite naudoti tiek, kiek norite. Kai apibrėžiate naują funkciją pagrindinio kompiuterio kalba (t. y. Haskell), mūsų eDSL leidžia pasirinkti, ar norite, kad ji taptų atskira TVM įprasta, ar tiesiog įtraukta į skambučio tašką.
- Kaip ir Haskell, funkcijos turi tipus, kurie tikrinami kompiliavimo metu. Mūsų eDSL funkcijos įvesties tipas yra dėklo tipas, kurio funkcija tikisi, o rezultato tipas yra dėklo tipas, kuris bus sukurtas po iškvietimo.
- Kode yra anotacijų
stacktype, aprašantis numatomą dėklo tipą iškvietimo taške. Pradinėje piniginės sutartyje tai buvo tik komentarai, tačiau mūsų eDSL jie iš tikrųjų yra kodo dalis ir tikrinami kompiliavimo metu. Jie gali būti naudojami kaip dokumentai arba teiginiai, padedantys kūrėjui rasti problemą, jei pasikeičia kodas ir dėklo tipas. Žinoma, tokie komentarai neturi įtakos vykdymo laikui, nes joms negeneruojamas TVM kodas. - Tai vis dar yra prototipas, parašytas per dvi savaites, todėl prie projekto dar reikia daug nuveikti. Pavyzdžiui, visi toliau pateiktame kode matomų klasių egzemplioriai turėtų būti sugeneruoti automatiškai.
Štai kaip atrodo multisig piniginės įdiegimas mūsų eDSL:
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 @Word32Visą mūsų eDSL ir kelių parašų piniginės sutarties šaltinio kodą galite rasti adresu Ir dar apie integruotas kalbas, mūsų kolega Georgijus Agapovas.
Išvados apie konkursą ir TON
Iš viso mūsų darbas užtruko 380 valandų (įskaitant susipažinimą su dokumentacija, susitikimus ir realią plėtrą). Konkurso projekte dalyvavo penki kūrėjai: CTO, komandos vadovas, blockchain platformos specialistai ir Haskell programinės įrangos kūrėjai.
Dalyvauti konkurse radome išteklių be vargo, nes hakatono dvasia, glaudus komandinis darbas ir poreikis greitai pasinerti į naujų technologijų aspektus visada džiugina. Kelias bemieges naktis siekiant maksimalių rezultatų ribotų išteklių sąlygomis kompensuoja neįkainojama patirtis ir puikūs prisiminimai. Be to, darbas atliekant tokias užduotis visada yra geras įmonės procesų išbandymas, nes be gerai veikiančios vidinės sąveikos labai sunku pasiekti tikrai gerų rezultatų.
Dainos žodžiai: mus sužavėjo TON komandos įdėtas darbas. Jiems pavyko sukurti sudėtingą, gražią ir, svarbiausia, veikiančią sistemą. TON įrodė, kad yra platforma, turinti didelį potencialą. Tačiau norint, kad ši ekosistema vystytųsi, reikia daug daugiau nuveikti tiek dėl jos panaudojimo blockchain projektuose, tiek tobulinant kūrimo priemones. Didžiuojamės, kad dabar esame šio proceso dalis.
Jei perskaitę šį straipsnį vis dar turite klausimų ar turite idėjų, kaip naudoti TON savo problemoms išspręsti, – mielai pasidalinsime savo patirtimi.
Šaltinis: www.habr.com
