Cliente de prueba TON (Telegram Open Network) y nuevo lenguaje Fift para contratos inteligentes

Hace más de un año se supo de los planes del mensajero Telegram de lanzar su propia red descentralizada. Telegram Open Network. Luego estuvo disponible un voluminoso documento técnico, que supuestamente fue escrito por Nikolai Durov y describía la estructura de la futura red. Para aquellos que se lo perdieron, les recomiendo que lean mi recuento de este documento (Parte 1, Parte 2; la tercera parte, lamentablemente, todavía está acumulando polvo en borradores).

Desde entonces, no ha habido noticias significativas sobre el estado del desarrollo de TON hasta hace un par de días (en uno de canales no oficiales) el enlace a la página no apareció https://test.ton.org/download.html, donde se encuentran:
ton-test-liteclient-full.tar.xz — fuentes de un cliente ligero para la red de prueba TON;
ton-lite-cliente-test1.config.json — archivo de configuración para conectarse a la red de prueba;
README — información sobre la construcción y el lanzamiento del cliente;
HOWTO — instrucciones paso a paso sobre cómo crear un contrato inteligente utilizando un cliente;
tonelada.pdf — documento actualizado (con fecha del 2 de marzo de 2019) con una descripción técnica de la red TON;
tvm.pdf — descripción técnica de TVM (TON Virtual Machine, máquina virtual TON);
tblkch.pdf — descripción técnica de la cadena de bloques TON;
quintabase.pdf — descripción del nuevo lenguaje Fift, diseñado para crear contratos inteligentes en TON.

Repito, no hubo confirmación oficial de la página y de todos estos documentos de Telegram, pero el volumen de estos materiales los hace bastante plausibles. Inicie el cliente publicado bajo su propio riesgo.

Construyendo un cliente de prueba

Primero, intentemos crear y ejecutar un cliente de prueba; afortunadamente, README describe este sencillo proceso en detalle. Haré esto usando macOS 10.14.5 como ejemplo; no puedo garantizar el éxito de la compilación en otros sistemas.

  1. Descargar y descomprimir archivo fuente. Es importante descargar la última versión ya que la compatibilidad con versiones anteriores no está garantizada en este momento.

  2. Asegúrese de que las últimas versiones de make, cmake (versión 3.0.2 o superior), OpenSSL (incluidos los archivos de encabezado C), g++ o clang estén instaladas en el sistema. No tuve que instalar nada, todo se montó de inmediato.

  3. Supongamos que las fuentes están descomprimidas en una carpeta. ~/lite-client. Por separado, cree una carpeta vacía para el proyecto ensamblado (por ejemplo, ~/liteclient-build), y de ella (cd ~/liteclient-build) llamar a los comandos:

    cmake ~/lite-client
    cmake --build . --target test-lite-client

    Cliente de prueba TON (Telegram Open Network) y nuevo lenguaje Fift para contratos inteligentes

    Para construir el intérprete de cinco idiomas para contratos inteligentes (más sobre esto a continuación), también llamamos

    cmake --build . --target fift

  4. Descargar el actual archivo de configuración para conectarse a la red de prueba y colocarlo en la carpeta con el cliente ensamblado.

  5. Hecho, puedes iniciar el cliente:

    ./test-lite-client -C ton-lite-client-test1.config.json

Si todo se hace correctamente, deberías ver algo como esto:

Cliente de prueba TON (Telegram Open Network) y nuevo lenguaje Fift para contratos inteligentes

Como podemos ver, hay pocos comandos disponibles:
help — mostrar esta lista de comandos;
quit - salir;
time — mostrar la hora actual en el servidor;
status — mostrar la conexión y el estado de la base de datos local;
last — actualizar el estado de la cadena de bloques (descargar el último bloque). Es importante ejecutar este comando antes de cualquier solicitud para asegurarse de ver el estado actual de la red.
sendfile <filename> — cargar un archivo local a la red TON. Así es como se produce la interacción con la red, incluida, por ejemplo, la creación de nuevos contratos inteligentes y solicitudes de transferencia de fondos entre cuentas;
getaccount <address> — muestra el actual (en el momento en que se ejecutó el comando) last) el estado de la cuenta con la dirección especificada;
privkey <filename> — carga la clave privada desde un archivo local.

Si al iniciar el cliente le transfiere una carpeta usando la opción -D, luego agregará el último bloque de la cadena maestra:

./test-lite-client -C ton-lite-client-test1.config.json -D ~/ton-db-dir

