Blockchain: PoC apakah yang perlu kita bina?

Mata anda takut dan tangan anda gatal!

Dalam artikel sebelumnya, kami melihat teknologi di mana blokchain dibina (Apakah yang perlu kita bina blockchain?) dan kes yang boleh dilaksanakan dengan bantuan mereka (Mengapa kita perlu membina kes?). Sudah tiba masanya untuk bekerja dengan tangan anda! Untuk melaksanakan juruterbang dan PoC (Proof of Concept), saya lebih suka menggunakan awan, kerana... mereka boleh diakses dari mana-mana sahaja di dunia dan, selalunya, tidak perlu membuang masa pada pemasangan persekitaran yang membosankan, kerana Terdapat konfigurasi pratetap. Jadi, mari kita buat sesuatu yang mudah, sebagai contoh, rangkaian untuk memindahkan syiling antara peserta dan mari kita panggil secara sederhana Bitcoin. Untuk ini kami akan menggunakan awan IBM dan Fabrik Hyperledger blockchain universal. Mula-mula, mari kita fikirkan mengapa Hyperledger Fabric dipanggil rantaian sejagat?

Blockchain: PoC apakah yang perlu kita bina?

Hyperledger Fabric - rantaian sejagat

Secara umumnya, sistem maklumat sejagat ialah:

  • Satu set pelayan dan teras perisian yang melaksanakan logik perniagaan;
  • Antara muka untuk interaksi dengan sistem;
  • Alat untuk pendaftaran, pengesahan dan kebenaran peranti/orang;
  • Pangkalan data menyimpan data operasi dan arkib:

Blockchain: PoC apakah yang perlu kita bina?

Versi rasmi mengenai Hyperledger Fabric boleh dibaca di Online, dan secara ringkasnya, Hyperledger Fabric ialah platform sumber terbuka yang membolehkan anda membina rantaian blok peribadi dan melaksanakan kontrak pintar sewenang-wenangnya yang ditulis dalam bahasa pengaturcaraan JS dan Go. Mari kita lihat secara terperinci seni bina Hyperledger Fabric dan pastikan ini adalah sistem universal yang hanya mempunyai khusus untuk menyimpan dan merekod data. Kekhususan adalah bahawa data, seperti dalam semua rantaian blok, disimpan dalam blok yang diletakkan pada rantaian blok hanya jika peserta mencapai kata sepakat dan selepas merekodkan data tidak boleh dibetulkan atau dipadamkan secara senyap-senyap.

Seni Bina Fabrik Hyperledger

Rajah menunjukkan seni bina Fabrik Hyperledger:

Blockchain: PoC apakah yang perlu kita bina?

Organisasi - organisasi mengandungi rakan sebaya, i.e. blockchain wujud kerana sokongan organisasi. Organisasi yang berbeza boleh menjadi sebahagian daripada saluran yang sama.

Saluran - struktur logik yang menyatukan rakan sebaya ke dalam kumpulan, i.e. blockchain ditentukan. Hyperledger Fabric boleh memproses berbilang blok secara serentak dengan logik perniagaan yang berbeza.

Pembekal Perkhidmatan Keahlian (MSP) ialah CA (Certificate Authority) untuk mengeluarkan identiti dan memberikan peranan. Untuk mencipta nod, anda perlu berinteraksi dengan MSP.

Nod rakan sebaya β€” sahkan urus niaga, simpan blockchain, laksana kontrak pintar dan berinteraksi dengan aplikasi. Rakan sebaya mempunyai identiti (sijil digital), yang dikeluarkan oleh MSP. Tidak seperti rangkaian Bitcoin atau Etherium, di mana semua nod mempunyai hak yang sama, dalam Hyperledger Fabric nod memainkan peranan yang berbeza:

  • Rakan sebaya mungkin menyokong rakan sebaya (EP) dan melaksanakan kontrak pintar.
  • Komitmen rakan sebaya (CP) - hanya simpan data dalam blockchain dan kemas kini "keadaan dunia".
  • Anchor Peer (AP) - jika beberapa organisasi mengambil bahagian dalam rantaian blok, maka rakan sebaya utama digunakan untuk komunikasi antara mereka. Setiap organisasi mesti mempunyai satu atau lebih rakan sebaya utama. Menggunakan AP, mana-mana rakan sebaya dalam organisasi boleh mendapatkan maklumat tentang semua rakan sebaya dalam organisasi lain. Digunakan untuk menyegerakkan maklumat antara AP protokol gosip.
  • Pemimpin Rakan Sebaya β€” jika organisasi mempunyai beberapa rakan sebaya, maka hanya ketua rakan sebaya akan menerima blok daripada perkhidmatan Pesanan dan memberikannya kepada rakan sebaya yang lain. Pemimpin boleh ditentukan sama ada secara statik atau dipilih secara dinamik oleh rakan sebaya dalam organisasi. Protokol gosip juga digunakan untuk menyegerakkan maklumat tentang pemimpin.

