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

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


Desde entonces, no hubo noticias significativas sobre el estado de desarrollo de TON, hasta hace un par de días (en uno de los canales no oficiales ) apareció un enlace en la página https://test.ton.org/download.html , donde se encuentran:


ton-test-liteclient-full.tar.xz : código fuente de cliente ligero para la red de prueba TON;
ton-lite-client-test1.config.json : archivo de configuración para conectarse a una red de prueba;
README : información sobre la creación y el inicio del cliente;
CÓMO : instrucciones paso a paso sobre cómo crear un contrato inteligente con un cliente;
ton.pdf : documento actualizado (fechado el 2 de marzo de 2019) con una descripción técnica de la red TON;
tvm.pdf : descripción técnica de TVM (máquina virtual TON, máquina virtual TON);
tblkch.pdf : descripción técnica de la cadena de bloques TON;
fiftbase.pdf : una descripción del nuevo lenguaje Fift, diseñado para crear contratos inteligentes en TON.


Repito, el Telegram no confirmó oficialmente la página y todos estos documentos, pero el volumen de estos materiales los hace bastante verosímiles. Ejecute un cliente publicado bajo su propio riesgo .


Prueba de compilación del cliente


Primero, intentemos construir y ejecutar un cliente de prueba; afortunadamente, README describe este sencillo proceso en detalle. Haré esto en el ejemplo de macOS 10.14.5, no puedo garantizar el éxito del ensamblaje en otros sistemas.


  1. Descargue y descomprima el archivo con los códigos fuente . Es importante descargar la última versión, ya que la compatibilidad con versiones anteriores no está garantizada en esta etapa.


  2. Nos aseguramos 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 reinstalar nada, todo se reunió de inmediato.


  3. Supongamos que las fuentes se descomprimen en la carpeta ~/lite-client . Por separado, creamos una carpeta vacía para el proyecto ensamblado (por ejemplo, ~/liteclient-build ), y desde él ( cd ~/liteclient-build ) cd ~/liteclient-build comandos:


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

    Construcción exitosa del cliente

    Para construir el intérprete de lenguaje Fift para contratos inteligentes (ver más abajo), también llamamos


     cmake --build . --target fift 

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


  5. Hecho , puede iniciar el cliente:


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


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


Lanzamiento del cliente


Como puede ver, hay pocos comandos disponibles:


help : muestra esta lista de comandos;
quit - salir;
time : muestra la hora actual en el servidor;
status : muestra el estado de la conexión y la base de datos local;
last : actualiza el estado de la cadena de bloques (carga el último bloque). Es importante ejecutar este comando antes de cualquier solicitud para asegurarse de que ve exactamente el estado actual de la red.
sendfile <filename> : sube un archivo local a la red TON. Esta es la interacción con la red, que incluye, por ejemplo, la creación de nuevos contratos inteligentes y solicitudes de transferencia de fondos entre cuentas;
getaccount <address> : muestra el estado actual (en el momento en que se ejecutó el last comando) con la dirección especificada;
privkey <filename> : carga la clave privada desde el archivo local.


Si en el inicio del cliente, le pasa la carpeta usando la opción -D , entonces 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), subirlo a la red e intentar transferir fondos entre cuentas.


Lenguaje quincuagésimo


A partir del documento fiftbase.pdf, puede descubrir que para crear contratos inteligentes, el equipo de Telegram creó un nuevo lenguaje de pila Fift (aparentemente, a partir del número quinto , por analogía con Forth, un lenguaje con el que Fift tiene mucho en común).


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


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


