체인코드 및 채널 간 기본 업데이트 수행

원자 트랜잭션을 사용하여 채널 및 체인코드 간에 여러 트랜잭션을 원자 방식으로 완료할 수 있습니다.

원자 트랜잭션은 모두 성공하거나 성공하지 못하는 분할할 수 없는 일련의 데이터 작업입니다.

원자 트랜잭션은 여러 체인코드가 별도의 채널에 배포되는 복잡한 상황에서 유용할 수 있습니다. 네트워크 또는 시스템 장애가 발생하더라도 원자 트랜잭션을 사용하여 여러 블록체인 트랜잭션을 실행하는 동안 데이터 일관성을 유지할 수 있습니다. Oracle Blockchain Platform은 2단계 커밋 프로토콜을 사용하여 원자 트랜잭션을 지원합니다. 이 프로토콜에서는 각 데이터 작업이 준비되는 초기 단계 다음에 각 데이터 작업이 실제로 커밋되는 단계가 나옵니다.

원자 트랜잭션은 응용 프로그램 레벨에서 작동합니다. 일반적으로 원자 트랜잭션을 지원하기 위해 기존 체인코드 논리를 변경할 필요가 없습니다. 원자 트랜잭션 프레임워크에서 하나 이상의 인수가 추가되므로 기존 체인코드가 체인코드 메소드에 전달된 인수 수에 대해 엄격한 검사를 수행하지 않는지 확인하십시오. 기본 트랜잭션은 다음 REST API 엔드포인트에서 지원됩니다.
  • restproxy/api/v2/atomicTransactions
REST API 엔드포인트는 체인 코드에 정의된 대로 트랜잭션을 준비한 다음 내장 체인 코드 함수를 사용하여 모든 트랜잭션을 커밋하거나 준비 단계 중 오류가 있는 경우 모든 트랜잭션을 롤백합니다. 기본 트랜잭션 구현에 사용할 REST 끝점에 대한 자세한 내용은 기본 트랜잭션 REST 끝점을 참조하십시오.

각 원자 트랜잭션은 두 개 이상의 블록체인 트랜잭션으로 구성됩니다. 원자 트랜잭션의 결과(returnCode 값)는 Success 또는 Failure입니다. 원자 트랜잭션에서 요청된 각 블록체인 트랜잭션은 준비 단계와 커밋 또는 롤백 단계의 두 가지 개별 작업으로 분할됩니다.

  • 준비 단계에서는 각 트랜잭션이 평소와 같이 승인되지만 완료되는 대신 변경 사항이 스테이지되고 다른 트랜잭션에서 스테이지된 값을 수정하지 못하도록 값이 잠깁니다.
  • 각 블록체인 트랜잭션에 대한 준비 단계가 성공하면 내장 체인코드를 사용하여 트랜잭션이 승인되고 커밋됩니다. 이전에 잠긴 값은 잠금 해제되며 원자 트랜잭션의 결과는 Success입니다.
  • 블록체인 트랜잭션에 대한 준비 단계가 실패하면 준비 단계가 성공한 다른 모든 트랜잭션이 다시 내장 체인코드를 사용하여 롤백됩니다. 스테이지된 변경 사항이 제거되고 이전에 잠긴 값이 잠금 해제됩니다. 원자 트랜잭션의 결과는 Failure입니다.
