Вы здесь

Как построить систему цепочек поставок по производству автомобилей с использованием Ethereum

Здесь у себя, в компании Daitan, мы всегда ищем новые технологии, которые могут помочь нашим клиентам более эффективно решить их проблемы. В последнее время наше внимание и внимание наших клиентов привлек блокчейн.

Как построить систему цепочек поставок по производству автомобилей с использованием Ethereum

Цель нашей статьи – показать практический способ применения цепочки поставок на базе блокчейн-платформы!

Эта система используется для решения одной из проблем, для которой, по моему мнению, применение блокчейна имеет самое большое значение: цепь поставок.

Эта область применения много исследовалась в последнее время, и крупные компании уже проводят эксперименты с этой сферой для своих работ.

Использование блокчейна для решения этой проблемы является хорошей альтернативой, поскольку с ее помощью мы можем извлечь выгоду из таких ее свойств, как прозрачность и эффективность отслеживания источников происхождения, которые присущи этой технологии.

Поскольку мы постарались максимально упростить эту статью, а не описать весь проект целиком, основной акцент будет сделан на самой проблеме.

В конце концов, у нас по-прежнему имеется замкнутая система, которая может продемонстрировать применимость этой технологии к этому конкретному набору проблем.

Выбор платформы

В настоящее время существует множество платформ, которые позволяют сделать свой собственный блокчейн или использовать уже имеющийся публичный блокчейн для ваших собственных проектов, поэтому мы воспользуемся им вместо того, чтобы строить новый блокчейн с нуля.

Эти проекты имеют хорошую поддержку как со стороны предприятий, так и со стороны открытых сообществ, поэтому мы считаем, что использование одного из них является наиболее практичным путем для решения большинства проблем, позволяя нам сосредоточиться на бизнес-логике, а не на инфраструктуре.

Для своей демо-версии мы выбрали проект Ethereum. Это популярная платформа, и все доступные инструменты разработки позволяют легко реализовать решения.

История производства

Мы создали домен, но что конкретно мы намерены дальше делать?
Давайте опишем простую проблему производства автомобилей и участников процесса.

Во-первых, у нас есть завод по производству деталей, который отвечает за изготовление колес, изделий для корпуса, двигателей и коробок передач. Завод сообщает об изготовлении каждой детали, используя смарт-контракт под названием «ProductManagement» (Управление продуктом), в котором будет дано подробное описание по каждой детали и продукту.

Помимо этого, завод делает заявление о том, что он является владельцем определенной детали, через функцию «ChangeOwnership» (Поменять собственника), заложенную в смарт-контракте, в котором будет храниться история о владельце каждой детали и продукта.

Двигаемся дальше по цепочке: у нас есть автозавод, который покупает детали у завода по производству деталей для последующего изготовления автомобилей. Контракт «ChangeOwnership» - это место, в котором мы храним сведения об этой операции, поэтому мы используем другой метод для того, чтобы позволить заводу по производству деталей передать право собственности на детали автозаводу.

Право собственности контролируется контрактом «ChangeOwnership», и поэтому автомобильный завод оформляет это право собственности на себя.

Наконец, мы добавляем к нашему сценарию дилеров, и они могут покупать автомобили у завода, а последний может передать право владения автомобилем с помощью «ChangeOwnership». Блокчейн хранит сведения о каждой транзакции, в которой был задействован этот автомобиль или любая из его составных частей, поэтому дилер (или любая другая сторона) может отслеживать все, через что прошел каждый конкретный элемент. В нашем случае это отслеживание будет осуществляться путем просмотра событий, генерируемых транзакциями. Все будет понятно, когда мы начнем анализировать код.

Полная производственная схема приведена на картинке ниже:


Цепочка поставок по производству автомобилей

Мы знаем, что делать, но нам все еще нужно вооружиться некоторыми инструментами, чтобы обеспечить дальнейшее развитие этой технологии.

Среда и инструменты

