D'FunC a FunCtional mam Haskell ëmsetzen: Wéi de Serokell den Telegram Blockchain Concours gewonnen huet

Dir hutt wahrscheinlech dat Telegram héieren ass amgaang d'Ton Blockchain Plattform ze lancéieren. Awer Dir hutt vläicht d'Noriichte verpasst datt net viru laanger Telegram e Concours ugekënnegt fir d'Ëmsetzung vun engem oder méi Smart Kontrakter fir dës Plattform.

D'Serokell Team, mat extensiv Erfahrung an der Entwécklung vu grousse Blockchain Projeten, konnt net ophalen. Mir hunn fënnef Mataarbechter un de Concours delegéiert, an zwou Woche méi spéit hunn se déi éischt Plaz ënnert dem (on)bescheidenen zoufällege Spëtznumm Sexy Chameleon geholl. An dësem Artikel wäert ech schwätzen iwwer wéi se et gemaach hunn. Mir hoffen, datt Dir an den nächsten zéng Minutten op d'mannst eng interessant Geschicht liest, an héchstens eppes Nëtzlechs dran fannt, wat Dir an Ärer Aarbecht benotze kënnt.

Mee loosst eis mat engem klenge Kontext ufänken.

Konkurrenz a seng Konditiounen

Also, d'Haaptaufgaben vun de Participanten waren d'Ëmsetzung vun engem oder méi vun de proposéierte Smart Kontrakter, souwéi Propositioune fir den TON-Ökosystem ze verbesseren. De Concours ass vum 24. September bis de 15. Oktober gelaf, an d'Resultater goufen eréischt de 15. November annoncéiert. Zimlech laang, bedenkt datt während dëser Zäit Telegram et fäerdeg bruecht huet d'Resultater vu Concoursen iwwer den Design an d'Entwécklung vun Uwendungen am C++ ze halen an ze verkënnegen fir d'Qualitéit vu VoIP-Uriff am Telegram ze testen an ze bewäerten.

Mir hunn zwee Smart Kontrakter aus der Lëscht vun den Organisateuren proposéiert. Fir ee vun hinnen hu mir Tools benotzt, déi mat TON verdeelt goufen, an déi zweet gouf an enger neier Sprooch implementéiert, déi vun eisen Ingenieuren speziell fir TON entwéckelt gouf an an Haskell gebaut gouf.

D'Wiel vun enger funktioneller Programméierungssprooch ass net zoufälleg. An eisem Firmen Blog Mir schwätzen dacks iwwer firwat mir mengen datt d'Komplexitéit vu funktionnelle Sproochen eng grouss Iwwerdreiung ass a firwat mir se allgemeng léiwer wéi objektorientéiert. Et enthält iwwregens och original vun dësem Artikel.

Firwat hu mir iwwerhaapt decidéiert matzemaachen?

Kuerz gesot, well eis Spezialisatioun net-Standard a komplex Projeten ass, déi speziell Fäegkeeten erfuerderen an dacks vu wëssenschaftleche Wäert fir d'IT Gemeinschaft sinn. Mir ënnerstëtzen staark Open-Source Entwécklung a sinn a senger Populariséierung engagéiert, a kooperéieren och mat féierende russeschen Universitéiten am Beräich vun der Informatik a Mathematik.

Déi interessant Aufgaben vum Concours an d'Bedeelegung un eisem beléifte Telegram-Projet waren u sech eng exzellent Motivatioun, awer de Präisfong gouf en zousätzlechen Ureiz. 🙂

TON Blockchain Fuerschung

Mir iwwerwaachen nei Entwécklungen am Blockchain, kënschtlech Intelligenz a Maschinnléieren no a probéieren net eng eenzeg bedeitend Verëffentlechung an all de Beräicher ze verpassen, an deenen mir schaffen. Dofir, wéi d'Konkurrenz ugefaang huet, war eist Team scho vertraut mat Iddien aus TON wäiss Pabeier. Wéi och ëmmer, ier mir mat TON schaffen, hu mir d'technesch Dokumentatioun an den aktuellen Quellcode vun der Plattform net analyséiert, sou datt den éischte Schrëtt ganz offensichtlech war - eng grëndlech Studie vun der offizieller Dokumentatioun op Site an a Projet Repositories.

