FunC-ni Haskell ilə FunCtional-a çevirmək: Serokell Telegram Blockchain Müsabiqəsini necə qazandı

Şübhəsiz ki, Telegram-ın Ton blockchain platformasını işə salmağa hazırlaşdığını eşitmisiniz. Lakin, bəlkə də, siz Telegram-ın bir müsabiqə elan etdiyini bu platforma üçün bir və ya bir neçə smart kontrakt hazırlanması məqsədilə göz ardı etmisiniz.

Serokell komandası, böyük blockchain layihələrinin inkişafında zəngin təcrübəyə malik bir qrup olaraq geri qalmadı. Biz müsabiqəyə beş işçimizi göndərdik və artıq iki həftədən sonra onlar Sexy Chameleon adını daşıyan (həmin) mücərrəd ləqəblə birinci yerdə irəlilədilər. Bu yazıda onların necə uğur qazandıqlarını sizə izah edəcəyəm. Ümid edirik ki, önümüzdəki on dəqiqə ərzində ya ən azı maraqlı bir hekayə oxuyarsınız, ya da işinizdə tətbiq edə biləcəyiniz bir şey taparsınız.

Amma əvvəlcə kontekstə kiçik bir daldırma edək.

Müsabiqə və onun şərtləri

Beləliklə, iştirakçıların əsas vəzifələri təklif olunan smart kontraktlardan birinin və ya bir neçəsinin icrası, eləcə də TON ekosisteminin təkmilləşdirilməsi üçün təkliflər təqdim etmək idi. Müsabiqə 24 sentyabr - 15 oktyabr tarixləri arasında keçirildi və nəticələr yalnız 15 noyabrda elan edildi. Bu, müvafiq olaraq, Telegram-ın dizayn və C++ tətbiq inkişafı üzrə müsabiqələrin nəticələrini açıqladığı vaxtdan bayaqdır, olduqca uzun bir müddət idi.

Biz təşkilatçılar tərəfindən təklif olunan siyahıdan iki smart kontrakt seçdik. Birinin icrası üçün TON ilə birlikdə təqdim olunan alətlərdən istifadə etdik, ikincisini isə mühəndislərimiz tərəfindən xüsusi olaraq TON üçün hazırlanmış yeni bir dildə reallaşdırdıq və Haskell-ə daxil etdik.

Funksional proqramlaşdırma dilinin seçimi təsadüfi deyil. Bizim korporativ blogumuzda biz tez-tez funksional dillərin çətinliyinin böyük bir abartı olduğunu düşündüyümüzü, eləcə də ümumilikdə onların obyekt yönlü dillərə nisbətən niyə üstünlük verdiyimizi izah edirik. Bu yazıda da bu məqalənin orijinalını.

Niyə iştirak etməyə qərar verdik

Qısaca desək, bizim ixtisas sahəmiz qeyri-standart və mürəkkəb layihələrdir ki, bunlar xüsusi bacarıqlar tələb edir və çox vaxt IT icması üçün elmi dəyəri vardır. Biz açıq mənbə inkişafını səmimi olaraq dəstəkləyirik və onun populyarlaşdırılması ilə məşğul oluruq, eyni zamanda Rusiyanın aparıcı universitetləri ilə kompüter elmləri və riyaziyyat sahəsində əməkdaşlıq edirik.

Müsabiqənin maraqlı tapşırıqları və sevimli Telegram layihəmizdə iştirak etməyimiz özlüyündə gözəl motivasiya oldu, mükafat fondu isə əlavə stimula çevrildi. 🙂

TON blockchain-nin araşdırılması

Biz blockchain, süni intellekt və maşın öyrənməsi sahələrindəki yeni inkişafları yaxından izləyirik və hər bir sahədə hər bir əhəmiyyətli buraxılışı qaçırmamağa çalışırıq. Buna görə müsabiqənin başlanmasına qədər komandamız artıq TON ağ kağızındaki ideyalarla tanış idi.. Lakin TON ilə işə başlamazdan əvvəl texniki sənədləri və faktiki mənbə kodunu analiz etmədiyimiz üçün ilk addım aydın oldu — rəsmi sənədləri diqqətlə araşdırmaq. saytdalayihə depozitində.

