FunC omsette yn FunCtional mei Haskell: Hoe Serokell wûn de Telegram Blockchain Competition

Jo hawwe wierskynlik heard dat Telegram stiet op it punt om it Ton blockchain-platfoarm te lansearjen. Mar jo miskien hawwe mist it nijs dat net lang lyn Telegram in kompetysje oankundige foar de ymplemintaasje fan ien of mear tûke kontrakten foar dit platfoarm.

It Serokell-team, mei wiidweidige ûnderfining yn it ûntwikkeljen fan grutte blockchain-projekten, koe net oan 'e kant stean. Wy delegearren fiif meiwurkers oan de kompetysje, en twa wiken letter pakten se dêryn it earste plak ûnder de (ûn)beskieden willekeurige bynamme Sexy Chameleon. Yn dit artikel sil ik prate oer hoe't se it diene. Wy hoopje dat jo yn 'e kommende tsien minuten op syn minst in nijsgjirrich ferhaal lêze, en op syn heechst wat nuttichs yn fine dat jo kinne tapasse yn jo wurk.

Mar lit ús begjinne mei in bytsje kontekst.

Kompetysje en syn betingsten

Dat, de wichtichste taken fan 'e dielnimmers wiene de ymplemintaasje fan ien of mear fan' e foarstelde tûke kontrakten, en ek it meitsjen fan útstellen om it TON-ekosysteem te ferbetterjen. De kompetysje rûn fan 24 septimber oant 15 oktober, en de resultaten waarden pas op 15 novimber bekend makke. In hiel lange tiid, yn betinken nommen dat Telegram yn dizze tiid slagge om de resultaten fan wedstriden te hâlden en oan te kundigjen oer it ûntwerp en ûntwikkeling fan applikaasjes yn C ++ foar it testen en beoardieljen fan de kwaliteit fan VoIP-oproppen yn Telegram.

Wy selekteare twa tûke kontrakten út 'e list foarsteld troch de organisatoaren. Foar ien fan harren brûkten wy ark ferspraat mei TON, en de twadde waard ymplementearre yn in nije taal ûntwikkele troch ús yngenieurs spesifyk foar TON en boud yn Haskell.

De kar fan in funksjonele programmeartaal is net tafallich. Yn ús bedriuw blog Wy prate faak oer wêrom't wy tinke dat de kompleksiteit fan funksjonele talen in enoarme oerdriuwing is en wêrom't wy se oer it algemien leaver hawwe boppe objektrjochte talen. Trouwens, it befettet ek orizjineel fan dit artikel.

Wêrom hawwe wy sels besletten om mei te dwaan?

Koartsein, om't ús spesjalisaasje net-standert en komplekse projekten is dy't spesjale feardichheden fereaskje en faaks fan wittenskiplike wearde binne foar de IT-mienskip. Wy stypje sterk iepen-boarne ûntwikkeling en binne dwaande mei syn popularisearring, en ek gearwurkje mei foaroansteande Russyske universiteiten op it mêd fan kompjûter wittenskip en wiskunde.

De nijsgjirrige taken fan 'e konkurrinsje en belutsenens by ús leafste Telegram-projekt wiene op himsels in poerbêste motivaasje, mar it priisfûns waard in ekstra stimulâns. 🙂

TON blockchain ûndersyk

Wy folgje nau nije ûntjouwings yn blockchain, keunstmjittige yntelliginsje en masine learen en besykje gjin inkele wichtige release te missen yn elk fan 'e gebieten wêryn wy wurkje. Dêrom, tsjin 'e tiid dat de konkurrinsje begon, wie ús team al bekend mei ideeën fan TON wyt papier. Foardat wy mei TON begon te wurkjen, hawwe wy de technyske dokumintaasje en de eigentlike boarnekoade fan it platfoarm net analysearre, dus de earste stap wie frij dúdlik - in yngeande stúdzje fan 'e offisjele dokumintaasje oer side en yn projekt repositories.

Tsjin de tiid dat de konkurrinsje begon wie de koade al publisearre, dus om tiid te besparjen, besleaten wy om te sykjen nei in gids of gearfetting skreaun troch brûkers. Spitigernôch joech dit gjin resultaten - útsein ynstruksjes foar it gearstallen fan it platfoarm op Ubuntu, hawwe wy gjin oare materialen fûn.

De dokumintaasje sels wie goed ûndersocht, mar wie op guon gebieten lestich te lêzen. Hiel faak moasten wy werom nei bepaalde punten en wikselje fan beskriuwingen op heech nivo fan abstrakte ideeën nei ymplemintaasjedetails op leech nivo.

It soe makliker wêze as de spesifikaasje hielendal gjin detaillearre beskriuwing fan 'e ymplemintaasje omfette. Ynformaasje oer hoe't in firtuele masine syn stack fertsjintwurdiget is mear kâns om ûntwikkelders ôf te lieden dy't tûke kontrakten meitsje foar it TON-platfoarm dan om har te helpen.

Nix: it projekt gearwurkje

