我构建了一个智能合约,正在尝试测试它。
它成功部署,但并非所有功能都有效(事件发射器触发问题),例如issueCertificate功能。
我必须编写一个调试脚本来测试问题出在哪里,然后我认为它来自 ethers.utility.id 方法,我什至进一步明确测试了 utils Id。
当我
run npx hardhat run scripts/debug.js
时,我从 debug.js 中收到此错误
错误:
TypeError: Cannot read properties of undefined (reading 'id')
at main (/Users/MASTERS/ACV/scripts/debug.js:22:38)
当我
run node scripts/testUtilsId.js
时,我从 testUtilsId.js 收到此错误
错误:
(base) ACV % node scripts/testUtilsId.js
TypeError: Cannot read properties of undefined (reading 'id')
at testUtilsId (/Users/MASTERS/ACV/scripts/testUtilsId.js:6:43)
at Object.<anonymous> (/Users/MASTERS/ACV/scripts/testUtilsId.js:15:1)
at Module._compile (node:internal/modules/cjs/loader:1364:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1422:10)
at Module.load (node:internal/modules/cjs/loader:1203:32)
at Module._load (node:internal/modules/cjs/loader:1019:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:128:12)
at node:internal/main/run_main_module:28:49
下面是 smartcontract.sol、debug.js 和 testUtilsId.js 的代码
证书管理.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract CertificateManagement {
// Struct to store certificate information
struct Certificate {
uint256 id;
string studentName;
string course;
uint256 issueDate;
bool isValid;
string issuer;
}
// Mapping from certificate ID to certificate details
mapping(uint256 => Certificate) public certificates;
// Mapping from an address to a boolean indicating if it is authorized to issue and revoke certificates
mapping(address => bool) public authorizedIssuers;
// Event emitted when a certificate is issued
event CertificateIssued(uint256 indexed certificateID, string studentName, string issuer);
// Event emitted when a certificate is revoked
event CertificateRevoked(uint256 indexed certificateID);
// Modifier to check if the caller is an authorized issuer
modifier onlyAuthorized() {
require(authorizedIssuers[msg.sender], "Caller is not authorized");
_;
}
constructor() {
// The deployer of the contract is the initial authorized issuer
authorizedIssuers[msg.sender] = true;
}
// Function to authorize a new issuer
function addIssuer(address issuer) external onlyAuthorized {
authorizedIssuers[issuer] = true;
}
// Function to revoke issuer rights
function removeIssuer(address issuer) external onlyAuthorized {
authorizedIssuers[issuer] = false;
}
// Function to issue a new certificate
function issueCertificate(string memory studentName, string memory course, string memory issuer) public onlyAuthorized returns (uint256) {
uint256 newCertificateID = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender, studentName, course)));
certificates[newCertificateID] = Certificate(newCertificateID, studentName, course, block.timestamp, true, issuer);
emit CertificateIssued(newCertificateID, studentName, issuer); // Ensure this line is correct
return newCertificateID;
}
// Function to revoke a certificate
function revokeCertificate(uint256 certificateID) public onlyAuthorized {
require(certificates[certificateID].isValid, "Certificate already revoked");
certificates[certificateID].isValid = false;
emit CertificateRevoked(certificateID);
}
// Function to verify the validity of a certificate
function verifyCertificate(uint256 certificateID) public view returns (bool) {
return certificates[certificateID].isValid;
}
}
调试.js:
require("@nomicfoundation/hardhat-toolbox");
const { ethers } = require("hardhat");
const utils = ethers.utils;
async function main() {
const [deployer] = await ethers.getSigners();
const CertificateManagement = await ethers.getContractFactory("CertificateManagement");
const certManagement = await CertificateManagement.deploy();
await certManagement.waitForDeployment();
console.log("CertificateManagement deployed to:", await certManagement.getAddress());
await certManagement.addIssuer(deployer.address);
const tx = await certManagement.issueCertificate("John Doe", "Blockchain 101", "University");
const receipt = await tx.wait();
console.log("Transaction Receipt:", receipt);
const logs = receipt.logs;
console.log("Transaction Logs:", logs);
if (logs.length > 0) {
// Calculate the event signature
const eventSignature = utils.id("CertificateIssued(uint256,string,string)");
console.log("Event Signature:", eventSignature);
// Log each topic and data for inspection
logs.forEach((log, index) => {
console.log(`Log ${index} Address:`, log.address);
console.log(`Log ${index} Topics:`, log.topics);
console.log(`Log ${index} Data:`, log.data);
});
// Find the log corresponding to the event
const event = logs.find(log => log.topics[0] === eventSignature);
if (event) {
console.log("Event found:", event);
// The first topic is the event signature, and the second topic is the indexed parameter (certificateID)
const certificateID = event.topics[1];
// Decode the data part (non-indexed parameters: studentName and issuer)
const decodedData = utils.defaultAbiCoder.decode(
["string", "string"],
event.data
);
const studentName = decodedData[0];
const issuer = decodedData[1];
console.log("Issued Certificate ID:", certificateID);
console.log("Student Name:", studentName);
console.log("Issuer:", issuer);
} else {
console.log("CertificateIssued event not found in the transaction receipt.");
}
} else {
console.log("No logs found in the transaction receipt.");
}
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
testUtilsId.js:
const { ethers } = require("hardhat");
async function testUtilsId() {
// Random string
const randomString = "Hello World";
const randomStringHash = ethers.utils.id(randomString);
console.log(`Hash of "${randomString}": ${randomStringHash}`);
// Event signature
const eventSignatureString = "CertificateIssued(uint256,string,string)";
const eventSignatureHash = ethers.utils.id(eventSignatureString);
console.log(`Hash of "${eventSignatureString}": ${eventSignatureHash}`);
}
testUtilsId().catch((error) => {
console.error(error);
process.exitCode = 1;
});
我修复了它,发现我的调用方式在 v6 中已被弃用,所以我更改了 ethers.utils.id(randomString);到 ethers.id(randomString);