Во-первых, нам нужно провести четкое различие между сетями экосистемы Ethereum. Главная сеть (так называемая Mainnet) - это то место, где находятся реальные приложения и где каждая единица эфира имеет реальную ценность.

Это означает, что все, что вы туда записываете, должно существовать до тех пор, пока существует сам Ethereum. Дополнительно получить эфир можно только с помощью майнинга или через его покупку за реальные деньги.

Использование этой сети для разработки демо-версий кажется плохой идеей, поэтому есть другие сети, которые лучше в плане поддержки разработки. Эти сети могут быть публичными сетями, как, например, Rinkeby, или вы можете создать свою собственную сеть Ethereum!

Несмотря на то, что использование открытой тестовой сети типа Rinkeby лучше всего подходит для проверки нашего даппа (децентрализованного приложения), мы создадим свою собственную сеть, чтобы сократить время согласования транзакций и максимально упростить разработку.

Инструмент, который мы будем использовать для создания нашей сети, называется Ganache.

Ganache – это простой инструмент, который создает локальную сеть Ethereum, и вы можете подключаться к ней так же, как и к основной сети. Он также предоставляет вам 10 счетов с 100 эфирами каждый раз, когда вы его запускаете.

Вместо пользовательского интерфейса Ganache я буду использовать ganache-cli, версию командной строки Ganache, которая является инструментом на основе NodeJS и может быть установлена с npm:

npm install -g ganache-cli

Для запуска просто выполните ganache-cli, и вы будете готовы к дальнейшей работе! При запуске CLI для ваших кошельков сгенерируется строка «mnemonic». Mnemonic – это фраза из 12 слов, которая является корнем для создания закрытых ключей счетов и, следовательно, кошельков.

Выходные данные выглядят примерно так:

1_Wnlj5Sl_5e-NTos9HPwc3A.png

Сохраните mnemonic: позже она вам понадобится. Всякий раз, когда вам нужно будет снова запустить Ganache, вы можете сохранять одни и те же счета, указывая mnemonic с параметром -m:

ganache-cli -m "now frame tenant chronic oven cube minute immune leaf clock demand volume"

Примечание: мнемонические фразы, созданные Ganache, небезопасны и не должны использоваться для кошельков в сети Ethereum

Теперь, когда у нас есть наша собственная сеть, нам нужно суметь протестировать ее и развернуть в ней наши контракты. Это выполняется с помощью другого инструмента под названием Truffle из того же пакета для разработки, что и Ganache. Truffle также можно установить с помощью пакетного менеджера npm, поэтому просто жмите на пуск:

npm install -g truffle

Для подготовки структуры проекта мы будем использовать Truffle, поэтому запускаем truffle init и проверяем созданную структуру папок:

ethereum-supply-chain
|-contracts
| — Migrations.sol
|-migrations
| — 1_initial_migration.js
|-test
truffle-config.js
  • Контракты (contracts): содержит код для наших смарт-контрактов
  • Миграции (Migrations): содержит инструкции по развертыванию для наших контрактов
  • Проверка (Test): содержит информацию о проверках наших контрактов
  • Truffle-config.js (или truffle.js, в зависимости от вашей операционной системы): главный конфигурационный файл, указывает на те сети Ethereum, которые мы можем развернуть

Конфигурационный файл идет вместе с большим количеством информации, но большая ее часть комментируется. Чтобы добавить нашу локальную сеть к вариантам для развертывания, просто раскомментируйте следующую часть (строки 49-53):

development: {
     host: "127.0.0.1",     // Localhost (default: none)
     port: 8545,            // Standard Ethereum port (default: none)
     network_id: "*",       // Any network (default: none)
}

Наконец, нам нужно предоставить интерфейс нашим пользователям, чтобы они могли взаимодействовать с сетями Ethereum.

Для этого, как вариант, можно установить Metamask, плагин браузера, который управляет кошельками, а также позволяет веб-системам общаться с сетями Ethereum.

