'Failed to evaluate transaction: Error: You've asked to invoke a function that does not exist: getLastPatientId
I want to do inheritance in Hyperledger Fabric Chaincode using NodeJs.
I have created two classes CommonContract and AdminContract. CommonContract is the base class and AdminContract child class. But I got error when I invoke getLastPatiendId function from AdminContract. Error is as follows.
Failed to evaluate transaction: Error: You've asked to invoke a function that does not exist: getLastPatientId
[nodemon] app crashed - waiting for file changes before starting...
Even though getLastPatientId function is written in contract it is giving error function does not exists.
Below are the code of AdminContract, CommonContract, index.js file for chaincode and the server API which invoke transaction
CommonContract.js
This is CommonContract smart contract which is a base class.
'use strict';
const { Contract } = require('fabric-contract-api');
class CommonContract extends Contract {
async initLedger(ctx) {
console.info('============= START : Initialize Ledger ===========');
const initData = [
{
"firstName": "ABC",
"middleName": "D",
"lastName": "BCA",
"password": "d74ff0ee8da3b9806b18c877dbf29bbde50b5bd8e4dad7a3a725000feb82e8f1",
"age": "16",
"phoneNumber": "1234567890",
"address": "India",
"bloodGroup": "O+ve",
"updatedBy": "initLedger",
"symptoms": "fever",
"diagnosis": "Covid",
"treatment": "dolo 2 times",
"other": "no",
},
{
"firstName": "Five",
"middleName": ".H.",
"lastName": "CDA",
"password": "d74ff0ee8da3b9806b18c877dbf29bbde50b5bd8e4dad7a3a725000feb82e8f1",
"age": "16",
"phoneNumber": "1234567890",
"address": "India",
"bloodGroup": "O+ve",
"updatedBy": "initLedger",
"symptoms": "fever",
"diagnosis": "Covid",
"treatment": "dolo 2 times",
"other": "no",
}
]
for (let i = 0; i < initData.length; i++) {
initData[i].docType = 'patient';
await ctx.stub.putState('PID' + i, Buffer.from(JSON.stringify(initData[i])));
console.log('Data Added:---', initData[i]);
}
}
async getPatient(ctx, patientId){
const patient = await ctx.stub.getState(patientId);
if(patient.length || patient.length > 0)
console.log(patient);
let data = JSON.parse(patient.toString());
return data;
}
async getAllPatient(ctx){
const startKey = '';
const endKey = '';
const allResults = [];
for await (const {key, value} of ctx.stub.getStateByRange(startKey, endKey)){
const strValue = Buffer.from(value).toString('utf8');
let record;
try {
record = JSON.parse(strValue);
} catch (err) {
console.log(err);
record = strValue;
}
allResults.push({ Key: key, Record: record });
}
console.info(allResults);
return JSON.stringify(allResults);
}
}
module.exports = CommonContract;
AdminContract.js
This is an AdminContract smart contract that inherits CommonContract and has a single function getLastPatientId() it generally returns the patient id of the last patient created in the ledger.
'use strict';
let Patient = require('./PatientAssets.js');
const CommonContract = require('./CommonContract.js');
class AdminContract extends CommonContract {
async getLastPatientId(ctx) {
let result = await getAllPatient(ctx);
console.log(result);
return result[result.length - 1].patiendId;
}
}
module.exports = AdminContract;
index.js
This file is main entry point all smart contract.
'use strict';
const CommonContract = require('./lib/CommonContract.js');
const AdminContract = require('./lib/AdminContract.js');
module.exports.contracts = [CommonContract, AdminContract];
admin.js
This is server side route file which invoke the getLastPatientId function which is in AdminContract.js smart contract file.
router.get('/getAllPatient', async (req, res) => {
try {
// load the network configuration
const ccpPath = path.resolve(__dirname, '..', '..', 'network-config', 'organizations', 'peerOrganizations', 'doctor.hospital_network.com', 'connection-doctor.json');
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = await Wallets.newFileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
// Check to see if we've already enrolled the user.
const identity = await wallet.get('appUser1');
if (!identity) {
console.log('An identity for the user "appUser" does not exist in the wallet');
console.log('Run the registerUser.js application before retrying');
return;
}
// Create a new gateway for connecting to our peer node.
const gateway = new Gateway();
await gateway.connect(ccp, { wallet, identity: 'appUser1', discovery: { enabled: true, asLocalhost: true } });
// Get the network (channel) our contract is deployed to.
const network = await gateway.getNetwork('hospital');
// Get the contract from the network.
const contract = network.getContract('basic');
const result = await contract.evaluateTransaction('getLastPatientId');
const data = JSON.parse(result);
console.log(`Transaction has been evaluated, result is: ${result}`);
// Disconnect from the gateway.
await gateway.disconnect();
return data;
} catch (error) {
console.error(`Failed to evaluate transaction: ${error}`);
process.exit(1);
}
});
I found out that evalutateTransaction() invokes the function in CommonContract but was not able to invoke AdminContract functions. Please help me out. What is the error in my code ?
Solution 1:[1]
First I was implementing multiple contracts.
By getting the metadata for the contracts there is one default contract.
{
CommonContract: {
name: 'CommonContract',
contractInstance: { name: 'CommonContract', default: true },
transactions: [ [Object], [Object], [Object], [Object], [Object] ],
info: { title: '', version: '' }
},
AdminContract: {
name: 'AdminContract',
contractInstance: { name: 'AdminContract' },
transactions: [ [Object], [Object], [Object], [Object], [Object] ],
info: { title: '', version: '' }
},
DoctorContract: {
name: 'DoctorContract',
contractInstance: { name: 'DoctorContract' },
transactions: [ [Object], [Object], [Object] ],
info: { title: '', version: '' }
},
PatientContract: {
name: 'PatientContract',
contractInstance: { name: 'PatientContract' },
transactions: [ [Object], [Object] ],
info: { title: '', version: '' }
},
'org.hyperledger.fabric': {
name: 'org.hyperledger.fabric',
contractInstance: { name: 'org.hyperledger.fabric' },
transactions: [ [Object] ],
info: { title: '', version: '' }
}
}
Now in the admin.js file, looking at the line where we getting the contract
const contract = network.getContract('basic');
Here this statement was using default contract i.e. CommonContract, But I was implementing multiple contracts so I have to give the reference of that contract, so I make this change.
const contract = network.getContract('basic', 'AdminContract');
and now when I invoke the contract
const result = await contract.evaluateTransaction('getLastPatientId');
or
const contract = network.getContract('basic');
const result = await contract.evaluateTransaction('AdminContract:getLastPatientId');
It works...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