Las palabras generalmente interactúan con significados en la parte superior de la pila. Un tipo separado de palabras, prefijo , no usa la pila, sino los caracteres posteriores del archivo fuente. Por ejemplo, los literales de cadena se implementan de esta manera: el carácter “comillas” ( " ) es una palabra de prefijo que busca la siguiente comilla (de cierre) y coloca la cadena entre ellos en la pila. La línea simple ( // ) y la línea múltiple ( /* ) se comportan de la misma manera. comentarios


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


Un ejemplo simple de un programa Fift:


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

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


En las siguientes dos líneas, se coloca un número en la pila, se setxy , setxy se setxy los valores de las constantes x , y (la palabra se usa para la salida) . Ambas constantes se colocan en la pila, se suman y también se muestra el resultado. 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 modo de entrada interactiva)


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 <bb{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 <bb{1000100} s, wc 8 i, wallet_addr 256 u, b{000010} s, swap <ss, b{0} s, swap B, swap <ss, 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 está diseñado para crear un contrato inteligente: se colocará en el new-wallet-query.boc después de la ejecución. Tenga en cuenta que aquí se usa otro lenguaje ensamblador para la máquina virtual TON (no me detendré 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 se encuentran en el archivo crypto/fift/Asm.fif y están conectadas al comienzo del código anterior.


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


Crear un contrato inteligente e interactuar con TON


Entonces, supongamos que reunimos un cliente TON y un intérprete de Fift, como se describió anteriormente, y nos familiarizamos con el idioma. ¿Cómo crear un contrato inteligente ahora? Esto se describe en el archivo HOWTO adjunto a la fuente.


TON Cuentas


Como describí en la revisión de TON , 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 cadena maestra tiene un identificador de -1, además de eso, también se puede usar una cadena de trabajo "básica" con el identificador 0. Cada cadena de trabajo puede tener su propia configuración. Internamente, cada grupo de trabajo se divide en cadenas de fragmentos, pero esto ya es un detalle de la implementación, que no tiene que tenerse en cuenta.


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


 -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d 

Este es un formato "en bruto": primero, el identificador de la cadena de trabajo, luego dos puntos y el identificador 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 forma binaria, se les agrega una suma de verificación y todo esto está codificado en Base64:


 Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb 

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


 getaccount -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d 

Recibimos una respuesta como esta:


 [ 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} -client.cpp: [ 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} por -1: 8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D con respecto a los bloques (-1,8000000000000000,72355): F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296: 1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F y [ 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 se almacena en el DHT de la cadena de trabajo especificada. Por ejemplo, en el campo storage.balance encuentra el saldo de la cuenta corriente, en storage.state.code encuentra el código de contrato inteligente y en storage.state.data encuentran sus datos actuales. Tenga en cuenta que el almacén de datos TON - Celda, celdas - es un árbol, cada celda puede tener sus propios datos, así como celdas secundarias. Esto se muestra como sangría en las últimas líneas.


Asamblea de contrato inteligente


Ahora creemos una estructura como esta (se llama BOC - bolsa de celdas ) usando el lenguaje Fift. Afortunadamente, no tendrá que escribir un contrato inteligente usted mismo: en la carpeta crypto/block archivo de origen hay un archivo new-wallet.fif que nos ayudará a crear una nueva billetera. Cópielo en la carpeta con el cliente ensamblado ( ~/liteclient-build , si ~/liteclient-build instrucciones anteriores). Cité su contenido arriba como un ejemplo de código en Fift.


Ejecutamos este archivo de la siguiente manera:


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

Aquí <source-directory> debe reemplazarse con la ruta a las fuentes desempaquetadas (el símbolo "~" no se puede usar aquí, desafortunadamente, necesita la ruta completa). En lugar de usar el FIFTPATH -I puede definir la FIFTPATH entorno FIFTPATH y poner esta ruta en ella.


Desde que lanzamos Fift con el nombre de archivo new-wallet.fif , lo ejecutará y completará. Si omite el nombre del archivo, puede jugar con el intérprete en modo interactivo.


Después de la ejecución, algo como esto debería mostrarse 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) } 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 identificador -1:4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 (o, lo que es lo mismo, 0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ El código correspondiente new-wallet-query.boc en el new-wallet-query.boc , su dirección en new-wallet.addr y la clave privada en new-wallet.pk (tenga cuidado: reiniciar el script sobrescribirá estos archivos).


Por supuesto, la red TON aún no conoce esta billetera, solo se almacena en forma de estos archivos. Ahora necesita subirlo a la red. Es cierto que el problema es que para crear un contrato inteligente debe pagar una comisión, y el saldo de su cuenta sigue siendo cero.


En el modo de trabajo, este problema se resolverá comprando gramos en el intercambio (o transfiriendo desde otra billetera). Bueno, en el modo de prueba actual, se ha instituido un contrato inteligente especial, desde el cual puede solicitar hasta 20 gramos de esa manera.


Formación de una solicitud para el contrato inteligente de otra persona.


Solicite un contrato inteligente, distribuyendo gramos a izquierda y derecha, hágalo. En la misma carpeta crypto/block encontramos el 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 // bx --> 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) <bb{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 <bb{1000100} s, wc 8 i, wallet_addr 256 u, 0 Gram, b{00} s, swap <ss, b> dup ."resulting external message: " <s csr. cr 2 boc+>B dup Bx. cr "wallet-query.boc" B>file 

También lo constant dest_addr en la carpeta con el cliente ensamblado, pero arreglamos la quinta línea, antes de la línea " constant dest_addr ". Reemplácelo con la dirección de la billetera que creó antes (completa, no abreviada). "-1:" no necesita escribir al principio, en su lugar, ponga "0x" al principio.


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


Finalmente, debe 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 los gramos. ¿De dónde conseguirlo? Como se mencionó anteriormente, inicie el cliente y ejecute:


 last getaccount -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d 

Al final en los datos del contrato inteligente será


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

El número 0000000D (tendrá más) es el número de secuencia, que debe sustituirse en testgiver.fif .


Eso es todo, guarde el archivo y ejecútelo ( ./crypto/fift testgiver.fif ). El resultado será el wallet-query.boc . Este es el mensaje formado para el contrato inteligente de otra persona: la solicitud es "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 llamamos al last y luego volvemos a solicitar el estado de la cuenta desde la que solicitamos gramos, entonces deberíamos ver que su número de secuencia ha aumentado en uno, esto significa que envió dinero a nuestra cuenta.


El último paso permanece: cargamos el código de nuestra billetera (su saldo ya se ha reabastecido, pero sin el código de contrato inteligente no podremos administrarlo). sendfile new-wallet-query.boc , y eso es todo, tiene su propia billetera en la red TON (aunque por ahora solo una de prueba).


Crear transacciones salientes


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


De manera similar a los pasos anteriores, debe corregir la cantidad que transfiere, la dirección del destinatario (dest_addr) y la seqno de su billetera (es 1 después de que la billetera se inicializa y aumenta en 1 después de cada transacción saliente; puede verla solicitando el estado de su cuenta) . Para las pruebas, puede usar, por ejemplo, mi billetera - 0x4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 .


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


Como antes, para ejecutar directamente la transacción, llamamos a sendfile new-wallet-query.boc en el cliente. Después de eso, no olvide actualizar el estado de la cadena de bloques ( last ) y verifique que el saldo y la seqno de nuestra billetera hayan cambiado ( getaccount <account_id> ).


Descripción de la cuenta


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, hacer una billetera más amigable con una interfaz gráfica (sin embargo, se espera que esté disponible como parte del messenger).

Source: https://habr.com/ru/post/453714/


All Articles