Сразу после установки Metamask предоставляет интерфейс для проверки денежных средств на кошельках в разных сетях. Когда веб-системе требуется провести операцию оплаты, Metamask запрашивает разрешение у пользователя.

Чтобы установить его, просто зайдите на сайт разработчиков и выберите расширение для вашего браузера.

После установки Metamask необходимо создать или импортировать кошелек, поэтому выберите «import with seed phrase» и вставьте мнемоническую фразу (mnemonic), которую вы получили от ganache-cli.

Примечание: Плагин Metamask в настоящее время представлен в бета-версии, поэтому имейте это в виду, когда используете его, и следуйте приведенным после конфигурации инструкциям.

Это все, что нам сейчас нужно, а теперь давайте перейдем к коду!

Практическое применение смарт-контрактов

Первое, что нам нужно сделать, это реализовать логику каждого смарт-контракта, поэтому мы начинаем с «ProductManagement» (Управление продуктом).

В этом контракте должен быть предусмотрен один метод для регистрации деталей, а другой для регистрации продуктов, даже если требования для каждой операции очень похожи.
Нам это необходимо для того, чтобы убедиться, что в наличии имеются все детали, необходимые для создания нового продукта. Таким образом, у нас в распоряжении могут быть следующие методы:

  • Регистрация деталей: создание мэппинга с учетом сведений о самой детали (тип, серийный номер и дата изготовления), заводе-изготовителе (идентификатор завода) и текущем владельце (идентификатор владельца).
  • Регистрация продукта: создание мэппинга по аналогии с регистрацией деталей; плюс к ней еще идут идентификаторы каждой из деталей, находящихся в составе продукта.
  • Геттеры для мэппингов, чтобы мы могли проверить наличие деталей и продуктов и получить подробные сведения о них.

Код контракта, который нам нужно реализовать, выглядит следующим образом:

pragma solidity >=0.4.21 <0.6.0;
contract ProductManagement {
    struct Part{
        address manufacturer;
        string serial_number;
        string part_type;
        string creation_date;
    }
    struct Product{
        address manufacturer;
        string serial_number;
        string product_type;
        string creation_date;
        bytes32[6] parts;
    }
    mapping(bytes32 => Part) public parts;
    mapping(bytes32 => Product) public products;
    constructor() public {
    }
    function concatenateInfoAndHash(address a1, string memory s1, string memory s2, string memory s3) private returns (bytes32){
        //First, get all values as bytes
        bytes20 b_a1 = bytes20(a1);
        bytes memory b_s1 = bytes(s1);
        bytes memory b_s2 = bytes(s2);
        bytes memory b_s3 = bytes(s3);
        //Then calculate and reserve a space for the full string
        string memory s_full = new string(b_a1.length + b_s1.length + b_s2.length + b_s3.length);
        bytes memory b_full = bytes(s_full);
        uint j = 0;
        uint i;
        for(i = 0; i < b_a1.length; i++){
            b_full[j++] = b_a1[i];
        }
        for(i = 0; i < b_s1.length; i++){
            b_full[j++] = b_s1[i];
        }
        for(i = 0; i < b_s2.length; i++){
            b_full[j++] = b_s2[i];
        }
        for(i = 0; i < b_s3.length; i++){
            b_full[j++] = b_s3[i];
        }
        //Hash the result and return
        return keccak256(b_full);
    }
    function buildPart(string memory serial_number, string memory part_type, string memory creation_date) public returns (bytes32){
        //Create hash for data and check if it exists. If it doesn't, create the part and return the ID to the user
        bytes32 part_hash = concatenateInfoAndHash(msg.sender, serial_number, part_type, creation_date);
        require(parts[part_hash].manufacturer == address(0), "Part ID already used");
        Part memory new_part = Part(msg.sender, serial_number, part_type, creation_date);
        parts[part_hash] = new_part;
        return part_hash;
    }
    function buildProduct(string memory serial_number, string memory product_type, string memory creation_date, bytes32[6] memory part_array) public returns (bytes32){
        //Check if all the parts exist, hash values and add to product mapping.
        uint i;
        for(i = 0;i < part_array.length; i++){
            require(parts[part_array[i]].manufacturer != address(0), "Inexistent part used on product");
        }
        //Create hash for data and check if exists. If it doesn't, create the part and return the ID to the user
        bytes32 product_hash = concatenateInfoAndHash(msg.sender, serial_number, product_type, creation_date);
        require(products[product_hash].manufacturer == address(0), "Product ID already used");
        Product memory new_product = Product(msg.sender, serial_number, product_type, creation_date, part_array);
        products[product_hash] = new_product;
        return product_hash;
    }
    function getParts(bytes32 product_hash) public returns (bytes32[6] memory){
        //The automatic getter does not return arrays, so lets create a function for that
        require(products[product_hash].manufacturer != address(0), "Product inexistent");
        return products[product_hash].parts;
    }
}

