超級賬本實踐——基於docker從零搭建聯盟鏈


本文分享基於docker如何從零搭建聯盟鏈。

 

一、前言

本文分享基於docker如何從零搭建聯盟鏈。使用其它方式搭建也可以,只不過docker相對容易一些,難點在於如何寫配置文件。

 

1. 准備運行環境

實際開發中有三種運行環境可供選擇:

(a). Vagrant: Vagrant是一個基於Ruby的工具,用於創建和部署虛擬化開發環境。

(b). virtualBox:

VirtualBox 是一款開源虛擬機軟件。如今被甲骨文收購

(c). Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然后發布到任何流行的 Linux 機器上,也可以實現虛擬化。容器是完全使用沙箱機制,相互之間不會有任何接口。

本節使用的是docker環境,也是相對簡單的環境配置。關於docker的使用可以參考之前的文章。

 

1.1 fabric鏡像

通過前面章節的步驟生成以下鏡像:

 

2. 逐步構建網絡

目標:構建圖示類型的網絡

 

 

 

 

 

2.1 編寫配置文件

以上鏡像准備好之后,開始編寫配置文件,因為使用docker-compose(批量管理docker容器的工具),所以需要編寫yaml格式的配置文件。

因為配置規則較多,所以剛開始建議參考官方提供的配置文件,具體在sample文件夾里的first-network配置。

 

 

2.1.1 生成公私鑰和證書

Fabric中有兩種類型的公私鑰和證書,一種是給節點之間,為了通訊安全而准備的TLS證書,另一種是用戶登錄和權限控制的用戶證書。這些證書本來應該是由CA來頒發,但是我們這里是測試環境,並沒有啟用CA節點,這里我們使用:cryptogen來生成這兩種證書。

 

2.1.1.2 配置crypto-config.yaml文件

cryptogen工具讀取這個配置文件產生證書和密鑰。

分別生成Order節點和兩個成員組織的Peer節點以及用戶證書。

> HyperLedger Fabric中,成員和用戶是兩個不同的角色。

成員是針對區塊鏈網絡中的組織,聯盟等而言,而用戶,是針對整個應用而言。

用戶指的是該系統給的使用者。

配置如下:

 

OrdererOrgs:
  - Name: Orderer
    Domain: example.com
    Specs:
      - Hostname: orderer
PeerOrgs:
  - Name: Org1
    Domain: org1.example.com
    EnableNodeOUs: true
    Template:
      Count: 2
    Users:
      Count: 1
  - Name: Org2
    Domain: org2.example.com
    EnableNodeOUs: true
    Template:
      Count: 2
    Users:
      Count: 1

 

2.1.1.3 生成公私鑰和證書

 

執行cryptogen generate --config=./crypto-config.yaml則會把生成的證書和公私鑰存放在'crypto-config'目錄里。如果提示“沒有cryptogen命令”說明環境變量沒有設置好,請重新設置。

 

2.1.2 生成公私鑰和證書

 

這里的創始區塊是指生成系統通道的創世區塊,主要用於啟動Ordering服務,配置網絡中的策略。而Channel配置區塊,主要用於新建應用通道,指定通道成員,以及訪問策略等等。

2.1.2.1 配置configtx.yaml

配置了由2個Org參與的Orderer共識配置TwoOrgsOrdererGenesis,

以及由2個Org參與的Channel配置:TwoOrgsChannel。

Orderer可以設置共識的算法是Solo還是Kafka,以及共識時區塊大小,超時時間等,我們使用默認值即可,不用更改。而Peer節點的配置包含了MSP的配置,錨節點的配置。

配置如下:

 

Organizations:
    - &OrdererOrg
        Name: OrdererOrg
        ID: OrdererMSP
        MSPDir: crypto-config/ordererOrganizations/example.com/msp
  Policies:
            Readers:
                Type: Signature
                Rule: "OR('OrdererMSP.member')"
            Writers:
                Type: Signature
                Rule: "OR('OrdererMSP.member')"
            Admins:
                Type: Signature
                Rule: "OR('OrdererMSP.admin')"
    - &Org1
        Name: Org1MSP
        ID: Org1MSP
        MSPDir: crypto-config/peerOrganizations/org1.example.com/msp
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org1MSP.admin')"
        AnchorPeers:
            - Host: peer0.org1.example.com
              Port: 7051
    - &Org2
        Name: Org2MSP
        ID: Org2MSP
        MSPDir: crypto-config/peerOrganizations/org2.example.com/msp
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')"
            Writers:
  Type: Signature
                Rule: "OR('Org2MSP.admin', 'Org2MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org2MSP.admin')"
        AnchorPeers:
            - Host: peer0.org2.example.com
              Port: 7051
Capabilities:
    Channel: &ChannelCapabilities
        V1_3: true
    Orderer: &OrdererCapabilities
        V1_1: true
    Application: &ApplicationCapabilities
        V1_3: true
        V1_2: false
        V1_1: false