By Serokell binne wy ​​grutte fans nix. Wy sammelje ús projekten dêrmei en sette se yn mei help fan NixOps, en ynstalleare op al ús servers Nix OS. Hjirmei binne al ús builds reprodusearjeber en wurkje op elk bestjoeringssysteem wêrop Nix kin wurde ynstalleare.

Sa begûnen wy mei it meitsjen Nix-overlay mei útdrukking foar TON-assemblage. Mei har help is it kompilearjen fan TON sa ienfâldich mooglik:

$ cd ~/.config/nixpkgs/overlays && git clone https://github.com/serokell/ton.nix
$ cd /path/to/ton/repo && nix-shell
[nix-shell]$ cmakeConfigurePhase && make

Tink derom dat jo gjin ôfhinklikens hoege te ynstallearjen. Nix sil op magyske wize alles foar jo dwaan, of jo NixOS, Ubuntu of macOS brûke.

Programming foar TON

De tûke kontraktkoade yn it TON Network rint op 'e TON Virtual Machine (TVM). TVM is komplekser as de measte oare firtuele masines, en hat hiel nijsgjirrige funksjonaliteit, bygelyks, it kin wurkje mei ferfolch и keppelings nei gegevens.

Boppedat makken de jonges fan TON trije nije programmeartalen:

Fift is in universele stack programmeartaal dy't liket foarút. Syn super fermogen is de mooglikheid om te ynteraksje mei TVM.

FunC is in tûke kontraktprogrammearringstaal dy't gelyk is oan C en is gearstald yn in oare taal - Fift Assembler.

Fyfde Assembler - Fift-bibleteek foar it generearjen fan binêre útfierbere koade foar TVM. Fifth Assembler hat gjin kompilator. Dit Embedded Domain Specific Language (eDSL).

Us konkurrinsje wurket

Uteinlik is it tiid om te sjen nei de resultaten fan ús ynspanningen.

Asynchronous betelling kanaal