Мы определяем структуры для деталей и продуктов, которые отображают всю информацию, необходимую для «создания» наших деталей и продуктов, и после этого добавляем мэппинги, которые будут хранить информацию обо всех зарегистрированных элементах.

Метод создания деталей (далее как «метод buildProduct») прост: он использует вспомогательную функцию для объединения адреса отправителя и информации о детали в массиве байтов и вычисления хэша. Этот хэш является ключом, используемым при регистрации и последующем запросе данных, поэтому мы возвращаем его для содействия в разработке.

Поскольку транзакции в Ethereum не проверяются и не выполняются при вызове смарт-контракта, мы получаем хэш транзакции и не можем использовать его для нашего веб-приложения, но мы можем выполнить вызов вместо транзакции, чтобы легко проверить результаты.

В реальной системе мы ждали бы, что изготовитель предоставит хэш о детали вместе с самой деталью, но мы не станем рассматривать этот механизм в этой статье. Мы знаем информацию, используемую для создания хэша, поэтому мы можем вычислить ее, когда нам это нужно; как раз этим мы и занимаемся при работе с тестовым кодом, а также веб-приложением.

Мы не будем описывать тестовый код, чтобы не перегружать статью информацией, а проверить его в нашем хранилище!

Метод buildProduct – это просто расширенный метод buildPart за счет добавления простой проверки для гарантии того, что все детали были зарегистрированы, перед тем, как создать продукт.

Говоря о коде, стоит отметить две вещи:

  • Solidity автоматически генерирует геттеры для открытых мэппингов, поэтому нам не нужно беспокоиться об этом!
  • Беспокоиться надо при возвращении значения массива: детали нашего продукта – именно этот случай. Для решения этой проблемы мы создали функцию «getParts» (Получить детали).

Продолжая нашу работу, мы будем кодировать контракт «ChangeOwnership». У него простая цель: управлять передачей деталей и продуктов между заинтересованными сторонами.

Так как мы будем использовать ID для операции передачи прав собственности, мы можем использовать один метод для производителей, чтобы зарегистрировать их «первоначальное право собственности», а другой метод, чтобы передать право собственности другим сторонам.

Нам просто нужно получить параметр, который позволил бы нам выбирать, что регистрировать – детали или продукты, чтобы знать, какой мэппинг проверять по контракту «ProductManagement», а также где хранить сведения о текущем владельце изделия. Код выглядит следующим образом:

