Segurament ho heu sentit a Telegram . Però potser us heu perdut la notícia de Telegram no fa molt per a la implementació d'un o més contractes intel·ligents per a aquesta plataforma.
L'equip de Serokell, amb una àmplia experiència en el desenvolupament de grans projectes blockchain, no es va poder deixar de banda. Vam delegar cinc empleats al concurs, i dues setmanes més tard van ocupar el primer lloc amb el sobrenom aleatori (in)modest de Camaleó Sexy. En aquest article parlaré de com ho van fer. Esperem que en els propers deu minuts llegiu almenys una història interessant, i com a molt hi trobeu alguna cosa útil que pugueu aplicar en el vostre treball.
Però comencem amb una mica de context.
La competència i les seves condicions
Així doncs, les principals tasques dels participants van ser la implementació d'un o més dels contractes intel·ligents proposats, així com fer propostes per millorar l'ecosistema TON. El concurs va tenir lloc del 24 de setembre al 15 d'octubre, i els resultats es van anunciar només el 15 de novembre. Fa molt de temps, tenint en compte que durant aquest temps Telegram va aconseguir celebrar i donar a conèixer els resultats de concursos de disseny i desenvolupament d'aplicacions en C++ per provar i avaluar la qualitat de les trucades VoIP a Telegram.
Hem seleccionat dos contractes intel·ligents de la llista proposada pels organitzadors. Per a un d'ells, vam utilitzar eines distribuïdes amb TON, i el segon es va implementar en un nou llenguatge desenvolupat pels nostres enginyers específicament per a TON i integrat a Haskell.
L'elecció d'un llenguatge de programació funcional no és casual. En la nostra Sovint parlem de per què pensem que la complexitat dels llenguatges funcionals és una gran exageració i per què en general els preferim als orientats a objectes. Per cert, també conté .
Per què hem decidit participar-hi?
En definitiva, perquè la nostra especialització són projectes no estàndard i complexos que requereixen habilitats especials i sovint tenen un valor científic per a la comunitat informàtica. Donem suport fermament al desenvolupament de codi obert i estem compromesos amb la seva popularització, i també cooperem amb les principals universitats russes en el camp de la informàtica i les matemàtiques.
Les tasques interessants del concurs i la participació en el nostre estimat projecte de Telegram van ser en si mateixes una excel·lent motivació, però el fons del premi es va convertir en un incentiu addicional. 🙂
Recerca de blockchain TON
Seguim de prop els nous desenvolupaments en blockchain, intel·ligència artificial i aprenentatge automàtic i intentem no perdre'ns ni una versió significativa en cadascuna de les àrees en què treballem. Per tant, quan va començar la competició, el nostre equip ja estava familiaritzat amb les idees . Tanmateix, abans de començar a treballar amb TON, no vam analitzar la documentació tècnica i el codi font real de la plataforma, de manera que el primer pas era força obvi: un estudi exhaustiu de la documentació oficial sobre i .
Quan va començar el concurs, el codi ja s'havia publicat, així que per estalviar temps, vam decidir buscar una guia o un resum escrit per pels usuaris. Malauradament, això no va donar cap resultat: a part de les instruccions per muntar la plataforma a Ubuntu, no vam trobar cap altre material.
La documentació en si estava ben investigada, però era difícil de llegir en algunes àrees. Molt sovint havíem de tornar a certs punts i canviar de descripcions d'alt nivell d'idees abstractes a detalls d'implementació de baix nivell.
Seria més fàcil si l'especificació no inclogués una descripció detallada de la implementació. La informació sobre com una màquina virtual representa la seva pila és més probable que distregui els desenvolupadors que creen contractes intel·ligents per a la plataforma TON que no pas que els ajudi.
Nix: muntar el projecte
A Serokell som grans fans . Recollim els nostres projectes amb ell i els despleguem utilitzant , i instal·lat a tots els nostres servidors . Gràcies a això, totes les nostres compilacions són reproduïbles i funcionen en qualsevol sistema operatiu on es pugui instal·lar Nix.
Així que vam començar creant . Amb la seva ajuda, compilar TON és el més senzill possible:
$ cd ~/.config/nixpkgs/overlays && git clone https://github.com/serokell/ton.nix
$ cd /path/to/ton/repo && nix-shell
[nix-shell]$ cmakeConfigurePhase && makeTingueu en compte que no cal que instal·leu cap dependència. Nix ho farà tot per tu màgicament, tant si estàs utilitzant NixOS, Ubuntu o macOS.
Programació per a TON
El codi de contracte intel·ligent de la xarxa TON s'executa a la màquina virtual TON (TVM). TVM és més complex que la majoria de les altres màquines virtuals i té una funcionalitat molt interessant, per exemple, pot funcionar amb continuacions и enllaços a dades.
A més, els nois de TON van crear tres nous llenguatges de programació:
Cinc és un llenguatge de programació de pila universal que s'assembla . La seva súper habilitat és la capacitat d'interactuar amb TVM.
FunC és un llenguatge de programació de contracte intel·ligent que és similar a i es compila en un altre llenguatge: Fift Assembler.
Cinquè muntador — Cinquena biblioteca per generar codi executable binari per a TVM. Fifth Assembler no té un compilador. Això .
El nostre concurs funciona
Finalment, és hora de mirar els resultats dels nostres esforços.
Canal de pagament asíncron
El canal de pagament és un contracte intel·ligent que permet a dos usuaris enviar pagaments fora de la cadena de blocs. Com a resultat, no només estalvieu diners (no hi ha comissió), sinó també temps (no cal esperar que es processi el següent bloc). Els pagaments poden ser tan petits com es desitgi i amb la freqüència que calgui. En aquest cas, les parts no han de confiar mútuament, ja que l'equitat de la liquidació final està garantida pel contracte intel·ligent.
Hem trobat una solució bastant senzilla al problema. Dues parts poden intercanviar missatges signats, cadascun conté dos números: l'import total pagat per cada part. Aquests dos números funcionen com en sistemes distribuïts tradicionals i establir l'ordre "va passar abans" a les transaccions. Mitjançant aquestes dades, el contracte podrà resoldre qualsevol possible conflicte.
De fet, n'hi ha prou amb un número per implementar aquesta idea, però hem deixat tots dos perquè així podríem fer una interfície d'usuari més còmoda. A més, vam decidir incloure l'import del pagament a cada missatge. Sense ell, si el missatge es perd per algun motiu, aleshores, tot i que tots els imports i el càlcul final seran correctes, és possible que l'usuari no noti la pèrdua.
Per provar la nostra idea, vam buscar exemples d'ús d'un protocol de canal de pagament tan senzill i concís. Sorprenentment, només n'hem trobat dos:
- un enfocament similar, només per al cas d'un canal unidireccional.
- , que descriu la mateixa idea que la nostra, però sense explicar molts detalls importants, com ara la correcció general i els procediments de resolució de conflictes.
Va quedar clar que té sentit descriure detalladament el nostre protocol, prestant especial atenció a la seva correcció. Després de diverses iteracions, l'especificació estava a punt, i ara també podeu fer-ho. .
Vam implementar el contracte a FunC i vam escriure la utilitat de línia d'ordres per interactuar amb el nostre contracte completament a Fift, tal com recomanen els organitzadors. Podríem haver triat qualsevol altre idioma per a la nostra CLI, però estàvem interessats a provar Fit per veure com funcionava a la pràctica.
Per ser sincers, després de treballar amb Fift, no vam veure cap motiu convincent per preferir aquest llenguatge als llenguatges populars i utilitzats activament amb eines i biblioteques desenvolupades. Programar en un llenguatge basat en la pila és bastant desagradable, ja que has de tenir constantment al cap el que hi ha a la pila, i el compilador no ajuda amb això.
Per tant, al nostre parer, l'única justificació de l'existència de Fift és el seu paper com a llengua d'acollida de Fift Assembler. Però no seria millor incrustar l'assemblador de TVM en algun llenguatge existent, en lloc d'inventar-ne un de nou per a aquest únic propòsit essencialment?
TVM Haskell eDSL
Ara és el moment de parlar del nostre segon contracte intel·ligent. Vam decidir desenvolupar una cartera multisigna, però escriure un altre contracte intel·ligent a FunC seria massa avorrit. Volíem afegir una mica de sabor, i aquest era el nostre propi llenguatge assemblador per a TVM.
Igual que Fift Assembler, el nostre nou llenguatge està integrat, però hem escollit Haskell com a amfitrió en lloc de Fift, cosa que ens permet aprofitar al màxim el seu sistema de tipus avançat. Quan es treballa amb contractes intel·ligents, on el cost fins i tot d'un petit error pot ser molt elevat, l'escriptura estàtica, al nostre parer, és un gran avantatge.
Per demostrar com sembla l'assemblador de TVM incrustat a Haskell, hi hem implementat una cartera estàndard. Aquí hi ha algunes coses a les quals cal prestar atenció:
- Aquest contracte consta d'una funció, però podeu utilitzar-ne tantes com vulgueu. Quan definiu una funció nova en l'idioma amfitrió (és a dir, Haskell), el nostre eDSL us permet triar si voleu que es converteixi en una rutina separada a TVM o simplement en línia al punt de trucada.
- Igual que Haskell, les funcions tenen tipus que es comproven en temps de compilació. Al nostre eDSL, el tipus d'entrada d'una funció és el tipus de pila que la funció espera, i el tipus de resultat és el tipus de pila que es produirà després de la trucada.
- El codi té anotacions
stacktype, descrivint el tipus de pila esperat al punt de trucada. Al contracte de cartera original, només eren comentaris, però al nostre eDSL formen part del codi i es comproven en temps de compilació. Poden servir com a documentació o declaracions que ajudin el desenvolupador a trobar el problema si el codi canvia i el tipus de pila canvia. Per descomptat, aquestes anotacions no afecten el rendiment del temps d'execució, ja que no es genera cap codi TVM per a elles. - Aquest encara és un prototip escrit en dues setmanes, així que encara queda molta feina per fer en el projecte. Per exemple, totes les instàncies de les classes que veieu al codi següent s'han de generar automàticament.
Així és com es veu la implementació d'una cartera multisig al nostre 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 @Word32El codi font complet del nostre contracte de cartera eDSL i multisignatura es pot trobar a I més sobre els idiomes integrats, el nostre company Georgy Agapov.
Conclusions sobre la competició i TON
En total, el nostre treball va durar 380 hores (incloent familiarització amb la documentació, reunions i desenvolupament real). Cinc desenvolupadors van participar en el projecte del concurs: CTO, cap d'equip, especialistes en plataforma blockchain i desenvolupadors de programari Haskell.
Hem trobat recursos per participar en el concurs sense dificultats, ja que l'esperit d'hackathon, el treball en equip proper i la necessitat de submergir-nos ràpidament en aspectes de les noves tecnologies és sempre apassionant. Diverses nits sense dormir per aconseguir els màxims resultats en condicions de recursos limitats es compensen amb una experiència inestimable i excel·lents records. A més, treballar en aquestes tasques és sempre una bona prova dels processos de l'empresa, ja que és extremadament difícil aconseguir resultats realment decents sense una interacció interna que funcioni correctament.
Lletres a banda: ens va impressionar la quantitat de treball realitzat per l'equip de TON. Van aconseguir construir un sistema complex, bonic i, sobretot, de treball. TON ha demostrat ser una plataforma amb un gran potencial. Tanmateix, perquè aquest ecosistema es desenvolupi, cal fer molt més, tant pel que fa al seu ús en projectes blockchain com pel que fa a la millora de les eines de desenvolupament. Estem orgullosos de formar part d'aquest procés.
Si després de llegir aquest article encara teniu cap pregunta o teniu idees sobre com utilitzar TON per resoldre els vostres problemes, — Estarem encantats de compartir la nostra experiència.
Font: www.habr.com
