Kubadilisha FunC kuwa FunCtional na Haskell: Jinsi Serokell alishinda Mashindano ya Telegraph Blockchain

Pengine umesikia hiyo Telegram inakaribia kuzindua jukwaa la Ton blockchain. Lakini unaweza kuwa umekosa habari ambayo si muda mrefu uliopita Telegram alitangaza shindano kwa utekelezaji wa kandarasi moja au zaidi mahiri za jukwaa hili.

Timu ya Serokell, yenye uzoefu mkubwa katika kuendeleza miradi mikubwa ya blockchain, haikuweza kusimama kando. Tuliwakabidhi wafanyikazi watano kwenye shindano hili, na wiki mbili baadaye walichukua nafasi ya kwanza katika shindano hili chini ya (katika)jina la utani la kawaida lisilo la kawaida la Sexy Chameleon. Katika makala hii nitazungumzia jinsi walivyofanya. Tunatumahi kuwa katika dakika kumi zijazo utasoma hadithi ya kupendeza, na zaidi utapata kitu muhimu ndani yake ambacho unaweza kuomba katika kazi yako.

Lakini wacha tuanze na muktadha mdogo.

Ushindani na masharti yake

Kwa hivyo, kazi kuu za washiriki zilikuwa utekelezaji wa moja au zaidi ya mikataba ya busara iliyopendekezwa, na pia kutoa mapendekezo ya kuboresha mfumo wa ikolojia wa TON. Mashindano hayo yalianza Septemba 24 hadi Oktoba 15, na matokeo yalitangazwa tu Novemba 15. Muda mrefu sana, kwa kuzingatia kwamba wakati huu Telegram iliweza kushikilia na kutangaza matokeo ya mashindano juu ya kubuni na maendeleo ya maombi katika C++ kwa ajili ya kupima na kutathmini ubora wa simu za VoIP katika Telegram.

Tulichagua mikataba miwili mahiri kutoka kwenye orodha iliyopendekezwa na waandaaji. Kwa mmoja wao, tulitumia zana zilizosambazwa na TON, na ya pili ilitekelezwa katika lugha mpya iliyotengenezwa na wahandisi wetu mahsusi kwa TON na kujengwa katika Haskell.

Uchaguzi wa lugha ya programu ya kazi sio ajali. Katika yetu blogu ya ushirika Mara nyingi tunazungumza juu ya kwanini tunafikiria ugumu wa lugha za utendaji ni chumvi kubwa na kwa nini kwa ujumla tunazipendelea kuliko zenye mwelekeo wa kupinga. Kwa njia, pia ina asili ya nakala hii.

Kwa nini hata tuliamua kushiriki?

Kwa kifupi, kwa sababu utaalam wetu si wa kawaida na miradi changamano ambayo inahitaji ujuzi maalum na mara nyingi ni ya thamani ya kisayansi kwa jumuiya ya IT. Tunaunga mkono kwa dhati maendeleo ya chanzo-wazi na tunajishughulisha na umaarufu wake, na pia tunashirikiana na vyuo vikuu vikuu vya Urusi katika uwanja wa sayansi ya kompyuta na hesabu.

Kazi za kupendeza za shindano na kuhusika katika mradi wetu tupendao wa Telegraph zilikuwa motisha bora, lakini mfuko wa tuzo ukawa motisha ya ziada. πŸ™‚

Utafiti wa blockchain wa TON

Tunafuatilia kwa karibu maendeleo mapya katika blockchain, akili bandia na kujifunza kwa mashine na kujaribu kutokosa toleo moja muhimu katika kila sehemu tunamofanyia kazi. Kwa hivyo, wakati shindano lilianza, timu yetu ilikuwa tayari imezoea maoni kutoka karatasi nyeupe ya TON. Walakini, kabla ya kuanza kufanya kazi na TON, hatukuchambua nyaraka za kiufundi na nambari halisi ya chanzo cha jukwaa, kwa hivyo hatua ya kwanza ilikuwa dhahiri - uchunguzi kamili wa hati rasmi juu ya. Online na hazina za mradi.

