- 이번 튜토리얼 에서는 자바스크립트 체인코드를 사용한다.
- Fabric 애플리케이션이 블록체인 네트워크와 상호작용하는 방법을 소개한다. 이 튜토리얼 에서는 Fabric SDK를 사용한 샘플 프로그램을 이용한다. 스마트 컨트랙트 API를 사용하여 ledger를 invoke, update하는 스마트 컨트랙트를 호출한다. 또한 샘플 프로그램과 인증 기관 사이에는 X.509 인증서를 생성한다.
네트워크 실행 및 체인코드 delpoy - 2 peer, 1 orderer, 2Org
./network.sh up createChannel -c mychannel -ca ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-javascript/ -ccl javascript
1, Admin 등록
async function main() {
try {
// 채널 path 설정
const ccp = buildCCP();
// 채널 구성에 따라 ca 클라이언트 인스턴스 빌드
const caClient = buildCAClient(FabricCAServices, ccp);
// 사용자의 지갑 설정
const wallet = await buildWallet(Wallets, walletPath);
// 실제 애플리케이션에서, admin 등록은 한 번만 실행된다.
await enrollAdmin(caClient, wallet);
2, 애플리케이션 사용자 등록
// 애플리케이션에 사용자가 추가될 때 호출
await registerAndEnrollUser(caClient, wallet, mspOrg1, org1UserId, 'org1.department1');
3, 애플리케이션의 channel 및 smart contract 연결 준비
자격 증명이 가능한 애플리케이션 사용자는 channel, smart contract 이름에 대한 참조를 얻은 후 체인코드 기능을 호출할 수 있다. → Gateway 사용
// Gateway 인스턴스 생성
// 실제 애플리케이션에서는 사용자에 대한 검증이 완료된 후에 이루어짐
const gateway = new Gateway();
try {
// Gateway 인스턴스 셋업, 이제 이 유저는 fabric network와 연결할 수 있고, transaction과 query를 보낼 수 있다.
// 이 게이트웨이로 보내진 모든 트랜잭션은 wallet에 저장된 crendentials를 이용하여 서명된다.
await gateway.connect(ccp, {
wallet,
identity: userId,
discovery: {enabled: true, asLocalhost: true} // using asLocalhost as this gateway is using a fabric network deployed locally
});
// smart contract가 배포된 채널을 기반으로 네트워크 인스턴스를 구축
const network = await gateway.getNetwork(channelName);
// 네트워크로부터 contract를 가져온다.
const contract = network.getContract(chaincodeName);
4, 애플리케이션은 일부 sample data로 ledger를 초기화 시킨다.
submitTransaction() 함수로 InitLedger 함수를 호출하여, Ledger를 일부 샘플 데이터로 초기화 시킬 수 있다.
// 이 유형의 트랜잭션은 애플리케이션이 처음 시작할 때 한 번만 실행된다.
// 체인코드가 업데이트 될 때에는 실행되지 않는다.
console.log('\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger');
await contract.submitTransaction('InitLedger');
console.log('*** Result: committed');
InitLedger 예시 → Ledger에 여섯개의 asset이 생성된 상태로 시작된다.
async InitLedger(ctx) {
const assets = [
{
ID: 'asset1',
Color: 'blue',
Size: 5,
Owner: 'Tomoko',
AppraisedValue: 300,
},
{
ID: 'asset2',
Color: 'red',
Size: 5,
Owner: 'Brad',
AppraisedValue: 400,
},
{
ID: 'asset3',
Color: 'green',
Size: 10,
Owner: 'Jin Soo',
AppraisedValue: 500,
},
{
ID: 'asset4',
Color: 'yellow',
Size: 10,
Owner: 'Max',
AppraisedValue: 600,
},
{
ID: 'asset5',
Color: 'black',
Size: 15,
Owner: 'Adriana',
AppraisedValue: 700,
},
{
ID: 'asset6',
Color: 'white',
Size: 15,
Owner: 'Michel',
AppraisedValue: 800,
},
];
for (const asset of assets) {
asset.docType = 'asset';
await ctx.stub.putState(asset.ID, Buffer.from(JSON.stringify(asset)));
console.info(`Asset ${asset.ID} initialized`);
}
}
5, 애플리케이션은 각 체인코드 기능을 호출한다.
// GetAllAssets 호출
let result = await contract.evaluateTransaction('GetAllAssets');
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
// CreateAsset 호출
await contract.submitTransaction('CreateAsset', 'asset13', 'yellow', '5', 'Tom', '1300');
console.log('*** Result: committed');
// GetAllAssets 정의
// GetAllAssets returns all assets found in the world state.
async GetAllAssets(ctx) {
const allResults = [];
// range query with empty string for startKey and endKey does an open-ended query of all assets in the chaincode namespace.
const iterator = await ctx.stub.getStateByRange('', '');
let result = await iterator.next();
while (!result.done) {
const strValue = Buffer.from(result.value.value.toString()).toString('utf8');
let record;
try {
record = JSON.parse(strValue);
} catch (err) {
console.log(err);
record = strValue;
}
allResults.push({ Key: result.value.key, Record: record });
result = await iterator.next();
}
return JSON.stringify(allResults);
}
// CreateAsset 정의
// CreateAsset issues a new asset to the world state with given details.
async CreateAsset(ctx, id, color, size, owner, appraisedValue) {
const asset = {
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
};
return ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
}
Share article