Представляем вторую статью из серии «Погружение в технологию блокчейн». В этом материалы вы узнаете о медицинском проекте Digital Dentistry Exchange, который представляет из себя экосистему цифровой стоматологии.
Мы расскажем о его технологических особенностях, ответим на самые частые вопросы о смарт-контрактах и поделимся видением команды о том, какое будущее у технологии блокчейн.
Цикл статей «Погружение в технологию блокчейн»
1. Погружение в технологию блокчейн: Секреты EmerCoin.
2. Погружение в технологию блокчейн: Быстрые и безопасные транзакции.
3. Погружение в технологию блокчейн: Экосистема цифровой стоматологии.
4. Loading…
Проблема распределения ответственности и повышения качества комплексных услуг в сфере стоматологии
В современной цифровой стоматологии существует направление под названием CAD/CAM (Computer Aided Design и Computer Aided Manufacturing). Оно применяется для создания таких зуботехнических конструкций, как коронки, виниры или вкладки (очень крутой вид пломб). Процесс производства с помощью ЭВМ состоит из нескольких этапов:
1. Врач производит подготовку зуба к установке зуботехнической конструкции, снимает оттиск и формирует заказ-наряд:
2. Врач договаривается о цене с пациентом, идет предоплата.
3. Оттиск сканируется и получается цифровая трехмерная модель зубов пациента:
4. С помощью системы специализированного проектирования (САПР) на базе этой модели конструируется дизайн зуботехнической конструкции с учетом пожеланий пациента и врача.
5. После подтверждения трехмерная модель зуботехнического изделия отправляется во фрезерный центр, где ее материализуют из выбранного материала (цирконий, титан, полимер или керамика).
6. Изделие дезинфицируется и устанавливается пациенту.
Каждый этап оплачивается отдельно, но если на одном из этапов происходит ошибка, то все последующие этапы будут сделаны напрасно, хотя они уже оплачены. Казалось бы, исправить это просто: тестировать каждый этап и забыть о проблеме. Но, например, трудности выявляются на этапе установки продукта пациенту, а предыдущие этапы (сканирование, дизайн и фрезерование) уже оплачены. Это значит, что врач теряет деньги, время и нервы. Последние два пункта касаются также и пациента.
Логичным решением является создание многосторонних договоров, которые позволяют распределить ответственность между участниками CAD/CAM процесса. Здесь появляется огромный выбор различных стратегий выплат, например:
- врач выплачивает всем участникам только при успешной установке изделия;
- врач выплачивает участникам по очереди при подтверждении каждым участником предыдущего результата, можно добавить страхование, репутацию и так далее.
В итоге, сделки с несколькими активными сторонами могут быть по разному представлены, в зависимости от этого также будут ранжироваться цены на услуги.
Этот подход не был реализован ранее по нескольким причинам: создать такие формы сделок было невозможно из-за отсутствия регулятора оплат, а также из-за высокой сложности формулирования договоров с большим количеством оговорок.
Реализация идеи
Примечание: ниже представлен реальный код, написанный в рамках хакатона.
Проблему описанную выше можно решить с помощью смарт-контрактов: сложные схемы оплат упаковываются в кнопки «accept/decline/pay». Для регулировки всего процесса самым надежным решением будет система с блокчейн-архитектурой.
Так у команды был определенный бэкграунд в разработке и дизайне, для back-end был выбран фреймворк Ruby on Rails (RoR), для front-end – JavaScript-фреймворк AngularJS.
С написанием смарт-контрактов было немного сложнее, так как никто из участников ранее не сталкивался с подобной задачей. Поэтому была выбрана платформа Ethereum (инструмент для создания децентрализованных онлайн-сервисов на базе блокчейна) на основе Azure Blockchain as a Service. Смарт-контракты программировались на специальном языке Solidity.
Участники поделились двумя вопросами, которые возникли у них при работе с данным инструментом, и ответами на них.
Где хранится контракт и кто обеспечивает его корректное исполнение?
Когда смарт-контракт написан и отлажен, он помещается в цепочку блоков транзакций, и может быть проверен (но не изменен!) любым пользователем системы, если тот знает адрес по которому расположен этот смарт-контракт. Корректность самого смарт-контракта зависит от того, насколько корректно его написал программист. Если смарт-контракт был описан неверно, его нельзя исправить и придется поместить другой смарт-контракт по другому адресу.
Какова цена создания смарт-контракта?
Для создания смарт-контракта требуется израсходовать некоторое количество внутренней валюты (Eth), чем выше будет его цена, тем выше он получает приоритет у майнеров (это машины которых вычисляют криптоблоки). Майнеры нужны для того, чтобы смарт-контракт был обработан и добавлен в блокчейн. Если первый взнос будет минимальным, может возникнуть ситуация, в которой смарт-контракт никогда не будет размещен в глобальном блокчейне. Стоит обратить внимание, что также можно задать время жизни контракта.
Что нужно знать для работы с платформой Ethereum для клиентской стороны
Прежде всего, вам необходимо понять для какой платформы вы пишете. Как писали выше, в данном решении был использован фреймворк AngularJS, поэтому вся логика была помещена в контроллер, и там происходила вся работа с web3.js.
Примечание: в реальных условиях подобные операции лучше держать на защищенном сервере подальше от клиента.
Далее необходимо инициализировать подключение к программе для связи с блокчейном:
var Web3 = require('web3');
var web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider("http://адрес_сервера:8545"));
var accounts = web3.eth.accounts;
accounts
– это все аккаунты, которые задействованы в программе подключения к блокчейну (в нашем случае, это geth).
Теперь нужна функция для того, чтобы узнать баланс подключенных токенов:
function getBalance(address){
var funds = web3.eth.getBalance(address);
return funds;
}
Попробуем оплатить что-нибудь через смарт-контракт по адресу contractAddress:
function pay (amount, myToken, password, token, contractAddress){
web3.personal.unlockAccount(myToken,password);
var contract = web3.eth.contract(abi).at(contractAddress);
var res = contract.initDoctor.sendTransaction(token, {from:myToken, value:web3.toWei(amount,'ether')});
alert("you dropped to system with token "+token);
}
Примечание: для простоты был задан пароль в виде plain text, но в реальной системе так делать нельзя.
Это основные функции, которые необходимо знать для вызова смарт-контрактов. Подробности можно узнать на официальном сайте Ethereum.
Что нужно знать для написания смарт-контракта на языке Solidity
Существуют онлайн-компиляторы, так и компиляторы смарт-контрактов, поставляемых Etherium. В данном проекте решили использовать этот редактор, так как он достаточно удобный и быстрый.
Далее в блокчейне для написания смарт-контракта был использован код:
pragma solidity ^0.4.0;
contract Dental {
uint cadPrice = 10;
uint millPrice = 10;
uint digitizePrice = 10;
mapping (address => uint) doctor_balances;
mapping (address => uint) digitizer_balances;
mapping (address => uint) cad_balances;
mapping (address => uint) mill_balances;
mapping (address => uint) statuses;
//0 -start,
//1 - digitizer initialized,
//2 - cad initialized,
//3 - mill initialized,
//4 - digitizer ready,
//5 - cad_ready,
//6 - mill ready,
//7 -payed
mapping (address => address) digitizer_addresses;
mapping (address => address) cad_addresses;
mapping (address => address) mill_addresses;
function initDoctor() { //Загрузка денег
doctor_balances[ msg.sender ] += msg.value;
statuses[msg.sender] = 0;
}
function initDigitizer(address digitizerAddr) {
digitizer_addresses[msg.sender] = digitizerAddr;
digitizer_balances[msg.sender] += msg.value;
if (statuses[msg.sender] == 0) statuses[msg.sender] = 1;
}
function initCad(address cadAddr) {
cad_addresses[msg.sender] = cadAddr;
doctor_balances[ msg.sender ] -= cadPrice;
cad_balances[msg.sender] += msg.value;
if (statuses[msg.sender] == 1) statuses[msg.sender] = 1;
}
function initMill(address millAddr) {
mill_addresses[msg.sender] = millAddr;
mill_balances[msg.sender] += msg.value;
if (statuses[msg.sender] == 2) statuses[msg.sender] = 3;
}
function digitizerDone() {
if (statuses[msg.sender]==3) statuses[msg.sender] = 4;
}
function cadDone() {
if (statuses[msg.sender]==4) statuses[msg.sender] = 5;
}
function millDone() {
if (statuses[msg.sender]==5) statuses[msg.sender] = 6;
}
function doctorDone(bool happy) payable returns (bool) {
if (statuses[msg.sender]!=6) return false;
if (!happy){
doctor_balances[msg.sender] += digitizer_balances[msg.sender];
doctor_balances[msg.sender] += cad_balances[msg.sender];
doctor_balances[msg.sender] += mill_balances[msg.sender];
digitizer_balances[msg.sender] = 0;
cad_balances[msg.sender] = 0;
mill_balances[msg.sender] = 0;
return false;
}
bool digitizerOk = digitizer_addresses[msg.sender].send(digitizer_balances[msg.sender]);
digitizer_balances[msg.sender] = 0;
bool cadOk = cad_addresses[msg.sender].send(cad_balances[msg.sender]);
cad_balances[msg.sender] = 0;
bool millOk = mill_addresses[msg.sender].send(mill_balances[msg.sender]);
mill_balances[msg.sender] = 0;
return (digitizerOk && cadOk && millOk);
}
}
Разберем его подробнее:
1. Сначала указываем версию Solidity и объявляем контракт:
pragma solidity ^0.4.0;
contract Dental {
2. задаем стоимость услуг 3D-сканирования, дизайна и фрезерования:
uint cadPrice = 10;
uint millPrice = 10;
uint digitizePrice = 10;
3. Создаем массивы балансов для оплаты участников процесса:
mapping (address => uint) doctor_balances;
mapping (address => uint) digitizer_balances;
mapping (address => uint) cad_balances;
mapping (address => uint) mill_balances;
4. Указываем статусы:
mapping (address => uint) statuses;
//0 - start,
//1 - digitizer initialized,
//2 - cad initialized,
//3 - mill initialized,
//4 - digitizer ready,
//5 - cad_ready,
//6 - mill ready,
//7 -payed
5. Создаем массивы аккаунтов участников процесса (без врачей):
mapping (address => address) digitizer_addresses;
mapping (address => address) cad_addresses;
mapping (address => address) mill_addresses;
6. Инициализируем врача, им будет считаться отправитель. Обратите внимание, что он может брать новые заказы, только если у него указан статус «еще не начал» или «заказ завершен»:
function initDoctor() { //Загрузка денег
if (statuses[msg.sender] == 0 || statuses[msg.sender] == 7){
doctor_balances[ msg.sender ] = msg.value;
statuses[msg.sender] = 0;
}
}
7. Инициализируем сканировщика, который будет задействован, если у врача стоит статус «еще не начал»:
function initDigitizer(address digitizerAddr) {
digitizer_addresses[msg.sender] = digitizerAddr;
digitizer_balances[msg.sender] = msg.value;
if (statuses[msg.sender] == 0) statuses[msg.sender] = 1;
}
8. Аналогично повторяем с дизайном:
function initCad(address cadAddr) {
cad_addresses[msg.sender] = cadAddr;
doctor_balances[ msg.sender ] -= cadPrice;
cad_balances[msg.sender] = msg.value;
if (statuses[msg.sender] == 1) statuses[msg.sender] = 1;
}
9. Аналогично повторяем с фрезеровщиком:
function initMill(address millAddr) {
mill_addresses[msg.sender] = millAddr;
mill_balances[msg.sender] += msg.value;
if (statuses[msg.sender] == 2) statuses[msg.sender] = 3;
}
10. Далее подтверждаем работу сканировщика:
function digitizerDone() {
if (statuses[msg.sender]==3) statuses[msg.sender] = 4;
}
11. Подтверждаем работу дизайнера:
function cadDone() {
if (statuses[msg.sender]==4) statuses[msg.sender] = 5;
}
12. Подтверждаем работу фрезеровщика:
function millDone() {
if (statuses[msg.sender]==5) statuses[msg.sender] = 6;
}
13. Врач может принять или не принять работу. В последнем случае все деньги будут возвращены на его счет. ). Если работа еще не отфрезерована, то ничего не происходит. Если врач принимает работу, деньги отправляются на счета участников:
function doctorDone(bool happy) payable returns (bool) {
if (!happy){
doctor_balances[msg.sender] += digitizer_balances[msg.sender];
doctor_balances[msg.sender] += cad_balances[msg.sender];
doctor_balances[msg.sender] += mill_balances[msg.sender];
digitizer_balances[msg.sender] = 0;
cad_balances[msg.sender] = 0;
mill_balances[msg.sender] = 0;
return true;
}
if (statuses[msg.sender]!=6) return false;
bool digitizerOk = digitizer_addresses[msg.sender].send(digitizer_balances[msg.sender]);
digitizer_balances[msg.sender] = 0;
bool cadOk = cad_addresses[msg.sender].send(cad_balances[msg.sender]);
cad_balances[msg.sender] = 0;
bool millOk = mill_addresses[msg.sender].send(mill_balances[msg.sender]);
mill_balances[msg.sender] = 0;
if (digitizerOk && cadOk && millOk) statuses[msg.sender]=7;
return (digitizerOk && cadOk && millOk);
}
}
Слово команде проекта Digital Dentistry Exchange
Мы спросили участников проекта, какое будущее они видят у технологии блокчейн:
«Технология блокчейн – потенциально самая подходящая технология для проведения транзакций любых типов, начиная от финансовых услуг заканчивая приготовлением еды. Единственным дополнением к блокчейну должен быть доработанный механизм proof-of-work, который будет приносить пользу людям или науке (например, давняя задача поиска целых значений параметров a,b,c в выражении a^3+b^3+c^3=33).
На данный момент система блокчейна может быть идеально интегрирована в систему оказания услуг, где результаты могут быть измерены (комплексные услуги в медицине, производстве, онлайн-продажах или достижение определенных метрик и, возможно, судебная арбитражная система).
Количество возможных приложений может быть огромным – главное тестировать идеи, реализации и активно их внедрять. Также было бы не лишним внедрение правового регулирования и ISO стандарта систем с архитектурой блокчейн.»
На фотографии ниже авторы материала: Константин Скобельцын, Виталий Дементьев, Ринат Хатипов, Айдар Нигматжанов, Роман Варнава.
Автор: Microsoft