Kufikia wakati shindano linaanza, msimbo ulikuwa tayari umechapishwa, kwa hivyo ili kuokoa muda, tuliamua kutafuta mwongozo au muhtasari ulioandikwa na na watumiaji. Kwa bahati mbaya, hii haikutoa matokeo yoyote - mbali na maagizo ya kukusanyika jukwaa kwenye Ubuntu, hatukupata vifaa vingine.

Nyaraka zenyewe zilifanyiwa utafiti wa kutosha, lakini ilikuwa vigumu kusoma katika baadhi ya maeneo. Mara nyingi tulilazimika kurudi kwenye sehemu fulani na kubadili kutoka kwa maelezo ya hali ya juu ya mawazo dhahania hadi maelezo ya utekelezaji wa kiwango cha chini.

Ingekuwa rahisi ikiwa maelezo hayakujumuisha maelezo ya kina ya utekelezaji hata kidogo. Taarifa kuhusu jinsi mashine pepe inavyowakilisha rafu yake kuna uwezekano mkubwa wa kuwatatiza wasanidi programu wanaounda kandarasi mahiri za mfumo wa TON kuliko kuwasaidia.

Nix: kuweka mradi pamoja

Katika Serokell sisi ni mashabiki wakubwa Nix. Tunakusanya miradi yetu nayo na kuipeleka kwa kutumia NixOps, na kusakinishwa kwenye seva zetu zote Nix OS. Shukrani kwa hili, miundo yetu yote inaweza kuzaliana na inafanya kazi kwenye mfumo wowote wa uendeshaji ambao Nix inaweza kusakinishwa.

Kwa hivyo tulianza kwa kuunda Nix inayowekelea kwa kujieleza kwa mkusanyiko wa TON. Kwa msaada wake, kuandaa TON ni rahisi iwezekanavyo:

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

Kumbuka kuwa hauitaji kusakinisha vitegemezi vyovyote. Nix itakufanyia kila kitu kichawi, iwe unatumia NixOS, Ubuntu, au macOS.

Kupanga kwa TON

Msimbo mahiri wa mkataba katika Mtandao wa TON hutumika kwenye TON Virtual Machine (TVM). TVM ni ngumu zaidi kuliko mashine zingine nyingi za mtandaoni, na ina utendaji wa kuvutia sana, kwa mfano, inaweza kufanya kazi nayo muendelezo ΠΈ viungo kwa data.

Kwa kuongezea, wavulana kutoka TON waliunda lugha tatu mpya za programu:

Tano ni lugha ya programu ya stack zima inayofanana Nne. Uwezo wake mkuu ni uwezo wa kuingiliana na TVM.

FunC ni lugha ya upangaji wa mikataba mahiri ambayo inafanana na C na imekusanywa katika lugha nyingine - Fift Assembler.

Mkusanyiko wa Tano - Maktaba ya tano ya kutengeneza nambari inayoweza kutekelezeka kwa TVM. Fifth Assembler haina mkusanyaji. Hii Lugha Maalum ya Kikoa (eDSL) Iliyopachikwa.

Ushindani wetu unafanya kazi

Hatimaye, ni wakati wa kuangalia matokeo ya juhudi zetu.

Njia ya malipo ya Asynchronous

Njia ya malipo ni mkataba mzuri unaowaruhusu watumiaji wawili kutuma malipo nje ya blockchain. Matokeo yake, huhifadhi pesa tu (hakuna tume), lakini pia wakati (sio lazima kusubiri kuzuia ijayo kusindika). Malipo yanaweza kuwa madogo kama unavyotaka na mara nyingi inavyohitajika. Katika kesi hiyo, vyama haipaswi kuaminiana, kwa kuwa haki ya makazi ya mwisho imehakikishwa na mkataba wa smart.