Betelkanaal is in tûk kontrakt wêrmei twa brûkers betellingen bûten de blockchain kinne stjoere. As resultaat besparje jo net allinich jild (d'r is gjin kommisje), mar ek tiid (jo hoege net te wachtsjen foar it folgjende blok om te ferwurkjen). Betellingen kinne sa lyts wêze as winske en sa faak as nedich. Yn dit gefal hoege de partijen inoar net te fertrouwe, om't de gerjochtichheid fan 'e definitive delsetting wurdt garandearre troch it tûke kontrakt.

Wy fûnen in frij ienfâldige oplossing foar it probleem. Twa partijen kinne ûndertekene berjochten útwikselje, elk mei twa nûmers - it folsleine bedrach betelle troch elke partij. Dizze twa nûmers wurkje lykas vector klok yn tradisjonele ferspraat systemen en set de "barre foardat" folchoarder op transaksjes. Mei dizze gegevens sil it kontrakt elk mooglik konflikt kinne oplosse.

Eins is ien nûmer genôch om dit idee út te fieren, mar wy ferlieten beide, om't wy op dizze manier in handiger brûkersynterface kinne meitsje. Derneist hawwe wy besletten om it betellingsbedrach yn elk berjocht op te nimmen. Sûnder it, as it berjocht om ien of oare reden ferlern is, dan, hoewol alle bedraggen en de definitive berekkening korrekt binne, kin de brûker it ferlies net fernimme.

Om ús idee te testen, sochten wy nei foarbylden fan it brûken fan sa'n ienfâldich en beknopt betellingskanaalprotokol. Ferrassend fûnen wy mar twa:

  1. beskriuwing in fergelykbere oanpak, allinich foar it gefal fan in ienrjochtingskanaal.
  2. Tutorial, dy't itselde idee beskriuwt as ús, mar sûnder in protte wichtige details te ferklearjen, lykas algemiene korrektens en prosedueres foar konfliktoplossing.

It waard dúdlik dat it sin hat om ús protokol yn detail te beskriuwen, spesjaal omtinken te jaan oan syn korrektheid. Nei ferskate iteraasjes wie de spesifikaasje klear, en no kinne jo ek. Sjoch nei har.

Wy hawwe it kontrakt yn FunC ymplementearre, en wy skreaunen it kommandorigelprogramma foar ynteraksje mei ús kontrakt folslein yn Fift, lykas oanrikkemandearre troch de organisatoaren. Wy koene elke oare taal foar ús CLI kieze, mar wy wiene ynteressearre om Fit te besykjen om te sjen hoe't it yn 'e praktyk prestearre.

Om earlik te wêzen, nei't wy mei Fift wurke hawwe, seagen wy gjin twingende redenen om dizze taal leaver te meitsjen foar populêre en aktyf brûkte talen mei ûntwikkele ark en biblioteken. Programma's yn in stack-basearre taal is frijwat onaangenaam, om't jo konstant yn jo holle moatte hâlde wat op 'e stapel stiet, en de kompilator helpt dit net.

Dêrom is neffens ús de ienige rjochtfeardiging foar it bestean fan Fift syn rol as gasttaal foar Fift Assembler. Mar soe it net better wêze om de TVM-assembler yn te ynbêdzjen yn guon besteande taal, ynstee fan in nije út te finen foar dit yn wêzen ienige doel?

TVM Haskell eDSL

No is it tiid om te praten oer ús twadde tûke kontrakt. Wy besletten om in wallet mei meardere hântekeningen te ûntwikkeljen, mar it skriuwen fan in oar tûk kontrakt yn FunC soe te saai wêze. Wy woene wat smaak taheakje, en dat wie ús eigen assemblagetaal foar TVM.

Lykas Fift Assembler, is ús nije taal ynbêde, mar wy keas Haskell as de host ynstee fan Fift, wêrtroch't wy folslein profitearje fan syn avansearre type systeem. By it wurkjen mei tûke kontrakten, wêr't de kosten fan sels in lytse flater tige heech kinne wêze, is statysk typen, nei ús miening, in grut foardiel.

Om te demonstrearjen hoe TVM-assembler derút sjocht ynbêde yn Haskell, hawwe wy der in standert wallet op ymplementearre. Hjir binne in pear dingen om omtinken te jaan:

  • Dit kontrakt bestiet út ien funksje, mar jo kinne safolle brûke as jo wolle. As jo ​​​​in nije funksje definiearje yn 'e hosttaal (dus Haskell), lit ús eDSL jo kieze of jo wolle dat it in aparte routine wurdt yn TVM of gewoan ynline op it punt fan oprop.
  • Lykas Haskell hawwe funksjes typen dy't wurde kontrolearre op kompilaasjetiid. Yn ús eDSL is it ynfiertype fan in funksje it type stack dat de funksje ferwachtet, en it resultaattype is it type stack dat sil wurde produsearre nei de oprop.
  • De koade hat annotaasjes stacktype, it beskriuwen fan it ferwachte stacktype op it oproppunt. Yn it orizjinele portemonneekontrakt wiene dit gewoan opmerkingen, mar yn ús eDSL binne se eins diel fan 'e koade en wurde kontrolearre op kompilaasjetiid. Se kinne tsjinje as dokumintaasje as útspraken dy't de ûntwikkelder helpe it probleem te finen as de koade feroaret en it stapeltype feroaret. Fansels hawwe sokke annotaasjes gjin ynfloed op runtime-prestaasjes, om't gjin TVM-koade foar har wurdt generearre.
  • Dit is noch in prototype dat yn twa wiken skreaun is, dus der is noch in soad wurk te dwaan oan it projekt. Bygelyks, alle eksimplaren fan 'e klassen dy't jo sjogge yn' e koade hjirûnder moatte automatysk oanmakke wurde.

Dit is hoe de ymplemintaasje fan in multisig wallet derút sjocht op ú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 @Word32

De folsleine boarne koade fan ús eDSL en multi-hântekening wallet kontrakt is te finen op dizze repository. En mear ferteld yn detail oer ynboude talen, ús kollega Georgy Agapov.

Konklúzjes oer de kompetysje en TON

Yn totaal duorre ús wurk 380 oeren (ynklusyf bekendmaking mei dokumintaasje, gearkomsten en eigentlike ûntwikkeling). Fiif ûntwikkelders namen diel oan it kompetysjeprojekt: CTO, teamleader, spesjalisten fan blockchain-platfoarm en Haskell-software-ûntwikkelders.

Wy fûnen boarnen om sûnder muoite mei te dwaan oan 'e wedstryd, om't de geast fan in hackathon, nauwe teamwurk, en de needsaak om ússels fluch te ferdjipjen yn aspekten fan nije technologyen altyd spannend is. Ferskate sliepleaze nachten om maksimale resultaten te berikken yn betingsten fan beheinde boarnen wurde kompensearre troch ûnskatbere wearde ûnderfining en treflike oantinkens. Derneist is it wurkjen oan sokke taken altyd in goede test fan 'e prosessen fan it bedriuw, om't it heul lestich is om wirklik fatsoenlike resultaten te berikken sûnder goed funksjonearjende ynterne ynteraksje.

Lyrics aside: wy wiene ûnder de yndruk fan de hoemannichte wurk set yn troch it TON team. Se slagge om te bouwen fan in kompleks, moai, en vooral, wurkje systeem. TON hat himsels bewiisd in platfoarm te wêzen mei grut potensjeel. Om dit ekosysteem te ûntwikkeljen, moat der lykwols folle mear dien wurde, sawol yn termen fan gebrûk yn blockchain-projekten as yn termen fan ferbetterjen fan ûntwikkelingsark. Wy binne grutsk no diel út te meitsjen fan dit proses.

As jo ​​​​nei it lêzen fan dit artikel noch fragen hawwe of ideeën hawwe oer hoe't jo TON kinne brûke om jo problemen op te lossen, skriuw ús - wy sille bliid wêze om ús ûnderfining te dielen.

Boarne: www.habr.com

Add a comment