Wéi de Concours ugefaang huet, war de Code scho publizéiert, also fir Zäit ze spueren, hu mir beschloss no engem Guide oder Resumé ze sichen geschriwwen vum Benotzer. Leider huet dëst keng Resultater ginn - ausser Instruktioune fir d'Plattform op Ubuntu ze montéieren, hu mir keng aner Materialien fonnt.

D'Dokumentatioun selwer war gutt recherchéiert, awer war an e puer Beräicher schwéier ze liesen. Zimlech dacks hu mir missen op bestëmmte Punkten zréckkommen a vun héije Beschreiwunge vun abstrakte Iddien op nidderegen Ëmsetzungsdetailer wiesselen.

Et wier méi einfach wann d'Spezifikatioun guer net eng detailléiert Beschreiwung vun der Ëmsetzung enthält. Informatioun iwwer wéi eng virtuell Maschinn säi Stack duerstellt ass méi wahrscheinlech Entwéckler oflenken déi intelligent Kontrakter fir d'TON Plattform kreéieren wéi hinnen ze hëllefen.

Nix: de Projet zesummesetzen

Bei Serokell si mir grouss Fans nix. Mir sammelen eis Projeten domat an ofsetzen se mat NixOps, an op all eise Serveren installéiert Nix OS. Dank dësem sinn all eis Builds reproduzéierbar a funktionnéieren op all Betribssystem op deem Nix installéiert ka ginn.

Also hu mir ugefaang mat der Schafung Nix Iwwerlagerung mat Ausdrock fir TON Assemblée. Mat senger Hëllef ass d'Kompilatioun vun TON sou einfach wéi méiglech:

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

Bedenkt datt Dir keng Ofhängegkeeten installéiere musst. Nix wäert magesch alles fir Iech maachen, egal ob Dir NixOS, Ubuntu oder macOS benotzt.

Programméiere fir TON

De Smart Kontrakt Code am TON Network leeft op der TON Virtual Machine (TVM). TVM ass méi komplex wéi déi meescht aner virtuell Maschinnen, an huet ganz interessant Funktionalitéit, zum Beispill, et kann mat schaffen Fortsetzungen и Linken op daten.

Ausserdeem hunn d'Jongen aus TON dräi nei Programméierungssproochen erstallt:

Fift ass eng universell Stack Programméierungssprooch déi gläicht Firth. Seng super Fäegkeet ass d'Fäegkeet fir mat TVM ze interagéieren.

FunC ass eng intelligent Kontraktprogramméierungssprooch déi ähnlech ass C an ass an eng aner Sprooch zesummegesat - Fift Assembler.

Fënneften Assembler - Fift Bibliothéik fir binär ausführbare Code fir TVM ze generéieren. Fënneften Assembler huet kee Compiler. Dëst Embedded Domain Specific Language (eDSL).

Eis Konkurrenz funktionnéiert

Endlech ass et Zäit d'Resultater vun eisen Efforten ze kucken.

Asynchrone Bezuelkanal

Bezuelungskanal ass e Smart Kontrakt deen zwee Benotzer erlaabt Bezuelungen ausserhalb vum Blockchain ze schécken. Als Resultat spuert Dir net nëmme Suen (et gëtt keng Kommissioun), awer och Zäit (Dir musst net op den nächste Block waarden fir ze veraarbecht). Bezuelungen kënnen esou kleng sinn wéi gewënscht a sou dacks wéi néideg. An dësem Fall mussen d'Parteien net géigesäiteg trauen, well d'Gerechtegkeet vun der definitiver Siidlung vum Smart Kontrakt garantéiert ass.

