Շատ հավանական է, որ լսած լինեք, որ Telegram . Բայց կարող է, որ բաց թողնեք նորությունը, որ մոտ ժամանակներս Telegram այս պլատֆորմայի համար մեկ կամ մի քանիսը սմարթ-կոնտրակտների կիրարկման։
Serokell թիմը, որը ունի մեծ փորձ համաշխարհային բլոկչեյն նախագծերի մշակման գործում, չէր կարող մնալ անդիմադրելի: Մենք մրցույթին հանձնարարեցինք հինգ աշխատակից, իսկ երկու շաբաթ անց նրանք զբաղեցրեցին առաջին տեղը (ոչ)խոնարհ անուն Sexy Chameleon-ն։ Այս հոդվածում ես կպատմեմ, թե ինչպես նրանք դա հաջողեցին։ Մ hoppas, որ ближайшие десять минут вы как минимум прочитаете интересную историю, а как максимум найдете в ней что-то полезное, что сможете применить в своей работе.
Բայց եկեք սկսենք փոքրիկ խորությամբ վերաբերականություն։
Մրցույթի և նրա պայմանները
Ուրեմն, մասնակցողների հիմնական հարցերը դարձան առաջարկված սմարթ-կոնտրակտներից մեկը կամ մի քանիսը իրականացնելը, ինչպես նաև TON էկոհամակարգի բարելավման առաջարկներ ներկայացնելը։ Մրցույթը սկսվեց սեպտեմբերի 24-ից և ավարտվեցին հոկտեմբերի 15-ին, իսկ արդյունքները հայտարարվեցին միայն նոյեմբերի 15-ին։ Շատ երկար, հաշվի առնելով, որ այս ժամանակահատվածում Telegram-ը հասցրել էր անցկացնել ու հայտնել դիզայնի և C++-ով հավելվածների մշակման մրցույթների արդյունքները VoIP զանգերի որակի փորձարկման և գնահատման համար։
Մենք ընտրեցինք կազմակերպողների առաջարկած ցուցակից երկու սմարթ-կոնտրակտ։ Նրանցից մեկի համար մենք օգտագործեցինք TON-ի հետ միասին տարածվող գործիքներ, իսկ երկրորդը մշակեցինք մեր ինժեներների կողմից հատուկ TON-ի համար մշակված նոր լեզվով, որը ներմուծված էր Haskell-ում։
Ֆունկցիոնալ ծրագրավորման լեզվի ընտրությունը պատահական չէ։ Մեր մենք հաճախ պատմում ենք, թե ինչու ենք կարծում, որ ֆունկցիոնալ լեզուների բարդությունը մեծ չափազանցություն է, իսկ ինչու մենք ընդհանուր առմամբ նախընտրում ենք դրանք օբյեկտային։ ÜBy the way, there is also the .
Ինչու մենք ընդհանրապես որոշեցինք մասնակցել
Եթե կարճ ասենք, որովհետև մեր մասնագիտությունը գտնվում է ոչ ստանդարտ և բարդ նախագծերի, որոնք պահանջում են հատուկ հմտություններ և հաճախ ներկայացնում են գիտական արժեք IT համայնքի համար։ Մենք միտված ենք աջակցել ոչ առևտրային մշակմանը և զբաղվում ենք դրա ժողովրդականացմանը, ինչպես նաև համագործակցում ենք ՌուսԵս համալսարանների հետ մաթեմատիկայի և համակարգչային գիտությունների ոլորտում։
Մրցույթի հետաքրքիր խնդիրները և մեր սիրելի Telegram նախագծին պատկանելը ինքնին լավ դրդապատճառներ էին, իսկ մրցանակային ֆոնը դարձել էր լրացուցիչ խթան։ 🙂
TON բլոկչեյնի հետազոտություն
Մենք ուշադիր հետևում ենք նոր զարգացումներին բլոկչեյնում, արհեստական բանականությամբ և մեքենայական ուսուցմամբ, և փորձում ենք չանտեսել ոչ մի նշանակալի թողարկում այն ոլորտներում, որտեղ աշխատում ենք։ Ուստի մրցույթի մեկնարկի պահին մեր թիմը արդեն ծանոթ էր գաղափարներին, որոնք բարձրաձայնված էին ։ Սակայն TON- ի հետ աշխատանքի սկսվելուց առաջ մենք չենք վերլուծել տեխնիկական փաստաթղթերը և թերևս արդիական կոդը, այդ պատճառով առաջին քայլը բավական պարզ էր՝ պաշտոնական փաստաթղթերի մանրակրկիտ ուսումնասիրություն մեր թիմի համար էր և .
Մրցույթի մեկնարկին կոդը արդեն հրապարակվել էր, այդ պատճառով, ժամանակի խնայելու նպատակով, որոշեցինք որոնել ուղեցույց կամ ամփոփագիր, որը պատրաստել են օգտագործողները։ Աτυχաբար, դա այլևս արդյունք չտվեց՝ բացի Ubuntu- ում հարթակի կառուցման հրահանգից, այլ նյութեր չգտանք։
Ուրեմն, փաստաթղթերն ինքնին լավ մշակված էին, սակայն որոշ կետերը ընթերցելը դժվար էր։ Միշտ պետք էր վերադառնալ որոշ կետերի և անցնել բարձր մակարդակային նկարագրությունից՝ դեպի իրականացման ցածր մակարդակի մանրամասներ։
Կպահպանվեր ավելի հեշտ, եթե სპეცֆիկացիայում իրականացման մանրամասն նկարագրություն ընդհանրապես չլիներ։ Տեղեկատվությունը այն մասին, թե ինչպես վիրտուալ մեքենան ներկայացնում է իր կույտը, ավելի շեղում է TON- ի հարթակային սմարթ- կոնտրակտներ ստեղծող մշակողների ուշադրությունը, քան օգնում նրանց։
Nix. նախագծի հավաքում
Մենք Serokell-ում մեծ երկրպագուներ ենք ։ Մենք նախագծեր ենք հավաքում նրանց համար և տեղադրում ենք հանդիսանում են բոլոր մեր սերվերներում ։ Դրա շնորհիվ մեր բոլոր կառուցումները վերարտադրելի են և աշխատում են ցանկացած գործող համակարգում, որը թույլ է տալիս տեղադրել Nix։
Ահա, մենք սկսեցինք ստեղծել ։ Նրա շնորհիվ TON- ի կոմպիլավորում շատ պարզ է.
$ cd ~/.config/nixpkgs/overlays && git clone https://github.com/serokell/ton.nix
$ cd /path/to/ton/repo && nix-shell
[nix-shell]$ cmakeConfigurePhase && makeԽնդրում ենք նկատի ունենալ, որ անհարկի կախվածություններ պետք չէ տեղադրել։ Nix մոգությամբ կատարում է ամեն բան՝ անկախ նրանից, թե օգտագործում եք NixOS, Ubuntu կամ macOS:
TON-ի համար ծրագրավորում
TON Network-ում սմարթ- կոնտրակտների կոդը կատարում է TON Virtual Machine (TVM)։ TVM-ն ավելի բարդ է, քան մյուս վիրտուալ մեքենաները և ունի բավական հետաքրքիր ֆունկցիոնալություն, օրինակ՝ այն կարող է աշխատել շարունակություններով և ենթակայներ.
Moreover, the TON team has created three new programming languages:
Fift — այսօրինակ խորը կույտերի ծրագրավորման լեզու, որը հիշեցնում է ։ Մենք նրա գերազանց կարողությունն է՝ TVM-ի հետ փոխգործակցելու հնարավորությունը։
FunC — սմարթ կոնտրակտների ծրագրավորման լեզու, որը հիշեցնում է և կոմպիլացնում է ևս մեկ լեզվին՝ Fift Assembler-ին։
Fift Assembler — Fift գրադարանը TVM-ի համար բիթային գործարկման կոդ ստեղծելու համար։ Fift Assembler-ի առկա չէ կոմպիլյատոր։ .
Մեր մրցույթային աշխատանքները
Վերջնականապես, ժամանակն է դիտելու մեր ջանքերի արդյունքները:
Ասինխրոն վճարային ալիք
Վճարային ալիք (payment channel)՝ սմարթ-կոնտրակտ, որը թույլ է տալիս երկու օգտվողների կատարել վճարումներ ներվողջ բլոկչեյնից: Արդյունքում փողի (անվճար տեխնոլոգիայի) ու ժամանակի (չէք սպասելու հերթական բլոկի մշակմանը) խնայողություն է առաջանում: Վճարումները կարող են լինել որքան ուզեք փոքր, և կատարվել այնքան հաճախ, որքան դա անհրաժեշտ է: Շնորհիվ սմարթ-կոնտրակտի, կողմերն իրար վստահելու կարիք չունեն:
Մենք գտանք բավականին պարզ լուծում խնդրին: Երկու կողմերը կարող են փոխանակվել ստորագրված հաղորդագրություններով, որոնց ներսում կան երկու թիվ՝ ընդհանուր գումարը, գումարված յուրաքանչյուր մասնակից կողմից: Այս երկու թվերը ծառայում են որպես 传统分布式系统中,并为交易设定“发生在……前”的顺序。使用这些数据,合同能够解决任何可能的冲突。
Ն tatsächlich ներկայիս ծրագիրը հնարավոր է իրականացնել ընդամենը մեկ թվով, սակայն մենք թողեցինք երկուսը, քանի որ այս կերպ կարողացանք ավելի հարմար օգտվողի ինտերֆես առաջացնել: Ընդլայնվելու համար, մենք ցանկացանք ընդգրկել յուրաքանչյուր հաղորդագրության մեջ վճարի չափը: Վճարների մանրամասը կարևոր է, որովհետև հակառակ դեպքում, եթե հաղորդագրությունը կորոշվելուց ինչ֊որ պատճառներով կորի, ապա, թեև բոլորը գումարները և վերջնական հաշվարկը ճիշտ կլինեն, օգտվողը կորուստը կարող է չնկատել:
Մեր գաղափարը ստուգելու համար մենք որոնեցինք նման պարզ և համեստ վճարային ալիքի արձակման օրինակներ: Արդյունքում,我们只发现了两个:
- առաջինը՝ նման մոտեցում, միայն մեկ ուղղությամբ ալիքի համար:
- , որ անվանում է նույն գաղափարը, որը նման է մեր գաղափարին, սակայն առանց շատ կարևոր մանրամասների բացատրության, ինչպիսիք են ընդհանուր աշխատանքը և冲突解決程序。
Պարզ դարձավ, որ իմաստ կա մանրամասն նկարագրել մեր պրոտոկոլը՝ ուշադրություն դարձնելով դրա ճշտությանը: Բազմաթիվ անկողմնակալություններից հետո, չափազանց վերջնականացումը պատրաստվել է, և այժմ դուք նույնպես կարող եք .
Մենք реализовали контракт на FunC, а утилиту командной строки для взаимодействия с нашим контрактом мы полностью написали на Fift, как рекомендовали организаторы. Мы могли бы выбрать любой другой язык для нашего CLI, но нам было интересно попробовать именно Fift, чтобы посмотреть, как он покажет себя в деле.
Հարավային հարությունից, աշխատելով Fift-ի հետ, մենք չհանդիպեցինք իրական պատճառների, որպեսզի նախապատվությունը տանք այս լեզվին հայտնի և ակտիվորեն օգտագործվող լեզուների նկատմամբ, որոնք ունեն զարգացած գործիքներ և գրադարաններ: Ստեկային լեզվով ծրագրավորելը բավականին անհարմար է, հետևաբար անհրաժեշտ է նախատեսել, թե ինչ տեղավորվում է stek-ում, և կոմպիլյատորը դրա համար գրեթե ոչ մի օգուտ չի տալիս:
Հետևաբար, մեր կարծիքով, Fift-ի գոյության միակ խնդիրը նրա դերն է որպես հոստ-լեզու Fift Assembler-ի համար: Նաև արդյոք չէր լինի ավելի լավ, եթե TVM-ի ասամբլերը մտցվեր արդեն առկա լեզու, այլ ոչ թե նոր ստեղծված լեզու միայն նրա, որ միակ նպատակի համար:
TVM Haskell eDSL
Այժմ ժամանակն է պատմել մեր երկրորդ սմարտ-կոնտրակտի մասին: Мы որոշեցինք ստեղծել բազմակողմանի դրամապանակ, բայց ևս մեկ սմարտ-կոնտրակտ FunC-ում գրել շատ скучно էր: Մենք ուզում էինք ավելացնել մի բան, և դա դարձավ մեր սեփական ասամբլեր լեզուն TVM-ի համար:
Ինչպես Fift Assembler-ը, մեր նոր լեզուն ներդրվում է, միայն որ հոստի առումով մենք ընտրել ենք Haskell, ինչը թույլ է տալիս լիովին օգտագործել նրա առաջադեմ տիպային համակարգը: Սմարտ-կոնտրակտների հետ աշխատելիս, որտեղ նույնիսկ փոքր սխալի գինը կարող է շատ բարձր լինել, ստատիկ տիպավորում, մեր կարծիքով, մեծ առավելություն է:
Համոզվելու համար, թե ինչպես է TVM ասամբլեր-ն կիրառվում Haskell-ում, մենք այն իրականացրինք ստանդարտ դրամապանակի վրա: Ահա մի քանի բաներ, որոնց տպավորություն է առաջացնում:
- Այս կոնտրակտը մեկ գործառույթից է, բայց կարող եք օգտագործել անսահմանափակ թվով: Երբ դուք սահմանում եք նոր գործառույթ հոստ-լեզվով (այն է՝ Haskell-ում), մեր eDSL-ը թույլ է տալիս ձեզ ընտրել, արդյոք այն պետք է վերածվի առանձին ենթածրագրի TVM-ում, թե պարզապես տեղադրվի կոչման վայրում:
- Ինչպես Haskell-ում, գործառույթները ունեն տիպեր, որոնք ստուգվում են կոմպիլյացիայի ժամանակ: Մեր eDSL-ում, գործառույթի մուտքի տիպը դա ստեկի տիպն է, որը սպասում է՝ և արդյունքի տիպը դա ստեկի տիպն է, որը կլինի կոչմանց հետո:
- Կոդում կան անոտացիաներ
stacktype, վկայակոչելով սպասվող ստեկի տիպը կոչման կետում: Ծրագիր դրամապանակի սկզբնական օրինակում սա պարզապես մեկնաբանություններ էին, բայց մեր eDSL-ում դրանք实际上 являются частями кода и проверяются во время компиляции. Они могут служить документацией или утверждениями, которые помогают разработчику найти проблему в случае, если при изменении кода тип стека изменится. Само собой, такие аннотации не влияют на производительность во время выполнения, поскольку никакой TVM код для них не генерируется. - Это все еще прототип, написанный за две недели, поэтому над проектом предстоит еще много работы. Например, все экземпляры классов, которые вы видите в приведенном ниже коде, должны генерироваться автоматически.
Вот как выглядит реализация multisig-кошелька на нашем 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Ձեր eDSL-ի և բազմակի ստորագրության դրամատուրյան ամբողջական ծածկագիրը կարող եք գտնել Ավելի մեր գործընկեր Գեորգի Ագապովի կողմից:
Մրցույթի և TON-ի արդյունքները
Մեր աշխատանքը ընդհանուր առմամբ տևել է 380 ժամ (ներառյալ փաստաթղթերին ծանոթանալը, ժողովները և իրական ծրագրավորումը): Մրցույթին մասնակցել է five ծրագրավորողներ՝ CTO, թիմի ղեկավար, բլոկչեյն հարթակների մասնագետներ և Haskell ծրագրերի մշակողներ:
Մրցույթում մասնակցելու համար անհրաժեշտ ռեսուրսները հեշտությամբ գտանք, քանի որ հաքաթոնի ոգին, խիստ թիմային աշխատանքը, նոր տեխնոլոգիաների մեջ արագ ներգրավվելու անհրաժեշտությունը՝ միշտ է հետաքրքիր: Մի քանի անհավատալի գիշերներ՝ լավագույն արդյունք ունենալու համար սահմանափակ ռեսուրսների պայմաններում, փոխվում են անգնահատելի փորձառությամբ և հիանալի հիշողություններով: Բացի այդ, նման խնդիրների վրա աշխատելը միշտ լավ ստուգում է ընկերության գործընթացները, քանի որ իսկապես արժանի արդյունքների հասնելը՝ առանց գերազանց կազմակերպական համագործակցության, միանգամայն դժվար է:
Բայց իրավիճակն ավելի լուրջ է: Մենք տպագրվել էինք TON թիմի կատարած աշխատանքի ծավալով։ Նրանց հաջողվել է կառուցել բարդ, գեղեցիկ և ամենակարևորը՝ աշխատանքային համակարգ։ TON-ը ապացուցել է, որ ունի մեծ ներուժ։ Այնուամենայնիվ, այդ էկոսիստեման զարգանալու համար դեռ շատ աշխատանք պետք է կատարվի, թե blockchain նախագծերում դրա կիրառման տեսանկյունից, թե զարգացման գործիքների կատարելագործման առումով։ Մենք ուրախանում ենք, որ հիմա դառնում ենք այս գործընթացի մաս։
Եթե այս հոդվածը կարդալուց հետո դեռ հարցեր ունեք կամ մտքեր ունեք TON-ի կիրառման մասին ձեր խնդիրներին լուծում տալու համար, ՝ մենք հաճությամբ կիսվելու ենք մեր փորձով։
Ընտանիք: habr.com
