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çar, embora não seja totalmente necessário, um conhecimento prático dos recursos e conceitos a seguir será útil neste codelab.

4670cd5427aa39a6.png

O que você vai aprender

Este laboratório fornece uma implementação de referência para realizar a assinatura de blockchain compatível com MPC usando o Espaço confidencial. Para ilustrar os conceitos, vamos abordar um cenário em que a Empresa Primus quer transferir recursos digitais para a Empresa 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ídos. Essas ações são mantidas por várias partes, neste caso, Alice e Bob. Essa abordagem oferece à Company 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 orientar você pelo processo de aprovação e assinatura que inicia a transferência de recursos digitais da Empresa Primus para a Empresa Secundus. Bob e Alice, que são funcionários da empresa 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 de MPC. Por exemplo, não abordamos a geração de chaves. Além disso, existem abordagens alternativas e complementares, como usar serviços que não são do Google Cloud para gerar coassinaturas ou fazer com que os coassinantes construam assinaturas de blockchain nos próprios ambientes, o que é uma arquitetura mais descentralizada. Esperamos que este laboratório inspire diferentes abordagens para 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 chaves de coassinatura. A assinatura de transações do Ethereum é um processo pelo qual um usuário pode autorizar uma transação na 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 um hash dos dados da transação.
  3. 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ó na rede recebe uma transação, ele verifica a assinatura para garantir que ela foi assinada pelo proprietário da conta. Se a assinatura for válida, o nó vai adicionar a transação à blockchain.

Para começar, configure os recursos do Cloud necessários. Em seguida, você vai executar a carga de trabalho no Confidential Space. Este codelab vai orientar você nas seguintes etapas gerais:

  • Como configurar os recursos do Cloud necessários para executar o Espaço confidencial
  • Como autorizar o acesso a recursos protegidos com base nos atributos de:
  • O quê: o contêiner de carga de trabalho
  • Onde: o 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 que executa 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 do Cloud

Antes de começar

  • Clone este repositório usando o comando abaixo para receber 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 para este 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 saber 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.
  • Ative a API Confidential Computing e as APIs a seguir para os 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 de recursos, use o comando abaixo. Isso vai substituir os nomes de recursos específicos do seu projeto do GCP para a empresa A, por exemplo, export PRIMUS_INPUT_STORAGE_BUCKET='primus-input-bucket'
  • As variáveis a seguir 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 do 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 do KMS que será usado para criar a chave de criptografia $PRIMUS_KEY para o Primus Bank.

$PRIMUS_WIP_PROVIDER

O provedor de pool de identidades 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_SERVICE_ACCOUNT

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 visualizar as chaves criptografadas 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 abaixo para definir os nomes das variáveis restantes como valores com base no ID do projeto para nomes de recursos.
source config_env.sh

Configurar recursos do Cloud

Nesta 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 essa chave privada em duas partes e criptografar cada uma delas. 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 totalmente ignorada e substituída pela criação personalizada de fragmentos de chaves MPC) e, em seguida, criptografada para que ninguém tenha acesso à chave privada ou aos fragmentos de chave. Para este laboratório, vamos usar a CLI gcloud.

Execute o script abaixo 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 as partes criptografadas da chave privada.
  • Um bucket do Cloud Storage ($PRIMUS_RESULT_STORAGE_BUCKET) para armazenar o resultado da transação de recursos digitais.
  • Uma chave de criptografia ($PRIMUS_KEY) e um chaveiro ($PRIMUS_KEYRING) no KMS para criptografar as partes compartilhadas da chave privada.
  • Um pool de identidade da 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 do KMS.
  • objectViewer para ler dados do bucket do Cloud Storage.
  • roles/iam.workloadIdentityUser para conectar essa conta de serviço ao pool de identidade da carga de trabalho.
./setup_resources.sh

3. Criar carga de trabalho

Criar uma conta de serviço de carga de trabalho

Agora você vai criar uma conta de serviço para a carga de trabalho com as funções e permissões necessárias. Para fazer isso, execute o script abaixo, 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 $PRIMUS_INPUT_STORAGE_BUCKET do Cloud Storage.
  • objectUser para gravar o resultado da carga de trabalho no bucket $PRIMUS_RESULT_STORAGE_BUCKET do Cloud Storage.
./create_workload_service_account.sh

Criar carga de trabalho

Nesta etapa, você vai criar uma imagem Docker de carga de trabalho. A carga de trabalho neste codelab é um aplicativo MPC simples do Node.js que assina transações digitais para transferir ativos usando compartilhamentos de chaves privadas criptografadas. Este é o código do projeto de carga de trabalho. O projeto de carga de trabalho inclui os seguintes arquivos.

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