Aset β€” entiti yang mempunyai nilai dan disimpan pada blockchain. Lebih khusus lagi, ini ialah data nilai kunci dalam format JSON. Data inilah yang direkodkan dalam Blockchain. Mereka mempunyai sejarah, yang disimpan dalam blockchain, dan keadaan semasa, yang disimpan dalam pangkalan data "keadaan dunia". Struktur data diisi sewenang-wenangnya bergantung pada tugas perniagaan. Tiada medan yang diperlukan, satu-satunya cadangan ialah aset mesti mempunyai pemilik dan bernilai.

lejar β€” terdiri daripada pangkalan data Blockchain dan keadaan Word, yang menyimpan keadaan semasa aset. Keadaan dunia menggunakan LevelDB atau CouchDB.

Kontrak pintar β€” menggunakan kontrak pintar, logik perniagaan sistem dilaksanakan. Dalam Hyperledger Fabric, kontrak pintar dipanggil kod rantai. Menggunakan kod rantai, aset dan urus niaga di atasnya ditentukan. Dari segi teknikal, kontrak pintar ialah modul perisian yang dilaksanakan dalam bahasa pengaturcaraan JS atau Go.

Dasar pengendorsan β€” untuk setiap kod rantaian, anda boleh menetapkan dasar tentang bilangan pengesahan untuk transaksi yang sepatutnya dijangka dan daripada siapa. Jika dasar tidak ditetapkan, maka lalainya ialah: "urus niaga mesti disahkan oleh mana-mana ahli mana-mana organisasi dalam saluran". Contoh dasar:

  • Urus niaga mesti diluluskan oleh mana-mana pentadbir organisasi;
  • Mesti disahkan oleh mana-mana ahli atau pelanggan organisasi;
  • Mesti disahkan oleh mana-mana organisasi rakan sebaya.

Perkhidmatan memesan β€” mengemas transaksi ke dalam blok dan menghantarnya kepada rakan sebaya dalam saluran. Menjamin penghantaran mesej kepada semua rakan sebaya di rangkaian. Digunakan untuk sistem perindustrian Broker mesej Kafka, untuk pembangunan dan ujian Pelancong.

CallFlow

Blockchain: PoC apakah yang perlu kita bina?

  • Aplikasi berkomunikasi dengan Hyperledger Fabric menggunakan Go, Node.js atau Java SDK;
  • Pelanggan mencipta transaksi tx dan menghantarnya kepada rakan sebaya yang menyokong;
  • Peer mengesahkan tandatangan pelanggan, menyelesaikan transaksi dan menghantar semula tandatangan pengesahan kepada pelanggan. Chaincode dilaksanakan hanya pada rakan yang menyokong, dan hasil pelaksanaannya dihantar kepada semua rakan sebaya. Algoritma kerja ini dipanggil konsensus PBFT (Practical Byzantine Fault Tolerant). Berbeza daripada BFT klasik hakikat bahawa mesej dihantar dan pengesahan dijangka bukan dari semua peserta, tetapi hanya dari set tertentu;
  • Selepas pelanggan menerima bilangan jawapan yang sepadan dengan dasar pengesahan, dia menghantar transaksi ke perkhidmatan Pesanan;
  • Perkhidmatan Pesanan menjana blok dan menghantarnya kepada semua rakan sebaya yang melakukan. Perkhidmatan pesanan memastikan rakaman berurutan bagi blok, yang menghapuskan apa yang dipanggil garpu lejar (lihat bahagian "Forks");
  • Rakan sebaya menerima sekatan, semak dasar pengesahan sekali lagi, tulis sekatan itu pada rantaian blok dan tukar keadaan dalam DB "Keadaan dunia".

