Hyperledger Composer Transaction Processor Function(1)
어떻게 하다 보니 여기까지 오긴 왔다. 이 링크 를 참고하여 트랜잭션을 관리(?)하는 함수를 작성해 보도록 하자! 예! 앞의 두 포스트는 이 포스트를 적기 위한 과정이었을 뿐. ㅠㅠ 험난했다.
Hyperledger Composer 비즈니스 네트워크는 모델 파일과 스크립트가 set로 구성된다. 스크립트에는 모델 파일에 정의 된 트랜잭션을 구현하는 트랜잭션 프로세서 기능을 포함할 수 있다.
Transaction Processor 함수는 BusinessNetworkConnection API를 사용하여 트랜잭션을 날릴 때 런타임에 의해 자동으로 호출된다.
문서 내의 decorator는 런타임 처리에 필요한 메타 데이터를 주석으로 단다.
각 트랜잭션에는 트랜잭션을 저장하는 레지스트리가 있다.
트랜잭션 프로세서의 구조
트랜잭션 프로세서 함수에는 Decorator, Metadata, JS 함수가 포함된다. 이 함수가 동작하기 위해서는 @param
과 @transaction
두 부분이 모두 필요하다.
주석의 첫 번째 줄에는 트랜잭션 처리 함수가 수행하는 기능에 대한 설명이 들어 있다. 두 번째 줄에는 @param
매개 변수 정의를 나타내는 태그가 있어야 한다 . @param
태그 다음에는 트랜잭션 프로세서 기능을 트리거하는 트랜잭션의 리소스 이름이 온다. 이 태그는 비즈니스 네트워크의 네임 스페이스 형식과 트랜잭션 이름 뒤에 위치한다. 리소스 이름 뒤에, 리소스를 참조 할 매개 변수 이름이 있으면 이 매개 변수를 JavaScript 함수에 인수로 제공해야 한다. 세 번째 줄에는 @transaction
태그가 있어야 한다. 이 태그는 코드를 트랜잭션 프로세서 기능으로 식별하므로 꼭 필요하다.
1 | /** |
주석은 트랜잭션에 권한을 부여하는 JavaScript 함수이다. 이 함수는 임의의 이름을 가질 수 있지만 주석에 정의 된 매개 변수 이름(parameter-name
)을 인수로 포함해야합니다.
1 | function transactionProcessor(parameter-name) { |
두 형식을 모두 적용한 코드는 다음과 같다.
1 | /** |
함수 작성하기
트랜잭션 프로세서 함수는 모델 파일에 정의 된 트랜잭션의 논리적 연산이다. 예를 들어, Trade
트랜잭션의 트랜잭션 프로세서는 owner
의 값을 한 참여자에서 다른 참여자로 변경할 수 있다.(owner
가 a였는데 b가 되는 등의 변경)
다음 basic-sample-network
예제의 SampleAsset
에 String
으로 정의된 value
속성이 있다. SampleTransaction
에 변경될 값인 newValue
를 value
속성으로 전달해야 한다.
1 | asset SampleAsset identified by assetId { |
SampleTransaction
은 다음의 코드처럼 asset 및 asset이 저장된 레지스트리 모두를 변경한다.
1 | /** |
에러 처리하기
트랜잭션은 딱 두 가지로 나뉜다. 성공해서 변경 사항이 적용되거나 실패하고 변경 사항이 적용되지 않거나(롤백).
1 | /** |
트랜잭션에서 모델의 관계 사용하기
다음의 코드와 같이, 모델의 관계가 연결(?)되는 경우가 있을 것이다. transaction -> asset -> participant 순서로 타고 들어가는 접근이 가능하다.
1 | namespace org.example.basic |
만약, transaction에서 participant로 접근하고 싶다면 함수를 아래와 같이 작성하면 된다.
1 | /** |
위의 경우, onwer
는 특정 참여자(tx.asset.owner
)를 가리키게 된다.
비동기 코드 및 Promise 처리
transaction 함수는 commit 전 promise
가 해결될 때까지 기다린다. promise
가 반환될 때까지 트랜잭션은 완료되지 않는다.
아래의 모델 파일을 활용한 함수를 작성해 보자.
1 | namespace org.example.basic |
node 8부터는 async/awit
구문이 지원되기 때문에 promise
를 사용하는 것보다 간결히 코드를 작성할 수 있다. 권장하는 스타일은 다음과 같다.
1 | /** |
위 코드를 사용하면 sampleTransaction()
은 getAssetRegistry()
가 완료되기 전에 assetRegistry
에 값을 저장하지 않고, assetRegistry
의 update()
가 완료되어야만 정상적으로 종료된다.
만약 개발자가 promise
구문을 그대로 사용하고 싶다면 다음와 같이 코드를 작성하면 된다.
1 | /** |
API 사용하기
함수에서 Hyperledger Composer API 호출하기
함수에서 적절한 인수를 사용하여 Hyperledger Composer API를 간단하게 호출할 수 있다.
1 | namespace org.example.basic |
아래의 예제 getAssetRegistry
에서 트랜잭션은 트랜잭션이 완료되기 전에 해결되는 promise
를 반환한다.
1 | /** |
함수에서 Hyperledger Fabric API 호출하기
Fabric API를 호출하려면 함수 getNativeAPI
를 먼저 호출해야 한다. 그 다음, Fabric API를 호출하여 사용할 수 있다. Fabric API를 사용하면 Composer API에서 사용할 수 없는 기능에 접근할 수 있다.
중요: getState
, putState
, deleteState
, getStateByPartialCompositeKey
, getQueryResult
는 Hyperledger Composer ACL을 무시한다.
getHistoryForKey
가 호출되면, 지정된 Asset의 History를 반환(return)한다. 트랜잭션 프로세서 함수는 반환 된 데이터를 배열에 저장한다.
트랜잭션 프로세서 함수에서 호출할 수 있는 Hyperledger Fabric API는 이 링크에 자세히 적혀 있다.
1 | async function simpleNativeHistoryTransaction (transaction) { |