Mir hunn eng zimlech einfach Léisung fir de Problem fonnt. Zwou Parteie kënnen ënnerschriwwene Messagen austauschen, déi all zwou Zuelen enthalen - de ganze Betrag dee vun all Partei bezuelt gëtt. Dës zwou Zuelen Aarbecht wéi Vektoruhr an traditionell verdeelt Systemer a setzt d'Bestellung "virdrun geschitt" op Transaktiounen. Mat dësen Donnéeën kann de Kontrakt all méiglech Konflikt léisen.

Tatsächlech ass eng Nummer genuch fir dës Iddi ëmzesetzen, awer mir hu béid verlooss well mir sou eng méi praktesch User-Interface kënne maachen. Zousätzlech hu mir decidéiert de Bezuelbetrag an all Message opzehuelen. Ouni et, wann de Message aus irgendege Grënn verluer ass, dann, obwuel all d'Quantitéiten an d'Finale Berechnung richteg sinn, kann de Benotzer de Verloscht net bemierken.

Fir eis Iddi ze testen, hu mir no Beispiller gesicht fir sou en einfachen a präzise Bezuelkanalprotokoll ze benotzen. Iwwerraschend hu mir nëmmen zwee fonnt:

  1. Beschreiwung eng ähnlech Approche, nëmme fir de Fall vun engem eendirektionalen Kanal.
  2. Tutorial, déi déi selwecht Iddi wéi eis beschreift, awer ouni vill wichteg Detailer ze erklären, wéi allgemeng Richtegkeet a Konfliktléisungsprozeduren.

Et gouf kloer datt et Sënn mécht eise Protokoll am Detail ze beschreiwen, besonnesch Opmierksamkeet op seng Richtegkeet ze bezuelen. No e puer Iteratiounen war d'Spezifikatioun fäerdeg, an elo kënnt Dir och. kuckt op hatt.

Mir hunn de Kontrakt am FunC ëmgesat, a mir hunn d'Kommandolinn Utility geschriwwen fir mat eisem Kontrakt ganz a Fift ze interagéieren, wéi recommandéiert vun den Organisateuren. Mir hätten all aner Sprooch fir eise CLI gewielt, awer mir waren interesséiert Fift ze probéieren fir ze kucken wéi et an der Praxis leeft.

Fir éierlech ze sinn, nodeems mir mat Fift geschafft hunn, hu mir keng zwéngend Grënn gesinn fir dës Sprooch ze léiwer wéi populär an aktiv benotzt Sprooche mat entwéckelt Tools a Bibliothéiken. Programméiere an enger stackbaséierter Sprooch ass zimmlech désagréabel, well Dir musst permanent am Kapp halen wat um Stack ass, an de Compiler hëlleft net mat dësem.

Dofir, eiser Meenung no, déi eenzeg Begrënnung fir d'Existenz vu Fift ass seng Roll als Gaaschtsprooch fir Fift Assembler. Awer wier et net besser den TVM Assembler an eng existent Sprooch z'integréieren, anstatt eng nei ze erfannen fir dësen am Wesentlechen eenzegen Zweck?

TVM Haskell eDSL

Elo ass et Zäit iwwer eisen zweete Smart Kontrakt ze schwätzen. Mir hunn decidéiert e Multi-Ënnerschrëft Portemonnaie z'entwéckelen, awer en anere Smart Kontrakt an FunC ze schreiwen wier ze langweileg. Mir wollten e bësse Goût addéieren, an dat war eis eege Versammlungssprooch fir TVM.

Wéi Fift Assembler, ass eis nei Sprooch agebonnen, awer mir hunn den Haskell als Host gewielt anstatt Fift, wat eis erlaabt eis voll Virdeel vu sengem fortgeschratt Typ System ze notzen. Wann Dir mat Smart Kontrakter schafft, wou d'Käschte vu souguer e klenge Feeler ganz héich kënne sinn, ass statesch Tippen, eiser Meenung no, e grousse Virdeel.