Müsabiqənin başlanğıcında kod artıq yayımlandığı üçün vaxt qazanmaq məqsədilə rəhbərlik və ya istifadəçilər tərəfindən yazılmış xülasə axtarmağa qərar verdik. istifadəçilər. Təssüf ki, bunun nəticəsi olmadı — Ubuntu-da platformanın yığılmasıyla bağlı təlimatdan başqa heç bir material tapa bilmədik.

Sənədin özü diqqətlə hazırlanmışdı, lakin bəzən oxumaq çətin olurdu. Tez-tez müəyyən bəndlərə qayıtmalı olduq və yüksək səviyyəli abstrakt fikirlərdən aşağı səviyyəli icra detallarına keçməli olduq.

Əgər spesifikasiyada icra detalları olmayaydı, daha asan olardı. Virtual maşının yığını necə təqdim etdiyinə dair məlumat, TON platforması üçün ağıllı müqavilələr yaradan tərtibatçılara kömək etməkdən çox, onları yayındırır.

Nix: layihəni yığırıq

Serokell-də biz Nixböyük pərəstişkarlarıyıq. Biz layihələrimizi yığırıq və onlarıNixOps ilə yerləşdiririk, bütün serverlərimizdə isəNixOS

. Bu sayədə bütün yükləmələrimiz reproducible-dir və Nix quraşdırıla bilən hər bir əməliyyat sistemi altında işləyir. Ona görə də TON-u yığmaq üçün birNix overlay yaratmağa başladıq.

Bu vasitə ilə TON-u yığmaq çox asandır:

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

Qeyd edək ki, heç bir asılılıq quraşdırmalısınız. Nix sehrli şəkildə sizin üçün hər şeyi edəcək, NixOS, Ubuntu və ya macOS-dan istifadə etmənizəsasən.

TON üçün proqramlaşdırma TON Şəbəkəsində ağıllı müqavilələrin kodu TON Virtual Maşınında (TVM) icra olunur. TVM, əksər digər virtual maşınlardan daha mürəkkəbdir və məsələn,xüsusiyyətləri ilə zəngin odda (continuations).

məlumatlara istinadlar

Bundan əlavə, TON-dan olanlar tam üç yeni proqramlaşdırma dili yaradıb: Fift — Forth-a bənzəyən universal yığma proqramlaşdırma dili. Onun super qabiliyyəti TVM ilə qarşılıqlı əlaqə qurmaqdır.FunC

— C-yə bənzəyən ağıllı müqavilə proqramlaşdırma dili və Fift Yığma dilinə tərtib olunur. Fift Yığma — TVM üçün ikili icra kodu istehsal edən Fift kitabxanası. Fift Yığmanın tərtibatçısı yoxdur. Bu, inteqrasiya olunmuş predmetə yönəldilmiş dildir (eDSL)

Müsabiqə işlərimiz Nəhayət, səylərimizin nəticələrinə baxma vaxtı gəlib. Asinxron ödəniş kanalı.

Müsabiqə işlərimiz

Nəhayət, əlimizdən gələnin nəticələrinə nəzər salmağın vaxtı gəldi.

Asinxron ödəmə kanalı

Ödəniş kanalı (payment channel) — smart müqavilədir ki, iki istifadəçiyə blockchain xaricində ödənişlər göndərməyə imkan tanıyır. Nəticədə həm pul (komissiya yoxdur), həm də vaxt (növbəti blokun emal edilməsini gözləmək lazım deyil) qənaət olunur. Ödənişlərin istənilən qədər kiçik olması və lazım olduğu qədər tez-tez baş verməsi mümkündür. Eyni zamanda, tərəflərin bir-birilərinə etibar etmələri zəruri deyil, çünki yekun hesabın ədaləti smart müqavilə ilə təmin olunur.

Biz problemi həll etmək üçün olduqca sadə bir yol tapdıq. İki tərəf imzalanmış mesajlar mübadilə edə bilər, hər biri iştirakçıların ödənilmiş tam məbləğini ehtiva edən iki ədəd daşıyır. Bu iki ədəd vektor saatları ənənəvi paylanmış sistemlərdədir və transaksiyalarda «bu baş verdi» sırasını müəyyən edir. Bu məlumatlardan istifadə edərək, müqavilə hər hansı bir mümkün konfliktin həllini təmin edə biləcək.

