quorum examples初探

環境

  • Ubuntu18.04
  • Docker Engine 18.02.0
  • Docker Compose 1.21+

引言

quorum examples包含Quorum平臺的安裝示例,啓動由7個獨立節點組成的功能齊全的Quorum環境,從這個例子中可以測試以太坊平臺的共識、隱私和所有預期功能。

1. 安裝docker

參考ubuntu安裝、更新docker社區版

2. 安裝docker-compose

sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

3. 啓動quorum網絡

git clone https://github.com/jpmorganchase/quorum-examples
cd quorum-examples
docker-compose up -d

默認使用Tessera隱私管理器和Istanbul BFT共識,如果要使用raft共識,請設置QUORUM_CONSENSUS=raft,啓動沒有關聯的隱私事務管理器,請設置PRIVATE_CONFIG=ignore ,兩者可以一同實用。

PRIVATE_CONFIG=ignore QUORUM_CONSENSUS=raft docker-compose up -d

4. 檢查網絡

  • 運行docker ps檢查所有的容器是否正常運行(7個節點、7個TX管理器、一個cakeshop:Quorum的集成開發環境和SDK)
 IMAGE                               PORTS
quorumengineering/quorum:2.5.0      8546/tcp, 21000/tcp, 30303/tcp, 50400/tcp, 30303/udp, 0.0.0.0:22005->8545/tcp
quorumengineering/quorum:2.5.0      8546/tcp, 21000/tcp, 30303/tcp, 50400/tcp, 30303/udp, 0.0.0.0:22006->8545/tcp
quorumengineering/quorum:2.5.0      8546/tcp, 21000/tcp, 30303/tcp, 50400/tcp, 30303/udp, 0.0.0.0:22004->8545/tcp
quorumengineering/quorum:2.5.0      8546/tcp, 21000/tcp, 30303/tcp, 50400/tcp, 30303/udp, 0.0.0.0:22000->8545/tcp
quorumengineering/quorum:2.5.0      8546/tcp, 21000/tcp, 30303/tcp, 50400/tcp, 30303/udp, 0.0.0.0:22001->8545/tcp
quorumengineering/quorum:2.5.0      8546/tcp, 21000/tcp, 30303/tcp, 50400/tcp, 30303/udp, 0.0.0.0:22002->8545/tcp
quorumengineering/quorum:2.5.0      8546/tcp, 21000/tcp, 30303/tcp, 50400/tcp, 30303/udp, 0.0.0.0:22003->8545/tcp
quorumengineering/tessera:0.10.4    9000/tcp, 0.0.0.0:9082->9080/tcp
quorumengineering/tessera:0.10.4    9000/tcp, 0.0.0.0:9087->9080/tcp
quorumengineering/tessera:0.10.4    9000/tcp, 0.0.0.0:9083->9080/tcp
quorumengineering/tessera:0.10.4    9000/tcp, 0.0.0.0:9084->9080/tcp
quorumengineering/tessera:0.10.4    9000/tcp, 0.0.0.0:9081->9080/tcp
quorumengineering/tessera:0.10.4    9000/tcp, 0.0.0.0:9085->9080/tcp
quorumengineering/cakeshop:0.11.0   8080/tcp, 8102/tcp, 0.0.0.0:8999->8999/tcp
quorumengineering/tessera:0.10.4    9000/tcp, 0.0.0.0:9086->9080/tcp
  • docker logs -f 查看特定容器的日誌

5. 隱私交易測試

這裏我們將做以下實驗測試交易:

  • 在node1和node7之間發送隱私交易
  • 證明只有node1和node7可以查看合約的初始狀態
  • node1更新合約的狀態,並且一旦包含更新交易的區塊被網絡驗證,再次驗證只有node1和node7能夠看到合約的更新狀態

5.1 發送隱私交易

連接node1

docker exec -it quorum-examples_node1_1 geth attach /qdata/dd/geth.ipc

