[Hyperledger] Composer Transaction Processor 함수(2)

Hyperledger Composer Transaction Processor Function(2)

튜토리얼 내용이 너무 길어 반으로 잘랐다. 오늘은 data return과 쿼리 내용을 살펴볼 예정! 설명은 거의 없고 예시 위주로 되어 있어서 편하면서도 불편하다. 역설적인 마음~


데이터 반환(return)

트랜잭션 프로세서에서는 데이터를 선택적으로 리턴할 수 있다. 리턴을 사용하면 트랜잭션 전달자에게 '제대로 전송되었어요!'를 반환으로(return) 증명할 수 있다. 이 방법으로, 트랜잭션 확정 확인을 위한 별도 조회 프로세스가 사라지기 때문에 부하가 줄어든다.

리턴 데이터는 기본 유형 (String, Integer, Long 등)이나 컴포저 모델링 언어를 사용하여 모델링한 유형(개념, 자산, 참가자, 트랜잭션, 이벤트 또는 열거)이 될 수 있다.

리턴 데이터의 유형도 @returns(Type)데코레이터를 사용하여 트랜잭션 모델에 지정해야 한다. 단일 트랜잭션에 대해 여러 트랜잭션 프로세서 기능이있는 경우, 하나의 데이터만 반환할 수 있다. 리턴 데이터가 누락되거나 잘못된 유형인 경우 트랜잭션이 실패하고 거부된다.


기본 유형 반환

다음은 트랜잭션 처리 함수에서 문자열을 클라이언트에 리턴하는 예시이다.

model file
1
2
3
4
5
6
namespace org.sample

@returns(String)
transaction MyTransaction {

}
transaction processor function
1
2
3
4
5
6
7
8
9
/**
* Handle a transaction that returns a string.
* @param {org.sample.MyTransaction} transaction The transaction.
* @returns [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string) The string.
* @transaction
*/
async function myTransaction(transaction) {
return 'hello world!';
}

아래와 같이, 클라이언트에서 string을 받을 수 있다.

1
2
3
4
5
6
const bnc = new BusinessNetworkConnection();
await bnc.connect('admin@sample-network');
const factory = bnc.getBusinessNetwork().getFactory();
const transaction = factory.newTransaction('org.sample', 'MyTransaction');
const string = await bnc.submitTransaction(transaction);
console.log(`transaction returned $[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string)`);

아래의 예시는 트랜잭션 처리 함수에서 정수형 배열을 클라이언트에 리턴하는 예시이다.

model file
1
2
3
4
5
6
namespace org.sample

@returns(Integer[])
transaction MyTransaction {

}
transaction processor function
1
2
3
4
5
6
7
8
9
/**
* Handle a transaction that returns an array of integers.
* @param {org.sample.MyTransaction} transaction The transaction.
* @returns {number[]} The array of integers.
* @transaction
*/
async function myTransaction(transaction) {
return [1, 2, 3];
}

int형 배열은 다음과 같이 받을 수 있다.

1
2
3
4
5
6
7
8
const bnc = new BusinessNetworkConnection();
await bnc.connect('admin@sample-network');
const factory = bnc.getBusinessNetwork().getFactory();
const transaction = factory.newTransaction('org.sample', 'MyTransaction');
const integers = await bnc.submitTransaction(transaction);
for (const integer of integers) {
console.log(`transaction returned ${integer}`);
}

복합 유형 반환

동일한 코드를 수정하여 자산, 참가자, 트랜잭션 또는 이벤트를 반환 할 수도 있다.

model file
1
2
3
4
5
6
7
8
9
10
namespace org.sample

concept MyConcept {
o String value
}

@returns(MyConcept)
transaction MyTransaction {

}
transaction prcessor function
1
2
3
4
5
6
7
8
9
10
11
12
/**
* Handle a transaction that returns a concept.
* @param {org.sample.MyTransaction} transaction The transaction.
* @returns {org.sample.MyConcept} The concept.
* @transaction
*/
async function myTransaction(transaction) {
const factory = getFactory();
const concept = factory.newConcept('org.sample', 'MyConcept');
concept.value = 'hello world!';
return concept;
}

복합 유형은 다음과 같이 받을 수 있다.

1
2
3
4
5
6
const bnc = new BusinessNetworkConnection();
await bnc.connect('admin@sample-network');
const factory = bnc.getBusinessNetwork().getFactory();
const transaction = factory.newTransaction('org.sample', 'MyTransaction');
const concept = await bnc.submitTransaction(transaction);
console.log(`transaction returned ${concept.value}`);

다음의 방법으로 트랜잭션 처리 함수에서 concept를 클라이언트에 리턴할 수도 있다.

model file
1
2
3
4
5
6
7
8
9
10
namespace org.sample

concept MyConcept {
o String value
}

@returns(MyConcept[])
transaction MyTransaction {

}
transaction prcessor function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Handle a transaction that returns an array of concepts.
* @param {org.sample.MyTransaction} transaction The transaction.
* @returns {org.sample.MyConcept[]} The array of concepts.
* @transaction
*/
async function myTransaction(transaction) {
const factory = getFactory();
const concept1 = factory.newConcept('org.sample', 'MyConcept');
concept1.value = 'hello alice!';
const concept2 = factory.newConcept('org.sample', 'MyConcept');
concept2.value = 'hello bob!';
const concept3 = factory.newConcept('org.sample', 'MyConcept');
concept3.value = 'hello charlie!';
return [ concept1, concept2, concept3 ];
}

클라이언트에서는 아래와 같이 받으면 된다.

1
2
3
4
5
6
7
8
const bnc = new BusinessNetworkConnection();
await bnc.connect('admin@sample-network');
const factory = bnc.getBusinessNetwork().getFactory();
const transaction = factory.newTransaction('org.sample', 'MyTransaction');
const concepts = await bnc.submitTransaction(transaction);
for (const concept of concepts) {
console.log(`transaction returned ${concept.value}`);
}

열거형 배열(enum)을 받고 싶다면? 다음의 예시를 확인해 보자.

model
1
2
3
4
5
6
7
8
9
10
11
namespace org.sample

enum MyEnum {
o HELLO
o WORLD
}

@returns(MyEnum[])
transaction MyTransaction {

}
transaction prcessor function
1
2
3
4
5
6
7
8
9
/**
* Handle a transaction that returns an array of enumerations.
* @param {org.sample.MyTransaction} transaction The transaction.
* @returns {org.sample.MyEnum[]} The array of enumerations.
* @transaction
*/
async function myTransaction(transaction) {
return [ 'HELLO', 'WORLD' ];
}

클라이언트에서는 이렇게 처리하면 된다.

1
2
3
4
5
6
7
8
const bnc = new BusinessNetworkConnection();
await bnc.connect('admin@sample-network');
const factory = bnc.getBusinessNetwork().getFactory();
const transaction = factory.newTransaction('org.sample', 'MyTransaction');
const enums = await bnc.submitTransaction(transaction);
for (const enum of enums) {
console.log(`transaction returned ${enum}`);
}

읽기 전용 Function(Query Processor Function)

@commit(false) decorator를 이용, 읽기 전용 트랜잭션으로 지정할 수 있다. 읽기 전용으로 모델링할 경우에도 트랜잭션은 정상 제출되며, 트랜잭션 프로세서 기능 또한 정상적으로 실행되지만 커밋되지 않는다.

이 기능은 클라이언트 응용 프로그램이 비즈니스 네트워크에서 데이터를 읽는 데 사용할 수있는 API가 사용 사례에 비해 너무 제한적일 때 사용하면 좋다. get(id), getAll(), exists(id), query(q, params) 등을 지원한다.

다음 예제를 확인해 보자. 이 예제는 현재의 비즈니스 네트워크뿐 아니라 다른 비즈니스 네트워크에서 Asset set을 검색하고, 찾아낸 모든 Asset의 집합을 return한다.

model
1
2
3
4
5
6
7
8
9
10
11
12
namespace org.sample

asset MyAsset identified by assetId {
o String assetId
o String value
}

@commit(false)
@returns(MyAsset[])
transaction MyTransaction {

}
transaction prcessor function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Handle a transaction that returns an array of assets.
* @param {org.sample.MyTransaction} transaction The transaction.
* @returns {org.sample.MyAsset[]} All the assets.
* @transaction
*/
async function myTransaction(transaction) {
const allAssets = [];
const assetRegistry = await getAssetRegistry('org.sample.MyAsset');
const localAssets = await assetRegistry.getAll();
for (const asset of localAssets) {
localAssets.push(asset);
}
const businessNetworkNames = ['other-network-1', 'other-network-2'];
for (const businessNetworkName of businessNetworkNames) {
const response = await getNativeAPI().invokeChaincode(businessNetworkName, ['getAllResourcesInRegistry', 'Asset', 'org.sample.MyAsset'], 'composerchannel');
const json = JSON.parse(response.payload.toString('utf8'));
for (const item of json) {
allAssets.push(getSerializer().fromJSON(item));
}
}
return allAssets;
}

클라이언트 어플리케이션에서는 다음과 같이 확인 가능하다.

1
2
3
4
5
6
7
8
const bnc = new BusinessNetworkConnection();
await bnc.connect('admin@sample-network');
const factory = bnc.getBusinessNetwork().getFactory();
const transaction = factory.newTransaction('org.sample', 'MyTransaction');
const assets = await bnc.submitTransaction(transaction);
for (const asset of assets) {
console.log(`transaction returned ${asset.value}`);
}

Share