pragma solidity >=0.4.21 <0.6.0;
contract ChangeOwnership {
    enum OperationType {PART, PRODUCT}
    mapping(bytes32 => address) public currentPartOwner;
    mapping(bytes32 => address) public currentProductOwner;
    event TransferPartOwnership(bytes32 indexed p, address indexed account);
    event TransferProductOwnership(bytes32 indexed p, address indexed account);
    ProductManagement private pm;
    constructor(address prod_contract_addr) public {
        //Just create a new auxiliary contract. We will use it to check if the part or product really exist
        pm = ProductManagement(prod_contract_addr);
    }
    function addOwnership(uint op_type, bytes32 p_hash) public returns (bool) {
        if(op_type == uint(OperationType.PART)){
            address manufacturer;
            (manufacturer, , , ) = pm.parts(p_hash);
            require(currentPartOwner[p_hash] == address(0), "Part was already registered");
            require(manufacturer == msg.sender, "Part was not made by requester");
            currentPartOwner[p_hash] = msg.sender;
            emit TransferPartOwnership(p_hash, msg.sender);
        } else if (op_type == uint(OperationType.PRODUCT)){
            address manufacturer;
            (manufacturer, , , ) = pm.products(p_hash);
            require(currentProductOwner[p_hash] == address(0), "Product was already registered");
            require(manufacturer == msg.sender, "Product was not made by requester");
            currentProductOwner[p_hash] = msg.sender;
            emit TransferProductOwnership(p_hash, msg.sender);
        }
    }
    function changeOwnership(uint op_type, bytes32 p_hash, address to) public returns (bool) {
      //Check if the element exists and belongs to the user requesting ownership change
        if(op_type == uint(OperationType.PART)){
            require(currentPartOwner[p_hash] == msg.sender, "Part is not owned by requester");
            currentPartOwner[p_hash] = to;
            emit TransferPartOwnership(p_hash, to);
        } else if (op_type == uint(OperationType.PRODUCT)){
            require(currentProductOwner[p_hash] == msg.sender, "Product is not owned by requester");
            currentProductOwner[p_hash] = to;
            emit TransferProductOwnership(p_hash, to);
            //Change part ownership too
            bytes32[6] memory part_list = pm.getParts(p_hash);
            for(uint i = 0; i < part_list.length; i++){
                currentPartOwner[part_list[i]] = to;
                emit TransferPartOwnership(part_list[i], to);
            }
        }
    }
}

Мы используем версию «ProductManagement» для запроса сведений о деталях и продуктах при каждой попытке взаимодействия с ними. Это подчеркивает важный аспект смарт-контрактов: вы можете использовать их для вызова других смарт-контрактов! Один из вариантов сделать это – объявить контракт ABI в начале файла контракта, но только для деталей, затребованных вашим контрактом. В нашем случае это означает:

//Add ProductManagement ABI to allow calls
contract ProductManagement{
    struct Part{
        address manufacturer;
        string serial_number;
        string part_type;
        string creation_date;
    }
    struct Product{
        address manufacturer;
        string serial_number;
        string product_type;
        string creation_date;
        bytes32[] parts;
    }
    mapping(bytes32 => Part) public parts;
    mapping(bytes32 => Product) public products;
    function getParts(bytes32 product_hash) public returns (bytes32[6] memory) {}
}

Чтобы указать на правильный контракт, нам просто нужно передать адрес контракта при создании его версии, как это:
pm = ProductManagement(prod_contract_add);

Продолжая обзор кода «ChangeOwnership», мы также можем видеть, что мы определяем два события: TransferPartOwnership и TransferProductOwnership. События могут регистрироваться с помощью транзакций, так что это будет ядром нашей функции «отслеживания».

Всякий раз, когда деталь или продукт будут успешно переводиться на другой аккаунт, мы будем выпускать событие.

Возьмем функцию «addOwnership» (Добавить собственника) в качестве примера: мы подтверждаем, что элемент существует; затем выясняем, зарегистрирован он или нет, и подтверждаем, что производителем является именно то лицо, которое запрашивает право собственности. Проверив все это, мы затем сохраняем производителя в качестве владельца детали и записываем это в блокчейн Ethereum как событие. Позже мы можем получить сведения о событиях, связанных с этой деталью, из ее хэша и увидеть все операции передачи.