Əslində, bu ideyanın həyata keçirilməsi üçün tək ədəd kifayət edir, amma biz həm ikisini saxladıq, çünki bu sayədə daha rahat bir istifadəçi interfeysi qura bildik. Bundan əlavə, hər mesajda ödənişin ölçüsünü daxil etməyə qərar verdik. Bu olmadan, əgər mesaj hər hansı bir səbəbdən itərsə, bütün məbləğlər və yekun hesab düzgün olsa da, istifadəçi itirimi əllə bilmir.

İdeyamızı yoxlamaq üçün belə sadə və sərt protokolun tətbiqinə dair misallar axtardıq. Təəccüblü şəkildə, yalnız iki nümunə tapdıq:

  1. Təsvir bənzər yanaşma, yalnız bir istiqamətli kanalla bağlıdır.
  2. Tutorial, burada eyni fikrin açıqlanması təklif olunur, amma mühüm detallar, məsələn, ümumi düzgünlük və konfliktlərin həll proseduru haqqında heç bir açıqlama yoxdur.

Aydın oldu ki, protokolumuzu ətraflı təsvir etmək, onun düzgünlüyünə xüsusilə diqqət yetirmək məsləhətlidir. Bir neçə iterasiyadan sonra spesifikasiya hazır oldu və indi siz də ona baxa bilərsiniz.

Biz FunC üzərində müqaviləni həyata keçirdik, komandalar ilə qarşılıqlı əlaqə üçün istifadə etdiyimiz köməkçi vasitəni isə tamamilə Fift üzərində yazdıq, təşkilatçıların tövsiyə etdiyi kimi. CLI üçün istənilən digər dili seçə bilərdik, amma Fiftin özünü necə göstərəcəyini görmək üçün məhz Fift ilə sınamağa maraqlandıq.

Honest olaraq, Fiftilə çalışdıqca, bu dilin geniş alətlər və kitabxanalarla tanınmış və aktiv şəkildə istifadə edilən dillərə nisbətən üstün olduğunu düşünmək üçün ciddi səbəblər görmədik. Stek dilində proqramlaşdırmaq olduqca narahatdır, çünki insanın yaddaşında stackdə nə olduğu daim saxlanılması lazım olur və kompilyator bununla heç bir kömək etmir.

Buna görə də, bizim fikrimizcə, Fift-in mövcud olmasının yeganə əsaslandırılması onun Fift Assembler üçün host dili kimi roludur. Ancaq bir mövcud dilin içində TVM assemblerini yerləşdirmək daha yaxşı olmazdımı, yeni bir dil icad etməkdən ziyadə, bu, əslində yeganə məqsəd üçündür?

TVM Haskell eDSL

İndi ikinci smart müqaviləmiz haqqında danışmağın vaxtıdır. Biz çox imza funksiyalı bir cüzdan hazırlamağa qərar verdik, amma FunC-da daha bir smart müqavilə yazmaq çox darıxdırıcı olacaqdı. Nəsə bir fərqlilik əlavə etmək istədik və bu, TVM üçün öz asan dili olan assemblerimiz oldu.

Fift Assembler-də olduğu kimi, yeni dilimiz daxildir, sadəcə Fift yerinə host kimi Haskell-i seçdiq, bu da onun inkişaf etmiş tip sistemindən tam istifadə etməyə imkan verdi. Smart müqavilələrlə işləyərkən, kiçik bir səhvin qiyməti çox yüksək ola biləcəyi üçün, statik tipizasiya bizim fikrimizcə böyük bir üstünlükdür.