Tulipata suluhisho rahisi kwa shida. Washirika wawili wanaweza kubadilishana ujumbe uliotiwa saini, kila moja ikiwa na nambari mbiliβ€”kiasi kamili kinacholipwa na kila mhusika. Nambari hizi mbili hufanya kazi kama saa ya vekta katika mifumo ya kitamaduni iliyosambazwa na kuweka agizo la "lililotokea hapo awali" juu ya shughuli. Kwa kutumia data hii, mkataba utaweza kutatua mzozo wowote unaowezekana.

Kwa kweli, nambari moja inatosha kutekeleza wazo hili, lakini tuliacha zote mbili kwa sababu kwa njia hii tunaweza kufanya kiolesura cha mtumiaji kinachofaa zaidi. Aidha, tuliamua kujumuisha kiasi cha malipo katika kila ujumbe. Bila hivyo, ikiwa ujumbe umepotea kwa sababu fulani, basi, ingawa kiasi na hesabu ya mwisho itakuwa sahihi, mtumiaji hawezi kutambua hasara.

Ili kujaribu wazo letu, tulitafuta mifano ya kutumia itifaki rahisi na fupi ya njia ya malipo kama hii. Kwa kushangaza, tulipata mbili tu:

  1. Description njia sawa, tu kwa kesi ya kituo cha unidirectional.
  2. Mafunzo, ambayo inafafanua wazo sawa na letu, lakini bila kueleza maelezo mengi muhimu, kama vile usahihi wa jumla na taratibu za utatuzi wa migogoro.

Ikawa wazi kuwa ni mantiki kuelezea itifaki yetu kwa undani, kulipa kipaumbele maalum kwa usahihi wake. Baada ya marudio kadhaa, vipimo vilikuwa tayari, na sasa unaweza pia. mtazame.

Tulitekeleza mkataba katika FunC, na tukaandika matumizi ya laini ya amri kwa kuingiliana na mkataba wetu kabisa katika Fift, kama ilivyopendekezwa na waandaaji. Tungeweza kuchagua lugha nyingine yoyote kwa ajili ya CLI yetu, lakini tulikuwa na nia ya kujaribu Fit ili kuona jinsi inavyofanya kazi kwa vitendo.

Kuwa waaminifu, baada ya kufanya kazi na Fift, hatukuona sababu zozote za kulazimisha kupendelea lugha hii kwa lugha maarufu na zinazotumiwa kikamilifu na zana na maktaba zilizotengenezwa. Kupanga programu katika lugha inayotegemea stack haifurahishi kabisa, kwani lazima uweke kichwani mwako kila wakati kile kilicho kwenye stack, na mkusanyaji haisaidii na hii.

Kwa hivyo, kwa maoni yetu, uhalali pekee wa uwepo wa Fift ni jukumu lake kama lugha mwenyeji wa Fift Assembler. Lakini haingekuwa bora kupachika mkusanyiko wa TVM katika lugha iliyopo, badala ya kuvumbua mpya kwa madhumuni haya pekee?

TVM Haskell eDSL

Sasa ni wakati wa kuzungumza juu ya mkataba wetu wa pili wa busara. Tuliamua kutengeneza pochi yenye saini nyingi, lakini kuandika mkataba mwingine mahiri katika FunC itakuwa ya kuchosha sana. Tulitaka kuongeza ladha, na hiyo ilikuwa lugha yetu ya kusanyiko kwa TVM.

Kama Fift Assembler, lugha yetu mpya imepachikwa, lakini tulichagua Haskell kama mwenyeji badala ya Fift, na kuturuhusu kuchukua fursa kamili ya mfumo wake wa aina ya juu. Wakati wa kufanya kazi na mikataba ya smart, ambapo gharama ya hata kosa ndogo inaweza kuwa ya juu sana, kuandika tuli, kwa maoni yetu, ni faida kubwa.

