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 CommonContractAdminContractCommonContract 是基础 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 函数。请帮帮我。我的代码有什么错误?

这是因为在调用交易时需要指定合约名称,除了第一个合约被视为默认。例如,您应该能够成功调用 initLedgerCommonContract:initLedgerAdminContract: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');

有效...