Historial de transacciones TON: lt, hashes y nodo de archivo
Cómo funciona el historial de transacciones TON: tiempo lógico (lt), hashes y por qué la profundidad exige un nodo de archivo. Lectura con agentes vía MCP.
Estás de guardia por la noche y a las 3:47 llega el mensaje: un usuario pagó un pedido en TON y el bot no lo registró. Abres el explorador: el dinero está ahí, la transferencia entrante se ve. O sea, el problema no está en la blockchain, sino en cómo tu servicio lee el historial de transacciones. Y ahí descubres que en TON ese historial funciona de una forma muy distinta a la que conoces de Ethereum.
Monitorear pagos en TON parece engañosamente simple: consultas el saldo y reaccionas al cambio. En la práctica todo se derrumba. Dos pagos por el mismo importe en el mismo minuto: ¿fueron uno o dos? El usuario pagó en USDT y el saldo de GRAM ni se inmutó. Necesitas un extracto de seis meses, pero el liteserver solo devuelve las últimas transacciones y calla sobre el resto.
Si estás conectando un agente de IA a TON o escribes un backend que concilia pagos, vamos al grano: qué es el historial de transacciones de TON, para qué sirve el par lt + hash, por qué la profundidad depende de un nodo de archivo y cómo leer todo esto con un agente vía MCP.
Qué es el historial de transacciones en TON y para qué lo necesita un agente
En TON cada cuenta —una wallet, un contrato, una jetton wallet— tiene su propia cadena de transacciones. Cada transacción es el resultado de procesar un mensaje entrante: recibir GRAM, transferir un jetton, invocar un método de un contrato. Para un agente (Claude, Cursor, cualquier cliente MCP) que acepta pagos o concilia cuentas, el historial es la única fuente fiable: el saldo dice «cuánto hay ahora», y el historial, «qué pasó exactamente, cuándo, de quién y por qué importe».
Tareas concretas para las que un agente necesita el historial:
- confirmar que un pago llegó («comprueba si hubo una transferencia a esta dirección en la última hora»);
- armar el extracto de una wallet;
- rastrear una transacción concreta por su identificador;
- cotejar los jettons entrantes (por ejemplo, USDT) con el importe esperado.
El problema es que «dame las transacciones n.º 100–120» en TON no funciona. Aquí no existe una numeración global y continua de bloques con la que pedir «la transacción número N». El orden se define de otra manera: con el tiempo lógico.
Tiempo lógico (lt): por qué en TON no hay numeración de bloques normal
En Ethereum todo es simple: existe el bloque n.º 19 000 000 y dentro van las transacciones en orden. Un contador global que crece de forma monótona, y todos se guían por el mismo número.
TON es un sistema multihilo: masterchain, workchains y shards que se dividen y se fusionan según la carga. Un «número de bloque» único con el que ordenar linealmente todos los eventos de la red simplemente no existe. En su lugar TON usa el tiempo lógico (lt, logical time): un contador que crece monótonamente y con el que la red ordena eventos, mensajes y transacciones. Garantiza que si el evento A influyó en el evento B, entonces lt(A) < lt(B).
De ahí la consecuencia práctica: la posición de una transacción no la define un número de bloque, sino el par (lt, hash). El lt se encarga del orden (quién fue antes); el hash, de identificar de forma inequívoca una transacción concreta. Por separado son inútiles para una consulta puntual: objetos distintos pueden tener lt cercanos, y el hash a solas no le dice al liteserver desde dónde empezar a leer.
El hash de la transacción y el par lt + hash: el puntero a la última transacción de la cuenta
El hash de una transacción es su huella criptográfica; en TON llega en base64 o hex. El lt dice «cuándo dentro del orden»; el hash, «cuál exactamente», porque sobre un mismo lt puede darse ambigüedad en teoría, y sin el hash el liteserver no entregará la transacción. Grábatelo a fuego: el par (lt, hash) es obligatorio en conjunto. Solo el lt o solo el hash no basta.
¿De dónde sacar el punto de partida? El estado de la cuenta guarda un puntero a su transacción más reciente: last_transaction_id, que es justamente ese par lt + hash (los campos last_trans_lt / last_trans_hash). Es la «cabeza» de la lista desde la que empieza el recorrido del historial hacia atrás.
En el set de herramientas MCP de TONNode esto lo hace get_account_state: devuelve el estado de la cuenta, sus flags y el puntero a la última transacción.
Cómo get_transactions pagina el historial: lt + hash y la cadena prev_trans
Ahora, el punto clave que hace que el historial se pueda paginar. Cada transacción, además de sus propios lt y hash, contiene dos campos: prev_trans_lt y prev_trans_hash, la referencia a la transacción anterior de esa misma cuenta. Es decir, las transacciones forman una lista enlazada que va hacia atrás en el tiempo; la cabeza es el last_transaction_id del estado.
get_transactions recibe:
account— la dirección de la cuenta;- los
ltyhashiniciales — el punto desde el que leer; count— el tamaño del lote.
Devuelve un lote de transacciones avanzando hacia atrás desde el punto indicado. La lógica del recorrido por páginas:
- Tomar
last_trans_lt/last_trans_hashdeget_account_state: esa es la cabeza. - Llamar a
get_transactions(account, lt, hash, count)y obtener el lote. - De la última transacción del lote tomar
prev_trans_ltyprev_trans_hash. - Volver a llamar a
get_transactionsya con ese par: esa es la página siguiente. - Repetir hasta que
prev_trans_ltllegue a 0 (el inicio de la vida de la cuenta) o hasta alcanzar la profundidad que necesitas.
Así funciona la paginación en TON: no «página 2», sino «continúa desde este par (lt, hash)».
Bloques recientes frente a historial profundo: para qué sirve el nodo de archivo
Aquí es donde tropieza la mayoría. Un liteserver normal entrega los bloques frescos y el historial reciente de la cuenta: mantiene una ventana limitada de estado —cierto número de bloques recientes— y, a medida que la red crece, los datos viejos van quedando fuera de ella. Recorre la cadena prev_trans lo suficientemente atrás y en algún momento el liteserver simplemente dejará de devolver transacciones: físicamente ya no están en su ventana. El pago fresco lo verás; la transacción de hace seis meses, no.
No es un bug, es diseño: mantener la ruta completa de cada cuenta desde el génesis sale caro. El historial profundo lo conserva el nodo de archivo: un nodo que no descarta los bloques viejos, sino que guarda el estado completo de la red durante toda su historia.
Conclusión práctica:
- detectar un pago, un extracto fresco, «¿llegó algo en la última hora?» — basta con un liteserver normal;
- auditoría completa de la wallet desde su primer día — hace falta un nodo de archivo.
Un dolor aparte son los liteservers públicos de la config global de TON. Son compartidos y limitados: bajo carga suelen responder not ready o irse a timeout de ADNL, y tampoco tienen historial profundo. Si lo que te sale es justamente not ready, es el síntoma de un liteserver compartido y sobrecargado; el análisis está en la nota por qué el liteserver responde not ready y cómo arreglarlo.
Con honestidad sobre TONNode: el nodo de archivo está en el roadmap y ahora mismo se está sincronizando; no te prometo la profundidad de archivo como una función terminada. A día de hoy esto es lectura del historial fresco y reciente a través de un endpoint gestionado, sin la lotería de los liteservers públicos. Para el archivo completo desde el génesis, espera el anuncio correspondiente.
Cómo leer el historial de TON con un agente de IA vía MCP
TONNode es un servidor MCP hosted para TON, exactamente 16 herramientas, y get_transactions forma parte del bloque de lectura. MCP (Model Context Protocol) es el estándar con el que el agente invoca herramientas por su cuenta, sin que tú armes peticiones ADNL a mano. No hace falta instalar un SDK, levantar un liteserver ni parsear TL-B: el agente llama a la herramienta directamente.
Conexión local gratuita
Set completo de lectura, config pública, paquete @tonnode/mcp — open source, MIT:
{
"mcpServers": {
"ton": {
"command": "npx",
"args": ["-y", "@tonnode/mcp"]
}
}
}
El paquete funciona sobre el protocolo nativo ADNL de TON, sin capas HTTP intermedias.
Endpoint hosted con clave propia
Para tener throughput garantizado, se usa el endpoint hosted con tu propia clave:
{
"mcpServers": {
"ton": {
"type": "http",
"url": "https://mcp.tonnode.io/mcp",
"headers": { "Authorization": "Bearer tn_live_…" }
}
}
}
Para leer el historial te servirán:
get_account_state— el punto de partida del recorrido (last_trans_lt/last_trans_hash), estado y flags de la cuenta;get_transactions— las transacciones en sí, por páginas, con el par(lt, hash);parse_address— conversión offline de direcciones entreEQ/UQ/raw;get_jetton_infoyget_jetton_balance— para el historial de jettons.
Práctica: detectar un pago y recorrer el historial por páginas
Montemos el escenario típico: «¿llegó el pago y por qué importe?».
Prompt para el agente
Con la herramienta
tontomaget_account_stateparaEQC…myshop, luegoget_transactionsdesde sulast_trans_lt/last_trans_hash, count 20. Busca una transferencia entrante de 5 GRAM en los últimos 10 minutos. Convierte las direcciones de los remitentes a EQ conparse_addressantes de comparar. Si necesitas más profundidad, tomaprev_trans_lt/prev_trans_hashde la última transacción y repiteget_transactions.
El agente irá por su cuenta a buscar la cabeza de la cadena, recorrerá el lote y cotejará los importes.
Pseudocódigo del recorrido por páginas
El mismo recorrido en pseudocódigo (las llamadas son herramientas MCP que invoca el agente):
state = get_account_state(account)
lt = state.last_trans_lt
hash = state.last_trans_hash
while lt != 0:
batch = get_transactions(account, lt, hash, count=20)
for tx in batch:
if matches_expected_payment(tx): # mensaje entrante con el importe/comentario esperado
return tx
last = batch[-1]
lt = last.prev_trans_lt
hash = last.prev_trans_hash # sin el hash no se puede pedir la página siguiente
Detalles que ahorran horas de depuración
- Las direcciones en los campos de la transacción llegan en formato raw (
0:abcd…). Antes de comparar el remitente o el destinatario con la habitual direcciónEQ…, lleva ambas al mismo formato conparse_address; si no, la comparación de strings no cuadrará aunque la dirección sea la misma. Más sobre los formatos en EQ, UQ y raw en las direcciones de TON. - Los pagos en USDT no se ven en la cadena de la wallet de GRAM. Los jettons viven en una jetton wallet aparte, cuya dirección se calcula on-chain (
get_jetton_balancelo hace por ti y te da el saldo actual). Para el historial de jettons recorre las transacciones de la jetton wallet, no de la wallet principal. - Recalcula los importes raw con los decimals. Los importes de jettons llegan en unidades mínimas: para convertir
5000000en los 5 USDT legibles por humanos, toma losdecimalsdeget_jetton_info; en USDT son 6, en la mayoría de los jettons 9. Confúndelos y te equivocarás por un factor de 1000. El análisis completo: cómo detectar un pago entrante de USDT en TON. - Deduplica por
(lt, hash), no por importe. Dos pagos idénticos solo se distinguen por el par lt+hash: esa es la clave de idempotencia.
Si además del historial el agente necesita consultar el estado actual de un contrato, para eso está run_get_method; cómo llamar get-methods sin SDK se muestra en leer TON sin SDK con un get-method.
En resumen
- En TON no hay números de bloque como en Ethereum: la posición de una transacción la define el par
(lt, hash)— lt es el orden, hash la identificación, y son obligatorios juntos. - Las transacciones de una cuenta son una lista enlazada vía
prev_trans_lt/prev_trans_hash; se pagina hacia atrás empezando por ellast_transaction_iddeget_account_state. - Un liteserver normal entrega el historial fresco y reciente; la profundidad completa es tarea del nodo de archivo.
- Con los jettons no olvides los decimals de
get_jetton_info(USDT = 6) ni las direcciones raw, que hay que pasar porparse_address.
¿No quieres pelearte con liteservers públicos que responden not ready? get_transactions está disponible de serie en el plan gratuito Hobby: 60 peticiones/min, para siempre, sin tarjeta, y la clave se emite nada más iniciar sesión.
Conecta la lectura del historial de TON en un minuto → tonnode.io/dashboard?plan=hobby
Y todo lo demás que puede hacer un agente en TON aparte de leer el historial: las 16 herramientas, en la página de herramientas de TONNode.
Dale a tu agente acceso a TON
16 herramientas MCP: lectura, swaps no custodiales, cross-chain y billeteras. Plan gratuito — 60 req/min, sin tarjeta.