Je hebt waarschijnlijk gehoord dat Telegram Maar je kunt het nieuws hebben gemist dat Telegram voor de implementatie van een of meerdere slimme contracten voor dit platform.
Het team van Serokell, met een rijke ervaring in de ontwikkeling van grote blockchain-projecten, kon niet aan de zijlijn blijven staan. We hebben vijf medewerkers naar de wedstrijd gestuurd, en al na twee weken stonden ze op de eerste plaats onder de (on)bescheiden random bijnaam Sexy Chameleon. In dit artikel zal ik vertellen hoe ze dat hebben gedaan. We hopen dat je in de komende tien minuten minstens een interessant verhaal leest, en mogelijk iets nuttigs vindt dat je in jouw werk kunt toepassen.
Maar laten we beginnen met een kleine contextverkenning.
De wedstrijd en de voorwaarden
Dus, de belangrijkste taken van de deelnemers waren de implementatie van een of meer van de voorgestelde slimme contracten, evenals het doen van voorstellen voor het verbeteren van het TON-ecosysteem. De wedstrijd vond plaats van 24 september tot 15 oktober, en de resultaten werden pas op 15 november bekendgemaakt. Vrij lang, gezien het feit dat Telegram in die tijd ook de resultaten van contests voor ontwerp en de ontwikkeling van applicaties in C++ voor het testen en evalueren van de kwaliteit van VoIP-gesprekken in Telegram had gepresenteerd en bekendgemaakt.
We hebben twee slimme contracten gekozen uit de lijst die door de organisatoren werd aangeboden. Voor een daarvan gebruikten we de tools die samen met TON worden verspreid, terwijl we de tweede implementeerden in een nieuwe taal, ontwikkeld door onze ingenieurs speciaal voor TON en ingebouwd in Haskell.
De keuze voor een functionele programmeertaal is geen toeval. In onze vertellen we vaak waarom we de complexiteit van functionele talen een grote overdrijving vinden en waarom we over het algemeen de voorkeur geven aan object-georiƫnteerde talen. Trouwens, daarin staat ook de .
Waarom we überhaupt besloten hebben om mee te doen
Kort gezegd, omdat onze specialisatie ligt in niet-standaard en complexe projecten die speciale vaardigheden vereisen en vaak wetenschappelijke waarde hebben voor de IT-gemeenschap. We ondersteunen open-source ontwikkeling van harte en zijn bezig met het populariseren ervan, evenals samenwerking met vooraanstaande universiteiten in Rusland op het gebied van computerwetenschappen en wiskunde.
De interessante taken van de wedstrijd en de betrokkenheid bij ons geliefde project Telegram waren op zichzelf al een geweldige motivatie, en het prijzengeld werd een extra stimulans. š
Onderzoek naar de TON-blockchain
We volgen nieuwe ontwikkelingen in blockchain, kunstmatige intelligentie en machine learning nauwlettend en proberen geen enkele belangrijke release in elk van de gebieden waarin we actief zijn te missen. Daarom was ons team bij de start van de wedstrijd al bekend met de ideeƫn van . Maar voordat we met TON aan de slag gingen, hadden we de technische documentatie en de feitelijke broncode van het platform niet geanalyseerd, dus de eerste stap was vrij duidelijk: een grondige studie van de officiƫle documentatie op en in .
Tegen de tijd dat de wedstrijd begon, was de code al gepubliceerd, dus om tijd te besparen, besloten we om te zoeken naar een handleiding of samenvatting geschreven door gebruikers. Helaas leverde dit geen resultaat op - naast de instructies voor het bouwen van het platform op Ubuntu vonden we geen ander materiaal.
De documentatie zelf was zorgvuldig uitgewerkt, maar op sommige momenten was het moeilijk te lezen. We moesten vaak terugkeren naar bepaalde punten en overschakelen van hoog-niveau beschrijvingen van abstracte ideeƫn naar laag-niveau details van de implementatie.
Het zou gemakkelijker zijn geweest als de specificaties helemaal geen gedetailleerde beschrijving van de implementatie hadden omvat. Informatie over hoe de virtuele machine zijn stack vertegenwoordigt, afleidt eerder ontwikkelaars die slimme contracten voor het TON-platform maken, dan dat het hen helpt.
Nix: we bouwen het project
Bij Serokell zijn we grote fans van . We bouwen onze projecten ermee en zetten ze op met behulp van , en op al onze servers is . Hierdoor zijn al onze builds reproduceerbaar en werken ze op elk besturingssysteem waarop je Nix kunt installeren.
Daarom zijn we begonnen met het creƫren van . Hiermee kan je TON zo eenvoudig mogelijk compileren:
$ cd ~/.config/nixpkgs/overlays && git clone https://github.com/serokell/ton.nix
$ cd /path/to/ton/repo && nix-shell
[nix-shell]$ cmakeConfigurePhase && makeLet op, je hoeft geen afhankelijkheden te installeren. Nix zal op magische wijze alles voor je doen, ongeacht of je NixOS, Ubuntu of macOS gebruikt.
Programmeren voor TON
De smart contract code in het TON-netwerk wordt uitgevoerd op de TON Virtual Machine (TVM). De TVM is complexer dan de meeste andere virtuele machines en heeft zeer interessante functionaliteiten, zoals het werken met vervolguitvoeringen (continuations) en gegevenslinks.
Bovendien hebben de jongens van TON drie nieuwe programmeertalen ontwikkeld:
Fift ā een algemene stack-gebaseerde programmeertaal, die lijkt op . Zijn superdomein is de mogelijkheid om met de TVM te interageren.
FunC ā een programmeertaal voor smart contracts, die lijkt op en die compileert naar een andere taal ā Fift Assembler.
Fift Assembler ā de Fift-bibliotheek voor het genereren van binaire uitvoerbare code voor de TVM. Fift Assembler heeft geen compiler. Het is .
Onze wedstrijdbijdragen
Het is eindelijk tijd om naar de resultaten van onze inspanningen te kijken.
Asynchrone betalingskanalen
Een betalingskanaal (payment channel) is een smart contract dat twee gebruikers in staat stelt om betalingen buiten de blockchain te verzenden. Hierdoor worden niet alleen kosten bespaard (geen vergoedingen), maar ook tijd (je hoeft niet te wachten tot een blok is verwerkt). Betalingen kunnen zo klein zijn als nodig en zo vaak plaatsvinden als nodig is. Het is niet nodig dat de partijen elkaar vertrouwen, aangezien de eerlijkheid van de uiteindelijke afrekening door het smart contract wordt gegarandeerd.
We hebben een vrij eenvoudige oplossing voor het probleem gevonden. Twee partijen kunnen ondertekende berichten uitwisselen, elk met twee getallen ā het totale bedrag dat door elke deelnemer is betaald. Deze twee getallen functioneren als in traditionele gedistribueerde systemen en bepalen de volgorde van āgebeurd voorā voor transacties. Met deze gegevens kan het contract elk mogelijk conflict oplossen.
Eigenlijk is het voor de implementatie van dit idee voldoende om ƩƩn getal te hebben, maar we hebben beide behouden omdat we zo een gebruiksvriendelijker interface konden creƫren. Daarnaast hebben we besloten om de grootte van de betaling in elk bericht op te nemen. Zonder dit, als het bericht om de een of andere reden verloren gaat, lijkt alles misschien correct, maar de gebruiker zou de verlies niet opmerken.
Om ons idee te testen, hebben we gezocht naar voorbeelden van het gebruik van zo'n eenvoudig en beknopt betalingskanaalprotocol. Tot onze verbazing ontdekten we er maar twee:
- een vergelijkbare aanpak, alleen voor een eenrichtingskanaal.
- , waarin hetzelfde idee wordt beschreven als bij ons, maar zonder uitleg van veel belangrijke details, zoals algemene correctheid en de procedure voor het oplossen van conflicten.
Het werd duidelijk dat het zinvol was om ons protocol gedetailleerd te beschrijven, met speciale aandacht voor de correctheid ervan. Na verschillende iteraties was de specificatie klaar, en nu kun jij ook .
We hebben een contract op FunC geĆÆmplementeerd, en de commandoregeltool voor interactie met ons contract hebben we volledig in Fift geschreven, zoals aanbevolen door de organisatoren. We hadden elke andere taal voor onze CLI kunnen kiezen, maar we waren benieuwd naar Fift om te zien hoe het presteert in de praktijk.
Eerlijk gezegd hebben we, na met Fift gewerkt te hebben, geen goede redenen gezien om deze taal te verkiezen boven populaire en veelgebruikte talen met ontwikkelde tooling en bibliotheken. Programmeren in een stacktaal is behoorlijk vervelend, omdat je voortdurend moet bijhouden wat waar in de stack ligt, en de compiler helpt daar niet bij.
Daarom is naar onze mening de enige rechtvaardiging voor het bestaan van Fift de rol ervan als hosttaal voor de Fift Assembler. Maar zou het niet beter zijn geweest om de TVM-assembler in een bestaande taal in te bouwen, in plaats van een nieuwe voor dit, in wezen enige, doel te verzinnen?
TVM Haskell eDSL
Nu is het tijd om over ons tweede smart contract te vertellen. We besloten om een multisig-portemonnee te ontwikkelen, maar om nog een smart contract op FunC te schrijven zou te saai zijn. We wilden een beetje pit toevoegen, en dat werd onze eigen assembleertaal voor TVM.
Net als de Fift Assembler is onze nieuwe taal in te bouwen, alleen hebben we Haskell gekozen als host in plaats van Fift, waardoor we zijn geavanceerde typesysteem volledig konden benutten. Bij het werken met smart contracts, waar de kosten van zelfs de kleinste fout erg hoog kunnen zijn, is statische typechecking naar onze mening een groot voordeel.
Om te demonstreren hoe de TVM-assembleur, ingebouwd in Haskell, eruitziet, hebben we een standaardportemonnee op gebouwd. Hier zijn een paar dingen om op te letten:
- Dit contract bestaat uit ƩƩn functie, maar je kunt er zoveel als je wilt gebruiken. Wanneer je een nieuwe functie definieert in de hosttaal (dat wil zeggen in Haskell), stelt onze eDSL je in staat om te kiezen of deze moet worden omgezet in een afzonderlijke subroutine in TVM of eenvoudigweg ingebed in de plaats van aanroepen.
- Net als in Haskell hebben functies types die tijdens de compilatie worden gecontroleerd. In onze eDSL is het invoertype van de functie het type stack dat de functie verwacht, en het resultaatype is het type stack dat ontstaat na de aanroep.
- In de code zijn annotaties
stacktype, die het verwachte stacktype op het aanroep punt beschrijven. In het originele portemonnee contract waren dit gewoon opmerkingen, maar in onze eDSL maken ze daadwerkelijk deel uit van de code en worden ze tijdens de compilatie gecontroleerd. Ze kunnen dienen als documentatie of claims die de ontwikkelaar helpen om een probleem te vinden in het geval dat het stacktype verandert bij codewijzigingen. Natuurlijk heeft dergelijke annotatie geen invloed op de prestaties tijdens runtime, aangezien er geen TVM-code voor hen wordt gegenereerd. - Het is nog steeds een prototype, geschreven in twee weken, dus er is nog veel werk aan het project. Bijvoorbeeld, alle klasse-instanties die je in de onderstaande code ziet, moeten automatisch worden gegenereerd.
Zo ziet de implementatie van een multisig-portemonnee eruit in onze 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 @Word32De volledige broncode van onze eDSL en de contracten van de wallet met multisig kunt u vinden in En een meer over de ingebouwde talen door onze collega Georgy Agapov.
Conclusies over de competitie en TON
In totaal heeft ons werk 380 uur gekost (inclusief het vertrouwd raken met de documentatie, vergaderingen en de daadwerkelijke ontwikkeling). Vijf ontwikkelaars hebben deelgenomen aan het project: CTO, teamleider, blockchainplatformspecialisten en softwareontwikkelaars met kennis van Haskell.
De middelen om deel te nemen aan de wedstrijd hebben we zonder moeite gevonden, aangezien de geest van de hackathon, nauwe samenwerking in teams en de noodzaak om snel in de aspecten van nieuwe technologieƫn te duiken altijd boeiend zijn. Enkele slapeloze nachten om het maximale resultaat te behalen onder beperkte middelen worden gecompenseerd door onschatbare ervaring en uitstekende herinneringen. Bovendien is het werken aan dergelijke taken altijd een goede test van de processen binnen het bedrijf, omdat het echt indrukwekkende resultaten behalen zonder een goed ingeregeld intern samenspel extreem moeilijk is.
Naast de poƫzie: we waren onder de indruk van de hoeveelheid werk dat het TON-team heeft verricht. Ze zijn erin geslaagd om een complex, mooi en vooral functionerend systeem te bouwen. TON heeft zich bewezen als een platform met groot potentieel. Echter, om dit ecosysteem te laten groeien, moet er nog veel gedaan worden, zowel qua gebruik in blockchain-projecten als qua verbetering van ontwikkelingsinstrumenten. We zijn trots dat we nu deel uitmaken van dit proces.
Als je na het lezen van dit artikel nog vragen hebt of ideeĆ«n hebt over hoe je TON kunt toepassen voor jouw taken, āwe delen graag onze ervaringen.
Bron: habr.com