發送一筆私有交易

> loadScript('/examples/private-contract.js')
Contract transaction send: TransactionHash: 0x88103cbf9b6e4823e214af0e50e21941ff416cc81320d20049f4d324627bcfcb waiting to be mined...
true
> Contract mined! Address: 0x1932c48b2bf8102ba33b4a6b545c32236e342f34
[object Object]

記錄下TransactionHash的值。

private-contract.js 內容如下:

a = eth.accounts[0]
web3.eth.defaultAccount = a;

// abi and bytecode generated from simplestorage.sol:
// > solcjs --bin --abi simplestorage.sol
var abi = [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initVal","type":"uint256"}],"payable":false,"type":"constructor"}];

var bytecode = "0x6060604052341561000f57600080fd5b604051602080610149833981016040528080519060200190919050505b806000819055505b505b610104806100456000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632a1afcd914605157806360fe47b11460775780636d4ce63c146097575b600080fd5b3415605b57600080fd5b606160bd565b6040518082815260200191505060405180910390f35b3415608157600080fd5b6095600480803590602001909190505060c3565b005b341560a157600080fd5b60a760ce565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b6000805490505b905600a165627a7a72305820d5851baab720bba574474de3d09dbeaabc674a15f4dd93b974908476542c23f00029";

var simpleContract = web3.eth.contract(abi);
var simple = simpleContract.new(42, {from:web3.eth.accounts[0], data: bytecode, gas: 0x47b760, privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}, function(e, contract) {
	if (e) {
		console.log("err creating contract", e);
	} else {
		if (!contract.address) {
			console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined...");
		} else {
			console.log("Contract mined! Address: " + contract.address);
			console.log(contract);
		}
	}
});

privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] 爲node7的公鑰。

5.1 檢查quorum node

通過geth attach打開Geth JavaScript控制檯,這裏我們檢查node1、node4、node7.
打開三個終端:

docker exec -it quorum-examples_node1_1 geth attach /qdata/dd/geth.ipc
docker exec -it quorum-examples_node4_1 geth attach /qdata/dd/geth.ipc
docker exec -it quorum-examples_node7_1 geth attach /qdata/dd/geth.ipc

在其中一個終端執行以下命令(參數爲上一步的TransactionHash):

>eth.getTransaction("0x88103cbf9b6e4823e214af0e50e21941ff416cc81320d20049f4d324627bcfcb")
{
  blockHash: "0x57766df2f6eee01b9babacbb1978ad5d60d2fbcbe117f8ba0d7f68052edb4cac",
  blockNumber: 516,
  from: "0xed9d02e382b34818e88b88a309c7fe71e65f419d",
  gas: 4700000,
  gasPrice: 0,
  hash: "0x88103cbf9b6e4823e214af0e50e21941ff416cc81320d20049f4d324627bcfcb",
  input: "0x7958c99b76a16c71637b9fa1f7e8728fcdb93c656c18e705ec8daf9b2c7221b7eae9afcb67961dc0bcbac0cc35aa3e51f21c5d7f11a465db6b8d3fe4b96e7426",
  nonce: 0,
  r: "0x3323ee2c9c4df841b1ac049a048a0e27a09b203c630e92a7e9daa7075e43ef52",
  s: "0xe09387feecaf051f4a7fe6cebdc00d5395b2dee56913bddecbc28de0da59398",
  to: null,
  transactionIndex: 0,
  v: "0x25",
  value: 0
}

請注意或的v字段值是 “0x25” or “0x26”(十進制爲37或38),它標示交易(事務)是是隱私交易。

5.3 檢查合約狀態

可以通過以下命令得到合約地址(在5.1中也發送交易後也打印了)

>eth.getTransactionReceipt("0x88103cbf9b6e4823e214af0e50e21941ff416cc81320d20049f4d324627bcfcb")

在三個終端運行以下命令:
定義合約地址