기본 트랜잭션은 키를 잠그면 작동하므로 다른 트랜잭션이 준비된 현재 활성 기본 트랜잭션에 의해 잠긴 키를 수정하려고 시도할 경우 Two_Phase_Commit_Lock 오류가 발생할 수 있습니다. 이 문제는 다음 두 시나리오 중 하나에서 발생할 수 있습니다.
  • 원자 트랜잭션은 아직 준비 단계에 있으며 다른 트랜잭션은 준비된 트랜잭션에 의해 잠긴 키를 수정하려고 시도합니다. 이 경우 시스템은 설계된 대로 작동합니다. 이 오류가 발생하면 두번째 트랜잭션을 재시도하십시오. 이는 응용 프로그램이 가상 읽기 오류 또는 MVCC(다중 버전 동시성 제어) 오류를 처리하는 방법과 유사합니다.
  • 원자 트랜잭션에서 반환되는 GlobalStatus 값은 HeuristicOutcome입니다. 이 경우 커밋 작업 중 하나가 실패하여 원자 트랜잭션 작업이 취소되었습니다. 이 문제는 드문 경우이므로 수동으로 해결해야 할 수도 있습니다. 경험적 결과의 한 가지 부작용은 커밋 또는 롤백에 실패한 트랜잭션에 의해 일부 키가 잠긴 상태로 남아 있을 수 있다는 것입니다. 이 경우 다음 REST API 엔드포인트를 사용하여 기본 트랜잭션의 잠금을 해제합니다.
    • restproxy/api/v2/atomicTransactions/{globalTransactionId}
    기본 트랜잭션 잠금 해제에 사용할 REST 끝점에 대한 자세한 내용은 기본 트랜잭션 잠금 해제를 참조하십시오.

시나리오: 샘플을 사용하여 원자 트랜잭션 탐색

Oracle Blockchain Platform, Balance Transfer 및 Marbles에 포함된 두 개의 샘플 체인코드를 사용하는 다음 예를 고려해 보십시오. 잔액 이체 샘플은 계정 잔액 간에 자금을 이체할 수 있는 두 당사자를 나타냅니다. Marbles 샘플을 사용하면 대리석을 만들고 소유자 간에 교환할 수 있습니다. 개별(비원자) 트랜잭션을 사용하여 잔액 이체 체인 코드에서 자금을 교환하고 대리석 체인 코드에서 대리석 소유권을 변경하여 대리석을 구입할 수 있습니다. 그러나 이러한 거래 중 하나에 오류가 발생하면 원장이 불일치 상태로 남아 있을 수 있습니다. 자금이 이전되었지만 대리석이 이전되지 않았거나 대리석이 이전되었지만 지급되지 않았습니다.

이 시나리오에서는 원자 트랜잭션을 지원하는 REST API 엔드포인트와 함께 기존 체인코드를 사용할 수 있습니다. 자금 교환과 대리석의 소유권 이전은 성공하거나 둘 다 실패해야합니다. 두 트랜잭션에서 모두 오류가 발생하면 트랜잭션이 커밋되지 않습니다. 이 시나리오를 보려면 다음 단계를 완료하십시오.

  1. 다른 채널에 Balance Transfer 및 Marbles 샘플을 설치합니다. 샘플 설치에 대한 자세한 내용은 샘플을 사용하여 Oracle Blockchain Platform 살펴보기를 참조하십시오.
  2. Marbles 샘플에서 Create a new marble 작업을 호출하여 다양한 대리석 소유자를 위한 여러 대리석을 만듭니다.
  3. Invoke Atomic Transaction REST 엔드포인트를 사용하여 대리석류 및 잔액 이전 샘플을 모두 호출하는 원자 트랜잭션을 완료합니다.

예를 들어, 다음 트랜잭션은 이름이 marble1인 대리석을 Tom에게 전송하고 계정 a에서 계정 b로 50개의 동전을 전송합니다.

{
 "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
}

이전 트랜잭션에서 두 트랜잭션이 준비 단계에서 성공하면 두 트랜잭션이 모두 원장에 커밋됩니다. 두 트랜잭션 중 하나에 오류가 있으면 두번째 단계 중 어느 트랜잭션도 커밋되지 않습니다. 대신 두 트랜잭션이 모두 롤백됩니다. 예를 들어, 계정 a에 50개 미만의 동전이 있는 경우 계정에서 돈을 받지 않고 대리석도 Tom에게 이체되지 않습니다.

대리석류 샘플과 대리석 소유자 필드의 기본값에는 알려진 문제가 있습니다. 자세한 내용은 Oracle Blockchain Platform에 대해 알려진 문제를 참조하십시오.