Duke e shndërruar FunC në FunCtional me Haskell: si Serokell fitoi në Garën e Blockchain të Telegramit.

Ju keni dëgjuar me siguri se Telegram po planifikon të nisë platformën blockchain Ton. Por ndoshta keni humbur lajmin se së fundmi Telegram deklaroi një konkurs për implementimin e një ose më shumë kontratave të mençura për këtë platformë.

Ekipi Serokell me përvojë të pasur në zhvillimin e projekteve të mëdha blockchain nuk mund të qëndronte indiferent. Ne deleguam pesë punonjës në konkurs, dhe pas dy javësh ata e fituan atë vend të parë me një emër (në)esk modest, Sexy Chameleon. Në këtë artikull, do të flas për mënyrën si ia dolën. Kemi shpresë se për dhjetë minutat e ardhshme, ju do të lexoni të paktën një histori interesante, dhe më shumë mund të gjeni diçka të dobishme që mund ta aplikoni në punën tuaj.

Por le të fillojmë me një përqasje të vogël në kontekst.

Konkursi dhe kushtet e tij

Pra, detyrat kryesore të pjesëmarrësve ishin implementimi i një ose më shumë të kontratave të propozuara të mençura, si dhe paraqitja e propozimeve për përmirësimin e ekosistemit TON. Konkursi u mbajt nga 24 Shtatori deri më 15 Tetor dhe rezultatet u shpallën vetëm më 15 Nëntor. Mjaft e gjatë, duke marrë parasysh se gjatë kësaj periudhe Telegram kishte arritur të zhvillonte dhe shpallte rezultatet e konkurseve për dizajn dhe zhvillim aplikacionesh në C++ për testimin dhe vlerësimin e cilësisë së thirrjeve VoIP në Telegram.

Ne zgjodhëm nga lista e propozuar nga organizatorët dy kontrata të mençura. Për një prej tyre përdorëm mjetet që shpërndahen me TON, ndërsa të dytën e realizuam në një gjuhë të re, të zhvilluar nga inxhinierët tanë veçmas për TON dhe të integruar në Haskell.

Zgjedhja e një gjuhe funksionale programimi nuk është rastësore. Në blogun tonë korporativ ne shpesh flasim për arsyet pse e konsiderojmë kompleksitetin e gjuhëve funksionale si një teprim të madh, dhe pse në përgjithësi i preferojmë ato mbi ato të orientuara nga objekti. Sidoqoftë, në të ka edhe origjinalin e këtij artikulli.

Pse vendosëm të marrim pjesë

Në përmbledhje, sepsespecializimi ynë është në projekte jo standarde dhe komplekse, që kërkojnë aftësi të veçanta dhe shpesh përbëjnë vlerë shkencore për komunitetin IT. Ne e mbështesim me pasion zhvillimin open-source dhe merremi me popullarizimin e tij, dhe gjithashtu bashkëpunojmë me universitetet kryesore të Rusisë në fushën e shkencave kompjuterike dhe matematikës.

Sfidhi konkurrencĂ«s dhe angazhimi nĂ« projektin qĂ« e duam shumĂ«, Telegrami, ishte njĂ« motivim i shkĂ«lqyer dhe fondi i çmimeve ishte njĂ« stimulus shtesĂ«. 🙂

Kërkimi mbi blockchain-in TON

Ne monitorojmë me vëmendje zhvillimet e reja në blockchain, inteligjencën artificiale dhe mësimin e makinerive dhe përpiqemi të mos humbasim asnjë publikim të rëndësishëm në secilën nga fushat në të cilat punojmë. Prandaj, në momentin e fillimit të konkurrencës, ekipi ynë tashmë ishte njohur me idetë nga ton white paper. Megjithatë, deri në fillimin e punës me TON, ne nuk kishim analizuar dokumentacionin teknik dhe kodin burimor të platformës, prandaj hapi i parë ishte mjaft i qartë - një studim i thellë i dokumentacionit zyrtar në website dhe në repositori i projektit.

Në fillim të konkurrencës, kodi tashmë ishte publikuar, prandaj, për të kursyer kohë, vendosëm të kërkojmë një udhëzues ose përmbledhje të shkruar nga përdoruesit. Fatkeqësisht, kjo nuk ishte shumë rezultative - përveç udhëzimit për ndërtimin e platformës në Ubuntu, nuk gjetëm materiale të tjera.