Еще один момент, который следует упомянуть относительно этого кода, это функция «changeOwnership» (Поменять владельца): всякий раз, когда автомобиль меняет владельца, мы также меняем владельца деталей, входящих в состав этого авто. Но хватит уже говорить о коде: давайте посмотрим, как его развернуть.

Развертывание контракта

Чтобы перенести наши контракты на Ethereum, нам нужно создать простой файл для развертывания в папке «deployments» (развертывания). Мы можем использовать файл «1_initial_migration.js», созданный Truffle, поэтому наш код принимает вид:

var Migrations = artifacts.require("./Migrations.sol");
var ProductManagement = artifacts.require("./ProductManagement.sol");
var ChangeOwnership = artifacts.require("./ChangeOwnership.sol");
module.exports = function(deployer) {
  deployer.deploy(Migrations);
  deployer.deploy(ProductManagement)
  .then(function(){
    return deployer.deploy(ChangeOwnership, ProductManagement.address);
  })
};

Мы можем, наконец, развернуть наш код в нашей локальной сети Ethereum, запустив:

truffle migrate -network development

При запуске вы, вероятно, заметите, что терминал ganache-cli выводит много сообщений, в том числе:

Транзакция: 0x9fe6d2ece9cdca2f12b574ead7abb7bea7feab316f5cd6ebbd5b713e76850a1d
Созданный контракт: 0xb6a3c3cf9d1e27e43e5fb12e505d79764748edbe

Они представляют адреса наших контрактов, поэтому сохраните их, чтобы иметь возможность позже связаться с ними. Нам понадобится этот адрес в нашем веб-интерфейсе!

Практическое использование веб-интерфейса

Теперь оба смарт-контракта готовы в нашей системе, и все, что нам нужно, это интерфейс, чтобы использовать их.

Мы сделали страницу для каждой роли в нашем сценарии; таким образом, у нас есть «Part Factory View» (взгляд со стороны завода-изготовителя деталей), «Car Factory View» (взгляд со стороны автозавода) и «Dealer View» (взгляд со стороны дилера). Мы не будем подробно вдаваться в специфику этих ролей, цель которых - осуществление взаимодействия, но давайте приведем краткий обзор, чтобы у вас был стимул проверить код!

Действия со стороны завода-изготовителя деталей, такие как, например, регистрация деталей, добавление собственника и передача права владения, можно выполнить на интерфейсе, показанном ниже. Любопытно отметить, что Metamask просит разрешения на каждую транзакцию, которую мы совершаем.


Интерфейс изготовления детали

Если смотреть на вещи с точки зрения производителя автомобилей, у нас есть список деталей, составленный из записей в блокчейне; потом есть детали, отобранные для сборки автомобиля, сам созданный автомобиль; и, наконец, мы передаем право собственности дилеру. Аналогично заводу-изготовителю деталей, автозавод также имеет свой собственный интерфейс, показанный ниже. Все взаимодействия с Ethereum происходят с использованием хэша детали/автомобиля, созданного на базе их свойств.


Интерфейс изготовления автомобиля

Последними в этой цепочке идут дилеры. В нашего примере все очень просто: мы можем просто проверить автомобили и детали на предмет истории их владельцев. На картинке ниже все очень подробно расписано:


Страница дилера, где приведена история владения автомобилями и деталями

Дополнительно мы используем библиотеку web3 для вызова опций наших смарт-контрактов. Библиотека предоставляет нам объекты, представляющие наши контракты и опции, и для этого нам нужно только установить:

  • Сетевое расположение
  • Контракт ABI (определение смарт-контракта)
  • Адрес контракта
  • Кошелек для операций

По умолчанию Ganache-cli запускает сеть на порту 8545, и ABI генерируется каждый раз, когда вы компилируете и развертываете свои контракты (но только когда мы обновляем код, поэтому нам не нужно менять это).

Если вам когда-нибудь нужно будет внести изменение, возьмите значение, сохраненное в папке «build» в закладке Установки.
Адрес контракта мы должны указать с сохраненными ранее значениями, поэтому замените следующие строки на нужные вам значения:

