Du har sÀkert hört det dÀr Telegram . Men du kanske har missat nyheterna som inte sÄ lÀnge sedan Telegram för implementering av ett eller flera smarta kontrakt för denna plattform.
Serokell-teamet, med lÄng erfarenhet av att utveckla stora blockchain-projekt, kunde inte stÄ Ät sidan. Vi delegerade fem anstÀllda till tÀvlingen och tvÄ veckor senare tog de första platsen i den under det (o)modiga slumpmÀssiga smeknamnet Sexy Chameleon. I den hÀr artikeln kommer jag att prata om hur de gjorde det. Vi hoppas att du under de nÀrmaste tio minuterna Ätminstone kommer att lÀsa en intressant berÀttelse, och som mest kommer du att hitta nÄgot anvÀndbart i den som du kan tillÀmpa i ditt arbete.
Men lÄt oss börja med ett litet sammanhang.
Konkurrens och dess förutsÀttningar
SÄ deltagarnas huvuduppgifter var implementeringen av ett eller flera av de föreslagna smarta kontrakten, samt att lÀgga fram förslag för att förbÀttra TON-ekosystemet. TÀvlingen pÄgick frÄn 24 september till 15 oktober, och resultaten tillkÀnnagavs först den 15 november. Ganska lÄng tid, med tanke pÄ att Telegram under denna tid lyckades hÄlla och tillkÀnnage resultaten av tÀvlingar om design och utveckling av applikationer i C++ för att testa och bedöma kvaliteten pÄ VoIP-samtal i Telegram.
Vi valde ut tvÄ smarta kontrakt frÄn listan som föreslagits av arrangörerna. För en av dem anvÀnde vi verktyg som distribuerades med TON, och det andra implementerades i ett nytt sprÄk utvecklat av vÄra ingenjörer specifikt för TON och inbyggt i Haskell.
Valet av ett funktionellt programmeringssprÄk Àr inte av misstag. I vÄr Vi pratar ofta om varför vi tycker att komplexiteten hos funktionella sprÄk Àr en enorm överdrift och varför vi i allmÀnhet föredrar dem framför objektorienterade. Den innehÄller förresten ocksÄ .
Varför valde vi ens att delta?
Kort sagt för att vÄr specialisering Àr icke-standardiserade och komplexa projekt som krÀver speciell kompetens och ofta Àr av vetenskapligt vÀrde för IT-gemenskapen. Vi stöder starkt utveckling av öppen kÀllkod och Àr engagerade i dess popularisering och samarbetar Àven med ledande ryska universitet inom datavetenskap och matematik.
TĂ€vlingens intressanta uppgifter och engagemang i vĂ„rt Ă€lskade Telegram-projekt var i sig en utmĂ€rkt motivation, men prisfonden blev ytterligare ett incitament. đ
TON blockchain forskning
Vi övervakar noggrant ny utveckling inom blockchain, artificiell intelligens och maskininlÀrning och försöker att inte missa en enda betydande release inom vart och ett av de omrÄden dÀr vi arbetar. DÀrför, nÀr tÀvlingen startade, var vÄrt team redan bekant med idéer frÄn . Men innan vi började arbeta med TON analyserade vi inte den tekniska dokumentationen och sjÀlva kÀllkoden för plattformen, sÄ det första steget var ganska uppenbart - en grundlig studie av den officiella dokumentationen pÄ och .
NÀr tÀvlingen startade hade koden redan publicerats, sÄ för att spara tid bestÀmde vi oss för att leta efter en guide eller sammanfattning skriven av anvÀndare. TyvÀrr gav detta inga resultat - förutom instruktioner för montering av plattformen pÄ Ubuntu hittade vi inget annat material.
SjÀlva dokumentationen var vÀl genomarbetad, men svÄrlÀst pÄ vissa omrÄden. Ganska ofta var vi tvungna att ÄtervÀnda till vissa punkter och byta frÄn högnivÄbeskrivningar av abstrakta idéer till lÄgnivÄimplementeringsdetaljer.
Det skulle vara lÀttare om specifikationen inte alls innehöll en detaljerad beskrivning av implementeringen. Information om hur en virtuell maskin representerar sin stack Àr mer sannolikt att distrahera utvecklare som skapar smarta kontrakt för TON-plattformen Àn att hjÀlpa dem.
Nix: sÀtta ihop projektet
PÄ Serokell Àr vi stora fans . Vi samlar vÄra projekt med den och distribuerar dem med hjÀlp av , och installerat pÄ alla vÄra servrar . Tack vare detta Àr alla vÄra builds reproducerbara och fungerar pÄ alla operativsystem som Nix kan installeras pÄ.
SÄ vi började med att skapa . Med dess hjÀlp Àr det sÄ enkelt som möjligt 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 kommer magiskt att göra allt för dig, oavsett om du anvÀnder NixOS, Ubuntu eller macOS.
Programmering för TON
Den smarta kontraktskoden i TON-nÀtverket körs pÄ TON Virtual Machine (TVM). TVM Àr mer komplex Àn de flesta andra virtuella maskiner, och har mycket intressant funktionalitet, den kan till exempel fungera med fortsÀttningar О lÀnkar till data.
Dessutom skapade killarna frÄn TON tre nya programmeringssprÄk:
Fift Àr ett universellt stackprogrammeringssprÄk som liknar . Hans superförmÄga Àr förmÄgan att interagera med TVM.
FunC Àr ett smart kontraktsprogrammeringssprÄk som liknar och Àr sammanstÀllt till ett annat sprÄk - Fift Assembler.
Femte Assembler â Fift-bibliotek för att generera binĂ€r körbar kod för TVM. Fifth Assembler har ingen kompilator. Detta .
VÄr tÀvling fungerar
Ăntligen Ă€r det dags att titta pĂ„ resultaten av vĂ„ra anstrĂ€ngningar.
Asynkron betalningskanal
Betalningskanal Àr ett smart kontrakt som lÄter tvÄ anvÀndare skicka betalningar utanför blockkedjan. Som ett resultat sparar du inte bara pengar (det finns ingen provision), utan ocksÄ tid (du behöver inte vÀnta pÄ att nÀsta block ska behandlas). Betalningar kan vara sÄ smÄ som önskas och sÄ ofta som krÀvs. I det hÀr fallet behöver parterna inte lita pÄ varandra, eftersom rÀttvisan i den slutliga uppgörelsen garanteras av det smarta kontraktet.
Vi hittade en ganska enkel lösning pĂ„ problemet. TvĂ„ parter kan utbyta undertecknade meddelanden som var och en innehĂ„ller tvĂ„ nummer â hela beloppet som betalas av varje part. Dessa tvĂ„ siffror fungerar som i traditionella distribuerade system och stĂ€ll in "hĂ€nde före"-ordningen pĂ„ transaktioner. Genom att anvĂ€nda dessa data kommer kontraktet att kunna lösa eventuella konflikter.
Faktum Àr att ett nummer rÀcker för att implementera denna idé, men vi lÀmnade bÄda eftersom vi pÄ sÄ sÀtt kunde skapa ett mer bekvÀmt anvÀndargrÀnssnitt. Dessutom bestÀmde vi oss för att ta med betalningsbeloppet i varje meddelande. Utan det, om meddelandet försvinner av nÄgon anledning, sÄ, Àven om alla belopp och den slutliga berÀkningen kommer att vara korrekta, kanske anvÀndaren inte mÀrker förlusten.
För att testa vĂ„r idĂ© letade vi efter exempel pĂ„ att anvĂ€nda ett sĂ„ enkelt och kortfattat betalningskanalprotokoll. Ăverraskande nog hittade vi bara tvĂ„:
- ett liknande tillvÀgagÄngssÀtt, endast för fallet med en enkelriktad kanal.
- , som beskriver samma idé som vÄr, men utan att förklara mÄnga viktiga detaljer, sÄsom allmÀn korrekthet och konfliktlösningsprocedurer.
Det blev tydligt att det Àr vettigt att beskriva vÄrt protokoll i detalj, med sÀrskild uppmÀrksamhet pÄ dess riktighet. Efter flera iterationer var specifikationen klar, och nu kan du ocksÄ. .
Vi implementerade kontraktet i FunC, och vi skrev kommandoradsverktyget för att interagera med vÄrt kontrakt helt och hÄllet i Fift, som rekommenderas av arrangörerna. Vi kunde ha valt vilket annat sprÄk som helst för vÄr CLI, men vi var intresserade av att prova Fit för att se hur det fungerade i praktiken.
För att vara Àrlig, efter att ha arbetat med Fift sÄg vi inga ö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 i huvudet vad som finns pÄ stacken, och kompilatorn hjÀlper inte till med detta.
DÀrför, enligt vÄr Äsikt, Àr den enda motiveringen för existensen av Fift dess roll som vÀrdsprÄk för Fift Assembler. Men skulle det inte vara bÀttre att bÀdda in TVM assembler i nÄgot befintligt sprÄk, snarare Àn att uppfinna ett nytt för detta i huvudsak enda syfte?
TVM Haskell eDSL
Nu Àr det dags att prata om vÄrt andra smarta kontrakt. Vi bestÀmde oss för att utveckla en plÄnbok med flera signaturer, men att skriva ett annat smart kontrakt i FunC skulle vara för trÄkigt. Vi ville tillföra lite smak, och det var vÄrt eget assemblersprÄk för TVM.
Precis som Fift Assembler Àr vÄrt nya sprÄk inbÀddat, men vi valde Haskell som vÀrd istÀllet för Fift, vilket gör att vi kan dra full nytta av dess avancerade typsystem. NÀr man arbetar med smarta kontrakt, dÀr kostnaden för Àven ett litet fel kan vara mycket hög, Àr statisk skrivning enligt vÄr uppfattning en stor fördel.
För att demonstrera hur TVM assembler ser ut inbÀddad i Haskell, implementerade vi en standardplÄnbok pÄ den. HÀr Àr nÄgra saker att vara uppmÀrksam pÄ:
- Detta kontrakt bestÄr av en funktion, men du kan anvÀnda sÄ mÄnga du vill. NÀr du definierar en ny funktion pÄ vÀrdsprÄket (d.v.s. Haskell) lÄter vÄr eDSL dig vÀlja om du vill att den ska bli en separat rutin i TVM eller helt enkelt infogas vid anropspunkten.
- Liksom Haskell har funktioner typer som kontrolleras vid kompilering. I vÄr eDSL Àr ingÄngstypen för en funktion den typ av stack som funktionen förvÀntar sig, och resultattypen Àr den typ av stack som kommer att produceras efter anropet.
- Koden har anteckningar
stacktype, som beskriver den förvÀntade stacktypen vid anropspunkten. I det ursprungliga plÄnbokskontraktet 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 uttalanden som hjÀlper utvecklaren att hitta problemet om koden Àndras och stacktypen Àndras. Naturligtvis pÄverkar sÄdana anteckningar inte körningsprestandan, eftersom ingen TVM-kod genereras för dem. - Det hÀr Àr fortfarande en prototyp skriven pÄ tvÄ veckor, sÄ det ÄterstÄr mycket arbete med projektet. Till exempel bör alla instanser av klasserna du ser i koden nedan genereras automatiskt.
SÄ hÀr ser implementeringen av en multisig-plÄnbok ut pÄ 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Ärt eDSL- och multisignaturplÄnbokskontrakt finns pÄ Och mer om inbyggda sprÄk, vÄr kollega Georgy Agapov.
Slutsatser om tÀvlingen och TON
Totalt tog vÄrt arbete 380 timmar (inklusive bekantskap med dokumentation, möten och faktisk utveckling). Fem utvecklare deltog i tÀvlingsprojektet: CTO, teamleader, blockchain-plattformsspecialister och Haskell mjukvaruutvecklare.
Vi hittade resurser för att delta i tÀvlingen utan svÄrighet, eftersom andan av ett hackathon, nÀra lagarbete och behovet av att snabbt fördjupa oss i aspekter av ny teknik alltid Àr spÀnnande. Flera sömnlösa nÀtter för att uppnÄ maximala resultat under förhÄllanden med begrÀnsade resurser kompenseras av ovÀrderlig erfarenhet och utmÀrkta minnen. Att arbeta med sÄdana uppgifter Àr dessutom alltid ett bra test av företagets processer, eftersom det Àr extremt svÄrt att uppnÄ riktigt anstÀndiga resultat utan vÀlfungerande intern interaktion.
Texten Äsido: vi var imponerade av mÀngden arbete som lagts ner av TON-teamet. De lyckades bygga ett komplext, vackert och viktigast av allt fungerande system. TON har visat sig vara en plattform med stor potential. Men för att detta ekosystem ska utvecklas mÄste mycket mer göras, bÄde nÀr det gÀller dess anvÀndning i blockchain-projekt och nÀr det gÀller att förbÀttra utvecklingsverktyg. Vi Àr stolta över att nu vara en del av denna process.
Om du efter att ha lĂ€st den hĂ€r artikeln fortfarande har nĂ„gra frĂ„gor eller har idĂ©er om hur du anvĂ€nder TON för att lösa dina problem, â Vi delar gĂ€rna med oss ââav vĂ„ra erfarenheter.
KĂ€lla: will.com
