Referencia

Verificar la disponibilidad de datos en Ethereum

Para verificar la disponibilidad de datos en Ethereum, primero es necesario enviar datos a Avail como una transacción de envío de datos. Los datos enviados de esta manera se incluirán en los bloques de disponibilidad, pero no se interpretarán ni ejecutarán de ninguna manera. El envío se puede realizar utilizando Polkadot-JSuna colección de herramientas para la comunicación con cadenas basadas en Substrate (que ahora forma parte del SDK de Polkadot).

El ejemplo completo se puede encontrar en github.(se abre en una nueva pestaña).

Ejemplo de envío de datos a Avail:

async function submitData(availApi, data, account) {  let submit = await availApi.tx.dataAvailability.submitData(data);  return await sendTx(availApi, account, submit);}

La función submitDatarecibe availApila instancia de API, dataque se enviará y accountque envía la transacción. Para crear una cuenta es necesario crear un par de llaveros para la cuenta que desea enviar los datos. Esto se puede hacer con lo que crea un par de llaveros mediante suri (el secreto puede ser una cadena hexadecimal, una frase mnemotécnica o una cadena). Después de crear un par de llaveros, es posible enviar datos en una transacción a la red Avail con . Una vez que la transacción se incluye en un bloque de disponibilidad, es posible iniciar el envío de la raíz de datos creando una transacción de envío con los parámetros:keyring.addFromUri(secret)availApi.tx.dataAvailability.submitData(data);availApi.tx.daBridge.tryDispatchDataRoot(destinationDomain, bridgeRouterEthAddress, header);

destinationDomainDominio de destino 1000.

bridgeRouterEthAddressDirección del contrato principal de enrutador de disponibilidad de datos implementado en la red Sepolia para Goldberg ( 0x305222c4DdB86FfA9fa9Aa0A479705577E3c4d33), para Kate 0xbD824890A51ed8bda53F51F27303b14EFfEbC152.

headerProporcionado desde el bloque cuando se envían los datos.

async function dispatchDataRoot(availApi, blockHash, account) {  const header = await availApi.rpc.chain.getHeader(blockHash);  let tx = await availApi.tx.daBridge.tryDispatchDataRoot(    process.env.DESTINATION_DOMAIN,    process.env.DA_BRIDGE_ADDRESS,    header,  );  return await sendTx(availApi, account, tx);}

Ejemplo de envío de datos a Avail y envío de la raíz de datos mediante Polkadot-JS.

Variables de entorno:

AVAIL_RPC= # avail network websocket urlSURI= # mnemonicDA_BRIDGE_ADDRESS= # main da bridge contract address deployed to Sepolia test network in format (Kate) 0x000000000000000000000000bD824890A51ed8bda53F51F27303b14EFfEbC152 (Goldberg) 0x000000000000000000000000305222c4DdB86FfA9fa9Aa0A479705577E3c4d33DESTINATION_DOMAIN= # destination domain is 1000DATA= # data sending to avail
Ejemplo de JavaScript raíz de datos de envío
import { ApiPromise, Keyring, WsProvider } from '@polkadot/api';import * as dotenv from 'dotenv'; dotenv.config(); /** * Creates api instance. * * @param url websocket address */async function createApi(url) {  const provider = new WsProvider(url);  return ApiPromise.create({    provider,    rpc: {      kate: {        queryDataProof: {          description: 'Generate the data proof for the given `index`',          params: [            {              name: 'transaction_index',              type: 'u32',            },            {              name: 'at',              type: 'Hash',              isOptional: true,            },          ],          type: 'DataProof',        },      },    },    types: {      AppId: 'Compact<u32>',      DataLookupIndexItem: {        appId: 'AppId',        start: 'Compact<u32>',      },      DataLookup: {        size: 'Compact<u32>',        index: 'Vec<DataLookupIndexItem>',      },      KateCommitment: {        rows: 'Compact<u16>',        cols: 'Compact<u16>',        dataRoot: 'H256',        commitment: 'Vec<u8>',      },      V1HeaderExtension: {        commitment: 'KateCommitment',        appLookup: 'DataLookup',      },      VTHeaderExtension: {        newField: 'Vec<u8>',        commitment: 'KateCommitment',        appLookup: 'DataLookup',      },      HeaderExtension: {        _enum: {          V1: 'V1HeaderExtension',          VTest: 'VTHeaderExtension',        },      },      DaHeader: {        parentHash: 'Hash',        number: 'Compact<BlockNumber>',        stateRoot: 'Hash',        extrinsicsRoot: 'Hash',        digest: 'Digest',        extension: 'HeaderExtension',      },      Header: 'DaHeader',      CheckAppIdExtra: {        appId: 'AppId',      },      CheckAppIdTypes: {},      CheckAppId: {        extra: 'CheckAppIdExtra',        types: 'CheckAppIdTypes',      },      DataProof: {        root: 'H256',        proof: 'Vec<H256>',        numberOfLeaves: 'Compact<u32>',        leafIndex: 'Compact<u32>',        leaf: 'H256',      },      Cell: {        row: 'u32',        col: 'u32',      },    },    signedExtensions: {      CheckAppId: {        extrinsic: {          appId: 'AppId',        },        payload: {},      },    },  });} /** * Sends transaction to Avail. * * @param api instance of the api * @param account sending the transaction * @param tx transaction */async function sendTx(api, account, tx) {  return new Promise(async (resolve) => {    try {      const res = await tx.signAndSend(account, (result) => {        if (result.status.isReady) {          console.log(`Txn has been sent to the mempool`);        }        if (result.status.isInBlock) {          console.log(            `Tx hash: ${result.txHash} is in block ${result.status.asInBlock}`,          );          res();          resolve(result);        }      });    } catch (e) {      console.log(e);      process.exit(1);    }  });} /** * Submitting data to Avail as a transaction. * * @param availApi api instance * @param data payload to send * @param account that is sending transaction * @returns {Promise<unknown>} */async function submitData(availApi, data, account) {  let submit = await availApi.tx.dataAvailability.submitData(data);  return await sendTx(availApi, account, submit);} /** * Sending dispatch data root transaction. * * @param availApi api instance * @param blockHash hash of the block * @param account sending transaction * @returns {Promise<unknown>} */async function dispatchDataRoot(availApi, blockHash, account) {  const destinationDomain = process.env.DESTINATION_DOMAIN;  const bridgeRouterEthAddress = process.env.DA_BRIDGE_ADDRESS;  const header = await availApi.rpc.chain.getHeader(blockHash);  console.log(`Block Number: ${header.number}`);  console.log(`State Root: ${header.stateRoot}`);  let tx = await availApi.tx.daBridge.tryDispatchDataRoot(    destinationDomain,    bridgeRouterEthAddress,    header,  );  return await sendTx(availApi, account, tx);} /** * Returns data root for the particular block. * * @param availApi api instance * @param blockHash hash of the block * @returns {Promise<(*)[]>} */async function getDataRoot(availApi, blockHash) {  const header = JSON.parse(await availApi.rpc.chain.getHeader(blockHash));  return [header.extension.v1.commitment.dataRoot, header.number];} (async function dataRootDispatch() {  const availApi = await createApi(process.env.AVAIL_RPC);  const keyring = new Keyring({ type: 'sr25519' });  const account = keyring.addFromMnemonic(process.env.SURI);  console.log('Submitting data to Avail...');   let result = await submitData(availApi, process.env.DATA, account);  const txIndex = JSON.parse(result.events[0].phase).applyExtrinsic;  const blockHash = result.status.asInBlock;  console.log(    `Transaction: ${result.txHash}. Block hash: ${blockHash}. Transaction index: ${txIndex}.`,  );   console.log('Triggering Home...');  result = await dispatchDataRoot(availApi, blockHash, account);  console.log(`Sent txn on Avail. Txn Hash: ${result.txHash}.`);  let [root, blockNum] = await getDataRoot(availApi, blockHash);  console.log('Data Root:' + root + ' and Block number: ' + blockNum);   await availApi.disconnect();})()  .then(() => {    console.log('Done');  })  .catch((err) => {    console.error(err);    process.exit(1);  });