Ahora podemos pasar a cosas más interesantes: aprender el lenguaje Fift, intentar compilar un contrato inteligente (por ejemplo, crear una billetera de prueba), cargarlo en la red e intentar transferir fondos entre cuentas.

Idioma quinto

Del documento quintabase.pdf Puedes descubrir que el equipo de Telegram ha creado un nuevo lenguaje de pila para crear contratos inteligentes. Cincuenta (aparentemente del numeral quinto, similar a Forth, un lenguaje con el que Fifth tiene mucho en común).

El documento es bastante voluminoso, 87 páginas, y no volveré a contar su contenido en detalle en el marco de este artículo (al menos porque no he terminado de leerlo yo mismo :). Me centraré en los puntos principales y daré un par de ejemplos de código en este lenguaje.

En un nivel básico, la sintaxis de Fift es bastante simple: su código consta de palabras, generalmente separados por espacios o saltos de línea (caso especial: algunas palabras no requieren un separador después de sí mismas). Cualquier palabra es una secuencia de caracteres que distingue entre mayúsculas y minúsculas y que corresponde a un determinado definición (aproximadamente, lo que debe hacer el intérprete cuando encuentra esta palabra). Si no hay una definición de una palabra, el intérprete intenta analizarla como un número y ponerla en la pila. Por cierto, los números aquí son, de repente, enteros de 257 bits y no hay fracciones en absoluto; más precisamente, inmediatamente se convierten en un par de números enteros, formando el numerador y el denominador de una fracción racional.

Las palabras tienden a interactuar con los valores en la parte superior de la pila. Un tipo separado de palabras - prefijo — no utiliza la pila, sino los caracteres subsiguientes del archivo fuente. Por ejemplo, así es como se implementan los literales de cadena: el carácter de comillas (") es una palabra de prefijo que busca la siguiente comilla (de cierre) y empuja la cadena entre ellas hacia la pila. Las frases ingeniosas se comportan de la misma manera (//) y multilínea (/*) comentarios.

Aquí termina casi toda la estructura interna del lenguaje. Todo lo demás (incluidas las construcciones de control) se define como palabras (ya sea internas, como operaciones aritméticas y la definición de nuevas palabras; o definidas en la "biblioteca estándar" Fift.fif, que está en la carpeta crypto/fift en las fuentes).

Un programa de ejemplo simple en Fift:

{ dup =: x dup * =: y } : setxy
3 setxy x . y . x y + .
7 setxy x . y . x y + .

La primera línea define una nueva palabra. setxy (tenga en cuenta el prefijo {, que crea un bloque antes del de cierre } y prefijo :, que realmente define la palabra). setxy toma un número de la parte superior de la pila, lo define (o redefine) como global constante x, y el cuadrado de este número como constante y (dado que los valores de las constantes se pueden redefinir, prefiero llamarlos variables, pero sigo la convención de nomenclatura del lenguaje).

Las siguientes dos líneas ponen un número en la pila y llaman setxy, luego se muestran los valores de las constantes. x, y (la palabra se usa para salida .), ambas constantes se colocan en la pila, se suman y el resultado también se imprime. Como resultado veremos:

3 9 12 ok
7 49 56 ok

(El intérprete imprime la línea "ok" cuando termina de procesar la línea actual en el modo de entrada interactivo)

Bueno, un ejemplo de código completo:

"Asm.fif" include

-1 constant wc  // create a wallet in workchain -1 (masterchain)

// Create new simple wallet
<{  SETCP0 DUP IFNOTRET INC 32 THROWIF  // return if recv_internal, fail unless recv_external
    512 INT LDSLICEX DUP 32 PLDU   // sign cs cnt
    c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS  // sign cs cnt cnt' pubk
    s1 s2 XCPU            // sign cs cnt pubk cnt' cnt
    EQUAL 33 THROWIFNOT   // ( seqno mismatch? )
    s2 PUSH HASHSU        // sign cs cnt pubk hash
    s0 s4 s4 XC2PU        // pubk cs cnt hash sign pubk
    CHKSIGNU              // pubk cs cnt ?
    34 THROWIFNOT         // signature mismatch
    ACCEPT
    SWAP 32 LDU NIP 
    DUP SREFS IF:<{
      8 LDU LDREF         // pubk cnt mode msg cs
      s0 s2 XCHG SENDRAWMSG  // pubk cnt cs ; ( message sent )
    }>
    ENDS
    INC NEWC 32 STU 256 STU ENDC c4 POPCTR
}>c
// code
<b 0 32 u, 
   newkeypair swap dup constant wallet_pk 
   "new-wallet.pk" B>file
   B, 
b> // data
// no libraries
<b b{00110} s, rot ref, swap ref, b>  // create StateInit
dup ."StateInit: " <s csr. cr
dup hash dup constant wallet_addr
."new wallet address = " wc . .": " dup x. cr
wc over 7 smca>$ type cr
256 u>B "new-wallet.addr" B>file
<b 0 32 u, b>
dup ."signing message: " <s csr. cr
dup hash wallet_pk ed25519_sign_uint rot
<b b{1000100} s, wc 8 i, wallet_addr 256 u, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
dup ."External message for initialization is " <s csr. cr
2 boc+>B dup Bx. cr
"new-wallet-query.boc" tuck B>file
."(Saved to file " type .")" cr

Este archivo de aspecto aterrador es para crear un contrato inteligente; se colocará en un archivo new-wallet-query.boc después de la ejecución. Tenga en cuenta que aquí se utiliza otro lenguaje ensamblador para TON Virtual Machine (no me detendré en ello en detalle), cuyas instrucciones se colocarán en la cadena de bloques.

Por lo tanto, el ensamblador para TVM está escrito en Fift; las fuentes de este ensamblador están en el archivo crypto/fift/Asm.fif y están conectados al comienzo del código anterior.

¿Qué puedo decir? Al parecer, a Nikolai Durov le encanta crear nuevos lenguajes de programación :)

