Tarifas, límites de recursos y medición
Resumen de tarifas
Stellar requiere una tarifa por todas las transacciones para que lleguen al ledger. Esto ayuda a prevenir spam y prioriza las transacciones durante picos de tráfico. Todas las tarifas se pagan utilizando el token nativo de Stellar, el lumen (o XLM).
Hay dos tipos de tarifas en Stellar:
Tarifa de recursos: aplica sólo a transacciones de contratos inteligentes. La cantidad que el remitente debe pagar por su transacción para ser ejecutada. Esta cantidad se basa en el consumo de recursos de una transacción y el estado del almacenamiento de la red (descrito en la sección de precios dinámicos para almacenamiento). Lee sobre las tarifas de recursos a continuación.
Tarifa de inclusión: el máximo que el remitente está dispuesto a pagar para que la transacción sea incluida en el ledger. Lee más a continuación.
Al competir por espacio en el ledger, las transacciones de contratos inteligentes sólo compiten con otras transacciones de contratos inteligentes, y las transacciones que no ejecutan un contrato inteligente sólo compiten con otras transacciones que no ejecutan un contrato inteligente.
Los lumens recolectados de las tarifas de transacción van a una cuenta bloqueada y no se entregan ni utilizan por nadie.
Tarifa de recursos
Todas las transacciones de contratos inteligentes requieren una tarifa de recursos además de una tarifa de inclusión:
Tarifa de Transacción (Tx.fee) = Tarifa de Recursos (sorobanData.resourceFee) + Tarifa de Inclusión
* Diagrama: Los cuadros de línea sólida son lo que realmente está presente en la transacción, mientras que las líneas punteadas son derivables.
Los contratos inteligentes en Stellar utilizan un modelo de tarifa de recursos multidimensional que cobra tarifas por varios tipos de recursos utilizando tarifas definidas por la red. La tarifa de recursos se calcula en función del consumo de recursos declarado en la transacción y puede fluctuar según una tarifa de escritura de almacenamiento mutable (más sobre eso en la sección de precios dinámicos para almacenamiento a continuación). Si la transacción intenta exceder los límites de recursos declarados, fallará. Si la transacción utiliza menos recursos de los declarados, no habrá reembolsos (con un par de excepciones).
La tarifa de recursos depende de los siguientes recursos:
- Instrucciones: el número de instrucciones CPU que utiliza la transacción, medida por el entorno host;
- Accesos a entradas del ledger: leer o escribir cualquier entrada de ledger única (cualquier clave de almacenamiento en el contexto del contrato);
- I/O del ledger: el número de bytes leídos o escritos en el ledger;
- Tamaño de la transacción: el tamaño de la transacción enviada a la red en bytes;
- Tamaño de eventos y retorno de valor: el tamaño de los eventos producidos por el contrato y el valor de retorno de la función del contrato de nivel superior — tanto los eventos como el valor de retorno se incluyen en los metadatos de la transacción;
- Alquiler del espacio del ledger: el pago por las extensiones TTL de entradas del ledger (es decir, pagos de alquiler) y pagos de alquiler por aumentar el tamaño de la entrada del ledger. Consulta la sección archivamiento de estado para más información sobre el alquiler de contratos inteligentes.
Los detalles de implementación para el cálculo de tarifas son proporcionados por la siguiente biblioteca. Esta biblioteca es utilizada por el protocolo para calcular las tarifas y, por lo tanto, puede considerarse canónica. Las tarifas de recursos pueden ser actualizadas basadas en el consenso de los validadores de la red. Por ejemplo, el tamaño de la transacción se cobra por la propagación de la red (ya que el ancho de banda de la red es limitado) y por el almacenamiento histórico (ya que almacenar el historial del ledger no es gratis).
Los detalles de implementación para el cálculo de tarifas son proporcionados por la siguiente biblioteca. Esta biblioteca es utilizada por el protocolo para calcular las tarifas y, por lo tanto, puede considerarse canónica. Las tarifas de recursos pueden ser actualizadas en base al consenso de los validadores de la red.
Encuentra las tarifas de recursos actuales en la página de Límites y Tarifas de Recursos en la sección de Redes.
Para ayuda en el análisis de costos y eficiencia de contratos inteligentes, consulta esta Guía Práctica.
Tarifas de recursos reembolsables y no reembolsables
La tarifa de recursos se calcula con una porción de tarifas no reembolsables y una porción de tarifas reembolsables: ResourceFee(sorobanData.resourceFee) = Tarifa de recursos no reembolsable + Tarifas de recursos reembolsables
.
Tarifas no reembolsables: calculadas a partir de instrucciones CPU, bytes leídos, bytes escritos y ancho de banda (tamaño de la transacción, incluyendo sus firmas).
Tarifas reembolsables: calculadas a partir de alquiler, eventos y valor de retorno. Las tarifas reembolsables se cargan desde la cuenta fuente antes de que se ejecute la transacción y luego se reembolsan en función del uso real. Sin embargo, la transacción fallará si refundableFee
no es suficiente para cubrir el uso real de recursos. Las tarifas reembolsables se cobran de la cuenta de origen antes de que se ejecute la transacción y luego se reembolsan según el uso real. Sin embargo, la transacción fallará si refundableFee
no es suficiente para cubrir el uso real de recursos.
Encuentra la tarifa de recursos de una transacción
La mejor manera de encontrar la tarifa de recursos requerida para cualquier transacción de contrato inteligente es usar el simulateTransaction
endpoint del RPC, que te permite enviar una transacción de pre-vuelo que devolverá los valores de recursos necesarios y la tarifa de recursos.
Limitaciones de recursos
Sólo las transacciones de contratos inteligentes están sujetas a limitaciones de recursos.
El tiempo de cierre del ledger de Stellar está limitado a unos pocos segundos, impidiendo la ejecución de transacciones arbitrariamente grandes, independientemente de las tarifas de recursos involucradas. Todos los recursos mencionados en la sección anterior están sujetos a un límite por transacción. La memoria (RAM) de una transacción también está limitada, aunque no está sujeta a ningún cargo.
Los límites de recursos son determinados por una votación de validadores y pueden ser ajustados según el uso de la red y las necesidades del ecosistema con un consenso de validadores.
Encuentra los límites de recursos actuales en la página de Límites y Tarifas de Recursos en la sección de Redes.
Tarifa de inclusión
La tarifa de inclusión es la máxima oferta (una oferta denota una tarifa dinámica, lo que significa que varía según ciertas condiciones de la red) que el remitente está dispuesto a pagar para que la transacción sea incluida en el ledger. La tarifa de inclusión es igual al número de operaciones en la transacción multiplicado por la tarifa base efectiva para el ledger dado: tarifa de inclusión = # de operaciones * tarifa base efectiva
Tarifa base efectiva: la tarifa requerida por operación para que una transacción llegue al ledger. Esto no puede ser menor de 100 stroops por operación (el mínimo de la red). Esto no puede ser inferior a 100 stroops por operación (el mínimo de la red).
Stroop: la unidad más pequeña de un lumen, una diez millonésima parte de un lumen (.0000001 XLM).
Las transacciones pueden tener hasta 100 operaciones por transacción excepto para las transacciones que ejecutan un contrato inteligente. Las transacciones de contratos inteligentes sólo pueden tener una operación por transacción (a menos que la transacción esté siendo incrementada de tarifas; esto añadiría otra operación), y los límites se especifican en instrucciones CPU y otros límites de recursos.
Cuando estableces una tarifa base para una transacción, estás especificando el máximo que estás dispuesto a pagar por operación en esa transacción. Esto no significa necesariamente que pagarás esa cantidad. Sólo se te cobrará la menor cantidad necesaria para que tu transacción llegue al ledger. Si el tráfico de la red es ligero y el número de operaciones o transacciones enviadas está por debajo del límite del ledger de la red (configurado por los validadores: actualmente 1,000 operaciones que no son de contrato inteligente y 100 transacciones de contratos inteligentes), sólo pagarás el mínimo de la red (configurado por los validadores, actualmente 100 stroops).
Alternativamente, tu transacción puede no llegar al ledger si la tarifa base efectiva es mayor que tu oferta de tarifa base. Cuando el tráfico de la red supera el límite del ledger, la red entra en modo de precios de picos, y tu tarifa base efectiva se convierte en tu oferta máxima.
Las tarifas se deducen de la cuenta fuente a menos que haya una transacción de incremento de tarifas que indique lo contrario. Descubre sobre las transacciones de incremento de tarifas en la sección de transacciones de aumento de tarifas.
Precios de picos y dinámicos
Precios de picos
La red puede entrar en modo de precios de picos bajo dos circunstancias: 1. cuando el número de operaciones sometidas a un ledger excede la capacidad de la red (1,000 operaciones para transacciones que no ejecutan contratos inteligentes), o 1. si hay competencia entre transacciones de contratos inteligentes por un recurso particular (instrucciones, accesos a entradas del ledger (lecturas y escrituras), I/O del ledger (bytes leídos y bytes escritos), y el tamaño total de las transacciones a aplicar). Durante este tiempo, la red utiliza dinámicas de mercado para decidir qué transacciones incluir en el ledger. Durante el modo de precios de picos, las transacciones se ordenan según su monto de tarifa de inclusión, y el usuario paga la tarifa de inclusión mínima en su conjunto de transacciones.
Durante el modo de precios de picos, las transacciones se ordenan según la cantidad de su tarifa de inclusión, y el usuario paga la tarifa de inclusión mínima en su conjunto de transacciones. Por ejemplo, si hay cinco transacciones con tarifas de inclusión respectivas de 2, 3, 4, 4 y 5 XLM, y sólo cuatro de ellas pueden llegar al ledger, entonces todas las transacciones incluidas pagan la tarifa de inclusión de 3 XLM. Si las cinco transacciones pueden llegar al ledger (lo que significaría que la red no está en modo de precios de picos), cada una pagaría la tarifa de inclusión mínima de 100 stroops (.0001 XLM).
Si hay múltiples transacciones ofreciendo la misma tarifa de inclusión, pero no pueden todas caber en el ledger, las transacciones se eligen al azar para que el total de operaciones para el conjunto completo no exceda 1,000. Las demás transacciones se empujan al siguiente ledger o se descartan si han estado esperando demasiado tiempo. Si tu transacción es descartada, Horizon devolverá un error de timeout.
Se recomienda aplicar límites de ledger o límites de tiempo a las transacciones — ya sea que tu transacción llegue al ledger o falle, dependiendo de tus parámetros de tiempo y/o ledger.
Es más probable que pagues una tarifa de inclusión más alta al enviar transacciones de contratos inteligentes. Las transacciones de contratos inteligentes tienen límites de ledger más estrictos que las transacciones que no interactúan con contratos inteligentes y, por lo tanto, experimentarán precios de picos más a menudo. Es más probable que pagues tu oferta máxima de tarifa de inclusión o, al menos, la oferta mínima de tarifa de inclusión en tu conjunto de transacciones. Por lo tanto, debes planear tu estrategia de oferta de tarifas en consecuencia.
Precios dinámicos para almacenamiento
El tamaño de la base de datos de almacenamiento de Stellar está determinado por dos fuerzas: la tasa de adiciones (escrituras) y la tasa de eliminaciones (desalojos). Stellar ha establecido un umbral de crecimiento del ledger a un valor constante (el parámetro de red BucketListTargetSizeBytes
, implementado para prevenir el crecimiento explosivo de estado y sujeto a cambios basado en la votación de validadores). Debido a que hay una capacidad fija, las tarifas de escritura se basan en el tamaño del ledger y pueden cambiar dinámicamente según ese tamaño.
Cuando el tamaño del ledger es grande, hay una mayor demanda de espacio de almacenamiento, lo que provoca una mayor tarifa de escritura. Con el tiempo, las entradas se archivan, reduciendo el tamaño total del ledger y, por ende, reduciendo el precio de almacenamiento. Este modelo de tarifas está diseñado como si el tamaño de la base de datos representara la demanda actual de almacenamiento en cualquier instante dado.
Las tarifas de escritura crecerán gradualmente con el tiempo cuando el tamaño de la base de datos esté por debajo del umbral de crecimiento del ledger y crecerán linealmente, pero con un factor de 1,000x después de superar ese umbral. Esto es una salvaguarda contra el spam y no se anticipa en circunstancias normales.
Medición
La medición es un mecanismo en el entorno host que contabiliza los costos de recursos incurridos durante la ejecución de un contrato inteligente. Los resultados de la medición actúan como la verdad canónica del costo de ejecución de un contrato inteligente y sirven como entrada para los cálculos de tarifas.
El entorno de ejecución de contratos inteligentes de Stellar comprende un host y un invitado. El host encapsula funcionalidades compartidas para todos los contratos, incluyendo objetos del host, funciones y un intérprete de Wasm (VM). El entorno del invitado es donde se interpreta y ejecuta el contrato Wasm compilado. Una discusión detallada de estos entornos se puede encontrar en Conceptos del Entorno.
La división entre los entornos host y del invitado y sus funcionalidades compartidas requiere un enfoque único para la contabilidad de recursos. En particular, los recursos requeridos para ejecutar instrucciones Wasm y ejecutar funciones del host deben contabilizarse uniformemente, con costos en términos de instrucciones CPU y bytes de memoria.
Considera dos contratos: A y B, ambos que comprenden el mismo número de instrucciones Wasm. Si el Contrato A llama repetidamente a funciones del host para cálculos complejos mientras que el Contrato B ejecuta operaciones aritméticas puras dentro de la VM, el Contrato A debería ser más costoso, y esta diferencia debería ser representada con precisión en el proceso de medición.
La medición asegura equidad, impide la manipulación de recursos y ataques, y genera una medida determinista y reproducible de los costos de recursos en tiempo de ejecución.
Metodología
Para mantener la equivalencia en la medición entre el host y el invitado, los costos de computación en ambos lados se expresan en términos de instrucciones CPU y bytes de memoria (representando el uso de CPU y RAM). La medición y la verificación de límites ocurren dentro del entorno host, y modelos numéricos pre-calibrados aseguran que los resultados sean deterministas.
Tipos de costo
La medición se segmenta en componentes del host, conocidos como tipos de costo. Cada tipo de costo se puede ver como una “meta instrucción” que simboliza una operación específica del host con una complejidad conocida que depende de una entrada en tiempo de ejecución. Por ejemplo, el tipo de costo ComputeSha256Hash
representa el costo de calcular el hash SHA256 de un array de bytes.
La ejecución de instrucciones Wasm se contabiliza como un tipo de costo del host WasmInsnExec
, que tiene un costo CPU constante por instrucción Wasm. Esta metodología trata las instrucciones del invitado y las ejecuciones del host de manera equivalente.
Encuentra una lista completa de tipos de costo del host y sus definiciones aquí: ContractCostType
.
Parámetros de costo
Los tipos de costo son cuidadosamente seleccionados para:
- Servir como bloques de construcción integrales para todos los costos significativos de ejecución de contratos;
- Asegurar que cada costo componente incremente como máximo linealmente (es decir, constante o lineal) con respecto a su entrada. Es decir,
y = a + bx
, dondey
es la salida de costo,x
es la entrada, ya
yb
son los parámetros del modelo constante y lineal, respectivamente.
Cada tipo de costo tiene un modelo separado para ambos tipos de recursos (CPU y memoria).
Los parámetros para cada modelo, a
y b
, son calibrados y ajustados fuera de línea contra entradas de varios tamaños. La colección de todos los parámetros de costo de modelo de las entradas configurables de la red (ver ConfigSettingsEntry
puede actualizarse a través del consenso de la red.
Proceso de medición
Antes de la ejecución del contrato, el entorno host se prepara con los parámetros de costo y un presupuesto que define los límites de recursos. La medición se implementa entonces para medir el consumo acumulado de recursos durante la ejecución del host.
Durante la ejecución, cada vez que se encuentra un componente (un bloque de código que define un tipo de costo), el modelo correspondiente calcula la salida de recursos a partir de la entrada en tiempo de ejecución y aumenta el medidor en consecuencia. El medidor verifica el consumo acumulativo contra el límite del presupuesto. Si se supera el límite, se produce un error y la ejecución se termina.
Si la ejecución del contrato concluye dentro de los límites de recursos especificados, el total medido de instrucciones CPU se registra y se utiliza como entrada para el cálculo de tarifas. Mientras que el uso de memoria no se incluye en el cálculo de tarifas, sigue estando sujeto a los límites de recursos.
Estrategias de precios de tarifas de inclusión
Durante las últimas tres horas, se pueden ver a continuación las estadísticas de tarifas de inclusión en la red Mainnet.
Hay dos métodos principales para tratar las fluctuaciones de tarifas de inclusión y precios de picos:
- Método 1: establece la tarifa más alta que estés dispuesto a pagar. Esto no significa que pagarás esa cantidad en cada transacción — solo pagarás lo que sea necesario para entrar en el ledger. En circunstancias normales (no de picos), solo pagarás la tarifa estándar incluso con una tarifa máxima más alta establecida. Este método es simple, conveniente y eficiente, pero aún puede fallar.
- Método 2: reenvía una transacción con una tarifa más alta usando una transacción de aumento de tarifas
Establece la tarifa más alta que estés dispuesto a pagar
En general, es una buena idea elegir la tarifa más alta que estás dispuesto a pagar por operación para que tu transacción llegue al ledger. Los desarrolladores de billeteras pueden querer ofrecer a los usuarios la oportunidad de especificar su propia tarifa base, aunque puede tener más sentido establecer una tarifa base global persistente que esté por encima de la tarifa de mercado, ya que el usuario promedio probablemente no se preocupe si está pagando 0.8 céntimos o 0.00008 céntimos.
Recuerda que es más probable que pagues tu oferta máxima de tarifa con transacciones de contratos inteligentes.
Aumentos de tarifas en transacciones pasadas
Incluso con una política liberal de pago de tarifas, tu transacción puede fallar al llegar al ledger debido a fondos insuficientes o aumentos de tarifas intempestivos. Las transacciones de aumento de tarifas pueden resolver este problema. El siguiente fragmento te muestra cómo reenviar una transacción con una tarifa más alta (siempre que tengas el sobre de transacción original):
- JavaScript
// Let `lastTx` be some transaction that fails submission due to high fees, and
// `lastFee` be the maximum fee (expressed as an int) willing to be paid by
// `account` for `lastTx`.
server.submitTransaction(lastTx).catch(function (error) {
if (isFeeError(error)) {
let bump = sdk.TransactionBuilder.buildFeeBumpTransaction(
account, // account that will PAY the new fee
lastFee * 10, // new fee
lastTx, // the (entire) failing transaction
server.networkPassphrase
);
bump.sign(someAccount);
return server.submitTransaction(bump);
}
// ...other error conditions...
}).then(...);
Supón que envías dos transacciones distintas con la misma cuenta fuente y número de secuencia; la segunda transacción es una transacción de aumento de tarifas. En ese caso, la segunda transacción será incluida en la cola de transacciones, reemplazando la primera transacción si y solo si la oferta de tarifa de la segunda transacción es al menos 10 veces la oferta de tarifa de la primera transacción.
Este valor se puede encontrar típicamente en el campo fee_charged
de la respuesta de la transacción bajo el caso de error tx_insufficient_fee
.