Itu. Ini mengakibatkan pembahagian peranan antara nod. Ini memastikan rantaian blok berskala dan selamat:

  • Kontrak pintar (chaincode) melaksanakan pengendorsan rakan sebaya. Ini memastikan kerahsiaan kontrak pintar, kerana ia tidak disimpan oleh semua peserta, tetapi hanya dengan menyokong rakan sebaya.
  • Pesanan harus berfungsi dengan cepat. Ini dipastikan oleh fakta bahawa Pesanan hanya membentuk satu blok dan menghantarnya kepada satu set tetap rakan sebaya pemimpin.
  • Komitmen rakan sebaya hanya menyimpan blockchain - mungkin terdapat banyak daripada mereka dan mereka tidak memerlukan banyak kuasa dan operasi segera.

Butiran lanjut mengenai penyelesaian seni bina Hyperledger Fabric dan mengapa ia berfungsi dengan cara ini dan bukan sebaliknya boleh didapati di sini: Asal-usul Seni Bina atau di sini: Fabrik Hyperledger: Sistem Pengendalian Teragih untuk Rantaian Sekat yang Dibenarkan.

Jadi, Hyperledger Fabric ialah sistem yang benar-benar universal yang anda boleh:

  • Melaksanakan logik perniagaan sewenang-wenangnya menggunakan mekanisme kontrak pintar;
  • Rekod dan terima data daripada pangkalan data blockchain dalam format JSON;
  • Berikan dan sahkan akses API menggunakan Pihak Berkuasa Sijil.

Sekarang setelah kita memahami sedikit tentang spesifikasi Fabrik Hyperledger, mari kita lakukan sesuatu yang berguna!

Menggunakan blockchain

Pernyataan masalah

Tugasnya adalah untuk melaksanakan rangkaian Citcoin dengan fungsi berikut: buat akaun, dapatkan baki, tambah nilai akaun anda, pindahkan syiling dari satu akaun ke akaun yang lain. Mari kita lukis model objek, yang akan kita laksanakan selanjutnya dalam kontrak pintar. Jadi, kami akan mempunyai akaun yang dikenal pasti dengan nama dan mengandungi baki, dan senarai akaun. Akaun dan senarai akaun adalah, dari segi aset Hyperledger Fabric. Sehubungan itu, mereka mempunyai sejarah dan keadaan semasa. Saya akan cuba melukis ini dengan jelas:

Blockchain: PoC apakah yang perlu kita bina?

Angka teratas ialah keadaan semasa, yang disimpan dalam pangkalan data "Keadaan dunia". Di bawahnya adalah angka yang menunjukkan sejarah yang disimpan dalam rantaian blok. Keadaan semasa aset diubah oleh urus niaga. Aset hanya berubah secara keseluruhan, jadi sebagai hasil daripada urus niaga, objek baharu dicipta dan nilai semasa aset tersebut masuk ke dalam sejarah.

Awan IBM

Kami membuat akaun di awan IBM. Untuk menggunakan platform blockchain, ia mesti dinaik taraf kepada Pay-As-You-Go. Proses ini mungkin tidak cepat, kerana... IBM meminta maklumat tambahan dan mengesahkannya secara manual. Secara positif, saya boleh katakan bahawa IBM mempunyai bahan latihan yang baik yang membolehkan anda menggunakan Hyperledger Fabric dalam awan mereka. Saya menyukai siri artikel dan contoh berikut:

Berikut ialah tangkapan skrin platform IBM Blockchain. Ini bukan arahan tentang cara membuat blockchain, tetapi hanya demonstrasi skop tugas. Jadi, untuk tujuan kami, kami membuat satu Organisasi:

Blockchain: PoC apakah yang perlu kita bina?

Kami mencipta nod di dalamnya: Orderer CA, Org1 CA, Orderer Peer:

Blockchain: PoC apakah yang perlu kita bina?

Kami mencipta pengguna:

Blockchain: PoC apakah yang perlu kita bina?

Buat Saluran dan panggil ia citcoin:

Blockchain: PoC apakah yang perlu kita bina?

Pada asasnya Channel ialah blockchain, jadi ia bermula dengan blok sifar (blok Genesis):

Blockchain: PoC apakah yang perlu kita bina?

Menulis Kontrak Pintar