Creando un contrato inteligente e interactuando con TON

Entonces, supongamos que hemos ensamblado el cliente TON y el intérprete Fift como se describe arriba y nos familiarizamos con el lenguaje. ¿Cómo crear un contrato inteligente ahora? Esto se describe en el archivo. HOWTO, adjunto a las fuentes.

Cuentas en TONELADAS

Como lo describí en revisión de toneladas, esta red contiene más de una cadena de bloques; hay una común, la llamada. "cadena maestra", así como un número arbitrario de "cadenas de trabajo" adicionales, identificadas por un número de 32 bits. La masterchain tiene un identificador de -1, además de él, también se puede utilizar una cadena de trabajo “base” con un identificador de 0. Cada cadena de trabajo puede tener su propia configuración. Internamente, cada cadena de trabajo se divide en cadenas de fragmentos, pero este es un detalle de implementación que no es necesario tener en cuenta.

Dentro de una cadena de trabajo, se almacenan muchas cuentas que tienen sus propios identificadores account_id. Para la cadena maestra y la cadena de trabajo cero, tienen una longitud de 256 bits. Así, el identificador de cuenta se escribe, por ejemplo, así:

-1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d

Este es el formato "sin formato": primero el ID de la cadena de trabajo, luego dos puntos y el ID de la cuenta en notación hexadecimal.

Además, hay un formato abreviado: el número de la cadena de trabajo y la dirección de la cuenta están codificados en formato binario, se les agrega una suma de verificación y todo esto está codificado en Base64:

Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb

Conociendo este formato de registro, podemos solicitar el estado actual de una cuenta a través de un cliente de prueba usando el comando

getaccount -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d

Obtendremos algo como esto:

[ 3][t 2][1558746708.815218925][test-lite-client.cpp:631][!testnode]    requesting account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D
[ 3][t 2][1558746708.858564138][test-lite-client.cpp:652][!testnode]    got account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D with respect to blocks (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F and (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F
account state is (account
  addr:(addr_std
    anycast:nothing workchain_id:-1 address:x8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D)
  storage_stat:(storage_info
    used:(storage_used
      cells:(var_uint len:1 value:3)
      bits:(var_uint len:2 value:539)
      public_cells:(var_uint len:0 value:0)) last_paid:0
    due_payment:nothing)
  storage:(account_storage last_trans_lt:74208000003
    balance:(currencies
      grams:(nanograms
        amount:(var_uint len:7 value:999928362430000))
      other:(extra_currencies
        dict:hme_empty))
    state:(account_active
      (
        split_depth:nothing
        special:nothing
        code:(just
          value:(raw@^Cell 
            x{}
             x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54}
            ))
        data:(just
          value:(raw@^Cell 
            x{}
             x{0000000D}
            ))
        library:hme_empty))))
x{CFF8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D2068086C000000000000000451C90E00DC0E35B7DB5FB8C134_}
 x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54}
 x{0000000D}

Vemos la estructura que está almacenada en el DHT de la cadena de trabajo especificada. Por ejemplo, en el campo storage.balance es el saldo de la cuenta corriente, en storage.state.code - código de contrato inteligente, y en storage.state.data - sus datos actuales. Tenga en cuenta que el almacenamiento de datos TON (Celda, celdas) tiene forma de árbol, cada celda puede tener sus propios datos y celdas secundarias. Esto se muestra como sangría en las últimas líneas.