Application: &ApplicationDefaults
    Organizations:
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
Orderer: &OrdererDefaults
    OrdererType: solo
    Addresses:
        - orderer.example.com:7050
    BatchTimeout: 2s
    BatchSize:
        MaxMessageCount: 10
  AbsoluteMaxBytes: 99 MB
        PreferredMaxBytes: 512 KB
    Kafka:
        Brokers:
            - 127.0.0.1:9092
    Organizations:
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        BlockValidation:
            Type: ImplicitMeta
            Rule: "ANY Writers"
Channel: &ChannelDefaults
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
    Capabilities:
        <<: *ChannelCapabilities
Profiles:
    TwoOrgsOrdererGenesis:
        <<: *ChannelDefaults
        Orderer:
 <<: *OrdererDefaults
            Organizations:
                - *OrdererOrg
            Capabilities:
                <<: *OrdererCapabilities
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *Org1
                    - *Org2
    TwoOrgsChannel:
        Consortium: SampleConsortium
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *Org1
                - *Org2
            Capabilities:
                <<: *ApplicationCapabilities

 

 

2.1.2.2 生成創世區塊

如果環境變量配置無誤,則執行

 

configtxgen -profile TwoOrgsOrdererGenesis 
-outputBlock ./channel-artifacts/genesis.block

 

 

2.1.2.3 生成通道配置區塊

執行

 

configtxgen -profile TwoOrgsChannel 
-outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel

 

 

2.1.2.4 錨節點的更新

錨節點負責代表組織與其他組織中的節點進行Gossip通信。

因為有兩個組織org1和org2因此需執行兩次:

configtxgen -profile TwoOrgsChannel 
-outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel 
-asOrg Org1MSP

再執行

configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP

 

 

最終,我們在channel-artifacts文件夾中,應該是能夠看到4個文件。

├── Org1MSPanchors.tx

├── Org2MSPanchors.tx

├── channel.tx

└── genesis.block

 

2.1.2 配置docker-compose文件

前面對節點和用戶的公私鑰以及證書,還有創世區塊都生成完畢了。這里采用的是docker-compose的方式來部署環境的,所以接下來我們就可以配置docker-compose的yaml文件,以便順利啟動Fabric的Docker環境。

配置如下:

 

version: '2'
volumes:
  orderer.example.com:
  peer0.org1.example.com:
  peer1.org1.example.com:
  peer0.org2.example.com:
  peer1.org2.example.com:
 
networks:
  myNetwork:
 
services:
 
  orderer.example.com:
    image: hyperledger/fabric-orderer:$IMAGE_TAG
    environment:
 - ORDERER_GENERAL_LOGLEVEL=INFO
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
      - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
      - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
      # enabled TLS
      - ORDERER_GENERAL_TLS_ENABLED=true
      - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
      - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
      - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    command: orderer
    volumes:
    - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
    - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
    - ./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls
    - orderer.example.com:/var/hyperledger/production/orderer
    ports:
      - 7050:7050
    container_name: orderer.example.com
    networks:
      - myNetwork
 
  peer0.org1.example.com:
    container_name: peer0.org1.example.com
    image: hyperledger/fabric-peer:$IMAGE_TAG
    environment:
      # base
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_myNetwork
      - CORE_LOGGING_LEVEL=DEBUG
      - CORE_PEER_TLS_ENABLED=true
  - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_PROFILE_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
      # other
      - CORE_PEER_ID=peer0.org1.example.com
      - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org1.example.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
      - CORE_PEER_LOCALMSPID=Org1MSP
    volumes:
      - /var/run/:/host/var/run/
      - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
      - ./crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls
      - peer0.org1.example.com:/var/hyperledger/production
    ports:
      - 7051:7051
      - 7053:7053
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start
    networks:
      - myNetwork
 
  peer1.org1.example.com:
    container_name: peer1.org1.example.com
    image: hyperledger/fabric-peer:$IMAGE_TAG
    environment:
      # base
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_myNetwork
      - CORE_LOGGING_LEVEL=DEBUG
      - CORE_PEER_TLS_ENABLED=true
 - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_PROFILE_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
      # other
      - CORE_PEER_ID=peer1.org1.example.com
      - CORE_PEER_ADDRESS=peer1.org1.example.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051
      - CORE_PEER_LOCALMSPID=Org1MSP
    volumes:
      - /var/run/:/host/var/run/
      - ./crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp
      - ./crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls:/etc/hyperledger/fabric/tls
      - peer1.org1.example.com:/var/hyperledger/production
    ports:
      - 8051:7051
      - 8053:7053
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start
    networks:
      - myNetwork
 
  peer0.org2.example.com:
    container_name: peer0.org2.example.com
    image: hyperledger/fabric-peer:$IMAGE_TAG
    environment:
      # base
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_myNetwork
      - CORE_LOGGING_LEVEL=DEBUG
      - CORE_PEER_TLS_ENABLED=true
  - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_PROFILE_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
      # other
      - CORE_PEER_ID=peer0.org2.example.com
      - CORE_PEER_ADDRESS=peer0.org2.example.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org2.example.com:7051
      - CORE_PEER_LOCALMSPID=Org2MSP
    volumes:
      - /var/run/:/host/var/run/
      - ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp
      - ./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls:/etc/hyperledger/fabric/tls
      - peer0.org2.example.com:/var/hyperledger/production
    ports:
      - 9051:7051
      - 9053:7053
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start
    networks:
      - myNetwork
 
  peer1.org2.example.com:
    container_name: peer1.org2.example.com
    image: hyperledger/fabric-peer:$IMAGE_TAG
    environment:
      # base
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_myNetwork
      - CORE_LOGGING_LEVEL=DEBUG
      - CORE_PEER_TLS_ENABLED=true
 - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_PROFILE_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
      # other
      - CORE_PEER_ID=peer1.org2.example.com
      - CORE_PEER_ADDRESS=peer1.org2.example.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org2.example.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:7051
      - CORE_PEER_LOCALMSPID=Org2MSP
    volumes:
      - /var/run/:/host/var/run/
      - ./crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/msp:/etc/hyperledger/fabric/msp
      - ./crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls:/etc/hyperledger/fabric/tls
      - peer1.org2.example.com:/var/hyperledger/production
    ports:
      - 10051:7051
      - 10053:7053
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start
    networks:
      - myNetwork
 
  cli:
    container_name: cli
    image: hyperledger/fabric-tools:$IMAGE_TAG
    tty: true
    stdin_open: true
    environment:
      - GOPATH=/opt/gopath
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_LOGGING_LEVEL=DEBUG
   - CORE_PEER_ID=cli
      - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
      - CORE_PEER_LOCALMSPID=Org1MSP
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
      - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: /bin/bash
    volumes:
        - /var/run/:/host/var/run/
        - ./chaincode/:/opt/gopath/src/github.com/chaincode
        - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
        - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
        - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
    depends_on:
      - orderer.example.com
      - peer0.org1.example.com
      - peer1.org1.example.com
      - peer0.org2.example.com
      - peer1.org2.example.com
    networks:
      - myNetwork

