├── .dockerignore
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── api
├── routes.go
└── server.go
├── cmd
├── blocklator.go
└── server
│ └── main.go
├── docker-compose.yaml
├── docker
└── Dockerfile
├── docs
├── block2.png
├── block3.png
├── ledger1.png
└── ledger2.png
├── front
├── .gitignore
├── README.md
├── babel.config.js
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
└── src
│ ├── App.vue
│ ├── assets
│ └── logo.png
│ ├── common
│ └── consts.js
│ ├── components
│ ├── BlockHead.vue
│ ├── Cert.vue
│ ├── GroupOrg.vue
│ ├── HelloWorld.vue
│ ├── Nav.vue
│ └── Transaction.vue
│ ├── main.js
│ ├── router
│ └── index.js
│ └── views
│ ├── About.vue
│ ├── Block.vue
│ ├── BlockList.vue
│ ├── Config.vue
│ ├── Home.vue
│ ├── Ledger.vue
│ └── Transaction.vue
├── go.mod
├── go.sum
└── pkg
├── block
├── block.go
├── blockfile.go
├── cert.go
├── config.go
├── consts.go
├── ledger.go
├── ledgerutil.go
├── model.go
├── transaction.go
└── txrwset.go
└── store
└── cache.go
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 |
3 | front/node_modules
4 | npm-debug.log
5 |
6 | docs
7 | tmp
8 | ./docker
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Docker Image CI
2 |
3 | on:
4 | push:
5 | branches: [master,main]
6 | pull_request:
7 | branches: [master,main]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 | - name: Build and Push the Docker image
16 | uses: elgohr/Publish-Docker-Github-Action@master
17 | with:
18 | name: tinywell/blocklator
19 | username: ${{ secrets.DOCKER_USERNAME }}
20 | password: ${{ secrets.DOCKER_PASSWORD }}
21 | dockerfile: ./docker/Dockerfile
22 | tag_names: true
23 | cache: true
24 | - name: executing remote ssh commands using key
25 | uses: appleboy/ssh-action@master
26 | with:
27 | host: ${{ secrets.REMOTE_HOST }}
28 | username: ${{ secrets.REMOTE_USERNAME }}
29 | key: ${{ secrets.REMOTE_SSH_KEY }}
30 | script: |
31 | cd blocklator && ./update.sh
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | # Editor directories and files
4 | .idea
5 | .vscode
6 | *.suo
7 | *.ntvs*
8 | *.njsproj
9 | *.sln
10 | *.sw?
11 |
12 | # backend
13 | tmp
14 | vendor
15 |
16 | # Binaries for programs and plugins
17 | *.exe
18 | *.exe~
19 | *.dll
20 | *.so
21 | *.dylib
22 |
23 | # Test binary, build with `go test -c`
24 | *.test
25 |
26 | # Output of the go coverage tool, specifically when used with LiteIDE
27 | *.out
28 |
29 | *.log
30 |
31 | # front
32 |
33 | node_modules
34 | /dist
35 |
36 | # local env files
37 | .env.local
38 | .env.*.local
39 |
40 | # Log files
41 | npm-debug.log*
42 | yarn-debug.log*
43 | yarn-error.log*
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 tinywell
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: front
2 | front:
3 | cd ./front && npm run build
4 |
5 | .PHONY: backend
6 | backend:
7 | go build -v -o blocklator cmd/blocklator.go
8 |
9 | .PHONY: docker
10 | docker:
11 | docker build -f ./docker/Dockerfile -t tinywell/blocklator .
12 |
13 | .PHONY: start
14 | start: front backend
15 | ./blocklator server
16 |
17 | .PHONY: clean
18 | clean:
19 | rm -rf ./front/dist blocklator
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/tinywell/blocklator/network)
2 | [](https://github.com/tinywell/blocklator/stargazers)
3 | [](https://github.com/tinywell/blocklator)
4 | # blocklator
5 |
6 | 这是一个用于解析 hyperledger/fabric 区块链网络产生的区块和账本的 web 小工具。可以解析查看配置区块中的组织结构、共识参数等,也可以解析交易区块中各交易提案和回复的详细数据。还可以直接解析账本文件,提取出其中的所有区块并解析。
7 |
8 | 前端使用 vue,后端使用 gin 提供 RESTful API,并由 gin 代理前端编译后的静态网页文件。
9 |
10 | # 安装部署
11 |
12 | ## 获取源码
13 |
14 | ```
15 | git clone https://github.com/tinywell/blocklator.git
16 | ```
17 |
18 | ## 本地编译部署
19 |
20 | 本地编译需要有 Node 环境及 go 环境
21 |
22 | 编译:
23 |
24 | ```
25 | cd blocklator
26 | make front
27 | make backend
28 | ```
29 |
30 | 启动:
31 |
32 | ```
33 | ./blocklator server
34 | ```
35 |
36 | 或者
37 |
38 | ```
39 | make start
40 | ```
41 |
42 | ## docker 编译部署
43 |
44 | docker 编译部署需要有 docker 环境
45 |
46 | 编译:
47 |
48 | ```
49 | cd blocklator
50 | make docker
51 | ```
52 |
53 | 启动:
54 |
55 | ```
56 | docker-compose up -d
57 | ```
58 |
59 | # 使用说明
60 |
61 | ## 区块解析
62 |
63 | 区块解析可以直接拖拽或点击上传区块文件(比如通过 `peer channel fetch` 命令或其他方式从通道中获取的区块文件)进行解析,也可以直接粘贴经过 base64 编码的区块数据。
64 | 
65 |
66 | 比如交易区块,会解析出交易提案相关请求参数以及回复信息、背书信息等。
67 | 
68 |
69 | ## 账本解析
70 |
71 | 账本解析可以直接拖拽或上传通道账本(比如 peer 节点中维护的 blockfile_000000),解析出其中的所有区块,展示区块列表,并支持查看区块详情。
72 | 
73 | 
74 |
--------------------------------------------------------------------------------
/api/routes.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "github.com/gin-contrib/cors"
5 | ginstatic "github.com/gin-contrib/static"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | // CollectRouter return gin router
10 | func CollectRouter(mode, static string) *gin.Engine {
11 | if len(mode) > 0 {
12 | gin.SetMode(mode)
13 | }
14 | r := gin.Default()
15 | r.Use(cors.Default())
16 | r.Use(ginstatic.Serve("/", ginstatic.LocalFile(static, false)))
17 | // r.Static("/front", static)
18 | r.POST("/api/block/file", BlockFile)
19 | r.POST("/api/block/raw", BlockRaw)
20 | r.POST("/api/ledger/file", LedgerFile)
21 | r.GET("/api/ledger/blocks", LedgerBlocks)
22 |
23 | return r
24 | }
25 |
--------------------------------------------------------------------------------
/api/server.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "bufio"
5 | "encoding/base64"
6 | "encoding/json"
7 | "io/ioutil"
8 | "net/http"
9 | "strconv"
10 |
11 | "github.com/gin-gonic/gin"
12 | "github.com/pkg/errors"
13 |
14 | "github.com/tinywell/blocklator/pkg/block"
15 | "github.com/tinywell/blocklator/pkg/store"
16 | )
17 |
18 | // Pagination params
19 | const (
20 | PageSize = 20
21 | )
22 |
23 | var (
24 | // Cache cache
25 | Cache store.Cache
26 | )
27 |
28 | func init() {
29 | Cache = store.NewCache()
30 | }
31 |
32 | // Ledger ledger data
33 | type Ledger struct {
34 | Pagination bool `json:"pagination" db:"pagination"`
35 | Key string `json:"key,omitempty" db:"key"`
36 | Blocks []*block.Desc `json:"blocks" db:"blocks"`
37 | CurPage int `json:"cur_page" db:"cur_page"`
38 | Total int `json:"total" db:"total"`
39 | }
40 |
41 | // BlockFile translate block data in file
42 | func BlockFile(c *gin.Context) {
43 | rfile, err := c.FormFile("block")
44 | if err != nil {
45 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": err.Error()})
46 | return
47 | }
48 | file, err := rfile.Open()
49 | if err != nil {
50 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": err.Error()})
51 | return
52 | }
53 | blockraw, err := ioutil.ReadAll(file)
54 | if err != nil {
55 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": err.Error()})
56 | return
57 | }
58 | blocklator, err := block.NewBlocklator(blockraw)
59 | if err != nil {
60 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": err.Error()})
61 | return
62 | }
63 | desc, err := blocklator.ToDesc()
64 | if err != nil {
65 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": err.Error()})
66 | return
67 | }
68 |
69 | c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "ok", "data": desc})
70 | return
71 | }
72 |
73 | // BlockRaw translate block data in base64 format
74 | func BlockRaw(c *gin.Context) {
75 | data := c.PostForm("block")
76 | if len(data) == 0 {
77 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": "需要上传区块数据"})
78 | return
79 | }
80 | blockraw, err := base64.StdEncoding.DecodeString(data)
81 | if err != nil {
82 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": err.Error()})
83 | return
84 | }
85 | blocklator, err := block.NewBlocklator(blockraw)
86 | if err != nil {
87 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": err.Error()})
88 | return
89 | }
90 | desc, err := blocklator.ToDesc()
91 | if err != nil {
92 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": err.Error()})
93 | return
94 | }
95 |
96 | c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "ok", "data": desc})
97 | return
98 | }
99 |
100 | // LedgerFile retrive ledger file into blocks
101 | func LedgerFile(c *gin.Context) {
102 | lfile, err := c.FormFile("ledger")
103 | if err != nil {
104 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": err.Error()})
105 | return
106 | }
107 | ledger, err := lfile.Open()
108 | defer ledger.Close()
109 | if err != nil {
110 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": err.Error()})
111 | return
112 | }
113 |
114 | ledgerLator := block.NewLedgerlator(bufio.NewReader(ledger))
115 | blocks, err := ledgerLator.RetriveBlocks()
116 | if err != nil {
117 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": err.Error()})
118 | return
119 | }
120 |
121 | // blockStrs := []string{}
122 | blockSums := []*block.Desc{}
123 | for _, b := range blocks {
124 | // blockStrs = append(blockStrs, base64.StdEncoding.EncodeToString(b))
125 | bl, err := block.NewBlocklatorFromLedgerRaw(b)
126 | if err != nil {
127 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": errors.WithMessage(err, "create blocklator error").Error()})
128 | return
129 | }
130 | sum, err := bl.ToDesc()
131 | if err != nil {
132 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": errors.WithMessage(err, "get block summary").Error()})
133 | return
134 | }
135 | blockSums = append(blockSums, sum)
136 | }
137 | ledgerRsp := &Ledger{
138 | Total: len(blockSums),
139 | Blocks: blockSums,
140 | }
141 | data, err := json.Marshal(blockSums)
142 | if err != nil {
143 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": errors.WithMessage(err, "marsh block summary error").Error()})
144 | return
145 | }
146 | if len(data) > 4*1024*1024 || len(blockSums) > PageSize {
147 | key, err := Cache.KeyGen(data)
148 | if err != nil {
149 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": errors.WithMessage(err, "generate block summar keyy error").Error()})
150 | return
151 | }
152 |
153 | Cache.Store(key, int64(len(data)), blockSums)
154 | ledgerRsp.Key = key
155 | ledgerRsp.CurPage = 1
156 | ledgerRsp.Pagination = true
157 | ledgerRsp.Blocks = blockSums[0:PageSize]
158 | }
159 | c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "ok", "data": ledgerRsp})
160 | return
161 | }
162 |
163 | // LedgerBlocks get blocks by pagination
164 | func LedgerBlocks(c *gin.Context) {
165 | key := c.Query("key")
166 | page := c.Query("page")
167 | if len(key) == 0 || len(page) == 0 {
168 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": errors.New("paaination query need key and page").Error()})
169 | return
170 | }
171 | cp, err := strconv.Atoi(page)
172 | if err != nil {
173 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": errors.WithMessage(err, "decode page param error").Error()})
174 | return
175 | }
176 | blocks, err := Cache.Load(key)
177 | if err != nil {
178 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": errors.WithMessage(err, "get data cache error").Error()})
179 | return
180 | }
181 | if blockSum, ok := blocks.([]*block.Desc); ok {
182 | ledgerRsp := Ledger{
183 | Pagination: true,
184 | CurPage: cp,
185 | Key: key,
186 | Total: len(blockSum),
187 | }
188 | start := (cp - 1) * PageSize
189 | end := cp * PageSize
190 | if end > len(blockSum) {
191 | end = len(blockSum)
192 | }
193 | ledgerRsp.Blocks = blockSum[start:end]
194 | c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "ok", "data": ledgerRsp})
195 | return
196 | }
197 | c.JSON(http.StatusOK, gin.H{"code": 500, "msg": "data cache invalid ,please reload your ledger file"})
198 | return
199 | }
200 |
--------------------------------------------------------------------------------
/cmd/blocklator.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "os"
6 |
7 | "github.com/spf13/cobra"
8 | "github.com/tinywell/blocklator/cmd/server"
9 | )
10 |
11 | var (
12 | rootCmd = &cobra.Command{
13 | Use: "blocklator",
14 | Short: "blocklator is a tool to translate fabric block",
15 | }
16 | )
17 |
18 | func main() {
19 | rootCmd.AddCommand(server.ServerCmd)
20 |
21 | if err := rootCmd.Execute(); err != nil {
22 | fmt.Println(err)
23 | os.Exit(1)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/server/main.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 |
8 | // pprof for server
9 | _ "net/http/pprof"
10 |
11 | "github.com/gin-gonic/gin"
12 | "github.com/spf13/cobra"
13 | "github.com/tinywell/blocklator/api"
14 | )
15 |
16 | var (
17 | port int
18 | production bool
19 | static string
20 |
21 | // ServerCmd server subcommand
22 | ServerCmd = &cobra.Command{
23 | Use: "server",
24 | Short: "server is a backend web service use of gin",
25 | Run: func(cmd *cobra.Command, args []string) {
26 | Execute()
27 | },
28 | }
29 | )
30 |
31 | func init() {
32 | ServerCmd.PersistentFlags().IntVarP(&port, "port", "p", 8080, "listen port")
33 | ServerCmd.PersistentFlags().BoolVarP(&production, "production", "m", false, "is in production mode")
34 | ServerCmd.PersistentFlags().StringVarP(&static, "static", "s", "./front/dist", "front page path")
35 | }
36 |
37 | // Execute execute server command
38 | func Execute() {
39 |
40 | go func() {
41 | log.Println(http.ListenAndServe("localhost:6060", nil))
42 | }()
43 |
44 | var mode = gin.DebugMode
45 | if production {
46 | mode = gin.ReleaseMode
47 | }
48 |
49 | r := api.CollectRouter(mode, static)
50 |
51 | if err := r.Run(fmt.Sprintf("0.0.0.0:%d", port)); err != nil {
52 | panic(err)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: "2"
2 |
3 | services:
4 | blocklator:
5 | container_name: blocklator
6 | image: tinywell/blocklator:latest
7 | tty: true
8 | stdin_open: true
9 | # environment:
10 | #
11 | ports:
12 | - 8080:80
13 | working_dir: /app
14 | # command:
15 | # volumes:
16 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | ## node 前端编译
2 | FROM node:16.14-alpine as nodeBuilder
3 |
4 | WORKDIR /app
5 |
6 | COPY ./front ./
7 |
8 | # RUN npm config set registry https://registry.npm.taobao.org && \
9 | # npm install
10 |
11 | RUN npm install
12 |
13 | RUN npm run build
14 |
15 | ## go 后端编译
16 | FROM golang:1.13-alpine as goBuilder
17 |
18 | WORKDIR /app
19 |
20 | COPY ./ ./
21 |
22 | # RUN go env -w GOPROXY="https://goproxy.cn,direct" && \
23 | # go build -v -o blocklator ./cmd/blocklator.go
24 |
25 | RUN go build -v -o blocklator ./cmd/blocklator.go
26 |
27 | ## 构建运行镜像
28 | FROM alpine:latest
29 |
30 | WORKDIR /app
31 |
32 | COPY --from=nodebuilder /app/dist/ ./dist
33 | COPY --from=goBuilder /app/blocklator ./
34 |
35 | EXPOSE 80
36 |
37 | CMD [ "./blocklator","server","-m","-p","80","-s","./dist"]
--------------------------------------------------------------------------------
/docs/block2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tinywell/blocklator/3c5d65d5d83ff01f1cf2def1acd7d3c6f9eeb400/docs/block2.png
--------------------------------------------------------------------------------
/docs/block3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tinywell/blocklator/3c5d65d5d83ff01f1cf2def1acd7d3c6f9eeb400/docs/block3.png
--------------------------------------------------------------------------------
/docs/ledger1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tinywell/blocklator/3c5d65d5d83ff01f1cf2def1acd7d3c6f9eeb400/docs/ledger1.png
--------------------------------------------------------------------------------
/docs/ledger2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tinywell/blocklator/3c5d65d5d83ff01f1cf2def1acd7d3c6f9eeb400/docs/ledger2.png
--------------------------------------------------------------------------------
/front/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/front/README.md:
--------------------------------------------------------------------------------
1 | # front
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Customize configuration
19 | See [Configuration Reference](https://cli.vuejs.org/config/).
20 |
--------------------------------------------------------------------------------
/front/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/front/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "blocklator",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve --port 8081",
7 | "build": "vue-cli-service build"
8 | },
9 | "dependencies": {
10 | "core-js": "^3.6.4",
11 | "element-ui": "^2.13.2",
12 | "vue": "^2.6.11",
13 | "vue-router": "^3.1.6"
14 | },
15 | "devDependencies": {
16 | "@vue/cli-plugin-babel": "~4.3.0",
17 | "@vue/cli-plugin-router": "~4.3.0",
18 | "@vue/cli-service": "~4.3.0",
19 | "axios": ">=0.21.2",
20 | "less": "^3.0.4",
21 | "less-loader": "^5.0.0",
22 | "vue-template-compiler": "^2.6.11"
23 | },
24 | "browserslist": [
25 | "> 1%",
26 | "last 2 versions",
27 | "not dead"
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/front/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tinywell/blocklator/3c5d65d5d83ff01f1cf2def1acd7d3c6f9eeb400/front/public/favicon.ico
--------------------------------------------------------------------------------
/front/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/front/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 区块解析 |
5 | 账本解析
6 |
7 |
8 |
9 |
10 |
11 |
12 |
38 |
--------------------------------------------------------------------------------
/front/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tinywell/blocklator/3c5d65d5d83ff01f1cf2def1acd7d3c6f9eeb400/front/src/assets/logo.png
--------------------------------------------------------------------------------
/front/src/common/consts.js:
--------------------------------------------------------------------------------
1 | let ServerAddrPre = '/api';
2 | if(process.env.NODE_ENV==="development"){
3 | ServerAddrPre = 'http://localhost:8080/api';
4 | }
5 |
6 |
7 | const BlockTypeOpts = [
8 | { text: '配置区块', value: 1 },
9 | { text: '交易区块', value: 0 },
10 | ];
11 |
12 | const BlockTypeOptsMap = {};
13 | BlockTypeOpts.forEach((item) => { BlockTypeOptsMap[item.value] = item.text; });
14 |
15 |
16 | export default {
17 | BlockTypeOpts,
18 | BlockTypeOptsMap,
19 | ServerAddrPre
20 | }
--------------------------------------------------------------------------------
/front/src/components/BlockHead.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 区块号:
5 | {{ block.block_num }}
6 |
7 |
8 | 通道:
9 | {{ block.channel }}
10 |
11 |
12 | 区块哈希:
13 | {{ block.hash }}
14 |
15 |
16 | 前区块哈希:
17 | {{ block.pre_hash }}
18 |
19 |
20 | Commit 哈希:
21 | {{ block.commit_hash }}
22 |
23 |
24 | 交易数量:
25 | {{ block.trans_count }}
26 |
27 |
28 | 配置区块号:
29 | {{ block.last_config }}
30 |
31 |
32 | 区块类型:
33 | {{
34 | this.$consts.BlockTypeOptsMap[block.type]
35 | }}
36 |
37 |
38 |
39 |
40 |
47 |
48 |
--------------------------------------------------------------------------------
/front/src/components/Cert.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CN:
5 | {{ cert.cn }}
6 |
7 |
8 | O:
9 | {{ cert.org }}
10 |
11 |
12 | OU:
13 | {{ cert.ou }}
14 |
15 |
16 | {{ cert.pem }}
17 |
18 |
19 |
20 |
21 |
28 |
29 |
--------------------------------------------------------------------------------
/front/src/components/GroupOrg.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ org.name }}
4 |
5 |
6 |
7 | {{ org.root_cert }}
8 |
9 |
10 | {{ org.tls_root_cert }}
11 |
12 |
13 | {{ org.admin }}
14 |
15 |
16 |
17 | AnchorPeers:
18 | OrdererAddresses:
19 |
26 | {{ endpoint }}
27 |
28 |
29 |
30 |
31 |
32 |
40 |
41 |
--------------------------------------------------------------------------------
/front/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
27 |
28 |
29 |
31 |
--------------------------------------------------------------------------------
/front/src/components/Nav.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/front/src/components/Transaction.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 提案请求MSPID:
7 | {{
8 | transaction.signer.mspid
9 | }}
10 |
11 |
20 |
21 | 提案请求者签名:
22 |
23 |
24 |
25 |
26 |
27 | {{ transaction.signer.signature }}
29 |
30 |
31 |
32 |
33 | 通道:
34 | {{ transaction.channel }}
35 |
36 |
37 | TxID:
38 | {{ transaction.tx_id }}
39 |
40 |
41 | 时间:
42 | {{ transaction.time }}
43 |
44 |
45 | 交易有效性:
46 | {{ transaction.filter }} | {{ transaction.validation_code }}
48 |
49 |
50 |
51 | 链码:
52 | {{ transaction.chaincode }}
53 |
54 |
55 | 方法:
56 | {{ transaction.func }}
57 |
58 |
59 |
60 |
61 |
62 | 请求参数
63 |
68 | [{{ index }}] {{ arg }}
69 |
70 |
71 |
72 | 回复数据
73 | 回复状态:{{ transaction.resp.status }}
74 | 回复消息:{{ transaction.resp.message }}
75 | 回复数据:{{ transaction.resp.data }}
76 |
77 |
78 |
79 |
84 | 读写集 namespace: {{ rwset.name_space }}
85 |
86 |
87 | 读集
88 |
93 |
key: {{ read.key }}
94 |
95 | version: {block:{{
96 | read.version.block_num
97 | }}
98 | txnum:{{ read.version.tx_num }}
99 | }
100 |
101 |
102 |
103 |
104 | 写集
105 |
110 |
key: {{ write.key }}
111 |
value: {{ write.value }}
112 |
113 |
114 |
115 |
116 |
117 |
118 | 背书签名
119 | [{{ i }}]
124 |
125 |
126 |
127 |
128 | {{ e.signature }}
129 |
130 |
131 |
132 |
133 |
134 |
146 |
147 |
--------------------------------------------------------------------------------
/front/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import ElementUI from 'element-ui'
3 | import 'element-ui/lib/theme-chalk/index.css'
4 | import App from './App.vue'
5 | import router from './router'
6 | import axios from 'axios';
7 | import consts from './common/consts';
8 |
9 | Vue.prototype.$consts = consts;
10 | Vue.prototype.$axios = axios
11 |
12 | Vue.config.productionTip = false
13 | Vue.use(ElementUI);
14 |
15 | new Vue({
16 | router,
17 | render: h => h(App)
18 | }).$mount('#app')
19 |
--------------------------------------------------------------------------------
/front/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueRouter from 'vue-router'
3 | import Block from '../views/Block.vue'
4 |
5 | Vue.use(VueRouter)
6 |
7 | const routes = [
8 | {
9 | path: '/',
10 | name: 'Block',
11 | component: Block
12 | },
13 | {
14 | path: '/about',
15 | name: 'About',
16 | // route level code-splitting
17 | // this generates a separate chunk (about.[hash].js) for this route
18 | // which is lazy-loaded when the route is visited.
19 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
20 | },
21 | {
22 | path: '/config',
23 | name: 'Config',
24 | component: () => import(/* webpackChunkName: "Config" */ '../views/Config.vue')
25 | },
26 | {
27 | path: '/transaction',
28 | name: 'Transaction',
29 | component: () => import(/* webpackChunkName: "Transaction" */ '../views/Transaction.vue')
30 | },
31 | {
32 | path: '/block',
33 | name: 'Block',
34 | component: () => import(/* webpackChunkName: "Block" */ '../views/Block.vue')
35 | },
36 | {
37 | path: '/ledger',
38 | name: 'Ledger',
39 | component: () => import(/* webpackChunkName: "Ledger" */ '../views/Ledger.vue')
40 | },
41 | {
42 | path: '/blocklist',
43 | name: 'BlockList',
44 | component: () => import(/* webpackChunkName: "BlockList" */ '../views/BlockList.vue')
45 | },
46 | ]
47 |
48 | const router = new VueRouter({
49 | mode: 'history',
50 | routes
51 | })
52 |
53 | export default router
54 |
--------------------------------------------------------------------------------
/front/src/views/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/front/src/views/Block.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
15 |
16 | 将区块文件拖到此处,或点击上传
17 |
18 |
19 | 上传通过 'peer channel fetch'
20 | 命令或其他方式从网络中拉取的单个区块文件(eg:mychannel.block)
21 |
22 |
23 | OR
24 |
25 |
26 |
32 |
33 |
34 | 提交
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
102 |
103 |
--------------------------------------------------------------------------------
/front/src/views/BlockList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
122 |
123 |
--------------------------------------------------------------------------------
/front/src/views/Config.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
13 |
14 |
18 |
19 |
20 |
联盟:
21 |
{{ name }}
22 |
23 |
24 |
25 | -
26 |
32 |
33 |
34 | {{ org.name }}
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | 应用组织
46 |
47 |
48 | -
53 |
59 |
60 |
61 |
62 | {{ org.name }}
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | 共识组织
71 |
72 |
73 | -
74 |
80 |
81 |
82 | {{ org.name }}
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | 共识参数
93 |
94 |
95 | 共识类型:
96 | {{
97 | block.config.consensus.type
98 | }}
99 |
100 |
101 | 区块最大交易数:
102 | {{
103 | block.config.consensus.max_message_count
104 | }}
105 |
106 |
107 | 区块最大绝对值 absolute:
110 | {{ block.config.consensus.absolute_max_bytes }} (Byte)
113 |
114 |
115 | 区块最大偏好值 preferred:
118 | {{ block.config.consensus.preferred_max_bytes }} (Byte)
121 |
122 |
123 | 出块超时时间:
124 | {{ block.config.consensus.batch_time_out }}
126 |
127 |
128 |
129 | raft consenters:
130 |
131 |
138 | {{ consenter.host }}:{{ consenter.port }}
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 | 网络参数
148 |
149 |
150 | hash 算法:
151 | {{ block.config.values.hashing_algorithm }}
153 |
154 |
155 |
156 | 联盟:
157 | {{ block.config.values.consortium }}
159 |
160 |
161 |
162 | 共识服务节点地址:
163 |
168 |
174 | {{ addr }}
175 |
176 |
177 |
178 |
179 | Channel Capabilities:
180 |
181 |
187 | {{ cap }}
188 |
189 |
190 |
191 |
192 | Orderer Capabilities:
193 |
194 |
200 | {{ cap }}
201 |
202 |
203 |
204 |
205 | Applicaiton Capabilities:
208 |
213 |
219 | {{ cap }}
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
374 |
375 |
--------------------------------------------------------------------------------
/front/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
18 |
--------------------------------------------------------------------------------
/front/src/views/Ledger.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 | 将账本文件拖到此处,或点击上传
13 |
14 | 上传 fabric peer 节点存储的账本文件(eg:blockfile_000000)
15 |
16 |
17 |
18 |
19 |
20 |
52 |
53 |
--------------------------------------------------------------------------------
/front/src/views/Transaction.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
75 |
76 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/tinywell/blocklator
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/gin-contrib/cors v1.3.1
7 | github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2
8 | github.com/gin-gonic/gin v1.7.7
9 | github.com/golang/protobuf v1.3.3
10 | github.com/hyperledger/fabric v1.4.7
11 | github.com/hyperledger/fabric-protos-go v0.0.0-20200506201313-25f6564b9ac4
12 | github.com/kr/text v0.2.0 // indirect
13 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
14 | github.com/modern-go/reflect2 v1.0.1 // indirect
15 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
16 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
17 | github.com/pkg/errors v0.9.1
18 | github.com/spf13/cobra v1.0.0
19 | github.com/stretchr/testify v1.6.1 // indirect
20 | github.com/sykesm/zap-logfmt v0.0.3 // indirect
21 | golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
22 | golang.org/x/text v0.3.3 // indirect
23 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a // indirect
24 | gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
25 | gopkg.in/yaml.v2 v2.3.0 // indirect
26 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
27 | )
28 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
3 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
4 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
5 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
6 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
7 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
8 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
9 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
10 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
11 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
12 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
13 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
14 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
15 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
16 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
17 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
18 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
19 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
20 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
21 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
22 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
23 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
24 | github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
25 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
26 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
27 | github.com/gin-contrib/cors v1.3.1 h1:doAsuITavI4IOcd0Y19U4B+O0dNWihRyX//nn4sEmgA=
28 | github.com/gin-contrib/cors v1.3.1/go.mod h1:jjEJ4268OPZUcU7k9Pm653S7lXUGcqMADzFA61xsmDk=
29 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
30 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
31 | github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2 h1:xLG16iua01X7Gzms9045s2Y2niNpvSY/Zb1oBwgNYZY=
32 | github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2/go.mod h1:VhW/Ch/3FhimwZb8Oj+qJmdMmoB8r7lmJ5auRjm50oQ=
33 | github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
34 | github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
35 | github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
36 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
37 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
38 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
39 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
40 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
41 | github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
42 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
43 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
44 | github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
45 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
46 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
47 | github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
48 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
49 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
50 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
51 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
52 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
53 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
54 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
55 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
56 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
57 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
58 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
59 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
60 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
61 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
62 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
63 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
64 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
65 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
66 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
67 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
68 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
69 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
70 | github.com/hyperledger/fabric v1.4.7 h1:weX0z8WybFIj2TTF0QOa+vBxwxBRZToRms3E1wtfRZk=
71 | github.com/hyperledger/fabric v1.4.7/go.mod h1:tGFAOCT696D3rG0Vofd2dyWYLySHlh0aQjf7Q1HAju0=
72 | github.com/hyperledger/fabric-protos-go v0.0.0-20200506201313-25f6564b9ac4 h1:75hBp86WljV3uQ7Q/wbO5w8ahfLAzxH7jfT5kVy2n6g=
73 | github.com/hyperledger/fabric-protos-go v0.0.0-20200506201313-25f6564b9ac4/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
74 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
75 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
76 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
77 | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
78 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
79 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
80 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
81 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
82 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
83 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
84 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
85 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
86 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
87 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
88 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
89 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
90 | github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
91 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
92 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
93 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
94 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
95 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
96 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
97 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
98 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
99 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
100 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
101 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
102 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
103 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
104 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
105 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
106 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
107 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
108 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
109 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
110 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
111 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
112 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
113 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
114 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
115 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
116 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
117 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
118 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
119 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
120 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
121 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
122 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
123 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
124 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
125 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
126 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
127 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
128 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
129 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
130 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
131 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
132 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
133 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
134 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
135 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
136 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
137 | github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
138 | github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
139 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
140 | github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
141 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
142 | github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
143 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
144 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
145 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
146 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
147 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
148 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
149 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
150 | github.com/sykesm/zap-logfmt v0.0.3 h1:3Wrhf7+I9JEUD8B6KPtDAr9j2jrS0/EPLy7GCE1t/+U=
151 | github.com/sykesm/zap-logfmt v0.0.3/go.mod h1:AuBd9xQjAe3URrWT1BBDk2v2onAZHkZkWRMiYZXiZWA=
152 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
153 | github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
154 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
155 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
156 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
157 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
158 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
159 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
160 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
161 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
162 | go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
163 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
164 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
165 | go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
166 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
167 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
168 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
169 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
170 | go.uber.org/zap v1.12.0 h1:dySoUQPFBGj6xwjmBzageVL8jGi8uxc6bEmJQjA06bw=
171 | go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
172 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
173 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
174 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
175 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
176 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
177 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
178 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
179 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
180 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
181 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
182 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
183 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
184 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
185 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
186 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
187 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
188 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
189 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
190 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
191 | golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
192 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
193 | golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
194 | golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
195 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
196 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
197 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
198 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
199 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
200 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
201 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
202 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
203 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
204 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
205 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
206 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
207 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
208 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
209 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
210 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
211 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
212 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
213 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
214 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
215 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
216 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
217 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
218 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
219 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
220 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
221 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
222 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
223 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
224 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
225 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
226 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
227 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
228 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
229 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4=
230 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
231 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
232 | google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
233 | google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
234 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
235 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
236 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
237 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
238 | gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
239 | gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
240 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
241 | gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
242 | gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
243 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
244 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
245 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
246 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
247 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
248 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
249 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
250 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
251 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
252 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
253 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
254 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
255 | honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
256 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
257 |
--------------------------------------------------------------------------------
/pkg/block/block.go:
--------------------------------------------------------------------------------
1 | package block
2 |
3 | import (
4 | "encoding/base64"
5 | "strings"
6 |
7 | "github.com/golang/protobuf/proto"
8 | "github.com/hyperledger/fabric-protos-go/common"
9 | "github.com/hyperledger/fabric-protos-go/peer"
10 | "github.com/pkg/errors"
11 | )
12 |
13 | // Blocklator for block translate
14 | type Blocklator struct {
15 | block *common.Block
16 | }
17 |
18 | // NewBlocklator return new Blocklator
19 | func NewBlocklator(raw []byte) (*Blocklator, error) {
20 | cb := &common.Block{}
21 | err := proto.Unmarshal(raw, cb)
22 | if err != nil {
23 | return nil, err
24 | }
25 | return &Blocklator{
26 | block: cb,
27 | }, nil
28 | }
29 |
30 | // NewBlocklatorFromLedgerRaw return new Blocklator from block data in ledger
31 | func NewBlocklatorFromLedgerRaw(raw []byte) (*Blocklator, error) {
32 | block, err := ExtractLeaderBlock(raw)
33 | if err != nil {
34 | return nil, err
35 | }
36 | return &Blocklator{
37 | block: block,
38 | }, nil
39 | }
40 |
41 | // GetBlockNum return block num
42 | func (bl *Blocklator) GetBlockNum() uint64 {
43 | return bl.block.Header.Number
44 | }
45 |
46 | // GetBlockHash return block hash
47 | func (bl *Blocklator) GetBlockHash() string {
48 | // hash := bl.block.Header.DataHash
49 | hash := HeaderHash(bl.block.Header)
50 | // return strings.ToUpper(hex.EncodeToString(hash))
51 | return strings.ToUpper(base64.StdEncoding.EncodeToString(hash))
52 | }
53 |
54 | // GetBlockPrehash return block previoous hash
55 | func (bl *Blocklator) GetBlockPrehash() string {
56 | hash := bl.block.Header.PreviousHash
57 | // return strings.ToUpper(hex.EncodeToString(hash))
58 | return strings.ToUpper(base64.StdEncoding.EncodeToString(hash))
59 | }
60 |
61 | // GetChannel return channel id
62 | func (bl *Blocklator) GetChannel() (string, error) {
63 | if len(bl.block.Data.Data) < 1 {
64 | return "", errors.New("invalid block")
65 | }
66 | env := &common.Envelope{}
67 | err := proto.Unmarshal(bl.block.Data.Data[0], env)
68 | if err != nil {
69 | return "", err
70 | }
71 | payload := &common.Payload{}
72 | err = proto.Unmarshal(env.Payload, payload)
73 | if err != nil {
74 | return "", err
75 | }
76 | ch := &common.ChannelHeader{}
77 | err = proto.Unmarshal(payload.Header.ChannelHeader, ch)
78 | if err != nil {
79 | return "", err
80 | }
81 | return ch.ChannelId, nil
82 | }
83 |
84 | // GetMetaDataLastConfig get the last config block num
85 | func (bl *Blocklator) GetMetaDataLastConfig() (uint64, error) {
86 | if len(bl.block.Metadata.Metadata) > int(common.BlockMetadataIndex_LAST_CONFIG) {
87 | meta := bl.block.Metadata.Metadata[common.BlockMetadataIndex_LAST_CONFIG]
88 | cmeta := &common.Metadata{}
89 | err := proto.Unmarshal(meta, cmeta)
90 | if err != nil {
91 | return 0, errors.Wrap(err, "unmarshal metadata error")
92 | }
93 | index := cmeta.Value
94 | cindex := &common.LastConfig{}
95 | err = proto.Unmarshal(index, cindex)
96 | if err != nil {
97 | return 0, errors.Wrap(err, "unmarshal lastconfig error")
98 | }
99 | return cindex.Index, nil
100 | }
101 | return 0, errors.New("no metadata for lastconfig")
102 | }
103 |
104 | // GetMetaDataTransFilter 获取交易有效性标志
105 | func (bl *Blocklator) GetMetaDataTransFilter() ([]bool, error) {
106 | txfilters := []bool{}
107 | if len(bl.block.Metadata.Metadata) > int(common.BlockMetadataIndex_TRANSACTIONS_FILTER) {
108 | filter := bl.block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]
109 | for _, f := range filter {
110 | tf := false
111 | if peer.TxValidationCode(f) == peer.TxValidationCode_VALID {
112 | tf = true
113 | }
114 | txfilters = append(txfilters, tf)
115 | }
116 | return txfilters, nil
117 | }
118 | return nil, errors.New("no metadata for transaction filter")
119 | }
120 |
121 | // GetMetaDataTransValidationCode 获取交易有效性标志
122 | func (bl *Blocklator) GetMetaDataTransValidationCode() ([]peer.TxValidationCode, error) {
123 | txfilters := []peer.TxValidationCode{}
124 | if len(bl.block.Metadata.Metadata) > int(common.BlockMetadataIndex_TRANSACTIONS_FILTER) {
125 | filter := bl.block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]
126 | for _, f := range filter {
127 | txfilters = append(txfilters, peer.TxValidationCode(f))
128 | }
129 | return txfilters, nil
130 | }
131 | return nil, errors.New("no metadata for transaction filter")
132 | }
133 |
134 | // GetCommitHash get commit hash of the block
135 | func (bl *Blocklator) GetCommitHash() (string, error) {
136 | if len(bl.block.Metadata.Metadata) > int(common.BlockMetadataIndex_COMMIT_HASH) {
137 | meta := &common.Metadata{}
138 | hash := bl.block.Metadata.Metadata[common.BlockMetadataIndex_COMMIT_HASH]
139 | err := proto.Unmarshal(hash, meta)
140 | if err != nil {
141 | return "", err
142 | }
143 | // return strings.ToUpper(hex.EncodeToString(meta.Value)), nil
144 | return strings.ToUpper(base64.StdEncoding.EncodeToString(meta.Value)), nil
145 | }
146 | return "", errors.New("no commit hash,invalid block metadata")
147 | }
148 |
149 | // GetConfig get config from block
150 | func (bl *Blocklator) GetConfig() *common.Config {
151 | if len(bl.block.Data.Data) > 1 || len(bl.block.Data.Data) < 1 {
152 | return nil
153 | }
154 | env := &common.Envelope{}
155 | err := proto.Unmarshal(bl.block.Data.Data[0], env)
156 | if err != nil {
157 | return nil
158 | }
159 | payload := &common.Payload{}
160 | err = proto.Unmarshal(env.Payload, payload)
161 | if err != nil {
162 | return nil
163 | }
164 |
165 | cfgenv := &common.ConfigEnvelope{}
166 | err = proto.Unmarshal(payload.Data, cfgenv)
167 | if err != nil {
168 | return nil
169 | }
170 | return cfgenv.Config
171 | }
172 |
173 | // GetTransactions get transction envelops from block
174 | func (bl *Blocklator) GetTransactions() []*common.Envelope {
175 | envs := []*common.Envelope{}
176 | for _, d := range bl.block.Data.Data {
177 | env := &common.Envelope{}
178 | err := proto.Unmarshal(d, env)
179 | if err != nil {
180 | continue
181 | }
182 | envs = append(envs, env)
183 | }
184 | return envs
185 | }
186 |
187 | // GetSummary get block summary info
188 | func (bl *Blocklator) GetSummary() (*Summary, error) {
189 | sum := &Summary{}
190 | sum.BlockNum = bl.GetBlockNum()
191 | channel, err := bl.GetChannel()
192 | if err != nil {
193 | sum.Channel = ""
194 | }
195 | sum.Channel = channel
196 | sum.Hash = bl.GetBlockHash()
197 | sum.PreHash = bl.GetBlockPrehash()
198 | if err != nil {
199 | return nil, err
200 | }
201 | sum.LastConfig, err = bl.GetMetaDataLastConfig()
202 | if err != nil {
203 | return nil, err
204 | }
205 | config := bl.GetConfig()
206 | if config == nil {
207 | sum.Type = BlockTypeTrans
208 | filters, err := bl.GetMetaDataTransFilter()
209 | if err != nil {
210 | return nil, err
211 | }
212 | sum.TransCount = len(filters)
213 | sum.CommitHash, err = bl.GetCommitHash()
214 | } else {
215 | sum.Type = BlockTypeConfig
216 | }
217 | return sum, nil
218 | }
219 |
220 | // ToDesc block to Desc
221 | func (bl *Blocklator) ToDesc() (*Desc, error) {
222 | blockdesc := &Desc{}
223 | blockdesc.BlockNum = bl.GetBlockNum()
224 | channel, err := bl.GetChannel()
225 | if err != nil {
226 | blockdesc.Channel = ""
227 | }
228 | blockdesc.Channel = channel
229 | blockdesc.Hash = bl.GetBlockHash()
230 | blockdesc.PreHash = bl.GetBlockPrehash()
231 | if err != nil {
232 | return nil, err
233 | }
234 | blockdesc.LastConfig, err = bl.GetMetaDataLastConfig()
235 | if err != nil {
236 | return nil, err
237 | }
238 | config := bl.GetConfig()
239 | if config == nil {
240 | blockdesc.Type = BlockTypeTrans
241 | filters, err := bl.GetMetaDataTransFilter()
242 | if err != nil {
243 | return nil, err
244 | }
245 | codes, err := bl.GetMetaDataTransValidationCode()
246 | if err != nil {
247 | return nil, err
248 | }
249 | trans := bl.GetTransactions()
250 | for i, t := range trans {
251 | translator, err := NewTranslator(t)
252 | if err != nil {
253 | continue
254 | }
255 | desc := translator.ToDesc()
256 | if len(filters) > i {
257 | desc.Filter = filters[i]
258 | }
259 | if len(codes) > i {
260 | desc.ValidationCode = peer.TxValidationCode_name[int32(codes[i])]
261 | }
262 | blockdesc.Transactions = append(blockdesc.Transactions, desc)
263 | }
264 | blockdesc.TransCount = len(trans)
265 | blockdesc.CommitHash, err = bl.GetCommitHash()
266 | } else {
267 | cfg := NewConfiglator(config)
268 | cfgdesc := cfg.ToDesc()
269 | blockdesc.Type = BlockTypeConfig
270 | blockdesc.Config = cfgdesc
271 | }
272 | return blockdesc, nil
273 | }
274 |
--------------------------------------------------------------------------------
/pkg/block/blockfile.go:
--------------------------------------------------------------------------------
1 | package block
2 |
--------------------------------------------------------------------------------
/pkg/block/cert.go:
--------------------------------------------------------------------------------
1 | package block
2 |
3 | import (
4 | "crypto/x509"
5 | "encoding/pem"
6 | "strings"
7 | "sync"
8 |
9 | "github.com/pkg/errors"
10 | )
11 |
12 | var certPool *sync.Pool
13 |
14 | func init() {
15 | certPool = &sync.Pool{
16 | New: func() interface{} {
17 | return &Cert{}
18 | },
19 | }
20 | }
21 |
22 | // Cert cert
23 | type Cert struct {
24 | Pem string `json:"pem,omitempty" db:"pem"`
25 | CN string `json:"cn,omitempty" db:"cn"`
26 | OU string `json:"ou,omitempty" db:"ou"`
27 | Org string `json:"org,omitempty" db:"org"`
28 | }
29 |
30 | // NewCert return new Cert
31 | func NewCert(certRaw []byte) (*Cert, error) {
32 | c := &Cert{
33 | Pem: string(certRaw),
34 | }
35 | // c := certPool.Get().(*Cert)
36 | // c.Pem = string(certRaw)
37 | b, _ := pem.Decode([]byte(certRaw))
38 | if b == nil {
39 | return nil, errors.New("decode cert pem error")
40 | }
41 | cert, err := x509.ParseCertificate(b.Bytes)
42 | if err != nil {
43 | return nil, errors.Wrap(err, "parse cert error")
44 | }
45 | c.CN = cert.Subject.CommonName
46 | c.OU = strings.Join(cert.Subject.OrganizationalUnit, ",")
47 | c.Org = strings.Join(cert.Issuer.Organization, ",")
48 | return c, nil
49 | }
50 |
--------------------------------------------------------------------------------
/pkg/block/config.go:
--------------------------------------------------------------------------------
1 | package block
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/golang/protobuf/proto"
7 | "github.com/hyperledger/fabric-protos-go/common"
8 | "github.com/hyperledger/fabric-protos-go/msp"
9 | "github.com/hyperledger/fabric-protos-go/orderer"
10 | "github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
11 | "github.com/hyperledger/fabric-protos-go/peer"
12 | "github.com/pkg/errors"
13 | )
14 |
15 | // Configlator 配置信息解析
16 | type Configlator struct {
17 | config *common.Config
18 | }
19 |
20 | // NewConfiglator 返回一个 Configlator
21 | func NewConfiglator(config *common.Config) *Configlator {
22 | return &Configlator{
23 | config: config,
24 | }
25 | }
26 |
27 | // ToDesc return ConfigDesc
28 | func (c *Configlator) ToDesc() *ConfigDesc {
29 | desc := &ConfigDesc{}
30 | desc.ApplicationOrgs = c.GetApplicationOrgs()
31 | desc.ConsortiumOrgs = c.GetConsortiumOrgs()
32 | desc.OrdererOrgs = c.GetOrdererOrgs()
33 | desc.Consensus = c.GetConsensusInfo()
34 | desc.Values = c.GetValues()
35 | desc.ApplicationValues = c.GetApplicationValues()
36 | return desc
37 | }
38 |
39 | // GetValues 解析配置块中的基本参数信息
40 | func (c *Configlator) GetValues() *ConfigValues {
41 | values := &ConfigValues{}
42 | pha := &common.HashingAlgorithm{}
43 | err := proto.Unmarshal(c.config.ChannelGroup.Values[HashingAlgorithmKey].Value, pha)
44 | if err != nil {
45 | return nil
46 | }
47 | values.HashingAlgorithm = pha.Name
48 |
49 | if ct, ok := c.config.ChannelGroup.Values[ConsortiumKey]; ok {
50 | pct := &common.Consortium{}
51 | err = proto.Unmarshal(ct.Value, pct)
52 | if err != nil {
53 | return nil
54 | }
55 | values.Consortium = pct.Name
56 | }
57 | pod := &common.OrdererAddresses{}
58 | if oa, ok := c.config.ChannelGroup.Values[OrdererAddressesKey]; ok {
59 | err = proto.Unmarshal(oa.Value, pod)
60 | if err != nil {
61 | return nil
62 | }
63 | }
64 | values.OrdererAddresses = pod.Addresses
65 | cap := &common.Capabilities{}
66 | if capV, ok := c.config.ChannelGroup.Values[CapabilitiesKey]; ok {
67 | err = proto.Unmarshal(capV.Value, cap)
68 | if err != nil {
69 | return nil
70 | }
71 | caps := []string{}
72 | for k := range cap.Capabilities {
73 | caps = append(caps, k)
74 | }
75 | values.Capabilities = caps
76 | }
77 |
78 | return values
79 | }
80 |
81 | // GetConsensusInfo 解析配置块中的共识相关配置信息
82 | func (c *Configlator) GetConsensusInfo() *ConsensusInfo {
83 | info := &ConsensusInfo{}
84 | ct := &orderer.ConsensusType{}
85 | err := proto.Unmarshal(c.config.ChannelGroup.Groups[OrdererGroupKey].Values[ConsensusTypeKey].Value, ct)
86 | if err != nil {
87 | return nil
88 | }
89 | info.Type = ct.Type
90 | switch ct.Type {
91 | case "etcdraft":
92 | meta := &etcdraft.ConfigMetadata{}
93 | err = proto.Unmarshal(ct.Metadata, meta)
94 | if err != nil {
95 | break
96 | }
97 | info.RaftMetadata = meta
98 | case "kafka":
99 | brokers := &orderer.KafkaBrokers{}
100 | err = proto.Unmarshal(c.config.ChannelGroup.Groups[OrdererGroupKey].Values[KafkaBrokersKey].Value, brokers)
101 | if err != nil {
102 | break
103 | }
104 | info.Borkers = brokers.Brokers
105 | default:
106 | break
107 | }
108 | bs := &orderer.BatchSize{}
109 | err = proto.Unmarshal(c.config.ChannelGroup.Groups[OrdererGroupKey].Values[BatchSizeKey].Value, bs)
110 | if err != nil {
111 | return nil
112 | }
113 | info.MaxMessageCount = bs.MaxMessageCount
114 | info.PreferredMaxBytes = bs.PreferredMaxBytes
115 | info.AbsoluteMaxBytes = bs.AbsoluteMaxBytes
116 | bt := &orderer.BatchTimeout{}
117 | err = proto.Unmarshal(c.config.ChannelGroup.Groups[OrdererGroupKey].Values[BatchTimeoutKey].Value, bt)
118 | if err != nil {
119 | return nil
120 | }
121 | info.BatchTimeOut = bt.Timeout
122 | cap := &common.Capabilities{}
123 | if capV, ok := c.config.ChannelGroup.Groups[OrdererGroupKey].Values[CapabilitiesKey]; ok {
124 | err = proto.Unmarshal(capV.Value, cap)
125 | if err != nil {
126 | return nil
127 | }
128 | caps := []string{}
129 | for k := range cap.Capabilities {
130 | caps = append(caps, k)
131 | }
132 | info.Capabilities = caps
133 | }
134 | return info
135 | }
136 |
137 | // GetApplicationValues 解析 Application 节中的 Values 信息
138 | func (c *Configlator) GetApplicationValues() *ApplicationValues {
139 | if _, ok := c.config.ChannelGroup.Groups[ApplicationGroupKey]; !ok {
140 | return nil
141 | }
142 | values := &ApplicationValues{}
143 | cap := &common.Capabilities{}
144 | if capV, ok := c.config.ChannelGroup.Groups[ApplicationGroupKey].Values[CapabilitiesKey]; ok {
145 | err := proto.Unmarshal(capV.Value, cap)
146 | if err != nil {
147 | return nil
148 | }
149 | caps := []string{}
150 | for k := range cap.Capabilities {
151 | caps = append(caps, k)
152 | }
153 | values.Capabilities = caps
154 | }
155 | acl := &peer.ACLs{}
156 | if aclV, ok := c.config.ChannelGroup.Groups[ApplicationGroupKey].Values[ACLsKey]; ok {
157 | err := proto.Unmarshal(aclV.Value, acl)
158 | if err != nil {
159 | return nil
160 | }
161 | acls := make(map[string]string)
162 | for k, v := range acl.Acls {
163 | acls[k] = v.PolicyRef
164 | }
165 | values.ACLs = acls
166 | }
167 | return values
168 | }
169 |
170 | // GetOrdererOrgs 解析配置块中的 orderer 组织
171 | func (c *Configlator) GetOrdererOrgs() []*GroupOrg {
172 | orgs := []*GroupOrg{}
173 | if _, ok := c.config.ChannelGroup.Groups[OrdererGroupKey]; ok {
174 | for _, g := range c.config.ChannelGroup.Groups[OrdererGroupKey].Groups {
175 | mspvalue := g.Values[MSPKey].Value
176 | org, err := c.getOrg(mspvalue)
177 | if err != nil {
178 | fmt.Println("getorg error:", err.Error())
179 | continue
180 | }
181 | if _, ok := g.Values[EndpointsKey]; ok {
182 | ep := g.Values[EndpointsKey].Value
183 | pbep := &common.OrdererAddresses{}
184 | err = proto.Unmarshal(ep, pbep)
185 | if err != nil {
186 | fmt.Println(err)
187 | continue
188 | }
189 | org.Endpoints = append(org.Endpoints, pbep.Addresses...)
190 | }
191 | orgs = append(orgs, org)
192 | }
193 | }
194 | return orgs
195 | }
196 |
197 | // GetApplicationOrgs 解析配置块中的应用组织
198 | func (c *Configlator) GetApplicationOrgs() []*GroupOrg {
199 | orgs := []*GroupOrg{}
200 | if _, ok := c.config.ChannelGroup.Groups[ApplicationGroupKey]; ok {
201 | for _, g := range c.config.ChannelGroup.Groups[ApplicationGroupKey].Groups {
202 | mspvalue := g.Values[MSPKey].Value
203 | org, err := c.getOrg(mspvalue)
204 | if err != nil {
205 | continue
206 | }
207 | if _, ok := g.Values[AnchorPeersKey]; ok {
208 | acp := g.Values[AnchorPeersKey].Value
209 | pbacp := &peer.AnchorPeers{}
210 | err = proto.Unmarshal(acp, pbacp)
211 | if err != nil {
212 | continue
213 | }
214 |
215 | for _, p := range pbacp.AnchorPeers {
216 | org.Endpoints = append(org.Endpoints, fmt.Sprintf("%s:%d", p.Host, p.Port))
217 | }
218 | }
219 | orgs = append(orgs, org)
220 | }
221 | }
222 | return orgs
223 | }
224 |
225 | // GetConsortiumOrgs 解析系统配置块中的联盟组织
226 | func (c *Configlator) GetConsortiumOrgs() map[string][]*GroupOrg {
227 | corgs := make(map[string][]*GroupOrg)
228 |
229 | if _, ok := c.config.ChannelGroup.Groups[ConsortiumsGroupKey]; ok {
230 | for cn, g := range c.config.ChannelGroup.Groups[ConsortiumsGroupKey].Groups {
231 | orgs := []*GroupOrg{}
232 | for _, o := range g.Groups {
233 | mspvalue := o.Values[MSPKey].Value
234 | org, err := c.getOrg(mspvalue)
235 | if err != nil {
236 | continue
237 | }
238 | orgs = append(orgs, org)
239 | }
240 | corgs[cn] = orgs
241 | }
242 | }
243 | return corgs
244 | }
245 |
246 | func (c *Configlator) getOrg(mspvalue []byte) (*GroupOrg, error) {
247 | mspc := &msp.MSPConfig{}
248 | err := proto.Unmarshal(mspvalue, mspc)
249 | if err != nil {
250 | return nil, errors.Wrap(err, "unmarshal MSPConfig")
251 | }
252 | org := &GroupOrg{}
253 | switch mspc.Type {
254 | case FABRIC:
255 | mspcfg := &msp.FabricMSPConfig{}
256 | err = proto.Unmarshal(mspc.Config, mspcfg)
257 | if err != nil {
258 | return nil, errors.Wrap(err, "unmarshal FabricMSPConfig error")
259 | }
260 | org.Type = mspc.Type
261 | org.TypeName = "FABRIC"
262 | org.Name = mspcfg.Name
263 | if len(mspcfg.Admins) > 0 {
264 | org.Admin = string(mspcfg.Admins[0])
265 | }
266 | if len(mspcfg.RootCerts) > 0 {
267 | org.RootCert = string(mspcfg.RootCerts[0])
268 | }
269 | if len(mspcfg.TlsRootCerts) > 0 {
270 | org.TLSRootCert = string(mspcfg.TlsRootCerts[0])
271 | }
272 | org.RevocationList = mspcfg.RevocationList
273 | case IDEMIX:
274 | mspcfg := &msp.IdemixMSPConfig{}
275 | err = proto.Unmarshal(mspc.Config, mspcfg)
276 | if err != nil {
277 | return nil, errors.Wrap(err, "unmarshal IdemixMSPConfig error")
278 | }
279 | org.Type = mspc.Type
280 | org.TypeName = "IDEMIX"
281 | org.Name = mspcfg.Name
282 | default:
283 | return nil, errors.Errorf("unexpected msp type:%d", mspc.Type)
284 | }
285 | return org, nil
286 | }
287 |
--------------------------------------------------------------------------------
/pkg/block/consts.go:
--------------------------------------------------------------------------------
1 | package block
2 |
3 | // const
4 | const (
5 | FABRIC int32 = iota // MSP is of FABRIC type
6 | IDEMIX // MSP is of IDEMIX type
7 | OTHER // MSP is of OTHER TYPE
8 |
9 | // These values are fixed for the genesis block.
10 | msgVersion = 0
11 | epoch = 0
12 |
13 | // ConsortiumKey is the key for the ConfigValue of a
14 | // Consortium.
15 | ConsortiumKey = "Consortium"
16 |
17 | // HashingAlgorithmKey is the key for the ConfigValue of a
18 | // HashingAlgorithm.
19 | HashingAlgorithmKey = "HashingAlgorithm"
20 |
21 | // BlockDataHashingStructureKey is the key for the ConfigValue
22 | // of a BlockDataHashingStructure.
23 | BlockDataHashingStructureKey = "BlockDataHashingStructure"
24 |
25 | // OrdererAddressesKey is the key for the ConfigValue, OrdererAddresses.
26 | OrdererAddressesKey = "OrdererAddresses"
27 |
28 | // CapabilitiesKey is the key for the ConfigValue, capabilities.
29 | // CapabiltiesKey can be used at the channel, application, and orderer levels.
30 | CapabilitiesKey = "Capabilities"
31 |
32 | // EndpointsKey is the key for the ConfigValue, Endpoints in
33 | // a OrdererOrgGroup.
34 | EndpointsKey = "Endpoints"
35 |
36 | // MSPKey is the key for the ConfigValue, MSP.
37 | MSPKey = "MSP"
38 |
39 | // ConsensusTypeKey is the key for the ConfigValue, ConsensusType.
40 | ConsensusTypeKey = "ConsensusType"
41 |
42 | // BatchSizeKey is the key for the ConfigValue, BatchSize.
43 | BatchSizeKey = "BatchSize"
44 |
45 | // BatchTimeoutKey is the key for the ConfigValue, BatchSize.
46 | BatchTimeoutKey = "BatchTimeout"
47 |
48 | // KafkaBrokersKey is the key for the ConfigValue, KafkaBrokers.
49 | KafkaBrokersKey = "KafkaBrokers"
50 |
51 | // HashingAlgorithmKey is the key for the ConfigValue, HashingAlgorithm.
52 |
53 | // AdminsPolicyKey is the key used for the admin policy.
54 | AdminsPolicyKey = "Admins"
55 |
56 | // ReadersPolicyKey is the key used for the read policy.
57 | ReadersPolicyKey = "Readers"
58 |
59 | // WritersPolicyKey is the key used for the write policy.
60 | WritersPolicyKey = "Writers"
61 |
62 | // EndorsementPolicyKey is the key used for the endorsement policy.
63 | EndorsementPolicyKey = "Endorsement"
64 |
65 | // LifecycleEndorsementPolicyKey is the key used for the lifecycle endorsement
66 | // policy.
67 | LifecycleEndorsementPolicyKey = "LifecycleEndorsement"
68 |
69 | // BlockValidationPolicyKey is the key used for the block validation policy in
70 | // the OrdererOrgGroup.
71 | BlockValidationPolicyKey = "BlockValidation"
72 |
73 | // ChannelCreationPolicyKey is the key used in the consortium config to denote
74 | // the policy to be used in evaluating whether a channel creation request
75 | // is authorized.
76 | ChannelCreationPolicyKey = "ChannelCreationPolicy"
77 |
78 | // ChannelGroupKey is the group name for the channel config.
79 | ChannelGroupKey = "Channel"
80 |
81 | // ConsortiumsGroupKey is the group name for the consortiums config.
82 | ConsortiumsGroupKey = "Consortiums"
83 |
84 | // OrdererGroupKey is the group name for the orderer config.
85 | OrdererGroupKey = "Orderer"
86 |
87 | // ApplicationGroupKey is the group name for the Application config.
88 | ApplicationGroupKey = "Application"
89 |
90 | // ACLsKey is the name of the ACLs config.
91 | ACLsKey = "ACLs"
92 |
93 | // AnchorPeersKey is the key name for the AnchorPeers ConfigValue.
94 | AnchorPeersKey = "AnchorPeers"
95 |
96 | // ImplicitMetaPolicyType is the 'Type' string for implicit meta policies.
97 | ImplicitMetaPolicyType = "ImplicitMeta"
98 |
99 | // SignaturePolicyType is the 'Type' string for signature policies.
100 | SignaturePolicyType = "Signature"
101 |
102 | ordererAdminsPolicyName = "/Channel/Orderer/Admins"
103 | )
104 |
--------------------------------------------------------------------------------
/pkg/block/ledger.go:
--------------------------------------------------------------------------------
1 | package block
2 |
3 | import (
4 | "bufio"
5 | "io"
6 |
7 | "github.com/golang/protobuf/proto"
8 | "github.com/pkg/errors"
9 | )
10 |
11 | const (
12 | peekBytes = 8
13 | )
14 |
15 | // Ledgerlator translator for ledger data
16 | type Ledgerlator struct {
17 | ledger *bufio.Reader
18 | }
19 |
20 | // NewLedgerlator return new ledgerlator from a Reader
21 | func NewLedgerlator(ledger *bufio.Reader) *Ledgerlator {
22 | return &Ledgerlator{
23 | ledger: ledger,
24 | }
25 | }
26 |
27 | // RetriveBlocks retrive blocks from ledger
28 | func (l Ledgerlator) RetriveBlocks() ([][]byte, error) {
29 | blocks := [][]byte{}
30 | for {
31 |
32 | peek, err := l.ledger.Peek(peekBytes)
33 | if err != nil {
34 | if err == io.EOF {
35 | break
36 | }
37 | return nil, errors.Wrap(err, "read peek info error")
38 | }
39 | length, n := proto.DecodeVarint(peek)
40 | if n == 0 {
41 | return nil, errors.New("peek decode not enough")
42 | }
43 |
44 | l.ledger.Discard(n)
45 | block := make([]byte, length)
46 | _, err = io.ReadAtLeast(l.ledger, block, int(length))
47 | if err != nil {
48 | return nil, errors.Wrap(err, "read block bytes error")
49 | }
50 | blocks = append(blocks, block)
51 | }
52 | return blocks, nil
53 | }
54 |
--------------------------------------------------------------------------------
/pkg/block/ledgerutil.go:
--------------------------------------------------------------------------------
1 | package block
2 |
3 | import (
4 | "crypto/sha256"
5 | "encoding/asn1"
6 | "math/big"
7 |
8 | "github.com/hyperledger/fabric-protos-go/common"
9 | ledgerutil "github.com/hyperledger/fabric/common/ledger/util"
10 | "github.com/pkg/errors"
11 | )
12 |
13 | // ExtractLeaderBlock extract block from ledger serialize block
14 | func ExtractLeaderBlock(data []byte) (*common.Block, error) {
15 | block := &common.Block{}
16 | var err error
17 | buf := ledgerutil.NewBuffer(data)
18 | if block.Header, err = extractHeader(buf); err != nil {
19 | return nil, errors.WithMessage(err, "extract header error")
20 | }
21 | if block.Data, err = extractData(buf); err != nil {
22 | return nil, errors.WithMessage(err, "extract data error")
23 | }
24 | if block.Metadata, err = extractMetadata(buf); err != nil {
25 | return nil, errors.WithMessage(err, "extract metadata error")
26 | }
27 | return block, err
28 | }
29 |
30 | func extractHeader(buf *ledgerutil.Buffer) (*common.BlockHeader, error) {
31 | header := &common.BlockHeader{}
32 | var err error
33 | if header.Number, err = buf.DecodeVarint(); err != nil {
34 | return nil, errors.Wrap(err, "error decoding the block number")
35 | }
36 | if header.DataHash, err = buf.DecodeRawBytes(false); err != nil {
37 | return nil, errors.Wrap(err, "error decoding the data hash")
38 | }
39 | if header.PreviousHash, err = buf.DecodeRawBytes(false); err != nil {
40 | return nil, errors.Wrap(err, "error decoding the previous hash")
41 | }
42 | if len(header.PreviousHash) == 0 {
43 | header.PreviousHash = nil
44 | }
45 | return header, nil
46 | }
47 |
48 | func extractData(buf *ledgerutil.Buffer) (*common.BlockData, error) {
49 | data := &common.BlockData{}
50 | var numItems uint64
51 | var err error
52 |
53 | if numItems, err = buf.DecodeVarint(); err != nil {
54 | return nil, errors.Wrap(err, "error decoding the length of block data")
55 | }
56 | for i := uint64(0); i < numItems; i++ {
57 | var txEnvBytes []byte
58 |
59 | if txEnvBytes, err = buf.DecodeRawBytes(false); err != nil {
60 | return nil, errors.Wrap(err, "error decoding the transaction enevelope")
61 | }
62 |
63 | data.Data = append(data.Data, txEnvBytes)
64 | }
65 | return data, nil
66 | }
67 |
68 | func extractMetadata(buf *ledgerutil.Buffer) (*common.BlockMetadata, error) {
69 | metadata := &common.BlockMetadata{}
70 | var numItems uint64
71 | var metadataEntry []byte
72 | var err error
73 | if numItems, err = buf.DecodeVarint(); err != nil {
74 | return nil, errors.Wrap(err, "error decoding the length of block metadata")
75 | }
76 | for i := uint64(0); i < numItems; i++ {
77 | if metadataEntry, err = buf.DecodeRawBytes(false); err != nil {
78 | return nil, errors.Wrap(err, "error decoding the block metadata")
79 | }
80 | metadata.Metadata = append(metadata.Metadata, metadataEntry)
81 | }
82 | return metadata, nil
83 | }
84 |
85 | type asn1Header struct {
86 | Number *big.Int
87 | PreviousHash []byte
88 | DataHash []byte
89 | }
90 |
91 | // HeaderBytes ...
92 | func HeaderBytes(b *common.BlockHeader) []byte {
93 | asn1Header := asn1Header{
94 | PreviousHash: b.PreviousHash,
95 | DataHash: b.DataHash,
96 | Number: new(big.Int).SetUint64(b.Number),
97 | }
98 | result, err := asn1.Marshal(asn1Header)
99 | if err != nil {
100 | // Errors should only arise for types which cannot be encoded, since the
101 | // BlockHeader type is known a-priori to contain only encodable types, an
102 | // error here is fatal and should not be propogated
103 | panic(err)
104 | }
105 | return result
106 | }
107 |
108 | // HeaderHash ...
109 | func HeaderHash(b *common.BlockHeader) []byte {
110 | sum := sha256.Sum256(HeaderBytes(b))
111 | return sum[:]
112 | }
113 |
--------------------------------------------------------------------------------
/pkg/block/model.go:
--------------------------------------------------------------------------------
1 | package block
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/hyperledger/fabric-protos-go/common"
7 | "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
8 | "github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
9 | "github.com/hyperledger/fabric-protos-go/peer"
10 | )
11 |
12 | // block type
13 | const (
14 | BlockTypeTrans = iota
15 | BlockTypeConfig
16 | )
17 |
18 | // GroupOrg 配置块中的组织信息
19 | type GroupOrg struct {
20 | Type int32 `json:"type" db:"type"`
21 | TypeName string `json:"type_name" db:"type_name"`
22 | Name string `json:"name" db:"name"`
23 | RootCert string `json:"root_cert" db:"root_cert"`
24 | TLSRootCert string `json:"tls_root_cert" db:"tls_root_cert"`
25 | Admin string `json:"admin" db:"admin"`
26 | RevocationList [][]byte `json:"revocation_list" db:"revocation_list"`
27 | Endpoints []string `json:"endpoints" db:"endpoints"` // peer: anchorpeers orderer: ordereraddress
28 | }
29 |
30 | // ConsensusInfo 配置快中的共识信息
31 | type ConsensusInfo struct {
32 | Type string `json:"type,omitempty" db:"type"`
33 | RaftMetadata *etcdraft.ConfigMetadata `json:"raft_metadata,omitempty" db:"raft_metadata"`
34 | MaxMessageCount uint32 `json:"max_message_count,omitempty" db:"max_message_count"`
35 | AbsoluteMaxBytes uint32 `json:"absolute_max_bytes,omitempty" db:"absolute_max_bytes"`
36 | PreferredMaxBytes uint32 `json:"preferred_max_bytes,omitempty" db:"preferred_max_bytes"`
37 | BatchTimeOut string `json:"batch_time_out,omitempty" db:"batch_time_out"`
38 | Borkers []string `json:"borkers,omitempty" db:"borkers"`
39 | Capabilities []string `json:"capabilities,omitempty" db:"capabilities"`
40 | }
41 |
42 | // ConfigValues config values
43 | type ConfigValues struct {
44 | Consortium string `json:"consortium,omitempty" db:"consortium"`
45 | HashingAlgorithm string `json:"hashing_algorithm,omitempty" db:"hashing_algorithm"`
46 | OrdererAddresses []string `json:"orderer_addresses,omitempty" db:"orderer_addresses"`
47 | BlockDataHashingWidth int `json:"block_data_hashing_width,omitempty" db:"block_data_hashing_width"`
48 | Capabilities []string `json:"capabilities,omitempty" db:"capabilities"`
49 | }
50 |
51 | // ApplicationValues values of application
52 | type ApplicationValues struct {
53 | ACLs map[string]string
54 | Capabilities []string `json:"capabilities,omitempty" db:"capabilities"`
55 | }
56 |
57 | // TxRwSet 交易读写集
58 | type TxRwSet struct {
59 | NsRwSets []*NsRwSet `json:"ns_rw_sets,omitempty" db:"ns_rw_sets"`
60 | }
61 |
62 | // NsRwSet encapsulates 'kvrwset.KVRWSet' proto message for a specific name space (chaincode)
63 | type NsRwSet struct {
64 | NameSpace string `json:"name_space,omitempty" db:"name_space"`
65 | KvRwSet *kvrwset.KVRWSet `json:"kv_rw_set,omitempty" db:"kv_rw_set"`
66 | CollHashedRwSets []*CollHashedRwSet `json:"coll_hashed_rw_sets,omitempty" db:"coll_hashed_rw_sets"`
67 | }
68 |
69 | // CollHashedRwSet encapsulates 'kvrwset.HashedRWSet' proto message for a specific collection
70 | type CollHashedRwSet struct {
71 | CollectionName string `json:"collection_name,omitempty" db:"collection_name"`
72 | HashedRwSet *kvrwset.HashedRWSet `json:"hashed_rw_set,omitempty" db:"hashed_rw_set"`
73 | PvtRwSetHash []byte `json:"pvt_rw_set_hash,omitempty" db:"pvt_rw_set_hash"`
74 | }
75 |
76 | //Summary block summary info
77 | type Summary struct {
78 | BlockNum uint64 `json:"block_num" db:"block_num"`
79 | Hash string `json:"hash" db:"hash"`
80 | PreHash string `json:"pre_hash" db:"pre_hash"`
81 | Channel string `json:"channel" db:"channel"`
82 | Type int `json:"type" db:"type"` // 0: transaction 1: config
83 | TransCount int `json:"trans_count" db:"trans_count"`
84 | CommitHash string `json:"commit_hash" db:"commit_hash"`
85 | LastConfig uint64 `json:"last_config" db:"last_config"`
86 | }
87 |
88 | // Desc block description
89 | type Desc struct {
90 | Summary
91 | // BlockNum uint64 `json:"block_num" db:"block_num"`
92 | // Hash string `json:"hash" db:"hash"`
93 | // PreHash string `json:"pre_hash" db:"pre_hash"`
94 | // Channel string `json:"channel" db:"channel"`
95 | // Type int `json:"type" db:"type"` // 0: transaction 1: config
96 | Config *ConfigDesc `json:"config" db:"config"`
97 | Transactions []*TranDesc `json:"transactions" db:"transactions"`
98 | // TransCount int `json:"trans_count" db:"trans_count"`
99 | // CommitHash string `json:"commit_hash" db:"commit_hash"`
100 | // LastConfig uint64 `json:"last_config" db:"last_config"`
101 | }
102 |
103 | // ConfigDesc config description
104 | type ConfigDesc struct {
105 | OrdererOrgs []*GroupOrg `json:"orderer_orgs" db:"orderer_orgs"`
106 | ConsortiumOrgs map[string][]*GroupOrg `json:"consortium_orgs" db:"consortium_orgs"`
107 | ApplicationOrgs []*GroupOrg `json:"application_orgs" db:"application_orgs"`
108 | ApplicationValues *ApplicationValues `json:"application_values" `
109 | Values *ConfigValues `json:"values" db:"values"`
110 | Consensus *ConsensusInfo `json:"consensus" db:"consensus"`
111 | }
112 |
113 | // SignInfo sign info
114 | type SignInfo struct {
115 | MSPID string `json:"mspid,omitempty" db:"mspid"`
116 | Cert *Cert `json:"cert,omitempty" db:"cert"`
117 | Signature string `json:"signature,omitempty" db:"signature"`
118 | }
119 |
120 | // TranDesc transaction description
121 | type TranDesc struct {
122 | Channel string `json:"channel" db:"channel"`
123 | TxID string `json:"tx_id" db:"tx_id"`
124 | Time time.Time `json:"time" db:"time"`
125 | Chaincode string `json:"chaincode" db:"chaincode"`
126 | Func string `json:"func" db:"func"`
127 | Args []string `json:"args" db:"args"`
128 | Resp struct {
129 | Status int32 `json:"status" db:"status"`
130 | Message string `json:"message" db:"message"`
131 | Data string `json:"data" db:"data"`
132 | } `json:"resp" db:"resp"`
133 | TxRwSet *TxRwSet `json:"tx_rw_set" `
134 | Filter bool `json:"filter" db:"filter"`
135 | ValidationCode string `json:"validation_code" db:"validation_code"`
136 | Signer *SignInfo `json:"signer" db:"signer"`
137 | Endorsers []*SignInfo `json:"endorsers," db:"endorsers"`
138 | }
139 |
140 | // Envelope clean struct for envelope
141 | type Envelope struct {
142 | Payload struct {
143 | Header struct {
144 | ChannelHeader *common.ChannelHeader
145 | SignatureHeader *common.SignatureHeader
146 | }
147 | Transaction struct {
148 | Header *common.SignatureHeader
149 | ChaincodeAction struct {
150 | Proposal struct {
151 | Input *peer.ChaincodeSpec
152 | }
153 | Response struct {
154 | ProposalHash []byte
155 | ChaincodeAction *peer.ChaincodeAction
156 | RWSet *TxRwSet
157 | }
158 | Endorses []*peer.Endorsement
159 | }
160 | }
161 | }
162 | Signature []byte
163 | }
164 |
--------------------------------------------------------------------------------
/pkg/block/transaction.go:
--------------------------------------------------------------------------------
1 | package block
2 |
3 | import (
4 | "encoding/base64"
5 | "errors"
6 | "time"
7 |
8 | "github.com/golang/protobuf/proto"
9 | "github.com/hyperledger/fabric-protos-go/common"
10 | "github.com/hyperledger/fabric-protos-go/msp"
11 | "github.com/hyperledger/fabric-protos-go/peer"
12 | )
13 |
14 | // Translator translator for transaction envelope
15 | type Translator struct {
16 | env *common.Envelope
17 | innerEnv *Envelope
18 | }
19 |
20 | // NewTranslator return new Translator
21 | func NewTranslator(env *common.Envelope) (*Translator, error) {
22 | translator := &Translator{
23 | env: env,
24 | innerEnv: &Envelope{
25 | Signature: env.Signature,
26 | },
27 | }
28 | if err := translator.init(); err != nil {
29 | return nil, err
30 | }
31 | return translator, nil
32 | }
33 |
34 | func (t *Translator) init() error {
35 | payload := &common.Payload{}
36 | err := proto.Unmarshal(t.env.Payload, payload)
37 | if err != nil {
38 | return err
39 | }
40 | trans := &peer.Transaction{}
41 | err = proto.Unmarshal(payload.Data, trans)
42 | if err != nil {
43 | return err
44 | }
45 | if err = t.unHeader(payload.Header); err != nil {
46 | return err
47 | }
48 | if len(trans.Actions) < 1 {
49 | return errors.New("no transaction in block")
50 | }
51 | if err = t.unAction(trans.Actions[0]); err != nil {
52 | return err
53 | }
54 | return nil
55 | }
56 |
57 | func (t *Translator) unHeader(header *common.Header) error {
58 | ch := &common.ChannelHeader{}
59 | err := proto.Unmarshal(header.ChannelHeader, ch)
60 | if err != nil {
61 | return err
62 | }
63 | t.innerEnv.Payload.Header.ChannelHeader = ch
64 | sh := &common.SignatureHeader{}
65 | err = proto.Unmarshal(header.SignatureHeader, sh)
66 | if err != nil {
67 | return err
68 | }
69 | t.innerEnv.Payload.Header.SignatureHeader = sh
70 | return nil
71 | }
72 |
73 | func (t *Translator) unAction(action *peer.TransactionAction) error {
74 | ccp := &peer.ChaincodeActionPayload{}
75 | err := proto.Unmarshal(action.Payload, ccp)
76 | if err != nil {
77 | return err
78 | }
79 | t.innerEnv.Payload.Transaction.ChaincodeAction.Endorses = ccp.Action.Endorsements
80 | pp := &peer.ChaincodeProposalPayload{}
81 | err = proto.Unmarshal(ccp.ChaincodeProposalPayload, pp)
82 | if err != nil {
83 | return err
84 | }
85 | ppi := &peer.ChaincodeInvocationSpec{}
86 | err = proto.Unmarshal(pp.Input, ppi)
87 | if err != nil {
88 | return err
89 | }
90 | t.innerEnv.Payload.Transaction.ChaincodeAction.Proposal.Input = ppi.ChaincodeSpec
91 |
92 | ccresp := &peer.ProposalResponsePayload{}
93 | err = proto.Unmarshal(ccp.Action.ProposalResponsePayload, ccresp)
94 | if err != nil {
95 | return err
96 | }
97 | t.innerEnv.Payload.Transaction.ChaincodeAction.Response.ProposalHash = ccresp.ProposalHash
98 | cca := &peer.ChaincodeAction{}
99 | err = proto.Unmarshal(ccresp.Extension, cca)
100 | if err != nil {
101 | return err
102 | }
103 | t.innerEnv.Payload.Transaction.ChaincodeAction.Response.ChaincodeAction = cca
104 | txrwset := &TxRwSet{}
105 | err = txrwset.FromProtoBytes(cca.Results)
106 | if err != nil {
107 | return err
108 | }
109 | t.innerEnv.Payload.Transaction.ChaincodeAction.Response.RWSet = txrwset
110 | return nil
111 | }
112 |
113 | // ToDesc transaction block to TranDesc
114 | func (t *Translator) ToDesc() *TranDesc {
115 | td := &TranDesc{}
116 | td.Channel = t.innerEnv.Payload.Header.ChannelHeader.ChannelId
117 | td.TxID = t.innerEnv.Payload.Header.ChannelHeader.TxId
118 | ts := t.innerEnv.Payload.Header.ChannelHeader.Timestamp
119 | td.Time = time.Unix(ts.Seconds, int64(ts.Nanos))
120 | td.Chaincode = t.innerEnv.Payload.Transaction.ChaincodeAction.Proposal.Input.ChaincodeId.Name
121 | td.Func = string(t.innerEnv.Payload.Transaction.ChaincodeAction.Proposal.Input.Input.Args[0])
122 | for _, a := range t.innerEnv.Payload.Transaction.ChaincodeAction.Proposal.Input.Input.Args[1:] {
123 | td.Args = append(td.Args, string(a))
124 | }
125 | td.Resp.Status = t.innerEnv.Payload.Transaction.ChaincodeAction.Response.ChaincodeAction.Response.Status
126 | td.Resp.Message = t.innerEnv.Payload.Transaction.ChaincodeAction.Response.ChaincodeAction.Response.Message
127 | td.Resp.Data = string(t.innerEnv.Payload.Transaction.ChaincodeAction.Response.ChaincodeAction.Response.Payload)
128 | td.TxRwSet = t.innerEnv.Payload.Transaction.ChaincodeAction.Response.RWSet
129 | seri := t.innerEnv.Payload.Header.SignatureHeader.Creator
130 | creator := &msp.SerializedIdentity{}
131 | err := proto.Unmarshal(seri, creator)
132 | if err != nil {
133 | //TODO:
134 | }
135 | si := &SignInfo{
136 | MSPID: creator.Mspid,
137 | Signature: base64.StdEncoding.EncodeToString(t.innerEnv.Signature),
138 | }
139 | si.Cert, err = NewCert(creator.IdBytes)
140 | if err != nil {
141 | //TODO:
142 | }
143 | td.Signer = si
144 | for _, e := range t.innerEnv.Payload.Transaction.ChaincodeAction.Endorses {
145 | er := &msp.SerializedIdentity{}
146 | err := proto.Unmarshal(e.Endorser, er)
147 | if err != nil {
148 | //TODO:
149 | }
150 | si := &SignInfo{
151 | MSPID: er.Mspid,
152 | Signature: base64.StdEncoding.EncodeToString(e.Signature),
153 | }
154 | cert, err := NewCert(er.IdBytes)
155 | if err != nil {
156 | //TODO:
157 | }
158 | si.Cert = cert
159 | td.Endorsers = append(td.Endorsers, si)
160 | }
161 | return td
162 | }
163 |
164 | // GetTxID return TxID
165 | func (t *Translator) GetTxID() string {
166 | return t.innerEnv.Payload.Header.ChannelHeader.TxId
167 | }
168 |
169 | // GetChannel return channel id
170 | func (t *Translator) GetChannel() string {
171 | return t.innerEnv.Payload.Header.ChannelHeader.ChannelId
172 | }
173 |
--------------------------------------------------------------------------------
/pkg/block/txrwset.go:
--------------------------------------------------------------------------------
1 | package block
2 |
3 | import (
4 | "github.com/golang/protobuf/proto"
5 | "github.com/hyperledger/fabric-protos-go/ledger/rwset"
6 | "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
7 | )
8 |
9 | // FromProtoBytes 解析 TxRwSet
10 | func (txRwSet *TxRwSet) FromProtoBytes(protoBytes []byte) error {
11 | protoMsg := &rwset.TxReadWriteSet{}
12 | var err error
13 | var txRwSetTemp *TxRwSet
14 | if err = proto.Unmarshal(protoBytes, protoMsg); err != nil {
15 | return err
16 | }
17 | if txRwSetTemp, err = TxRwSetFromProtoMsg(protoMsg); err != nil {
18 | return err
19 | }
20 | txRwSet.NsRwSets = txRwSetTemp.NsRwSets
21 | return nil
22 | }
23 |
24 | // TxRwSetFromProtoMsg ...
25 | func TxRwSetFromProtoMsg(protoMsg *rwset.TxReadWriteSet) (*TxRwSet, error) {
26 | txRwSet := &TxRwSet{}
27 | var nsRwSet *NsRwSet
28 | var err error
29 | for _, nsRwSetProtoMsg := range protoMsg.NsRwset {
30 | if nsRwSet, err = nsRwSetFromProtoMsg(nsRwSetProtoMsg); err != nil {
31 | return nil, err
32 | }
33 | if nsRwSet.NameSpace == "lscc" {
34 | continue
35 | }
36 | txRwSet.NsRwSets = append(txRwSet.NsRwSets, nsRwSet)
37 | }
38 | return txRwSet, nil
39 | }
40 |
41 | func nsRwSetFromProtoMsg(protoMsg *rwset.NsReadWriteSet) (*NsRwSet, error) {
42 | nsRwSet := &NsRwSet{NameSpace: protoMsg.Namespace, KvRwSet: &kvrwset.KVRWSet{}}
43 | if err := proto.Unmarshal(protoMsg.Rwset, nsRwSet.KvRwSet); err != nil {
44 | return nil, err
45 | }
46 | return nsRwSet, nil
47 | }
48 |
--------------------------------------------------------------------------------
/pkg/store/cache.go:
--------------------------------------------------------------------------------
1 | package store
2 |
3 | import (
4 | "crypto/sha256"
5 | "encoding/base64"
6 | "errors"
7 | "fmt"
8 | "sync"
9 | "time"
10 | )
11 |
12 | // clean params
13 | const (
14 | Experied = time.Minute * 10
15 | ScanInterval = time.Minute
16 | MaxCacheSize = 150 * 1024 * 1024 // byte
17 | )
18 |
19 | // Cache cache
20 | type Cache interface {
21 | Store(key string, size int64, data interface{}) error
22 | Load(key string) (interface{}, error)
23 | KeyGen(raw []byte) (string, error)
24 | }
25 |
26 | // MapCache cache base map
27 | type MapCache struct {
28 | cache *sync.Map
29 | create map[string]time.Time
30 | size map[string]int64
31 | stop chan struct{}
32 | cacheLock *sync.RWMutex
33 | }
34 |
35 | // NewCache return new mapcache
36 | func NewCache() *MapCache {
37 | cache := &MapCache{
38 | cache: &sync.Map{},
39 | create: make(map[string]time.Time),
40 | stop: make(chan struct{}),
41 | size: make(map[string]int64),
42 | cacheLock: &sync.RWMutex{},
43 | }
44 | go cache.scan()
45 | return cache
46 | }
47 |
48 | // KeyGen genarate a cache key by cache data
49 | func (c *MapCache) KeyGen(raw []byte) (string, error) {
50 | sha := sha256.New()
51 | _, err := sha.Write(raw)
52 | if err != nil {
53 | return "", err
54 | }
55 | res := sha.Sum([]byte{})
56 | return base64.StdEncoding.EncodeToString(res), nil
57 | }
58 |
59 | // PreStore store prepare
60 | func (c *MapCache) preStore(key string, size int64) {
61 | if _, ok := c.create[key]; ok {
62 | return
63 | }
64 | var total int64 = 0
65 | for _, v := range c.size {
66 | total += v
67 | }
68 | fmt.Println("total size:", total)
69 | if total+size > MaxCacheSize {
70 | c.cacheLock.Lock()
71 | c.create = make(map[string]time.Time)
72 | c.cache = &sync.Map{}
73 | c.size = make(map[string]int64)
74 | c.cacheLock.Unlock()
75 | fmt.Println("clear all")
76 | }
77 | c.size[key] = size
78 | }
79 |
80 | // Store cache data in MapCache,return key
81 | func (c *MapCache) Store(key string, size int64, data interface{}) error {
82 | c.preStore(key, size)
83 | c.cacheLock.RLock()
84 | defer c.cacheLock.RUnlock()
85 | if _, ok := c.create[key]; ok {
86 | return nil
87 | }
88 | c.cache.Store(key, data)
89 | c.create[key] = time.Now()
90 | return nil
91 | }
92 |
93 | // Load load data by key
94 | func (c *MapCache) Load(key string) (interface{}, error) {
95 | value, ok := c.cache.Load(key)
96 | if ok {
97 | return value, nil
98 | }
99 | return nil, errors.New("no data")
100 | }
101 |
102 | func (c *MapCache) scan() {
103 | tick := time.NewTicker(ScanInterval)
104 | for {
105 | select {
106 | case <-tick.C:
107 | go c.clean()
108 | case <-c.stop:
109 | tick.Stop()
110 | return
111 | }
112 | }
113 | }
114 | func (c *MapCache) clean() {
115 | for k, v := range c.create {
116 | if time.Now().Sub(v) > Experied {
117 | fmt.Println("clean: ", k)
118 | c.cache.Delete(k)
119 | delete(c.create, k)
120 | delete(c.size, k)
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------