체인코드 및 채널 전체에서 원자 갱신

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

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

원자 트랜잭션은 여러 체인 코드가 별도의 채널에 배치되는 복잡한 상황에서 유용할 수 있습니다. 네트워크 또는 시스템 장애가 발생하더라도 원자 트랜잭션을 사용하여 여러 블록체인 트랜잭션을 실행하는 동안 데이터 일관성을 유지할 수 있습니다. 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에 포함된 두 개의 샘플 체인코드인 잔액 이전 및 마블을 사용하는 다음 예를 고려해 보십시오. 잔액 이체 샘플은 계정 잔액 간에 자금을 이체할 수 있는 두 당사자를 나타냅니다. Marbles 샘플을 사용하면 대리석을 만들고 소유자 간에 교환할 수 있습니다. 잔액 이체 체인 코드에서 자금을 교환하고 Marbles 체인 코드에서 대리석 소유권을 변경하여 개별(비원자) 거래를 사용하여 대리석을 구매할 수 있습니다. 그러나 해당 거래 중 하나에서 오류가 발생하면 원장이 불일치 상태로 남을 수 있습니다. 자금이 이전되었지만 대리석이 아니거나 대리석이 이전되었지만 지급되지 않았습니다.

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

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

예를 들어, 다음 트랜잭션은 이름이 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에게 대리석이 전송되지 않습니다.

Marbles 샘플 및 Marble Owner 필드의 기본값과 관련하여 알려진 문제가 있습니다. 자세한 내용은 Oracle Blockchain Platform에 대한 알려진 문제를 참조하십시오.