index.js::é um ponto de entrada do aplicativo de carga de trabalho e especifica quais comandos devem ser executados quando o contêiner de carga de trabalho for iniciado. Também incluímos uma transação não assinada de exemplo que normalmente seria fornecida por um app não confiável que pede a assinatura dos usuários. Esse arquivo index.js também importa funções do mpc.js, que vamos criar em seguida. Confira abaixo o conteúdo do arquivo index.js. Você também pode acessá-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::é aqui que a assinatura da transação acontece. Ele importa funções de kms-decrypt e credential-config, que serão abordados a seguir. Confira abaixo o conteúdo do arquivo mpc.js. Você também pode acessá-lo 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:este arquivo contém o código para a descriptografia usando chaves gerenciadas no KMS. Confira abaixo o conteúdo do arquivo kms-decrypt.js. Também é possível encontrá-lo 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 identidade da carga de trabalho e os detalhes da falsificação de identidade da conta de serviço. Este é o arquivo credential-config.js que usaremos neste codelab.

Dockerfile:por fim, vamos criar o Dockerfile que será usado para criar a imagem do Docker de carga de trabalho. O Dockerfile é definido 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 é uma política de inicialização definida pelo autor da imagem. Ele permite que o operador substitua o CMD ao executar a carga de trabalho. Por padrão, a opção "allow_cmd_override" é definida como "false". O LABEL "tee.launch_policy.allow_env_override" informa ao Confidential Space quais variáveis de ambiente os usuários da imagem podem usar .

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

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

Criar o nó de blockchain

Nó do Ethereum do Ganache

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

gcloud compute instances create-with-container ${ETHEREUM_NODE} \
  --zone=${PRIMUS_PROJECT_ZONE} \
  --tags=http-server \
  --project=${PRIMUS_PROJECT_ID} \
  --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 a carga de trabalho

Autorizar a carga de trabalho

Nesta etapa, vamos configurar o provedor do pool de identidades da carga de trabalho no pool de identidades 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

Esta seção explica como executar a carga de trabalho na VM confidencial. Para isso, vamos transmitir os argumentos necessários do TEE usando a flag de metadados. Além disso, vamos definir variáveis de ambiente para o contêiner de carga de trabalho usando a flag "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 mpc.
  • KEY_BUCKET: o bucket que armazena as chaves criptografadas do MPC.
  • PRIMUS_PROJECT_NUMBER: o número do projeto usado para o arquivo de configuração da credencial.
  • PRIMUS_PROJECT_ID: o ID do projeto usado para o arquivo de configuração da credencial. O resultado da execução da carga de trabalho será publicado em $PRIMUS_RESULT_STORAGE_BUCKET.
  • PRIMUS_WORKLOAD_IDENTITY_POOL: o pool de identidade da carga de trabalho usado para validar declarações.
  • PRIMUS_WIP_POROVIDER: o provedor do pool de Identidade da carga de trabalho, que inclui as condições de 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 compute instances create $WORKLOAD_VM \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=TERMINATE \
 --scopes=cloud-platform \
 --zone=${PRIMUS_PROJECT_ZONE} \
 --project=${PRIMUS_PROJECT_ID} \
 --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 ${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}"

Verificar os resultados do Cloud Storage

É possível conferir o recibo da transação no Cloud Storage. Pode levar alguns minutos para que o Espaço confidencial seja inicializado e os resultados apareçam. 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 o download" para fazer o download e conferir a resposta da transação.

Como alternativa, execute os comandos a seguir para conferir o resultado.

gcloud config set project $PRIMUS_PROJECT_ID
gsutil cat gs://$PRIMUS_RESULT_STORAGE_BUCKET/transaction_receipt

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

Verificar a transação da blockchain Ganache

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

  1. Acesse a página Cloud Compute Engine.
  2. Clique em ${ETHEREUM_NODE} VM.
  3. Clique em SSH para abrir a janela SSH no navegador.
  4. Na janela do SSH, digite sudo docker ps para conferir 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. Confira os registros do Ganache e confirme se há uma transação listada neles.

5. Limpar

Este é o script que pode ser usado para limpar os recursos criados como parte deste codelab. Como parte dessa limpeza, os seguintes recursos serão excluídos:

  • Bucket de armazenamento de entrada usado para armazenar compartilhamentos de chaves criptografadas ($PRIMUS_INPUT_STORAGE_BUCKET).
  • Chave de criptografia ($PRIMUS_KEY).
  • 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 de carga de trabalho ($WORKLOAD_SERVICEACCOUNT).
  • Instâncias de computação de carga de trabalho ($WORKLOAD_VM e $ETHEREUM_NODE).
  • Bucket de armazenamento de resultados usado para armazenar o resultado da transação ($PRIMUS_RESULT_STORAGE_BUCKET).
  • Registro de artefato usado para armazenar a imagem da carga de trabalho ($PRIMUS_ARTIFACT_REPOSITORY).
./cleanup.sh

Se você já tiver terminado 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 de cima. Isso programa o projeto para exclusão.

Qual é a próxima etapa?

Confira alguns desses codelabs semelhantes:

Leia mais