Una transacción generalmente representa una unidad de trabajo dentro de un sistema de base de datos. En el caso de blockchain, eso ocurre cuando una acción firmada por una cuenta cambia su estado.
Bitxor admite muchos tipos de transacción diferentes. Por ejemplo, existen transacciones para transferir tokens entre cuentas, mensajes o configurar la propiedad de cuentas (incluyendo el uso de reglas de multifirma), entre otras.
Los siguientes tipos de transacción están incluidos por defecto en las redes basadas en Bitxor:
Cada tipo de transacción base disponible en Bitxor se define como un plugin separado. El enfoque de plugins permite a los desarrolladores introducir nuevos tipos de transacción sin modificar el motor principal ni afectar otras características.
Las transacciones se definen en una forma serializada. Cada transacción extiende el esquema base “Transaction�? agregando las propiedades particulares del tipo.
Todas las transacciones deben definir una fecha límite (deadline) y una comisión máxima (max_fee):
deadline
: Una transacción tiene una ventana de tiempo para ser aceptada antes de alcanzar su fecha límite. La transacción expira cuando se alcanza la fecha límite y todos los nodos rechazan la transacción. Por defecto, el SDK establece la fecha límite en 2 horas, pero puede extenderse hasta 6 horas (o 48 horas para transacciones Agregado Enlazado).
max_fee
: La cantidad máxima de moneda de la red que el remitente de la transacción está dispuesto a pagar para que la transacción sea aceptada. La siguiente documentación te muestra cómo configurar el valor óptimo de max_fee.
Note
El repositorio catbuffer schemas define cómo se deben serializar cada tipo de transacción. En combinación con los generadores de catbuffer, los desarrolladores pueden generar clases de construcción para un conjunto determinado de lenguajes de programación.
Recomendamos utilizar el SDK para definir nuevas transacciones.
// replace with recipient address
const rawAddress = 'BXRQ5E-YACWBP-CXKGIL-I6XWCH-DRFLTB-KUK34I-YJQ';
const recipientAddress = Address.createFromRawAddress(rawAddress);
const transferTransaction = TransferTransaction.create(
Deadline.create(epochAdjustment),
recipientAddress,
[currency.createRelative(10)],
PlainMessage.create('This is a test message'),
networkType,
UInt64.fromUint(2000000),
);
Las cuentas deben firmar transacciones antes de anunciarlas a la red. La firma de una transacción expresa el acuerdo de la cuenta para cambiar el estado de la red según lo definido.
Por ejemplo, TransferTransaction describe quién es el destinatario y la cantidad de tokens que se transferirán. En este caso, firmar la transacción significa aceptar mover esos tokens del saldo de una cuenta a otra.
Una cuenta debe seguir los siguientes pasos para [firmar una transacción](https://github.com/bitxorcorp/bitxor-sdk-typescript-javascript/blob/main/src/model/transaction/Transaction.ts#L216):
Obtener los “bytes para firmar�? que son todos los bytes de la transacción excepto el tamaño, la firma y el firmante.
Obtener el “hash de generación del bloque génesis�? Puedes consultar la URL del nodo /node/info y copiar el valor de meta.networkGenerationHash.
Preceder el hash de generación del bloque génesis a los bytes para firmar.
Firmar la cadena resultante con la clave privada del firmante. Esto te dará la “firma de la transacción�?
Añadir la firma y la clave pública del firmante a la transacción para obtener el “payload�?
Calcular el [hash de la transacción](https://github.com/bitxorcorp/bitxor-sdk-typescript-javascript/blob/main/src/model/transaction/Transaction.ts#L127) aplicando el algoritmo de hash SHA3-512 a los primeros 32 bytes de la firma, la clave pública del firmante, el hash de generación del bloque génesis y el resto del payload de la transacción.
Las transacciones firmadas están listas para ser anunciadas a la red.
Puedes usar el SDK TransactionHttp
servicio o agregar la carga útil a la solicitud del transaction endpoint.
const transactionRepository = repositoryFactory.createTransactionRepository();
const response = await transactionRepository
.announce(signedTransaction)
.toPromise();
console.log(response);
curl -X PUT -H "Content-type: application/json" -d '{"payload":"B3000000F77A8DCFCB57B81F9BE5B46738F7132998F55123BFF4D89DC8E5CAE1F071A040E5571F4D8DA125B243C785DA5261F878E3DE898815F6E8F12A2C0A5F0A9C3504FA6249E8334E3F83E972461125504AFFD3E7750AFBB3371E7B2D22A599A3D0E3039054410000000000000000265DEE3F1700000090FA39EC47E05600AFA74308A7EA607D145E371B5F4F1447BC0F00010057656C636F6D6520546F204E454D44B262C46CEABB858096980000000000"}' http://localhost:3000/transaction
Después de anunciar la transacción, la API REST siempre devolverá una respuesta OK inmediatamente. En este punto, aún se desconoce si la transacción es válida.
La primera etapa de validación ocurre en los nodos de la API. Si la transacción encuentra un error, el WebSocket envía una notificación a través del canal de estado. Si no hay errores, la transacción llega a la red P2P con un estado no confirmado. En este estado, aún no está claro si la transacción será incluida en un bloque. Por lo tanto, nunca se debe confiar en una transacción no confirmada.
La segunda validación ocurre antes de que la transacción se agregue en un bloque cosechado. Si tiene éxito, el cosechador almacena la transacción en un bloque y la transacción alcanza el estado confirmado. En este estado, la transacción se registra oficialmente en el libro mayor de la cadena de bloques, pero aún no ha alcanzado la finalización.
Bajo ciertas circunstancias, como una falla o partición de la red, los bloques confirmados más recientes pueden ser revertidos. Por lo tanto, las transacciones confirmadas que no han sido finalizadas son reconocidas por la red, pero no son inmutables, ya que aún pueden revertirse.
Para que un bloque sea inmutable, debe completar el proceso de finalización. Una vez que un bloque se finaliza, tanto el bloque como las transacciones incluidas se registran permanentemente en el libro mayor de la cadena de bloques.
La caché del nodo almacena transacciones no confirmadas hasta que puedan incluirse en un bloque. Dado que la caché es un recurso valioso, Bitxor implementa un control de spam que evita que un atacante llene la caché con transacciones no confirmadas, al tiempo que permite que los actores honestos envíen con éxito nuevas transacciones no confirmadas.
El control de spam controla la cantidad de transacciones no confirmadas que las cuentas pueden enviar calculando la cuota justa de caché para cada cuenta en relación con su puntuación de importancia. Si una cuenta ha superado su cuota justa de caché y la caché del nodo contiene más transacciones no confirmadas que la cantidad que se puede incluir en un solo bloque, la transacción será rechazada. Esto bloquea efectivamente a los actores maliciosos de inundar un nodo con transacciones, al tiempo que permite que otros usuarios continúen utilizando el nodo normalmente.
Convirtiendo el anuncio de transacción asincrónica en sincrónica
Fragmento útil para anunciar una transacción y esperar hasta que se confirme.