Je hebt dat Telegram waarschijnlijk gehoord . Maar misschien heb je het nieuws van Telegram nog niet zo lang geleden gemist voor de implementatie van één of meerdere smart contracts voor dit platform.
Het Serocell-team, met uitgebreide ervaring in het ontwikkelen van grote blockchain-projecten, kon niet aan de kant blijven staan. We hebben vijf medewerkers afgevaardigd naar de wedstrijd, en twee weken later behaalden zij de eerste plaats onder de (in)bescheiden willekeurige bijnaam Sexy Chameleon. In dit artikel zal ik vertellen hoe ze dat deden. We hopen dat je de komende tien minuten op zijn minst een interessant verhaal leest, en er hoogstens iets nuttigs in vindt dat je in je werk kunt toepassen.
Maar laten we beginnen met een beetje context.
Concurrentie en haar voorwaarden
De belangrijkste taken van de deelnemers waren dus de implementatie van een of meer van de voorgestelde slimme contracten, en het doen van voorstellen om het TON-ecosysteem te verbeteren. De wedstrijd liep van 24 september tot 15 oktober en de resultaten werden pas op 15 november bekendgemaakt. Een behoorlijk lange tijd, gezien het feit dat Telegram gedurende deze tijd erin slaagde de resultaten te houden en bekend te maken van wedstrijden over het ontwerp en de ontwikkeling van applicaties in C++ voor het testen en beoordelen van de kwaliteit van VoIP-gesprekken in Telegram.
We hebben twee slimme contracten geselecteerd uit de door de organisatoren voorgestelde lijst. Voor één ervan hebben we tools gebruikt die met TON werden gedistribueerd, en de tweede werd geïmplementeerd in een nieuwe taal die speciaal door onze ingenieurs voor TON was ontwikkeld en in Haskell was ingebouwd.
De keuze voor een functionele programmeertaal is niet toevallig. In onze We praten vaak over waarom we denken dat de complexiteit van functionele talen enorm overdreven is en waarom we ze over het algemeen verkiezen boven objectgeoriënteerde talen. Het bevat trouwens ook .
Waarom hebben we überhaupt besloten om mee te doen?
Kortom omdat onze specialisatie niet-standaard en complexe projecten zijn die speciale vaardigheden vereisen en vaak van wetenschappelijke waarde zijn voor de IT-gemeenschap. We ondersteunen de ontwikkeling van open source krachtig en zijn betrokken bij de popularisering ervan, en werken ook samen met toonaangevende Russische universiteiten op het gebied van informatica en wiskunde.
De interessante taken van de wedstrijd en de betrokkenheid bij ons geliefde Telegram-project waren op zichzelf een uitstekende motivatie, maar het prijzengeld werd een extra stimulans. 🙂
TON blockchain-onderzoek
We volgen nieuwe ontwikkelingen op het gebied van blockchain, kunstmatige intelligentie en machine learning op de voet en proberen geen enkele belangrijke release te missen op elk van de gebieden waarop we werken. Daarom was ons team tegen de tijd dat de competitie begon al bekend met de ideeën van . Voordat we met TON aan de slag gingen, hebben we echter de technische documentatie en de daadwerkelijke broncode van het platform niet geanalyseerd, dus de eerste stap lag voor de hand: een grondige studie van de officiële documentatie over en .
Tegen de tijd dat de wedstrijd begon, was de code al gepubliceerd, dus om tijd te besparen besloten we op zoek te gaan naar een gids of samenvatting geschreven door gebruikers. Helaas leverde dit geen resultaat op - afgezien van instructies voor het monteren van het platform op Ubuntu, hebben we geen ander materiaal gevonden.
De documentatie zelf was goed onderzocht, maar was op sommige gebieden moeilijk te lezen. Heel vaak moesten we terugkeren naar bepaalde punten en overschakelen van beschrijvingen op hoog niveau van abstracte ideeën naar implementatiedetails op laag niveau.
Het zou gemakkelijker zijn als de specificatie helemaal geen gedetailleerde beschrijving van de implementatie zou bevatten. Informatie over hoe een virtuele machine zijn stack vertegenwoordigt, zal ontwikkelaars die slimme contracten voor het TON-platform maken eerder afleiden dan hen helpen.
Nix: het project samenstellen
Bij Serokell zijn we grote fans . We verzamelen er onze projecten mee en zetten ze in met behulp van , en geïnstalleerd op al onze servers . Hierdoor zijn al onze builds reproduceerbaar en werken ze op elk besturingssysteem waarop Nix kan worden geïnstalleerd.
Dus zijn we begonnen met creëren . Met zijn hulp is het samenstellen van TON zo eenvoudig mogelijk:
$ cd ~/.config/nixpkgs/overlays && git clone https://github.com/serokell/ton.nix
$ cd /path/to/ton/repo && nix-shell
[nix-shell]$ cmakeConfigurePhase && makeHoud er rekening mee dat u geen afhankelijkheden hoeft te installeren. Nix zal op magische wijze alles voor je doen, of je nu NixOS, Ubuntu of macOS gebruikt.
Programmering voor TON
De slimme contractcode in het TON-netwerk draait op de TON Virtual Machine (TVM). TVM is complexer dan de meeste andere virtuele machines en heeft bijvoorbeeld zeer interessante functionaliteiten waarmee het kan werken voortzettingen и koppelingen naar gegevens.
Bovendien hebben de jongens van TON drie nieuwe programmeertalen gemaakt:
Vijf is een universele stapelprogrammeertaal die lijkt op . Zijn supervermogen is het vermogen om te communiceren met TVM.
FunC is een slimme contract-programmeertaal die vergelijkbaar is met en is gecompileerd in een andere taal: Fift Assembler.
Vijfde Assemblee — Vijft-bibliotheek voor het genereren van binaire uitvoerbare code voor TVM. Fifth Assembler heeft geen compiler. Dit .
Onze concurrentie werkt
Eindelijk is het tijd om te kijken naar de resultaten van onze inspanningen.
Asynchrone betalingskanaal
Betaalkanaal is een slim contract waarmee twee gebruikers betalingen buiten de blockchain kunnen verzenden. Hierdoor bespaar je niet alleen geld (er is geen commissie), maar ook tijd (je hoeft niet te wachten tot het volgende blok is verwerkt). Betalingen kunnen zo klein zijn als gewenst en zo vaak als nodig. In dit geval hoeven de partijen elkaar niet te vertrouwen, aangezien de eerlijkheid van de eindafrekening wordt gegarandeerd door het slimme contract.
We hebben een vrij eenvoudige oplossing voor het probleem gevonden. Twee partijen kunnen ondertekende berichten uitwisselen, die elk twee nummers bevatten: het volledige bedrag dat elke partij heeft betaald. Deze twee cijfers werken als in traditionele gedistribueerde systemen en stel de volgorde van 'er is eerder gebeurd' in op transacties. Met behulp van deze gegevens kan het contract elk mogelijk conflict oplossen.
In feite is één getal voldoende om dit idee te implementeren, maar we hebben beide laten staan omdat we op deze manier een handiger gebruikersinterface konden maken. Daarnaast hebben we besloten om in elk bericht het betalingsbedrag te vermelden. Als het bericht om de een of andere reden verloren gaat, zal de gebruiker zonder dit bericht het verlies mogelijk niet opmerken, ook al zijn alle bedragen en de uiteindelijke berekening correct.
Om ons idee te testen, zochten we naar voorbeelden van het gebruik van zo’n eenvoudig en beknopt betalingskanaalprotocol. Verrassend genoeg vonden we er slechts twee:
- een vergelijkbare aanpak, alleen in het geval van een unidirectioneel kanaal.
- , dat hetzelfde idee beschrijft als het onze, maar zonder veel belangrijke details uit te leggen, zoals algemene correctheid en procedures voor het oplossen van conflicten.
Het werd duidelijk dat het zinvol is om ons protocol in detail te beschrijven, met speciale aandacht voor de juistheid ervan. Na een aantal iteraties was de specificatie gereed, en nu kunt u dat ook doen. .
We hebben het contract in FunC geïmplementeerd en we hebben het opdrachtregelhulpprogramma voor de interactie met ons contract volledig in Fift geschreven, zoals aanbevolen door de organisatoren. We hadden elke andere taal voor onze CLI kunnen kiezen, maar we waren geïnteresseerd om Fit uit te proberen om te zien hoe het in de praktijk presteerde.
Om eerlijk te zijn, zagen we na het werken met Fift geen dwingende redenen om deze taal te verkiezen boven populaire en actief gebruikte talen met ontwikkelde tools en bibliotheken. Programmeren in een stack-gebaseerde taal is behoorlijk onaangenaam, omdat je constant in je hoofd moet houden wat er op de stack staat, en de compiler helpt hierbij niet.
Daarom is naar onze mening de enige rechtvaardiging voor het bestaan van Fift zijn rol als gasttaal voor Fift Assembler. Maar zou het niet beter zijn om de TVM-assembler in een bestaande taal in te bedden, in plaats van een nieuwe uit te vinden voor dit in essentie enige doel?
TVM Haskell eDSL
Nu is het tijd om over ons tweede slimme contract te praten. We besloten een portemonnee met meerdere handtekeningen te ontwikkelen, maar het schrijven van nog een slim contract in FunC zou te saai zijn. We wilden wat smaak toevoegen, en dat was onze eigen assembleertaal voor TVM.
Net als Fift Assembler is onze nieuwe taal ingebed, maar we hebben Haskell als host gekozen in plaats van Fift, waardoor we volledig kunnen profiteren van het geavanceerde typesysteem. Bij het werken met slimme contracten, waarbij de kosten van zelfs een kleine fout erg hoog kunnen zijn, is statisch typen naar onze mening een groot voordeel.
Om te demonstreren hoe TVM assembler er in Haskell uitziet, hebben we er een standaard portemonnee op geïmplementeerd. Hier zijn een paar dingen waar u op moet letten:
- Dit contract bestaat uit één functie, maar je kunt er zoveel gebruiken als je wilt. Wanneer u een nieuwe functie in de hosttaal (d.w.z. Haskell) definieert, kunt u met onze eDSL kiezen of u wilt dat dit een aparte routine in TVM wordt of gewoon inline op het oproeppunt.
- Net als Haskell hebben functies typen die tijdens het compileren worden gecontroleerd. In onze eDSL is het invoertype van een functie het type stapel dat de functie verwacht, en het resultaattype is het type stapel dat na de oproep wordt geproduceerd.
- De code bevat annotaties
stacktype, waarin het verwachte stapeltype bij het handbrandmelder wordt beschreven. In het oorspronkelijke portemonneecontract waren dit slechts opmerkingen, maar in onze eDSL maken ze feitelijk deel uit van de code en worden ze tijdens het compileren gecontroleerd. Ze kunnen dienen als documentatie of verklaringen die de ontwikkelaar helpen het probleem te vinden als de code verandert en het stapeltype verandert. Dergelijke annotaties hebben uiteraard geen invloed op de runtimeprestaties, aangezien er geen TVM-code voor wordt gegenereerd. - Dit is nog steeds een prototype dat in twee weken is geschreven, dus er moet nog veel aan het project worden gewerkt. Alle exemplaren van de klassen die u in de onderstaande code ziet, moeten bijvoorbeeld automatisch worden gegenereerd.
Zo ziet de implementatie van een multisig wallet eruit op 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 ons eDSL- en multi-signature portemonnee-contract kunt u vinden op En meer over ingebouwde talen, onze collega Georgy Agapov.
Conclusies over de concurrentie en TON
In totaal duurde ons werk 380 uur (inclusief kennismaking met documentatie, bijeenkomsten en daadwerkelijke ontwikkeling). Aan het competitieproject namen vijf ontwikkelaars deel: CTO, teamleider, blockchainplatformspecialisten en Haskell-softwareontwikkelaars.
We hebben middelen gevonden om zonder problemen aan de wedstrijd deel te nemen, omdat de geest van een hackathon, hecht teamwerk en de noodzaak om ons snel te verdiepen in aspecten van nieuwe technologieën altijd spannend zijn. Verschillende slapeloze nachten om maximale resultaten te bereiken in omstandigheden met beperkte middelen worden gecompenseerd door onschatbare ervaring en uitstekende herinneringen. Bovendien is het werken aan dergelijke taken altijd een goede test voor de bedrijfsprocessen, omdat het uiterst moeilijk is om echt fatsoenlijke resultaten te behalen zonder goed functionerende interne interactie.
Afgezien van de teksten: we waren onder de indruk van de hoeveelheid werk die het TON-team erin heeft gestoken. Ze zijn erin geslaagd een complex, mooi en vooral werkend systeem te bouwen. TON heeft bewezen een platform te zijn met veel potentie. Om dit ecosysteem zich te laten ontwikkelen, moet er echter nog veel meer worden gedaan, zowel wat betreft het gebruik ervan in blockchain-projecten als wat betreft het verbeteren van ontwikkelingsinstrumenten. We zijn er trots op dat we nu deel uitmaken van dit proces.
Als u na het lezen van dit artikel nog vragen heeft of ideeën heeft over hoe u TON kunt gebruiken om uw problemen op te lossen, – wij delen graag onze ervaringen.
Bron: www.habr.com