/*
 * Citcoin smart-contract v1.5 for Hyperledger Fabric
 * (c) Alexey Sushkov, 2019
 */
 
'use strict';
 
const { Contract } = require('fabric-contract-api');
const maxAccounts = 5;
 
class CitcoinEvents extends Contract {
 
    async instantiate(ctx) {
        console.info('instantiate');
        let emptyList = [];
        await ctx.stub.putState('accounts', Buffer.from(JSON.stringify(emptyList)));
    }
    // Get all accounts
    async GetAccounts(ctx) {
        // Get account list:
        let accounts = '{}'
        let accountsData = await ctx.stub.getState('accounts');
        if (accountsData) {
            accounts = JSON.parse(accountsData.toString());
        } else {
            throw new Error('accounts not found');
        }
        return accountsData.toString()
    }
     // add a account object to the blockchain state identifited by their name
    async AddAccount(ctx, name, balance) {
        // this is account data:
        let account = {
            name: name,
            balance: Number(balance),       
            type: 'account',
        };
        // create account:
        await ctx.stub.putState(name, Buffer.from(JSON.stringify(account)));
 
        // Add account to list:
        let accountsData = await ctx.stub.getState('accounts');
        if (accountsData) {
            let accounts = JSON.parse(accountsData.toString());
            if (accounts.length < maxAccounts)
            {
                accounts.push(name);
                await ctx.stub.putState('accounts', Buffer.from(JSON.stringify(accounts)));
            } else {
                throw new Error('Max accounts number reached');
            }
        } else {
            throw new Error('accounts not found');
        }
        // return  object
        return JSON.stringify(account);
    }
    // Sends money from Account to Account
    async SendFrom(ctx, fromAccount, toAccount, value) {
        // get Account from
        let fromData = await ctx.stub.getState(fromAccount);
        let from;
        if (fromData) {
            from = JSON.parse(fromData.toString());
            if (from.type !== 'account') {
                throw new Error('wrong from type');
            }   
        } else {
            throw new Error('Accout from not found');
        }
        // get Account to
        let toData = await ctx.stub.getState(toAccount);
        let to;
        if (toData) {
            to = JSON.parse(toData.toString());
            if (to.type !== 'account') {
                throw new Error('wrong to type');
            }  
        } else {
            throw new Error('Accout to not found');
        }
 
        // update the balances
        if ((from.balance - Number(value)) >= 0 ) {
            from.balance -= Number(value);
            to.balance += Number(value);
        } else {
            throw new Error('From Account: not enought balance');          
        }
 
        await ctx.stub.putState(from.name, Buffer.from(JSON.stringify(from)));
        await ctx.stub.putState(to.name, Buffer.from(JSON.stringify(to)));
                 
        // define and set Event
        let Event = {
            type: "SendFrom",
            from: from.name,
            to: to.name,
            balanceFrom: from.balance,
            balanceTo: to.balance,
            value: value
        };
        await ctx.stub.setEvent('SendFrom', Buffer.from(JSON.stringify(Event)));
 
        // return to object
        return JSON.stringify(from);
    }
 
    // get the state from key
    async GetState(ctx, key) {
        let data = await ctx.stub.getState(key);
        let jsonData = JSON.parse(data.toString());
        return JSON.stringify(jsonData);
    }
    // GetBalance   
    async GetBalance(ctx, accountName) {
        let data = await ctx.stub.getState(accountName);
        let jsonData = JSON.parse(data.toString());
        return JSON.stringify(jsonData);
    }
     
    // Refill own balance
    async RefillBalance(ctx, toAccount, value) {
        // get Account to
        let toData = await ctx.stub.getState(toAccount);
        let to;
        if (toData) {
            to = JSON.parse(toData.toString());
            if (to.type !== 'account') {
                throw new Error('wrong to type');
            }  
        } else {
            throw new Error('Accout to not found');
        }
 
        // update the balance
        to.balance += Number(value);
        await ctx.stub.putState(to.name, Buffer.from(JSON.stringify(to)));
                 
        // define and set Event
        let Event = {
            type: "RefillBalance",
            to: to.name,
            balanceTo: to.balance,
            value: value
        };
        await ctx.stub.setEvent('RefillBalance', Buffer.from(JSON.stringify(Event)));
 
        // return to object
        return JSON.stringify(from);
    }
}
module.exports = CitcoinEvents;