Dokumentacioni vetë rezultoi të ishte i punuar me kujdes, por leximi i tij në disa momente ishte i vështirë. Mjaft shpesh na duhej të ktheheshim në pika të ndryshme dhe të kalonim nga përshkrime të nivelit të lartë të ideve abstrakte në detaje të nivelit të ulët të realizimit.

Do të ishte më e lehtë nëse specifikimi nuk do të kishte ndonjë përshkrim të detajuar të realizimit. Informacioni se si maƥina virtuale paraqet stekën e saj, më tepër e shpërqendron zhvilluesit që krijojnë kontrata inteligente për platformën TON, sesa i ndihmon ata.

Nix: ndërtimi i projektit

Në Serokell ne jemi adhurues të mëdhenj të Nix. Ne i ndjejmë projektet tona me të dhe i zbatojmë ato me NixOps, dhe në të gjitha serverët tanë është instaluar NixOS. Kjo na lejon që të gjitha ndërtimet tona të jenë të riprodhueshme dhe të funksionojnë në çdo sistem operativ, në të cilin mund të instalohet Nix.

Prandaj, filluam me krijimin e Nix overlay me shprehjen për ndërtimin e TON. Me ndihmën e tij, të kompilosh TON është shumë e lehtë:

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

Vini re, nuk keni nevojë të instaloni asnjë varësi. Nix do të bëjë çdo gjë magjikisht për ju pa marrë parasysh nëse përdorni NixOS, Ubuntu ose macOS.

Programimi për TON

Kodi i kontratave të mençura në Rrjetin TON ekzekutohet në TON Virtual Machine (TVM). TVM është më e ndërlikuar se shumica e makinave të tjera virtuale dhe ka funksionalitete shumë interesante, për shembull, ajo mund të punojë me vazhdate (continuations) dhe lidhet me të dhëna.

Për më tepër, djemtë nga TON krijuan tre gjuhë të reja programimi:

Fift — njĂ« gjuhĂ« universale programuese me gjendje (stack-based), qĂ« i ngjan Forth. Superfuqia e saj Ă«shtĂ« mundĂ«sia pĂ«r t'u ndĂ«rvepruar me TVM.

FunC — njĂ« gjuhĂ« programimi pĂ«r kontrata tĂ« mençura qĂ« ngjason me C dhe kompilohet nĂ« njĂ« gjuhĂ« tjetĂ«r — Fift Assembler.

Fift Assembler — njĂ« bibliotekĂ« Fift pĂ«r gjenerimin e kodit ekzekutiv binar pĂ«r TVM. Fift Assembler nuk ka njĂ« kompilator. Ky Ă«shtĂ« njĂ« gjuhĂ« (eDSL) e integruar me objekt..

Punimet tona konkurente

Më në fund, erdhi koha të shikojmë rezultatet e përpjekjeve tona.

Kanalet e pagesave asinkrone

Kanalet e pagesave (payment channels) janë kontrata të mençura që lejojnë dy përdorues të dërgojnë pagesa jashtë blockchain-it. Si rezultat, jo vetëm që kurseni para (nuk ka komision), por edhe kohë (nuk keni nevojë të prisni në procesin e bllokut tjetër). Pagesat mund të jenë sa të vogla dhe të ndodhin aq shpesh sa është e nevojshme. Në të njëjtën kohë, palët nuk është e nevojshme të besojnë njëra-tjetrën, pasi drejtësia e llogaritjes përfundimtare garantohet nga kontrata e mençur.

Kemi gjetur njĂ« zgjidhje tĂ« mjaftueshme pĂ«r problemin. Dy palĂ«t mund tĂ« shkĂ«mbejnĂ« mesazhe tĂ« nĂ«nshkruara, secili prej tĂ« cilĂ«ve pĂ«rmban dy numra — shumĂ«n totale tĂ« paguar nga secili nga pjesĂ«marrĂ«sit. KĂ«ta dy numra funksionojnĂ« si ora vektoriale nĂ« sistemet e shpĂ«rndara tradicionale dhe pĂ«rcaktojnĂ« rendin "ka ndodhur para" nĂ« transaksione. Duke pĂ«rdorur kĂ«to tĂ« dhĂ«na, kontrata do tĂ« jetĂ« nĂ« gjendje tĂ« zgjidhĂ« çdo konflikt tĂ« mundshĂ«m.

