Esta página discutirá el formato de transacción en Polkadot y cómo crear, firmar y emitir transacciones. Como las otras páginas de esta guía, esta página demuestra algunas de las herramientas disponibles. Consulta siempre la documentación de cada herramienta cuando se integre.
Formato de transacción #
Polkadot tiene cierta información básica sobre transacciones que es común a todas las transacciones.
- Address (Dirección): La address codificada SS58 de la cuenta remitente.
- Block Hash (Hash del bloque): El hash del bloque checkpoint (control).
- Block Number (Número de bloque): El número del bloque checkpoint.
- Genesis Hash (Hash génesis): El hash génesis de la cadena.
- Metadata (metadatos): Los metadatos codificados en SCALE para el runtime cuando se envía.
- Nonce: El nonce para esta transacción.*
- Spec Version: La versión actual de las especificaciones del runtime.
- Transaction Version: (Versión de transacción): La versión actual para el formato de transacción.
- Tip: Opcional, el tip (propina) para aumentar la prioridad de la transacción.
- Era Period: Opcional, el número de bloques después del checkpoint para el que una transacción es válida. Si es cero, la transacción es inmortal.
PRECAUCIÓN
Hay riesgos al hacer una transacción inmortal. Si una cuenta es cosechada y un usuario vuelve a poner fondos en la cuenta, entonces podrían reproducir una transacción inmortal. Utiliza siempre por defecto un extrinsic mortal.
*El nonce consultado desde el módulo System no tiene en cuenta las transacciones pendientes. Debes realizar un seguimiento e incrementar el nonce manualmente si quieres enviar varias transacciones válidas al mismo tiempo.
Cada transacción tendrá sus propios parámetros (o ninguno) que añadir. Por ejemplo, la función transferKeepAlive
del pallet Balances tomará:
dest:
Address de destino#[compact] value:
Número de tokens (codificación compacta)
Formato de transacción serializada #
Antes de ser enviadas, las transacciones se serializan. Las transacciones serializadas son bytes codificados con codificación hexadecimal SCALE. Los runtimes Polkadot son actualizables y por lo tanto cualquier interfaz está sujeta a cambios, los metadatos permiten a los desarrolladores estructurar cualquier extrinsic o entradas de almacenamiento en consecuencia. Dicho esto, el formato de serialización puede describirse como sigue:
- Número codificado compacto de bytes codificados SCALE siguiendo esto.
- 1 bit: es un 0 si no hay firma, o un 1 si la hay.
- 7 bits: la versión extrínseca, es igual a 4 en decimal.
- 4 bytes: La versión Spec del runtime.
- 4 bytes: Versión de transacción del runtime.
- 32 bytes: Hash Génesis de la cadena.
- 32 bytes: Hash del bloque que sirve como referencia de la era. Si la transacción es inmortal, este sería el hash génesis.
- Si hay firma:
- un
sp_runtime::MultiAddress::Id<AccountId32, u32>
codificado en SCALE que indica el firmante o firmantes de la transacción. - un
sp_runtime::MultiSignature::{SigningScheme}
con la firma*. - un
sp_runtime::generic::Era
codificado en SCALE indicando el tiempo de validez de la transacción:- Si la transacción es inmortal, la Era sería simplemente 0.
- En caso contrario, sería un Vec[u64, u64] compuesto por el periodo y la fase.
- Compacto codificado
u32
con el nonce. - Compact codificado
u128
con el tip pagado al productor del bloque. - un SCALE codificado
sp_runtime::traits::SignedExtension<Vec<Text>>
con los datos adicionales y la lógica asociada a esta transacción.
- un
- Los parámetros específicos de la transacción o datos de llamada, que consisten en:
- 1 byte: el índice del pallet a la que llama la transacción.
- 1 byte: la función en el pallet a la que llama la transacción.
- variable: los parámetros codificados en SCALE requeridos por la función a la que se llama.
Los metadatos te proporcionan toda la información necesaria para saber cómo construir los datos de llamada serializados específicos de tu transacción. Puedes leer más sobre los metadatos, su formato y cómo obtenerlos en la documentación de Substrate.
- Polkadot soporta sr25519, ed25519, y ECDSA como esquemas de firma.
Resumen #
Una vez que tengas toda la información necesaria, necesitarás:
- Construir una transacción sin firmar.
- Crear un payload de firma.
- Firmar el payload.
- Serializar el payload firmado en una transacción.
- Enviar la transacción serializada.
Parity proporciona las siguientes herramientas para ayudar a realizar estos pasos.
Herramientas Polkadot-JS #
Polkadot-JS Tools contiene un conjunto de herramientas de línea de comandos para interactuar con un cliente Substrate, incluyendo una llamada “Signer CLI” para crear, firmar y transmitir transacciones.
Este ejemplo utilizará el comando signer submit
, que creará y enviará la transacción. El comando signer sendOffline
tiene exactamente la misma API, pero no transmitirá la transacción. submit
y sendOffline
deben estar conectados a un nodo para obtener los metadatos actuales y construir una transacción válida. Su API tiene el formato:
yarn
run:signer <submit|sendOffline> –account <from-account-ss58> –ws <endpoint> <module.method> [param1] […] [paramX]
Firma:
yarn run:signer sign --account <from-account-ss58> --seed <seed> --type <sr25519|ed25519> <payload>
Por ejemplo, enviemos 0,5 DOT de 121X5bEgTZcGQx5NZjwuTjqqKoiG8B2wEAvrUFjuw24ZGZf2
a 15vrtLsCQFG3qRYUcaEeeih4JwepocNJHkpsrqojqnZPc2y
.
yarn run:signer submit --account 121X5bEgTZcGQx5NZjwuTjqqKoiG8B2wEAvrUFjuw24ZGZf2 --ws ws://127.0.0.1:9944 balances.transferKeepAlive 15vrtLsCQFG3qRYUcaEeeEih4JwepocNJHkpsrqojqnZPc2y 5000000000
Esto devolverá un payload para firmar y un input en espera de firma. Toma este payload y utiliza tu entorno de firma normal (por ejemplo, una gapped machine, una VM, etc.). Firma el payload:
yarn run:signer sign --account 121X5bEgTZcGQx5NZjwuTjqqKoiG8B2wEAvrUFjuw24ZGZf2 --seed "pulp gaze fuel ... mercy inherit equal" --type sr25519 0x040300ff4a83f1...a8239139ff3ff7c3f6
Guarda el output y llévalo a la máquina desde la que emitirás, introdúcelo en el campo de firma submit y envía la transacción (o simplemente devuelve la transacción serializada si utilizas sendOffline).
Tx wrapper #
Si no quieres utilizar la CLI para las operaciones de firma, Parity proporciona un SDK llamado TxWrapper Core para generar y firmar transacciones offline. Para Polkadot, Kusama, y parachains selectas, utiliza el paquete txwrapper-polkadot
. Otras cadenas basadas en Substrate tendrán sus propias implementaciones de txwrapper-{chain}
. Consulta los ejemplos para obtener una guía.
Importar una clave privada #
import { importPrivateKey } from '@substrate/txwrapper-polkadot';
const keypair = importPrivateKey(“pulp gaze fuel ... mercy inherit equal”);
Derivar una address desde una clave pública #
import { deriveAddress } from '@substrate/txwrapper-polkadot';
// Public key, can be either hex string, or Uint8Array
const publicKey = “0x2ca17d26ca376087dc30ed52deb74bf0f64aca96fe78b05ec3e720a72adb1235”;
const address = deriveAddress(publicKey);
Construir una transacción offline #
import { methods } from "@substrate/txwrapper-polkadot";
const unsigned = methods.balances.transferKeepAlive(
{
dest: "15vrtLsCQFG3qRYUcaEeeEih4JwepocNJHkpsrqojqnZPc2y",
value: 5000000000,
},
{
address: "121X5bEgTZcGQx5NZjwuTjqqKoiG8B2wEAvrUFjuw24ZGZf2",
blockHash: "0x1fc7493f3c1e9ac758a183839906475f8363aafb1b1d3e910fe16fab4ae1b582",
blockNumber: 4302222,
genesisHash: "0xe3777fa922cafbff200cadeaea1a76bd7898ad5b89f7848999058b50e715f636",
metadataRpc, // must import from client RPC call state_getMetadata
nonce: 2,
specVersion: 1019,
tip: 0,
eraPeriod: 64, // number of blocks from checkpoint that transaction is valid
transactionVersion: 1,
},
{
metadataRpc,
registry, // Type registry
}
);
Construir un payload de firma #
mport { methods, createSigningPayload } from ‘@substrate/txwrapper-polkadot’;
// See “Construct a transaction offline” for “{…}”
const unsigned = methods.balances.transferKeepAlive({…}, {…}, {…});
const signingPayload = createSigningPayload(unsigned, { registry });
Serializar una transacción firmada #
import { createSignedTx } from "@substrate/txwrapper-polkadot";
// Example code, replace `signWithAlice` with actual remote signer.
// An example is given here:
// https://github.com/paritytech/txwrapper-core/blob/b213cabf50f18f0fe710817072a81596e1a53cae/packages/txwrapper-core/src/test-helpers/signWithAlice.ts
const signature = await signWithAlice(signingPayload);
const signedTx = createSignedTx(unsigned, signature, { metadataRpc, registry });
Decodificar los tipos de payload #
Puedes querer decodificar los payloads para verificar su contenido antes de la presentación.
import { decode } from "@substrate/txwrapper-polkadot";
// Decode an unsigned tx
const txInfo = decode(unsigned, { metadataRpc, registry });
// Decode a signing payload
const txInfo = decode(signingPayload, { metadataRpc, registry });
// Decode a signed tx
const txInfo = decode(signedTx, { metadataRpc, registry });
Comprobar el hash de la transacción #
import { getTxHash } from ‘@substrate/txwrapper-polkadot’;
const txHash = getTxHash(signedTx);
Enviar un payload firmado #
Hay varias formas de enviar un payload firmado:
- Signer CLI (
yarn run:signer submit --tx <signed-transaction> --ws <endpoint>
) - Substrate API Sidecar
- RPC con
author_submitExtrinsic
oauthor_submitAndWatchExtrinsic
, el último de los cuales te suscribirá a eventos para ser notificado cuando una transacción se valide y se incluya en la cadena.
Notas #
Algunos addresses para usar en los ejemplos. Mira Subkey documentation.
$ subkey --network polkadot generate
Secret phrase `pulp gaze fuel ... mercy inherit equal` is account:
Secret seed: 0x57450b3e09ba4598 ... ... ... ... ... ... ... .. 219756eeba80bb16
Public key (hex): 0x2ca17d26ca376087dc30ed52deb74bf0f64aca96fe78b05ec3e720a72adb1235
Account ID: 0x2ca17d26ca376087dc30ed52deb74bf0f64aca96fe78b05ec3e720a72adb1235
SS58 Address: 121X5bEgTZcGQx5NZjwuTjqqKoiG8B2wEAvrUFjuw24ZGZf2
$ subkey --network polkadot generate
Secret phrase `exercise auction soft ... obey control easily` is account:
Secret seed: 0x5f4bbb9fbb69261a ... ... ... ... ... ... ... .. 4691ed7d1130fbbd
Public key (hex): 0xda04de6cd781c98acf0693dfb97c11011938ad22fcc476ed0089ac5aec3fe243
Account ID: 0xda04de6cd781c98acf0693dfb97c11011938ad22fcc476ed0089ac5aec3fe243
SS58 Address: 15vrtLsCQFG3qRYUcaEeeEih4JwepocNJHkpsrqojqnZPc2y