Chỉ có chủ sở hữu hợp đồng và những người được ủy quyền mới có thể thực hiện các thao tác như đăng ký, cập nhật, xóa bệnh nhân và cấp quyền ủy quyền.. modifier onlyOwner // Modifier này
Trang 1
BÁO CÁO KẾT THÚC MÔN LẬP TRÌNH ỨNG DỤNG PHÂN TÁN
GIẢNG VIÊN: TS Đỗ Sính NHÓM: 9
SVTH: 1 Phan Khắc Điền Trang (Nhóm trưởng)
2 Huỳnh Thị Kim Ngân
3 Dương Bá Thắng
LỚP: ST21A1A KHÓA: 2021 – 2025
Đà Nẵng, 12/2023
TRƯỜNG ĐẠI HỌC ĐÔNG Á
KHOA CÔNG NGHỆ THÔNG TIN
Trang 2
-MỤC LỤC
BẢNG PHÂN CÔNG 3 TÓM TẮT CHỨC NĂNG 4 GIẢI THÍCH CODE 5
Trang 3BẢNG PHÂN CÔNG
Tên thành viên IDSV Phân công Mức độ hoàn
thành
Phan Khắc Điền Trang 93190 Làm báo cáo,
quay video, lên ý tưởng, code bài, giải thích code
100 %
Huỳnh Thị Kim Ngân 93176 Làm silde, code
bài, lên ý tưởng, giải thích code
100 %
Dương Bá Thắng 93152 Code bài, lên ý
tưởng, hỗ trợ làm báo cáo, giải thích
code
100 %
Trang 4TÓM TẮT CHỨC NĂNG
- Quản lý Thông Tin Bệnh Nhân:
Hợp đồng có khả năng lưu trữ thông tin của mỗi bệnh nhân, bao gồm tên, ngày tháng năm sinh, nhóm máu, thông tin liên hệ, và tình trạng sức khỏe.
- Quản Lý Quyền Truy Cập:
Cung cấp cơ chế quản lý quyền truy cập thông tin Chỉ có chủ sở hữu hợp đồng và những người được ủy quyền mới có thể thực hiện các thao tác như đăng ký, cập nhật, xóa bệnh nhân và cấp quyền ủy quyền.
- Sự Kiện (Events):
Sử dụng sự kiện để thông báo về các sự kiện quan trọng như việc đăng ký bệnh nhân mới, cập nhật thông tin, xóa bệnh nhân, cấp quyền ủy quyền, và thu hồi quyền ủy quyền Điều này giúp theo dõi lịch sử hoạt động của hợp đồng.
- Quản Lý Quyền Ủy Quyền:
Trang 5Hợp đồng có các hàm để cấp và thu hồi quyền ủy quyền Điều này cho phép chủ sở hữu quản lý những người được phép thực hiện các thao tác trên hồ sơ bệnh nhân.
- Hàm Đăng Ký và Cập Nhật:
Cung cấp hàm để đăng ký bệnh nhân mới và cập nhật thông tin của bệnh nhân đã đăng ký Những hàm này chỉ có sẵn cho những người được ủy quyền.
- Hàm Xóa Bệnh Nhân:
Chỉ có chủ sở hữu hợp đồng mới có thể xóa bệnh nhân khỏi hệ thống.
- Truy Vấn Thông Tin:
Cung cấp hàm để truy vấn số lượng bệnh nhân đã đăng ký trong
hệ thống.
- Modifiers (Điều Kiện):
Sử dụng modifiers để áp đặt điều kiện nhất định, như chỉ chủ sở hữu hoặc những người được ủy quyền mới có thể thực hiện một số thao tác.
Trang 6- Constructor (Hàm Khởi Tạo):
Hàm khởi tạo được sử dụng để thiết lập chủ sở hữu là người triển khai hợp đồng.
Trang 7GIẢI THÍCH CODE
// SPDX-License-Identifier: MIT
pragma solidity 0.8.0; // sử dụng phiên bản từ 0.8.0 trở lên
contract MedicalRecords { // Khai báo một hợp đồng mới có tên là
MedicalRecords
address public owner; // Biến owner được khai báo là public, có nghĩa là
// nó có thể được truy cập từ bên ngoài hợp đồng Biến này lưu trữ địa chỉ
// của chủ sở hữu hợp đồng
// Contact là một cấu trúc (struct) chứa thông tin liên lạc của một người
// Có năm trường dữ liệu:
struct Contact {
string addressLine1;// Địa chỉ dòng 1
string addressLine2;// Địa chỉ dòng 2
string city; // Thành phố
string phoneNumber;// Số điện thoại
string email; // Địa chỉ email
}
Trang 8// Patient là một cấu trúc (struct) đại diện cho thông tin của một bệnh nhân
// Có năm trường dữ liệu:
struct Patient {
string name;// Tên của bệnh nhân
string dob; // Ngày tháng năm sinh
string bloodType; // Nhóm máu của bệnh nhân
Contact contactInfo;// Một trường kiểu Contact chứa thông tin liên lạc của bệnh nhân
string healthStatus; // Tình trạng sức khỏe
}
mapping(address => Patient) public patients;
// patients là một bảng ánh xạ (mapping) từ địa chỉ (address)
// của một bệnh nhân đến thông tin chi tiết về bệnh nhân (kiểu Patient)
address[] public patientAddresses;
// patientAddresses là một mảng các địa chỉ (address) của bệnh nhân
// Điều này có thể được sử dụng để duyệt qua tất cả các bệnh nhân mapping(address => bool) public authorizedAddresses;
// authorizedAddresses là một bảng ánh xạ từ địa chỉ (address) đến một
Trang 9// giá trị boolean, xác định xem địa chỉ đó có được ủy quyền hay không
event PatientRegistered(address indexed patientAddress, string
name);
event PatientRemoved(address indexed patientAddress);
event PatientUpdated(address indexed patientAddress, string field,
string newValue);
event AuthorizationGranted(address indexed authorizedAddress); event AuthorizationRevoked(address indexed authorizedAddress); // PatientRegistered: Được kích hoạt khi một bệnh nhân mới được đăng ký Chứa địa chỉ và tên của bệnh nhân
// PatientRemoved: Được kích hoạt khi một bệnh nhân bị xóa khỏi hệ thống Chứa địa chỉ của bệnh nhân
// PatientUpdated: Được kích hoạt khi thông tin của bệnh nhân được cập nhật Chứa địa chỉ, trường được cập nhật và giá trị mới của trường // AuthorizationGranted: Được kích hoạt khi một địa chỉ được cấp quyền truy cập Chứa địa chỉ được cấp quyền
// AuthorizationRevoked: Được kích hoạt khi một địa chỉ mất quyền truy cập Chứa địa chỉ mất quyền
modifier onlyOwner() // Modifier này đảm bảo rằng chỉ chủ sở hữu của hợp đồng mới có thể gọi được hàm chứa modifier này
Trang 10require(msg.sender == owner, "Only contract owner can call this function");
// kiểm tra xem người gọi hàm có phải là chủ sở hữu của hợp đồng không Nếu không, hàm sẽ bị ngừng lại và một thông báo lỗi sẽ được hiển thị
// Nếu không, hàm sẽ bị ngừng lại và một thông báo lỗi sẽ được hiển thị
_;
//là nơi mà nội dung của hàm gốc sẽ được thực thi nếu điều kiện của modifier đúng
}
modifier onlyAuthorized() // Modifier này đảm bảo rằng chỉ các địa chỉ được ủy quyền hoặc chủ sở hữu mới có thể gọi được hàm chứa modifier này
require(
authorizedAddresses[msg.sender] || msg.sender == owner, "Not authorized to perform this action"
// kiểm tra xem người gọi hàm có phải là một địa chỉ được ủy quyền hoặc là chủ sở hữu của hợp đồng không
// Nếu không, hàm sẽ bị ngừng lại và một thông báo lỗi sẽ được hiển thị
);
_;
Trang 11// là nơi mà nội dung của hàm gốc sẽ được thực thi nếu điều kiện của modifier đúng
}
constructor() {
owner = msg.sender;
// Hàm này được gọi khi hợp đồng được triển khai Nó sẽ đặt chủ sở hữu của hợp đồng
// là địa chỉ của người triển khai hợp đồng (msg.sender)
}
function grantAuthorization(address _authorizedAddress) external
onlyOwner {
// Hàm này cho phép chủ sở hữu của hợp đồng (onlyOwner modifier đảm bảo chỉ chủ sở hữu mới có thể gọi được)
// cấp quyền ủy quyền cho một địa chỉ khá
require(_authorizedAddress != owner, "Owner cannot grant
authorization to themselves");
// kiểm tra xem chủ sở hữu có cố gắng cấp quyền ủy quyền cho chính họ không
// Nếu có, hàm sẽ dừng lại và hiển thị một thông báo lỗi
authorizedAddresses[_authorizedAddress] = true;
// thiết lập quyền ủy quyền cho địa chỉ được chỉ định
emit AuthorizationGranted(_authorizedAddress);
Trang 12// phát ra một sự kiện để thông báo rằng quyền ủy quyền đã được cấp cho một địa chỉ cụ thể
}
function revokeAuthorization(address _authorizedAddress) external
onlyOwner {
// Hàm này cho phép chủ sở hữu của hợp đồng (onlyOwner modifier đảm bảo chỉ chủ sở hữu mới có thể gọi được)
// thu hồi quyền ủy quyền từ một địa chỉ
authorizedAddresses[_authorizedAddress] = false;
// thu hồi quyền ủy quyền của địa chỉ được chỉ định
emit AuthorizationRevoked(_authorizedAddress);
// phát ra một sự kiện để thông báo rằng quyền ủy quyền đã được thu hồi từ một địa chỉ cụ thể
}
function registerPatient(
// Hàm registerPatient được thiết kế để đăng ký thông tin của một bệnh nhân mới vào hệ thống
string memory _name,
string memory _dob,
string memory _bloodType,
string memory _addressLine1,
string memory _addressLine2,
Trang 13string memory _city,
string memory _phoneNumber,
string memory _email,
string memory _healthStatus
) external onlyAuthorized {
// modifier Đảm bảo rằng chỉ những địa chỉ được ủy quyền mới có thể gọi hàm này
require(bytes(_name).length > 0 "Name must not be empty"); // Đảm bảo tên bệnh nhân không được trống
require(bytes(_dob).length > 0, "Date of birth must not be empty");
// Đảm bảo ngày tháng năm sinh không được trống
require(bytes(patients[msg.sender].dob).length == 0 "Patient already registered");
// Kiểm tra xem bệnh nhân đã được đăng ký trước đó hay chưa bằng cách kiểm tra xem ngày
// tháng năm sinh đã được lưu trữ cho địa chỉ người gọi hàm chưa
// để tham chiếu đến thông tin bệnh nhân mới, sẽ được lưu trữ trong patients mapping
// với khóa là địa chỉ của người gọi hàm
// Lưu trữ tên, ngày tháng năm sinh, nhóm máu, thông tin liên lạc
Trang 14// (bao gồm cả địa chỉ dòng 1 và dòng 2, thành phố, số điện thoại, email), và tình trạng sức khỏe của bệnh nhân
Patient storage newPatient = patients[msg.sender];
newPatient.name = _name;
newPatient.dob = _dob;
newPatient.bloodType = _bloodType;
newPatient.contactInfo = Contact({
addressLine1: _addressLine1,
addressLine2: _addressLine2,
city: _city,
phoneNumber: _phoneNumber,
email: _email
});
newPatient.healthStatus = _healthStatus;
patientAddresses.push(msg.sender);
// Thêm địa chỉ của bệnh nhân mới vào danh sách các địa chỉ bệnh nhân
emit PatientRegistered(msg.sender, _name);
// Phát ra sự kiện để thông báo rằng một bệnh nhân mới đã được đăng ký thành công,
// kèm theo địa chỉ và tên của bệnh nhân
}
Trang 15function updatePatientInfo(
// Hàm updatePatientInfo được thiết kế để cập nhật thông tin của một bệnh nhân đã được đăng ký trong hệ thống
address _patientAddress,
string memory _name,
string memory _dob,
string memory _bloodType,
string memory _addressLine1,
string memory _addressLine2,
string memory _city,
string memory _phoneNumber,
string memory _email,
string memory _healthStatus
) external onlyAuthorized {
// modifier Đảm bảo rằng chỉ những địa chỉ được ủy quyền mới có thể gọi hàm này
require(bytes(_name).length > 0 "Name must not be empty"); // Đảm bảo tên bệnh nhân không được trống
require(bytes(_dob).length > 0, "Date of birth must not be empty");
// Đảm bảo ngày tháng năm sinh không được trống
require(bytes(patients[_patientAddress].dob).length > 0
"Patient not found");
Trang 16// Kiểm tra xem bệnh nhân cần cập nhật có tồn tại không, dựa trên việc kiểm tra ngày tháng năm sinh
// đã được lưu trữ cho địa chỉ bệnh nhân cần cập nhật hay không
Patient storage patient = patients[_patientAddress];
// Lấy ra thông tin của bệnh nhân cần cập nhật từ mapping patients
// Cập nhật tên, ngày tháng năm sinh, nhóm máu, thông tin liên lạc
// (bao gồm cả địa chỉ dòng 1 và dòng 2, thành phố, số điện thoại, email),
// và tình trạng sức khỏe của bệnh nhân
patient.name = _name;
patient.dob = _dob;
patient.bloodType = _bloodType;
patient.contactInfo = Contact({
addressLine1: _addressLine1,
addressLine2: _addressLine2,
city: _city,
phoneNumber: _phoneNumber,
email: _email
});
patient.healthStatus = _healthStatus;
Trang 17// Phát ra sự kiện để thông báo rằng thông tin của một bệnh nhân đã được cập nhật thành công,
// kèm theo địa chỉ của bệnh nhân và thông tin cụ thể đã được cập nhật
emit PatientUpdated(_patientAddress, "Name", _name);
emit PatientUpdated(_patientAddress, "DateOfBirth", _dob); emit PatientUpdated(_patientAddress, "BloodType", _bloodType); emit PatientUpdated(_patientAddress, "AddressLine1",
_addressLine1);
emit PatientUpdated(_patientAddress, "AddressLine2",
_addressLine2);
emit PatientUpdated(_patientAddress, "City", _city);
emit PatientUpdated(_patientAddress, "PhoneNumber",
_phoneNumber);
emit PatientUpdated(_patientAddress, "Email", _email);
emit PatientUpdated(_patientAddress, "HealthStatus",
_healthStatus);
}
function removePatient(address _patientAddress) external onlyOwner {
// Hàm removePatient được thiết kế để loại bỏ một bệnh nhân khỏi hệ thống
Trang 18// modifier Đảm bảo rằng chỉ chủ sở hữu (owner) mới có thể gọi hàm này
require(msg.sender == owner, "Only owner can remove patients"); // Chỉ chủ sở hữu mới có quyền loại bỏ bệnh nhân
delete patients[_patientAddress];
// Xóa thông tin của bệnh nhân khỏi mapping patients
// Duyệt qua mảng patientAddresses để tìm địa chỉ của bệnh nhân cần xóa và xóa nó
for uint256 i = ; i < patientAddresses.length; i++) {
if (patientAddresses[i == _patientAddress)
delete patientAddresses[i];
// delete patientAddresses[i];: Xóa địa chỉ bệnh nhân khỏi mảng patientAddresses
break;
}
}
emit PatientRemoved(_patientAddress);
// Phát ra sự kiện để thông báo rằng một bệnh nhân đã được loại
bỏ khỏi hệ thống,
// kèm theo địa chỉ của bệnh nhân đã bị xóa
}
Trang 19function getPatientCount() external view returns (uint256)
// Hàm getPatientCount được thiết kế để trả về số lượng bệnh nhân
đã được đăng ký trong hệ thống
uint256 count = 0 // ban đầu là 0
// Duyệt qua mảng patientAddresses để kiểm tra từng phần tử for uint256 i = ; i < patientAddresses.length; i++) {
// Kiểm tra xem địa chỉ bệnh nhân có khác với địa chỉ mặc định (0x0) không
// địa chỉ mặc định là
0x0000000000000000000000000000000000000000
if (patientAddresses[i != address( )) {
count++; // Mỗi khi tìm thấy một địa chỉ bệnh nhân khác
0, tăng biến count lên 1
}
}
return count;
// Trả về tổng số lượng bệnh nhân đã được đếm
}
}