Construyendo un contrato inteligente

Ahora creemos nosotros mismos una estructura de este tipo (se llama BOC - bolsa de celulas) utilizando el idioma Five. Afortunadamente, no es necesario que usted mismo escriba un contrato inteligente: en la carpeta crypto/block hay un archivo del archivo fuente new-wallet.fif, que nos ayudará a crear una nueva billetera. Copiémoslo a la carpeta con el cliente ensamblado (~/liteclient-build, si siguió las instrucciones anteriores). Cité su contenido arriba como un ejemplo de código en Fift.

Ejecute este archivo de la siguiente manera:

./crypto/fift -I"<source-directory>/crypto/fift" new-wallet.fif

es <source-directory> debe reemplazarse con la ruta a las fuentes descomprimidas (el símbolo “~”, desafortunadamente, no se puede usar aquí, se necesita la ruta completa). En lugar de usar una llave -I puedes definir una variable de entorno FIFTPATH y poner este camino en él.

Desde que lanzamos Fift con el nombre de archivo new-wallet.fif, lo ejecutará y saldrá. Si omite el nombre del archivo, puede jugar con el intérprete de forma interactiva.

Después de la ejecución, debería mostrarse algo como esto en la consola:

StateInit: x{34_}
 x{FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54}
 x{0000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B}

new wallet address = -1 : 4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 
0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ
signing message: x{00000000}

External message for initialization is x{89FEE120E20C7E953E31546F64C23CD654002C1AA919ADD24DB12DDF85C6F3B58AE41198A28AD8DAF3B9588E7A629252BA3DB88F030D00BC1016110B2073359EAC3C13823C53245B65D056F2C070B940CDA09789585935C7ABA4D2AD4BED139281CFA1200000001_}
 x{FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54}
 x{0000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B}

B5EE9C724104030100000000D60002CF89FEE120E20C7E953E31546F64C23CD654002C1AA919ADD24DB12DDF85C6F3B58AE41198A28AD8DAF3B9588E7A629252BA3DB88F030D00BC1016110B2073359EAC3C13823C53245B65D056F2C070B940CDA09789585935C7ABA4D2AD4BED139281CFA1200000001001020084FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED5400480000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B6290698B
(Saved to file new-wallet-query.boc)

Esto significa que la billetera con el ID -1:4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 (o, lo que es lo mismo, 0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ) creado exitosamente. El código correspondiente estará en el archivo. new-wallet-query.boc, su dirección está en new-wallet.addr, y la clave privada está en new-wallet.pk (tenga cuidado: ejecutar el script nuevamente sobrescribirá estos archivos).

Por supuesto, la red TON aún no conoce esta billetera; se almacena únicamente en forma de estos archivos. Ahora hay que subirlo a la red. Sin embargo, el problema es que para crear un contrato inteligente debes pagar una comisión y el saldo de tu cuenta sigue siendo cero.

En modo de trabajo, este problema se resolverá comprando gramos en el intercambio (o transfiriéndolos desde otra billetera). Bueno, en el modo de prueba actual, se ha creado un contrato inteligente especial al que puedes pedir hasta 20 gramos así como así.

Generar una solicitud al contrato inteligente de otra persona

Hacemos una solicitud a un contrato inteligente que distribuye gramos a izquierda y derecha de esta manera. En la misma carpeta crypto/block encontrar archivo testgiver.fif:

// "testgiver.addr" file>B 256 B>u@ 
0x8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d
dup constant wallet_addr ."Test giver address = " x. cr

0x4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2
constant dest_addr

-1 constant wc
0x00000011 constant seqno

1000000000 constant Gram
{ Gram swap */ } : Gram*/

6.666 Gram*/ constant amount

// b x --> b'  ( serializes a Gram amount )
{ -1 { 1+ 2dup 8 * ufits } until
  rot over 4 u, -rot 8 * u, } : Gram, 

// create a message (NB: 01b00.., b = bounce)
<b b{010000100} s, wc 8 i, dest_addr 256 u, amount Gram, 0 9 64 32 + + 1+ 1+ u, "GIFT" $, b>
<b seqno 32 u, 1 8 u, swap ref, b>
dup ."enveloping message: " <s csr. cr
<b b{1000100} s, wc 8 i, wallet_addr 256 u, 0 Gram, b{00} s,
   swap <s s, b>
dup ."resulting external message: " <s csr. cr
2 boc+>B dup Bx. cr
"wallet-query.boc" B>file

