Du har sÀkert hört talas om att Telegram . Men du kanske har missat nyheten att Telegram för implementering av en eller flera smarta kontrakt för denna plattform.
Teamet pÄ Serokell, med omfattande erfarenhet av utveckling av stora blockkedjeprojekt, kunde inte stÄ vid sidan av. Vi delegerade fem anstÀllda till tÀvlingen, och redan efter tvÄ veckor tog de förstaplatsen med det (inte sÄ) blygsamma slumpmÀssiga namnet Sexy Chameleon. I denna artikel kommer jag att berÀtta om hur de lyckades. Vi hoppas att du inom de nÀrmaste tio minuterna Ätminstone kommer att lÀsa en intressant historia, och som mest hitta nÄgot nyttigt att anvÀnda i ditt arbete.
Men lÄt oss börja med en liten dykning i kontexten.
TĂ€vlingen och dess villkor
SÄ, de huvudsakliga uppgifterna för deltagarna bestod av att implementera ett eller flera av de föreslagna smarta kontrakten, samt att föreslÄ förbÀttringar av TON-ekosystemet. TÀvlingen pÄgick frÄn 24 september till 15 oktober, och resultaten tillkÀnnagavs först den 15 november. Ganska lÀnge, med tanke pÄ att Telegram under denna tid lyckades genomföra och tillkÀnnage resultaten av tÀvlingarna för design och utveckling av applikationer i C++ för att testa och bedöma kvaliteten pÄ VoIP-samtal i Telegram.
Vi valde tvÄ smarta kontrakt frÄn listan som presenterades av arrangörerna. För ett av dem anvÀnde vi verktyg som distribueras tillsammans med TON, och det andra implementerade vi pÄ ett nytt sprÄk som vÄra ingenjörer utvecklade speciellt för TON och integrerade i Haskell.
Valet av funktionellt programmeringssprÄk Àr inte av en slump. I vÄr berÀttar vi ofta varför vi anser att komplexiteten i funktionella sprÄk Àr en stor överdrift och varför vi generellt föredrar dem framför objektorienterade. Förresten, dÀr finns ocksÄ .
Varför bestÀmde vi oss överhuvudtaget för att delta
Kort sagt specialist för oss Àr skrÀddarsydda och komplexa projekt som krÀver speciella fÀrdigheter och ofta har vetenskapligt vÀrde för IT-gemenskapen. Vi stödjer hÀngivet open-source-utveckling och arbetar med att popularisera den, samt samarbetar med ledande universitet i Ryssland inom datavetenskap och matematik.
De intressanta uppgifterna i tĂ€vlingen och vĂ„r koppling till det Ă€lskade projektet Telegram var en stor motivation i sig, och prispotten blev en extra stimulans. đ
Forskning om blockchain TON
Vi följer noggrant de nya framstegen inom blockchain, artificiell intelligens och maskininlĂ€rning och försöker inte missa nĂ„gon signifikant release inom varje omrĂ„de dĂ€r vi arbetar. DĂ€rför var vĂ„rt team redan bekant med idĂ©erna frĂ„n . Men innan vi började arbeta med TON hade vi inte analyserat den tekniska dokumentationen eller den faktiska kĂ€llkoden för plattformen, sĂ„ det första steget var ganska uppenbart â noggrant studera den officiella dokumentationen pĂ„ och i .
Vid tĂ€vlingens början var koden redan publicerad, sĂ„ för att spara tid beslutade vi att leta efter handledning eller sammanstĂ€llningar skrivna av anvĂ€ndare. TyvĂ€rr gav detta ingen framgĂ„ng â vi hittade inte andra material Ă€n instruktionshandboken för att kompilera plattformen pĂ„ Ubuntu.
SjÀlva dokumentationen visade sig vara noggrant genomarbetad, men det var ibland svÄrt att lÀsa den. Vi fick ofta gÄ tillbaka till olika punkter och vÀxla frÄn hög nivÄ beskrivningar av abstrakta idéer till lÄgnivÄ detaljer av implementationen.
Det skulle ha varit lÀttare om specifikationen överhuvudtaget inte hade en detaljerad beskrivning av implementationen. Informationen om hur den virtuella maskinen representerar sin stack stör snarare utvecklare som skapar smarta kontrakt för TON-plattformen Àn hjÀlper dem.
Nix: vi bygger projektet
PÄ Serokell Àr vi stora fans av . Vi bygger vÄra projekt med den och deployar dem med hjÀlp av , och pÄ alla vÄra servrar Àr . Detta gör att alla vÄra byggen Àr reproducerbara och fungerar pÄ vilket operativsystem som helst dÀr Nix kan installeras.
DÀrför började vi med att skapa . Med hjÀlp av det Àr det enkelt att kompilera TON:
$ cd ~/.config/nixpkgs/overlays && git clone https://github.com/serokell/ton.nix
$ cd /path/to/ton/repo && nix-shell
[nix-shell]$ cmakeConfigurePhase && makeObservera att du inte behöver installera nÄgra beroenden. Nix gör magiskt allt Ät dig oavsett om du anvÀnder NixOS, Ubuntu eller macOS.
Programmering för TON
Koden för smarta kontrakt inom TON Network körs pÄ TON Virtual Machine (TVM). TVM Àr mer komplex Àn de flesta andra virtuella maskiner och har mycket intressanta funktioner, till exempel kan den arbeta med fortsÀttningar (continuations) och datareferenser.
Dessutom har killarna frÄn TON skapat hela tre nya programmeringssprÄk:
Fift â ett mĂ„ngsidigt stackbaserat programmeringssprĂ„k som pĂ„minner om . Dess superkraft Ă€r förmĂ„gan att interagera med TVM.
FunC â ett programmeringssprĂ„k för smarta kontrakt som liknar och kompileras till ytterligare ett sprĂ„k â Fift Assembler.
Fift Assembler â ett Fift-bibliotek för att generera binĂ€r körbar kod för TVM. Fift Assembler har ingen kompilator. Det Ă€r en .
VÄra tÀvlingsarbeten
Ăntligen Ă€r det dags att titta pĂ„ resultaten av vĂ„ra anstrĂ€ngningar.
Asynkront betalningskanal
Betalningskanalen (payment channel) Àr ett smart kontrakt som lÄter tvÄ anvÀndare göra betalningar utanför blockchain. Detta sparar inte bara pengar (ingen avgift), utan ocksÄ tid (du behöver inte vÀnta pÄ att nÀsta block ska behandlas). Betalningar kan vara hur smÄ som helst och ske sÄ ofta det krÀvs. Parterna behöver inte nödvÀndigtvis lita pÄ varandra, eftersom rÀttvisan i den slutliga avrÀkningen garanteras av smarta kontrakt.
Vi har hittat en ganska enkel lösning pĂ„ problemet. TvĂ„ parter kan byta signerade meddelanden, var och en innehĂ„llande tvĂ„ nummer â det totala belopp som betalats av varje deltagare. Dessa tvĂ„ nummer fungerar som i traditionella distribuerade system och bestĂ€mmer ordningen "skedde före" pĂ„ transaktionerna. Med hjĂ€lp av dessa data kan kontraktet lösa eventuella möjliga konflikter.
För att genomföra denna idé rÀcker det faktiskt med ett enda nummer, men vi har lÀmnat bÄda eftersom det gör att vi kan skapa ett mer anvÀndarvÀnligt grÀnssnitt. Dessutom beslutade vi att inkludera betalningsbeloppet i varje meddelande. Utan detta, om meddelandet av nÄgon anledning gÄr förlorat, kan anvÀndaren missa förlusten, trots att alla belopp och den slutliga berÀkningen Àr korrekta.
För att testa vÄr idé letade vi efter exempel pÄ anvÀndning av ett sÄdant enkelt och koncist betalningskanalsprotokoll. Till vÄr förvÄning upptÀckte vi bara tvÄ:
- en liknande metod, men för en envÀgs kanal.
- , som beskriver samma idé som vÄr, men utan att förklara mÄnga viktiga detaljer, som den övergripande korrektheten och konfliktlösningsproceduren.
Det blev tydligt att det Àr meningsfullt att noggrant beskriva vÄrt protokoll, med sÀrskilt fokus pÄ dess korrekthet. Efter nÄgra iterationer var specificationen klar, och nu kan du ocksÄ .
Vi implementerade kontraktet pÄ FunC, och verktyget för kommandorad för att interagera med vÄrt kontrakt skrev vi helt pÄ Fift, som rekommenderades av arrangörerna. Vi skulle kunna vÀlja vilket annat sprÄk som helst för vÄr CLI, men vi var intresserade av att prova just Fift för att se hur det presterar i praktiken.
Ărligt talat, efter att ha arbetat med Fift har vi inte sett nĂ„gra övertygande skĂ€l att föredra detta sprĂ„k framför populĂ€ra och aktivt anvĂ€nda sprĂ„k med utvecklade verktyg och bibliotek. Att programmera pĂ„ ett stackbaserat sprĂ„k Ă€r ganska obehagligt, eftersom man hela tiden mĂ„ste hĂ„lla reda pĂ„ vad som ligger i stacken, och kompilatorn hjĂ€lper inte pĂ„ nĂ„got sĂ€tt.
DÀrför anser vi att den enda rimliga anledningen till Fifts existens Àr dess roll som vÀrd-sprÄk för Fift Assembler. Men skulle det inte varit bÀttre att integrera TVM-assemblern i ett befintligt sprÄk istÀllet för att skapa ett nytt för detta i sjÀlva verket enda syfte?
TVM Haskell eDSL
Nu Àr det dags att berÀtta om vÄrt andra smarta kontrakt. Vi beslutade oss för att utveckla en plÄnbok med multisignatur, men att skriva ett ytterligare smart kontrakt pÄ FunC skulle vara alldeles för trÄkigt. Vi ville lÀgga till nÄgot speciellt, och det blev vÄrt eget assembler-sprÄk för TVM.
Precis som Fift Assembler, Àr vÄrt nya inbÀddade sprÄk, men istÀllet för Fift har vi valt Haskell som vÀrd vilket gjorde att vi fullt ut kunde utnyttja dess avancerade typystem. NÀr man arbetar med smarta kontrakt, dÀr kostnaden för Àven ett litet fel kan vara mycket hög, anser vi att statisk typning Àr en stor fördel.
För att demonstrera hur TVM-assemblern inbÀddad i Haskell ser ut, har vi implementerat en standardplÄnbok. HÀr Àr nÄgra saker att beakta:
- Detta kontrakt bestÄr av en funktion, men du kan anvÀnda hur mÄnga som helst. NÀr du definierar en ny funktion pÄ vÀrd-sprÄket (d.v.s. pÄ Haskell), lÄter vÄr eDSL dig vÀlja om du vill att den ska bli en separat underprogram i TVM eller bara inbÀddas i anropsstÀllet.
- Likt Haskell har funktioner typer som kontrolleras vid kompilering. I vÄr eDSL Àr typ av funktionens ingÄng den typ av stack som funktionen förvÀntar sig, medan resultattypen Àr den typ av stack som kommer att fÄs efter anropet.
- Koden innehÄller annotationer
stacktype, som beskriver den förvÀntade typen av stack i anropspunkten. I det ursprungliga plÄnboks-kontraktet var dessa bara kommentarer, men i vÄr eDSL Àr de faktiskt en del av koden och kontrolleras vid kompilering. De kan fungera som dokumentation eller pÄstÄenden som hjÀlper utvecklaren att identifiera problem om typstacken Àndras vid kodÀndringar. SjÀlvklart pÄverkar sÄdana annotationer inte prestandan vid körning, eftersom ingen TVM-kod genereras för dem. - Detta Àr fortfarande en prototyp som skrevs pÄ tvÄ veckor, sÄ det ÄterstÄr mycket arbete i projektet. Till exempel mÄste alla klassinstanser som du ser i koden nedan genereras automatiskt.
SÄ hÀr ser implementeringen av en multisig-plÄnbok ut i vÄr 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 @Word32Den fullstÀndiga kÀllkoden för vÄr eDSL och plÄnbokskontraktet med multisignatur kan du hitta i En mer vÄr kollega Georgiy Agapov.
Slutsatser om tÀvlingen och TON
Totalt tog vÄrt arbete 380 timmar (inklusive att sÀtta sig in i dokumentationen, möten och sjÀlva utvecklingen). Fem utvecklare deltog i tÀvlingsprojektet: CTO, teamledare, specialister pÄ blockchain-plattformar och programvaruutvecklare i Haskell.
Vi hittade resurser för att delta i tÀvlingen utan svÄrighet, eftersom hackathon-andan, den nÀra lag-arbetsinsatsen och behovet av att snabbt dyka ner i aspekter av ny teknik alltid Àr fascinerande. NÄgra sömnlösa nÀtter för att uppnÄ maximala resultat under begrÀnsade resurser kompenseras av ovÀrderlig erfarenhet och utmÀrkta minnen. Dessutom Àr arbete med sÄdana uppgifter alltid en bra test pÄ företagets processer, eftersom det Àr extremt svÄrt att uppnÄ verkligt anstÀndiga resultat utan en utmÀrkt inre interaktion.
Förutom lyriken: vi var imponerade av den arbetsvolym som TON-teamet utfört. De lyckades bygga ett komplext, vackert och framför allt fungerande system. TON har visat sig vara en plattform med stor potential. Men för att detta ekosystem ska utvecklas krÀvs det fortfarande mycket arbete, bÄde nÀr det gÀller dess anvÀndning i blockchain-projekt och nÀr det gÀller att förbÀttra utvecklingsverktygen. Vi Àr stolta över att nu vara en del av denna process.
Om du efter att ha lĂ€st den hĂ€r artikeln har nĂ„gra frĂ„gor eller idĂ©er om hur du kan anvĂ€nda TON för att lösa dina uppgifter, â vi delar gĂ€rna med oss av vĂ„r erfarenhet.
KĂ€lla: habr.com
