Faça Atualizações Atômicas em Chaincodes e Canais

Você pode usar transações atômicas para concluir várias transações entre canais e códigos de cadeia de maneira atômica.

Uma transação atômica é uma série indivisível de operações de dados que são bem-sucedidas ou nenhuma é bem-sucedida.

As transações atômicas podem ser úteis em situações complexas em que vários códigos de cadeia são implantados em canais separados. Você pode usar transações atômicas para manter a consistência dos dados ao executar várias transações blockchain, mesmo que ocorra uma falha na rede ou no sistema. O Oracle Blockchain Platform suporta transações atômicas usando o protocolo de commit de duas fases, em que uma fase inicial em que cada operação de dados é preparada é seguida por uma fase em que cada operação de dados é realmente confirmada.

As transações atômicas funcionam no nível do aplicativo. Normalmente, você não precisa alterar a lógica de chaincode existente para suportar transações atômicas. Como um ou mais argumentos adicionais são adicionados pela estrutura de transações atômicas, certifique-se de que qualquer chaincode existente não execute verificações rigorosas sobre o número de argumentos passados no método chaincode. As transações atômicas são suportadas pelo seguinte ponto final da API REST:
  • restproxy/api/v2/atomicTransactions
O ponto final da API REST prepara as transações conforme definido pelo seu chaincode e, em seguida, usa funções de chaincode incorporadas para confirmar todas as transações ou reverter todas as transações se houver erros durante a fase de preparação. Para obter mais informações sobre os pontos finais REST a serem usados para implementar transações atômicas, consulte Pontos Finais REST de Transações Atômicas.

Cada transação atômica é composta por duas ou mais transações blockchain. O resultado (o valor returnCode) da transação atômica é Success ou Failure. Em uma transação atômica, cada transação de blockchain solicitada é dividida em duas operações distintas: uma fase de preparação e, em seguida, uma fase de commit ou de rollback.

  • Na fase de preparação, cada transação é endossada normalmente, mas em vez de ser finalizada, as alterações são preparadas e os valores são bloqueados para evitar que outras transações modifiquem os valores preparados.
  • Se a fase de preparação for bem-sucedida para cada transação de blockchain, as transações serão endossadas e confirmadas usando o chaincode integrado. Os valores bloqueados anteriormente são desbloqueados e o resultado da transação atômica é Success.
  • Se a fase de preparação falhar para qualquer transação blockchain, todas as outras transações em que a fase de preparação foi bem-sucedida serão revertidas, novamente usando o chaincode incorporado. As alterações preparadas são removidas e os valores bloqueados anteriormente são desbloqueados. O resultado da transação atômica é Failure.
Como as transações atômicas funcionam bloqueando chaves, você poderá receber um erro Two_Phase_Commit_Lock se outras transações tentarem modificar uma chave bloqueada por uma transação atômica atualmente ativa preparada. Isso pode ocorrer em um dos dois cenários a seguir:
  • Uma transação atômica ainda está na fase preparada, e outra transação tenta modificar uma chave que foi bloqueada pela transação preparada. Nesse caso, o sistema está funcionando conforme projetado. Se você encontrar esse erro, repita a segunda transação. Isso é análogo a como os aplicativos lidam com erros de leitura fantasma ou erros de controle de simultaneidade de várias versões (MVCC).
  • O valor GlobalStatus retornado pela transação atômica é HeuristicOutcome. Nesse caso, uma operação de transação atômica foi cancelada porque uma das operações de commit falhou. Esta é uma ocorrência rara e pode precisar ser resolvida manualmente. Um efeito colateral de um resultado heurístico é que algumas chaves podem ser deixadas bloqueadas por transações que não foram submetidas a commit ou a rollback. Nesse caso, use o seguinte ponto final da API REST para desbloquear a transação atômica:
    • restproxy/api/v2/atomicTransactions/{globalTransactionId}
    Para obter mais informações sobre o ponto final REST a ser usado para desbloquear transações atômicas, consulte Desbloquear Transação Atômica.

Cenário: Explorar Transações Atômicas Usando Amostras

Considere o exemplo a seguir, que usa dois dos exemplos de códigos de cadeia incluídos no Oracle Blockchain Platform, Balance Transfer e Marbles. A amostra de Transferência de Saldo representa duas partes com a capacidade de transferir fundos entre saldos de conta. A amostra de mármores permite que você crie mármores e troque-os entre os proprietários. Você pode usar transações individuais (não atômicas) para comprar um mármore trocando fundos no código de cadeia de Transferência de Saldo e alterando a propriedade do mármore no código de cadeia de Mármores. No entanto, se ocorrer um erro com uma dessas transações, o razão poderá ficar em um estado inconsistente: ou os fundos foram transferidos, mas não o mármore ou o mármore é transferido, mas não pago.

Nesse cenário, você pode usar o chaincode existente com os pontos finais da API REST que suportam transações atômicas. A troca de fundos e a transferência de propriedade do mármore devem ter sucesso ou ambos falharem. Se uma das transações encontrar um erro, nenhuma delas será confirmada. Para explorar esse cenário, execute as seguintes etapas:

  1. Instale as amostras de Transferência de Saldo e Mármores em diferentes canais. Para obter mais informações sobre como instalar as amostras, consulte Explorar o Oracle Blockchain Platform Usando Amostras.
  2. Na amostra Mármores, chame a ação Create a new marble para criar vários mármores para vários proprietários de mármore.
  3. Use o ponto final REST Invoke Atomic Transaction para concluir transações atômicas que chamam as amostras de Mármores e Transferência de Saldo.

Por exemplo, a transação a seguir transfere um mármore chamado marble1 para Tom e envia 50 moedas da conta a para a conta b.

{
 "transactions": [
   {"chaincode":"obcs-marbles","args":["transferMarble", "marble1", "tom"],"timeout":0, "channel":"goods"},
   {"chaincode":"obcs-example02","args":["invoke", "a", "b", "50"],"timeout":0, "channel":"wallet"}
 ],
 "isolationLevel": "serializable",
 "prepareTimeout": 10000,
 "sync": true
}

Na transação anterior, se ambas as transações forem bem-sucedidas na fase de preparação, ambas as transações serão confirmadas no razão. Se houver um erro com uma das transações, nenhuma delas será confirmada durante a segunda fase. Em vez disso, ambas as transações são submetidas a rollback. Por exemplo, se houver menos de 50 moedas na conta a, nenhum dinheiro será retirado da conta e nenhum mármore será transferido para Tom.

Há um problema conhecido com a amostra Mármores e o valor padrão do campo Proprietário do mármore. Para obter mais informações, consulte: Problemas Conhecidos do Oracle Blockchain Platform.