El envío de la raíz de datos activará un puente optimista que conectará la raíz de datos con la red Ethereum. Dado que el puente es optimista, es necesario esperar 30 minutos antes de que la raíz de datos esté disponible en Ethereum.

Después de conectar con éxito la raíz de datos con el contrato principal de certificación de disponibilidad de datos en Ethereum, es posible demostrar que los datos están disponibles en la red Avail enviando una prueba Merkle al contrato de verificación. La obtención de pruebas de Avail se puede realizar mediante una llamada RPC, kate_queryDataProofpor ejemplo, availApi.rpc.kate.queryDataProof(transactionIndex, hashBlock); dónde transactionIndexestá el índice de la transacción en el bloque y hashBlockcuál es un hash del bloque en el que se incluyen los datos. Este punto final RPC devuelve DataProofun objeto que se puede utilizar para demostrar en Ethereum que los datos están disponibles en la red Avail. Ejemplo:

Datos devueltos:

rootHash de raíz del árbol merkle generado.

proofArtículos a prueba de Merkle (no contiene el hash de hoja ni la raíz).

numberOfLeavesNúmero de hojas del árbol original.

leafIndexÍndice de la hoja para la que es la prueba (comienza desde 0).

leafHoja de la cual es la prueba.

EJEMPLO

Ejemplo de contrato de verificación

Al presentar prueba al contrato de verificación es posible verificar que los datos están disponibles en Avail. La prueba de Merkle es una lista de hashes que se pueden usar para demostrar que una hoja determinada es miembro del árbol de Merkle. Se puede consultar un ejemplo de envío de una prueba al contrato de verificación implementado en la red Sepolia para Kate ( 0xA06386C65B1f56De57CE6aB9CeEB2552fa811529) y Goldberg ( 0x67044689F7e274a4aC7b818FDea64Cb4604c6875) llamando a la función de membresía raíz de datos async function checkProof(sepoliaApi, blockNumber, proof, numberOfLeaves, leafIndex, leafHash);donde

sepoliaApiInstancia de API de red Sepolia.

blockNumberNúmero de bloque de disponibilidad.

proofPrueba de Merkle para la hoja.

numberOfLeavesNúmero de hojas del árbol original.

leafIndexÍndice de la hoja del árbol Merkle.

leafHashHachís de la hoja del árbol Merkle.

Esto llamará a la función de los contratos implementados verificationContract.checkDataRootMembership(blockNumber, proof, numberOfLeaves, leafIndex, leafHash) y devolverá trueo falsedependiendo de la prueba proporcionada.

EJEMPLO DE OBTENER LA PRUEBA Y VERIFICARLA CON EL CONTRATO DE VERIFICACIÓN UTILIZANDO POLKADOT-JSY ETHERS.JS. Variables de entorno:

Enviar ejemplo de prueba

Last updated