Ili kuonyesha kile kikusanyaji cha TVM kinaonekana kama kilichopachikwa katika Haskell, tulitekeleza mkoba wa kawaida juu yake. Hapa kuna mambo machache ya kuzingatia:

  • Mkataba huu una kazi moja, lakini unaweza kutumia nyingi upendavyo. Unapofafanua chaguo mpya za kukokotoa katika lugha ya seva pangishi (yaani Haskell), eDSL yetu hukuruhusu kuchagua kama unataka iwe utaratibu tofauti katika TVM au iwe na mstari wakati wa kupiga simu.
  • Kama Haskell, kazi zina aina ambazo huangaliwa kwa wakati wa kukusanya. Katika eDSL yetu, aina ya ingizo ya chaguo za kukokotoa ni aina ya rafu ambayo chaguo la kukokotoa linatarajia, na aina ya matokeo ni aina ya rafu itakayotolewa baada ya simu.
  • Msimbo una vidokezo stacktype, ikielezea aina ya rafu inayotarajiwa kwenye sehemu ya simu. Katika mkataba wa asili wa mkoba haya yalikuwa maoni tu, lakini katika eDSL yetu kwa kweli ni sehemu ya msimbo na huangaliwa kwa wakati wa kukusanya. Zinaweza kutumika kama hati au taarifa zinazomsaidia msanidi programu kupata tatizo ikiwa msimbo utabadilika na aina ya rafu itabadilika. Bila shaka, maelezo kama haya hayaathiri utendakazi wa wakati wa utekelezaji, kwani hakuna msimbo wa TVM unaotolewa kwa ajili yao.
  • Hii bado ni mfano ulioandikwa katika wiki mbili, kwa hivyo bado kuna kazi nyingi ya kufanywa kwenye mradi. Kwa mfano, matukio yote ya madarasa unayoona kwenye msimbo hapa chini yanapaswa kuzalishwa kiotomatiki.

Hivi ndivyo utekelezaji wa mkoba wa multisig unavyoonekana kwenye eDSL yetu:

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

Msimbo kamili wa chanzo wa eDSL yetu na mkataba wa pochi wenye saini nyingi unaweza kupatikana hazina hii. Na zaidi aliiambia kwa undani kuhusu lugha zilizojengwa, mwenzetu Georgy Agapov.

Hitimisho kuhusu ushindani na TON

Kwa jumla, kazi yetu ilichukua masaa 380 (ikiwa ni pamoja na kufahamiana na nyaraka, mikutano na maendeleo halisi). Watengenezaji watano walishiriki katika mradi wa shindano: CTO, kiongozi wa timu, wataalamu wa jukwaa la blockchain na wasanidi programu wa Haskell.

Tulipata nyenzo za kushiriki katika shindano bila shida, kwa kuwa roho ya hackathon, kazi ya pamoja ya karibu, na hitaji la kuzama haraka katika vipengele vya teknolojia mpya daima ni ya kusisimua. Usiku kadhaa wa kutolala ili kupata matokeo ya juu zaidi katika hali ya rasilimali chache hulipwa na uzoefu muhimu na kumbukumbu bora. Kwa kuongezea, kufanya kazi kwenye kazi kama hizi kila wakati ni mtihani mzuri wa michakato ya kampuni, kwani ni ngumu sana kufikia matokeo bora bila mwingiliano wa ndani unaofanya kazi vizuri.

Nyimbo za kando: tulivutiwa na kazi nyingi iliyowekwa na timu ya TON. Waliweza kujenga mfumo mgumu, mzuri, na muhimu zaidi, wa kufanya kazi. TON imejidhihirisha kuwa jukwaa lenye uwezo mkubwa. Hata hivyo, ili mfumo huu wa ikolojia uendelezwe, mengi zaidi yanahitajika kufanywa, katika suala la matumizi yake katika miradi ya blockchain na katika suala la kuboresha zana za maendeleo. Tunajivunia sasa kuwa sehemu ya mchakato huu.

Ikiwa baada ya kusoma makala hii bado una maswali yoyote au una mawazo juu ya jinsi ya kutumia TON kutatua matatizo yako, tuandikie - tutafurahi kushiriki uzoefu wetu.

Chanzo: mapenzi.com

Kuongeza maoni