TVM-ni Haskell-ə daxil edilən assembler ilə necə görünəcəyini nümayiş etdirmək üçün standart cüzdanı həyata keçirmişik. Diqqət yetirməlisiniz bir neçə şey:

  • Bu müqavilə yalnız bir funksiyadan ibarətdir, amma siz istədiyiniz qədər istifadə edə bilərsiniz. Host dilində (yəni Haskell-də) yeni funksiya müəyyən etdiyiniz zaman, bizim eDSL sizə bunun TVM-də ayrı bir subprograma çevrilməsini və ya sadəcə çağırış yerinə daxil edilməsini seçmək imkanı verir.
  • Haskell-də olduğu kimi, funksiyaların tipləri var ki, bu da kompilyasiya zamanı yoxlanılır. Bizim eDSL-də funksiyanın giriş tipi gözlənilən yığın tipidir, funksiyanın çağırılmasından sonra əldə ediləcək nəticə tipi isə yığın tipidir.
  • Kodda anotasyonlar var stacktype, çağırış yerində gözlənilən yığın tipini təsvir edən. Orijinal cüzdan müqaviləsində bunlar sadəcə şərhlər idi, amma bizim eDSL-də bunlar əslində kodun bir hissəsidir və kompilyasiya zamanı yoxlanılır. Onlar inkişaf etdiricinin kodu dəyişdirdikdə yığın tipinin dəyişməsi halında problemi tapmasına kömək edən sənəd və ya iddialar olaraq xidmət edə bilər. Bu anotasyonların icra zamanı performansa heç bir təsiri yoxdur, çünki onlar üçün heç bir TVM kodu yaradılmır.
  • Bu hələ də iki həftə ərzində yazılmış prototipdir, buna görə də layihə üzərində daha çox iş var. Məsələn, aşağıdakı kodda gördüyünüz bütün sinif nümunələri avtomatik olaraq yaradılmalıdır.

Budur, bizim eDSL-də multisig cüzdanın icrası belə görünür:

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

Tam bir eDSL-nin tam qaynaq kodunu və çoxsaylı imza ilə cüzdan müqaviləsini burada tapa bilərsiniz bu depoda. Daha ətraflı proqramlaşdırma dilləri haqqında bizim həmkarımız Georgiy Agapov danışdı. Tədqiqatın nəticələri və TON

Cəm bizim işimiz 380 saat (sənədlərlə, görüşlərlə və inkişafla birlikdə) çəkdi. Müsabiqə layihəsinə beş inkişafçı qatıldı: CTO, komanda lideri, blokçeyn platformaları üzrə mütəxəssislər və Haskell-də proqram təminatı tərtibatçıları.

Müsabiqədə iştirak üçün resursları asanlıqla tapdıq, çünki hackathon ruhu, sıx komanda işi, yeni texnologiyaların aspektlərinə sürətli uyğunlaşma ehtiyacı həmişə maraqlıdır. Məhdud resurslar şəraitində maksimum nəticə əldə etmək üçün bir neçə yatmamış gecələrin təmin etdiyi dəyərlidir, bu da improper dəyişikliklər qrafiyalardan doğurur. Belə məsələlər üzərində iş görmək, şirkət proseslərinin yaxşı testidir, çünki gerçəkdən layiqli nəticələr əldə etməyi yüksəkdə inkişaf etdirilmiş daxili əməkdaşlıq olmadan çox çətindir.

Müsabiqədə iştirak üçün resursları asanlıqla tapdıq, çünki hackathon ruhu, sıx komanda işi, yeni texnologiyaların aspektlərinə sürətli adaptasiya ehtiyacı həmişə maraqlıdır. Məhdud resurslar şəraitində maksimum nəticəyə nail olmaq üçün bir neçə yuxusuz gecə keçirilmiş olsa da, bu, qiymətsiz təcrübə və gözəl xatirələrlə kompensasiya olunur. Üstəlik, belə tapşırıqlar üzərində işləmək, şirkətin proseslərini yoxlamaq üçün hər zaman yaxşı bir yoldur, çünki həqiqətən layiqli nəticələr əldə etmək üçün mükəmməl təşkil edilmiş daxili əlaqələr olmadan çox çətindir.

Lirikanı bir kenara bırakırsak: TON ekibinin yaptığı çalışmaların hacminden etkilendik. Karmaşık, güzel ve en önemlisi çalışan bir sistem inşa etmeyi başardılar. TON, büyük bir potansiyele sahip bir platform olarak kendini gösterdi. Ancak bu ekosistemin gelişmesi için hala çok şey yapılması gerekiyor; hem blok zincir projelerinde kullanımı açısından, hem de geliştirme araçlarının iyileştirilmesi açısından. Bu sürecin bir parçası olmaktan gurur duyuyoruz.

Bu makaleyi okuduktan sonra herhangi bir sorunuz veya TON'u ihtiyaçlarınızı çözmek için nasıl kullanabileceğinize dair fikirleriniz varsa, bize yazın — deneyimlerimizi seve seve paylaşırız.

Mənbə: habr.com

DDoS qoruması olan saytlara etibarlı hosting satın alın, VPS VDS serverlər 🔥 DDoS qoruması olan saytlara etibarlı hosting satın alın, VPS VDS serverlər | ProHoster