其中ORDERER_GENERAL_GENESISFILE就是前面生成的創世區塊。因為節點之間需要加密通信,因此把ORDERER_GENERAL_TLS_ENABLED的值設置為true。另外開發調試階段把CORE_LOGGING_LEVEL設為DEBUG模式。

這個配置文件里分別配置了兩個組織,四個peer節點,一個orderer節點和cli節點。

CLI在整個Fabric網絡中扮演客戶端的角色,我們在開發測試的時候可以用CLI來代替SDK,執行各種SDK能執行的操作。CLI會和Peer相連,把指令發送給對應的Peer執行。而且CLI啟動的時候默認連接的是http://peer0.org1.example.com,並且啟用了TLS。默認是以Admin@org1.example.com這個身份連接到Peer的。連接之后會直接打開bin/bash從而可以直接輸入操作peer節點的命令。

 

2.2. 啟動網絡

因為docker-compose是批量管理docker容器的工具,所以寫完配置文件之后,通過執行docker-compose -f docker-compose-cli.yaml up -d命令批量啟動節點容器。 (-d參數如果不加,那么當前終端就會一直附加在docker-compose上,而如果加上的話,那么docker容器就在后台運行。)

啟動完成之后,終端里輸入docker ps -a可以看到所有節點容器已經全部啟動成功。

 

 

 

2.2.1 創建通道

* 首先進入cli節點:docker exec -it cli bash

* 創建通道執行:peer channel create:

 

peer channel create -o orderer.example.com:7050 -c mychannel 
-f ./channel-artifacts/channel.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/examp
le.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

 

 

 

系統會在cli內部的當前目錄創建一個mychannel.block文件,這個文件非常重要,接下來其他節點要加入這個Channel就必須使用這個文件。

* 加入通道執行:peer channel join -b mychannel.block:

如果提示“Successfully submitted proposal to join channel”,說明peer0.org1節點成功加入通道。

如果其它節點也要加入通道則先改變變量,然后再次執行join命令。

環境變量改為:

 

 

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/pe
erOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer0.org2.example.com:7051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypt
o/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt

 

 

* 指定錨節點:

參考以上步驟先把變量設置為組織一的,然后為org1定義錨節點為

 

peer0.org1.example.com:
peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

 

同理指定組織2的節點也是先改變量,然后再執行一遍以上命令。

如果提示“Successfully submitted channel update”表示錨節點指定成功。

以上過程全部完成之后,就可以部署鏈碼調用合約了,篇幅有限鏈碼的章節隨后發布。

 

 

本章總結

本文分享了從零部署超級賬本網絡環境。

1. 先配置證書和私鑰的文件crypto-config.yaml,然后通過工具cryptogen生成對應的證書到crypto-config目錄。

2. 再配置configtx.yaml,然后通過工具configtxgen生成創世區塊和通道配置區塊以及錨節點交易文件。

3. 所有文件配置好之后,通過docker-compose工具啟動節點容器

4. 進入cli節點分別執行創建通道、加入通道、更新錨節點的命令。

《超級賬本實踐系列》下一篇分享有關鏈碼的實踐。

 

-END-


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM