ibm-blockchain-js
Advanced tools
Comparing version 1.0.0 to 1.1.0
223
index.js
@@ -35,2 +35,3 @@ 'use strict'; | ||
git_url: '', | ||
options: {}, | ||
peers: [], | ||
@@ -40,4 +41,4 @@ timestamp: 0, | ||
unzip_dir: '', | ||
version: '', | ||
zip_url: '', | ||
options: {} | ||
} | ||
@@ -84,2 +85,3 @@ }; | ||
git_url: '', | ||
options: options.network.options, | ||
peers: [], | ||
@@ -89,4 +91,4 @@ timestamp: 0, | ||
unzip_dir: '', | ||
version: '', | ||
zip_url: '', | ||
options: options.network.options | ||
} | ||
@@ -137,8 +139,11 @@ }; | ||
// 2. Iter over go files | ||
// 2a. Find the boundaries for Run() in the cc | ||
// 2b. Grab function names that need to be exported | ||
// 2c. Create JS invoke functions for golang functions | ||
// 2d. Find the boundaries for Query() in the cc | ||
// 2e. Grab function names that need to be exported | ||
// 2f. Create JS query functions for golang functions | ||
// 2a. Find what shim version | ||
// 2b. Find the boundaries for Invoke() in the cc | ||
// 2c. Grab function names that need to be exported | ||
// 2d. Create JS invoke functions for golang functions | ||
// 2e. Find the boundaries for Query() in the cc | ||
// 2f. Grab function names that need to be exported | ||
// 2g. Create JS query functions for golang functions | ||
// 2h. Find the boundaries for Init() in the cc | ||
// 2i. Record function names that need to be exported | ||
// 3. Call callback() | ||
@@ -157,4 +162,4 @@ // ============================================================================================================================ | ||
var go_funcs = [], cc_suspects = [], cc_invocations = [], cc_queries = []; | ||
var found_query = false, found_run = false; | ||
var go_funcs = [], cc_suspects = [], cc_invocations = [], cc_queries = [], cc_inits = []; | ||
var found_query = false, found_invoke = false; | ||
var zip_dest = path.join(tempDirectory, '/file.zip'); // =./temp/file.zip | ||
@@ -232,7 +237,13 @@ var unzip_dest = path.join(tempDirectory, '/unzip'); // =./temp/unzip | ||
if(obj[i].indexOf('.go') >= 0){ //look for GoLang files | ||
if(!found_run || !found_query){ | ||
if(!found_invoke || !found_query){ | ||
foundGo = true; | ||
var file = fs.readFileSync(path.join(unzip_cc_dest, obj[i]), 'utf8'); | ||
parse_for_invoke(obj[i], file); | ||
parse_for_query(obj[i], file); | ||
// Step 2a. | ||
ibc.chaincode.details.version = find_shim(file); | ||
if(ibc.chaincode.details.version !== ''){ //we can't search for functions until we identify the shim version | ||
parse_for_invoke(obj[i], file); | ||
parse_for_query(obj[i], file); | ||
parse_for_init(obj[i], file); | ||
} | ||
} | ||
@@ -252,10 +263,10 @@ } | ||
if(!found_run){ //warning no run/invoke functions | ||
msg = 'did not find any invoke functions in chaincode\'s "Run()"'; | ||
console.log('! [ibc-js] Warning -', msg); | ||
if(!found_invoke){ //warning no run/invoke functions | ||
console.log('! [ibc-js] Warning - did not find any invoke functions in chaincode\'s "Invoke()", building a generic "invoke"'); | ||
build_invoke_func('invoke'); //this will make chaincode.invoke.invokce(args) | ||
} | ||
if(!found_query){ //warning no query functions | ||
msg = 'did not find any query functions in chaincode\'s "Query()"'; | ||
console.log('! [ibc-js] Warning -', msg); | ||
console.log('! [ibc-js] Warning - did not find any query functions in chaincode\'s "Query()", building a generic "query"'); | ||
build_query_func('query'); //this will make chaincode.query.query(args) | ||
} | ||
@@ -270,3 +281,21 @@ | ||
} | ||
//regex to find the shim version for this chaincode | ||
function find_shim(file){ | ||
var ret = ''; | ||
if(file == null) console.log('! [ibc-js] fs readfile Error'); | ||
else{ | ||
console.log('[ibc-js] Parsing file for shim version'); | ||
var shim_regex = /github.com\/\S+\/shim/g; //find chaincode's shim version | ||
var result = file.match(shim_regex); | ||
if(result[0]){ | ||
console.log('[ibc-js] Found shim version:', result[0]); | ||
ret = result[0]; | ||
} | ||
} | ||
return ret; | ||
} | ||
//look for Invokes | ||
function parse_for_invoke(name, str){ | ||
@@ -283,9 +312,11 @@ if(str == null) console.log('! [ibc-js] fs readfile Error'); | ||
} | ||
var i_start = 0; | ||
var i_stop = 0; | ||
var invokeFunctionName = 'Run'; //use Run for obc peer adn Invoke for hyperledger | ||
if(ibc.chaincode.details.version.indexOf('hyperledger/fabric/core/chaincode/shim') >= 0) invokeFunctionName = 'Invoke'; | ||
for(var i in go_funcs){ | ||
if(go_funcs[i].name.toLowerCase() === 'run'){ | ||
i_start = go_funcs[i].pos; //find start and stop positions around the "Run()" function | ||
if(go_funcs[Number(i) + 1] == null) i_stop = i_start * 2; //run is the last function.. so uhhhh just make up a high number | ||
if(go_funcs[i].name === invokeFunctionName){ | ||
i_start = go_funcs[i].pos; //find start and stop positions around the "Invoke()" function | ||
if(go_funcs[Number(i) + 1] == null) i_stop = i_start * 2; //invoke is the last function.. so uhhhh just make up a high number | ||
else i_stop = go_funcs[Number(i) + 1].pos; | ||
@@ -297,9 +328,9 @@ break; | ||
if(i_start > 0 && i_stop > 0){ | ||
// Step 2b. | ||
var regex = /function\s+==\s+["'](\w+)["']/g; //find the exposed chaincode functions in "Run()"" | ||
// Step 2c. | ||
var regex = /function\s+==\s+["'](\w+)["']/g; //find the exposed chaincode functions in "Invoke()"" | ||
var result2; | ||
while ( (result2 = regex.exec(str)) ) { | ||
cc_suspects.push({name: result2[1], index: result2.index}); //store this for when parsing query which runs next | ||
if(result2.index > i_start && result2.index < i_stop){ //make sure its inside Run() | ||
cc_invocations.push(result2[1]); | ||
cc_suspects.push({name: result2[1], index: result2.index}); //store this for future parsing like query & init | ||
if(result2.index > i_start && result2.index < i_stop){ //make sure its inside Invoke() | ||
cc_invocations.push(result2[1]); //build a list of function names | ||
} | ||
@@ -309,5 +340,5 @@ } | ||
if(cc_invocations.length > 0){ | ||
found_run = true; | ||
found_invoke = true; | ||
// Step 2c. | ||
// Step 2d. | ||
ibc.chaincode.details.func.invoke = []; | ||
@@ -321,3 +352,4 @@ for(i in cc_invocations){ //build the rest call for each function | ||
} | ||
//look for Queries | ||
function parse_for_query(name, str){ | ||
@@ -328,7 +360,7 @@ if(str == null) console.log('! [ibc-js] fs readfile Error'); | ||
// Step 2a. | ||
// Step 2e. | ||
var q_start = 0; | ||
var q_stop = 0; | ||
for(var i in go_funcs){ | ||
if(go_funcs[i].name.toLowerCase() === 'query'){ | ||
if(go_funcs[i].name === 'Query'){ | ||
q_start = go_funcs[i].pos; //find start and stop positions around the "Query()" function | ||
@@ -342,6 +374,6 @@ if(go_funcs[Number(i) + 1] == null) q_stop = q_start * 2; //query is the last function.. so uhhhh just make up a high number | ||
if(q_start > 0 && q_stop > 0){ | ||
// Step 2b. | ||
// Step 2f. | ||
for(i in cc_suspects){ | ||
if(cc_suspects[i].index > q_start && cc_suspects[i].index < q_stop){//make sure its inside Query() | ||
cc_queries.push(cc_suspects[i].name); | ||
cc_queries.push(cc_suspects[i].name); //build a list of function names | ||
} | ||
@@ -353,3 +385,3 @@ } | ||
// Step 2c. | ||
// Step 2g. | ||
ibc.chaincode.details.func.query = []; | ||
@@ -363,2 +395,39 @@ for(i in cc_queries){ //build the rest call for each function | ||
} | ||
//look for Inits | ||
function parse_for_init(name, str){ | ||
if(str == null) console.log('! [ibc-js] fs readfile Error'); | ||
else{ | ||
//console.log('[ibc-js] Parsing file for init functions -', name); | ||
// Step 2h. | ||
var q_start = 0; | ||
var q_stop = 0; | ||
for(var i in go_funcs){ | ||
if(go_funcs[i].name === 'Init'){ | ||
q_start = go_funcs[i].pos; //find start and stop positions around the "Init()" function | ||
if(go_funcs[Number(i) + 1] == null) q_stop = q_start * 2; //init is the last function.. so uhhhh just make up a high number | ||
else q_stop = go_funcs[Number(i) + 1].pos; | ||
break; | ||
} | ||
} | ||
if(q_start > 0 && q_stop > 0){ | ||
for(i in cc_suspects){ | ||
if(cc_suspects[i].index > q_start && cc_suspects[i].index < q_stop){//make sure its inside Init() | ||
cc_inits.push(cc_suspects[i].name); //build a list of function names | ||
} | ||
} | ||
if(cc_inits.length > 0){ | ||
// Step 2i. | ||
ibc.chaincode.details.func.init = []; | ||
for(i in cc_inits){ //no rest call to build, just remember it in 'details' | ||
ibc.chaincode.details.func.init.push(name); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
@@ -669,4 +738,26 @@ | ||
console.log('\n\n\t Waiting...'); //this can take awhile | ||
var options = {path: '/devops/deploy'}; | ||
var body = { | ||
var options = {}, body = {}; | ||
if(ibc.chaincode.details.version.indexOf('hyperledger/fabric/core/chaincode/shim') >= 0){ | ||
options = {path: '/chaincode'}; | ||
body = { | ||
jsonrpc: '2.0', | ||
method: 'deploy', | ||
params: { | ||
type: 1, | ||
chaincodeID:{ | ||
path: ibc.chaincode.details.git_url | ||
}, | ||
ctorMsg: { | ||
function: func, | ||
args: args | ||
}, | ||
secureContext: enrollId | ||
}, | ||
id: 11100010 | ||
}; | ||
} | ||
else{ | ||
options = {path: '/devops/deploy'}; | ||
body = { | ||
type: 'GOLANG', | ||
@@ -682,2 +773,3 @@ chaincodeID: { | ||
}; | ||
} | ||
//console.log('!body', body); | ||
@@ -795,4 +887,25 @@ options.success = function(statusCode, data){ | ||
var options = {path: '/devops/invoke'}; | ||
var body = { | ||
var options = {}, body = {}; | ||
if(ibc.chaincode.details.version.indexOf('hyperledger/fabric/core/chaincode/shim') >= 0){ | ||
options = {path: '/chaincode'}; | ||
body = { | ||
jsonrpc: '2.0', | ||
method: 'invoke', | ||
params: { | ||
type: 1, | ||
chaincodeID:{ | ||
name: ibc.chaincode.details.deployed_name | ||
}, | ||
ctorMsg: { | ||
function: 'invoke', | ||
args: args | ||
}, | ||
secureContext: enrollId | ||
}, | ||
id: 11100010 | ||
}; | ||
} | ||
else{ | ||
options = {path: '/devops/invoke'}; | ||
body = { | ||
chaincodeSpec: { | ||
@@ -810,3 +923,4 @@ type: 'GOLANG', | ||
}; | ||
} | ||
options.success = function(statusCode, data){ | ||
@@ -844,5 +958,27 @@ console.log('[ibc-js]', name, ' - success:', data); | ||
} | ||
var options = {}, body = {}; | ||
var options = {path: '/devops/query'}; | ||
var body = { | ||
if(ibc.chaincode.details.version.indexOf('hyperledger/fabric/core/chaincode/shim') >= 0){ | ||
options = {path: '/chaincode'}; | ||
body = { | ||
jsonrpc: '2.0', | ||
method: 'query', | ||
params: { | ||
type: 1, | ||
chaincodeID:{ | ||
name: ibc.chaincode.details.deployed_name | ||
}, | ||
ctorMsg: { | ||
function: 'query', | ||
args: args | ||
}, | ||
secureContext: enrollId | ||
}, | ||
id: 11100010 | ||
}; | ||
} | ||
else{ | ||
options = {path: '/devops/query'}; | ||
body = { | ||
chaincodeSpec: { | ||
@@ -860,2 +996,3 @@ type: 'GOLANG', | ||
}; | ||
} | ||
@@ -868,3 +1005,3 @@ options.success = function(statusCode, data){ | ||
console.log('[ibc-js]', name, ' - failure:', statusCode, e); | ||
if(cb) cb(helper.eFmt('invoke() error', statusCode, e), null); | ||
if(cb) cb(helper.eFmt('query() error', statusCode, e), null); | ||
}; | ||
@@ -871,0 +1008,0 @@ rest.post(options, '', body); |
{ | ||
"name": "ibm-blockchain-js", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "A library for easily interacting with IBM Blockchain.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
102
README.md
@@ -59,8 +59,8 @@ *Are you looking for the Marbles app demo? That’s not here, head to the [marbles example](https://github.com/IBM-Blockchain/marbles)* | ||
"api_port": "xxxxx", | ||
"id": "xxxxxx-xxxx-xxx-xxx-xxxxxxxxxxxx_vpx", | ||
"api_url": "http://xxx.xxx.xxx.xxx:xxxxx" | ||
"api_port_tls": "xxx", | ||
"id": "xxxxxx-xxxx-xxx-xxx-xxxxxxxxxxxx_vpx" | ||
}], | ||
users: [{ | ||
"username": "user1", | ||
"secret": "xxxxxxxx" | ||
"enrollID": "user1", | ||
"enrollSecret": "xxxxxxxx" | ||
}], | ||
@@ -89,3 +89,3 @@ options: { //this is optional | ||
if(cc.details.deployed_name === ""){ //decide if I need to deploy or not | ||
cc.deploy('init', ['99'], './cc_summaries', cb_deployed); | ||
cc.deploy('init', ['99'], null, cb_deployed); | ||
} | ||
@@ -166,3 +166,3 @@ else{ | ||
1. ibc.register(...) | ||
- It will register the first peer with the first username, the 2nd peer against the 2nd username and so on. | ||
- It will register the first peer with the first enrollID, the 2nd peer against the 2nd enrollID and so on. | ||
- This function only runs if valid users are found in options.network.users. A valid user is one that contains 'type_1'. | ||
@@ -173,3 +173,3 @@ - Any errors in register will stop execution and run callback(err). | ||
Options Parameter: | ||
Ex: | ||
@@ -182,12 +182,13 @@ ```js | ||
"api_port": "xxxxx", | ||
"api_url": "http://xxx.xxx.xxx.xxx:xxxxx" | ||
"id": "xxxxxx-xxxx-xxx-xxx-xxxxxxxxxxxx_vpx", | ||
"api_port_tls": "xxx", | ||
"id": "xxxxxx-xxxx-xxx-xxx-xxxxxxxxxxxx_vpx" | ||
}], | ||
users: [{ | ||
"username": "user1", | ||
"secret": "xxxxxxxx" | ||
"enrollID": "user1", | ||
"enrollSecret": "xxxxxxxx" | ||
}], | ||
options: { //this is optional, gets passed to ibc.network(peers, options); | ||
quiet: true, | ||
timeout: 60000 | ||
timeout: 60000, | ||
tls: false | ||
} | ||
@@ -203,2 +204,6 @@ }, | ||
}; | ||
ibc.load(options, function(err, data){ | ||
//callback here | ||
}); | ||
``` | ||
@@ -213,4 +218,4 @@ | ||
Example | ||
Ex: | ||
```js | ||
@@ -234,2 +239,3 @@ var options = { | ||
- tls = boolean - when `false` will use HTTP instead of HTTPS. Defaults `true`. | ||
Ex: | ||
@@ -242,4 +248,4 @@ | ||
"api_port": "xxxxx", | ||
"id": "xxxxxx-xxxx-xxx-xxx-xxxxxxxxxxxx_vpx", | ||
"api_url": "http://xxx.xxx.xxx.xxx:xxxxx" | ||
"api_port_tls": "xxx", | ||
"id": "xxxxxx-xxxx-xxx-xxx-xxxxxxxxxxxx_vpx" | ||
} | ||
@@ -300,3 +306,3 @@ ] | ||
Example Block Stats: | ||
Example Response: | ||
@@ -332,3 +338,3 @@ ```js | ||
Ex: | ||
```js | ||
@@ -343,7 +349,8 @@ ibc.switchPeer(2); | ||
- peerIndex = integer - position of peer in peers array (the one you fed ibc.networks()) you want to register against. | ||
- enrollID = string - name of secure context username. | ||
- enrollID = string - name of secure context user. | ||
- enrollSecret = string - password/secret/api key of secure context user. | ||
- maxRetry = integer - number of times to retry this call before giving up. | ||
Ex: | ||
```js | ||
@@ -385,25 +392,48 @@ ibc.register(3, 'user1', 'xxxxxx', 3, my_cb); | ||
### chaincode.deploy(func, args, [options], [username], [callback]) | ||
### chaincode.deploy(func, args, [options], [enrollID], [callback]) | ||
Deploy the chaincode. | ||
Call GoLang function named 'func' and feed it 'args'. | ||
Usually "args" is an array of strings. | ||
The `username` parameter should be the desired secure context username that has already been registered against the selected peer. | ||
If left `null` the SDK will use a known username for the selected peer. (this is only relevant in a permissioned network) | ||
Options are | ||
The `enrollID` parameter should be the desired secure context enrollID that has already been registered against the selected peer. | ||
If left `null` the SDK will use a known enrollID for the selected peer. (this is only relevant in a permissioned network) | ||
Options: | ||
- save_path = save the [Chaincode Summary File](#ccsf) to 'save_path'. | ||
- delay_ms = time in milliseconds to postpone the callback after deploy. Default is `40000` | ||
### chaincode.query.CUSTOM_FUNCTION_NAME(args, [username], [callback]) | ||
Ex: | ||
```js | ||
chaincode.deploy('init', ['99'], {delay_ms: 60000}, cb_deployed); | ||
``` | ||
### chaincode.query.CUSTOM_FUNCTION_NAME(args, [enrollID], [callback]) | ||
Will invoke your Go function CUSTOM_FUNCTION_NAME and pass it `args`. | ||
Usually `args` is an array of strings. | ||
The `username` parameter should be the desired secure context username that has already been registered against the selected peer. | ||
If left `null` the SDK will use a known username for the selected peer. (this is only relevant in a permissioned network) | ||
The `enrollID` parameter should be the desired secure context enrollID that has already been registered against the selected peer. | ||
If left `null` the SDK will use a known enrollID for the selected peer. (this is only relevant in a permissioned network) | ||
### chaincode.invoke.CUSTOM_FUNCTION_NAME(args, [username], [callback]) | ||
Ex: | ||
```js | ||
chaincode.query.read(['abc'], function(err, data){ | ||
console.log('read abc:', data, err); | ||
}); | ||
``` | ||
### chaincode.invoke.CUSTOM_FUNCTION_NAME(args, [enrollID], [callback]) | ||
Will query your Go function CUSTOM_FUNCTION_NAME and pass it `args`. | ||
Usually `args` is an array of strings. | ||
The `username` parameter should be the desired secure context username that has already been registered against the selected peer. | ||
If left `null` the SDK will use a known username for the selected peer. (this is only relevant in a permissioned network) | ||
The `enrollID` parameter should be the desired secure context enrollID that has already been registered against the selected peer. | ||
If left `null` the SDK will use a known enrollID for the selected peer. (this is only relevant in a permissioned network) | ||
### chaincode.query.read(name, [username], [callback]) *depreciated 4/1/2016* | ||
Ex: | ||
```js | ||
chaincode.invoke.init_marbles([args], function(err, data){ | ||
console.log('create marble response:', data, err); | ||
}); | ||
``` | ||
### chaincode.query.read(name, [enrollID], [callback]) *depreciated 4/1/2016* | ||
*This function is only here to help people transition from ibc v0.0.x to v1.x.x.* | ||
@@ -416,4 +446,4 @@ *You should create your own read() function in your chaincode which will overwrite this prebuilt one.* | ||
This will call the `Query()` function in the Go chaincode. | ||
The `username` parameter should be the desired secure context username that has already been registered against the selected peer. | ||
If left `null` the SDK will use a known username for the selected peer. (this is only relevant in a permissioned network) | ||
The `enrollID` parameter should be the desired secure context enrollID that has already been registered against the selected peer. | ||
If left `null` the SDK will use a known enrollID for the selected peer. (this is only relevant in a permissioned network) | ||
@@ -508,6 +538,6 @@ *** | ||
#FAQ | ||
- *ibc.load() appears to ignore all of my users for secure context. Then it complains it found no usernames and never registers with a Peer!* | ||
- *ibc.load() appears to ignore all of my users for secure context. Then it complains it found "No membership users" and never registers with a Peer!* | ||
Correct behavior of `ibc.load()` is to remove any usernames that do not contain 'type_1' in their name. | ||
This is to conform to the OBC Peer spec of what usernames a dev's app should use. | ||
Correct behavior of `ibc.load()` is to remove any enrollIDs that do not contain 'type_1' in their name. | ||
This is to conform to the OBC Peer spec of what enrollIDs a dev's app should use. | ||
If this is not applicable for your network (ie you have a custom IBM Blockchain network) you can easily create your own version of `ibc.load()` for your needs. | ||
@@ -514,0 +544,0 @@ I would copy the code found in `ibc.load()` then modify it to fit your own needs. |
73151
1292
535