Secara intuitif, semuanya harus jelas di sini:

  • Terdapat beberapa fungsi (AddAccount, GetAccounts, SendFrom, GetBalance, RefillBalance) yang akan dipanggil oleh program demo menggunakan Hyperledger Fabric API.
  • Fungsi SendFrom dan RefillBalance menjana Acara yang akan diterima oleh program demo.
  • Fungsi instantiate dipanggil sekali apabila kontrak pintar dibuat instantiate. Malah, ia dipanggil bukan sekali sahaja, tetapi setiap kali versi kontrak pintar berubah. Oleh itu, memulakan senarai dengan tatasusunan kosong adalah idea yang tidak baik, kerana Sekarang, apabila kami menukar versi kontrak pintar, kami akan kehilangan senarai semasa. Tapi tak apa, saya baru belajar).
  • Akaun dan senarai akaun ialah struktur data JSON. JS digunakan untuk manipulasi data.
  • Anda boleh mendapatkan nilai semasa aset menggunakan panggilan fungsi getState dan mengemas kininya menggunakan putState.
  • Apabila membuat Akaun, fungsi AddAccount dipanggil, di mana perbandingan dibuat untuk bilangan maksimum akaun dalam blokchain (maxAccounts = 5). Dan di sini terdapat jamb (adakah anda perasan?), yang membawa kepada peningkatan yang tidak berkesudahan dalam bilangan akaun. Kesilapan sedemikian mesti dielakkan)

Seterusnya, kami memuatkan kontrak pintar ke dalam Saluran dan membuat contoh:

Blockchain: PoC apakah yang perlu kita bina?

Mari lihat transaksi untuk memasang Kontrak Pintar:

Blockchain: PoC apakah yang perlu kita bina?

Mari lihat butiran mengenai Saluran kami:

Blockchain: PoC apakah yang perlu kita bina?

Hasilnya, kami mendapat gambar rajah rangkaian blockchain berikut dalam awan IBM. Rajah juga menunjukkan program demo yang berjalan di awan Amazon pada pelayan maya (lebih lanjut mengenainya dalam bahagian seterusnya):

Blockchain: PoC apakah yang perlu kita bina?

Mencipta GUI untuk panggilan API Hyperledger Fabric

Hyperledger Fabric mempunyai API yang boleh digunakan untuk:

  • Buat saluran;
  • Sambungan peer to channel;
  • Pemasangan dan pemasangan kontrak pintar dalam saluran;
  • Urus niaga panggilan;
  • Minta maklumat mengenai blockchain.

Pembangunan aplikasi

Dalam program demo kami, kami akan menggunakan API hanya untuk memanggil transaksi dan meminta maklumat, kerana Kami telah menyelesaikan langkah yang tinggal menggunakan platform blockchain IBM. Kami menulis GUI menggunakan tindanan teknologi standard: Express.js + Vue.js + Node.js. Anda boleh menulis artikel berasingan tentang cara mula membuat aplikasi web moden. Di sini saya akan meninggalkan pautan kepada siri kuliah yang paling saya sukai: Apl Web Tindanan Penuh menggunakan Vue.js & Express.js. Hasilnya ialah aplikasi pelayan pelanggan dengan antara muka grafik yang biasa dalam gaya Reka Bentuk Bahan Google. API REST antara klien dan pelayan terdiri daripada beberapa panggilan:

  • HyperledgerDemo/v1/init - mulakan blockchain;
  • HyperledgerDemo/v1/accounts/list β€” dapatkan senarai semua akaun;
  • HyperledgerDemo/v1/account?name=Bob&balance=100 β€” buat akaun Bob;
  • HyperledgerDemo/v1/info?account=Bob β€” dapatkan maklumat tentang akaun Bob;
  • HyperledgerDemo/v1/transaction?from=Bob&to=Alice&volume=2 - pindahkan dua syiling daripada Bob kepada Alice;
  • HyperledgerDemo/v1/disconnect - tutup sambungan ke blockchain.

Penerangan API dengan contoh disertakan dalam laman web posmen - program yang terkenal untuk menguji HTTP API.

Aplikasi demo dalam awan Amazon

