Надежно храните и делитесь своими медицинскими записями с помощью смарт-контрактов
Использование блокчейна для общедоступных данных: сложный вопрос
Вопрос о том, подходит ли блокчейн для общедоступных данных, сложен, и не существует универсального решения. Тем не менее, есть несколько возможных решений, которые можно было бы рассмотреть:
- Частная сеть. Одним из решений проблем конфиденциальности, связанных с технологией блокчейна, является использование частного блокчейна вместо общедоступного. Частные блокчейны могут обеспечить преимущества технологии блокчейн, такие как неизменность и прозрачность, а также обеспечить конфиденциальность и безопасность данных.
- Гибридный подход. Другой вариант — использовать гибридный подход, при котором конфиденциальные данные хранятся в частной цепочке блоков, а неконфиденциальные данные хранятся в общедоступной цепочке блоков. Это позволяет вам пользоваться преимуществами обоих типов блокчейна, обеспечивая при этом безопасность конфиденциальной информации.
- Многоуровневая архитектура. Многоуровневую архитектуру можно использовать для отделения конфиденциальных данных от неконфиденциальных данных, обеспечивая безопасное хранение конфиденциальной информации, в то время как неконфиденциальные данные могут храниться в общедоступной цепочке блоков.
- Шифрование: Шифрование можно использовать для обеспечения безопасности конфиденциальных данных. Это может обеспечить дополнительный уровень безопасности и защитить от несанкционированного доступа к конфиденциальной информации.
Разработка смарт-контрактов
Определите переменные, используемые для хранения данных о владельце контракта, медицинских записях, авторизованных пользователях и ограничениях доступа к каждой записи. Переменные records
и accessRestrictions
представляют собой сопоставления, хранилища ключей и значений, в которых ключи и значения могут быть любого типа.
Отображение records
сопоставляет ключ типа bytes32
со значением типа Record
, которое является структурой, определенной позже в контракте. Отображение authorizedUsers
сопоставляет адрес с логическим значением, указывающим, может ли пользователь получать доступ к записям. Отображение accessRestrictions
сопоставляет ключ bytes32
со значением типа Restrictions
, которое также является структурой, определенной позже в контракте.
pragma solidity ^0.7.0; // It is important to thoroughly review and test any smart contract before using it. contract MedicalRecord { // The address of the owner of the contract. address private owner; // The medical records that are being stored. mapping(bytes32 => Record) private records; // The authorized users who are allowed to access the records. mapping(address => bool) private authorizedUsers; // The restrictions on access to each record. mapping(bytes32 => Restrictions) private accessRestrictions;
Ниже данные строки определяют структуры Record
и Restrictions
, которые используются для хранения данных для одной медицинской карты и ограничения доступа к одной карте соответственно. Структура Record
имеет два поля: data
, значение bytes
, в котором хранятся фактические данные медицинской карты, и timestamp
, значение uint256
, в котором хранится время добавления или последнего обновления записи. Структура Restrictions
имеет три поля: authorizedUsers
— сопоставление, в котором хранятся пользователи, которым разрешен доступ к записи, minRole
— значение uint8
, в котором хранится минимальная роль, необходимая для доступа к записи, и expirationDate
— поле uint256
. значение, в котором хранится дата истечения срока действия записи.
// The roles that a user can have. // The data for a single medical record. struct Record { bytes data; uint256 timestamp; } // The restrictions on access to a single record. struct Restrictions { // The users who are allowed to access the record. mapping(address => bool) authorizedUsers; // The minimum role required to access the record. uint8 minRole; // The expiration date for the record. uint256 expirationDate; }
Теперь определите тип enum
(перечисление) с именем Roles
, который используется для представления различных ролей, которые может иметь пользователь. enum
имеет три возможных значения: Patient
, Doctor
и Administrator
.
// The roles that a user can have. enum Roles { Patient, Doctor, Administrator }
Создайте имя сопоставления userRoles
, которое сопоставляет адрес со значением типа Roles
, которое enum
определено ранее. Это сопоставление используется для хранения роли каждого пользователя. Вот как это выглядит:
// The role of each user. mapping(address => Roles) private userRoles;
Создайте конструктор контракта, который вызывается при развертывании контракта. Конструктор устанавливает переменную owner
в адрес пользователя, развертывающего контракт. Вот как это сделать:
// The constructor sets the owner of the contract. constructor() public { owner = msg.sender; }
Теперь создайте функции, позволяющие владельцу контракта авторизовать или отозвать авторизацию пользователя для доступа к записям и установить роль пользователя. Отображение authorizedUsers
обновляется, чтобы отразить изменения в статусе авторизации. Отображение userRoles
также обновляется, чтобы отразить изменения роли. Вот как это выглядит:
// Only the owner can authorize a user to access records. function authorizeUser(address user) public onlyOwner { authorizedUsers[user] = true; } // Only the owner can remove a user's authorization to access records. function removeAuthorization(address user) public onlyOwner { authorizedUsers[user] = false; } // Only the owner can set the role of a user. function setUserRole(address user, Roles role) public onlyOwner { userRoles[user] = role; }
Теперь создайте функцию, которая позволит авторизованным пользователям получать медицинскую карту. Функция принимает на вход ключ типа bytes32
, который используется для идентификации записи. Функция сначала извлекает запись и ее ограничения из хранилища, используя сопоставления records
и accessRestrictions
. Затем функция проверяет, не предшествует ли текущее время дате истечения срока действия записи, равна ли роль пользователя минимальной роли, необходимой для доступа к записи, или выше, и имеет ли пользователь право доступа к записи.
Если какое-либо из этих условий не выполняется, функция выдает ошибку. Функция возвращает данные для записи, если все условия соблюдены. Вот что вы можете увидеть:
// Only authorized users can access a record if the current time is before the record's expiration date // and the user's role is equal to or higher than the minimum role required to access the record. function getRecord(bytes32 key) public view onlyAuthorized returns (bytes memory) { Record storage record = records[key]; Restrictions storage restrictions = accessRestrictions[key]; require(block.timestamp < restrictions.expirationDate, "This record has expired."); require(uint8(userRoles[msg.sender]) >= restrictions.minRole, "Your role is not high enough to access this record."); require(restrictions.authorizedUsers[msg.sender], "You are not authorized to access this record."); return record.data; }
Функция setRecord
позволяет владельцу добавлять или обновлять медицинскую карту. Функция принимает ключ типа bytes32
и данные для записи в качестве входных данных и дату истечения срока действия. Это выглядит так:
// Only the owner can add or update a record. function setRecord(bytes32 key, bytes memory data, uint256 expirationDate, uint8 minRole, address[] memory authorizedUsers) public onlyOwner { Record storage record = records[key]; record.data = data; record.timestamp = block.timestamp; Restrictions storage restrictions = accessRestrictions[key]; restrictions.expirationDate = expirationDate; restrictions.minRole = minRole; for (uint i = 0; i < authorizedUsers.length; i++) { restrictions.authorizedUsers[authorizedUsers[i]] = true; } }
Функция deleteRecord
позволяет владельцу удалить медицинскую карту. Функция принимает на вход ключ типа bytes32
и удаляет запись и ее ограничения из хранилища с помощью ключевого слова delete
. Вот как это сделать:
// Only the owner can delete a record. function deleteRecord(bytes32 key) public onlyOwner { delete records[key]; delete accessRestrictions[key]; }
Следующие строки определяют две функции modifier
: onlyOwner
и onlyAuthorized
. modifier
— это функция, которую можно использовать для изменения поведения других функций. Модификатор onlyOwner
можно применить к функции, чтобы ограничить вызов функции только владельцем контракта.
Модификатор onlyAuthorized
можно применить к функции, чтобы ограничить вызов функции только авторизованными пользователями. Функции modifier
используют ключевое слово require
для принудительного применения ограничений. Если условия, указанные в операторе require
, не выполняются, функция выдает ошибку.
// Only the owner can call these functions. modifier onlyOwner { require(msg.sender == owner, "Only the owner can perform this action."); _; } // Only authorized users can call these functions. modifier onlyAuthorized { require(authorizedUsers[msg.sender], "You are not authorized to perform this action."); _; } }
Полный код
Этот контракт позволяет владельцу хранить медицинские записи, устанавливать ограничения на доступ к каждой записи и разрешать пользователям доступ к записям. Ограничения включают дату истечения срока действия, минимальную требуемую роль и список авторизованных пользователей. Контракт также имеет сопоставление для хранения роли каждого пользователя.
Внешний интерфейс и полный код доступны на GitHub:https://github.com/ac12644/Medical-Records.git