Në të vërtetë, për realizimin e kësaj ideje mjafton edhe një numër, por ne e lamë të dyja, pasi në këtë mënyrë mundëm të krijojmë një ndërfaqe më të rehatshme për përdoruesin. Përveç kësaj, vendosëm që të përfshijmë në çdo mesazh madhësinë e pagesës. Pa të, nëse mesazhi humbet për ndonjë arsye, megjithëse të gjitha shumat dhe llogaritja përfundimtare do të ishin të sakta, përdoruesi mund të mos vërehet humbjen.

Për të verifikuar idenë tonë, ne kërkuam shembuj të përdorimit të një protokolli të tillë të thjeshtë dhe të qartë të kanalit të pagesës. Për habinë tonë, gjetëm vetëm dy:

  1. Përshkrimi një qasje të ngjashme, vetëm për rastin e një kanali njëdrejtues.
  2. Tutorial, në të cilin përshkruhet po e njëjta ide si e jona, vetëm pa shpjegimin e detajeve të shumta të rëndësishme, si korrektësia e përgjithshme dhe procedura e zgjidhjes së konflikteve.

U bë e qartë se ka kuptim të përshkruajmë në detaje protokollin tonë, duke i kushtuar vëmendje të veçantë korrektësisë së tij. Pas disa iteracioneve, specifikimi ishte gati, dhe tani ju gjithashtu mund të shikoni atë.

Ne realizuam kontratën në FunC, ndërsa utilitarin e linjës së komandës për të ndërvepruar me kontratën tonë e kemi shkruar plotësisht në Fift, ashtu siç rekomanduan organizatorët. Ne mund të kishim zgjedhur çfarëdo gjuhe tjetër për CLI-në tonë, por na kishte interes ta provonim pikërisht Fift, për të parë si do t'i shfaqej vetja në praktikë.

Sinqerisht, pasi punuam me Fift, ne nuk pamë arsye të forta për ta preferuar këtë gjuhë ndaj gjuhëve më popullore dhe aktivisht të përdorura me mjete dhe biblioteka të zhvilluar. Programimi në një gjuhë me të dhëna është mjaft i dhimbshëm, pasi duhet të mbash gjithmonë mend se çfarë ndodhet ku në të dhënat, dhe kompajleri nuk ndihmon në këtë.

Prandaj, e vetmja justifikim, sipas mendimit tonë, për ekzistencën e Fift është roli i tij si gjuhë host për Fift Assembler. Por nuk do të ishte më mirë të integrohej asmbler TVM në ndonjë gjuhë ekzistuese, përpara se të shpiknim një të re për këtë qëllim, në thelb, të vetëm?

TVM Haskell eDSL

Tani ka ardhur koha të flasim për kontratën tonë të dytë të zgjuar. Ne vendosëm të zhvillojmë një portofol me shumë nënshkrime, por të shkruajmë një tjetër kontratë të zgjuar në FunC do të ishte tepër e mërzitshme. Na pëlqente të shtonim ndonjë element të veçantë, dhe ai ishte gjuha jonë e vetme e asmblerit për TVM.

Ashtu si Fift Assembler, gjuha jonë e re është e integrueshme, vetëm se si host në vend të Fift, ne zgjodhëm Haskell, që na lejoi të shfrytëzojmë plotësisht sistemin e tij të avancuar të tipeve. Kur punoni me kontratat e zgjuara, ku çmimi i një gabimi të vogël mund të jetë shumë i lartë, tipizimi statik, sipas mendimit tonë, është një avantazh i madh.