Saya memuat naik aplikasi ke Amazon kerana... IBM masih belum dapat menaik taraf akaun saya dan membenarkan saya mencipta pelayan maya. Cara menambah ceri pada domain: www.citcoin.info. Saya akan menghidupkan pelayan untuk seketika, kemudian mematikannya, kerana... sen untuk sewa menitis, dan syiling citcoin belum lagi disenaraikan di bursa saham) Saya sertakan tangkapan skrin demo dalam artikel supaya logik kerja itu jelas. Aplikasi demo boleh:

  • Mulakan blockchain;
  • Cipta Akaun (tetapi kini anda tidak boleh membuat Akaun baharu, kerana bilangan maksimum akaun yang dinyatakan dalam kontrak pintar telah dicapai dalam rantaian blok);
  • Terima senarai Akaun;
  • Pindahkan syiling citcoin antara Alice, Bob dan Alex;
  • Terima acara (tetapi kini tiada cara untuk menunjukkan acara, jadi untuk kesederhanaan, antara muka mengatakan bahawa acara tidak disokong);
  • Log tindakan.

Mula-mula kita memulakan blockchain:

Blockchain: PoC apakah yang perlu kita bina?

Seterusnya, kami membuat akaun kami, jangan buang masa dengan baki:

Blockchain: PoC apakah yang perlu kita bina?

Kami mendapat senarai semua akaun yang tersedia:

Blockchain: PoC apakah yang perlu kita bina?

Kami memilih penghantar dan penerima dan mendapatkan baki mereka. Jika pengirim dan penerima adalah sama, maka akaunnya akan diisi semula:

Blockchain: PoC apakah yang perlu kita bina?

Dalam log kami memantau pelaksanaan transaksi:

Blockchain: PoC apakah yang perlu kita bina?

Sebenarnya, itu sahaja dengan program demo. Di bawah anda boleh melihat transaksi kami dalam rantaian blok:

Blockchain: PoC apakah yang perlu kita bina?

Dan senarai umum transaksi:

Blockchain: PoC apakah yang perlu kita bina?

Dengan ini, kami telah berjaya menyelesaikan pelaksanaan PoC untuk mencipta rangkaian Citcoin. Apa lagi yang perlu dilakukan untuk Citcoin menjadi rangkaian penuh untuk memindahkan syiling? Sangat sedikit:

  • Pada peringkat penciptaan akaun, laksanakan penjanaan kunci persendirian / awam. Kunci persendirian mesti disimpan dengan pengguna akaun, kunci awam mesti disimpan dalam rantaian blok.
  • Buat pemindahan syiling di mana kunci awam, bukannya nama, digunakan untuk mengenal pasti pengguna.
  • Sulitkan transaksi dari pengguna ke pelayan dengan kunci peribadinya.

Kesimpulan

Kami telah melaksanakan rangkaian Citcoin dengan fungsi berikut: tambah akaun, dapatkan baki, tambah nilai akaun anda, pindahkan syiling dari satu akaun ke akaun yang lain. Jadi, apakah kos kami untuk membina PoC?

  • Anda perlu mempelajari blockchain secara umum dan Hyperledger Fabric khususnya;
  • Belajar menggunakan awan IBM atau Amazon;
  • Pelajari bahasa pengaturcaraan JS dan beberapa rangka kerja web;
  • Jika sesetengah data perlu disimpan bukan dalam blokchain, tetapi dalam pangkalan data yang berasingan, kemudian belajar untuk mengintegrasikan, sebagai contoh, dengan PostgreSQL;
  • Dan akhir sekali - anda tidak boleh hidup dalam dunia moden tanpa pengetahuan tentang Linux!)

Sudah tentu, ia bukan sains roket, tetapi anda perlu bekerja keras!

Sumber di GitHub

Sumber diletakkan GitHub. Penerangan ringkas repositori:
Katalog Β«serverΒ» β€” Pelayan Node.js
Katalog Β«pelangganΒ» β€” Pelanggan Node.js
Katalog Β«blockchain"(nilai parameter dan kunci, sudah tentu, tidak berfungsi dan diberikan hanya sebagai contoh):

  • kontrak β€” kod sumber kontrak pintar
  • dompet β€” kunci pengguna untuk menggunakan Hyperledger Fabric API.
  • *.cds - versi kompilasi kontrak pintar
  • *.json files - contoh fail konfigurasi untuk menggunakan Hyperledger Fabric API

Ia hanya permulaan!

Sumber: www.habr.com

Tambah komen