Failed to evaluate transaction: Error: You've asked to invoke a function that does not exist: getLastPatientId
Failed to evaluate transaction: Error: You've asked to invoke a function that does not exist: getLastPatientId
我想使用 NodeJs 在 Hyperledger Fabric Chaincode 中进行继承。
我创建了两个 classes CommonContract
和 AdminContract
。 CommonContract
是基础 class 和 AdminContract 子 class。但是当我从 AdminContract
调用 getLastPatiendId
函数时出现错误。报错如下
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...
即使 getLastPatientId
函数写在合约中,它给出错误函数不存在。
下面是AdminContract、CommonContract、index.js链码文件和调用交易的服务器API的代码
CommonContract.js
这是基于class的CommonContract智能合约。
'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
这是一个继承CommonContract的AdminContract智能合约,功能单一getLastPatientId()
一般returns账本中最后创建的患者id
'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
此文件是所有智能合约的主要入口点。
'use strict';
const CommonContract = require('./lib/CommonContract.js');
const AdminContract = require('./lib/AdminContract.js');
module.exports.contracts = [CommonContract, AdminContract];
admin.js
这是服务器端路由文件,它调用 AdminContract.js 智能合约文件中的 getLastPatientId
函数。
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);
}
});
我发现 evalutateTransaction()
调用了 CommonContract 中的函数,但无法调用 AdminContract 函数。请帮帮我。我的代码有什么错误?
这是因为在调用交易时需要指定合约名称,除了第一个合约被视为默认。例如,您应该能够成功调用 initLedger
、CommonContract:initLedger
和 AdminContract:getLastPatientId
,但 getLastPatientId
将失败,因为默认合约上没有此类交易。
您可以通过获取合同的元数据来查看可用的交易以及默认的合同。您可以使用 org.hyperledger.fabric:GetMetadata
交易获取元数据,其中 org.hyperledger.fabric
是系统合约,GetMetadata
是交易。如果有帮助,ccmetadata 实用程序将调用该获取元数据事务。
您还可以使用构造函数自定义合约名称。例如,要调用 Admin:getLastPatientId
事务,请添加以下构造函数:
class AdminContract extends Contract {
constructor() {
super('Admin');
}
//...
}
注意:我认为这与您当前的问题无关,但我不确定您为什么要在这种情况下使用继承。它可能会导致其他问题,所以我会坚持扩展 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: '' }
}
}
现在在 admin.js
文件中,查看我们获取合同的行
const contract = network.getContract('basic');
此处此语句使用默认合同,即 CommonContract
,但我正在实施多个合同,因此我必须提供该合同的参考,因此我进行了此更改。
const contract = network.getContract('basic', 'AdminContract');
现在当我调用合约时
const result = await contract.evaluateTransaction('getLastPatientId');
或
const contract = network.getContract('basic');
const result = await contract.evaluateTransaction('AdminContract:getLastPatientId');
有效...
我想使用 NodeJs 在 Hyperledger Fabric Chaincode 中进行继承。
我创建了两个 classes CommonContract
和 AdminContract
。 CommonContract
是基础 class 和 AdminContract 子 class。但是当我从 AdminContract
调用 getLastPatiendId
函数时出现错误。报错如下
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...
即使 getLastPatientId
函数写在合约中,它给出错误函数不存在。
下面是AdminContract、CommonContract、index.js链码文件和调用交易的服务器API的代码
CommonContract.js
这是基于class的CommonContract智能合约。
'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
这是一个继承CommonContract的AdminContract智能合约,功能单一getLastPatientId()
一般returns账本中最后创建的患者id
'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
此文件是所有智能合约的主要入口点。
'use strict';
const CommonContract = require('./lib/CommonContract.js');
const AdminContract = require('./lib/AdminContract.js');
module.exports.contracts = [CommonContract, AdminContract];
admin.js
这是服务器端路由文件,它调用 AdminContract.js 智能合约文件中的 getLastPatientId
函数。
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);
}
});
我发现 evalutateTransaction()
调用了 CommonContract 中的函数,但无法调用 AdminContract 函数。请帮帮我。我的代码有什么错误?
这是因为在调用交易时需要指定合约名称,除了第一个合约被视为默认。例如,您应该能够成功调用 initLedger
、CommonContract:initLedger
和 AdminContract:getLastPatientId
,但 getLastPatientId
将失败,因为默认合约上没有此类交易。
您可以通过获取合同的元数据来查看可用的交易以及默认的合同。您可以使用 org.hyperledger.fabric:GetMetadata
交易获取元数据,其中 org.hyperledger.fabric
是系统合约,GetMetadata
是交易。如果有帮助,ccmetadata 实用程序将调用该获取元数据事务。
您还可以使用构造函数自定义合约名称。例如,要调用 Admin:getLastPatientId
事务,请添加以下构造函数:
class AdminContract extends Contract {
constructor() {
super('Admin');
}
//...
}
注意:我认为这与您当前的问题无关,但我不确定您为什么要在这种情况下使用继承。它可能会导致其他问题,所以我会坚持扩展 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: '' }
}
}
现在在 admin.js
文件中,查看我们获取合同的行
const contract = network.getContract('basic');
此处此语句使用默认合同,即 CommonContract
,但我正在实施多个合同,因此我必须提供该合同的参考,因此我进行了此更改。
const contract = network.getContract('basic', 'AdminContract');
现在当我调用合约时
const result = await contract.evaluateTransaction('getLastPatientId');
或
const contract = network.getContract('basic');
const result = await contract.evaluateTransaction('AdminContract:getLastPatientId');
有效...