Hyperledger Fabric SDK例fabric-samples-「balance-transfer」の6「chaincodeの実行」
30193 ワード
本文はすでに私の公衆番号Fabric技術でオリジナルの先発を分かち合った.転載は出典を明記してください.https://blog.csdn.net/qq_27818541/article/details/78416848出典:【BigManingのブログ】
ここでは、A−>Bのような振り替え機能を実現し、最終的にはchaincodeの
fabricが取引を実行する基本的な流れに関連しています.
Created with Raphal2.1.2 Startは、現在のユーザーパッケージ取引提案送信提案requestがバックグラウンドノードのすべてのバックグラウンド応答に対してokパッケージ取引要求送信取引を行うか否かを取得し、最終的にmoveメソッド処理結果End yes noを呼び出す
コンソール印刷:
バックグラウンド印刷:
前言
ここでは、A−>Bのような振り替え機能を実現し、最終的にはchaincodeの
move
メソッドを実行する.ここでは、chaincode
のmove
の方法を見てみましょう.
func (t *SimpleChaincode) move(stub shim.ChaincodeStubInterface, args []string) pb.Response {
// must be an invoke
//1
var A, B string // Entities
//2
var Aval, Bval int // Asset holdings
var X int // Transaction value
var err error
if len(args) != 3 {
return shim.Error("Incorrect number of arguments. Expecting 4, function followed by 2 names and 1 value")
}
A = args[0]
B = args[1]
//3 A Get the state from the ledger
Avalbytes, err := stub.GetState(A)
if err != nil {
return shim.Error("Failed to get state")
}
if Avalbytes == nil {
return shim.Error("Entity not found")
}
Aval, _ = strconv.Atoi(string(Avalbytes))
//4 B
Bvalbytes, err := stub.GetState(B)
if err != nil {
return shim.Error("Failed to get state")
}
if Bvalbytes == nil {
return shim.Error("Entity not found")
}
Bval, _ = strconv.Atoi(string(Bvalbytes))
//5
X, err = strconv.Atoi(args[2])
if err != nil {
return shim.Error("Invalid transaction amount, expecting a integer value")
}
Aval = Aval - X
Bval = Bval + X
logger.Infof("Aval = %d, Bval = %d
", Aval, Bval)
//6 ( map k-v) Write the state back to the ledger
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
if err != nil {
return shim.Error(err.Error())
}
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil);
}
ルート
app.js
// peer Invoke transaction on chaincode on target peers
app.post('/channels/:channelName/chaincodes/:chaincodeName', function(req, res) {
logger.debug('==================== INVOKE ON CHAINCODE ==================');
//1
//
var peers = req.body.peers;
//chaincode
var chaincodeName = req.params.chaincodeName;
//channel
var channelName = req.params.channelName;
//chaincode
var fcn = req.body.fcn;
//
var args = req.body.args;
logger.debug('channelName : ' + channelName);
logger.debug('chaincodeName : ' + chaincodeName);
logger.debug('fcn : ' + fcn);
logger.debug('args : ' + args);
if (!chaincodeName) {
res.json(getErrorMessage('\'chaincodeName\''));
return;
}
if (!channelName) {
res.json(getErrorMessage('\'channelName\''));
return;
}
if (!fcn) {
res.json(getErrorMessage('\'fcn\''));
return;
}
if (!args) {
res.json(getErrorMessage('\'args\''));
return;
}
//2
invoke.invokeChaincode(peers, channelName, chaincodeName, fcn, args, req.username, req.orgname)
.then(function(message) {
res.send(message);
});
});
具体的な実装
fabricが取引を実行する基本的な流れに関連しています.
invoke-transaction.js
var path = require('path');
var fs = require('fs');
var util = require('util');
var hfc = require('fabric-client');
var Peer = require('fabric-client/lib/Peer.js');
var helper = require('./helper.js');
var logger = helper.getLogger('invoke-chaincode');
var EventHub = require('fabric-client/lib/EventHub.js');
var ORGS = hfc.getConfigSetting('network-config');
var invokeChaincode = function (peerNames, channelName, chaincodeName, fcn, args, username, org) {
logger.debug(util.format('
============ invoke transaction on organization %s ============
', org));
var client = helper.getClientForOrg(org);
var channel = helper.getChannelForOrg(org);
var targets = (peerNames) ? helper.newPeers(peerNames, org) : undefined;
var tx_id = null;
//1 jim ( )
return helper.getRegisteredUsers(username, org).then((user) => {
tx_id = client.newTransactionID();
logger.debug(util.format('Sending transaction "%j"', tx_id));
//2
var request = {
chaincodeId: chaincodeName,
fcn: fcn,
args: args,
chainId: channelName,
txId: tx_id
};
if (targets)
request.targets = targets;
//3
// send proposal to endorser
return channel.sendTransactionProposal(request);
}, (err) => {
logger.error('Failed to enroll user \'' + username + '\'. ' + err);
throw new Error('Failed to enroll user \'' + username + '\'. ' + err);
}).then((results) => {
//4
var proposalResponses = results[0];
var proposal = results[1];
var all_good = true;
for (var i in proposalResponses) {
let one_good = false;
if (proposalResponses && proposalResponses[i].response &&
proposalResponses[i].response.status === 200) {
one_good = true;
logger.info('transaction proposal was good');
} else {
logger.error('transaction proposal was bad');
}
all_good = all_good & one_good;
}
if (all_good) {
logger.debug(util.format(
'Successfully sent Proposal and received ProposalResponse: Status - %s, message - "%s", metadata - "%s", endorsement signature: %s',
proposalResponses[0].response.status, proposalResponses[0].response.message,
proposalResponses[0].response.payload, proposalResponses[0].endorsement
.signature));
//5 ok
var request = {
proposalResponses: proposalResponses,
proposal: proposal
};
// set the transaction listener and set a timeout of 30sec
// if the transaction did not get committed within the timeout period,
// fail the test
var transactionID = tx_id.getTransactionID();
var eventPromises = [];
if (!peerNames) {
peerNames = channel.getPeers().map(function (peer) {
return peer.getName();
});
}
//5.1 promise
var eventhubs = helper.newEventHubs(peerNames, org);
for (let key in eventhubs) {
let eh = eventhubs[key];
eh.connect();
let txPromise = new Promise((resolve, reject) => {
let handle = setTimeout(() => {
eh.disconnect();
reject();
}, 30000);
eh.registerTxEvent(transactionID, (tx, code) => {
clearTimeout(handle);
eh.unregisterTxEvent(transactionID);
eh.disconnect();
if (code !== 'VALID') {
logger.error(
'The balance transfer transaction was invalid, code = ' + code);
reject();
} else {
logger.info(
'The balance transfer transaction has been committed on peer ' +
eh._ep._endpoint.addr);
resolve();
}
});
});
eventPromises.push(txPromise);
};
//6
var sendPromise = channel.sendTransaction(request);
//7 promise
return Promise.all([sendPromise].concat(eventPromises)).then((results) => {
logger.debug(' event promise all complete and testing complete');
return results[0]; // the first returned value is from the 'sendPromise' which is from the 'sendTransaction()' call
}).catch((err) => {
logger.error(
'Failed to send transaction and get notifications within the timeout period.'
);
return 'Failed to send transaction and get notifications within the timeout period.';
});
} else {
logger.error(
'Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...'
);
return 'Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...';
}
}, (err) => {
logger.error('Failed to send proposal due to error: ' + err.stack ? err.stack :
err);
return 'Failed to send proposal due to error: ' + err.stack ? err.stack :
err;
}).then((response) => {
//8
if (response.status === 'SUCCESS') {
logger.info('Successfully sent transaction to the orderer.');
return tx_id.getTransactionID();
} else {
logger.error('Failed to order the transaction. Error code: ' + response.status);
return 'Failed to order the transaction. Error code: ' + response.status;
}
}, (err) => {
logger.error('Failed to send transaction due to error: ' + err.stack ? err
.stack : err);
return 'Failed to send transaction due to error: ' + err.stack ? err.stack :
err;
});
};
exports.invokeChaincode = invokeChaincode;
基本プロセス
Created with Raphal2.1.2 Startは、現在のユーザーパッケージ取引提案送信提案requestがバックグラウンドノードのすべてのバックグラウンド応答に対してokパッケージ取引要求送信取引を行うか否かを取得し、最終的にmoveメソッド処理結果End yes noを呼び出す
APIアクセス
echo "POST invoke chaincode on peers of Org1 and Org2"
echo
TRX_ID=$(curl -s -X POST \
http://localhost:4000/channels/mychannel/chaincodes/mycc \
-H "authorization: Bearer $ORG1_TOKEN" \
-H "content-type: application/json" \
-d '{
"fcn":"move",
"args":["a","b","10"]
}')
echo "Transacton ID is $TRX_ID"
echo
echo
コンソール印刷:
Transacton ID is eb058850e7247ad0bc25ec57ced1cd1255666c390ca0c9300858ce6e57175221
バックグラウンド印刷:
[2017-10-16 11:07:40.822] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:40.823] [DEBUG] SampleWebApp - ==================== INVOKE ON CHAINCODE ==================
//
[2017-10-16 11:07:40.823] [DEBUG] SampleWebApp - channelName : mychannel
[2017-10-16 11:07:40.823] [DEBUG] SampleWebApp - chaincodeName : mycc
[2017-10-16 11:07:40.823] [DEBUG] SampleWebApp - fcn : move
[2017-10-16 11:07:40.823] [DEBUG] SampleWebApp - args : a,b,10
[2017-10-16 11:07:40.824] [DEBUG] invoke-chaincode -
============ invoke transaction on organization org1 ============
// Jim
[2017-10-16 11:07:40.824] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:40.825] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:40.826] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:40.826] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:40.827] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:40.828] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:40.828] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:40.829] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:40.831] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:40.831] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:40.832] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:40.833] [INFO] Helper - Successfully loaded member from persistence
//
[2017-10-16 11:07:40.833] [DEBUG] invoke-chaincode - Sending transaction "{"_nonce":{"type":"Buffer","data":[169,122,192,203,43,77,68,42,128,240,8,81,90,35,63,156,13,236,81,59,126,148,200,17]},"_transaction_id":"eb058850e7247ad0bc25ec57ced1cd1255666c390ca0c9300858ce6e57175221"}"
[2017-10-16 11:07:40.841] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: 2a552dc46d1921f3bacd95df82cc38c855946021a93a7b8cba61ee9b4cdb9857>,
s: 4877817703a392a85561824acfcf695ec09a37d8032c2d52afddccfae2063d22>,
recoveryParam: 0 }
[2017-10-16 11:07:40.855] [INFO] invoke-chaincode - transaction proposal was good
[2017-10-16 11:07:40.855] [INFO] invoke-chaincode - transaction proposal was good
//
[2017-10-16 11:07:40.855] [DEBUG] invoke-chaincode - Successfully sent Proposal and received ProposalResponse: Status - 200, message - "OK", metadata - "", endorsement signature: 0D ?�cEW�>��N���p����r�[b�gaR5f�@ `"���D��}������0�s0�6��:�%�v/í
//
info: [EventHub.js]: _connect - options {"grpc.ssl_target_name_override":"peer0.org1.example.com","grpc.default_authority":"peer0.org1.example.com"}
[2017-10-16 11:07:40.861] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: ,
s: ,
recoveryParam: 0 }
info: [EventHub.js]: _connect - options
{" grpc.ssl_target_name_override":"peer1.org1.example.com","grpc.default_authority":"peer1.org1.example.com"}
[2017-10-16 11:07:40.867] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: ,
s: ,
recoveryParam: 0 }
[2017-10-16 11:07:40.875] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: ,
s: ,
recoveryParam: 1 }
[2017-10-16 11:07:43.022] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: ,
s: ,
recoveryParam: 1 }
[2017-10-16 11:07:43.022] [INFO] invoke-chaincode - The balance transfer transaction has been committed on peer localhost:7058
[2017-10-16 11:07:43.045] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: ,
s: ,
recoveryParam: 1 }
[2017-10-16 11:07:43.045] [INFO] invoke-chaincode - The balance transfer transaction has been committed on peer localhost:7053
[2017-10-16 11:07:43.046] [DEBUG] invoke-chaincode - event promise all complete and testing complete
// orderer , peer
[2017-10-16 11:07:43.046] [INFO] invoke-chaincode - Successfully sent transaction to the orderer.