var address = "0x1932c48b2bf8102ba33b4a6b545c32236e342f34"; //替換成你自己的合約地址

定義abi

> var abi = [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initVal","type":"uint256"}],"type":"constructor"}];

調用合約

>var private = eth.contract(abi).at(address)
  • 終端窗口1(node1):
    > private.get()
    42
    
  • 終端窗口2(node4):
    > private.get()
    0
    
  • 終端窗口3(node4):
    > private.get()
    42
    

因此,我們可以看到node1和node7能夠讀取隱私合約的狀態,並且其初始值爲42。如果您進行查看private-contract.js您將看到這是創建合同時設置的值。而node4無法讀取狀態。

5.3 更新合約狀態

接下來我們在node1上將合約的狀態值更新爲4,並在node4和node7上查看最新的狀態。

終端窗口1(node1):

> private.set(4,{from:"0xed9d02e382b34818e88b88a309c7fe71e65f419d",privateFor:["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]});
"0x4a5618b41019161f710b16f3c749f88de605ddbb9b3c495809f461d64b30b76e"
  • 終端窗口1(node1):
    > private.get()
    4
    
  • 終端窗口2(node4):
    > private.get()
    0
    
  • 終端窗口3(node4):
    > private.get()
    4
    

所有7個節點都在驗證相同的交易區塊鏈,隱私交易僅包含512位哈希值來代替交易數據,並且只有隱私交易的參與方纔能查看和更新​​隱私合約狀態。

6. 節點許可測試

節點許可是Quorum中的一項功能,它僅允許一組預定義的節點連接到許可的網絡。
在此演示中,我們將:

  • 查看當前節點已連接的peer
  • 看一下permissioned-nodes.json文件的細節
  • 證明只有permissioned-nodes.json中指定的節點才能連接到網絡
    單個節點可以通過傳遞-permissioned命令行標誌來啓用/禁用。如果啓用,則只有其中的節點/permissioned-nodes.json可以連接到它。

6.1 查看已經連接的節點

進入node1的JavaScript控制檯

docker exec -it quorum-examples_node1_1 geth attach /qdata/dd/geth.ipc

查看已連接的peer

> admin.peers
[{
    caps: ["istanbul/64"],
    enode: "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@172.16.239.17:21000?discport=0&raftport=50400",
    id: "3cb4aaea0f49f73c9de4a34db131288f355bc27090e542ae0be213c20350b767",
    name: "Geth/node7-istanbul/v1.8.18-stable-685f59fb(quorum-v2.5.0)/linux-amd64/go1.11.13",
    network: {
      inbound: false,
      localAddress: "172.16.239.11:48834",
      remoteAddress: "172.16.239.17:21000",
      static: true,
      trusted: false
    },
    protocols: {
      istanbul: {
        difficulty: 36998,
        head: "0xeb173a1f54a705a880fa8f7ee65ee8e8214563713e6a3ca64146d73f5e97f6ac",
        version: 64
      }
    }
}, {
    caps: ["istanbul/64"],
    enode: "enode://0ba6b9f606a43a95edc6247cdb1c1e105145817be7bcafd6b2c0ba15d58145f0dc1a194f70ba73cd6f4cdd6864edc7687f311254c7555cc32e4d45aeb1b80416@172.16.239.12:43910",
    id: "995dbe18829f1affb75402e66571d97f340c8495b661a823f2c2145ca47d63c2",
    name: "Geth/node2-istanbul/v1.8.18-stable-685f59fb(quorum-v2.5.0)/linux-amd64/go1.11.13",
    network: {
      inbound: true,
      localAddress: "172.16.239.11:21000",
      remoteAddress: "172.16.239.12:43910",
      static: false,
      trusted: false
    },
    protocols: {
      istanbul: {
        difficulty: 36998,
        head: "0xeb173a1f54a705a880fa8f7ee65ee8e8214563713e6a3ca64146d73f5e97f6ac",
        version: 64
      }
    }
}, {
    caps: ["istanbul/64"],
    enode: "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@172.16.239.16:52748",
    id: "ab62dd7df5863a5f3bb61f458157d4437104e3b8df4451a85f7b2438ef6699ff",
    name: "Geth/node6-istanbul/v1.8.18-stable-685f59fb(quorum-v2.5.0)/linux-amd64/go1.11.13",
    network: {
      inbound: true,
      localAddress: "172.16.239.11:21000",
      remoteAddress: "172.16.239.16:52748",
      static: false,
      trusted: false
    },
    protocols: {
      istanbul: {
        difficulty: 36997,
        head: "0xfe5892fc865d7c3c759d559e5ca0fe4f52ba30ad38021ddf72e320c5a4b9e6b8",
        version: 64
      }
    }
}, {
    caps: ["istanbul/64"],
    enode: "enode://579f786d4e2830bbcc02815a27e8a9bacccc9605df4dc6f20bcc1a6eb391e7225fff7cb83e5b4ecd1f3a94d8b733803f2f66b7e871961e7b029e22c155c3a778@172.16.239.13:49578",
    id: "c39143f98d04e97bd9e31ac1e36cbeb565b061217930767886474e3cde903ac5",
    name: "Geth/node3-istanbul/v1.8.18-stable-685f59fb(quorum-v2.5.0)/linux-amd64/go1.11.13",
    network: {
      inbound: true,
      localAddress: "172.16.239.11:21000",
      remoteAddress: "172.16.239.13:49578",
      static: false,
      trusted: false
    },
    protocols: {
      istanbul: {
        difficulty: 36997,
        head: "0xfe5892fc865d7c3c759d559e5ca0fe4f52ba30ad38021ddf72e320c5a4b9e6b8",
        version: 64
      }
    }
}, {
    caps: ["istanbul/64"],
    enode: "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@172.16.239.14:37980",
    id: "c75f7dcb9fd6063f0ada0998f512a992f3fb749857d758ffda1330e590fa915e",
    name: "Geth/node4-istanbul/v1.8.18-stable-685f59fb(quorum-v2.5.0)/linux-amd64/go1.11.13",
    network: {
      inbound: true,
      localAddress: "172.16.239.11:21000",
      remoteAddress: "172.16.239.14:37980",
      static: false,
      trusted: false
    },
    protocols: {
      istanbul: {
        difficulty: 36998,
        head: "0xeb173a1f54a705a880fa8f7ee65ee8e8214563713e6a3ca64146d73f5e97f6ac",
        version: 64
      }
    }
}, {
    caps: ["istanbul/64"],
    enode: "enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@172.16.239.15:21000?discport=0&raftport=50400",
    id: "f06c06f1e958cb2edf90d8bfb912de287f9b047b4228436e94b5b78e3ee16171",
    name: "Geth/node5-istanbul/v1.8.18-stable-685f59fb(quorum-v2.5.0)/linux-amd64/go1.11.13",
    network: {
      inbound: false,
      localAddress: "172.16.239.11:51332",
      remoteAddress: "172.16.239.15:21000",
      static: true,
      trusted: false
    },
    protocols: {
      istanbul: {
        difficulty: 36998,
        head: "0xeb173a1f54a705a880fa8f7ee65ee8e8214563713e6a3ca64146d73f5e97f6ac",
        version: 64
      }
    }
}]

6.2 節點許可配置

配置在examples/7nodes/permissioned-nodes.json:

[
  "enode://ac6b1096ca56b9f6d004b779ae3728bf83f8e22453404cc3cef16a3d9b96608bc67c4b30db88e0a5a6c6390213f7acbe1153ff6d23ce57380104288ae19373ef@127.0.0.1:21000?discport=0&raftport=50401",
  "enode://0ba6b9f606a43a95edc6247cdb1c1e105145817be7bcafd6b2c0ba15d58145f0dc1a194f70ba73cd6f4cdd6864edc7687f311254c7555cc32e4d45aeb1b80416@127.0.0.1:21001?discport=0&raftport=50402",
  "enode://579f786d4e2830bbcc02815a27e8a9bacccc9605df4dc6f20bcc1a6eb391e7225fff7cb83e5b4ecd1f3a94d8b733803f2f66b7e871961e7b029e22c155c3a778@127.0.0.1:21002?discport=0&raftport=50403",
  "enode://3d9ca5956b38557aba991e31cf510d4df641dce9cc26bfeb7de082f0c07abb6ede3a58410c8f249dabeecee4ad3979929ac4c7c496ad20b8cfdd061b7401b4f5@127.0.0.1:21003?discport=0&raftport=50404",
  "enode://3701f007bfa4cb26512d7df18e6bbd202e8484a6e11d387af6e482b525fa25542d46ff9c99db87bd419b980c24a086117a397f6d8f88e74351b41693880ea0cb@127.0.0.1:21004?discport=0&raftport=50405",
  "enode://eacaa74c4b0e7a9e12d2fe5fee6595eda841d6d992c35dbbcc50fcee4aa86dfbbdeff7dc7e72c2305d5a62257f82737a8cffc80474c15c611c037f52db1a3a7b@127.0.0.1:21005?discport=0&raftport=50406",
  "enode://239c1f044a2b03b6c4713109af036b775c5418fe4ca63b04b1ce00124af00ddab7cc088fc46020cdc783b6207efe624551be4c06a994993d8d70f684688fb7cf@127.0.0.1:21006?discport=0&raftport=50407"
]

6.3 禁用其中一個節點

刪掉permissioned-nodes.json中的一個node6

vi examples/7nodes/permissioned-nodes.json

重啓網絡

docker-compose restart

連接到node1

docker exec -it quorum-examples_node1_1 geth attach /qdata/dd/geth.ipc

查看peer

>admin.peers

可以觀察,比原來少了一個peer,也可以在cakeshop dashboard中查看,切換到node6 可以發現peer數量爲0

7. cakeshop dashboard

cakeshop是一個集成開發環境,提供管理控制ui,包含節點管理、合約管理、編譯沙箱環境、區塊瀏覽器、錢包管理、peer管理。

打開 http://yourip:8999,觀察節點是否正常。

8. 停止(關閉)quorum網絡

docker-compose down
docker-compose rm

問題

cakeshop容器報錯,不能解析host.docker.internal
解決辦法:修改docker-compose.yaml,在啓動cakeshop的時候將ip地址寫入 /etc/hosts

x-cakeshop-def:
  &cakeshop-def
  image: "${CAKESHOP_DOCKER_IMAGE:-quorumengineering/cakeshop:0.11.0}"
  expose:
    - "8999"
  restart: "no"
  healthcheck:
    test: ["CMD", "wget", "--spider", "--proxy=off", "http://localhost:8999/actuator/health"]
    interval: 5s
    timeout: 5s
    retries: 20
    start_period: 5s
  entrypoint:
    - /bin/sh
    - -c
    - |
      ip -4 route list match 0/0 | awk '{print $$3" host.docker.internal"}' >> /etc/hosts
      DDIR=/qdata/cakeshop/local
      rm -rf $${DDIR}
      mkdir -p $${DDIR}
      DOCKER_IMAGE="${CAKESHOP_DOCKER_IMAGE:-quorumengineering/cakeshop:0.11.0}"
      cp /examples/cakeshop/application.properties.template $${DDIR}/application.properties
      cp /examples/cakeshop/7nodes_docker.json $${DDIR}/7nodes.json
      java -Xms128M -Xmx128M -Dcakeshop.config.dir=/qdata/cakeshop -Dlogging.path=/qdata/logs/cakeshop -jar /opt/cakeshop/cakeshop.war
      ;;

參考

https://github.com/jpmorganchase/quorum-examples
https://github.com/docker/for-linux/issues/264

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章