window.pm.options.address = '0xE5987169978243A040fba66245E982D884108A70'

window.co.options.address = "0x5F064EDfd972D3Cd9A129b8DFE96Ea7fEe5Dd000"

Теперь, когда у нас есть наша страница, готовая к взаимодействию с нашими смарт-контрактами, нам просто нужно подготовить функции, которые используют объекты, предоставляемые web3, и наша система завершена!

Функции в основном получают данные из полей ввода на странице, а затем вызывают функции с ними в качестве параметров. Полный код слишком большой, чтобы уместиться в этой статье, но давайте проверим только две части, которые объясняют большинство взаимодействий с блокчейном. Первая – это:

window.co.methods.currentPartOwner(item).call({ from: window.accounts[0] }, function (error, result) {

window.co.methods.addOwnership(0, item).send({ from: window.accounts[0], gas: 1000000 }, function (error, result) {

Объект «window.co» является нашим контрактом «ChangeOwnership», а «currentPartOwner» и «addOwnership» являются опциями, предоставляемыми этим контрактом.
Разница здесь в функции, используемой для их вызова: call vs send (вызвать Vs отправить).

Web3 1.0 требует, чтобы вы указывали тип взаимодействия, которое вы хотите выполнить с блокчейном: чтения или транзакции.

Поэтому всякий раз, когда вы используете опцию с функцией «call», вы просто считываете данные с блокчейна; за это не взимается эфир, и оно не меняет состояние цепи.

С другой стороны, если вы используете функцию «send» (отправить), вы должны отправить газ для выполнения операции, и это создает транзакцию. Как мы уже говорили ранее, транзакции майнятся не сразу, поэтому учитывайте это при разработке реальных даппов.

И, наконец, вторая часть, которая заслуживает внимания:

return window.co.getPastEvents(event, { filter: { p: p_hash }, fromBlock: 0, toBlock: 'latest' })

Помните, мы говорили, что события будут ядром нашей цепочки поставок? Эта строка используется для получения всех событий из определенного типа, фильтруя результаты по хэшу детали.

Это означает, что мы можем получить всю информацию обо всем, что произошло с конкретной деталью, и при желании мы также можем получить подробные сведения о детали, используя тот же хэш и вызывая функцию «parts» (детали) из «ProductManagement».

Довольно круто, не правда ли?

Заключение

Вот и все – мы закончили!

Каждый раз, когда производитель деталей хочет уведомить о производстве новых деталей, а производитель автомобилей захочет включить эти детали в сборку автомобиля или мы захотим передать детали и автомобили от одного владельца к другому, мы можем просто использовать веб-интерфейс, чтобы сделать это.

У нас есть прозрачная система записей, которая позволяет производителям, дилерам и покупателям иметь одинаковую информацию о продукции.

Если какая-либо проблема будут обнаружена в определенном диапазоне серийных номеров на заводах, то сам завод сможет проверить, где решать и устранять проблему.

То же самое верно и в обратном направлении: дилеры и покупатели могут отследить детали своих продуктов на заводах, если у них возникнут проблемы или им нужны будут замены.

Внедрение системы на основе блокчейна также обеспечивает распределенную и последовательную запись, которую никто из участников не сможет бесследно изменить, поэтому мы тем самым избегаем риска нечестной игры.

Мы сильно упростили сценарий цепочки поставок, но мы надеемся, что эта статья показала плюсы использования блокчейна для этой конкретной сферы применения. Теперь можно начать планирование внедрения этого решения и рассматривать его как альтернативу существующей системе.

Надеюсь, вам понравилась статья!

Категория: 
Tutorial
2
Ваша оценка: Нет Средняя: 2 (1 оценка)
18473 / 0
Аватар пользователя Serg Demin
Публикацию добавил: Serg Demin
Дата публикации: пн, 04/08/2019 - 10:14

Что еще почитать: