transaction id from getHistoryForKey() is always undefined in Hyperledger Fabric - hyperledger-fabric

I am working on Nodejs chaincode on Fabric 2.1, when I tried to fetch the history for a key. It returns the "Timestamp" and "value" correctly, but the tx_id in the iterator is always undefined.
has anyone successfully retrived the associated transaction ID ??
async getAllResults(iterator, isHistory) {
let allResults = [];
while (true) {
let res = await iterator.next();
if (res.value && res.value.value.toString()) {
let jsonRes = {};
console.log(res.value.toString('utf8'));
console.log(res.value.tx_id);
console.log(res.value.value.toString('utf8'));
logs:
dev-peer0.org1.example.com-mycc_7-7cd3dda|[object Object]
dev-peer0.org1.example.com-mycc_7-7cd3dda|undefined
dev-peer0.org1.example.com-mycc_7-7cd3dda|{"entityType":"product","model":"somemodel","name":"bike","newdata":"somedata","owner":"e7854d50-8793-449a-a903-d740d8d5952b","txDate":"Wed Jul 29 2020"}

At last i figured it out,
the iterator returns "txId" and not "tx_id"
correct way is
jsonRes.TxId = res.value.txId;
Apparently the code from
https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02/javascript/marbles_chaincode.js
has it wrong, or it is old and needs to be updated

Related

Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string. /*what is empty or not a string*/

this is the error that I get. I checked multiple times that the paths that I indicate are actually pointing at something in the database. I'm kinda going crazy about why this is not working, so help will be appreciated. (the same error is given by both functions, two times every invocation of the function)
this is my code:
exports.onCreatePost = functions.firestore
.document('/time/{userid}/date/{postId}')
.onCreate (async (snapshot, context) => {
const postCreated = snapshot.data();
const userID = context.params.userid;
const postID = context.params.postId;
//get all the followers who made the post
const userFollowerRef = admin.firestore().collection('time').doc(userID).collection('followers');
const querySnap = await userFollowerRef.get();
//add the post in each follower timeline
querySnap.forEach(doc => {
const followerid = doc.id;
admin.firestore().collection('time').doc(followerid).collection('timelinePosts').doc(postID).set(postCreated);
})
});
//when a post is updated
exports.onUpdatePost = functions.firestore
.document('/time/{userid}/date/{postid}')
.onUpdate(async (change, context) => {
const postUpdated = change.after.data();
const userID = context.params.userid;
const postID = context.params.postId;
//get all the followers who made the post
const userFollowerRef = admin.firestore().collection('time').doc(userID).collection('followers');
const querySnap = await userFollowerRef.get();
//Update the post in each follower timeline
querySnap.forEach(doc => {
const follower = doc.id;
admin.firestore().collection('time').doc(follower).collection('timelinePosts').doc(postID)
.get().then(doc => {
if (doc.exists) {
doc.ref.update(postUpdated);
}
});
});
});
I personally don't know how to log each variable and did not find how to do it online. I'll keep searching but in the mindtime I can share my extensive logs that from my interpretation are not very useful but maybe is just because I'm inexperienced.
this is the error log
enter image description here
In function exports.onUpdatePost ...you're likely trying to access documentPath null (or something alike that). Add logging, this permits to log custom debug information into the log which you've screenshotted. When logging every step of the procedure, it's a whole lot easier to determine what is happening and why - or why not, when skipping something. Alike this you should be able to solve the issue on your own. My functions logging actually utilizes emojis, because UTF-8 is being supported: ✅❌ (visual indicators make the log more readable).
The cause seems to be one of these instructions:
admin.firestore().collection('time') // it is being assumed that it exists
.doc(userID) // argument or return value may be null
.collection('followers') // return value may be null
Or:
admin.firestore().collection('time') // it is being assumed that it exists
.doc(follower) // argument or return value may be null
.collection('timelinePosts') // return value may be null
.doc(postID) // argument or return value may be null
eg. one first has to check if follower != null or empty and if the desired document even exists. The same goes for userID and .doc(userID) (the seemingly "own" timeline).
if (follower != null && follower.length > 0) {
admin.firestore().collection('time').doc(follower).get().then(timeline => {
functions.logger.log('timeline: ' follower + ', ' + timeline.exists);
if (timeline.exists) {
} else {
}
});
}
documentPath == null comes from .doc() + userID, followerid, follower or postID.

Hyperledger node.js failed to parse null

can somebody help with error which appears on HL Composer?
Error content: Error: SyntaxError: Failed to parse null: Unexpected token (377:39)
Line 377 is: let exists = await accounts.exists(element.destinationAcc)
let accounts = await getAssetRegistry(ns + '.Account');
let transactions = await getAssetRegistry(ns + '.Transactions');
let allTransactions = await query('pendingTransactions');
let allAccounts = await accounts.getAll();
if (allTransactions.length() > 0) {
allTransactions.forEach(element => {
if (element.status == 'PENDING') {
let exists = await accounts.exists(element.destinationAcc);
if (exists) {
let destAcc = await allAccounts.find(element.destinationAcc);
This is a pretty standard mistake that javascript developers make and isn't related to hyperledger composer at all.
You are trying to perform an await within a method that hasn't been declared async. HOWEVER even if you do add the keyword async to the method that you have declared inside the forEach declaration it still won't work, due to the way forEach works.
So for you the solution is, don't use the forEach method of an array to try to run an anonymous function with an await in it. Use an alternative method to iterate the allTransactions array such as a for loop.

Caliper Error: Transaction returned with failure. The key already exists

I'm still on my journey to set up the Caliper for the first time. Hope you can save me :)
Right know I got the error: Transaction returned with failure: User 1 already exists.
when I try to launch the caliper benchmark.
Because I do not allow to register users with an existing userID (verified on my chaincode).
This is my test file:
'use strict';
module.exports.info = 'opening accounts';
const { v1: uuidv4 } = require('uuid')
let account_array = [];
let bc, contx;
var txnPerBatch = 1
let j;
module.exports.init = function (blockchain, context, args) {
if (!args.hasOwnProperty('txnPerBatch')) {
args.txnPerBatch = 1;
}
txnPerBatch = args.txnPerBatch;
bc = blockchain;
contx = context;
j = 0;
let workload = [];
workload.push({
chaincodeFunction: 'instantiate',
chaincodeArguments: [],
});
bc.invokeSmartContract(contx, 'loyalty', '1', workload);
return Promise.resolve();
};
function generateWorkload() {
let workload = [];
for (let i = 0; i < txnPerBatch; i++) {
var random = (j+1).toString();
var gam_admin = {
userID: random
};
workload.push({
chaincodeFunction: 'createGamificationAdmin',
chaincodeArguments: [JSON.stringify(gam_admin)],
});
}
return workload;
}
module.exports.run = function () {
let workload = [];
let args = generateWorkload();
return bc.invokeSmartContract(contx, 'loyalty', '1', args);
};
module.exports.end = function () {
return Promise.resolve();
};
module.exports.account_array = account_array;
Do you know how can I solve this? Thanks so much.
Looking at the callback file you have defined, the User name will always be the same for all transactions that are sent by the caliper workers.
Each time a caliper worker issues a transaction, it will invoke the run function that you have defined ... in this case it forms the same content each time and so you get the conflict that you have seen.
There are ways around this:
caliper workers know their index (0 based out of all workers)
caliper workers know the transaction that they are working on (0 based out of all transactions sent over the round duration)
It looks like you will have to refactor the work load generation to take into account both the caliper worker index, and the transaction number being send, so that each invocation of run gives you a unique userID

History of asset in Hyperledger Fabric

I am using node.js to write chaincode and I want to get the history of drug in pharmaceutical supply chain. I deployed chaincode, invoked manufacture and buy contract which modifies the drug's current state from one owner to another owner. Infact, I just modified commercial paper chaincode for this. The change in owner is reflected in couchdb database. But when I try to get the history of drug by drug key it doesn't work as expected.
Code I used
const promiseOfIterator = this.ctx.stub.getHistoryForKey(drugKey);
const results = [];
for await (const keyMod of promiseOfIterator) {
const resp = {
timestamp: keyMod.timestamp,
txid: keyMod.tx_id
}
if (keyMod.is_delete) {
resp.data = 'KEY DELETED';
} else {
resp.data = keyMod.value.toString('utf8');
}
results.push(resp);
}
return results;
When I printed the results, it gives: []
And when I do this: Drug.fromBuffer(getDrugHistoryResponse); and print it, it gives Drug { class: 'org.medicochainnet.drug', key: ':', currentState: null }
How to make this work? What am I doing wrong here? Please help me.
the function
ctx.stub.getHistoryForKey(drugKey);
is an asynchronous function. So you need to add await
const promiseOfIterator = await this.ctx.stub.getHistoryForKey(drugKey);
Then you can iterate over the result.
I have done it in a demo like that:
const promiseOfIterator = await this.ctx.stub.getHistoryForKey(drugKey);
const results = [];
while(true){
let res = await promiseOfIterator.next();
//In the loop you have to check if the iterator has values or if its done
if(res.value){do your actions}
if(res.done){
// close the iterator
await promiseOfIterator.close()
// exit the loop
return results
}
}
Check the Mozilla Documentation for more information about Iterators in Javascript. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators

AutoIncrement of Multiple columns in indexeddb

Does any one know - how we can specify autoincrement for two columns in indexeddb.
I know - we can specify autoincremnt for one column while creating table like this -
var objectStore = thisDb.createObjectStore("note", { keyPath: "id", autoIncrement:true });
but not able to find how we can do the same for multiple columns. Also as far as i know - we cant get the value of autoincrement. The value will be autoincremented & added when we will insert the data. So if i can get the autoincrement value somehow, that would the solution too.
You cannot create two auto-incremented properties in a store. That feature is only available for the property defined as the key path.
You can easily get the auto-incremented value. The value is provided as the result of the put or add request that inserted a new object.
For example:
function addThing(db, thing) {
return new Promise((resolve, reject) => {
let id = undefined;
const transaction = db.transaction('things', 'readwrite');
const store = transaction.objectStore('things');
// wait to resolve the promise until the transaction is completed
// so that we do not prematurely pretend the operation succeeded. resolve
// to the value of the new id
transaction.oncomplete = event => resolve(id);
transaction.onerror = event => reject(event.target.error);
// store.add also works here
const request = store.put(thing);
// listen for the add event and grab the value of the new id
// that indexedDB generated and store it in the id variable
request.onsuccess = event => id = event.target.result;
});
}
async function doSomething() {
const something = {bar: 'baz'};
const db = await open(...);
const id = await addThing(db, something);
db.close();
something.id = id;
console.log(something);
}

Resources