C++, Rust y los intercambios criptográficos descentralizados: aplicabilidad y eficiencia
Introducción
Los argumentos lingüísticos se vuelven especialmente engañosos en el ámbito de las criptomonedas porque los sistemas en sí son muy fáciles de describir erróneamente. La gente dice "construir un DEX" como si un intercambio descentralizado fuera un ejecutable con un perfil de latencia, un modelo de confianza y un tipo de falla. En realidad, un DEX serio es un organismo en capas. Puede incluir lógica en cadena, interacciones de validador o nodo, conciencia de creación de bloques, monitoreo de mempool, recopilación de datos de mercado, simulación de estado, fijación de precios, enrutamiento, verificaciones de riesgos, paneles de control de operadores y, a veces, libros de pedidos o servicios adyacentes a coincidencias que se parecen sospechosamente a la infraestructura de intercambio tradicional con vocabulario de blockchain.
Una vez que reconocemos esa realidad en capas, la discusión entre C++ y Rust se vuelve más tranquila y mucho más útil. La pregunta correcta no es qué idioma merece toda la arquitectura como punto de honor. La pregunta correcta es qué capas se benefician de la seguridad y el ajuste del ecosistema de Rust, qué capas aún recompensan el control de rendimiento de bajo nivel de C++ y dónde el diseño híbrido deja de ser un compromiso y comienza a ser un simple sentido común.
Ese marco es importante porque los sistemas de intercambio descentralizados viven bajo presiones mixtas. Algunas capas son castigadas con mayor dureza por fallas de corrección, problemas de auditabilidad y transiciones de estado inseguras. Otras capas son castigadas por la latencia, el rendimiento y la incapacidad de evaluar oportunidades con la suficiente rapidez. Otros son servicios operativos donde el costo real es el mantenimiento a largo plazo y la velocidad del equipo. Un idioma puede ser excelente para una de esas cargas y simplemente adecuado para otra. La arquitectura madura comienza cuando lo admitimos abiertamente.
Un DEX es una pila, no una declaración de identidad
La primera y más importante corrección es conceptual. Un DEX no es una sola cosa. Un protocolo AMM orientado a EVM, un ecosistema de programas nativo de Solana, un intercambio perpetuo de cadena de aplicaciones y un sistema de búsqueda que reacciona a las condiciones del mercado merecen instintos de ingeniería diferentes. La lógica AMM en cadena vive dentro de un conjunto de restricciones. Los simuladores fuera de cadena y los evaluadores de rutas viven dentro de otro. Los componentes similares a libros de pedidos o la infraestructura de búsqueda de alta frecuencia pueden parecer, desde una perspectiva de sistemas, mucho más cercanos al software de intercambio clásico que al desarrollo de aplicaciones web ordinarias.
Por eso los debates lingüísticos se desvían tan rápidamente. Un ingeniero señala Solana y observa correctamente que Rust es el camino natural para el desarrollo de programas allí. Otro señala un motor de simulación o enrutamiento sensible a la latencia y observa correctamente que C++ sigue siendo una opción brutalmente sólida. Ambos están en contexto. El problema comienza cuando cada observación se infla en una teoría total de toda la pila.
Un reinicio mental útil es preguntar, para cada subsistema, por qué tipo de dolor es castigado. Si un componente está mal, ¿el problema es principalmente una falla de corrección pública? ¿Es un costo operativo privado? ¿Es la incapacidad de responder a un estado que cambia rápidamente antes de que se cierre la oportunidad? ¿Es carga de auditoría, carga de contratación o carga de infraestructura? Diferentes capas responden a estas preguntas de manera diferente, razón por la cual los sistemas DEX maduros a menudo terminan lingüísticamente mezclados incluso cuando los debates públicos anhelan pureza.
Donde Rust toma la delantera con razón
Rust gana su lugar de forma más natural donde las transiciones estatales, la disciplina de seguridad y el ajuste del ecosistema dominan la arquitectura. En entornos blockchain que priorizan Rust, como Solana, esa no es una ventaja marginal. Es el centro de gravedad. El idioma no sólo está disponible allí; está rodeado de marcos, ejemplos, hábitos de seguridad y herramientas que ayudan a los equipos de protocolo a moverse en el sentido del ecosistema en lugar de ir en contra de él. Para los programas en cadena, ese ajuste es más importante que la comparación de lenguajes abstractos. El mejor lenguaje sobre el papel es a menudo el peor lenguaje si cada camino operativo serio a su alrededor espera algo más.
Rust también es atractivo en servicios totalmente nuevos que rodean un DEX cuando el principal enemigo no es la latencia ultrabaja sino la corrección y la mantenibilidad a largo plazo. Los servicios del plano de control, las capas de coordinación y ciertas herramientas orientadas al protocolo pueden beneficiarse genuinamente de la disciplina que fomenta Rust. El compilador detecta categorías de errores que de otro modo exigirían proceso, vigilancia y cultura de revisión para controlar en C++. Esa no es una afirmación romántica. Es práctico. Los equipos con un gran talento en Rust pueden reducir algunas clases de riesgo desde el principio y mantener los límites del servicio más tranquilos con el tiempo.
Un contraejemplo útil mantiene esto fundamentado. A veces, los equipos infieren de la fortaleza de Rust en el trabajo nativo de la cadena que todos los subsistemas circundantes fuera de la cadena también deberían ser Rust de forma predeterminada. Pero eso sólo ocurre si los sistemas circundantes tienen el mismo dolor dominante. Un simulador de ruta activa o un motor de búsqueda que evalúa repetidamente el estado del mercado bajo una presión de tiempo ajustada no deja de ser un sistema nativo sensible al rendimiento solo porque sirve un producto criptográfico. La cadena puede tener forma de Rust, mientras que la ruta de ejecución circundante sigue teniendo una forma muy similar a C++.
Donde C++ todavía se gana la vida
C++ se vuelve difícil de reemplazar cuando un DEX comienza a comportarse menos como una plataforma de aplicaciones y más como una infraestructura de intercambio. La ingesta de datos de mercado, la escucha de mempool, los canales de normalización, la evaluación de rutas, la simulación de estado, la búsqueda de arbitraje, los motores de liquidación y los servicios adyacentes al libro de pedidos comparten una propiedad común: realizan trabajos repetidos de bajo nivel bajo presión, y ese trabajo a menudo se ubica cerca del diseño de la memoria, la estrategia de asignación, la eficiencia del analizador, el comportamiento de la cola o la previsibilidad de la CPU.
Aquí es donde la larga historia de C++ en sistemas y comercio sigue siendo importante. El lenguaje brinda a los ingenieros control directo sobre las estructuras de datos, los modelos de subprocesamiento, la vida útil de los objetos, los asignadores personalizados, los diseños compatibles con vectores y las herramientas de rendimiento que han sido probadas exactamente en este tipo de entornos. También se beneficia de un ecosistema más antiguo y denso de ejemplos de sistemas en red de alto rendimiento, simuladores, analizadores, puertas de enlace nativas y código compatible con el hardware. En una era en la que a los asistentes de IA también se les pide que ayuden con esos problemas, esa densidad agrava la ventaja.
Consideremos un buscador que escucha las señales del mercado, simula caminos y decide si vale la pena aprovechar una oportunidad. El costo interesante rara vez es una fórmula aislada. El costo interesante es el uso repetido y con estado de muchas fórmulas rodeadas de ingesta, decodificación, enrutamiento y lógica de decisión. Unas pocas copias evitables, un candado mal colocado o una cola indisciplinada pueden cambiar la economía de todo el camino. C++ no es mágico aquí, pero brinda a los ingenieros un lenguaje profundamente familiar para hacer preguntas exactas a la máquina. En sistemas que viven y mueren por repetición bajo presión del tiempo, eso todavía importa.
La economía cambia la respuesta del lenguaje
Una de las razones por las que estos debates se vuelven acalorados es que los ingenieros hablan como si la condición para ganar fuera la elegancia. En los sistemas DEX la condición de ganancia suele ser económica. La latencia es importante porque las oportunidades perdidas tienen un costo. La eficiencia importa porque la simulación repetida a escala tiene un costo. La seguridad es importante porque las transiciones de estado incorrectas tienen un costo. La simplicidad operativa es importante porque un sistema que constantemente asusta a sus operadores tiene un costo. Una vez que el argumento se plantea en esos términos, la elección del idioma deja de ser simbólica y se vuelve financiera.
Rust a menudo se amortiza por sí solo cuando el mayor costo futuro provendría de fallas de corrección en la lógica de estado estricta o del mantenimiento de servicios complejos sin suficiente disciplina estructural. C++ a menudo se amortiza cuando el mayor costo futuro provendría de la ineficiencia de la ruta activa, demasiada abstracción en el cálculo repetido o la dificultad de integrarse con una infraestructura nativa de alto rendimiento. Un equipo sensato pregunta qué costo predominará durante la vida del subsistema y elige en consecuencia.
Esta perspectiva también ayuda con una confusión común: la velocidad de liquidación y la velocidad de la ruta de ejecución no son lo mismo. Una cadena de bloques puede tener un conjunto de características de sincronización a nivel de protocolo, mientras que los sistemas fuera de la cadena que la rodean viven en un mundo de latencia completamente diferente. La liquidación lenta dentro de la cadena no hace que la evaluación rápida fuera de la cadena sea irrelevante. De hecho, cuando se disputan oportunidades, la velocidad fuera de la cadena puede volverse aún más valiosa porque determina quién reacciona, quién fija el precio con precisión y quién presenta primero una acción útil. Los ingenieros que combinan estos dos dominios del tiempo en un solo concepto llamado velocidad generalmente terminan desperdiciando esfuerzos.
La arquitectura híbrida suele ser la respuesta de los adultos
Muchas de las arquitecturas DEX más serias se vuelven más fáciles de razonar una vez que se permite que el diseño híbrido sea respetable. La lógica en cadena puede vivir en el entorno de lenguaje y marco que espera la cadena. El plano de control y los servicios de productos pueden elegir el lenguaje que mantenga el mantenimiento cuerdo. La simulación de ruta activa, el enrutamiento, el procesamiento de datos de mercado o la coincidencia de componentes adyacentes pueden mantenerse cerca de las tradiciones de rendimiento que los hacen más fáciles de ajustar y verificar. El resultado no es un compromiso ideológico. Es un sistema donde a cada parte se le permite optimizar su carga real.
Esto requiere madurez. Los sistemas híbridos sólo son saludables cuando los límites son explícitos. Los equipos necesitan interfaces claras, divisiones estrechas de responsabilidades y honestidad sobre dónde pertenece la complejidad. Pero eso es cierto independientemente del idioma. Una arquitectura de un solo lenguaje con límites confusos no es más simple que una arquitectura de dos lenguajes con límites claros. A veces se trata simplemente de una expresión monolingüe de la misma confusión.
Aquí también hay una dimensión de dotación de personal. Los equipos a menudo imaginan que deben elegir un idioma porque resulta difícil contratar en múltiples dominios nativos. Esa preocupación es comprensible, pero puede convertirse en una excusa para la pereza arquitectónica. Una mejor pregunta es si la capa más sensible al rendimiento realmente necesita su propio lenguaje o si el generador de perfiles aún no ha justificado ese costo. Algunos equipos deberían permanecer principalmente en Rust y solo introducir C++ cuando un camino activo se lo haya ganado. Otros ya tienen una profunda experiencia en C++ y se dañarían a sí mismos al forzar todo a un flujo de trabajo en forma de Rust que no coincida con sus instintos sistémicos más fuertes. Nuevamente el contexto importa más que el prestigio.
Qué cambia la ingeniería asistida por IA
La llegada de los sistemas de codificación de IA en realidad fortalece los argumentos a favor de la elección del lenguaje contextual en lugar de debilitarlos. En los ecosistemas blockchain de Rust, los agentes pueden ayudar con el andamiaje compatible con el marco, el código de servicio de rutina y algunas categorías de refactorización de manera más cómoda que antes. Pero en subsistemas nativos de bajo nivel y con alto rendimiento, la balanza todavía se inclina hacia C++ por una sencilla razón: el código público, las herramientas públicas y los ejemplos de integración pública son mucho más densos allí. Actualmente, los agentes tienen más material histórico a partir del cual producir borradores útiles para los tipos de infraestructura de ruta activa que los sistemas DEX a menudo necesitan.
Esto no significa que la IA haga que C++ sea universalmente superior. Significa que la gravedad del antiguo ecosistema ahora se ve amplificada por una nueva herramienta. Cuando un asistente ayuda a depurar una integración de CMake, sugiere un rediseño de cola, mejora un analizador o redacta un punto de referencia para un bucle de simulación, se beneficia de la profunda memoria nativa del mundo público de C++. Cuando un asistente trabaja dentro de un entorno en cadena que prioriza Rust, puede ocurrir lo contrario. La decisión sobre el idioma todavía pertenece a la carga de trabajo, pero la era de la IA hace que la densidad ambiental sea aún más importante que antes.
Mi recomendación práctica
Si está creando programas nativos de cadena en un ecosistema de Rust-first, no luche contra el terreno por el bien de la retórica del lenguaje. Dejemos que Rust lidere donde ya es el hogar natural de la corrección, las herramientas y la práctica comunitaria. Si está creando una infraestructura fuera de la cadena que se comporta como ingeniería de intercambio sensible al rendimiento, no abandone C++ simplemente porque el dominio del producto sea criptográfico. Deje que C++ haga el trabajo que todavía hace excepcionalmente bien: ingesta rápida, simulación repetida, lógica de enrutamiento estricta y control de sistemas de bajo nivel.
Y si su arquitectura realmente abarca ambos mundos, acepte ese hecho sin avergonzarse. La buena ingeniería no se vuelve más pura pretendiendo que todos los componentes sufren el mismo tipo de falla. Se fortalece asignando a cada componente un lenguaje que respete la física de su trabajo real.
Hay un tranquilo optimismo al abordar el problema de esta manera. Recuerda a los ingenieros que la arquitectura puede ser más tranquila que el discurso público. No tenemos que elegir un idioma para ganar la discusión para siempre. Sólo tenemos que elegir la herramienta adecuada para la siguiente capa honesta del sistema. Ése es un tipo de inteligencia mucho más rentable.
Laboratorio práctico: cree un pequeño evaluador de rutas AMM
Construyamos algo lo suficientemente pequeño como para entenderlo y lo suficientemente real como para tocarlo.
El objetivo no es recrear Uniswap. El objetivo es sentir qué tan rápido el trabajo DEX se convierte en una cuestión de simulación y comparación repetidas.
__CÓDIGO_0__
#include <cmath>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
struct Pool {
std::string name;
double reserve_in;
double reserve_out;
double fee; // 0.003 for 0.3%
};
double swap_out(const Pool& p, double amount_in) {
const double effective_in = amount_in * (1.0 - p.fee);
return (effective_in * p.reserve_out) / (p.reserve_in + effective_in);
}
double two_hop(const Pool& a, const Pool& b, double amount_in) {
const double mid = swap_out(a, amount_in);
return swap_out(b, mid);
}
int main() {
Pool eth_usdc_a{"ETH/USDC pool A", 500.0, 1750000.0, 0.003};
Pool eth_usdc_b{"ETH/USDC pool B", 650.0, 2262000.0, 0.0005};
Pool usdc_dai{"USDC/DAI stable pool", 900000.0, 901200.0, 0.0001};
const double trade_eth = 4.0;
const double direct_a = swap_out(eth_usdc_a, trade_eth);
const double direct_b = swap_out(eth_usdc_b, trade_eth);
const double routed = two_hop(eth_usdc_b, usdc_dai, trade_eth);
std::cout << std::fixed << std::setprecision(4);
std::cout << "Input: " << trade_eth << " ETH\n";
std::cout << "Direct via " << eth_usdc_a.name << ": " << direct_a << " USDC\n";
std::cout << "Direct via " << eth_usdc_b.name << ": " << direct_b << " USDC\n";
std::cout << "Two-hop via " << eth_usdc_b.name << " -> " << usdc_dai.name
<< ": " << routed << " DAI\n";
if (direct_b > direct_a) {
std::cout << "Best direct route: " << eth_usdc_b.name << "\n";
} else {
std::cout << "Best direct route: " << eth_usdc_a.name << "\n";
}
}
Construir
En Linux o macOS:
g++ -O2 -std=c++20 -o amm_router main.cpp
./amm_router
En Windows:
cl /O2 /std:c++20 main.cpp
.\main.exe
Por qué esto importa
Incluso este pequeño programa ya insinúa la forma real del trabajo DEX fuera de la cadena:
- evaluación de ruta repetida
- comparación con reconocimiento de tarifas
- salida dependiente del estado
- tensión constante entre corrección y velocidad
Amplíe esto a cientos de grupos, actualizaciones de estado frecuentes y presión de tiempo adversaria, y comenzará a ver por qué la elección del idioma deja de ser abstracta muy rápidamente.
Tareas de prueba para entusiastas
- Agregue tolerancia al deslizamiento y rechace rutas cuya salida efectiva caiga por debajo de un umbral configurado.
- Amplíe el programa para comparar cinco o diez grupos en lugar de dos y perfile dónde va el tiempo.
- Agregue un bucle que reevalúe la ruta un millón de veces con reservas ligeramente cambiantes y mida cómo un enrutador de "juguete" comienza a parecerse a un camino caliente real.
- Reemplace el formato de salida de punto flotante con registro numérico estructurado y observe cuánto trabajo "no matemático" aparece en torno a la lógica de ruta real.
- Agregue una segunda versión en Rust u otro idioma y compare no solo el tiempo de ejecución sin formato, sino también qué tan cómodo se siente el lenguaje una vez que el bucle de simulación se convierte en el centro del trabajo.
Este es un buen ejercicio porque revela algo sutil: en el software de intercambio, la dificultad interesante a menudo no reside en una única fórmula, sino en el uso repetido, con estado y sensible a la latencia de muchas fórmulas ordinarias a la vez.
Resumen
Tanto C++ como Rust pertenecen a la ingeniería de intercambio descentralizado, pero pertenecen allí por diferentes razones. Rust se gana la confianza en ecosistemas y capas donde la seguridad estatal, la auditabilidad y el flujo de trabajo nativo de la cadena son fundamentales. C++ gana confianza en capas donde el trabajo comienza a parecerse nuevamente a una infraestructura de intercambio: simulación repetida, procesamiento de datos de mercado, enrutamiento, búsqueda y otros sistemas de ruta activa que recompensan el control estricto sobre la memoria, la programación y la verificación del desempeño.
Por lo tanto, la pregunta más útil no es qué idioma gana todo el paquete. Se trata de qué capa estamos diseñando realmente y qué tipo de fallo esa capa menos puede permitirse. Una vez que se hace esa pregunta honestamente, la arquitectura suele volverse mucho más clara y el argumento se vuelve menos ideológico. Un DEX bien diseñado rara vez es un monumento a la pureza del lenguaje. Es una disposición práctica de componentes, cada uno escrito en el idioma que mejor respeta la carga que conlleva.
Referencias
- Documento técnico de Uniswap v3: https://uniswap.org/whitepaper-v3.pdf
- Repositorio principal de Uniswap v3: https://github.com/Uniswap/v3-core
- Documentación MEV de Ethereum.org: https://ethereum.org/developers/docs/mev/
- Descripción general de los programas Solana: https://solana.com/docs/core/programs
- Desarrollo del programa Solana Rust: https://solana.com/docs/programs/rust
- Documentación ancla: https://www.anchor-lang.com/docs
- Documentación de la cadena dYdX: https://docs.dydx.exchange/
- Documentación de integración dYdX: https://docs.dydx.xyz/
- dYdX en libros de pedidos fuera de la cadena con liquidación dentro de la cadena: https://integral.dydx.exchange/dydx-closes-10m-series-b-investment/
- Documentación del SDK de Cosmos: https://docs.cosmos.network/