Për të demonstruar se si duket assembleri TVM, i integruar në Haskell, ne realizuam një portofol standard. Ja disa gjëra për të cilat duhet të keni parasysh:

  • Ky kontratĂ« pĂ«rbĂ«het nga njĂ« funksion, por ju mund tĂ« pĂ«rdorni sa mĂ« shumĂ« qĂ« dĂ«shironi. Kur pĂ«rcaktoni njĂ« funksion tĂ« ri nĂ« gjuhĂ«n e hostit (dmth. nĂ« Haskell), eDSL jonĂ« ju lejon tĂ« zgjidhni nĂ«se dĂ«shironi qĂ« ai tĂ« shndĂ«rrohet nĂ« njĂ« nĂ«nprogram tĂ« veçantĂ« nĂ« TVM ose thjesht tĂ« integrohet nĂ« vendin e thirrjes.
  • Si nĂ« Haskell, funksionet kanĂ« tipe qĂ« kontrollohen gjatĂ« kompaktimit. NĂ« eDSL tonĂ«, tipi i hyrjes sĂ« funksionit Ă«shtĂ« tipi i shtakĂ«s qĂ« funksioni pret, ndĂ«rsa tipi i rezultatit Ă«shtĂ« tipi i shtakĂ«s qĂ« do tĂ« rezultojĂ« pas thirrjes.
  • NĂ« kod ka annotime stacktype, tĂ« cilat pĂ«rshkruajnĂ« tipi e pritur tĂ« shtakĂ«s nĂ« pikĂ«n e thirrjes. NĂ« kontratĂ«n origjinale tĂ« portofolit, kĂ«to ishin thjesht komente, por nĂ« eDSL tonĂ« ato nĂ« fakt janĂ« pjesĂ« e kodit dhe kontrollohen gjatĂ« kompaktimit. Ato mund tĂ« shĂ«rbejnĂ« si dokumentacion ose deklarata qĂ« ndihmojnĂ« programuesin tĂ« gjejĂ« problemin nĂ«se, gjatĂ« ndryshimeve nĂ« kod, tipi i shtakĂ«s ndryshon. Natyrisht, kĂ«to annotime nuk ndikojnĂ« nĂ« performancĂ«n gjatĂ« ekzekutimit, pasi asnjĂ« kod TVM nuk gjenerohet pĂ«r to.
  • Ky Ă«shtĂ« ende njĂ« prototip, i shkruar brenda dy javĂ«ve, kĂ«shtu qĂ« ka ende shumĂ« punĂ« pĂ«r tĂ« bĂ«rĂ« nĂ« projekt. PĂ«r shembull, tĂ« gjitha instancat e klasave qĂ« shihni nĂ« kodin mĂ« poshtĂ« duhet tĂ« gjenerohen automatikisht.

Këtu është si duket realizimi i portofolit multisig në eDSL tonë:

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

Kodu i plotë burimor i eDSL tonë dhe kontrata e portofolit me shumë nënshkrim mund të gjeni në këtë depo. Një më të detajuar tregoi për gjuhët e integruara kolegu ynë Georgiy Agapov.

Konkluzionet për garën dhe TON

Në total, puna jonë zuri 380 orë (duke përfshirë njohjen me dokumentacionin, takimet dhe zhvillimin e drejtpërdrejt). Në projektin e konkursit morën pjesë pesë zhvillues: CTO, lideri i ekipit, specialistët e platformave blockchain dhe zhvilluesit e softuerit në Haskell.

Burimet për pjesëmarrjen në konkurs i gjetëm lehtësisht, pasi fryma e hackathon-it, puna e ngushtë në ekip, nevoja për të hyrë shpejt në aspektet e teknologjive të reja - gjithmonë është emocionuese. Disa net pa gjumë për të arritur rezultate maksimale në kushte burimesh të kufizuara kompenzohen nga përvoja të paçmuara dhe kujtime të shkëlqyera. Për më tepër, puna mbi këto detyra është gjithmonë një verifikim i mirë i proceseve të kompanisë, pasi të arrish rezultate të vërteta të denja pa një ndërveprim të brendshëm të përshtatshëm është jashtëzakonisht e vështirë.

Përveç lirizmit: ne ishim të impresionuar nga volumi i punës së kryer nga ekipi TON. Ata arritën të ndërtuan një sistem të ndërlikuar, të bukur dhe, mbi të gjitha, funksional. TON e tregoi veten si një platformë me potencial të madh. Megjithatë, për të zhvilluar këtë ekosistem, duhet të bëhet ende shumë, si sa i përket përdorimit të tij në projektet blockchain, ashtu edhe në përmirësimin e mjeteve të zhvillimit. Ne jemi krenarë që tani jemi pjesë e këtij procesi.

NĂ«se pas leximit tĂ« kĂ«tij artikulli ju kanĂ« mbetur ndonjĂ« pyetje ose keni ide se si tĂ« aplikoni TON pĂ«r zgjidhjen e detyrave tuaja, na shkruani — ne do tĂ« jemi tĂ« lumtur tĂ« ndihmojmĂ« me pĂ«rvojĂ«n tonĂ«.

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster