Como fazer transações de ativos digitais com computação de várias partes e o Confidential Space

1. Visão geral

Antes de começarmos, embora não seja totalmente necessário, ter conhecimento prático dos recursos e conceitos a seguir será útil para este codelab.

4670cd5427aa39a6.png

O que você vai aprender

Este laboratório apresenta uma implementação de referência para realizar a assinatura de blockchain em conformidade com o MPC usando o Confidential Space. Para ilustrar os conceitos, vamos abordar um cenário em que a Empresa Primus quer transferir ativos digitais para a Company Secundus. Nesse cenário, a Empresa Primus usa um modelo compatível com MPC, o que significa que, em vez de usar chaves privadas individuais, ela usa compartilhamentos de chaves distribuídas. Esses compartilhamentos de chaves são detidos por várias partes, neste caso Alice e Bob. Essa abordagem oferece à Empresa Primus vários benefícios, incluindo experiência do usuário simplificada, eficiência operacional e controle sobre as chaves privadas.

Para explicar os aspectos fundamentais desse processo, vamos detalhar a configuração técnica e acompanhar o processo de aprovação e assinatura que inicia a transferência de ativos digitais da Company Primus para a Company Secundus. Bob e Alice, que são funcionários da Company Primus, precisam aprovar a transação.

Embora essa implementação de referência demonstre operações de assinatura, ela não abrange todos os aspectos do gerenciamento de chaves da MPC. Por exemplo, não vamos discutir a geração de chaves. Além disso, há abordagens alternativas e complementares, como usar serviços que não são do Google Cloud para gerar coassinaturas ou solicitar que co-assinantes construam assinaturas de blockchain nos próprios ambientes, o que é uma arquitetura mais descentralizada. Esperamos que este laboratório inspire diferentes abordagens em relação à MPC no Google Cloud.

Você vai trabalhar com uma carga de trabalho simples que assina uma transação do Ethereum no Confidential Space usando materiais de chave de co-signatário. A assinatura de transação do Ethereum é um processo em que um usuário pode autorizar uma transação no blockchain do Ethereum. Para enviar uma transação do Ethereum, você precisa assiná-la com sua chave privada. Isso prova que você é o proprietário da conta e autoriza a transação. O processo de assinatura é o seguinte:

  1. O remetente cria um objeto de transação que especifica o endereço do destinatário, a quantidade de ETH a ser enviada e outros dados relevantes.
  2. A chave privada do remetente é usada para gerar hash dos dados da transação.
  3. Depois, o hash é assinado com a chave privada.
  4. A assinatura é anexada ao objeto da transação.
  5. A transação é transmitida para a rede Ethereum.

Quando um nó da rede recebe uma transação, ele verifica a assinatura para ter certeza de que ela foi feita pelo proprietário da conta. Se a assinatura for válida, o nó vai adicionar a transação ao blockchain.

Para começar, você vai configurar os recursos necessários do Cloud. Depois, você vai executar a carga de trabalho no Confidential Space. Este codelab vai guiar você pelas seguintes etapas de alto nível:

  • Como configurar os recursos do Cloud necessários para executar o Confidential Space
  • Como autorizar o acesso a recursos protegidos com base nos atributos de:
  • O quê: o contêiner da carga de trabalho
  • Onde: no ambiente do Confidential Space (a imagem do Confidential Space na VM confidencial)
  • Quem: a conta que está executando a carga de trabalho
  • Como executar a carga de trabalho em uma VM confidencial executando a imagem da VM do Confidential Space

APIs necessárias

Você precisa ativar as seguintes APIs nos projetos especificados para concluir este guia.

Nome da API

Título da API

cloudkms.googleapis.com

Cloud KMS

compute.googleapis.com

Compute Engine

confidentialcomputing.googleapis.com

Computação confidencial

iamcredentials.googleapis.com

IAM

artifactregistry.googleapis.com

Artifact Registry

2. Configurar recursos na nuvem

Antes de começar

  • Clone este repositório com o comando abaixo para acessar os scripts necessários que são usados como parte deste codelab.
git clone https://github.com/GoogleCloudPlatform/confidential-space.git
  • Mude o diretório deste codelab.
cd confidential-space/codelabs/digital_asset_transaction_codelab/scripts
  • Verifique se você definiu as variáveis de ambiente do projeto necessárias, conforme mostrado abaixo. Para mais informações sobre como configurar um projeto do GCP, consulte este codelab. Consulte este link para ver detalhes sobre como recuperar o ID do projeto e como ele é diferente do nome e do número do projeto. .
export PRIMUS_PROJECT_ID=<GCP project id>
  • Ative o faturamento dos projetos.
  • Ativar a API Confidential Computing e as APIs seguintes nos dois projetos.
gcloud services enable \
   cloudapis.googleapis.com \
    cloudkms.googleapis.com \
    cloudresourcemanager.googleapis.com \
    cloudshell.googleapis.com \
    container.googleapis.com \
    containerregistry.googleapis.com \
    iam.googleapis.com \
    confidentialcomputing.googleapis.com
  • Para definir as variáveis dos nomes dos recursos, use o comando a seguir. Isso vai substituir os nomes dos recursos específicos do seu projeto do GCP para a empresa A, por exemplo, export PRIMUS_INPUT_STORAGE_BUCKET='primus-input-bucket'
  • As seguintes variáveis podem ser definidas para o projeto do GCP na Empresa A:

$PRIMUS_INPUT_STORAGE_BUCKET

O bucket que armazena as chaves criptografadas.

$PRIMUS_RESULT_STORAGE_BUCKET

O bucket que armazena o resultado da transação da MPC.

$PRIMUS_KEY

A chave do KMS usada para criptografar os dados armazenados em $PRIMUS_INPUT_STORAGE_BUCKET para o Primus Bank.

$PRIMUS_KEYRING

O keyring KMS que será usado para criar a chave de criptografia $PRIMUS_KEY para o Primus Bank.

$PRIMUS_WIP_PROVIDER

O provedor de pool de Identidade da carga de trabalho, que inclui a condição de atributo a ser usada para tokens assinados pelo serviço de carga de trabalho do MPC.

$PRIMUS_SERVICEACCOUNT

A conta de serviço que $PRIMUS_WORKLOAD_IDENTITY_POOL usa para acessar os recursos protegidos. Essa conta de serviço terá permissão para ver as chaves criptografadas que estão armazenadas no bucket $PRIMUS_INPUT_STORAGE_BUCKET.

$PRIMUS_ARTIFACT_REPOSITORY

O repositório de artefatos para armazenar a imagem do contêiner da carga de trabalho.

$WORKLOAD_SERVICEACCOUNT

A conta de serviço que tem permissão para acessar a VM confidencial que executa a carga de trabalho.

$WORKLOAD_CONTAINER

O contêiner do Docker que executa a carga de trabalho

$WORKLOAD_IMAGE_NAME

O nome da imagem do contêiner da carga de trabalho.

$WORKLOAD_IMAGE_TAG

A tag da imagem do contêiner da carga de trabalho.

  • Execute o script a seguir para definir os nomes de variáveis restantes como valores baseados no ID do projeto para nomes de recursos.
source config_env.sh

Configurar recursos do Cloud

Como parte desta etapa, você vai configurar os recursos de nuvem necessários para a computação de várias partes. Neste laboratório, você vai usar a seguinte chave privada: 0000000000000000000000000000000000000000000000000000000000000001

Em um ambiente de produção, você vai gerar sua própria chave privada. No entanto, para os fins deste laboratório, vamos dividir a chave privada em dois compartilhamentos e criptografar cada um deles. Em um cenário de produção, as chaves nunca devem ser armazenadas em arquivos de texto simples. Em vez disso, a chave privada pode ser gerada fora do Google Cloud (ou ignorada e substituída pela criação personalizada de fragmentos de chaves MPC) e depois criptografada para que ninguém tenha acesso à chave privada ou aos compartilhamentos de chaves. Para este laboratório, vamos usar a CLI gcloud.

Execute o script a seguir para configurar os recursos de nuvem necessários. Como parte dessas etapas, os recursos abaixo serão criados:

  • Um bucket do Cloud Storage ($PRIMUS_INPUT_STORAGE_BUCKET) para armazenar os compartilhamentos de chaves privadas criptografadas.
  • Um bucket do Cloud Storage ($PRIMUS_RESULT_STORAGE_BUCKET) para armazenar o resultado da transação do ativo digital.
  • Uma chave de criptografia ($PRIMUS_KEY) e um keyring ($PRIMUS_KEYRING) no KMS para criptografar os compartilhamentos de chaves privadas.
  • Um pool de identidades de carga de trabalho ($PRIMUS_WORKLOAD_IDENTITY_POOL) para validar declarações com base nas condições de atributos configuradas no provedor.
  • Uma conta de serviço ($PRIMUS_SERVICEACCOUNT) anexada ao pool de identidade da carga de trabalho ($PRIMUS_WORKLOAD_IDENTITY_POOL) mencionado acima com o seguinte acesso do IAM:
  • roles/cloudkms.cryptoKeyDecrypter para descriptografar os dados usando a chave KMS.
  • objectViewer para ler dados do bucket do Cloud Storage.
  • roles/iam.workloadIdentityUser para conectar essa conta de serviço ao pool de identidades da carga de trabalho.
./setup_resources.sh

3. Criar carga de trabalho

Criar conta de serviço da carga de trabalho

Agora você criará uma conta de serviço para a carga de trabalho com os papéis e permissões necessários. Para isso, execute o script a seguir, que vai criar uma conta de serviço de carga de trabalho para a Empresa A. Essa conta de serviço será usada pela VM que executa a carga de trabalho.

A conta de serviço da carga de trabalho ($WORKLOAD_SERVICEACCOUNT) terá os seguintes papéis:

  • confidentialcomputing.workloadUser para receber um token de atestado
  • logging.logWriter para gravar registros no Cloud Logging.
  • objectViewer para ler dados do bucket do Cloud Storage $PRIMUS_INPUT_STORAGE_BUCKET.
  • objectUser para gravar o resultado da carga de trabalho no bucket do Cloud Storage $PRIMUS_RESULT_STORAGE_BUCKET.
./create_workload_service_account.sh

Criar carga de trabalho

Esta etapa envolve a criação de uma imagem Docker de carga de trabalho. A carga de trabalho deste codelab é um aplicativo simples de MPC em Node.js que assina transações digitais para transferir recursos usando compartilhamentos de chaves privadas criptografadas. Confira aqui o código do projeto da carga de trabalho. O projeto de carga de trabalho inclui os arquivos a seguir.

package.json::esse arquivo contém a lista de pacotes que precisam ser usados para o aplicativo MPC de carga de trabalho. Neste caso, estamos usando as bibliotecas @google-cloud/kms, @google-cloud/storage, ethers e fast-crc32c. Aqui está o arquivo package.json que vamos usar para este codelab.

index.js::é um ponto de entrada do aplicativo de carga de trabalho e especifica quais comandos precisam ser executados quando o contêiner da carga de trabalho é iniciado. Também incluímos um exemplo de transação não assinada que normalmente é fornecida por um aplicativo não confiável que solicita a assinatura dos usuários. Esse arquivo index.js também importa funções de mpc.js, que serão criadas a seguir. Confira abaixo o conteúdo do arquivo index.js. Também é possível encontrá-lo aqui.

import {signTransaction, submitTransaction, uploadFromMemory} from './mpc.js';

const signAndSubmitTransaction = async () => {
  try {
    // Create the unsigned transaction object
    const unsignedTransaction = {
      nonce: 0,
      gasLimit: 21000,
      gasPrice: '0x09184e72a000',
      to: '0x0000000000000000000000000000000000000000',
      value: '0x00',
      data: '0x',
    };

    // Sign the transaction
    const signedTransaction = await signTransaction(unsignedTransaction);

    // Submit the transaction to Ganache
    const transaction = await submitTransaction(signedTransaction);

    // Write the transaction receipt
    uploadFromMemory(transaction);

    return transaction;
  } catch (e) {
    console.log(e);
    uploadFromMemory(e);
  }
};

await signAndSubmitTransaction();

mpc.js::é onde a assinatura da transação ocorre. Ela importa funções de kms-decrypt e credentials-config, que vamos abordar a seguir. Confira abaixo o conteúdo do arquivo mpc.js ou aqui.

import {Storage} from '@google-cloud/storage';
import {ethers} from 'ethers';

import {credentialConfig} from './credential-config.js';
import {decryptSymmetric} from './kms-decrypt.js';

const providers = ethers.providers;
const Wallet = ethers.Wallet;

// The ID of the GCS bucket holding the encrypted keys
const bucketName = process.env.KEY_BUCKET;

// Name of the encrypted key files.
const encryptedKeyFile1 = 'alice_encrypted_key_share';
const encryptedKeyFile2 = 'bob_encrypted_key_share';

// Create a new storage client with the credentials
const storageWithCreds = new Storage({
  credentials: credentialConfig,
});

// Create a new storage client without the credentials
const storage = new Storage();

const downloadIntoMemory = async (keyFile) => {
  // Downloads the file into a buffer in memory.
  const contents =
      await storageWithCreds.bucket(bucketName).file(keyFile).download();

  return contents;
};

const provider =
    new providers.JsonRpcProvider(`http://${process.env.NODE_URL}:80`);

export const signTransaction = async (unsignedTransaction) => {
  /* Check if Alice and Bob have both approved the transaction
  For this example, we're checking if their encrypted keys are available. */
  const encryptedKey1 =
      await downloadIntoMemory(encryptedKeyFile1).catch(console.error);
  const encryptedKey2 =
      await downloadIntoMemory(encryptedKeyFile2).catch(console.error);

  // For each key share, make a call to KMS to decrypt the key
  const privateKeyshare1 = await decryptSymmetric(encryptedKey1[0]);
  const privateKeyshare2 = await decryptSymmetric(encryptedKey2[0]);

  /* Perform the MPC calculations
  In this example, we're combining the private key shares
  Alternatively, you could import your mpc calculations here */
  const wallet = new Wallet(privateKeyshare1 + privateKeyshare2);

  // Sign the transaction
  const signedTransaction = await wallet.signTransaction(unsignedTransaction);

  return signedTransaction;
};

export const submitTransaction = async (signedTransaction) => {
  // This can now be sent to Ganache
  const hash = await provider.sendTransaction(signedTransaction);
  return hash;
};

export const uploadFromMemory = async (contents) => {
  // Upload the results to the bucket without service account impersonation
  await storage.bucket(process.env.RESULTS_BUCKET)
      .file('transaction_receipt_' + Date.now())
      .save(JSON.stringify(contents));
};

kms-decrypt.js: esse arquivo contém o código para descriptografia usando chaves gerenciadas no KMS. Confira abaixo o conteúdo do arquivo kms-decrypt.js ou aqui.

import {KeyManagementServiceClient} from '@google-cloud/kms';
import crc32c from 'fast-crc32c';

import {credentialConfig} from './credential-config.js';

const projectId = process.env.PRIMUS_PROJECT_ID;
const locationId = process.env.PRIMUS_LOCATION;
const keyRingId = process.env.PRIMUS_ENC_KEYRING;
const keyId = process.env.PRIMUS_ENC_KEY;

// Instantiates a client
const client = new KeyManagementServiceClient({
  credentials: credentialConfig,
});

// Build the key name
const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId);

export const decryptSymmetric = async (ciphertext) => {
  const ciphertextCrc32c = crc32c.calculate(ciphertext);
  const [decryptResponse] = await client.decrypt({
    name: keyName,
    ciphertext,
    ciphertextCrc32c: {
      value: ciphertextCrc32c,
    },
  });

  // Optional, but recommended: perform integrity verification on
  // decryptResponse. For more details on ensuring E2E in-transit integrity to
  // and from Cloud KMS visit:
  // https://cloud.google.com/kms/docs/data-integrity-guidelines
  if (crc32c.calculate(decryptResponse.plaintext) !==
      Number(decryptResponse.plaintextCrc32c.value)) {
    throw new Error('Decrypt: response corrupted in-transit');
  }

  const plaintext = decryptResponse.plaintext.toString();

  return plaintext;
};

credential-config.js::o arquivo armazena os caminhos do pool de identidades da carga de trabalho e os detalhes da representação da conta de serviço. Confira aqui o arquivo credentials-config.js que usaríamos para este codelab.

Dockerfile:por fim, vamos criar o Dockerfile, que será usado na criação da imagem Docker da carga de trabalho. define o Dockerfile, conforme especificado aqui.

FROM node:16.18.0

ENV NODE_ENV=production

WORKDIR /app

COPY ["package.json", "package-lock.json*", "./"]

RUN npm install --production

COPY . .

LABEL "tee.launch_policy.allow_cmd_override"="true"
LABEL "tee.launch_policy.allow_env_override"="NODE_URL,RESULTS_BUCKET,KEY_BUCKET,PRIMUS_PROJECT_NUMBER,PRIMUS_PROJECT_ID,PRIMUS_WORKLOAD_IDENTITY_POOL,PRIMUS_WIP_PROVIDER,PRIMUS_SERVICEACCOUNT,PRIMUS_ENC_KEYRING,PRIMUS_ENC_KEY"

CMD [ "node", "index.js" ]

Observação: LABEL "tee.launch_policy.allow_cmd_override"="true" no Dockerfile, há uma política de inicialização definida pelo autor da imagem. Permite que o operador substitua o CMD ao executar a carga de trabalho. Por padrão, allow_cmd_override é definido como falso. LABEL &quot;tee.launch_policy.allow_env_override&quot; informa ao Confidential Space quais variáveis de ambiente os usuários da imagem podem usar .

Execute o script a seguir para criar uma carga de trabalho em que as seguintes etapas estão sendo realizadas:

  • Crie o Artifact Registry($PRIMUS_ARTIFACT_REPOSITORY) para armazenar a imagem Docker da carga de trabalho.
  • Atualize o código da carga de trabalho com os nomes dos recursos obrigatórios. Confira aqui o código da carga de trabalho usado neste codelab.
  • Crie um Dockerfile para gerar uma imagem Docker do código de carga de trabalho. O Dockerfile está aqui.
  • Crie e publique a imagem Docker no Artifact Registry ($PRIMUS_ARTIFACT_REPOSITORY) criado na etapa anterior.
  • Conceder permissão de leitura a $WORKLOAD_SERVICEACCOUNT para $PRIMUS_ARTIFACT_REPOSITORY. Isso é necessário para que o contêiner da carga de trabalho extraia a imagem do Docker da carga de trabalho do Artifact Registry.
./create_workload.sh

Criar o nó da blockchain

Nó Ganache Ethereum

Antes de autorizar a carga de trabalho, precisamos criar a instância do Ethereum Ganache. A transação assinada seria enviada a esta instância do Ganache. Anote o endereço IP da instância. Depois de executar o comando abaixo, talvez seja necessário digitar y para ativar a API.

gcloud config set project $PRIMUS_PROJECT_ID
gcloud compute instances create-with-container mpc-lab-ethereum-node \
  --zone=${PRIMUS_PROJECT_ZONE}\
  --tags=http-server \
  --shielded-secure-boot \
  --shielded-vtpm \
  --shielded-integrity-monitoring \
  --container-image=docker.io/trufflesuite/ganache:v7.7.3 \
--container-arg=--wallet.accounts=\"0x0000000000000000000000000000000000000000000000000000000000000001,0x21E19E0C9BAB2400000\" \
  --container-arg=--port=80

4. Autorizar e executar carga de trabalho

Autorizar carga de trabalho

Como parte desta etapa, vamos configurar o provedor do pool de identidade da carga de trabalho no pool de identidade da carga de trabalho ($PRIMUS_WORKLOAD_IDENTITY_POOL). Há condições de atributo configuradas para a identidade da carga de trabalho, conforme mostrado abaixo. Uma das condições é validar se a imagem da carga de trabalho está sendo extraída do repositório de artefatos esperado.

gcloud config set project $PRIMUS_PROJECT_ID
gcloud iam workload-identity-pools providers create-oidc ${PRIMUS_WIP_PROVIDER} \
 --location="${PRIMUS_PROJECT_LOCATION}" \
 --workload-identity-pool="$PRIMUS_WORKLOAD_IDENTITY_POOL" \
 --issuer-uri="https://confidentialcomputing.googleapis.com/" \
 --allowed-audiences="https://sts.googleapis.com" \
 --attribute-mapping="google.subject='assertion.sub'" \
 --attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE' && 'STABLE' in assertion.submods.confidential_space.support_attributes && assertion.submods.container.image_reference == '${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG' && '$WORKLOAD_SERVICEACCOUNT@$PRIMUS_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts"

Executar carga de trabalho

Nesta seção, explicamos como executar a carga de trabalho em VMs confidenciais. Para isso, vamos transmitir os argumentos TEE necessários usando a flag de metadados. Além disso, definiremos variáveis de ambiente para o contêiner de carga de trabalho usando "tee-env-*" . A imagem tem as seguintes variáveis:

  • NODE_URL: o URL do nó do Ethereum que processará a transação assinada.
  • RESULTS_BUCKET: o bucket que armazena o resultado da transação de MPC.
  • KEY_BUCKET: o bucket que armazena as chaves criptografadas de MPC.
  • PRIMUS_PROJECT_NUMBER: o número do projeto usado no arquivo de configuração de credenciais.
  • PRIMUS_PROJECT_ID: o ID do projeto usado no arquivo de configuração de credenciais. O resultado da execução da carga de trabalho será publicado em $PRIMUS_RESULT_STORAGE_BUCKET.
  • PRIMUS_WORKLOAD_IDENTITY_POOL: o pool de identidades de carga de trabalho usado para validar declarações.
  • PRIMUS_WIP_POROVIDER: o provedor do pool de identidades da carga de trabalho que inclui as condições do atributo a serem usadas para validar os tokens apresentados pela carga de trabalho.
  • WORKLOAD_SERVICEACCOUNT: a conta de serviço da carga de trabalho.
gcloud config set project $PRIMUS_PROJECT_ID
gcloud compute instances create $WORKLOAD_VM \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=TERMINATE \
 --scopes=cloud-platform \
 --zone=${PRIMUS_PROJECT_ZONE} \
 --image-project=confidential-space-images \
 --image-family=confidential-space \
 --service-account=$WORKLOAD_SERVICEACCOUNT@$PRIMUS_PROJECT_ID.iam.gserviceaccount.com \
 --metadata "^~^tee-image-reference=${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG~tee-restart-policy=Never~tee-env-NODE_URL=$(gcloud compute instances describe mpc-lab-ethereum-node --format='get(networkInterfaces[0].networkIP)' --zone=${PRIMUS_PROJECT_ZONE})~tee-env-RESULTS_BUCKET=$PRIMUS_RESULT_STORAGE_BUCKET~tee-env-KEY_BUCKET=$PRIMUS_INPUT_STORAGE_BUCKET~tee-env-PRIMUS_PROJECT_ID=$PRIMUS_PROJECT_ID~tee-env-PRIMUS_PROJECT_NUMBER=$(gcloud projects describe $PRIMUS_PROJECT_ID --format="value(projectNumber)")~tee-env-PRIMUS_WORKLOAD_IDENTITY_POOL=$PRIMUS_WORKLOAD_IDENTITY_POOL~tee-env-PRIMUS_PROJECT_LOCATION=${PRIMUS_PROJECT_LOCATION}~tee-env-PRIMUS_WIP_PROVIDER=$PRIMUS_WIP_PROVIDER~tee-env-PRIMUS_SERVICEACCOUNT=$PRIMUS_SERVICEACCOUNT~tee-env-PRIMUS_KEY=${PRIMUS_KEY}~tee-env-PRIMUS_KEYRING=${PRIMUS_KEYRING}"

Verifique os resultados do Cloud Storage

É possível visualizar o comprovante da transação no Cloud Storage. Pode levar alguns minutos para o Confidential Space ser inicializado e para os resultados aparecerem. Você vai saber que o contêiner foi concluído quando a VM estiver no estado interrompido.

  1. Acesse a página Navegador do Cloud Storage.
  2. Clique em $PRIMUS_RESULT_STORAGE_BUCKET.
  3. Clique no arquivo transaction_receipt.
  4. Clique em "Fazer download" para fazer o download e conferir a resposta da transação.

Observação:se os resultados não estiverem aparecendo, acesse $WORKLOAD_VM na página do console do Cloud do Compute Engine e clique em "Porta serial 1 (console)" para acessar os registros.

Verificar a transação do Ganache Blockchain

Também é possível conferir a transação no registro do blockchain.

  1. Acesse a página do Cloud Compute Engine.
  2. Clique no mpc-lab-ethereum-node VM.
  3. Clique em SSH para abrir a janela de SSH no navegador.
  4. Na janela SSH, digite sudo docker ps para ver o contêiner do Ganache em execução.
  5. Encontre o ID do contêiner para trufflesuite/ganache:v7.7.3.
  6. Insira sudo docker logs CONTAINER_ID, substituindo CONTAINER_ID pelo ID de trufflesuite/ganache:v7.7.3.
  7. Veja os registros do Ganache e confirme se há uma transação listada nos registros.

5. Limpar

Confira aqui o script que pode ser usado para limpar os recursos criados neste codelab. Como parte dessa limpeza, os seguintes recursos serão excluídos:

  • Bucket de armazenamento de entrada usado para armazenar compartilhamentos de chaves criptografados ($PRIMUS_INPUT_STORAGE_BUCKET).
  • Chave de criptografia e keyring ($PRIMUS_KEY e $PRIMUS_KEYRING).
  • Conta de serviço usada para acessar recursos protegidos ($PRIMUS_SERVICEACCOUNT).
  • Pool de Identidade da carga de trabalho ($PRIMUS_WORKLOAD_IDENTITY_POOL).
  • Conta de serviço da carga de trabalho ($WORKLOAD_SERVICEACCOUNT).
  • Instâncias de computação da carga de trabalho.
  • Bucket de armazenamento de resultados usado para armazenar o resultado da transação.($PRIMUS_RESULT_STORAGE_BUCKET).
  • Artifact Registry usado para armazenar imagem da carga de trabalho ($PRIMUS_ARTIFACT_REPOSITORY).
./cleanup.sh

Quando terminar de explorar, considere excluir seu projeto.

  • Acesse o console do Cloud Platform.
  • Selecione o projeto que você quer encerrar e clique em "Excluir" na parte superior. Isso programa a exclusão do projeto.

Qual é a próxima etapa?

Confira alguns destes codelabs parecidos:

Leia mais