También lo guardaremos en la carpeta con el cliente ensamblado, pero corregiremos la quinta línea, antes de la línea "constant dest_addr". Reemplacémosla con la dirección de la billetera que creó antes (completa, no abreviada). No es necesario escribir “-1:” al principio; en su lugar, escriba “0x” al principio.

También puedes cambiar la línea. 6.666 Gram*/ constant amount — esta es la cantidad en gramos que solicitas (no más de 20). Incluso si especifica un número entero, deje el punto decimal.

Finalmente, necesitas corregir la línea. 0x00000011 constant seqno. El primer número aquí es el número de secuencia actual, que se almacena en la cuenta que emite gramos. ¿De dónde puedo conseguirlo? Como se indicó anteriormente, inicie el cliente y ejecute:

last
getaccount -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d

Al final, los datos del contrato inteligente contendrán

...
x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54}
 x{0000000D}

El número 0000000D (el suyo será mayor) es el número de secuencia que debe sustituirse en testgiver.fif.

Eso es todo, guarda el archivo y ejecuta (./crypto/fift testgiver.fif). La salida será un archivo. wallet-query.boc. esto es lo que se forma сообщение al contrato inteligente de otra persona: una solicitud "transferir tantos gramos a tal o cual cuenta".

Usando el cliente lo subimos a la red:

> sendfile wallet-query.boc
[ 1][t 1][1558747399.456575155][test-lite-client.cpp:577][!testnode]    sending query from file wallet-query.boc
[ 3][t 2][1558747399.500236034][test-lite-client.cpp:587][!query]   external message status is 1

Si ahora llamas last, y luego solicite nuevamente el estado de la cuenta desde la cual solicitamos gramos, luego deberíamos ver que su número de secuencia ha aumentado en uno; esto significa que envió dinero a nuestra cuenta.

Queda el último paso: descargar el código de nuestra billetera (su saldo ya se ha recargado, pero sin el código de contrato inteligente no podremos administrarlo). realizamos sendfile new-wallet-query.boc - y eso es todo, tienes tu propia billetera en la red TON (aunque por ahora solo sea de prueba).

Crear transacciones salientes

Para transferir dinero del saldo de la cuenta creada, existe un archivo crypto/block/wallet.fif, que también debe colocarse en la carpeta con el cliente ensamblado.

De manera similar a los pasos anteriores, debe ajustar la cantidad que está transfiriendo, la dirección del destinatario (dest_addr) y el número de secuencia de su billetera (es igual a 1 después de inicializar la billetera y aumenta en 1 después de cada transacción saliente; puede verlo solicitando el estado de tu cuenta). Para las pruebas, puede utilizar, por ejemplo, mi billetera. 0x4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2.

En el arranque (./crypto/fift wallet.fif) el script tomará la dirección de su billetera (desde donde realiza la transferencia) y su clave privada de los archivos new-wallet.addr и new-wallet.pk, y el mensaje recibido se escribirá en new-wallet-query.boc.

Como antes, para realizar directamente la transacción, llame sendfile new-wallet-query.boc en el cliente. Después de esto, no olvides actualizar el estado de la blockchain (last) y comprobar que el saldo y el número de secuencia de nuestra billetera han cambiado (getaccount <account_id>).

Cliente de prueba TON (Telegram Open Network) y nuevo lenguaje Fift para contratos inteligentes

Eso es todo, ahora podemos crear contratos inteligentes en TON y enviarles solicitudes. Como puede ver, la funcionalidad actual ya es suficiente para, por ejemplo, crear una billetera más amigable con una interfaz gráfica (sin embargo, se espera que ya esté disponible como parte del mensajero).

Solo los usuarios registrados pueden participar en la encuesta. Registrarsepor favor

¿Estás interesado en continuar los artículos con análisis de TON, TVM, Fift?

  • Sí, estoy esperando que se complete la serie de artículos con una descripción general de TON.

  • Sí, es interesante leer más sobre el idioma Fift.

  • Sí, quiero aprender más sobre TON Virtual Machine y su ensamblador.

  • No, nada de esto es interesante.

39 usuarios votaron. 12 usuarios se abstuvieron.

¿Qué opinas de los planes de Telegram para lanzar TON?

  • Tengo grandes esperanzas en este proyecto.

  • Simplemente sigo su desarrollo con interés.

  • Soy escéptico y dudo de su éxito.

  • Me inclino a considerar esta iniciativa un fracaso e innecesaria para las grandes masas.

47 usuarios votaron. 12 usuarios se abstuvieron.

Fuente: habr.com

Añadir un comentario