Fir ze demonstréieren wéi den TVM Assembler ausgesäit agebaut an Haskell, hu mir e Standard Portemonnaie drop implementéiert. Hei sinn e puer Saachen fir opzepassen:

  • Dëse Kontrakt besteet aus enger Funktioun, awer Dir kënnt esou vill benotzen wéi Dir wëllt. Wann Dir eng nei Funktioun an der Hostsprooch definéiert (dh Haskell), erlaabt eis eDSL Iech ze wielen ob Dir wëllt datt et eng separat Routine an TVM gëtt oder einfach um Uruffpunkt inlineéiert gëtt.
  • Wéi Haskell, hunn d'Funktiounen Typen, déi bei der Kompiléierungszäit gepréift ginn. An eisem eDSL ass den Inputtyp vun enger Funktioun den Typ Stack deen d'Funktioun erwaart, an de Resultattyp ass den Typ Stack deen nom Uruff produzéiert gëtt.
  • De Code huet Annotatiounen stacktype, beschreiwen der erwaart Stack Typ op der Call Punkt. Am Original Portemonnaie Kontrakt waren dës just Kommentaren, mä an eiser eDSL si eigentlech Deel vun de Code a sinn am Zesummenhang Zäit iwwerpréift. Si kënnen als Dokumentatioun oder Aussoen déngen, déi den Entwéckler hëllefen de Problem ze fannen wann de Code ännert an de Stacktyp ännert. Natierlech beaflossen esou Annotatiounen keng Runtime Performance, well keen TVM Code fir si generéiert gëtt.
  • Dëst ass nach ëmmer e Prototyp deen an zwou Wochen geschriwwe gouf, sou datt et nach vill Aarbecht um Projet muss gemaach ginn. Zum Beispill, all Instanzen vun de Klassen, déi Dir am Code hei ënnen gesitt, sollten automatesch generéiert ginn.

Dëst ass wéi d'Ëmsetzung vun engem Multisig Portemonnaie op eisem eDSL ausgesäit:

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 komplette Quellcode vun eisem eDSL a Multi-Ënnerschrëft Portemonnaie Kontrakt fannt Dir op dëse Repository. A méi am Detail gesot iwwer agebaute Sproochen, eise Kolleg Georgy Agapov.

Conclusiounen iwwert d'Konkurrenz an TON

Am Ganzen huet eis Aarbecht 380 Stonnen gedauert (inklusive Bekanntschaft mat Dokumentatioun, Reuniounen an aktuell Entwécklung). Fënnef Entwéckler hunn um Konkurrenzprojet deelgeholl: CTO, Teamleader, Blockchain Plattform Spezialisten an Haskell Software Entwéckler.

Mir hu Ressourcen fonnt fir ouni Schwieregkeeten un de Concours deelzehuelen, well de Geescht vun engem Hackathon, enk Teamwork, an d'Noutwennegkeet eis séier an Aspekter vun neien Technologien z'entdecken ass ëmmer spannend. E puer schloflos Nuechte fir maximal Resultater a Konditioune vu limitéierten Ressourcen z'erreechen ginn duerch onschätzbar Erfahrung an exzellent Erënnerungen kompenséiert. Zousätzlech ass d'Aarbecht un esou Aufgaben ëmmer e gudden Test vun de Prozesser vun der Firma, well et extrem schwéier ass wierklech uerdentlech Resultater ze erreechen ouni gutt funktionéierend intern Kommunikatioun.

Texter ofgesinn: mir waren beandrockt vun der Quantitéit vun der Aarbecht, déi d'Team TON gemaach huet. Si hunn et fäerdeg bruecht e komplexen, schéinen, an am wichtegsten Aarbechtssystem ze bauen. TON huet sech als Plattform mat groussem Potenzial bewisen. Wéi och ëmmer, fir dësen Ökosystem z'entwéckelen, muss vill méi gemaach ginn, souwuel wat d'Benotzung a Blockchain Projeten ugeet a wat d'Entwécklungsinstrumenter verbessert. Mir sinn houfreg elo en Deel vun dësem Prozess ze sinn.

Wann Dir no dësem Artikel nach ëmmer Froen hutt oder Iddien hutt wéi Dir TON benotzt fir Är Probleemer ze léisen, schreiwen eis - mir wäerte frou eis Erfahrung ze deelen.

Source: will.com

Setzt e Commentaire