diff --git a/Gomd_super/go_file.md b/Gomd_super/go_file.md new file mode 100644 index 00000000..49ecffe1 --- /dev/null +++ b/Gomd_super/go_file.md @@ -0,0 +1,512 @@ +# Go语言文本编码处理 + +[toc] + +#### 判断是否字符串是否包含字符串 + +介绍strings使用方法 + +```go +package main + +import ( + "fmt" + "strings" +) + +func main() { + s := "hello word!" + fmt.Println(strings.Contains(s, "hello"), strings.Contains(s, "?")) +} +``` + +**编译:** + +``` +PS C:\Users\smile\Desktop\区块链\code\gin> go run .\main.go +true false +``` + +**包含hello返回true,不包含?返回false** + +**看下contains源码** + +``` +// Contains reports whether substr is within s. +func Contains(s, substr string) bool { + return Index(s, substr) >= 0 +} +``` + + + +### 字符串拆分 + +```go +package main + +import ( + "fmt" + "strings" +) + +func main() { + s := "hello word!" + fmt.Println(strings.Contains(s, "hello"), strings.Contains(s, "?")) + + ss := "a&s*a##av" + splitedStr := strings.Split(ss, "#") + fmt.Println(splitedStr) +} + +``` + +**编译:** + +``` +PS C:\Users\smile\Desktop\区块链\code\gin> go run .\main.go +true false +[a&s*a av] +``` + +**看下源码** + +```go +func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) } + +// SplitAfter slices s into all substrings after each instance of sep and +// returns a slice of those substrings. +// +// If s does not contain sep and sep is not empty, SplitAfter returns +// a slice of length 1 whose only element is s. +// +// If sep is empty, SplitAfter splits after each UTF-8 sequence. If +// both s and sep are empty, SplitAfter returns an empty slice. +// +// It is equivalent to SplitAfterN with a count of -1. +func SplitAfter(s, sep string) []string { + return genSplit(s, sep, len(sep), -1) +} +``` + + + +### 可以使用join将其合并起来 + +``` +fmt.Println("string.Join(splitedStr,"#")) +``` + +**看下join源码** + +```go +func Join(elems []string, sep string) string { + switch len(elems) { + case 0: + return "" + case 1: + return elems[0] + } + n := len(sep) * (len(elems) - 1) + for i := 0; i < len(elems); i++ { + n += len(elems[i]) + } + + var b Builder + b.Grow(n) + b.WriteString(elems[0]) + for _, s := range elems[1:] { + b.WriteString(sep) + b.WriteString(s) + } + return b.String() +} +``` + + + +## 字符串转化 + +```go +package main + +import ( + "fmt" + "strconv" +) + +func main() { + s := "zxcvzbnznz" + fmt.Println("s=", s) + fmt.Println(strconv.Itoa(100)) + // func Itoa(i int) string { + // return FormatInt(int64(i), 10) + // } + a, err := strconv.Atoi("12") + if err != nil { + fmt.Println("err = ", err) + return + } + fmt.Println(a) +} +``` + +**编译:** + +``` +PS C:\Users\smile\Desktop\区块链\code\gin> go run .\main.go +s= zxcvzbnznz +100 +12 +``` + + + +**继续** + +```go +package main + +import ( + "fmt" + "strconv" +) + +func main() { + s := "zxcvzbnznz" + fmt.Println("s=", s) + fmt.Println(strconv.Itoa(100)) + // func Itoa(i int) string { + // return FormatInt(int64(i), 10) + // } + a, err := strconv.ParseBool("t") + if err != nil { + fmt.Println("err = ", err) + return + } + /*func ParseBool(str string) (bool, error) { + switch str { + case "1", "t", "T", "true", "TRUE", "True": + return true, nil + case "0", "f", "F", "false", "FALSE", "False": + return false, nil + } + return false, syntaxError("ParseBool", str) + }*/ + fmt.Println("a=", a) + a1, err1 := strconv.ParseFloat("123.2134", 64) + if err1 != nil { + fmt.Println("err = ", err) + return + } + /*func ParseFloat(s string, bitSize int) (float64, error) { + f, n, err := parseFloatPrefix(s, bitSize) + if n != len(s) && (err == nil || err.(*NumError).Err != ErrSyntax) { + return 0, syntaxError(fnParseFloat, s) + } + return f, err + }*/ + fmt.Println("a1=", a1) +} +``` + + + +**编译:** + +``` +PS C:\Users\smile\Desktop\区块链\code\gin> go run .\main.go +s= zxcvzbnznz +100 +a= true +a1= 123.2134 +``` + + + + + +## 序列化和反序列化 + +```go +package main + +import ( + "encoding/xml" + "fmt" +) + +type Person struct { + Name string + Age int +} + +func main() { + p := Person{"smiel", 19} + fmt.Println("person = ", p) + if data, err := xml.Marshal(p); err != nil { + fmt.Println("err = ", err) + return + } else { + fmt.Println(string(data)) + } + /*func Marshal(v any) ([]byte, error) { + var b bytes.Buffer + if err := NewEncoder(&b).Encode(v); err != nil { + return nil, err + } + return b.Bytes(), nil +}*/ +} +``` + +**编译:** + +``` +PS C:\Users\smile\Desktop\区块链\code\gin> go run .\main.go +person = {smiel 19} +smiel19 +``` + +**这个默认不是可读性的xml需要格式化** + +``` +xml.MarshalIndent(p,""," ") +``` + ++ 第二个:前缀 ++ 第三个:缩进 + +**底层源码** + +``` +func MarshalIndent(v any, prefix, indent string) ([]byte, error) { + var b bytes.Buffer + enc := NewEncoder(&b) + enc.Indent(prefix, indent) + if err := enc.Encode(v); err != nil { + return nil, err + } + return b.Bytes(), nil +} +``` + +**此时还有一个小技巧,我的err放在if语句中,此时可以确定作用域仅仅在if语句中** + + + +## 使用flag获取复杂参数 + +```go +package main + +import ( + "flag" + "fmt" +) + +func main() { + methodPtr := flag.String("method", "default", "method of sample") + //func String(name string, value string, usage string) *string { + //return CommandLine.String(name, value, usage)} + valuePtr := flag.Int64("value", -1, "value of sample") + + flag.Parse() + fmt.Println(*methodPtr, *valuePtr) +} +``` + +**编译:** + +``` +C:\Users\smile\Desktop\区块链\code\gin>go build main.go + +C:\Users\smile\Desktop\区块链\code\gin>a.exe +'a.exe' 不是内部或外部命令,也不是可运行的程序 +或批处理文件。 + +C:\Users\smile\Desktop\区块链\code\gin>go build main.go + +C:\Users\smile\Desktop\区块链\code\gin>main.exe +default -1 + +C:\Users\smile\Desktop\区块链\code\gin>main.exe -method helloxiongxinwei@mail.com +helloxiongxinwei@mail.com -1 +``` + + + +## 控制命令行操作 + +```go +package main + +import ( + "bufio" + "bytes" + "fmt" + "os/exec" +) + +func cmd1() { + //首先生成cmd结构体,该结构体包含了很多信息,如执行命令的参数,命令的标准输入输出等 + command := exec.Command("ls", "-l") + //给标准输入以及标准错误初始化一个buffer,每条命令的输出位置可能是不一样的, + //比如有的命令会将输出放到stdout,有的放到stderr + command.Stdout = &bytes.Buffer{} + command.Stderr = &bytes.Buffer{} + //执行命令,直到命令结束 + err := command.Run() + if err != nil { + //打印程序中的错误以及命令行标准错误中的输出 + fmt.Println(err) + fmt.Println(command.Stderr.(*bytes.Buffer).String()) + return + } + //打印命令行的标准输出 + fmt.Println(command.Stdout.(*bytes.Buffer).String()) +} + +func cmd2() { + //首先生成cmd结构体 + cmd := exec.Command("strace", "-p", "15284") + //调用stderrPipe生成一个管道,该管道连接到命令行进程的标准错误, 该方法返回一个 + //ReadCloser, 我们可以通过读取返回的ReadCloser来实时读取命令行进程的标准错误 + piper, _ := cmd.StderrPipe() + //开始执行命令 + cmd.Start() + //使用bufio包封装的方法实现对reader的读取 + reader := bufio.NewReader(piper) + for { + //换行分隔 + line, err := reader.ReadString('\n') + if err != nil { + fmt.Println(err) + break + } + //打印内容 + fmt.Println(line) + } + //等待命令结束并回收子进程资源等 + cmd.Wait() +} + +func main() { + fmt.Println("调用cmd1函数:") + cmd1() + + fmt.Println("调用cmd2函数:") + cmd2() + + command := exec.Command("ifconfig") + command.Stdout = &bytes.Buffer{} + command.Stderr = &bytes.Buffer{} + //执行命令,直到命令结束 + err := command.Run() + if err != nil { + //打印程序中的错误以及命令行标准错误中的输出 + fmt.Println(err) + fmt.Println(command.Stderr.(*bytes.Buffer).String()) + return + } + fmt.Println(command.Stdout.(*bytes.Buffer).String()) + +} +``` + + + +**查看底层源码:** + +```go +func Command(name string, arg ...string) *Cmd { + cmd := &Cmd{ + Path: name, + Args: append([]string{name}, arg...), + } + if filepath.Base(name) == name { + if lp, err := LookPath(name); err != nil { + cmd.lookPathErr = err + } else { + cmd.Path = lp + } + } + return cmd +} +``` + + + +## 获取所有结点名 + + + + + + + +## 补充:变量的作用域 + +```go +package main + +import ( + "fmt" +) + +func style(method string, value int) { + //this.method = method + method = "smile3" + value = 1003 + fmt.Println(method) + fmt.Println(value) +} +func style2() { + var method string + var value int + method = "smile" + value = 100 + fmt.Println(method) + fmt.Println(value) +} + +func main() { + var method string + var value int + method = "hello main" + value = 10 + fmt.Println(method) + fmt.Println(value) + fmt.Println(" === ") + style2() + fmt.Println(" === ") + fmt.Println(method) + fmt.Println(value) + fmt.Println(" === ") + style(method, value) + fmt.Println(" == 3") + fmt.Println(method) + fmt.Println(value) +} +``` + +**编译:** + +``` +C:\Users\smile\Desktop\区块链\code\gin>go run main.go +hello main +10 + === +smile +100 + === +hello main +10 + === +smile3 +1003 + == 3 +hello main +10 +``` + diff --git a/Gomd_super/go_mod.md b/Gomd_super/go_mod.md new file mode 100644 index 00000000..3bb87bc4 --- /dev/null +++ b/Gomd_super/go_mod.md @@ -0,0 +1,250 @@ +# Go-mod包 + +[toc] + + + +### 包的导入方式 + +1. 绝对路径导入(在GOPATH目录中导入包) + +2. 相对路径导入(不建议!!!) + +3. 点导入 + + + 相当于直接复制源文件过来,此时不需要用. + + ``` + Println("hello word") + ``` + +4. 别名导入 + +5. 下划线导入 + + + +### Go-mod方式管理包 + +#### 优势: + +- **代码可以放在任意位置,不用设置GOPATH** +- **自动下载依赖管理** +- **版本控制** +- **不允许使用相对导入** +- **replace机制(goproxy代理机制)** + + + + + +### 项目开始~ + +> 为了理清关系,这一节从头开始做 + +**目录结构** + +![image-20220525220447501](https://s2.loli.net/2022/05/25/eKIV2UnTLjcWRJC.png) + +**我们的项目就叫go-mod** + +``` +mkdir go-mod +cd go-mod +mkdir hello +``` + +### 为代码启用依赖项跟踪 + +**需要设置名字,一般和报名是一样的** + +``` +PS C:\Users\smile\Desktop\区块链\code\go-mod> go mod init go-mod +go: creating new go.mod: module go-mod +go: to add module requirements and sums: + go mod tidy +``` + +**查看模块** + +``` +module go-mod + +go 1.18 +``` + +**编辑hello.go** + +``` +package main + +import "fmt" + +func main() { + fmt.Println("hello word") +} +``` + +**编译:** + +``` +PS C:\Users\smile\Desktop\区块链\code\go-mod\hello> go run . +hello word +``` + + + +**目录结构** + +```bash +PS C:\Users\smile\Desktop\区块链\code\go-mod> tree +卷 系统 的文件夹 PATH 列表 +卷序列号为 DE95-1D97 +C:. +├─hello +└─main + +PS C:\Users\smile\Desktop\区块链\code\go-mod> cd .\main\ +PS C:\Users\smile\Desktop\区块链\code\go-mod\main> New-Item main.go + + 目录: C:\Users\smile\Desktop\区块链\code\go-mod\main + +Mode LastWriteTime Length Name +---- ------------- ------ ---- +-a---- 2022/5/25 21:32 0 main.go +``` + + + +**创建一个包文件夹,创建一个文件task.go** + +``` +PS C:\Users\smile\Desktop\区块链\code\go-mod> mkdir models + + + 目录: C:\Users\smile\Desktop\区块链\code\go-mod + + +Mode LastWriteTime Length Name +---- ------------- ------ ---- +d----- 2022/5/25 22:00 models + +PS C:\Users\smile\Desktop\区块链\code\go-mod> New-Item task.go + + 目录: C:\Users\smile\Desktop\区块链\code\go-mod + +Mode LastWriteTime Length Name +---- ------------- ------ ---- +-a---- 2022/5/25 22:02 0 task.go +``` + + + +**主函数** + +``` +package main + +import ( + . "fmt" + "go-mod/hello" + "go-mod/models" +) + +func main() { + Println("main主函数") + hello.Hello() + Println(models.Name) + //hello.Hello() +} +``` + +**编译:** + +``` +PS C:\Users\smile\Desktop\区块链\code\go-mod> go run .\main.go +main主函数 +hello word +test +``` + + + + + +### 所出现问题 + +文件mod包嵌入使用的问题,导致mod机制没办法正常在子目录使用~ + + + +### github导入包 + +```go +package models + +import "fmt" +import "github.com/astaxie/beego" + +var Name = "test" + +func init() { + fmt.Println("最先开始调用多个") +} + +func main() { + beego.Run() +} +``` + +**回到主目录** + +``` +PS C:\Users\smile\Desktop\区块链\code\go-mod> go get github.com/astaxie/beego +``` + +**下载依赖,查看go-mod** + +``` +module go-mod + +go 1.18 + +require ( + github.com/astaxie/beego v1.12.3 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/golang/protobuf v1.4.2 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/prometheus/client_golang v1.7.0 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.10.0 // indirect + github.com/prometheus/procfs v0.1.3 // indirect + github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect + golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect + golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect + golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 // indirect + golang.org/x/text v0.3.0 // indirect + google.golang.org/protobuf v1.23.0 // indirect + gopkg.in/yaml.v2 v2.2.8 // indirect +) + +``` + + + +**还有一个go sum文件** + + + + + +### 远程推送到github上 + +1. 在github上新建一个项目Go-mod +2. `go mod init github.com/3293172751/go-mod` +3. 添加readme.m + + + diff --git a/README.md b/README.md index e4846069..20ffdce6 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,9 @@ + [🖱️Go语言包管理工具mod](Gomd_super/mod.md) + [🖱️命名规范](Gomd_super/name.md) + 🖱️[Go语言目录结构](Gomd_super/catalogue.md) ++ 🖱️[Go文件以及编码处理](Gomd_super/go_file.md) + + 🖱️[Go-mod包](Gomd_super/go_mod.md) --- @@ -71,7 +74,7 @@ ### [🖱️ Docker入门到进阶](docker/README.md) -### [🖱️ Git—必备神器](Git/README.md) +### [🖱️ Git—必备神器](Git/README.md) ### [🖱️linux从入门到精通](linux/README.md) @@ -79,7 +82,7 @@ --- -## 以太坊ETH学习 +## 区块链学习 以太坊和比特币一样,底层框架都是区块链协议,区块链本质上是一个应用了密码学技术的分布式数据库系统。建议看一下**以太坊白皮书(需要有golang编程基础)** @@ -87,6 +90,8 @@ ## [🖱️点击进入ETH学习](eth/TOC.md) +## [区块链技术指南](chainbrock-learning/SUMMARY.md) + --- @@ -118,7 +123,7 @@ #### [ 🖱️go语言Linux内核(未开始)]() -#### [🖱️C-Universal Brockchain](C_Universal_Brockchain) +#### [🖱️C-Universal Brockchain](C_Universal_Brockchain/README.md) #### [🖱️C-Universal Brockchain(链学)组织地址](https://github.com/C-UB) diff --git a/TOC.md b/TOC.md index c732704f..8af821aa 100644 --- a/TOC.md +++ b/TOC.md @@ -67,11 +67,11 @@ ### Go web框架gin框架 -#### 1. [](1.md) +#### 1. [](gin/1.md) -#### 2. [](2.md) +#### 2. [](gin/2.md) -#### 3. [](3.md) +#### 3. [](gin/3.md) #### 4. [](4.md) diff --git a/btc/1.md b/btc/1.md deleted file mode 100644 index 2a7e07fd..00000000 --- a/btc/1.md +++ /dev/null @@ -1,380 +0,0 @@ -😶‍🌫️go语言官方编程指南:[https://golang.org/#](https://golang.org/#) - -> go语言的官方文档学习笔记很全,推荐去官网学习 - -😶‍🌫️我的学习笔记:github: [https://github.com/3293172751/golang-rearn](https://github.com/3293172751/golang-rearn) - ---- - -**区块链技术(也称之为分布式账本技术)**,是一种互联网数据库技术,其特点是去中心化,公开透明,让每一个人均可参与的数据库记录 - -> ❤️💕💕关于区块链技术,可以关注我,共同学习更多的区块链技术。博客[http://nsddd.top](http://nsddd.top) - ---- - -# 比特币源码分析 - -**首先第一步看目录** - -```shell -[root@mail bitcoin]# pwd -/c/cpp/bitcoin -[root@mail bitcoin]# ls -al -total 256 -drwxr-xr-x 13 root root 4096 Jan 25 17:31 . -drwxr-xr-x 14 root root 4096 Jan 25 16:30 .. --rw-r--r-- 1 root root 562 Jan 25 16:36 autogen.sh -drwxr-xr-x 3 root root 4096 Dec 29 10:19 build-aux -drwxr-xr-x 27 root root 4096 Dec 29 10:20 build_msvc -drwxr-xr-x 5 root root 4096 Jan 25 16:37 ci --rw-r--r-- 1 root root 13235 Dec 29 10:18 .cirrus.yml --rw-r--r-- 1 root root 77855 Dec 29 10:20 configure.ac -drwxr-xr-x 20 root root 4096 Dec 29 10:20 contrib --rw-r--r-- 1 root root 21956 Dec 29 10:20 CONTRIBUTING.md --rw-r--r-- 1 root root 1164 Dec 29 10:20 COPYING -drwxr-xr-x 6 root root 4096 Dec 29 10:20 depends -drwxr-xr-x 5 root root 4096 Mar 11 15:59 doc --rw-r--r-- 1 root root 442 Dec 29 10:18 .editorconfig --rw-r--r-- 1 root root 36 Dec 29 10:19 .gitattributes -drwxr-xr-x 3 root root 4096 Dec 29 10:19 .github --rw-r--r-- 1 root root 2097 Dec 29 10:19 .gitignore --rw-r--r-- 1 root root 27 Dec 29 10:21 INSTALL.md --rw-r--r-- 1 root root 277 Dec 29 10:21 libbitcoinconsensus.pc.in --rw-r--r-- 1 root root 14674 Dec 29 10:21 Makefile.am --rw-r--r-- 1 root root 8 Dec 29 10:19 .python-version --rw-r--r-- 1 root root 3652 Jan 25 17:27 README.md --rw-r--r-- 1 root root 4572 Dec 29 10:21 REVIEWERS --rw-r--r-- 1 root root 904 Dec 29 10:21 SECURITY.md -drwxr-xr-x 6 root root 4096 Dec 29 10:21 share -drwxr-xr-x 29 root root 12288 Mar 4 16:49 src --rw-r--r-- 1 root root 8204 Dec 29 10:19 .style.yapf -drwxr-xr-x 7 root root 4096 Dec 29 10:23 test -drwxr-xr-x 2 root root 4096 Dec 29 10:19 .tx -``` - -打开bitcoin的github地址,我们发现共有四个目录: - -- bitcoin 比特币核心源代码 C++ -- bips 有关比特币改进建议的相关文档 我们经常听到的“” -- libbase58 比特币base58编解码库 C -- libblkmaker 比特币区块模板库 C - -[![bitcoin项目目录](https://s2.loli.net/2022/03/16/prTSnmsCH4he6W2.png)](https://camo.githubusercontent.com/433e1eae76c357ad7dd268f6671a2230dbd9f59106d13b6fe7fec6e817e51573/68747470733a2f2f75706c6f61642d696d616765732e6a69616e7368752e696f2f75706c6f61645f696d616765732f3833303538352d636365303239646134393361643932662e706e673f696d6167654d6f6772322f6175746f2d6f7269656e742f7374726970253743696d61676556696577322f322f772f31323430) - -打开bitcoin,我们看一下核心代码的架构: - -[![bitcoin项目结构](https://s2.loli.net/2022/03/16/clqMHNtSa4gIOX8.png)](https://camo.githubusercontent.com/e9bc5beb36d10af181b60c3d28d55f1b41048ba9160644fbf79f07b3b7967a2b/68747470733a2f2f75706c6f61642d696d616765732e6a69616e7368752e696f2f75706c6f61645f696d616765732f3833303538352d313761653737623339663466326131332e706e673f696d6167654d6f6772322f6175746f2d6f7269656e742f7374726970253743696d61676556696577322f322f772f31323430) - -[![Mac下bitcoin编译文档](https://s2.loli.net/2022/03/16/spYlbXAOuPBKMRc.png)](https://camo.githubusercontent.com/bd86cb175760f2ca7ef9506a7cd68c55dda820106a795b40969f758ae74d79e6/68747470733a2f2f75706c6f61642d696d616765732e6a69616e7368752e696f2f75706c6f61645f696d616765732f3833303538352d343336343530333130613865376536362e706e673f696d6167654d6f6772322f6175746f2d6f7269656e742f7374726970253743696d61676556696577322f322f772f31323430) - - - ---- - -```shell -//拉取bitcoin源代码 -git clone https://github.com/bitcoin/bitcoin.git - -//切换版本到最新 -git checkout 0.16 -``` - -##### 3.几个主要程序 - -- **Bitcoin Core.app** Bitcoin客户端图形界面版 -- **bitcoind** /src/bitcoind Bitcoin简洁命令行版,也是下一步源代码分析的重点(不能与Bitcoin Core同事运行,如果不小心尝试同时运行另外一个客户端,它会提示已经有一个客户端在运行并且自动退出) -- **bitcoin-cli** /src/bitcoin-cli Bitcoind的一个功能完备的RPC客户端,可以通过它在命令行查询某个区块信息, 交易信息等 -- **bitcoin-tx** /src/bitcoind 比特币交易处理模块,可以进行交易的查询和创建 - -## bitcoind - -##### 1.启动与结束bitcoind - -``` -cd .../bitcoin/src - -//1.启动bitcoind,会联网进行block的同步,180多G耗时耗内存 -./bitcoind - -//2.启动并指定同步数 -./bitcoind -maxconnections=0 - -//3.或者在1启动后通过bitcoin-cli无效化当前区块 -./bitcoin-cli invalidateblock `bitcoin-cli getbestblockhash` - -//4.结束 -./bitcoin-cli stop -``` - -##### ***注***:如果突然发现你的Mac内存不够用了,老铁,一定是bitcoin干的!Mac下默认的block同步路径可是让我好找,贴出来省得大家到时候懵逼不知道哪里找: - -``` -/Users/[User]/Library/Application Support/Bitcoin/blocks -``` - -##### 2. bitcoind其他命令 - -./bitcoind -help可以查看bitcoind支持的各种命令和带参格式: - -``` - //bitcoind 命令通用格式 - - bitcoind [选项] - - bitcoind [选项] <命令> [参数] 将命令发送到 -server 或 bitcoind - - bitcoind [选项] help 列出命令 - - bitcoind [选项] help <命令> 获取该命令的帮助 - - - //bitcoind常见命令 - - -conf=<文件名> 指定配置文件(默认:bitcoin.conf) - - -pid=<文件名> 指定 pid (进程 ID)文件(默认:bitcoind.pid) - - -gen 生成比特币 - - -gen=0 不生成比特币 - - -min 启动时最小化 - - -splash 启动时显示启动屏幕(默认:1) - - -datadir=<目录名> 指定数据目录 - - -dbcache= 设置数据库缓存大小,单位为兆字节(MB)(默认:25) - - -dblogsize= 设置数据库磁盘日志大小,单位为兆字节(MB)(默认:100) - - -timeout= 设置连接超时,单位为毫秒 - - -proxy= 通过 Socks4 代理链接 - - -dns addnode 允许查询 DNS 并连接 - - -port=<端口> 监听 <端口> 上的连接(默认:8333,测试网络 testnet:18333) - - -maxconnections= 最多维护 个节点连接(默认:125) - - -addnode= 添加一个节点以供连接,并尝试保持与该节点的连接 - - -connect= 仅连接到这里指定的节点 - - -irc 使用 IRC(因特网中继聊天)查找节点(默认:0) - - -listen 接受来自外部的连接(默认:1) - - -dnsseed 使用 DNS 查找节点(默认:1) - - -banscore= 与行为异常节点断开连接的临界值(默认:100) - - -bantime= 重新允许行为异常节点连接所间隔的秒数(默认:86400) - - -maxreceivebuffer= 最大每连接接收缓存,*1000 字节(默认:10000) - - -maxsendbuffer= 最大每连接发送缓存,*1000 字节(默认:10000) - - -upnp 使用全局即插即用(UPNP)映射监听端口(默认:0) - - -detachdb 分离货币块和地址数据库。会增加客户端关闭时间(默认:0) - - -paytxfee= 您发送的交易每 KB 字节的手续费 - - -testnet 使用测试网络 - - -debug 输出额外的调试信息 - - -logtimestamps 调试信息前添加[时间戳](http://8btc.com/article-165-1.html) - - -printtoconsole 发送跟踪/调试信息到控制台而不是 debug.log 文件 - - -printtodebugger 发送跟踪/调试信息到调试器 - - -rpcuser=<用户名> JSON-RPC 连接使用的用户名 - - -rpcpassword=<密码> JSON-RPC 连接使用的密码 - - -rpcport= JSON-RPC 连接所监听的 <端口>(默认:8332) - - -rpcallowip= 允许来自指定 地址的 JSON-RPC 连接 - - -rpcconnect= 发送命令到运行在 地址的节点(默认:127.0.0.1) - - -blocknotify=<命令> 当最好的货币块改变时执行命令(命令中的 %s 会被替换为货币块哈希值) - - -upgradewallet 将钱包升级到最新的格式 - - -keypool= 将密匙池的尺寸设置为 (默认:100) - - -rescan 重新扫描货币块链以查找钱包丢失的交易 - - -checkblocks= 启动时检查多少货币块(默认:2500,0 表示全部) - - -checklevel= 货币块验证的级别(0-6,默认:1) - -**SSL 选项:** - - -rpcssl 使用 OpenSSL(https)JSON-RPC 连接 - - -rpcsslcertificatechainfile=<文件.cert> 服务器证书文件(默认:server.cert) - - -rpcsslprivatekeyfile=<文件.pem> 服务器私匙文件(默认:server.pem) - - -rpcsslciphers=<密码> 可接受的密码(默认:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH) -``` - -## bitcoin-cli - -Bitcoin Core包含的一个功能完备的RPC客户端,可以查询区块,钱包,交易等各项信息。比特币使用的是Json-RPC接口。 - -##### 1.命令示例 - -``` -//获取height为0的区块哈希 -./src/bitcoin-cli getblockhash 0 - -000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f - -//获取已知某哈希的区块具体信息 -./src/bitcoin-cli getblock 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f - -{ - "hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", - "confirmations": 187783, - "strippedsize": 285, - "size": 285, - "weight": 1140, - "height": 0, - "version": 1, - "versionHex": "00000001", - "merkleroot": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", - "tx": [ - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" - ], - "time": 1231006505, - "mediantime": 1231006505, - "nonce": 2083236893, - "bits": "1d00ffff", - "difficulty": 1, - "chainwork": "0000000000000000000000000000000000000000000000000000000100010001", - "nextblockhash": "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048" -} -``` - -##### 2.其他命令 - -``` -A、一般性的命令 -//帮助指令 -help ( "command" ) - -stop //停止bitcoin服务 -getinfo //获取当前节点信息 -ping -getnettotals -getnetworkinfo -getpeerinfo -getconnectioncount -verifychain ( checklevel numblocks ) -getaddednodeinfo dns ( "node" ) -addnode "node" "add|remove|onetry" - - -B、钱包、账户、地址、转帐、发消息 - -getwalletinfo //获取钱包信息 -walletpassphrase "passphrase" timeout //解锁钱包 密码-多久钱包自动锁定 -walletlock //锁定钱包 -walletpassphrasechange "oldpassphrase" "newpassphrase" //更改钱包密码 -backupwallet "destination" //钱包备份 -importwallet "filename" //钱包备份文件导入 -dumpwallet "filename" //钱包恢复 - -listaccounts ( minconf ) //列出所有用户 -getaddressesbyaccount "account" //列出用户所有的钱包地址 -getaccountaddress "account" -getaccount "bitcoinaddress" -validateaddress "bitcoinaddress" -dumpprivkey "bitcoinaddress" -setaccount "bitcoinaddress" "account" -getnewaddress ( "account" ) //获取新的钱包地址,由钱包地址池生成 -keypoolrefill ( newsize ) -importprivkey "bitcoinprivkey" ( "label" rescan ) //导入私钥 -createmultisig nrequired ["key",...] -addmultisigaddress nrequired ["key",...] ( "account" ) - -getbalance ( "account" minconf ) //显示所有经过至少minconf个确认的交易加和后的余额 -getunconfirmedbalance - -//获取account或bitcoinaddress对应收到的比特币数量 -getreceivedbyaccount "account" ( minconf ) -getreceivedbyaddress "bitcoinaddress" ( minconf ) - -listreceivedbyaccount ( minconf includeempty ) -listreceivedbyaddress ( minconf includeempty ) -move "fromaccount" "toaccount" amount ( minconf "comment" ) -listunspent ( minconf maxconf ["address",...] ) -listlockunspent -lockunspent unlock [{"txid":"txid","vout":n},...] - -getrawchangeaddress -listaddressgroupings -settxfee amount -sendtoaddress "bitcoinaddress" amount ( "comment" "comment-to" ) -sendfrom "fromaccount" "tobitcoinaddress" amount ( minconf "comment" "comment-to" ) -sendmany "fromaccount" {"address":amount,...} ( minconf "comment" ) - -signmessage "bitcoinaddress" "message" -verifymessage "bitcoinaddress" "signature" "message" - - - -C、Tx、Block、Ming - -createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,...} -signrawtransaction "hexstring" ( [{"txid":"id","vout":n,"scriptPubKey":"hex","redeemScript":"hex"},...] ["privatekey1",...] sighashtype ) -sendrawtransaction "hexstring" ( allowhighfees ) - - -gettransaction "txid" //获取简化版交易信息 -//获取完整交易信息 -getrawtransaction "txid" ( verbose ) //得到一个描述交易的16进制字符串 -decoderawtransaction "hexstring" //解码上面的字符串 -listtransactions ( "account" count from ) //获取钱包对应的交易 -listsinceblock ( "blockhash" target-confirmations ) - - -getrawmempool ( verbose ) -gettxoutsetinfo -gettxout "txid" n ( includemempool ) - -decodescript "hex" - -getblockchaininfo -getblockcount -getbestblockhash -getblockhash index -getblock "hash" ( verbose ) - -getmininginfo -getdifficulty -getnetworkhashps ( blocks height ) -gethashespersec -getgenerate -setgenerate generate ( genproclimit ) -getwork ( "data" ) -getblocktemplate ( "jsonrequestobject" ) -submitblock "hexdata" ( "jsonparametersobject" ) -``` - -Mac下bitcoin源码的编译就完成了 - - - -**比特币的源码结构** - -![bitcoin源码结构](https://s2.loli.net/2022/03/16/6QovqB8U9ZlwVtX.jpg) - -![bitcoin功能模块](https://camo.githubusercontent.com/653efd6e8c39331d60fb5ec49e1bb7da1125f62d156911a444f23af2af795d55/68747470733a2f2f75706c6f61642d696d616765732e6a69616e7368752e696f2f75706c6f61645f696d616765732f3833303538352d383238383939376262623638386161632e706e673f696d6167654d6f6772322f6175746f2d6f7269656e742f7374726970253743696d61676556696577322f322f772f31323430) \ No newline at end of file diff --git a/btc/2.md b/btc/2.md deleted file mode 100644 index 660ada45..00000000 --- a/btc/2.md +++ /dev/null @@ -1,254 +0,0 @@ -# 0x02Block - -区块是组成区块的基本单位,我们可以通过bitcoin-cli命令查看一个区块的基本信息。 - -![bitcli-cli获取区块信息](https://s2.loli.net/2022/03/16/3xkTZsE2LDjAnv9.png) - -接下来我们就在源代码找一下区块的定义,由于我们并不知道区块定义在哪。我们试着全局搜一下block.h(或block.cpp): - -![搜索block.h](https://s2.loli.net/2022/03/16/qMsEo3LDcBNpP6f.png) - -进去发现还真被我找到了,其实我们在上一篇的bitcoin源码结构的目录结构里已经说过./private目录下是区块类和交易类的实现。接下来,就让我们一窥block的究竟。 - -# 源码初窥 -### CBlockHeader -```C++ -/** Nodes collect new transactions into a block, hash them into a hash tree, - * and scan through nonce values to make the block's hash satisfy proof-of-work - * requirements. When they solve the proof-of-work, they broadcast the block - * to everyone and the block is added to the block chain. The first transaction - * in the block is a special one that creates a new coin owned by the creator - * of the block. - * - **网络中的节点不断收集新的交易打包到区块中,所有的交易会通过两两哈希的方式形成一个Merkle树 - * 打包的过程就是要完成工作量证明的要求,当节点解出了当前的随机数时, - * 它就把当前的区块广播到其他所有节点,并且加到区块链上。 - * 区块中的第一笔交易称之为CoinBase交易,是产生的新币,奖励给区块的产生者 - * - * add by chaors 20180419 - */ - -class CBlockHeader -{ -public: - // header - int32_t nVersion; //版本 - uint256 hashPrevBlock; //上一个区块的hash - uint256 hashMerkleRoot; //包含交易信息的Merkle树根 - uint32_t nTime; //时间戳 - uint32_t nBits; //工作量证明(POW)的难度 - uint32_t nNonce; //要找的符合POW的随机数 - - CBlockHeader() //构造函数初始化成员变量 - { - SetNull(); - } - - ADD_SERIALIZE_METHODS; //通过封装的模板实现类的序列化 - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(this->nVersion); - READWRITE(hashPrevBlock); - READWRITE(hashMerkleRoot); - READWRITE(nTime); - READWRITE(nBits); - READWRITE(nNonce); - } - - void SetNull() //初始化成员变量 - { - nVersion = 0; - hashPrevBlock.SetNull(); - hashMerkleRoot.SetNull(); - nTime = 0; - nBits = 0; - nNonce = 0; - } - - bool IsNull() const - { - return (nBits == 0); //难度为0说明区块还未创建,区块头为空 - } - - uint256 GetHash() const; //获取哈希 - - int64_t GetBlockTime() const //获取区块时间 - { - return (int64_t)nTime; - } -}; -``` - -### CBlock -```C++ -class CBlock : public CBlockHeader //继承自CBlockHeader,拥有其所有成员变量 -{ -public: - // network and disk - std::vector vtx; //所有交易的容器 - - // memory only - mutable bool fChecked; //交易是否验证 - - CBlock() - { - SetNull(); - } - - CBlock(const CBlockHeader &header) - { - SetNull(); - *((CBlockHeader*)this) = header; - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(*(CBlockHeader*)this); - READWRITE(vtx); - } - - void SetNull() - { - CBlockHeader::SetNull(); - vtx.clear(); - fChecked = false; - } - - CBlockHeader GetBlockHeader() const - { - CBlockHeader block; - block.nVersion = nVersion; - block.hashPrevBlock = hashPrevBlock; - block.hashMerkleRoot = hashMerkleRoot; - block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; - return block; - } - - std::string ToString() const; -}; -``` - -### CBlockLocator -```C++ - -/** Describes a place in the block chain to another node such that if the - * other node doesn't have the same branch, it can find a recent common trunk. - * The further back it is, the further before the fork it may be. - * - **描述区块链中在其他节点的一个位置, - *如果其他节点没有相同的分支,它可以找到一个最近的中继(最近的相同块)。 - *更进一步地讲,它可能是分叉前的一个位置 - */ -struct CBlockLocator -{ - std::vector vHave; - - CBlockLocator() {} - - explicit CBlockLocator(const std::vector& vHaveIn) : vHave(vHaveIn) {} - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - int nVersion = s.GetVersion(); - if (!(s.GetType() & SER_GETHASH)) - READWRITE(nVersion); - READWRITE(vHave); - } - - void SetNull() - { - vHave.clear(); - } - - bool IsNull() const - { - return vHave.empty(); - } -}; -``` - -###. cpp函数 -```C++ -uint256 CBlockHeader::GetHash() const -{ - return SerializeHash(*this); //生成256位的哈希值 -} - -std::string CBlock::ToString() const //区块对象格式化字符串输出 -{ - std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n", - GetHash().ToString(), - nVersion, - hashPrevBlock.ToString(), - hashMerkleRoot.ToString(), - nTime, nBits, nNonce, - vtx.size()); - for (const auto& tx : vtx) { - s << " " << tx->ToString() << "\n"; - } - return s.str(); -} -``` - -# 区块结构分析 - -区块是通过前后链接构成区块链的一种容器数据结构。它由描述区块主要信息的区块头和包含若干交易数据的区块共同组成。区块头是80字节,而平均每个交易至少是250字节,而且平均每个区块至少包含超过500个交易。所以,一个区块是比区块头大好多的数据体。这也是比特币验证交易是否存在采用Merkcle树的原因。 - -### 整体结构 - -| 数据项 | 大小(Byte) | 描述 | -| :------------------: | :---------: | :------------: | -| Block Size | 4 | 区块大小 | -| Block Header | 80 | 区块头信息大小 | -| Transactions | m*n(n>=250) | 所有交易的列表 | -| Transactions Counter | 1-9 | 交易数额 | - -比特币的区块大小目前被严格限制在1MB以内。4字节的区块大小字段不包含在此内! - -### 区块头 -| 数据项 | 大小(Byte) | 存储方式 | 描述 | -| :-----------------: | :--------: | :----------: | :----------------------------------------------------------: | -| Version | 4 | 小端 | [区块版本](https://bitcoin.org/en/developer-reference#block-versions),规定了区块遵守的验证规则 | -| Previous Block Hash | 32 | 内部字节顺序 | 上一个区块哈希值(SHA256 (SHA256(Block Header))) | -| Merkle Root | 32 | 内部字节顺序 | [Merkle](https://bitcoin.org/en/developer-reference#merkle-trees)树根,包含了所有交易的哈希 | -| Timestamp | 4 | 小端 | 区块产生时间戳,大于前11个区块时间戳的平均值,全节点会拒绝时间戳超出自己2小时的区块 | -| nBitS | 4 | 小端 | 工作量证明(POW)的目标难度值,当前区块难度值需要经过[Target nBits编码](https://bitcoin.org/en/developer-reference#merkle-trees)才能转化为目标哈希值 | -| Nonce | 4 | 小端 | 用于POW的一个随机数,随着算力增大可能会导致Nonce位数不够 协议规定时间戳和CoinbaseTransaction信息可修改用于扩展Nonce位数 | - -### 区块标识符 - - - __BlockHash__ 区块哈希值,是通过SHA256算法对区块头信息进行哈希得到的,这个值必须满足POW的DifficultyTarget,该区块才被认为有效。同时,也是区块的唯一标识符,可以通过通过bitcoin-cli根据BlockHash查询区块信息(文章开头我们就使用过) - -- __BlockHeight__ 区块高度,是用来标示区块在区块链中的位置。创世区块高度为0,每一个加在后面的区块,区块高度递增1。可以通过bitcoin-cli根据高度查询区块哈希值(文章开头我们就使用过) - -##### 注:BlockHeight并不是唯一标识符,当区块链出现临时分叉时,会有两个区块的高度值相同的情况。 - -### 创世区块 - -区块链上第一个区块被称为创世区块,它是所有区块的共同祖先。我们可以查看下比特币的创世区块: - -![创世区块](https://upload-images.jianshu.io/upload_images/830585-c55b9849ed27f2cc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -比特币创始人聪哥在创世区块包含了一个隐藏的信息。在其Coinbase交易的输入中包含这样一句话“The Times 03/Jan/2009 Chancellor on brink of second bailout forbanks.”这句话是泰晤士报当天的头版文章标题,聪哥这样做的目的不得而知。但是,这样一条非交易信息可以轻而易举地插入比特币,这个现象值得深思。如此,就不难理解前不久曝光的"不法分子利用比特币存储儿童色情内容"新闻,当然这种存储可能远比聪哥的那句话要更复杂一点。 - -# 思考 - -- 1. 我们查看的区块信息中,以下不在源码结构中的字段有什么含义?为什么他们不在源码定义的区块结构中? - confirmations - strippedsize - weight - mediantime - bits - chainwork - -- 2.为什么区块的哈希没有定义在区块头内部? - -##### 注:以上问题可能我也没答案,可以留言我们一起交流共同进步。 \ No newline at end of file diff --git a/btc/README.md b/btc/README.md new file mode 100644 index 00000000..33055a01 --- /dev/null +++ b/btc/README.md @@ -0,0 +1,168 @@ +[😶‍🌫️XML学习指南(需外网)](https://www.w3schools.com/xml/default.asp) + +> 学习资料很全,推荐!!!! + +[😶‍🌫️我的学习笔记(Github)](https://github.com/3293172751/Block_Chain) + +--- + +**区块链技术(也称之为分布式账本技术)**,是一种互联网数据库技术,其特点是去中心化,公开透明,让每一个人均可参与的数据库记录 + +> ❤️💕💕关于区块链技术,可以关注我,共同学习更多的区块链技术。博客[http://nsddd.top](http://nsddd.top) +> +> + +--- + +# XML + +## 为什么要学习 XML? + +> + +## 目录 + +#### 1. [](markdown/1.md) + +#### 2. [](markdown/2.md) + +#### 3. [](markdown/3.md) + +#### 4. [](markdown/4.md) + +#### 5. [](markdown/5.md) + +#### 6. [](markdown/6.md) + +#### 7. [](markdown/7.md) + +#### 8. [](markdown/8.md) + +#### 9. [](markdown/9.md) + +#### 10. [](markdown/10.md) + +#### 11. [](markdown/11.md) + +#### 12. [](markdown/12.md) + +#### 13. [](markdown/13.md) + +#### 14. [](markdown/14.md) + +#### 15. [](markdown/15.md) + +#### 16. [](markdown/16.md) + +#### 17. [](markdown/17.md) + +#### 18. [](markdown/18.md) + +#### 19. [](markdown/19.md) + +#### 20. [](markdown/20.md) + +#### 21. [](markdown/21.md) + +#### 22. [](markdown/22.md) + +#### 23. [](markdown/23.md) + +#### 24. [](markdown/24.md) + +#### 25. [](markdown/25.md) + +#### 26. [](markdown/26.md) + +#### 27. [](markdown/27.md) + +#### 28. [](markdown/28.md) + +#### 29. [](markdown/29.md) + +#### 30. [](markdown/30.md) + +#### 31. [](markdown/31.md) + +#### 32. [](markdown/32.md) + +#### 33. [](markdown/33.md) + +#### 34. [](markdown/34.md) + +#### 35. [](markdown/35.md) + +#### 36. [](markdown/36.md) + +#### 37. [](markdown/37.md) + +#### 38. [](markdown/38.md) + +#### 39. [](markdown/39.md) + +#### 40. [](markdown/40.md) + +#### 41. [](markdown/41.md) + +#### 42. [](markdown/42.md) + +#### 43. [](markdown/43.md) + +#### 44. [](markdown/44.md) + +#### 45. [](markdown/45.md) + +#### 46. [](markdown/46.md) + +#### 47. [](markdown/47.md) + +#### 48. [](markdown/48.md) + +#### 49. [](markdown/49.md) + +#### 50. [](markdown/50.md) + + + +# ⏬⏬⏬⏬⏬⏬**往下看**⏬⏬⏬⏬⏬⏬ + +---- + +## Golang学习 + +😶‍🌫️[go语言官方编程指南](https://golang.org/#) + +> go语言的官方文档学习笔记很全,推荐可以去官网学习–了解 + +⏬⏬⏬⏬⏬**理解一个事物最好的方式就是把问题当作机器来层层解析**⏬⏬⏬⏬⏬ + +## [🖱️点击进入Go语言学习](https://github.com/3293172751/Block_Chain/blob/master/TOC.md) + +## [🖱️Go语言路线](https://github.com/3293172751/Block_Chain/blob/master/go_route.md) + +------ + +------ + +## 以太坊ETH学习 + +以太坊和比特币一样,底层框架都是区块链协议,区块链本质上是一个应用了密码学技术的分布式数据库系统。建议看一下**以太坊白皮书(需要有golang编程基础)** + +[![img](https://camo.githubusercontent.com/a411fbf80ed8b270ce46ab6f188b1d8468bb67d9001e7bebbbedbe0ee36b585f/68747470733a2f2f73322e6c6f6c692e6e65742f323032322f30332f32302f67546944645541787448474a3466382e706e67)](https://etherscan.io/) + +## [🖱️点击进入ETH学习](https://github.com/3293172751/Block_Chain/blob/master/eth/TOC.md) + +------ + +------ + +## 区块链 + +> 我认为世界历史可以用两句话来描述:分久必合,合久必分。区块链将是催化下一个‘合久必分’时代的新技术。区块链的产生铸就了一个新的时代,我们的信念是建筑在一个数学的算法上面,In math we trust。 +> +> ——张首晟 + +## [🖱️区块链工程师路线](https://github.com/3293172751/Block_Chain/blob/master/route.md) + +- [区块链公益项目(NFT+私链/联盟链/私链)](https://github.com/3293172751/Block_Chain/blob/master/区块链公益项目) +- [共识算法](https://github.com/3293172751/Block_Chain/blob/master/blockchain/README.md) \ No newline at end of file diff --git a/btc/markdown/1.md b/btc/markdown/1.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/10.md b/btc/markdown/10.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/11.md b/btc/markdown/11.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/12.md b/btc/markdown/12.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/13.md b/btc/markdown/13.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/14.md b/btc/markdown/14.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/15.md b/btc/markdown/15.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/16.md b/btc/markdown/16.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/17.md b/btc/markdown/17.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/18.md b/btc/markdown/18.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/19.md b/btc/markdown/19.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/2.md b/btc/markdown/2.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/20.md b/btc/markdown/20.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/21.md b/btc/markdown/21.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/22.md b/btc/markdown/22.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/23.md b/btc/markdown/23.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/24.md b/btc/markdown/24.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/25.md b/btc/markdown/25.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/26.md b/btc/markdown/26.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/27.md b/btc/markdown/27.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/28.md b/btc/markdown/28.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/29.md b/btc/markdown/29.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/3.md b/btc/markdown/3.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/30.md b/btc/markdown/30.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/31.md b/btc/markdown/31.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/32.md b/btc/markdown/32.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/33.md b/btc/markdown/33.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/34.md b/btc/markdown/34.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/35.md b/btc/markdown/35.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/36.md b/btc/markdown/36.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/37.md b/btc/markdown/37.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/38.md b/btc/markdown/38.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/39.md b/btc/markdown/39.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/4.md b/btc/markdown/4.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/40.md b/btc/markdown/40.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/41.md b/btc/markdown/41.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/42.md b/btc/markdown/42.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/43.md b/btc/markdown/43.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/44.md b/btc/markdown/44.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/45.md b/btc/markdown/45.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/46.md b/btc/markdown/46.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/47.md b/btc/markdown/47.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/48.md b/btc/markdown/48.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/49.md b/btc/markdown/49.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/5.md b/btc/markdown/5.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/50.md b/btc/markdown/50.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/6.md b/btc/markdown/6.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/7.md b/btc/markdown/7.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/8.md b/btc/markdown/8.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/markdown/9.md b/btc/markdown/9.md new file mode 100644 index 00000000..e69de29b diff --git a/btc/toc.md b/btc/toc.md new file mode 100644 index 00000000..ab6294d9 --- /dev/null +++ b/btc/toc.md @@ -0,0 +1,1995 @@ +#### 1. [](markdown/1.md) + +#### 2. [](markdown/2.md) + +#### 3. [](markdown/3.md) + +#### 4. [](markdown/4.md) + +#### 5. [](markdown/5.md) + +#### 6. [](markdown/6.md) + +#### 7. [](markdown/7.md) + +#### 8. [](markdown/8.md) + +#### 9. [](markdown/9.md) + +#### 10. [](markdown/10.md) + +#### 11. [](markdown/11.md) + +#### 12. [](markdown/12.md) + +#### 13. [](markdown/13.md) + +#### 14. [](markdown/14.md) + +#### 15. [](markdown/15.md) + +#### 16. [](markdown/16.md) + +#### 17. [](markdown/17.md) + +#### 18. [](markdown/18.md) + +#### 19. [](markdown/19.md) + +#### 20. [](markdown/20.md) + +#### 21. [](markdown/21.md) + +#### 22. [](markdown/22.md) + +#### 23. [](markdown/23.md) + +#### 24. [](markdown/24.md) + +#### 25. [](markdown/25.md) + +#### 26. [](markdown/26.md) + +#### 27. [](markdown/27.md) + +#### 28. [](markdown/28.md) + +#### 29. [](markdown/29.md) + +#### 30. [](markdown/30.md) + +#### 31. [](markdown/31.md) + +#### 32. [](markdown/32.md) + +#### 33. [](markdown/33.md) + +#### 34. [](markdown/34.md) + +#### 35. [](markdown/35.md) + +#### 36. [](markdown/36.md) + +#### 37. [](markdown/37.md) + +#### 38. [](markdown/38.md) + +#### 39. [](markdown/39.md) + +#### 40. [](markdown/40.md) + +#### 41. [](markdown/41.md) + +#### 42. [](markdown/42.md) + +#### 43. [](markdown/43.md) + +#### 44. [](markdown/44.md) + +#### 45. [](markdown/45.md) + +#### 46. [](markdown/46.md) + +#### 47. [](markdown/47.md) + +#### 48. [](markdown/48.md) + +#### 49. [](markdown/49.md) + +#### 50. [](markdown/50.md) + +#### 51. [](markdown/51.md) + +#### 52. [](markdown/52.md) + +#### 53. [](markdown/53.md) + +#### 54. [](markdown/54.md) + +#### 55. [](markdown/55.md) + +#### 56. [](markdown/56.md) + +#### 57. [](markdown/57.md) + +#### 58. [](markdown/58.md) + +#### 59. [](markdown/59.md) + +#### 60. [](markdown/60.md) + +#### 61. [](markdown/61.md) + +#### 62. [](markdown/62.md) + +#### 63. [](markdown/63.md) + +#### 64. [](markdown/64.md) + +#### 65. [](markdown/65.md) + +#### 66. [](markdown/66.md) + +#### 67. [](markdown/67.md) + +#### 68. [](markdown/68.md) + +#### 69. [](markdown/69.md) + +#### 70. [](markdown/70.md) + +#### 71. [](markdown/71.md) + +#### 72. [](markdown/72.md) + +#### 73. [](markdown/73.md) + +#### 74. [](markdown/74.md) + +#### 75. [](markdown/75.md) + +#### 76. [](markdown/76.md) + +#### 77. [](markdown/77.md) + +#### 78. [](markdown/78.md) + +#### 79. [](markdown/79.md) + +#### 80. [](markdown/80.md) + +#### 81. [](markdown/81.md) + +#### 82. [](markdown/82.md) + +#### 83. [](markdown/83.md) + +#### 84. [](markdown/84.md) + +#### 85. [](markdown/85.md) + +#### 86. [](markdown/86.md) + +#### 87. [](markdown/87.md) + +#### 88. [](markdown/88.md) + +#### 89. [](markdown/89.md) + +#### 90. [](markdown/90.md) + +#### 91. [](markdown/91.md) + +#### 92. [](markdown/92.md) + +#### 93. [](markdown/93.md) + +#### 94. [](markdown/94.md) + +#### 95. [](markdown/95.md) + +#### 96. [](markdown/96.md) + +#### 97. [](markdown/97.md) + +#### 98. [](markdown/98.md) + +#### 99. [](markdown/99.md) + +#### 100. [](markdown/100.md) + +#### 101. [](markdown/101.md) + +#### 102. [](markdown/102.md) + +#### 103. [](markdown/103.md) + +#### 104. [](markdown/104.md) + +#### 105. [](markdown/105.md) + +#### 106. [](markdown/106.md) + +#### 107. [](markdown/107.md) + +#### 108. [](markdown/108.md) + +#### 109. [](markdown/109.md) + +#### 110. [](markdown/110.md) + +#### 111. [](markdown/111.md) + +#### 112. [](markdown/112.md) + +#### 113. [](markdown/113.md) + +#### 114. [](markdown/114.md) + +#### 115. [](markdown/115.md) + +#### 116. [](markdown/116.md) + +#### 117. [](markdown/117.md) + +#### 118. [](markdown/118.md) + +#### 119. [](markdown/119.md) + +#### 120. [](markdown/120.md) + +#### 121. [](markdown/121.md) + +#### 122. [](markdown/122.md) + +#### 123. [](markdown/123.md) + +#### 124. [](markdown/124.md) + +#### 125. [](markdown/125.md) + +#### 126. [](markdown/126.md) + +#### 127. [](markdown/127.md) + +#### 128. [](markdown/128.md) + +#### 129. [](markdown/129.md) + +#### 130. [](markdown/130.md) + +#### 131. [](markdown/131.md) + +#### 132. [](markdown/132.md) + +#### 133. [](markdown/133.md) + +#### 134. [](markdown/134.md) + +#### 135. [](markdown/135.md) + +#### 136. [](markdown/136.md) + +#### 137. [](markdown/137.md) + +#### 138. [](markdown/138.md) + +#### 139. [](markdown/139.md) + +#### 140. [](markdown/140.md) + +#### 141. [](markdown/141.md) + +#### 142. [](markdown/142.md) + +#### 143. [](markdown/143.md) + +#### 144. [](markdown/144.md) + +#### 145. [](markdown/145.md) + +#### 146. [](markdown/146.md) + +#### 147. [](markdown/147.md) + +#### 148. [](markdown/148.md) + +#### 149. [](markdown/149.md) + +#### 150. [](markdown/150.md) + +#### 151. [](markdown/151.md) + +#### 152. [](markdown/152.md) + +#### 153. [](markdown/153.md) + +#### 154. [](markdown/154.md) + +#### 155. [](markdown/155.md) + +#### 156. [](markdown/156.md) + +#### 157. [](markdown/157.md) + +#### 158. [](markdown/158.md) + +#### 159. [](markdown/159.md) + +#### 160. [](markdown/160.md) + +#### 161. [](markdown/161.md) + +#### 162. [](markdown/162.md) + +#### 163. [](markdown/163.md) + +#### 164. [](markdown/164.md) + +#### 165. [](markdown/165.md) + +#### 166. [](markdown/166.md) + +#### 167. [](markdown/167.md) + +#### 168. [](markdown/168.md) + +#### 169. [](markdown/169.md) + +#### 170. [](markdown/170.md) + +#### 171. [](markdown/171.md) + +#### 172. [](markdown/172.md) + +#### 173. [](markdown/173.md) + +#### 174. [](markdown/174.md) + +#### 175. [](markdown/175.md) + +#### 176. [](markdown/176.md) + +#### 177. [](markdown/177.md) + +#### 178. [](markdown/178.md) + +#### 179. [](markdown/179.md) + +#### 180. [](markdown/180.md) + +#### 181. [](markdown/181.md) + +#### 182. [](markdown/182.md) + +#### 183. [](markdown/183.md) + +#### 184. [](markdown/184.md) + +#### 185. [](markdown/185.md) + +#### 186. [](markdown/186.md) + +#### 187. [](markdown/187.md) + +#### 188. [](markdown/188.md) + +#### 189. [](markdown/189.md) + +#### 190. [](markdown/190.md) + +#### 191. [](markdown/191.md) + +#### 192. [](markdown/192.md) + +#### 193. [](markdown/193.md) + +#### 194. [](markdown/194.md) + +#### 195. [](markdown/195.md) + +#### 196. [](markdown/196.md) + +#### 197. [](markdown/197.md) + +#### 198. [](markdown/198.md) + +#### 199. [](markdown/199.md) + +#### 200. [](markdown/200.md) + +#### 201. [](markdown/201.md) + +#### 202. [](markdown/202.md) + +#### 203. [](markdown/203.md) + +#### 204. [](markdown/204.md) + +#### 205. [](markdown/205.md) + +#### 206. [](markdown/206.md) + +#### 207. [](markdown/207.md) + +#### 208. [](markdown/208.md) + +#### 209. [](markdown/209.md) + +#### 210. [](markdown/210.md) + +#### 211. [](markdown/211.md) + +#### 212. [](markdown/212.md) + +#### 213. [](markdown/213.md) + +#### 214. [](markdown/214.md) + +#### 215. [](markdown/215.md) + +#### 216. [](markdown/216.md) + +#### 217. [](markdown/217.md) + +#### 218. [](markdown/218.md) + +#### 219. [](markdown/219.md) + +#### 220. [](markdown/220.md) + +#### 221. [](markdown/221.md) + +#### 222. [](markdown/222.md) + +#### 223. [](markdown/223.md) + +#### 224. [](markdown/224.md) + +#### 225. [](markdown/225.md) + +#### 226. [](markdown/226.md) + +#### 227. [](markdown/227.md) + +#### 228. [](markdown/228.md) + +#### 229. [](markdown/229.md) + +#### 230. [](markdown/230.md) + +#### 231. [](markdown/231.md) + +#### 232. [](markdown/232.md) + +#### 233. [](markdown/233.md) + +#### 234. [](markdown/234.md) + +#### 235. [](markdown/235.md) + +#### 236. [](markdown/236.md) + +#### 237. [](markdown/237.md) + +#### 238. [](markdown/238.md) + +#### 239. [](markdown/239.md) + +#### 240. [](markdown/240.md) + +#### 241. [](markdown/241.md) + +#### 242. [](markdown/242.md) + +#### 243. [](markdown/243.md) + +#### 244. [](markdown/244.md) + +#### 245. [](markdown/245.md) + +#### 246. [](markdown/246.md) + +#### 247. [](markdown/247.md) + +#### 248. [](markdown/248.md) + +#### 249. [](markdown/249.md) + +#### 250. [](markdown/250.md) + +#### 251. [](markdown/251.md) + +#### 252. [](markdown/252.md) + +#### 253. [](markdown/253.md) + +#### 254. [](markdown/254.md) + +#### 255. [](markdown/255.md) + +#### 256. [](markdown/256.md) + +#### 257. [](markdown/257.md) + +#### 258. [](markdown/258.md) + +#### 259. [](markdown/259.md) + +#### 260. [](markdown/260.md) + +#### 261. [](markdown/261.md) + +#### 262. [](markdown/262.md) + +#### 263. [](markdown/263.md) + +#### 264. [](markdown/264.md) + +#### 265. [](markdown/265.md) + +#### 266. [](markdown/266.md) + +#### 267. [](markdown/267.md) + +#### 268. [](markdown/268.md) + +#### 269. [](markdown/269.md) + +#### 270. [](markdown/270.md) + +#### 271. [](markdown/271.md) + +#### 272. [](markdown/272.md) + +#### 273. [](markdown/273.md) + +#### 274. [](markdown/274.md) + +#### 275. [](markdown/275.md) + +#### 276. [](markdown/276.md) + +#### 277. [](markdown/277.md) + +#### 278. [](markdown/278.md) + +#### 279. [](markdown/279.md) + +#### 280. [](markdown/280.md) + +#### 281. [](markdown/281.md) + +#### 282. [](markdown/282.md) + +#### 283. [](markdown/283.md) + +#### 284. [](markdown/284.md) + +#### 285. [](markdown/285.md) + +#### 286. [](markdown/286.md) + +#### 287. [](markdown/287.md) + +#### 288. [](markdown/288.md) + +#### 289. [](markdown/289.md) + +#### 290. [](markdown/290.md) + +#### 291. [](markdown/291.md) + +#### 292. [](markdown/292.md) + +#### 293. [](markdown/293.md) + +#### 294. [](markdown/294.md) + +#### 295. [](markdown/295.md) + +#### 296. [](markdown/296.md) + +#### 297. [](markdown/297.md) + +#### 298. [](markdown/298.md) + +#### 299. [](markdown/299.md) + +#### 300. [](markdown/300.md) + +#### 301. [](markdown/301.md) + +#### 302. [](markdown/302.md) + +#### 303. [](markdown/303.md) + +#### 304. [](markdown/304.md) + +#### 305. [](markdown/305.md) + +#### 306. [](markdown/306.md) + +#### 307. [](markdown/307.md) + +#### 308. [](markdown/308.md) + +#### 309. [](markdown/309.md) + +#### 310. [](markdown/310.md) + +#### 311. [](markdown/311.md) + +#### 312. [](markdown/312.md) + +#### 313. [](markdown/313.md) + +#### 314. [](markdown/314.md) + +#### 315. [](markdown/315.md) + +#### 316. [](markdown/316.md) + +#### 317. [](markdown/317.md) + +#### 318. [](markdown/318.md) + +#### 319. [](markdown/319.md) + +#### 320. [](markdown/320.md) + +#### 321. [](markdown/321.md) + +#### 322. [](markdown/322.md) + +#### 323. [](markdown/323.md) + +#### 324. [](markdown/324.md) + +#### 325. [](markdown/325.md) + +#### 326. [](markdown/326.md) + +#### 327. [](markdown/327.md) + +#### 328. [](markdown/328.md) + +#### 329. [](markdown/329.md) + +#### 330. [](markdown/330.md) + +#### 331. [](markdown/331.md) + +#### 332. [](markdown/332.md) + +#### 333. [](markdown/333.md) + +#### 334. [](markdown/334.md) + +#### 335. [](markdown/335.md) + +#### 336. [](markdown/336.md) + +#### 337. [](markdown/337.md) + +#### 338. [](markdown/338.md) + +#### 339. [](markdown/339.md) + +#### 340. [](markdown/340.md) + +#### 341. [](markdown/341.md) + +#### 342. [](markdown/342.md) + +#### 343. [](markdown/343.md) + +#### 344. [](markdown/344.md) + +#### 345. [](markdown/345.md) + +#### 346. [](markdown/346.md) + +#### 347. [](markdown/347.md) + +#### 348. [](markdown/348.md) + +#### 349. [](markdown/349.md) + +#### 350. [](markdown/350.md) + +#### 351. [](markdown/351.md) + +#### 352. [](markdown/352.md) + +#### 353. [](markdown/353.md) + +#### 354. [](markdown/354.md) + +#### 355. [](markdown/355.md) + +#### 356. [](markdown/356.md) + +#### 357. [](markdown/357.md) + +#### 358. [](markdown/358.md) + +#### 359. [](markdown/359.md) + +#### 360. [](markdown/360.md) + +#### 361. [](markdown/361.md) + +#### 362. [](markdown/362.md) + +#### 363. [](markdown/363.md) + +#### 364. [](markdown/364.md) + +#### 365. [](markdown/365.md) + +#### 366. [](markdown/366.md) + +#### 367. [](markdown/367.md) + +#### 368. [](markdown/368.md) + +#### 369. [](markdown/369.md) + +#### 370. [](markdown/370.md) + +#### 371. [](markdown/371.md) + +#### 372. [](markdown/372.md) + +#### 373. [](markdown/373.md) + +#### 374. [](markdown/374.md) + +#### 375. [](markdown/375.md) + +#### 376. [](markdown/376.md) + +#### 377. [](markdown/377.md) + +#### 378. [](markdown/378.md) + +#### 379. [](markdown/379.md) + +#### 380. [](markdown/380.md) + +#### 381. [](markdown/381.md) + +#### 382. [](markdown/382.md) + +#### 383. [](markdown/383.md) + +#### 384. [](markdown/384.md) + +#### 385. [](markdown/385.md) + +#### 386. [](markdown/386.md) + +#### 387. [](markdown/387.md) + +#### 388. [](markdown/388.md) + +#### 389. [](markdown/389.md) + +#### 390. [](markdown/390.md) + +#### 391. [](markdown/391.md) + +#### 392. [](markdown/392.md) + +#### 393. [](markdown/393.md) + +#### 394. [](markdown/394.md) + +#### 395. [](markdown/395.md) + +#### 396. [](markdown/396.md) + +#### 397. [](markdown/397.md) + +#### 398. [](markdown/398.md) + +#### 399. [](markdown/399.md) + +#### 400. [](markdown/400.md) + +#### 401. [](markdown/401.md) + +#### 402. [](markdown/402.md) + +#### 403. [](markdown/403.md) + +#### 404. [](markdown/404.md) + +#### 405. [](markdown/405.md) + +#### 406. [](markdown/406.md) + +#### 407. [](markdown/407.md) + +#### 408. [](markdown/408.md) + +#### 409. [](markdown/409.md) + +#### 410. [](markdown/410.md) + +#### 411. [](markdown/411.md) + +#### 412. [](markdown/412.md) + +#### 413. [](markdown/413.md) + +#### 414. [](markdown/414.md) + +#### 415. [](markdown/415.md) + +#### 416. [](markdown/416.md) + +#### 417. [](markdown/417.md) + +#### 418. [](markdown/418.md) + +#### 419. [](markdown/419.md) + +#### 420. [](markdown/420.md) + +#### 421. [](markdown/421.md) + +#### 422. [](markdown/422.md) + +#### 423. [](markdown/423.md) + +#### 424. [](markdown/424.md) + +#### 425. [](markdown/425.md) + +#### 426. [](markdown/426.md) + +#### 427. [](markdown/427.md) + +#### 428. [](markdown/428.md) + +#### 429. [](markdown/429.md) + +#### 430. [](markdown/430.md) + +#### 431. [](markdown/431.md) + +#### 432. [](markdown/432.md) + +#### 433. [](markdown/433.md) + +#### 434. [](markdown/434.md) + +#### 435. [](markdown/435.md) + +#### 436. [](markdown/436.md) + +#### 437. [](markdown/437.md) + +#### 438. [](markdown/438.md) + +#### 439. [](markdown/439.md) + +#### 440. [](markdown/440.md) + +#### 441. [](markdown/441.md) + +#### 442. [](markdown/442.md) + +#### 443. [](markdown/443.md) + +#### 444. [](markdown/444.md) + +#### 445. [](markdown/445.md) + +#### 446. [](markdown/446.md) + +#### 447. [](markdown/447.md) + +#### 448. [](markdown/448.md) + +#### 449. [](markdown/449.md) + +#### 450. [](markdown/450.md) + +#### 451. [](markdown/451.md) + +#### 452. [](markdown/452.md) + +#### 453. [](markdown/453.md) + +#### 454. [](markdown/454.md) + +#### 455. [](markdown/455.md) + +#### 456. [](markdown/456.md) + +#### 457. [](markdown/457.md) + +#### 458. [](markdown/458.md) + +#### 459. [](markdown/459.md) + +#### 460. [](markdown/460.md) + +#### 461. [](markdown/461.md) + +#### 462. [](markdown/462.md) + +#### 463. [](markdown/463.md) + +#### 464. [](markdown/464.md) + +#### 465. [](markdown/465.md) + +#### 466. [](markdown/466.md) + +#### 467. [](markdown/467.md) + +#### 468. [](markdown/468.md) + +#### 469. [](markdown/469.md) + +#### 470. [](markdown/470.md) + +#### 471. [](markdown/471.md) + +#### 472. [](markdown/472.md) + +#### 473. [](markdown/473.md) + +#### 474. [](markdown/474.md) + +#### 475. [](markdown/475.md) + +#### 476. [](markdown/476.md) + +#### 477. [](markdown/477.md) + +#### 478. [](markdown/478.md) + +#### 479. [](markdown/479.md) + +#### 480. [](markdown/480.md) + +#### 481. [](markdown/481.md) + +#### 482. [](markdown/482.md) + +#### 483. [](markdown/483.md) + +#### 484. [](markdown/484.md) + +#### 485. [](markdown/485.md) + +#### 486. [](markdown/486.md) + +#### 487. [](markdown/487.md) + +#### 488. [](markdown/488.md) + +#### 489. [](markdown/489.md) + +#### 490. [](markdown/490.md) + +#### 491. [](markdown/491.md) + +#### 492. [](markdown/492.md) + +#### 493. [](markdown/493.md) + +#### 494. [](markdown/494.md) + +#### 495. [](markdown/495.md) + +#### 496. [](markdown/496.md) + +#### 497. [](markdown/497.md) + +#### 498. [](markdown/498.md) + +#### 499. [](markdown/499.md) + +#### 500. [](markdown/500.md) + +#### 501. [](markdown/501.md) + +#### 502. [](markdown/502.md) + +#### 503. [](markdown/503.md) + +#### 504. [](markdown/504.md) + +#### 505. [](markdown/505.md) + +#### 506. [](markdown/506.md) + +#### 507. [](markdown/507.md) + +#### 508. [](markdown/508.md) + +#### 509. [](markdown/509.md) + +#### 510. [](markdown/510.md) + +#### 511. [](markdown/511.md) + +#### 512. [](markdown/512.md) + +#### 513. [](markdown/513.md) + +#### 514. [](markdown/514.md) + +#### 515. [](markdown/515.md) + +#### 516. [](markdown/516.md) + +#### 517. [](markdown/517.md) + +#### 518. [](markdown/518.md) + +#### 519. [](markdown/519.md) + +#### 520. [](markdown/520.md) + +#### 521. [](markdown/521.md) + +#### 522. [](markdown/522.md) + +#### 523. [](markdown/523.md) + +#### 524. [](markdown/524.md) + +#### 525. [](markdown/525.md) + +#### 526. [](markdown/526.md) + +#### 527. [](markdown/527.md) + +#### 528. [](markdown/528.md) + +#### 529. [](markdown/529.md) + +#### 530. [](markdown/530.md) + +#### 531. [](markdown/531.md) + +#### 532. [](markdown/532.md) + +#### 533. [](markdown/533.md) + +#### 534. [](markdown/534.md) + +#### 535. [](markdown/535.md) + +#### 536. [](markdown/536.md) + +#### 537. [](markdown/537.md) + +#### 538. [](markdown/538.md) + +#### 539. [](markdown/539.md) + +#### 540. [](markdown/540.md) + +#### 541. [](markdown/541.md) + +#### 542. [](markdown/542.md) + +#### 543. [](markdown/543.md) + +#### 544. [](markdown/544.md) + +#### 545. [](markdown/545.md) + +#### 546. [](markdown/546.md) + +#### 547. [](markdown/547.md) + +#### 548. [](markdown/548.md) + +#### 549. [](markdown/549.md) + +#### 550. [](markdown/550.md) + +#### 551. [](markdown/551.md) + +#### 552. [](markdown/552.md) + +#### 553. [](markdown/553.md) + +#### 554. [](markdown/554.md) + +#### 555. [](markdown/555.md) + +#### 556. [](markdown/556.md) + +#### 557. [](markdown/557.md) + +#### 558. [](markdown/558.md) + +#### 559. [](markdown/559.md) + +#### 560. [](markdown/560.md) + +#### 561. [](markdown/561.md) + +#### 562. [](markdown/562.md) + +#### 563. [](markdown/563.md) + +#### 564. [](markdown/564.md) + +#### 565. [](markdown/565.md) + +#### 566. [](markdown/566.md) + +#### 567. [](markdown/567.md) + +#### 568. [](markdown/568.md) + +#### 569. [](markdown/569.md) + +#### 570. [](markdown/570.md) + +#### 571. [](markdown/571.md) + +#### 572. [](markdown/572.md) + +#### 573. [](markdown/573.md) + +#### 574. [](markdown/574.md) + +#### 575. [](markdown/575.md) + +#### 576. [](markdown/576.md) + +#### 577. [](markdown/577.md) + +#### 578. [](markdown/578.md) + +#### 579. [](markdown/579.md) + +#### 580. [](markdown/580.md) + +#### 581. [](markdown/581.md) + +#### 582. [](markdown/582.md) + +#### 583. [](markdown/583.md) + +#### 584. [](markdown/584.md) + +#### 585. [](markdown/585.md) + +#### 586. [](markdown/586.md) + +#### 587. [](markdown/587.md) + +#### 588. [](markdown/588.md) + +#### 589. [](markdown/589.md) + +#### 590. [](markdown/590.md) + +#### 591. [](markdown/591.md) + +#### 592. [](markdown/592.md) + +#### 593. [](markdown/593.md) + +#### 594. [](markdown/594.md) + +#### 595. [](markdown/595.md) + +#### 596. [](markdown/596.md) + +#### 597. [](markdown/597.md) + +#### 598. [](markdown/598.md) + +#### 599. [](markdown/599.md) + +#### 600. [](markdown/600.md) + +#### 601. [](markdown/601.md) + +#### 602. [](markdown/602.md) + +#### 603. [](markdown/603.md) + +#### 604. [](markdown/604.md) + +#### 605. [](markdown/605.md) + +#### 606. [](markdown/606.md) + +#### 607. [](markdown/607.md) + +#### 608. [](markdown/608.md) + +#### 609. [](markdown/609.md) + +#### 610. [](markdown/610.md) + +#### 611. [](markdown/611.md) + +#### 612. [](markdown/612.md) + +#### 613. [](markdown/613.md) + +#### 614. [](markdown/614.md) + +#### 615. [](markdown/615.md) + +#### 616. [](markdown/616.md) + +#### 617. [](markdown/617.md) + +#### 618. [](markdown/618.md) + +#### 619. [](markdown/619.md) + +#### 620. [](markdown/620.md) + +#### 621. [](markdown/621.md) + +#### 622. [](markdown/622.md) + +#### 623. [](markdown/623.md) + +#### 624. [](markdown/624.md) + +#### 625. [](markdown/625.md) + +#### 626. [](markdown/626.md) + +#### 627. [](markdown/627.md) + +#### 628. [](markdown/628.md) + +#### 629. [](markdown/629.md) + +#### 630. [](markdown/630.md) + +#### 631. [](markdown/631.md) + +#### 632. [](markdown/632.md) + +#### 633. [](markdown/633.md) + +#### 634. [](markdown/634.md) + +#### 635. [](markdown/635.md) + +#### 636. [](markdown/636.md) + +#### 637. [](markdown/637.md) + +#### 638. [](markdown/638.md) + +#### 639. [](markdown/639.md) + +#### 640. [](markdown/640.md) + +#### 641. [](markdown/641.md) + +#### 642. [](markdown/642.md) + +#### 643. [](markdown/643.md) + +#### 644. [](markdown/644.md) + +#### 645. [](markdown/645.md) + +#### 646. [](markdown/646.md) + +#### 647. [](markdown/647.md) + +#### 648. [](markdown/648.md) + +#### 649. [](markdown/649.md) + +#### 650. [](markdown/650.md) + +#### 651. [](markdown/651.md) + +#### 652. [](markdown/652.md) + +#### 653. [](markdown/653.md) + +#### 654. [](markdown/654.md) + +#### 655. [](markdown/655.md) + +#### 656. [](markdown/656.md) + +#### 657. [](markdown/657.md) + +#### 658. [](markdown/658.md) + +#### 659. [](markdown/659.md) + +#### 660. [](markdown/660.md) + +#### 661. [](markdown/661.md) + +#### 662. [](markdown/662.md) + +#### 663. [](markdown/663.md) + +#### 664. [](markdown/664.md) + +#### 665. [](markdown/665.md) + +#### 666. [](markdown/666.md) + +#### 667. [](markdown/667.md) + +#### 668. [](markdown/668.md) + +#### 669. [](markdown/669.md) + +#### 670. [](markdown/670.md) + +#### 671. [](markdown/671.md) + +#### 672. [](markdown/672.md) + +#### 673. [](markdown/673.md) + +#### 674. [](markdown/674.md) + +#### 675. [](markdown/675.md) + +#### 676. [](markdown/676.md) + +#### 677. [](markdown/677.md) + +#### 678. [](markdown/678.md) + +#### 679. [](markdown/679.md) + +#### 680. [](markdown/680.md) + +#### 681. [](markdown/681.md) + +#### 682. [](markdown/682.md) + +#### 683. [](markdown/683.md) + +#### 684. [](markdown/684.md) + +#### 685. [](markdown/685.md) + +#### 686. [](markdown/686.md) + +#### 687. [](markdown/687.md) + +#### 688. [](markdown/688.md) + +#### 689. [](markdown/689.md) + +#### 690. [](markdown/690.md) + +#### 691. [](markdown/691.md) + +#### 692. [](markdown/692.md) + +#### 693. [](markdown/693.md) + +#### 694. [](markdown/694.md) + +#### 695. [](markdown/695.md) + +#### 696. [](markdown/696.md) + +#### 697. [](markdown/697.md) + +#### 698. [](markdown/698.md) + +#### 699. [](markdown/699.md) + +#### 700. [](markdown/700.md) + +#### 701. [](markdown/701.md) + +#### 702. [](markdown/702.md) + +#### 703. [](markdown/703.md) + +#### 704. [](markdown/704.md) + +#### 705. [](markdown/705.md) + +#### 706. [](markdown/706.md) + +#### 707. [](markdown/707.md) + +#### 708. [](markdown/708.md) + +#### 709. [](markdown/709.md) + +#### 710. [](markdown/710.md) + +#### 711. [](markdown/711.md) + +#### 712. [](markdown/712.md) + +#### 713. [](markdown/713.md) + +#### 714. [](markdown/714.md) + +#### 715. [](markdown/715.md) + +#### 716. [](markdown/716.md) + +#### 717. [](markdown/717.md) + +#### 718. [](markdown/718.md) + +#### 719. [](markdown/719.md) + +#### 720. [](markdown/720.md) + +#### 721. [](markdown/721.md) + +#### 722. [](markdown/722.md) + +#### 723. [](markdown/723.md) + +#### 724. [](markdown/724.md) + +#### 725. [](markdown/725.md) + +#### 726. [](markdown/726.md) + +#### 727. [](markdown/727.md) + +#### 728. [](markdown/728.md) + +#### 729. [](markdown/729.md) + +#### 730. [](markdown/730.md) + +#### 731. [](markdown/731.md) + +#### 732. [](markdown/732.md) + +#### 733. [](markdown/733.md) + +#### 734. [](markdown/734.md) + +#### 735. [](markdown/735.md) + +#### 736. [](markdown/736.md) + +#### 737. [](markdown/737.md) + +#### 738. [](markdown/738.md) + +#### 739. [](markdown/739.md) + +#### 740. [](markdown/740.md) + +#### 741. [](markdown/741.md) + +#### 742. [](markdown/742.md) + +#### 743. [](markdown/743.md) + +#### 744. [](markdown/744.md) + +#### 745. [](markdown/745.md) + +#### 746. [](markdown/746.md) + +#### 747. [](markdown/747.md) + +#### 748. [](markdown/748.md) + +#### 749. [](markdown/749.md) + +#### 750. [](markdown/750.md) + +#### 751. [](markdown/751.md) + +#### 752. [](markdown/752.md) + +#### 753. [](markdown/753.md) + +#### 754. [](markdown/754.md) + +#### 755. [](markdown/755.md) + +#### 756. [](markdown/756.md) + +#### 757. [](markdown/757.md) + +#### 758. [](markdown/758.md) + +#### 759. [](markdown/759.md) + +#### 760. [](markdown/760.md) + +#### 761. [](markdown/761.md) + +#### 762. [](markdown/762.md) + +#### 763. [](markdown/763.md) + +#### 764. [](markdown/764.md) + +#### 765. [](markdown/765.md) + +#### 766. [](markdown/766.md) + +#### 767. [](markdown/767.md) + +#### 768. [](markdown/768.md) + +#### 769. [](markdown/769.md) + +#### 770. [](markdown/770.md) + +#### 771. [](markdown/771.md) + +#### 772. [](markdown/772.md) + +#### 773. [](markdown/773.md) + +#### 774. [](markdown/774.md) + +#### 775. [](markdown/775.md) + +#### 776. [](markdown/776.md) + +#### 777. [](markdown/777.md) + +#### 778. [](markdown/778.md) + +#### 779. [](markdown/779.md) + +#### 780. [](markdown/780.md) + +#### 781. [](markdown/781.md) + +#### 782. [](markdown/782.md) + +#### 783. [](markdown/783.md) + +#### 784. [](markdown/784.md) + +#### 785. [](markdown/785.md) + +#### 786. [](markdown/786.md) + +#### 787. [](markdown/787.md) + +#### 788. [](markdown/788.md) + +#### 789. [](markdown/789.md) + +#### 790. [](markdown/790.md) + +#### 791. [](markdown/791.md) + +#### 792. [](markdown/792.md) + +#### 793. [](markdown/793.md) + +#### 794. [](markdown/794.md) + +#### 795. [](markdown/795.md) + +#### 796. [](markdown/796.md) + +#### 797. [](markdown/797.md) + +#### 798. [](markdown/798.md) + +#### 799. [](markdown/799.md) + +#### 800. [](markdown/800.md) + +#### 801. [](markdown/801.md) + +#### 802. [](markdown/802.md) + +#### 803. [](markdown/803.md) + +#### 804. [](markdown/804.md) + +#### 805. [](markdown/805.md) + +#### 806. [](markdown/806.md) + +#### 807. [](markdown/807.md) + +#### 808. [](markdown/808.md) + +#### 809. [](markdown/809.md) + +#### 810. [](markdown/810.md) + +#### 811. [](markdown/811.md) + +#### 812. [](markdown/812.md) + +#### 813. [](markdown/813.md) + +#### 814. [](markdown/814.md) + +#### 815. [](markdown/815.md) + +#### 816. [](markdown/816.md) + +#### 817. [](markdown/817.md) + +#### 818. [](markdown/818.md) + +#### 819. [](markdown/819.md) + +#### 820. [](markdown/820.md) + +#### 821. [](markdown/821.md) + +#### 822. [](markdown/822.md) + +#### 823. [](markdown/823.md) + +#### 824. [](markdown/824.md) + +#### 825. [](markdown/825.md) + +#### 826. [](markdown/826.md) + +#### 827. [](markdown/827.md) + +#### 828. [](markdown/828.md) + +#### 829. [](markdown/829.md) + +#### 830. [](markdown/830.md) + +#### 831. [](markdown/831.md) + +#### 832. [](markdown/832.md) + +#### 833. [](markdown/833.md) + +#### 834. [](markdown/834.md) + +#### 835. [](markdown/835.md) + +#### 836. [](markdown/836.md) + +#### 837. [](markdown/837.md) + +#### 838. [](markdown/838.md) + +#### 839. [](markdown/839.md) + +#### 840. [](markdown/840.md) + +#### 841. [](markdown/841.md) + +#### 842. [](markdown/842.md) + +#### 843. [](markdown/843.md) + +#### 844. [](markdown/844.md) + +#### 845. [](markdown/845.md) + +#### 846. [](markdown/846.md) + +#### 847. [](markdown/847.md) + +#### 848. [](markdown/848.md) + +#### 849. [](markdown/849.md) + +#### 850. [](markdown/850.md) + +#### 851. [](markdown/851.md) + +#### 852. [](markdown/852.md) + +#### 853. [](markdown/853.md) + +#### 854. [](markdown/854.md) + +#### 855. [](markdown/855.md) + +#### 856. [](markdown/856.md) + +#### 857. [](markdown/857.md) + +#### 858. [](markdown/858.md) + +#### 859. [](markdown/859.md) + +#### 860. [](markdown/860.md) + +#### 861. [](markdown/861.md) + +#### 862. [](markdown/862.md) + +#### 863. [](markdown/863.md) + +#### 864. [](markdown/864.md) + +#### 865. [](markdown/865.md) + +#### 866. [](markdown/866.md) + +#### 867. [](markdown/867.md) + +#### 868. [](markdown/868.md) + +#### 869. [](markdown/869.md) + +#### 870. [](markdown/870.md) + +#### 871. [](markdown/871.md) + +#### 872. [](markdown/872.md) + +#### 873. [](markdown/873.md) + +#### 874. [](markdown/874.md) + +#### 875. [](markdown/875.md) + +#### 876. [](markdown/876.md) + +#### 877. [](markdown/877.md) + +#### 878. [](markdown/878.md) + +#### 879. [](markdown/879.md) + +#### 880. [](markdown/880.md) + +#### 881. [](markdown/881.md) + +#### 882. [](markdown/882.md) + +#### 883. [](markdown/883.md) + +#### 884. [](markdown/884.md) + +#### 885. [](markdown/885.md) + +#### 886. [](markdown/886.md) + +#### 887. [](markdown/887.md) + +#### 888. [](markdown/888.md) + +#### 889. [](markdown/889.md) + +#### 890. [](markdown/890.md) + +#### 891. [](markdown/891.md) + +#### 892. [](markdown/892.md) + +#### 893. [](markdown/893.md) + +#### 894. [](markdown/894.md) + +#### 895. [](markdown/895.md) + +#### 896. [](markdown/896.md) + +#### 897. [](markdown/897.md) + +#### 898. [](markdown/898.md) + +#### 899. [](markdown/899.md) + +#### 900. [](markdown/900.md) + +#### 901. [](markdown/901.md) + +#### 902. [](markdown/902.md) + +#### 903. [](markdown/903.md) + +#### 904. [](markdown/904.md) + +#### 905. [](markdown/905.md) + +#### 906. [](markdown/906.md) + +#### 907. [](markdown/907.md) + +#### 908. [](markdown/908.md) + +#### 909. [](markdown/909.md) + +#### 910. [](markdown/910.md) + +#### 911. [](markdown/911.md) + +#### 912. [](markdown/912.md) + +#### 913. [](markdown/913.md) + +#### 914. [](markdown/914.md) + +#### 915. [](markdown/915.md) + +#### 916. [](markdown/916.md) + +#### 917. [](markdown/917.md) + +#### 918. [](markdown/918.md) + +#### 919. [](markdown/919.md) + +#### 920. [](markdown/920.md) + +#### 921. [](markdown/921.md) + +#### 922. [](markdown/922.md) + +#### 923. [](markdown/923.md) + +#### 924. [](markdown/924.md) + +#### 925. [](markdown/925.md) + +#### 926. [](markdown/926.md) + +#### 927. [](markdown/927.md) + +#### 928. [](markdown/928.md) + +#### 929. [](markdown/929.md) + +#### 930. [](markdown/930.md) + +#### 931. [](markdown/931.md) + +#### 932. [](markdown/932.md) + +#### 933. [](markdown/933.md) + +#### 934. [](markdown/934.md) + +#### 935. [](markdown/935.md) + +#### 936. [](markdown/936.md) + +#### 937. [](markdown/937.md) + +#### 938. [](markdown/938.md) + +#### 939. [](markdown/939.md) + +#### 940. [](markdown/940.md) + +#### 941. [](markdown/941.md) + +#### 942. [](markdown/942.md) + +#### 943. [](markdown/943.md) + +#### 944. [](markdown/944.md) + +#### 945. [](markdown/945.md) + +#### 946. [](markdown/946.md) + +#### 947. [](markdown/947.md) + +#### 948. [](markdown/948.md) + +#### 949. [](markdown/949.md) + +#### 950. [](markdown/950.md) + +#### 951. [](markdown/951.md) + +#### 952. [](markdown/952.md) + +#### 953. [](markdown/953.md) + +#### 954. [](markdown/954.md) + +#### 955. [](markdown/955.md) + +#### 956. [](markdown/956.md) + +#### 957. [](markdown/957.md) + +#### 958. [](markdown/958.md) + +#### 959. [](markdown/959.md) + +#### 960. [](markdown/960.md) + +#### 961. [](markdown/961.md) + +#### 962. [](markdown/962.md) + +#### 963. [](markdown/963.md) + +#### 964. [](markdown/964.md) + +#### 965. [](markdown/965.md) + +#### 966. [](markdown/966.md) + +#### 967. [](markdown/967.md) + +#### 968. [](markdown/968.md) + +#### 969. [](markdown/969.md) + +#### 970. [](markdown/970.md) + +#### 971. [](markdown/971.md) + +#### 972. [](markdown/972.md) + +#### 973. [](markdown/973.md) + +#### 974. [](markdown/974.md) + +#### 975. [](markdown/975.md) + +#### 976. [](markdown/976.md) + +#### 977. [](markdown/977.md) + +#### 978. [](markdown/978.md) + +#### 979. [](markdown/979.md) + +#### 980. [](markdown/980.md) + +#### 981. [](markdown/981.md) + +#### 982. [](markdown/982.md) + +#### 983. [](markdown/983.md) + +#### 984. [](markdown/984.md) + +#### 985. [](markdown/985.md) + +#### 986. [](markdown/986.md) + +#### 987. [](markdown/987.md) + +#### 988. [](markdown/988.md) + +#### 989. [](markdown/989.md) + +#### 990. [](markdown/990.md) + +#### 991. [](markdown/991.md) + +#### 992. [](markdown/992.md) + +#### 993. [](markdown/993.md) + +#### 994. [](markdown/994.md) + +#### 995. [](markdown/995.md) + +#### 996. [](markdown/996.md) + +#### 997. [](markdown/997.md) + +#### 998. [](markdown/998.md) \ No newline at end of file diff --git a/chainbrock-learning/01_history/README.md b/chainbrock-learning/01_history/README.md new file mode 100644 index 00000000..4e414cea --- /dev/null +++ b/chainbrock-learning/01_history/README.md @@ -0,0 +1,11 @@ +# 区块链的诞生 + +** 大道无形,链生其中。 ** + +认识新事物,首先要弄清楚它的来龙去脉。知其出身,方能知其所以然。 + +区块链(Blockchain)结构首次为人关注,源于 2009 年初上线的比特币(Bitcoin)开源项目。从记账科技数千年的演化角度来看,区块链实际上是记账问题发展到分布式场景下的天然结果。 + +本章将从记账问题的历史讲起,剖析区块链和分布式账本技术的来龙去脉。通过介绍比特币项目探讨区块链的诞生过程,并初步剖析区块链技术潜在的商业价值。 + +通过阅读本章内容,读者可以了解到区块链思想和技术的起源和背景,以及在商业应用中的巨大潜力。 diff --git a/chainbrock-learning/01_history/_images/3-hops.png b/chainbrock-learning/01_history/_images/3-hops.png new file mode 100644 index 00000000..251596c1 Binary files /dev/null and b/chainbrock-learning/01_history/_images/3-hops.png differ diff --git a/chainbrock-learning/01_history/_images/Adam_Back.png b/chainbrock-learning/01_history/_images/Adam_Back.png new file mode 100644 index 00000000..fcc64692 Binary files /dev/null and b/chainbrock-learning/01_history/_images/Adam_Back.png differ diff --git a/chainbrock-learning/01_history/_images/David_Chaum.png b/chainbrock-learning/01_history/_images/David_Chaum.png new file mode 100644 index 00000000..08d7d8a9 Binary files /dev/null and b/chainbrock-learning/01_history/_images/David_Chaum.png differ diff --git a/chainbrock-learning/01_history/_images/Nick_Szabo.png b/chainbrock-learning/01_history/_images/Nick_Szabo.png new file mode 100644 index 00000000..13d3b0ea Binary files /dev/null and b/chainbrock-learning/01_history/_images/Nick_Szabo.png differ diff --git a/chainbrock-learning/01_history/_images/Wei_Dai.png b/chainbrock-learning/01_history/_images/Wei_Dai.png new file mode 100644 index 00000000..58b91f37 Binary files /dev/null and b/chainbrock-learning/01_history/_images/Wei_Dai.png differ diff --git a/chainbrock-learning/01_history/_images/application_circle.png b/chainbrock-learning/01_history/_images/application_circle.png new file mode 100644 index 00000000..ad7055be Binary files /dev/null and b/chainbrock-learning/01_history/_images/application_circle.png differ diff --git a/chainbrock-learning/01_history/_images/blockchain.png b/chainbrock-learning/01_history/_images/blockchain.png new file mode 100644 index 00000000..9d8c45ba Binary files /dev/null and b/chainbrock-learning/01_history/_images/blockchain.png differ diff --git a/chainbrock-learning/01_history/_images/computing_history.png b/chainbrock-learning/01_history/_images/computing_history.png new file mode 100644 index 00000000..9af641e7 Binary files /dev/null and b/chainbrock-learning/01_history/_images/computing_history.png differ diff --git a/chainbrock-learning/01_history/_images/dlt-01.png b/chainbrock-learning/01_history/_images/dlt-01.png new file mode 100644 index 00000000..5750df1f Binary files /dev/null and b/chainbrock-learning/01_history/_images/dlt-01.png differ diff --git a/chainbrock-learning/01_history/_images/dlt-02.png b/chainbrock-learning/01_history/_images/dlt-02.png new file mode 100644 index 00000000..7969c910 Binary files /dev/null and b/chainbrock-learning/01_history/_images/dlt-02.png differ diff --git a/chainbrock-learning/01_history/_images/dlt-03.png b/chainbrock-learning/01_history/_images/dlt-03.png new file mode 100644 index 00000000..d109faec Binary files /dev/null and b/chainbrock-learning/01_history/_images/dlt-03.png differ diff --git a/chainbrock-learning/01_history/_images/kushim.png b/chainbrock-learning/01_history/_images/kushim.png new file mode 100644 index 00000000..caf8a0cc Binary files /dev/null and b/chainbrock-learning/01_history/_images/kushim.png differ diff --git a/chainbrock-learning/01_history/_images/ledger.jpg b/chainbrock-learning/01_history/_images/ledger.jpg new file mode 100644 index 00000000..03e8951c Binary files /dev/null and b/chainbrock-learning/01_history/_images/ledger.jpg differ diff --git a/chainbrock-learning/01_history/_images/ledger_history.png b/chainbrock-learning/01_history/_images/ledger_history.png new file mode 100644 index 00000000..affc07d3 Binary files /dev/null and b/chainbrock-learning/01_history/_images/ledger_history.png differ diff --git a/chainbrock-learning/01_history/_images/near_dream.png b/chainbrock-learning/01_history/_images/near_dream.png new file mode 100644 index 00000000..244525a7 Binary files /dev/null and b/chainbrock-learning/01_history/_images/near_dream.png differ diff --git a/chainbrock-learning/01_history/_images/simpleBlockchain.png b/chainbrock-learning/01_history/_images/simpleBlockchain.png new file mode 100644 index 00000000..ce877918 Binary files /dev/null and b/chainbrock-learning/01_history/_images/simpleBlockchain.png differ diff --git a/chainbrock-learning/01_history/bitcoin.md b/chainbrock-learning/01_history/bitcoin.md new file mode 100644 index 00000000..adddbd9a --- /dev/null +++ b/chainbrock-learning/01_history/bitcoin.md @@ -0,0 +1,76 @@ +## 集大成者的比特币 + +要了解区块链的诞生过程,先要弄清楚比特币的来龙去脉。这要从加密货币数十年的历史说起。 + +### 加密货币的历史 + +上世纪 50 年代计算机(ENIAC,1946 年)出现后,人们就尝试利用信息技术提高支付系统的效率。除了作为电子支付手段的各种银行卡,自 80 年代起,利用密码学手段构建的加密数字货币(Cryptocurrency)也开始成为研究的热门。 + +加密货币前后经历了 30 多年的探索,比较典型的成果包括 [e-Cash](http://www.hit.bme.hu/~buttyan/courses/BMEVIHIM219/2009/Chaum.BlindSigForPayment.1982.PDF)、[HashCash](http://en.wikipedia.org/wiki/Hashcash)、[B-money](http://www.weidai.com/bmoney.txt)和 Bit Gold 等。 + +![David Chaum](_images/David_Chaum.png) + +1983 年,时任加州大学圣塔芭芭拉分校教授的 [David Chaum](https://en.wikipedia.org/wiki/David_Chaum) 最早在论文《Blind Signature for Untraceable Payments》中提出了 [e-Cash](http://www.hit.bme.hu/~buttyan/courses/BMEVIHIM219/2009/Chaum.BlindSigForPayment.1982.PDF),并于 1989 年创建了 [DigiCash](https://en.wikipedia.org/wiki/Digicash) 公司。ecash 系统是首个尝试实现不可追踪(untraceable)的匿名数字货币,基于 David Chaum 自己发明的盲签名技术,曾被应用于部分银行的小额支付系统中。ecash 虽然不可追踪,但仍依赖中心化机构(银行)的协助,同期也由于信用卡体系的快速崛起,DigiCash 公司最终于 1998 年宣告破产。鉴于 David Chaum 在数字货币研究领域发展早期的贡献,有人认为他是“数字货币之父”。值得一提的是,David Chaum 目前仍活跃在数字货币领域,期待他能做出更重要的贡献。 + +![Adam Back](_images/Adam_Back.png) + +1997 年,[Adam Back](https://en.wikipedia.org/wiki/Adam_Back) 提出了 [HashCash](http://en.wikipedia.org/wiki/Hashcash),来解决邮件系统和博客网站中“拒绝服务攻击(Deny of Service,DoS)”攻击问题。Hashcash 首次应用工作量证明(Proof of Work,PoW)机制来获取额度,该机制后来被比特币所采用。类似思想最早曾在 1993 年的论文《Pricing via processing or combatting junk mail》中提出。 + +![Wei Dai](_images/Wei_Dai.png) + +1998 年,刚大学毕业的华人[Wei Dai](http://www.weidai.com) (戴维)提出了 [B-money](http://www.weidai.com/bmoney.txt) 的设计,这是首个不依赖中心化机构的匿名数字货币方案。B-money 引入工作量证明的思想来解决数字货币产生的问题,指出任何人都可以发行一定量的货币,只要他可以给出某个复杂计算问题(未说明是用 Hash 计算)的答案,货币的发行量将跟问题的计算代价成正比。并且,任何人(或部分参与者)都可以维护一套账本,构成一套初级的 P2P 网络,使用者在网络内通过对带签名的交易消息的广播来实现转账的确认。B-money 是去中心化数字货币领域里程碑式的成果,为后面比特币的出现奠定了基础。从设计上看,B-money 已经很好地解决了货币发行的问题,但是未能解决“双花”问题,也未能指出如何有效、安全地维护账本,最终未能实现。 + +![Nick Szabo](_images/Nick_Szabo.png) + +同年,[Nick Szabo](http://szabo.best.vwh.net/) 也提出了名为 [Bit Gold](https://unenumerated.blogspot.com/2005/12/bit-gold.html) 的非中心化数字货币设计。系统中将解决密码学难题(challenge string)作为发行货币的前提,并且上一个难题的结果作为下一个难题生成的参数。对方案的确认需要系统中大多数参与者确认。该方案最终也并未实现。 + +这些方案要么依赖于一个中心化的管理机构,要么更多偏重理论层面的设计而未能实现。直到比特币的出现,采用创新的区块链结构来维护账本,使用 1999 年后出现的 P2P 网络技术实现账本同步,并引入经济博弈机制,充分利用现代密码学成果,**首次从实践意义上实现了一套非中心化(decentralized)的开源数字货币系统**。也正因为比特币的影响力巨大,很多时候谈到数字货币其实是指类似以加密技术为基础的数字货币(crypto currency)。 + +比特币依托的分布式网络无需任何管理机构,基于密码学原理来确保交易的正确进行;另一方面,比特币的价值和发行并未有中央机构进行调控,而是通过计算力进行背书,通过经济博弈进行自动调整。这也促使人们开始思考,在数字化的世界中,应该如何发行货币,以及如何衡量价值。 + +比特币也启发了众多数字货币的出现。截至 2018 年底,全球已有超过 2000 种数字货币,既包括以官方为发行主体的法定数字货币(Digital Fiat Currency,DFC)或央行数字货币(Central Bank Digital Currency,CBDC),也包括各种民间数字货币。 + +目前,除了像以比特币这样的分布式技术之外,仍然存在不少中心化代理模式的数字货币机制,包括 paypal、支付宝甚至 Q 币等。通过跟已有的支付系统合作,也可以高效地进行代理交易。 + +现在还很难讲哪种模式将会成为日后的主流,未来甚至还可能出现更先进的技术。但毫无疑问,这些成果都为后来的数字货币设计提供了极具价值的参考;而站在前人肩膀上的比特币,必将在人类货币史上留下难以磨灭的印记。 + +*注:严格来说,加密货币并非依赖加密机制,而是使用了密码学中的签名机制。* + +### 比特币的诞生 +2008 年 10 月 31 日(东部时间),星期五下午 2 点 10 分,化名 Satoshi Nakamoto(中本聪)的人在 [metzdowd 密码学邮件列表](http://www.metzdowd.com/pipermail/cryptography/2008-October/014810.html) 中提出了比特币(Bitcoin)的设计白皮书《Bitcoin: A Peer-to-Peer Electronic Cash System》,并在 2009 年公开了最初的实现代码。首个比特币是 UTC 时间 2009 年 1 月 3 日 18:15:05 生成。但比特币真正流行开来,被人们所关注则是至少两年以后了。 + +作为开源项目,比特币很快吸引了大量开发者的加入,目前的官方网站 [bitcoin.org](http://bitcoin.org),提供了比特币相关的代码实现和各种工具软件。 + +除了精妙的设计理念外,比特币最为人津津乐道的一点,是发明人“中本聪”到目前为止尚无法确认真实身份。也有人推测,“中本聪”背后可能不止一个人,而是一个团队。这些猜测都为比特币项目带来了不少传奇色彩。 + +### 比特币的意义和价值 + +直到今天,关于比特币的话题仍充满了不少争议。但大部分人应该都会认可,比特币是数字货币历史上,甚至整个金融历史上一次了不起的社会学实验。 + +比特币网络上线以来,在无人管理的情况下,已经在全球范围内无间断地运行了 10 年时间,成功处理了千万笔交易,最大单笔支付超过 1.5 亿美金。难得的是,比特币网络从未出现过重大的系统故障。 + +比特币网络目前由数千个核心节点参与构成,不需要任何中心化的支持机构参与,纯靠分布式机制支持了稳定上升的交易量。 + +比特币**首次真正从实践意义上实现了安全可靠的非中心化数字货币机制**,这也是它受到无数金融科技从业者热捧的根本原因。 + +作为一种概念货币,比特币主要希望解决已有货币系统面临的几个核心问题: + +* 被掌控在单一机构手中,容易被攻击; +* 自身的价值无法保证,容易出现波动; +* 无法匿名化交易,不够隐私。 + +要实现一套数字货币机制,最关键的还是要建立一套完善的交易记录系统,以及形成一套合理的货币发行机制。 + +这个交易记录系统要能准确、公正地记录发生过的每一笔交易,并且无法被恶意篡改。对比已有的银行系统,可以看出,现有的银行机制作为金融交易的第三方中介机构,有代价地提供了交易记录服务。如果参与交易的多方都完全相信银行的记录(数据库),就不存在信任问题。可是如果是更大范围(甚至跨多家银行)进行流通的货币呢?哪家银行的系统能提供完全可靠不中断的服务呢?唯一可能的方案是一套分布式账本。这个账本可以被所有用户自由访问,而且任何个体都无法对所记录的数据进行恶意篡改和控制。为了实现这样一个前所未有的账本系统,比特币网络巧妙地设计了区块链结构,提供了可靠、无法被篡改的数字货币账本功能。 + +比特币网络中,货币的发行是通过比特币协议来规定的。货币总量受到控制,发行速度随时间自动进行调整。既然总量确定,那么单个比特币的价值会随着越来越多的经济实体认可而水涨船高。发行速度的自动调整则可以避免出现通胀或者通缩的情况。 + +此外,也要看到,作为社会学实验,比特币已经获得了某种成功,特别是基于区块链技术,已经出现了许多颇有价值的商业场景和创新技术。但这绝不意味着比特币自身必然能够进入未来的商业体系中。比特币自身价值的波动十分剧烈;同时由于账目公开可查,通过分析仍有较大概率追踪到实际使用者;比特币系统在管理环节上仍然依赖中心化的机制。 + +### 更有价值的区块链技术 + +如果说比特币是影响力巨大的社会学实验,那么从比特币核心设计中提炼出来的区块链技术,则让大家看到了塑造更高效、更安全的未来商业网络的可能性。 + +2014 年开始,比特币背后的区块链技术开始逐渐受到大家关注,并进一步引发了分布式记账(Distributed Ledger)技术的革新浪潮。区块链思想和结构恰好应对了分布式场景下记账的技术挑战。 + +区块链技术早已从比特币项目脱颖而出,在金融、贸易、征信、物联网、共享经济等诸多领域崭露头角。现在,除非特别指出是“比特币区块链”,否则当人们提到“区块链”时,往往已与比特币没有什么必然联系了。 diff --git a/chainbrock-learning/01_history/business.md b/chainbrock-learning/01_history/business.md new file mode 100644 index 00000000..38884ad1 --- /dev/null +++ b/chainbrock-learning/01_history/business.md @@ -0,0 +1,49 @@ +## 区块链的商业价值 + +商业行为的典型过程为:交易多方通过协商确定商业合约,通过执行合约完成交易。区块链擅长的正是如何在多方之间达成合约,并确保合约的顺利执行。 + +根据类别和应用场景不同,区块链所体现的特点和价值也不同。 + +从技术角度,一般认为,区块链具有如下特点: + +* 分布式容错性:分布式账本网络极其鲁棒,能够容忍部分节点的异常状态; +* 不可篡改性:共识提交后的数据会一直存在,不可被销毁或修改; +* 隐私保护性:密码学保证了数据隐私,即便数据泄露,也无法解析。 + +随之带来的业务特性将可能包括: + +* 可信任性:区块链技术可以提供天然可信的分布式账本平台,不需要额外第三方中介机构参与; +* 降低成本:与传统技术相比,区块链技术可能通过自动化合约执行带来更快的交易,同时降低维护成本; +* 增强安全:区块链技术将有利于安全、可靠的审计管理和账目清算,减少犯罪风险。 + +区块链并不是凭空诞生的新技术,而是多种技术演化到一定程度后的产物,因此,其商业应用场景也跟促生其出现的环境息息相关。对于基于数字方式的交易行为,区块链技术能潜在地降低交易成本、加快交易速度,同时能提高安全性。笔者认为,**能否最终提高生产力,将是一项技术能否被实践接受的关键**。 + +Gartner 在 2017 年的报告《Forecast: Blockchain Business Value, Worldwide, 2017-2030》中预测:“区块链带来的商业价值在 2025 年将超过 1760 亿美金,2030 年将超过 3.1 万亿美金(the business value-add of blockchain will grow to slightly more than $176 billion by 2025, and then it will exceed $3.1 trillion by 2030)”。IDC 在 2018 年的报告《Worldwide Semiannual Blockchain Spending Guide》中预测,到 2021 年全球分布式记账科技相关投资将接近百亿美元,五年内的复合增长率高达 81.2%。 + +目前,区块链技术已经得到了众多金融机构和商业公司的关注,包括大量金融界和信息技术界的领军性企业和团体。典型企业和组织如下所列(排名不分先后)。 + +* 维萨国际公司(VISA International) +* 美国纳斯达克证券交易所(Nasdaq Stock Exchange) +* 高盛投资银行(Goldman Sachs) +* 花旗银行(Citi Bank) +* 美国富国银行(Wells Fargo) +* 中国人民银行(The People's Bank Of China,PBOC) +* 瑞士联合银行(Union Bank of Switzerland) +* 德意志银行(Deutsche Bank AG) +* 美国证券集中保管结算公司(Depository Trust Clearing Corporation,DTCC) +* 全球同业银行金融电讯协会(Society for Worldwide Interbank Financial Telecommunication,SWIFT) +* 三菱日联金融集团(Mitsubishi UFJ Financial Group, Inc.,MUFG) +* 国际商业机器公司(International Business Machines Corporation,IBM) +* 甲骨文公司(Oracle Corporation) +* 微软公司(Microsoft Corporation) +* 英特尔公司(Intel Corporation) +* 亚马逊公司(Amazon Corporation) +* 思科公司(Cisco Corporation) +* 埃森哲公司(Accenture Corporation) +* 脸书公司(Facebook Incorporated) + +实际上,区块链可以有效地实现大规模信息和个体的自主化连接。因此,所有与信息、价值(包括货币、证券、专利、版权、数字商品、实际物品等)、信用等相关的交换过程,都将可能从区块链技术中得到启发或直接受益。但这个过程绝不是一蹴而就的,需要长时间的探索和论证。 + +![区块链影响的交换过程](_images/application_circle.png) + +本书将在后续章节中通过具体的案例来讲解区块链的多个典型商业应用场景。 diff --git a/chainbrock-learning/01_history/dlt_problem.md b/chainbrock-learning/01_history/dlt_problem.md new file mode 100644 index 00000000..3a2b9a90 --- /dev/null +++ b/chainbrock-learning/01_history/dlt_problem.md @@ -0,0 +1,70 @@ +## 分布式记账与区块链 + +金融行业是对前沿信息科技成果最敏感的行业之一。特别是对记账科技,其每次突破都会引发金融领域的重要革新,进而对社会生活的各个方面产生阶段性的影响。那么,从技术层面看,区块链到底解决了什么记账难题呢? + +### 分布式记账的难题 + +分布式记账由来已久。为了正常进行商业活动,参与者需要找到一个多方均能信任的第三方来负责记账,确保交易记录的准确。然而,随着商业活动的规模越来越大,商业过程愈加动态和复杂,很多场景下难以找到符合要求的第三方记账方(例如,供应链领域动辄涉及来自数十个行业的数百家参与企业)。这就需要交易各方探讨在分布式场景下进行协同记账的可能性。 + +实际上,可以很容易设计出一个简单粗暴的分布式记账结构,如下图所示方案(一)。多方均允许对账本进行任意读写,一旦发生新的交易即追加到账本上。这种情况下,如果参与多方均诚实可靠,则该方案可以正常工作;但是一旦有参与方恶意篡改已发生过的记录,则无法确保账本记录的正确性。 + +![方案(一):简单分布式记账结构](_images/dlt-01.png) + +为了防止有参与者对交易记录进行篡改,需要引入一定的验证机制。很自然,可以借鉴信息安全领域的数字摘要(Digital Digest)技术,从而改进为方案(二)。每次当有新的交易记录被追加到账本上时,参与各方可以使用 Hash 算法对完整的交易历史计算数字摘要,获取当前交易历史的“指纹”。此后任意时刻,每个参与方都可以对交易历史重新计算数字摘要,一旦发现指纹不匹配,则说明交易记录被篡改过。同时,通过追踪指纹改变位置,可以定位到被篡改的交易记录。 + +![方案(二):带有数字摘要验证的分布式记账](_images/dlt-02.png) + +方案(二)可以解决账本记录防篡改的问题,然而在实际生产应用时,仍存在较大缺陷。由于每次追加新的交易记录时需要从头对所有的历史数据计算数字摘要,当已存在大量交易历史时,数字摘要计算成本将变得很高。而且,随着新交易的发生,计算耗费将越来越大,系统扩展性很差。 + +为了解决可扩展性的问题,需要进一步改进为方案(三)。注意到每次摘要已经确保了从头开始到摘要位置的完整历史,当新的交易发生后,实际上需要进行额外验证的只是新的交易,即增量部分。因此,计算摘要的过程可以改进为对旧的摘要值再加上新的交易内容进行验证。这样就既解决了防篡改问题,又解决了可扩展性问题。 + +![方案(三):带有数字摘要验证的可扩展的分布式记账](_images/dlt-03.png) + +实际上,读者可能已经注意到,方案(三)中的账本结构正是一个区块链结构(如下图所示)。可见,从分布式记账的基本问题出发,可以自然推导出区块链结构,这也说明了**对于分布式记账问题,区块链结构是一个简洁有效的天然答案**。 + +![区块链结构](_images/blockchain.png) + +*注:当然,区块链结构也并非解决分布式记账问题的唯一答案,实际上,除了简单的线性队列结构,也有人提出采用树或图结构。* + +### 区块链的三次热潮 + +区块链结构的首次大规模应用是在比特币项目。从比特币项目诞生之日算起,区块链已在全球掀起了三次热潮。 + +![区块链的三次热潮](_images/3-hops.png) + +第一波热潮出现在 2013 年左右。比特币项目上线后,很长一段时间里并未获得太多关注。直到比特币价格发生增长,各种加密货币项目纷纷出现,隐藏在其后的区块链结构才首次引发大家的兴趣。2014 年起,区块链这个术语开始频繁出现,但更多集中在加密货币和相关技术领域。 + +第二波热潮出现在 2016 年前后。以区块链为基础的分布式账本技术被证实在众多商业领域存在应用价值。2015 年 10 月《经济学人》封面文章《信任机器》中,正式指出区块链在构建分布式账本平台中的重要作用,促使更多实验性应用出现。下半年更是出现了“初始代币发行(Initial Coin Offering,ICO)”等新型融资募集形式。这一时期,区块链技术自身也有了发展和突破。2015 年 7 月底,以太坊(Ethereum)开源项目正式上线。该项目面向公有场景针对比特币项目的缺陷进行了改善,重点在于对通用智能合约的支持,同时优化了性能和安全性。 + +2015 年底,Linux 基金会牵头发起了超级账本(Hyperledger)开源项目,希望联合各行业的力量构造开放、企业级的分布式账本技术生态。与此前的开源项目相比,超级账本项目主要面向联盟链场景,关注企业在权限管理、隐私保护和安全性能等方面的核心诉求,并积极推动技术成果在各行业的落地实践。首批会员企业包括来自科技界和金融界的领军企业,如 IBM、Intel、Cisco、Digital Asset 等。超级账本项目自诞生后发展十分迅速,目前已经包括 16 大顶级项目,超过 280 家企业会员,并在金融、供应链等领域得到实践应用。尤为值得称道的是,超级账本项目采取了商业友好的 Apache 2.0 开源许可,吸引了众多企业的选用。 + +随着更多商业项目开始落地,从 2017 年开始至今,众多互联网领域的资本开始关注区块链领域,人才缺口持续加大,商业和政策环境开始加强。区块链已经俨然成为继人工智能后的又一资本热点。 + +分析这三次热潮可以看出,每一次热潮的出现都与金融行业对区块链技术的深化应用密切相关。这也表明金融行业对信息科技始终保持了较高的敏感度。 + +### 分布式记账的重要性 + +分布式记账问题为何重要?可以类比互联网出现后给社会带来的重大影响。 + +互联网是人类历史上最大的分布式互联系统,它已成为信息社会的基础设施,很好地解决了传递**信息**的问题。然而,由于早期设计上的缺陷,互联网无法确保所传递信息的可靠性,这大大制约了人们利用互联网进行大规模协作的能力。而以区块链为基础的分布式记账科技则可能解决传递**可信信息**的问题,这意味着基于分布式记账科技的未来商业网络将成为新一代的文明基础设施——大规模协同网络。 + +分布式记账科技的核心价值在于为未来多方协同网络提供可信基础。区块链引发的记账科技的演进,将促使商业协作和组织形态发生变革。甚至世界经济论坛执行主席 Klaus Schwab 认为 “区块链是(继蒸汽机、电气化、计算机之后的)第四次工业革命的核心成果(Blockchains are at the heart of the Fourth Industrial Revolution)”。 + +### 分布式记账的现状与未来 + +类比互联网,从科技发展的一般规律来看,笔者认为,分布式记账科技现在仍处于发展早期,而商业应用已经在加速落地中,如下表所示。 + +阶段 | 互联网 | 区块链 | 阶段 +-- | -- | -- | -- +1974~1983 | ARPANet 内部试验网络 | 比特币试验网络 | 2009~2013 +1984~1993 | TCP/IP 基础协议确立,基础架构完成 | 基础协议和框架探索,出现超级账本、以太坊等开源项目 | 2014~2018 +1990s~2000s | HTTP 应用协议出现;互联网正式进入商用领域 | 商业应用的加速落地,仍未出现杀手级应用 | 2019~2023 +2000s~? | 桌面互联网、移动互联网、物联网 | 分布式协同商业网络 | 2024~ + +互联网在发展过程中,先后经历了试验网络、基础架构和协议、商业应用、大规模普及等四个阶段,每个阶段都长达 10 年左右。其中第二个阶段尤为关键,TCP/IP 取代了已有的网络控制协议成为核心协议,这奠定了后来全球规模互联网的技术基础。 + +作为一套前所未有的大规模协同网络,分布式记账网络的发展很大可能也要经历这四个阶段的演化。当然,站在前人肩膀上,无论是演化速度还是决策效率,都会有不小的优势。 + +客观来看,虽然超级账本、以太坊等开源项目在基础协议和框架方面进行了诸多探索,并取得了重要成果,但在多账本互联、与已有系统的互操作性等方面还存在不足,商业应用的广度和深度仍需实践的考验。 + +但毫无疑问,分布式记账科技已经成为金融科技领域的重要创新,必将为金融行业创造新的发展机遇。而未来的商业协同网络,也将成为人类文明进步的重要基础。 diff --git a/chainbrock-learning/01_history/ledger_history.md b/chainbrock-learning/01_history/ledger_history.md new file mode 100644 index 00000000..b05eef72 --- /dev/null +++ b/chainbrock-learning/01_history/ledger_history.md @@ -0,0 +1,104 @@ +## 记账科技的千年演化 + +如果说金融科技(Financial Technology,Fintech)是保障社会文明的重要支柱,那么记账科技(Ledger Technology,或账本科技)则是这一支柱最核心的基石。 + +大到国际贸易,小到个人消费,都离不开记账这一看似普通却不简单的操作。无论是资金的流转,还是资产的交易,都依赖于银行、交易机构正确维护其记账系统。 + +毫不夸张地说,人类文明的整个发展历程,都伴随着记账科技的持续演化。 + +目前,很少见到对记账科技演化规律的研究,这导致了人们对其认知的局限。近年来,以区块链为基础的分布式账本技术飞速崛起并得到快速应用。尽管如此,却很少有人能说清楚区块链与记账问题的关系。区块链到底解决了哪些问题?为何能在金融领域产生如此巨大的影响? + +按照科技发展的一般规律,可将记账科技从古至今的演化过程大致分为四个阶段:单式账本、复式账本、数字化账本、分布式账本。各个阶段的时期和特点如下表所示。 + +| 阶段 | 时期 | 主要特点 | +| --- | --- | --- | +| 阶段一:单式账本 | 约公元前 3500 年 ~ 15 世纪 | 使用原始的单式记账法(Single Entry Bookkeeping) | +| 阶段二:复式账本 | 15 世纪 ~ 20 世纪中期 | 现代复式记账法(Double Entry Bookkeeping)出现和应用 | +| 阶段三:数字化账本 | 20 世纪中期 ~ 21 世纪初 | 物理媒介账本演化到数字化账本 | +| 阶段四:分布式账本 | 2009 年至今 | 以区块链为代表的分布式账本相关思想和技术出现 | + +科技创新往往不是孤立的。记账科技的发展也与众多科技和商业成果的出现息息相关,特别是商业贸易、计算技术、数据处理等,如下图所示。 + +![记账科技的演化](_images/ledger_history.png) + +下面笔者将具体讲述不同阶段中记账科技的发展状况。 + +### 阶段一:单式账本 + +人类文明早期,就已经产生了记账需求和相关活动。 + +已知最早的账本是“库辛(Kushim)泥板”,于 1929 年发掘于幼发拉底河下游右岸的伊拉克境内。据鉴定,库辛泥板属于公元前 3500 ~ 前 3000 年的乌鲁克城(Uruk,美索不达米亚西南部苏美尔人的古城),其内容据破译为“37 个月收到了 29086 单位的大麦,并由库辛签核”。如下图所示。 + +![乌鲁克城的库辛泥板](_images/kushim.png) + +库辛泥板同时也是目前已知的最古老的人类文字记录。除了昙花一现的苏美尔文明,在古中国、古埃及、古希腊、古罗马等人类早期文明中,都不乏与记账相关的考古发现。 + +类似于这样的通过单条记录进行账目记录的方法称为“单式记账法”或“简单记账法”,对应的账本叫“单式账本”。 + +此后相当长的一段时间里(甚至到今天),人们都在使用单式记账法进行记账,无论是记录在泥板、绳索上,还是记录在后来的纸质账本中,虽然物理媒介不同,但核心方法都是一致的。 + +简单记账法自然易用,适合小规模的简易账务,但当面对大规模账务,特别是涉及多个实体的复杂记账需求时,就暴露出不少问题。 + +首先是容易出错。以库辛账本为例,如果大麦入库和出库交易记录很多,很难确认账本记录跟实际情况是否匹配;即便发现不匹配,也很难定位到哪次记录出了问题。 + +其次是容易篡改。账本只有一个,只能保管在记账者个人手里。假设记账者不那么诚实,那么,他可以轻易地通过修改已有的记录来窃取大麦。并且其他人很难发现账本被篡改过。 + +随着商业活动的普及、交易规模增大和参与方的增多(特别是所有者和经营者的分离),单式记账法已经难以满足人们日益提高的记账需求。代表现代记账思想的“复式记账法”应运而生。 + +### 阶段二:复式账本 + +14 世纪的意大利,是世界贸易的门户,来自各国的商人、学者、艺术家、工匠等齐聚于此,揭开了文艺复兴大时代的序幕。此后长达三个世纪里,整个欧洲在商业、文化、艺术、科技等方面都涌现出大量创新成果,对全世界产生了深远的影响。其中有三项尤为引人注目: + +* 宗教改革:马丁·路德批判了当时基督教的诸多弊端,提出宗教不应有等级制度,即宗教面前人人平等,无需任何代理人或中间介绍人; +* 朴素宇宙观:从地心说,到日心说,再到宇宙观形成,人类终于意识到地球并非所处宇宙的“中心”,甚至任何位置都可以被认为是宇宙的“中心”,是否是中心也并不特别或重要; +* 复式记账法:前所未有的繁荣的商业活动催生了更先进的记账方式。复式记账法将单一中心记录分拆为多个科目,极大提高了账目的可靠性,一旦发现问题,方便追查根源,对应的账本叫“复式账本”。 + +这些成果虽然分属文化、天文和金融等不同领域,但在核心思想上却如此一致和谐,不得不令人惊讶。 + +关于复式记账法的文字记载最早出现于 1494 年,意大利著名数学家卢卡·帕西奥利(Luca Pacioli)在其著作《Summa de arithmetica, geometria, Proportioni et proportionalita(算术、几何、比及比例概要)》中介绍了算术的原理和应用、意大利各地的度量衡制度、商业记账方法和几何学基础。当然,复式记账法的出现是数百年商业活动和数学发展的结果。早在 1202 年,比萨(意大利北部城市)的数学家斐波那契在《珠算原理》中介绍了东方数学思想,包括十进制阿拉伯数字、分数等,还指出了如何使用这些数学手段来进行记账和计算利息。这些都极大地促进了金融行业的发展。 + +复式记账法演化到现在包括增减记账法、收付记账法、借贷记账法三种。目前最常用的是借贷记账法,它基于会计恒等式(资产=负债+权益),确保每笔交易都按照该恒等式进行记录。复式记账法很快就得到了广泛应用,并成为现代会计学的重要基础。卢卡·帕西奥利也因此被誉为“会计学之父”。 + +复式记账法原理并不复杂。由于交易的本质是将某种价值从来源方转移到目标方,因此可将每笔交易分别在贷方(来源方)和借方(目标方)两个科目进行记录,且借贷双方的总额应该时刻保持相等(即守恒)。 + +如果库辛当年也懂得复式记账法,当大麦入库时,就会分别在“库存大麦科目”和“应收大麦科目”上都进行记录,并且记录数额应该一致。如果要做审核,可以分别对不同科目进行统计,查看其结果是否相同。可见,使用复式记账法能很容易对交易的来龙去脉进行追踪,而且验证账目是否记录正确。实际上,比特币的交易模型中也借鉴了复式记账法的思想。 + +复式记账法虽然解决了单个记账人所持本地账本的可信度问题,但是仍然无法解决多方之间账本的可信互通问题。例如,投资者如何确保所投资企业的账目没有作假?贸易双方产生交易纠纷时该以谁的账本为准?这些问题的解决要等到数百年以后了。 + +*注:借(Debit)意味着债务,表示从其他方转移到本科目内;贷(Credit)意味着债权,代表从该科目转移出去。* + +### 阶段三:数字化账本 + +如果要评价 20 世纪最伟大的十大发明,数字计算机一定会入围。它在物理世界之外开创了全新的赛博空间,为人类社会的方方面面都带来了巨大变化。 + +早期计算机很重要的用途之一便是进行账目相关的统计处理。1951年,全世界首台商用计算机 UNIVAC即为美国人口普查局所用。 + +使用计算机,不但可以提高大规模记账的效率,还可以避免人工操作的错误。为了更好地管理统计数据,人们发明了专门的数据库技术。从最早的网状数据库(Network Databases)和层次数据库(Hierarchical Databases),到具有开创意义的关系型数据库(Relational Database),再到互联网出现后大量新需求催生的大数据、NoSQL 等技术,根源上都与记账问题息息相关。 + +在这一阶段,记账方法本身并没有太多创新,但由于数字媒介的出现,使得账本的规模、处理的速度、账本的复杂度,都有了天翻地覆的提升。而这些为后来包括电子商务、互联网金融在内的多种数字化服务奠定了技术基础。 + +### 阶段四:分布式账本 + +复式记账法虽然记录了交易的来龙去脉,不易出错,但本质上仍然是中心化模式。 + +中心化模式的记账系统方便使用,但在很多情况下仍然存在不少问题:账本掌握在个体手中,一旦出现数据丢失则无法找回;在同时涉及到多个交易方的情况下,需要分别维护各自的账本,如果出现不一致,对账较为困难。 + +因此,人们很自然地想到借助分布式系统的思想来实现分布式账本(Distributed Ledger):由交易多方共同维护同一个共享的分布式账本;打通交易在不同阶段的来龙去脉;凭借分布式技术,进一步提高记账的规模、效率、可靠性以及合规性。 + +但在分布式场景下,如何避免某个参与方恶意篡改或破坏记录?该由谁来决定将交易记录写到账本中?这些问题一直没有得到很好的解决。 + +2009 年 1 月,基于区块链结构的比特币网络悄然问世,它融合了现代密码学和分布式网络技术等重要成果。此后数年里,在纯分布式场景下,比特币网络稳定支持了海量转账交易。这让人们开始认识到,**区块链这一看似极为简洁的数据结构,居然恰好解决了分布式记账的基本需求**,于是基于区块链结构的分布式记账技术开始大量出现。由于这些技术多以区块链结构作为其核心的账本结构,也往往被统称为区块链技术。 + +2014 年开始,金融、科技领域的专家们开始关注区块链技术,并积极推动分布式账本相关应用落地。在此过程中,对开放、先进分布式账本平台的需求越来越迫切。 + +2015 年的年底,三十家金融和科技领域的领军企业(包括 IBM、Accenture、Intel、J.P.Morgan、DTCC、SWIFT、Cisco 等)联合发起了超级账本(Hyperledger)开源项目,并由中立的 Linux 基金会进行管理。该项目遵循 Apache v2 许可(商业友好),致力于打造一个开源、满足企业场景的分布式记账科技生态。围绕企业分布式账本的核心诉求,超级账本社区已经发展到涵盖 16 大顶级项目,超过 280 名全球企业会员,支撑了众多的应用案例。 + +目前,基于分布式账本技术的各种创新方案已经在金融、供应链、医疗等领域得到了不少落地应用。但笔者认为,类比互联网的发展过程,目前分布式账本技术整体还处于发展的初期,还存在不少尚待解决的问题,包括权限管理、隐私保护、性能优化和互操作性等。未来在这些方面的科技突破,将极大拓展分布式账本技术的应用场景和形态,最终实现传递“价值”的商业协同网络。 + +*注:1371 年,中国明朝开展了首次面向全国的户籍勘查。勘查采用户帖制度,十年清查一次,每次记录各户现有人数,以及距上次的新增、减少情况。将历届信息进行前后对照,有效规避了统计错误。* + +### 记账科技的未来 + +记账科技历千年而弥新,由简单到复杂,由粗糙到精细,由中心化到分布式,这与业务需求的不断变化密不可分。大规模、高安全、易审计等特性将越来越受到关注。 + +笔者相信,随着社会文明的进步,特别是商业活动的进一步成熟,分布式记账的需求将更加普遍,分布式记账科技也将更加繁荣。 diff --git a/chainbrock-learning/01_history/summary.md b/chainbrock-learning/01_history/summary.md new file mode 100644 index 00000000..7c49a027 --- /dev/null +++ b/chainbrock-learning/01_history/summary.md @@ -0,0 +1,5 @@ +## 本章小结 + +区块链思想诞生于对更先进的分布式记账技术的追求,它支持了首个自带信任、防篡改的分布式账本系统——比特币网络。这让人们意识到,除了互联网这样的尽力而为(不保证可信)的基础设施外,区块链技术还将可能塑造彼此信任的未来网络基础设施。 + +从应用角度讲,以比特币为代表的加密货币只是基于区块链技术的一种金融应用。区块链技术还能带来更通用的计算能力和更广泛的商业价值。本书后续章节将具体介绍区块链的核心技术,以及代表性的开源项目,包括 [以太坊](https://www.ethereum.org/)和[超级账本](https://hyperledger.org) 等。这些开源项目加速释放了区块链技术的威力,为更多更复杂的应用场景提供了技术支持。 diff --git a/chainbrock-learning/02_overview/README.md b/chainbrock-learning/02_overview/README.md new file mode 100644 index 00000000..f3fdcd4d --- /dev/null +++ b/chainbrock-learning/02_overview/README.md @@ -0,0 +1,18 @@ +# 核心技术概览 + +** 设计之妙夺造化,存乎一心胜天工。 ** + +跨境商贸中签订的合同,怎么确保对方能严格遵守和及时执行? + +酒店宣称刚打捞上来的三文鱼,怎么追踪捕捞和运输过程中的时间和卫生情况? + +数字世界里,怎么证明你是谁?怎么证明某个资产属于你? + +囚徒困境中的两个人,怎样才能达成利益的最大化? + +宇宙不同文明之间的“黑暗森林”猜疑链,有没有可能被彻底打破? + +这些看似很难解决的问题,在区块链的世界里已经有了初步的答案。 + +本章将带领大家探索区块链的核心技术,包括其定义与原理、关键的问题等,还将探讨区块链技术的演化,并对未来发展的趋势进行展望。最后,对一些常见的认识误区进行了澄清。 + diff --git a/chainbrock-learning/02_overview/_images/application_circle.png b/chainbrock-learning/02_overview/_images/application_circle.png new file mode 100644 index 00000000..aeb62569 Binary files /dev/null and b/chainbrock-learning/02_overview/_images/application_circle.png differ diff --git a/chainbrock-learning/02_overview/_images/blockchain_example.png b/chainbrock-learning/02_overview/_images/blockchain_example.png new file mode 100644 index 00000000..887d7ea4 Binary files /dev/null and b/chainbrock-learning/02_overview/_images/blockchain_example.png differ diff --git a/chainbrock-learning/02_overview/_images/computing_history.png b/chainbrock-learning/02_overview/_images/computing_history.png new file mode 100644 index 00000000..9af641e7 Binary files /dev/null and b/chainbrock-learning/02_overview/_images/computing_history.png differ diff --git a/chainbrock-learning/02_overview/_images/ledger.jpg b/chainbrock-learning/02_overview/_images/ledger.jpg new file mode 100644 index 00000000..03e8951c Binary files /dev/null and b/chainbrock-learning/02_overview/_images/ledger.jpg differ diff --git a/chainbrock-learning/02_overview/_images/near_dream.png b/chainbrock-learning/02_overview/_images/near_dream.png new file mode 100644 index 00000000..244525a7 Binary files /dev/null and b/chainbrock-learning/02_overview/_images/near_dream.png differ diff --git a/chainbrock-learning/02_overview/_images/simpleBlockchain.png b/chainbrock-learning/02_overview/_images/simpleBlockchain.png new file mode 100644 index 00000000..ce877918 Binary files /dev/null and b/chainbrock-learning/02_overview/_images/simpleBlockchain.png differ diff --git a/chainbrock-learning/02_overview/_images/trust_curve.png b/chainbrock-learning/02_overview/_images/trust_curve.png new file mode 100644 index 00000000..835019dd Binary files /dev/null and b/chainbrock-learning/02_overview/_images/trust_curve.png differ diff --git a/chainbrock-learning/02_overview/challenge.md b/chainbrock-learning/02_overview/challenge.md new file mode 100644 index 00000000..00d33e7a --- /dev/null +++ b/chainbrock-learning/02_overview/challenge.md @@ -0,0 +1,112 @@ +## 关键问题和挑战 + +从技术角度讲,区块链所涉及的领域比较繁杂,包括分布式系统、密码学、心理学、经济学、博弈论、控制论、网络协议等,这也意味着我们在工程实践中会面临大量的挑战。 + +下面列出了目前业界关注较多的一些技术话题。 + +### 隐私保护 + +隐私保护一直是分布式系统领域十分关键的问题。在分布式场景下,因为缺乏独立的管理机制,参与网络的各方无法保证严格遵守协议,甚至会故意试图获取网络中他人的数据,对这些行为都很难进行约束。 + +要在共享协同信息和隐私保护之间达到合适的平衡是个不小的挑战,目前,公有账本系统屡屡出现安全漏洞,动辄造成数千万美金损失的风险。随着欧盟《通用数据保护条例》(General Data Protection Regulation,GDPR)的落地,隐私保护的合规要求愈加严格;传统的信息安全技术、形式化验证技术在应对新的需求时暴露出实践性不强的缺陷,都亟待解决。 + +尤其是医疗健康领域,对数据的隐私性需求最为强烈,要求严格控制数据的来源、所有权和使用范围。传统的基于加密的手段很难满足这些要求,需要结合零知识证明、同态加密、隐私查询等新的密码学手段。而这些新技术在实际应用中还存在不少问题。 + +### 分布式共识 + +共识是分布式系统领域经典的技术难题,学术界和业界都已有大量的研究成果(包括 Paxos、拜占庭系列算法等)。 + +问题的核心在于确保某个变更在分布式网络中得到一致的执行结果,是被参与多方都承认的,同时这个信息是不可推翻的。 + +该问题在公开匿名场景下和带权限管理的场景下需求差异较大,从而导致了基于概率的算法和确定性算法两类思想。 + +最初,比特币区块链考虑的是公开匿名场景下的最坏保证。通过引入了“工作量证明”(Proof of Work)策略来规避少数人的恶意行为,并通过概率模型保证最终共识到最长链。算法的核心思想是基于经济利益的博弈,让恶意破坏的参与者损失经济利益,从而保证大部分人的合作。同时,确认必须经过多个区块的生成之后达成,从概率上进行保证。这类算法的主要问题在于效率低下和能源浪费。类似地,还有以权益为抵押的 PoS 和 DPoS 算法等。 + +后来更多的区块链技术(如超级账本)在带权限许可的场景下,开始考虑支持更多的确定性的共识机制,包括改进的拜占庭算法等,可以解决快速确认的问题。但已有算法往往在大规模和动态场景下表现不佳。 + +共识问题在很长一段时间内都将是极具学术价值的研究热点,核心的指标将包括支持规模、容错的节点比例、决策收敛速度、出错后的恢复、动态特性等。PoW 等基于概率的系列算法理论上允许少于一半的不合作节点,PBFT 等确定性算法理论上则允许不超过 1/3 的不合作节点。 + +### 交易性能 + +一般情况下,区块链并不适用于高频交易的场景,但由于金融系统的迫切需求,业界目前积极探讨如何提高其交易性能,包括吞吐量(Throughput)和确认延迟(Latency)两个方面。 + +目前,公开的比特币公有区块链只能支持平均每秒约 7 笔的吞吐量,其安全的交易确认时间为一小时。以太坊公有区块链的吞吐量略高,达到每秒几十笔,但仍不能满足较大的应用。2017 年底,游戏应用 CryptoKitties 就造成了以太坊网络的严重堵塞。 + +这种场景下,为了提高处理性能,一方面可以提升单个节点的性能(如采用高配置的硬件),同时设计优化的策略和并行算法而提高性能;另外一方面可将交易处理卸载(off-load)到链下,只用区块链记录最终交易信息,如比特币社区提出的 [闪电网络](https://lightning.network/lightning-network-paper.pdf) 等设计。类似地,侧链(side chain)、影子链(shadow chain)等思路在当前阶段也有一定的借鉴意义。类似设计可将整体性能提升 1~2 个数量级。 + +联盟链场景下,参与方在共同的信任前提和利益约束下,可以采取更激进的设计,换取性能的提升。以超级账本 Fabric 项目为例,普通虚拟机配置即可达到每秒数千次的交易吞吐量;在进一步优化或硬件加速情况下可以达到每秒数万次的处理性能。 + +整体来看,目前开源区块链系统已经可以满足大量应用场景的性能需求,但离大规模商用交易系统的吞吐性能(每秒稳定数万笔)还有差距。 + +*注:据公开的数据,VISA 系统的处理均值为 2,000 tps,峰值为 56,000 tps;某大规模金融支付系统的处理峰值超过了 85,000 tps;某大型证券交易所号称的处理均(峰)值在 80,000 tps 左右。* + +### 扩展性 + +常见的分布式系统,可以通过横向增加节点来扩展整个系统的处理能力。 + +对于区块链网络系统来说,跟传统分布式系统不同,这个问题往往并非那么简单。实际上,大部分区块链系统的性能,很大程度上取决于单个节点的处理能力。对这些系统来说,节点需要满足 **高性能、安全、稳定、硬件辅助加解密能力**。 + +例如,对于比特币和以太坊区块链而言,网络中每个参与维护的核心节点都要保持一份完整的存储,并且进行智能合约的处理。此时,整个网络的总存储和计算能力,取决于单个节点的能力。甚至当网络中节点数过多时,可能会因为共识延迟而降低整个网络的性能。尤其在公有网络中,由于大量低性能处理节点的存在,问题将更加明显。 + +要解决这个问题,根本上是放松对每个节点都必须参与完整处理的限制(当然,网络中节点要能合作完成完整的处理),这个思路已经在超级账本等项目中得到应用;同时尽量减少核心层的处理工作,甚至采用多层处理结构来分散交易。 + +在联盟链模式下,还可以专门采用高性能的节点作为核心节点,用相对较弱的节点作为代理访问节点。 + +另外,未来必然会涉及到不同账本之间互通的需求(跨链)。目前无论是基于公证人(Notary)、侧链/中继链锚定(Sidechains / Relays)还是哈希锁定(Hash-locking)机制,在实践中仍存在一些不足。公证人机制往往需要依赖第三方的公证人,存在中心化的弱点;侧链/中继链锚定机制目前应用在资产类转移场景,依赖不同链之间的合约配合;哈希锁定在闪电网络中最早提出,并应用在 W3C 的 Interledger 协议中,目前只支持支付类交换操作,而且要求双方账本理解彼此合约。 + +超级账本的 Quilt 项目和 W3C 的 Interledger Payments 工作组已对此问题开展研究,但离通用的跨链需求还有距离。目前来看,要想解决跨链的扩展性问题,需要有办法打通不同框架,类似路由器来沟通不同的子网。 + +### 安全防护 + +区块链目前最热门的应用场景是金融相关的服务,安全自然是最敏感也是挑战最大的问题。 + +区块链在设计上大量采用了现代成熟的密码学算法和网络通信协议。但这是否就能确保其绝对安全呢? + +**世界上并没有绝对安全的系统。** + +系统越复杂,攻击面越多,安全风险越高;另外系统是由人设计的和运营的,难免出现漏洞。 + +作为分布式系统,区块链首先要考虑传统的网络安全(认证、过滤、攻防)、信息安全(密码配置、密钥管理)、管理安全(审计、风险分析控制)等问题。其次,尤其要注意新场景下凸显的安全挑战。 + +首先是立法。对区块链系统如何进行监管?攻击区块链系统是否属于犯罪?攻击银行系统是要承担后果的。但是目前还没有任何法律保护区块链(特别是公有链)以及基于它的实现。 + +其次是代码实现的漏洞管理。考虑到使用了几十年的 openssl 还带着那么低级的漏洞([heart bleeding](https://heartbleed.com/)),而且是源代码完全开放的情况下,让人不禁对运行中的大量线上系统持谨慎态度。而对于金融系统来说,无论客户端还是平台侧,即便是很小的漏洞都可能造成难以估计的损失。 + +另外,公有区块链所有交易记录都是公开可见的,这意味着所有的交易,即便被匿名化和加密处理,但总会在未来某天被破解。安全界一般认为,只要物理上可接触就不是彻底的安全。实际上,已有文献证明,比特币区块链的交易记录大部分都能追踪到真实用户。 + +公有链普遍缺乏有效的治理和调整机制,一旦运行中出现问题难以及时修正。即使是有人提交了修正补丁,只要有部分既得利益者联合起来反对,就无法得到实施。比特币社区已经出现过多次类似的争论。 + +最后,运行在区块链上的智能合约应用五花八门,可能存在潜在的漏洞,必须要有办法进行安全管控,在注册和运行前进行形式化验证和安全探测,以规避恶意代码的破坏。运行智能合约的环境也会成为攻击的目标。近些年区块链领域的安全事件大都跟智能合约漏洞有关。 + +2014 年 3 月,Mt.gox 交易所宣称其保存的 85 万枚比特币被盗,直接导致破产。 + +2016 年 6 月 17 日,发生 [DAO 系统漏洞被利用](https://blog.daohub.org/the-dao-is-under-attack-8d18ca45011b) 事件,直接导致价值 6000 万美元的数字货币被利用者获取。尽管对于这件事情的反思还在进行中,但事实再次证明,目前基于区块链技术进行生产应用时,务必要细心谨慎地进行设计和验证。必要时,甚至要引入“形式化验证”和人工审核机制。 + +2018 年 3 月,币安交易所被黑客攻击,造成用户持有比特币被大量卖出。虽然事后进行了追回,但仍在短期内对市场价格造成了巨大冲击。 + +*注:著名黑客凯文•米特尼克(Kevin D. Mitnick)所著的《反欺骗的艺术——世界传奇黑客的经历分享》一书中分享了大量的真实社交工程欺骗案例。* + +### 数据库和存储系统 + +区块链网络中的大量信息需要写到文件和数据库中进行存储。 + +观察区块链的应用,大量的读写操作、Hash 计算和验证操作,跟传统数据库的行为十分不同。 + +当年,人们观察到互联网场景中大量非事务性的查询操作,而设计了非关系型(NoSQL)数据库。那么,针对区块链应用的这些特点,是否可以设计出一些特殊的针对性的数据库呢? + +LevelDB、RocksDB 等键值数据库,具备很高的随机写和顺序读、写性能,以及相对较差的随机读的性能,被广泛应用到了区块链信息存储中。但目前来看,面向区块链的数据库技术仍然是需要突破的技术难点之一,特别是如何支持更丰富语义的操作。 + +正如此前预测,目前已经出现了引入区块链特性的“账本数据库”,包括甲骨文和亚马逊等产品。它们通过签名来防抵赖,并追溯数据修改历史,提供审计功能。 + +此外,在高吞吐量的场景下,本地账本结构会快速累积大量数据。这些数据的保存、索引、清理,发生故障后的恢复,新加入节点的数据获取等,都是值得探索的开放问题。 + +### 互操作和运营治理 + +大部分企业内和企业之间都已经存在了一些信息化产品和工具,例如,处于核心位置的数据库、企业信息管理系统、通讯系统等。企业在采用新的产品时,往往会重点考察与已有商业流程和信息系统进行集成时的平滑度。 + +两种系统如何共存,如何分工,彼此的业务交易如何进行合理传递?出现故障如何排查和隔离?已有数据如何在不同系统之间进行迁移和灾备?这些都是很迫切要解决的实际问题。解决不好,将是区块链技术落地的不小阻碍。 + +另外,虽然大部分区块链系统在平台层面都支持了非中心化机制,在运营和治理层面却往往做不到那么非中心化。以比特币网络为例,历史上多次发生过大部分算力集中在少数矿池的情况,同时软件的演化路线集中在少数开发者手中。运营和治理机制是现有区块链系统中普遍缺失的,但在实际应用中又十分重要。 + +如何进行合理的共识、高效的治理仍属于尚未解决的问题。公有账本试图通过将计算机系统中的令牌与经济利益挂钩,维护系统持续运行;联盟账本通过商业合作和投票等方式,推举联盟治理机构,进行联盟网络的维护管理。这些机制仍需在实践过程中不断完善和改进。以供应链场景为例,动辄涉及数百家企业,上下游几十个环节,而且动态性较强。这些都需要分布式账本平台能提供很强的治理投票和权限管控机制。 + diff --git a/chainbrock-learning/02_overview/classify.md b/chainbrock-learning/02_overview/classify.md new file mode 100644 index 00000000..f181e8a3 --- /dev/null +++ b/chainbrock-learning/02_overview/classify.md @@ -0,0 +1,53 @@ +## 技术的演化与分类 + +区块链技术自比特币网络中首次被大规模应用,到今天应用在越来越多的分布式记账场景中。 + +### 区块链的演化 + +比特币区块链面向转账场景,支持简单的脚本计算。很自然想到如果引入更多复杂的计算逻辑,将能支持更多应用场景,这就是智能合约(Smart Contract)。智能合约可以提供除了货币交易功能外更灵活的功能,执行更为复杂的操作。 + +引入智能合约后的区块链,已经超越了单纯的数据记录功能,实际上带有点“智能计算”的意味了;更进一步地,还可以为区块链加入权限管理、高级编程语言支持等,实现更强大的、支持更多商用场景的分布式账本系统。 + +从计算特点上,可以看到现有区块链技术的三种典型演化场景: + +| 场景 | 功能 | 智能合约 | 一致性 | 权限 | 类型 | 性能 | 编程语言 | 代表 | +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +| 数字货币 | 记账功能 | 不带有或较弱 | PoW | 无 | 公有链 | 较低 | 简单脚本 | 比特币网络 | +| 分布式应用引擎 | 智能合约 | 图灵完备 | PoW、PoS | 无 | 公有链 | 受限 | 特定语言 | 以太坊网络 | +| 带权限的分布式账本 | 商业处理 | 多种语言,图灵完备 | 包括 CFT、BFT 在内的多种机制,可插拔 | 支持 | 联盟链 | 可扩展 | 高级编程语言 | 超级账本 | + +### 区块链与分布式记账 + +![复式记账的账本](_images/ledger.jpg) + +[现代复式记账系统](https://zh.wikipedia.org/wiki/%E5%A4%8D%E5%BC%8F%E7%B0%BF%E8%AE%B0)最早出现在文艺复兴时期的意大利,直到今天仍是会计学科的核心方法。复式记账法对每一笔账目同时记录来源和去向,首次将对账验证功能嵌入记账过程,提升了记账过程的可靠性和可追查性。区块链则实现了完整交易历史的记录和保护。 + +从这个角度来看,**区块链是首个自带对账功能的数字账本结构**。 + +更广泛地,区块链实现了非中心化的记录。参与到系统中的节点,并不属于同一组织,彼此可以信任或不信任;链上数据由所有节点共同维护,每个节点都存储一份完整或部分的记录拷贝。 + +跟传统的记账技术相比,基于区块链的分布式账本包括如下特点: + +* 维护一条不断增长的链,只可能添加记录,而且记录一旦确认则不可篡改; +* 非中心化,或者说多中心化的共识,无需集中的控制,实现上尽量分布式; +* 通过密码学的机制来确保交易无法被抵赖和破坏,并尽量保护用户信息和记录的隐私性。 + +### 技术分类 + +根据参与者的不同,可以分为公有(Public 或 Permissionless)链、联盟(Consortium 或 Permissioned)链和私有(Private)链。 + +公有链,顾名思义,任何人都可以参与使用和维护,参与者多为匿名。典型的如比特币和以太坊区块链,信息是完全公开的。 + +如果进一步引入许可机制,可以实现私有链和联盟链两种类型。 + +私有链,由集中管理者进行管理限制,只有内部少数人可以使用,信息不公开。一般认为跟传统中心化记账系统的差异不明显。 + +联盟链则介于两者之间,由若干组织一起合作(如供应链机构或银行联盟等)维护一条区块链,该区块链的使用必须是带有权限的限制访问,相关信息会得到保护,典型如超级账本项目。在架构上,现有大部分区块链在实现都至少包括了网络层、共识层、智能合约和应用层等分层结构,联盟链实现往还会引入额外的权限管理机制。 + +目前来看,公有链信任度最高,也容易引发探讨,但短期内更多的应用会首先在联盟链上落地。公有链因为要面向匿名公开的场景,面临着更多的安全挑战和风险;同时为了支持互联网尺度的交易规模,需要更高的可扩展性。这些技术问题在短期内很难得到解决。 + +对于信任度和中心化程度的关系,对于大部分场景都可以绘制如下所示的曲线。一般地,非中心化程度越高,信任度会越好。但两者的关系并非线性那么简单。随着节点数增加,前期的信任度往往会增长较快,到了一定程度后,信任度随节点数增多并不会得到明显改善。这是因为随着成员数的增加,要实现共谋作恶的成本会指数上升。 + +![信任度和非中心化程度](_images/trust_curve.png) + +另外,根据使用目的和场景的不同,又可以分为以数字货币为目的的货币链,以记录产权为目的的产权链,以众筹为目的的众筹链等,也有不局限特定应用场景的所谓通用链。通用链因为要兼顾不同场景下的应用特点,在设计上需要考虑更加全面。 diff --git a/chainbrock-learning/02_overview/definition.md b/chainbrock-learning/02_overview/definition.md new file mode 100644 index 00000000..850b85d2 --- /dev/null +++ b/chainbrock-learning/02_overview/definition.md @@ -0,0 +1,58 @@ +## 定义与原理 + +### 定义 + +区块链技术自身仍然在飞速发展中,相关规范和标准还待进一步成熟。 + +公认的最早关于区块链的描述性文献是中本聪所撰写的 [《比特币:一种点对点的电子现金系统》](https://bitcoin.org/bitcoin.pdf),但该文献重点在于讨论比特币系统,并没有明确提出区块链的术语。在其中,区块和链被描述为用于记录比特币交易账目历史的数据结构。 + +另外,[Wikipedia](https://en.wikipedia.org/wiki/Blockchain) 上给出的定义中,将区块链类比为一种分布式数据库技术,通过维护数据块的链式结构,可以维持持续增长的、不可篡改的数据记录。 + +笔者认为,讨论区块链可以从狭义和广义两个层面来看待。 + +狭义上,区块链是一种以区块为基本单位的链式数据结构,区块中利用数字摘要对之前的交易历史进行校验,适合分布式记账场景下防篡改和可扩展性的需求。 + +广义上,区块链还指代基于区块链结构实现的分布式记账技术,包括分布式共识、隐私与安全保护、点对点通信技术、网络协议、智能合约等。 + +### 早期应用 + +1990 年 8 月,Bellcore(1984 年由 AT&T 拆分而来的研究机构)的 Stuart Haber 和 W. Scott Stornetta 在论文《How to Time-Stamp a Digital Document》中就提出利用链式结构来解决防篡改问题,其中新生成的时间证明需要包括之前证明的 Hash 值。这可以被认为是区块链结构的最早雏形。 + +后来,2005 年 7 月,在 Git 等开源软件中,也使用了类似区块链结构的机制来记录提交历史。 + +区块链结构最早的大规模应用出现在 2009 年初上线的比特币项目中。在无集中式管理的情况下,比特币网络持续稳定,支持了海量的交易记录,并且从未出现严重的漏洞,引发了广泛关注。这些都与区块链结构自身强校验的特性密切相关。 + +### 基本原理 + +区块链的基本原理理解起来并不复杂。首先来看三个基本概念: + +* 交易(Transaction):一次对账本的操作,导致账本状态的一次改变,如添加一条转账记录; +* 区块(Block):记录一段时间内发生的所有交易和状态结果等,是对当前账本状态的一次共识; +* 链(Chain):由区块按照发生顺序串联而成,是整个账本状态变化的日志记录。 + +如果把区块链系统作为一个状态机,则每次交易意味着一次状态改变;生成的区块,就是参与者对其中交易导致状态改变结果的共识。 + +区块链的目标是实现一个分布的数据记录账本,这个账本只允许添加、不允许删除。账本底层的基本结构是一个线性的链表。链表由一个个“区块”串联组成(如下图所示),后继区块中记录前导区块的哈希(Hash)值。某个区块(以及块里的交易)是否合法,可通过计算哈希值的方式进行快速检验。网络中节点可以提议添加一个新的区块,但必须经过共识机制来对区块达成确认。 + +![区块链结构示例](_images/blockchain_example.png) + +### 以比特币为例理解区块链工作过程 + +具体以比特币网络为例,来看其中如何使用了区块链技术。 + +首先,用户通过比特币客户端发起一项交易,消息广播到比特币网络中等待确认。网络中的节点会将收到的等待确认的交易请求打包在一起,添加上前一个区块头部的哈希值等信息,组成一个区块结构。然后,试图找到一个 nonce 串(随机串)放到区块里,使得区块结构的哈希结果满足一定条件(比如小于某个值)。这个计算 nonce 串的过程,即俗称的“挖矿”。nonce 串的查找需要花费一定的计算力。 + +一旦节点找到了满足条件的 nonce 串,这个区块在格式上就“合法”了,成为候选区块。节点将其在网络中广播出去。其它节点收到候选区块后进行验证,发现确实合法,就承认这个区块是一个新的合法区块,并添加到自己维护的本地区块链结构上。当大部分节点都接受了该区块后,意味着区块被网络接受,区块中所包括的交易也就得到确认。 + +这里比较关键的步骤有两个,一个是完成对一批交易的共识(创建合法区块结构);一个是新的区块添加到链结构上,被网络认可,确保未来无法被篡改。当然,在实现上还会有很多额外的细节。 + +比特币的这种基于算力(寻找 nonce 串)的共识机制被称为工作量证明(Proof of Work,PoW)。这是因为要让哈希结果满足一定条件,并无已知的快速启发式算法,只能对 nonce 值进行逐个尝试的蛮力计算。尝试的次数越多(工作量越大),算出来的概率越大。 + +通过调节对哈希结果的限制条件,比特币网络控制平均约 10 分钟产生一个合法区块。算出区块的节点将得到区块中所有交易的管理费和协议固定发放的奖励费(目前是 12.5 比特币,每四年减半)。 + +读者可能会关心,比特币网络是任何人都可以加入的,如果网络中存在恶意节点,能否进行恶意操作来对区块链中记录进行篡改,从而破坏整个比特币网络系统。比如最简单的,故意不承认别人产生的合法候选区块,或者干脆拒绝来自其它节点的交易请求等。 + +实际上,因为比特币网络中存在大量(据估计数千个)的维护节点,而且大部分节点都是正常工作的,默认都只承认所看到的最长的链结构。只要网络中不存在超过一半的节点提前勾结一起采取恶意行动,则最长的链将很大概率上成为最终合法的链。而且随着时间增加,这个概率会越来越大。例如,经过 6 个区块生成后,即便有一半的节点联合起来想颠覆被确认的结果,其概率也仅为 (1/2)^6 ≈ 1.6%,即低于 1/60 的可能性。10 个区块后概率将降到千分之一以下。 + +当然,如果整个网络中大多数的节点都联合起来作恶,可以导致整个系统无法正常工作。要做到这一点,往往意味着付出很大的代价,跟通过作恶得到的收益相比,往往得不偿失。 + diff --git a/chainbrock-learning/02_overview/misunderstand.md b/chainbrock-learning/02_overview/misunderstand.md new file mode 100644 index 00000000..6e0b03e1 --- /dev/null +++ b/chainbrock-learning/02_overview/misunderstand.md @@ -0,0 +1,19 @@ +## 认识上的误区 + +目前,区块链作为一种相对年轻的技术,自身仍在飞速发展中,在相关概念上仍有一些值得探讨之处。 + +下面总结一些常见的认知误区。 + +**区块链是完全创新的新技术** 作为融合多项已有技术而出现的事物,区块链跟现有记账科技和信息体系是一脉相承的。区块链在解决多方合作和可信计算问题上向前多走了一步,但并不意味着它就是万能的(从来不会存在一项万能的科技),更不会快速颠覆已有的众多商业模式。很长一段时间里,区块链的应用场景仍需不断摸索,区块链在自身发展的同时也会与已有系统共存互通。 + +**区块链必然是非中心化的,非中心化一定优于中心化设计** 比较两种技术的优劣,必须要先确定场景,区块链也是如此。不可能存在某种技术在任意场景下都是最优的。目前区块链的两大形态——公有链和联盟链之所以在技术选型上存在较大差异,正是因为它们面向的场景不同。中心化设计往往具有设计简单、管理完善、性能高、安全可控的特点,但容错性能比较差;非中心化(多中心化)的设计可以提高容错性能,可以利用多方共识来降低篡改风险,但意味着设计较复杂,性能较差。 + +从实际需求出发,现有大部分区块链技术都介于绝对的中心化和绝对的非中心化之间,以取得不同指标上的平衡。例如某些公有链为了提高性能,选择部分代表节点来参与共识。 + +**区块链离不开加密数字货币** 虽说区块链的早期应用之一是比特币等加密数字货币,但发展到今日,区块链技术早已脱颖而出,两者也各自朝着不同的目标向前发展。比特币侧重从金融角度发掘加密数字货币的实验和实践意义;区块链则从技术层面探讨和研究分布式账本科技的商业价值,并试图拓展到更多分布式互信的场景。 + +**区块链是一种数据库技术** 虽然区块链中往往使用了已有的数据库技术,也可以用来存储或管理数据(Data Management),但它要面向的主要问题是多方数据互信协作(Data Collaboration)问题,这是传统数据技术无法解决的。单纯从数据存储或管理角度,区块链效率可能不如传统数据库效率高,因此一般不推荐把大量原始数据直接放到区块链系统中。当然,区块链系统可以与现有数据库和大数据系统等进行集成。甲骨文、亚马逊等团队尝试将区块链的一些特性引入到数据库中,提出了 Blockchain Table、Quantum Ledger Database 等新型数据系统,可以满足防篡改历史、方便审计等需求。 + +另一方面,区块链复杂大规模的场景需求也对数据库技术提出了新的需求。例如开源社区普遍使用的 levelDB 在扩展性方面表现并不特别优秀,需要进行增强;部分业务场景下需要支持 SQL 语义。可以借鉴其它数据库(如 RocksDB 和 BerkeleyDB)的一些优势进行改造。 + +**Token 等于加密数字货币** 早在区块链概念出现之前,Token(令牌或凭证)就大量应用在计算机系统中。作为权限证明,它可以协助计算机系统进行认证等操作。作为分布式系统,区块链中很自然也可以在某些场景(如游戏积分)下借用 Token 机制,带来应用生态的管理便利。而加密数字货币试图借用数字化技术来实现货币功能,更强调经济价值,跟计算机系统中的原生功能无必然联系。总之,两者是不同层面的概念,即使不依赖 Token,仍然可以实现加密数字货币;数字凭证只有具备可靠、大范围接受的购买力,才可能成为货币,否则只能作为收藏品在小圈子内流通。 diff --git a/chainbrock-learning/02_overview/summary.md b/chainbrock-learning/02_overview/summary.md new file mode 100644 index 00000000..20bc3acb --- /dev/null +++ b/chainbrock-learning/02_overview/summary.md @@ -0,0 +1,7 @@ +## 本章小结 + +本章剖析了区块链的相关核心技术,包括其定义、工作原理、技术分类、关键问题和认识上的误区等。通过本章的学习,读者可以对区块链的相关技术体系形成整体上的认识,并对区块链的发展趋势形成更清晰的把握。 + +除了数字货币应用外,业界越来越看重区块链技术在商业应用场景中的潜力。开源社区发起的开放的 [以太坊](https://www.ethereum.org) 和 [超级账本](https://hyperledger.org) 等项目,为更复杂的分布式账本应用提供了坚实的平台支撑。 + +有理由相信,随着更多商业应用场景的落地,区块链技术将在金融和科技领域都起到越来越重要的作用。 diff --git a/chainbrock-learning/02_overview/vision.md b/chainbrock-learning/02_overview/vision.md new file mode 100644 index 00000000..65ef3b65 --- /dev/null +++ b/chainbrock-learning/02_overview/vision.md @@ -0,0 +1,41 @@ +## 趋势与展望 + +关于区块链技术发展趋势的探讨和争论,自其诞生之日起就从未停息。或许,读者可以从现代计算技术的演变史中得到一些启发。 + +![现代计算技术的演变史,笔者于某次技术交流会中提出](_images/computing_history.png) + +以云计算为代表的现代计算技术,其发展历史上有若干重要的时间点和事件: + +* 1969 - ARPANet(Advanced Research Projects Agency Network):现代互联网的前身,由美国高级研究计划署(Advanced Research Project Agency)提出,使用的协议是 NCP ,核心缺陷之一是无法做到和个别计算机网络交流; +* 1973 - TCP/IP:Vinton.Cerf(温顿•瑟夫)与 Bob Karn(鲍勃•卡恩)共同开发出 TCP 模型,解决了 NCP 的缺陷; +* 1982 - Internet:TCP/IP 正式成为规范,并被大规模应用,现代互联网诞生; +* 1989 - WWW:早期互联网的应用主要包括 telnet、ftp、email 等,蒂姆·伯纳斯-李(Tim Berners-Lee)设计的 WWW 协议成为互联网的杀手级应用,引爆了现代互联网,从那开始,互联网业务快速扩张; +* 1999 - salesforce:互联网出现后,一度只能进行通信应用,但 salesforce 开始以云的理念提供基于互联网的企业级服务; +* 2006 - aws ec2:AWS EC2 奠定了云计算的业界标杆,直到今天,竞争者们仍然在试图追赶 AWS 的脚步; +* 2013 - cognitive:以 IBM Watson 为代表的认知计算开始进入商业领域,计算开始变得智能,进入“后云计算时代”。 + +从这个历史中能看出哪些端倪呢? + +一个是 **技术领域也存在着周期律。** 这个周期目前看是 7 年左右。或许正如人有“七年之痒”,技术也存在着七年这道坎,到了这道坎,要么自身发生突破迈过去,要么就被新的技术所取代。事实上,从比特币网络上线(2009 年 1 月)算起,区块链技术在七年后出现了不少突破。 + +*注:为何恰好是七年?7 年按照产品周期来看基本是 2~3 个产品周期,市场或许只能提供不超过三次机会。* + +另外,**最早出现的未必是先驱,也可能是先烈。** 创新科技固然先进,但过早播撒种子,缺乏合适环境也难发芽长大。技术创新与科研创新很不同的一点便是,技术创新必须立足于需求,过早过晚都会错失良机;科研创新则要越早越好,比如二十世纪的现代物理学发展,超前的研究成果奠定了后续一百多年内科技革命的基础。 + +最后,**事物的发展往往是延续的、长期的。** 新生事物大多数不是凭空而生,往往是解决了先贤未能解决的问题,或是出现了之前未曾出现过的场景。很多时候,新生事物的出现需要长期的孵化,坚持还是放弃的故事会不断重复。但只要是朝着提高生产力的正确方向努力,迟早会有出现在舞台上的一天。 + +![坚持还是放弃?](_images/near_dream.png) + +目前,区块链在金融相关领域的应用相对成熟,其它方向尚处于初步实践阶段。但毫无疑问的是,区块链技术在已经落地的行业中,确实带来了生产力提升。2018 年 3 月,国际银行间金融电信协会(The Society for Worldwide Interbank Financial Telecommunication,SWIFT)基于超级账本项目经过一年多的成功验证,宣布认可分布式账本技术可满足银行间实时交易,同时遵守监管的报告要求。 + +此外,相关标准化组织也在积极从标准和规范角度探讨如何使用分布式账本。包括: + +* 国际电信联盟电信标准化组织(International Telecommunication Union Telecommunication Standardization Sector,ITU-T)自 2016 年起发起 3 个工作小组(SG16,17,20)来分别进行分布式账本整体需求、分布式账本安全需求和分布式账本在物联网领域应用等方面的研究; +* 国际标准化组织(International Organization for Standardization,ISO)成立 5 个课题组,探讨制定关于分布式账本架构、应用、安全保护、身份管理和智能合约方面的相关规范; +* 电气电子工程师协会(IEEE)成立 P2418.2 项目,探讨区块链系统数据格式标准; +* 国际互联网工程任务组(Internet Engineering Task Force,IETF)成立了 Decentralized Internet Infrastructure Proposed RG (dinrg)。该研究组将集中在非中心化架构服务中的信任管理、身份管理、命名和资源发现等问题; +* 万维网联盟(World Wide Web Consortium,W3C)成立了三个相关的研究小组,分别探讨区块链技术和应用;数字资产管理规范以及跨账本互联协议等。 + +当然,企业界的进展也不甘落后。不少科技企业已推出了分布式账本相关的产品或方案,并得到了初步的验证。由于分布式账本技术自身的复杂性且尚不成熟,正确使用还需要较高的门槛。目前,这些企业方案多数依托流行的云计算技术,将节约开发成本、方便用户使用账本服务作为主要目标。 + +笔者大胆预测,随着区块链和分布式账本相关技术的成熟,更多应用实践将会落地,特别是面向企业应用的场景。而在未来解决了跨链等一系列问题后,将会出现随时接入、成本低廉的联合账本网络,为人们生活带来更多便利。 diff --git a/chainbrock-learning/03_scenario/README.md b/chainbrock-learning/03_scenario/README.md new file mode 100644 index 00000000..fc22eccd --- /dev/null +++ b/chainbrock-learning/03_scenario/README.md @@ -0,0 +1,9 @@ +# 典型应用场景 + +** 创新落地,应用为王。 ** + +新的技术能否最终落地得以普及,受很多因素影响,其中最关键一点便是合适的应用场景。 + +比特币网络支撑了全球范围内的支付交易,成功论证了去中心化系统长时间自治运转的可行性。这引发了对区块链应用潜力的遐想:如果基于区块链技术构造自动运行的商业价值网络,其中的交易自动完成且无法伪造;所有签署的合同都能按照约定严格执行,这将大大提高商业系统协作的效率。从这个意义上讲,人们相信,基于区块链技术构建的未来商业网络,将是继互联网之后又一次巨大的产业变革。 + +目前,除了金融领域外,在权属追溯、资源共享、物流供应链、征信管理和物联网等诸多领域,也涌现出大量的应用案例。本章将通过剖析这些典型的应用场景,展现区块链技术为不同行业带来的创新潜力。 diff --git a/chainbrock-learning/03_scenario/finance.md b/chainbrock-learning/03_scenario/finance.md new file mode 100644 index 00000000..83469188 --- /dev/null +++ b/chainbrock-learning/03_scenario/finance.md @@ -0,0 +1,266 @@ +## 金融服务 + +金融活动影响人类社会的方方面面,目前涉及货币、证券、保险、抵押、捐赠等诸多行业。通过金融交易,可以优化社会资源运转效率,实现资源使用的最优化。可以说,人类社会的文明发展,离不开金融交易。 + +交易本质上交换的是价值的所属权。为了完成一些贵重资产(例如房产、车辆)的交易,往往需要依靠中介和担保机构,不仅过程繁琐,而且手续费用高昂。之所以需要第三方机构介入,是因为交易双方无法充分信任对方提供的信息。一方面,证明所属权只能通过相关机构开具的证明材料,存在造假风险;另一方面,交换过程手续繁琐,存在篡改和错误的风险。 + +为了确保金融交易的可靠完成,出现了第三方担保机构这样的角色。它们通过提供信任保障服务,提高了社会整体经济活动的效率。但现有的第三方中介机制往往存在成本高、时间周期长、流程复杂、容易出错等缺陷。因此,金融领域长期存在提高交易效率的迫切需求。 + +区块链技术可以为金融服务提供有效、可信的所属权证明,以及相当可靠的合约确保机制。 + +### 数字货币 +银行从角色上,一般分为中央银行(央行)和普通银行。 + +中央银行的两大职能是“促进宏观经济稳定”和“维护金融稳定”(《金融的本质》,本·伯南克(Ben Bernanke),中信出版社,2014 年出版),主要手段就是管理各种证券和利率。央行的存在,为整个社会的金融体系提供了最终的信用担保。 + +普通银行业则往往基于央行的信用,作为中介和担保方,来协助完成多方的金融交易。 + +银行活动主要包括发行货币、完成存贷款等功能。为了保障货币价值稳定,发行机构必须能时时刻刻保证交易的可靠性和确定性。为了做到这一点,传统的金融系统设计了复杂的安全流程,采用了极为复杂的软件和硬件方案,其建设和维护成本都十分昂贵。即便如此,这些系统仍然存在诸多缺陷,每年都会出现安全攻击和金融欺诈事件。此外,交易过程还常常需要经由额外的支付企业进行处理。这些实际上都增大了交易成本。 + +以区块链技术为基础的数字货币的出现,对货币的研究和实践都提出了新的启发,被认为有可能促使这一领域发生革命性变化。 + +除了众所周知的比特币等数字货币实验之外,还有诸多金融机构进行了有意义的尝试,尤其是各国进行的法定数字货币研究,具备越来越多的实践意义。 + +#### 中国人民银行投入区块链研究 + +2016 年,中国人民银行对外发布消息,称深入研究了数字货币涉及的相关技术,包括区块链技术、移动支付、可信可控云计算、密码算法、安全芯片等,被认为积极关注区块链技术的发展。 + +实际上,央行对于区块链技术的研究很早便已开展。 + +2014 年,央行成立发行数字货币的专门研究小组对基于区块链的数字货币进行研究,次年形成研究报告。 + +2016 年 1 月 20 日,央行专门组织了“数字货币研讨会”,邀请了业内的区块链技术专家就数字货币发行的总体框架、演进、以及国家加密货币等话题进行了研讨。会后,发布对我国银行业数字货币的战略性发展思路,提出要早日发行数字货币,并利用数字货币相关技术来打击金融犯罪活动。 + +2016 年 12 月,央行成立数字货币研究所。初步公开设计为“由央行主导,在保持实物现金发行的同时发行以加密算法为基础的数字货币,M0(流通中的现金)的一部分由数字货币构成。为充分保障数字货币的安全性,发行者可采用安全芯片为载体来保护密钥和算法运算过程的安全”。 + +2018 年 7 月,央行数字货币研究所在联合国国际电信联盟(ITU)会议上发表了关于法定数字货币双层架构的主题演讲。 + +2020 年 4 月,央行通过农行账户在多地测试其数字货币钱包应用,支持扫码支付、汇款、收付款和离线支付功能。同年,高盛报告《Reinventing the Yuan for the Digital Age》中预测,未来十年内央行数字货币用户将达到 10 亿人,年度支付额预计达到 19 万亿。 + +目前,中央银行与国家系统重要性金融机构共同维护分布式账本系统,试验直接发行和管理数字货币,作为流通现金的一种补充形式。一旦全面实施,将对现有的支付清算体系,特别商业银行产生重大影响。数字货币由于其电子属性,在发行和防伪方面成本都优于已有的纸质货币。另外,相对信用卡等支付手段,数字现金很难被盗用,大大降低了管理成本。同时也要注意到由银行发行数字货币在匿名程度、点对点直接支付、利息计算等方面仍有待商榷,并且可能对现有商业银行产生较大冲击。 + +#### 加拿大银行提出新的数字货币 + +2016 年 6 月,加拿大央行公开正在开发基于区块链技术的数字版加拿大元(名称为 CAD 币),以允许用户使用加元来兑换该数字货币。经过验证的对手方将会处理货币交易;另外,如果需要,银行将保留销毁 CAD 币的权利。 + +发行 CAD 币是更大的一个探索型科技项目 Jasper 的一部分。除了加拿大央行外,据悉,蒙特利尔银行、加拿大帝国商业银行、加拿大皇家银行、加拿大丰业银行、多伦多道明银行等多家机构也都参与了该项目。Jasper 项目的目标是希望评估分布式账本技术对金融基础设施的变革潜力。通过在大额支付系统的概念验证,认为在基于分布式账本的金融基础设施中应重视监管能力;另外,虽然分布式支付系统并不能降低运营风险,但在与更广泛的金融基础设施进行合作互动时,有助于实现规模效益,实现全行业的效率提升。 + +*[金融时报:Canada experiments with digital dollar on blockchain](http://www.ft.com/cms/s/1117c780-3397-11e6-bda0-04585c31b153,Authorised=false.html?siteedition=uk&_i_location=http%3A%2F%2Fwww.ft.com%2Fcms%2Fs%2F0%2F1117c780-3397-11e6-bda0-04585c31b153.html%3Fsiteedition%3Duk&_i_referer=&classification=conditional_standard&iab=barrier-app#axzz4Bk8JvZsk),2016-06-16。* + +#### 英国央行实现 RSCoin + +英国央行(英格兰银行)在数字货币方面进展十分突出,已经实现了基于分布式账本平台的数字货币原型系统——RSCoin。旨在强化本国经济及国际贸易。 + +RSCoin目标是提供一个由中央银行控制的、可扩展的数字货币,采用了中央银行-商业银行双层链架构、改进版的两阶段提交(Two Phase Commitment),以及多链之间的交叉验证机制。该货币由中央银行发行,交易机构维护底层账本,并定期提交给中央银行。因为该系统主要是央行和下属银行之间使用,通过提前建立一定的信任基础和采用分片机制,可以提供较好的处理性能(单记账机构可以达到2000笔每秒)。RSCoin理论上可以作为面向全社会的支付手段,但技术和监管细节上需要进一步完善。 + +英国央行对 RSCoin 进行了推广,希望能尽快普及该数字货币,以带来节约经济成本、促进经济发展的效果。同时,英国央行认为,数字货币相对传统货币更适合国际贸易等场景,同时理论上具备成为各国货币兑换媒介的潜力。 + +### 支付清结算业务 + +支付和清结算是现代金融行业十分重要的操作。随着信息技术的发展,支付清结算业务系统的效率也在不断提高。但当资金的清算涉及到多个交易主体和多个认证环节时效率仍然不高,特别涉及到跨境多方交易等场景时。 + +区块链技术在处理交易时即确保了交易记录的不可篡改性和对交易结果的有效确认,有望节约清结算的人力和时间成本,降低机构间的争议,提高自动化处理效率。 + +#### SWIFT 完成跨银行的分布式账本验证 + +2018 年 3 月,环球同业银行金融电讯协会(SWIFT)完成了涉及到 34 家银行的分布式账本验证。验证重点关注基于超级账本项目的分布式账本技术能否满足监管、安全、隐私性等方面的需求。验证表明分布式账本技术可以满足自动化的资产管理需求,为未来多银行间合作提供重要支撑。 + +SWIFT 研发中心负责人 Damien Vanderveken 称:“验证进行得相当好,证实了分布式账本技术的巨大进展,尤其是超级账本 Fabric 项目 1.0(The PoC went extremely well, proving the fantastic progress that has been made with DLT and the Hyperledger Fabric 1.0 in particular)”。 + +#### IBM 构建全球支付网络 + +TODO: https://www.coindesk.com/ibm-signs-6-banks-to-issue-stablecoins-and-use-stellars-xlm-cryptocurrency + +2018 年 8 月,IBM 推出了基于区块链的全球支付解决方案 —— WorldWire,该网络使用 Stellar 协议,可以实现在数秒钟之内完成跨境支付的清结算。 + +IBM 认为该新型支付解决方案可以很好的接入已有的支付系统,并且有能力支持包括法币、数字资产、稳定币等资产的支付,所有交易存储在账本上,可以持久保留。 + +目前,该支付网络上已经实现了与美元挂钩的稳定币,IBM 正在与多家国际银行(巴西布拉德斯科银行、釜山银行等)合作,计划增加更多类型的稳定币支持。 + +#### 巴克莱银行用区块链进行国际贸易结算 + +在国际贸易活动中,买卖双方可能互不信任。因此需要银行作为买卖双方的保证人,代为收款交单,并以银行信用代替商业信用。 + +区块链可以为信用证交易参与方提供共同账本,允许银行和其它参与方拥有经过确认的共同交易记录并据此履约,从而降低风险和成本。 + +2016 年 9 月,英国巴克莱银行用区块链技术完成了一笔国际贸易的结算,贸易金额 10 万美元,出口商品是爱尔兰农场出产的芝士和黄油,进口商是位于离岸群岛塞舌尔的一家贸易商。结算用时不到 4 小时,而传统采用信用证方式做此类结算需要 7 到 10 天。 + +在这笔贸易背后,区块链提供了记账和交易处理系统,替代了传统信用证结算过程中占用大量人力和时间的审单、制单、电报或邮寄等流程。 + +#### 中国邮储银行在核心业务系统中使用区块链 + +2016 年 10 月,中国邮储银行宣布携手 IBM 推出基于区块链技术的资产托管系统,是中国银行业首次将区块链技术成功应用于核心业务系统。 + +新的业务系统免去了重复的信用校验过程,将原有业务环节缩短了约 60-80% 的时间,提高了信用交易的效率。 + +#### 多家银行合作推出信用证区块链 + +2017 年 7 月,民生银行、中信银行、中国银行和苏宁银行基于超级账本技术推出了首家基于区块链的信用证业务平台。该业务上线当日交易额即达到了 1 亿人民币,目前,每天交易额在十亿量级。该系统与传统的信用证结算不同,没有使用 SWIFT 代码,而是使用独创的信用证交换系统。 + +基于区块链技术,不仅大幅降低了成本,还提高了交易效率和安全性。当然,如何与已有的基于 SWIFT 系统的国际业务打通,将是该平台面临的挑战之一。 + +#### 蚂蚁金服推出区块链跨境汇款服务 + +2018 年 6 月 25 日,蚂蚁金服宣布其基于区块链的电子钱包跨境汇款服务在香港上线。该系统实现香港金管局、新加坡金管局、港版支付宝(Alipay HK)、渣打银行、菲律宾钱包 GCash 间的跨机构协同,Alipay HK 用户可基于区块链技术向 Gcash 汇款,汇款时间为 3~6 秒。 + +#### 摩根大通用区块链进行机构间实时支付 + +2019 年 2 月,摩根大通宣布推出基于区块链的数字货币”JPM Coin“,以实现客户之间的实时结算。据悉,每个 JPM Coin 暂时等价 1 美元。摩根大通的机构客户向指定账户存款后可获得等值的 JPM Coin。 + +通过区块链,机构之间可以以 JPM Coin 为价值载体进行实时交易。持有 JPM Coin 的机构客户可在摩根大通实时赎回美元。这意味着这家美国最大的金融服务机构已经开始主动拥抱区块链科技带来的新变化。 + +目前,JPM Coin 仅限大型机构客户使用,并将持续与监管部门合作。 + +#### 其它新型支付业务 +基于区块链技术,出现了大量的创新支付企业,这些支付企业展示了利用区块链技术带来的巨大商业优势。 + +* Abra:区块链数字钱包,以近乎实时的速度进行跨境支付,无需银行账户,实现不同币种的兑换,融资超过千万美金。 +* Bitfinex:组建 Tether Limited 公司来发行稳定币 USDT,作为最流行的稳定币,市值超过 10 亿美金。稳定币通过绑定代币到法定货币以保障价格的稳定性。如果抵押过程公开并支持审计,则可以降低用户因为代币价格波动带来的风险。 +* Bitwage:基于比特币区块链的跨境工资支付平台,可以实现每小时的工资支付,方便跨国企业进行外包工资管理。 +* BitPOS:澳大利亚创业企业,提供基于比特币的低成本的快捷线上支付,适用于餐饮行业。 +* Circle:由区块链充当支付网络,允许用户进行跨币种、跨境的快速汇款。Circle 获得了来自 IDG、百度的超过 6000 万美金的 D 轮投资。2018 年 9 月,Circle 推出了稳定币 USDC,上市 2 个月,USDC 的市值已达到 2 亿美元。 +* Ripple:实现跨境的多币种、低成本、实时交易,引入了网关概念(类似银行),结构偏中心化,可以与银行等金融机构合作完成跨境支付。 + +### 证券交易后处理 +证券交易包括交易执行环节和交易后处理环节。 + +交易环节本身相对简单,主要是由交易系统(高性能实时处理系统)完成电子数据库中内容的变更。中心化的验证系统往往极为复杂和昂贵。交易指令执行后的清算(计算交易方的财务义务)和结算(最终资产的转移)环节也十分复杂,需要大量的人力成本和时间成本,并且容易出错。 + +目前来看,基于区块链的处理系统还难以实现海量交易系统所需要的性能(典型性能为每秒数万笔以上成交,日处理能力超过五千万笔委托、三千万笔成交)。但在交易的审核和清算环节,区块链技术存在诸多的优势,可以极大降低处理时间,同时减少人工的参与。 + +2016 年 2 月,咨询公司 Oliver Wyman 在给 SWIFT(环球同业银行金融电讯协会)提供的研究报告《Blockchain in Capital Markets -- The Prize and the Journey》中预计,全球清算行为成本约 50~100 亿美元,结算成本、托管成本和担保物管理成本 400~450 亿美元(390 亿美元为托管链的市场主体成本),而交易后流程数据及分析花费 200~250 亿美元。 + +2016 年 4 月,欧洲央行在报告《Distributed ledger technologies in securities post-trading》中指出,区块链作为分布式账本技术,可以很好地节约对账的成本,同时简化交易过程。相对原先的交易过程,可以近乎实时的变更证券的所有权。 + +2015 年 10 月,美国纳斯达克(Nasdaq)证券交易所推出区块链平台 Nasdaq Linq,实现主要面向一级市场的股票交易流程。通过该平台进行股票发行的发行者将享有“数字化”的所有权。 + +其它证券相关案例还包括: + +* BitShare 推出基于区块链的证券发行平台,号称每秒达到 10 万笔交易。 +* DAH 为金融市场交易提供基于区块链的交易系统。获得澳洲证交所项目。 +* Symbiont 帮助金融企业创建存储于区块链的智能债券,当条件符合时,清算立即执行。 +* Overstock.com 推出基于区块链的私有和公开股权交易“T0”平台,提出“交易即结算”(The trade is the settlement)的理念,主要目标是建立证券交易实时清算结算的全新系统。 +* 高盛为一种叫做“SETLcoin”的数字货币申请专利,用于为股票和债券等资产交易提供“近乎立即执行和结算”的服务。 + +### 供应链金融 + +供应链金融是一种重要的融资模式。传统上一般由银行基于真实贸易,以核心企业信用为担保来连接上下游企业。供应链金融可为供应链上的企业提供自偿性融资,有助于缓解小微企业融资难的问题,增强供应链活力。 + +该领域长期以来一直存在众多问题: + +* 弱势成员企业供货应收账款周期长,面临较大的资金压力,但融资难。银行从风控角度考虑,愿意为核心企业上游直接供应商提供保理服务,为直接下游经销商提供融资,但不愿意给其它企业(通常往往规模较小,缺乏足够抵押)授信。而核心企业和直接上下游企业往往不愿意承担风险,导致整个链条缺乏活力; +* 供应链上下游企业关系密切,风险往往息息相关。来自上下游的不确定性(特别是核心企业)增大了整个供应链企业的整体风险。 +* 由于供应链往往涉及到数十家甚至数百家企业,供货生命周期很长,涉及生产制造、运输、担保等多种环节,信息隐瞒或票据篡改造假的情况很难避免。银行要获取多家企业真实贸易信息的难度很大,造成实际融资成本高居不下。 +* 作为主要融资工具的票据(包括商业汇票、银行汇票)使用场景局限,票据实际可兑换情况和价值依赖背书企业的信誉和实力,实际操作难度大。 + +供应链金融的业务特点,使得其十分契合区块链的技术特点。区块链上数据都带有签名和时间戳,提供高度可靠的历史记录,可以有效降低银行对信息可靠性的疑虑,实现核心企业信用在链上的分割与流转。最终提高整个供应链的金融效率。 + +目前,供应链金融区块链平台主要以联盟链的形式打造,具有如下业务优势: + +* 时间戳设计保证债权拆分、流转后信用不变,整体流程完整可追溯; +* 分布式数据存储打破信息不对称,防止信息篡改和造假; +* 智能合约自动执行,减少人工干预,提高资金流通效率。 + +为使供应链金融迅速且有序发展,我国也推出一系列指导意见。如 2017 年七部门联合印发的《小微企业应收账款融资专项行动工作方案(2017-2019年)》提到:“推动供应链核心企业支持小微企业应收账款融资,引导金融机构和其他融资服务机构扩大应收账款融资业务规模”;此外,2017 年国务院办公厅《关于积极推进供应链创新与应用的指导意见》也指出:“积极稳妥发展供应链金融”。这些在政策层面上的指导建议,促进了国内供应链金融的发展速度与态势。 + +2017 年 3 月,深圳区块链金融服务有限公司基于区块链技术与全国范围内多家银行建立联盟,共同推出“票链”产品,通过创新模式为持有银行承兑汇票的中小微企业提供高效便捷的票据融资服务。“票链”产品发布后,在江西地区率先进行试点运营,上线首月交易规模已近亿元人民币。其中绝大部分交易标的为数十万元的小额银行承兑汇票,切实解决了中小微企业客户长期面对的融资难、融资贵难题。 + +2017 年 4 月,易见科技供应链金融平台上线运营,2018 年 9 月发布 2.0 版本;自上线以来,已帮助近200家企业及金融机构完成了超过 40 亿元的供应链金融业务,线上融资合同近 500 份,涉及医药、化工、制造、大宗、物流、航空和地产等多个行业。易见区块平台基于超级账本技术,产品体系包括供应链贸易系统、供应链融资平台和供应链资产证券化平台。 + +2018 年 4 月 13 日,平安集团金融壹帐通在深圳推出国内首个连接金融机构和中小企业的“壹企银中小企业智能金融服务平台”,将助力银行等金融机构解决中小企业融资难题。壹企银广泛应用金融科技最新技术,全程实现银行等金融机构信贷业务流程智能化,点对点实时打通中小企业信息“死结”,从而实现中小企业融资快捷、高效和低成本、低风险。 + +“Chained Finance”区块链金融平台是由国内互联网金融公司点融和富士康旗下金融平台富金通共同推出的供应链金融平台,在业内首次借助区块链技术破解供应链金融和中小企业融资难题。 + +另外,类似“一带一路”这样创新的投资建设模式,会碰到来自地域、货币、物流等各方面的挑战。现在已经有一些部门对区块链技术进行探索应用。区块链技术可以让原先无法交易的双方(例如,不存在多方都认可的国际货币储备的情况下)顺利完成交易,并且降低贸易风险、减少流程管控的成本。 + +### 税收服务 + +传统的税收服务体系在税务信用等级、税收遵从、税源监控等领域存在数据孤岛、信息壁垒等难题,这也导致税务管理中存在大量增值税发票虚开虚抵、农产品优惠政策骗税、出口骗税、稽查取证等争议。 + +基于区块链的分布式账本可记录跨地域、跨企业的电子票信息,打破数据壁垒。例如,通过融入密码学算法及数据可信上链服务,在保护纳税人数据的同时,实现以税票为中心的发生过程监控。将纳税规则写入智能合约,系统根据往来业务和数据实现交易与开票数据的自动匹配、核对、缴纳,避免虚开错开,实现税源的全面监控。而区块链透明、弱中心化的特点可为建立税务、工商、海关、银行等部门横向信息的全面掌握分析机制奠定基础,提升征税效率与准确性。 + +2018 年 8 月 10 日,由深圳市税务局主导、腾讯提供底层技术支持,深圳国贸旋转餐厅开出了国内"首张"区块链电子发票。通过在微信中整合支付、开票、报销等功能,该成果致力于实现“交易即开票,开票即报销”。以区块链作为底层支撑技术,接入税务局、微信支付、财务软件商、商家等相关方,可确保发票唯一,并且领票、开票、流转、入账、报销等流程信息完整可追溯,解决传统系统“一票多报、虚报虚抵”等难题,降低经营成本和税收风险。 + +### 众筹管理 + +区块链自身带来的多方信任合作机制,有望提高众筹的效率和安全性。该领域的尝试目前主要是“首次代币发行(Initial Coin Offering,ICO)”形式。 + +ICO 设计思想十分简单。项目发起方通过售卖项目早期的数字资产(代币)向外界融资,投资者可以直接以比特币等形式参与。当项目上线后,如果能得以健康成长,项目代币价格上涨,投资者可以获得回报,并且可以选择任何时候卖出这些代币而无条件退出。 + +最早的 ICO 出现在 2013 年 6 月,万事达币(MSC)在 Bitcointalk 论坛上众筹 5000 个比特币。虽然,很可惜该项目后来并没有成功,但开启了 ICO 的浪潮。 + +2014 年,比较出名的如比特股 Bitshares 和以太坊 Ethereum 先后发起 ICO,并且随着平台自身的发展,投资者获取了大量的回报。这些早期项目支持了区块链领域的初创企业,同时探索了新的众筹模式。 + +2016 年 4 月 30 日上线的 DAO(Decentralized Autonomous Organization)项目,试图打造基于以太坊的众筹平台,更是一度创下历史最高的融资记录,数额超过 1.6 亿美金。该项目暴露出这种创新形式的组织者们在应对安全风险时候缺乏足够的应对经验。6 月 12 日,有技术人员报告合约执行过程中存在软件漏洞,但很遗憾并未得到组织的重视和及时修复。四天后,黑客利用漏洞转移了 360 万枚以太币,当时价值超过 5000 万美金。虽然最后采用了一些技术手段来挽回经济损失,但该事件毫无疑问给以太坊平台带来了负面影响,也给 ICO 这种新模式的流程管理敲响了警钟。 + +2017 年开始,传统风投基金也开始尝试用 ICO 来募集资金。Blockchain Capital 在 2017 年发行的一支基金创新地采用了传统方式加 ICO 的混合方式进行募资,其中传统部分规模 4000 万美元,ICO 部分规模 1000 万美元。4 月 10 日,ICO 部分 1000 万美元的募集目标在启动后六小时内全部完成。整个 2017 年全球超过 1000 个 ICO 项目,总募资额超过 40 亿美金。 + +Telegram 在 2018 年初通过两轮 ICO 共募集资金 17 亿美金,值得注意的是,在第二轮时已经明确限制最低投资门槛为 100 万美元。 + +由于市场过于火爆,投资者投机心理加重,同时出现了大量欺诈性的项目。这些项目的白皮书粗制滥造,有的项目甚至连白皮书都没有,被戏称为“空气项目”。2017 年下半年开始,大量不成熟项目因为无法完成预设目标而破灭,这被认为是第一次 ICO 泡沫的结束,同时市场在泡沫后变得更加成熟和理性。 + +同期,各国开始加强监管,要么将其纳入已有监管体系,要么暂时禁止 ICO 活动。2017 年 8 月 28 日,美国证监会发布关于谨防 ICO 骗局的警告,后将 ICO 纳入证券监管;此外,澳大利亚、加拿大、印度、菲律宾以及欧洲主要国家也将 ICO 纳入监管。同年 9 月 4 日,中国人民银行等 7 部门发文,称 ICO 为“未经批准非法公开融资的行为”,各类代币发行融资活动应立即停止。这些措施提高了项目发行的门槛,客观上促进了整个生态系统的进化。全球范围内 ICO 项目发行的频率明显下降,但优质项目比例明显提高。 + +客观来看,作为一种创新的模式,ICO 众筹方式相对 IPO 更加灵活,适合早期中小资金额的创业项目。但目前 ICO 项目仍属于法律监管的灰色地带,往往存在如下问题: + +* 缺少法律支持和监管机制。作为一种新型融资行为,由于缺乏相关法规,监管流程很难执行。出现问题后投资者无法得到合理赔偿; +* 项目的评估难度很大。进行 ICO 的项目往往是科技和创新含量较高的产品,无论是审查机构还是普通投资者都很难进行准确评估; + +我国《证券法》第二章第 10 条明确规定:“公开发行证券,必须符合法律、行政法规规定的条件,并依法报经国务院证券监督管理机构或者国务院授权的部门核准;未经依法核准,任何单位和个人不得公开发行证券”。这可以保障投资者的长期权益,有利于建设健康的交易环境。因此,为了解决 ICO 的现有缺陷,应当参考 IPO 等证券管理办法制定监管框架。具体可从三个方面进行完善: + +* 从项目方角度需要通过行业共识建立规范的准入机制。如要求必要信息的公开和接受第三方的监督审查,同时设定融资额度限制。通过这些机制可以避免欺诈,保护市场投资者; +* 从投资者角度在一定时间内应当提高入场门槛。如募集资金超过一定额度的项目只能接受来自专业投资机构的投资。同时加强投资者教育和风险告知; +* 最后,法律界需要和科技界开展合作,尽早主动出台相关监管法规,将这一新型募资方式纳入到正式监管之下,并建立完整的市场机制。 + +### 去中心化交易所 + +不同数字资产之间如果要进行兑换,需要经过交易所等中介渠道。 + +传统交易所是中心化模式,即交易双方通过第三方提供的交易平台按照汇率进行交换,交易平台方往往需要从交易中收取手续费用。这种模式下不仅成本高,而且存在对交易平台依赖过高的风险。 + +为了解决这些问题,去中心化交易所(Decentralized Exchange,DEX)被设计出来。其初步想法是通过基于区块链的协议,让交易双方可以直接进行点对点的兑换。由于无需交易平台方参与,交易成本较低,而且可以实时完成,也不用担心安全风险。目前,去中心化交易所是去中心化金融领域最热门的课题之一。 + +要实现去中心化交易所,需要解决一些基本问题: + +* 交易能自动完成,无需人工参与; +* 交易过程中无人能造假或欺骗对方; +* 自动计算汇率,并根据汇率来完成交易; +* 避免市场发生过大波动,带来损失。 + +目前,去中心化交易所根据其订单位置,主要包括三种模式:链上记账、链下记账和自动做市商(Automated Market Makers,AMM)。 + +#### 链上记账 + +链上记账的思路十分简单,将兑换交易直接存储在区块链上。 + +该模式实现简单,但是存在较大缺陷。 + +* 每笔交易都需要上链,会产生记账费用。当交易频繁时,记账成本过高; +* 需要将所有信息记录在链上,可能会产生有人提前知晓交易信息而获益; +* 交易较多时,对区块链的性能要求很高,大部分公有链都无法支持。 + +采用该方案的平台包括 Stellar 等。 + +#### 链下记账 + +与链上记账相反,链下记账将交易存放在第三方平台上。第三方平台仅当需要时候才将交易写入区块链。 + +这种方式可以避免写入大量交易到区块链,但是需要依赖第三方平台,存在较高的安全风险。 + +采用该方案的平台包括 Binance 等。 + +#### 自动做市商 + +类似证券市场中的做市商,可以使用智能合约来实现自动化的做市商机制。 + +用户需要兑换货币时,不跟其他用户直接进行交易,而是和区块链智能合约进行兑换。 + +智能合约背后根据其流动资金池和定价算法(如倒数曲线、直线等)实时算出汇率。每笔交易会收取少量的手续费(如 Uniswap 收取 0.3%)。 + +该机制无需依赖交易记账,交易成本通常较低,且风险小。 + +用户也可以将持有的货币按照协议投入流动资金池中,成为流动性提供者(Liquidity Provider,LP)。流动性提供者可以获得交易手续费带来的收益。 + +该模式主要的问题是市场深度依赖流动资金池,要平衡好 LP 收益和交易成本之间的矛盾。同时,当货币价格波动较大时,LP 可能产生暂时性损失(Impermanent Loss)。 + +典型的实现协议包括 Uniswap、Bancor 等,平台包括 Kyber 等。 \ No newline at end of file diff --git a/chainbrock-learning/03_scenario/glance.md b/chainbrock-learning/03_scenario/glance.md new file mode 100644 index 00000000..f1563a42 --- /dev/null +++ b/chainbrock-learning/03_scenario/glance.md @@ -0,0 +1,27 @@ +## 应用场景概览 + +区块链技术已经从单纯的技术探讨走向了应用落地的阶段。国内外已经出现大量与之相关的企业和团队。有些企业已经结合自身业务摸索出了颇具特色的应用场景,更多的企业还处于不断探索和验证的阶段。 + +实际上,要找到合适的应用场景,还是要从区块链技术自身的特性出发进行分析。 + +区块链在不引入第三方中介机构的前提下,可以提供去中心化、不可篡改、安全可靠等特性保证。因此,所有直接或间接依赖于第三方担保机构的活动,均可能从区块链技术中获益。 + +区块链自身维护着一个按时间顺序持续增长、不可篡改的数据记录,当现实或数字世界中的资产可以生成数字摘要时,区块链便成为确权类应用的完美载体,提供包含所属权和时间戳的数字证据。 + +可编程的智能合约使得在区块链上登记的资产可以获得在现实世界中难以提供的流动性,并能够保证合约规则的透明和不可篡改。这就为区块链上诞生更多创新的经济活动提供了土壤,为社会资源价值提供更加高效且安全的流动渠道。 + +此外,还需要思考区块链解决方案的合理边界。面向大众消费者的区块链应用需要做到公开、透明、可审计,既可以部署在无边界的公有链,也可以部署在应用生态内多中心节点共同维护的区块链;面向企业内部或多个企业间的商业区块链场景,则可将区块链的维护节点和可见性限制在联盟内部,并用智能合约重点解决联盟成员间信任或信息不对等问题,以提高经济活动效率。 + +笔者认为,未来几年内,可能深入应用区块链技术的场景将包括: + +* 金融服务:区块链带来的潜在优势包括降低交易成本、减少跨组织交易风险等。该领域的区块链应用目前最受关注,全球不少银行和金融交易机构都是主力推动者。部分投资机构也在应用区块链技术降低管理成本和管控风险。从另一方面,要注意可能引发的问题和风险。例如,DAO(Decentralized Autonomous Organization 是史上最大的一次众筹活动,基于区块链技术确保资金的管理和投放)这样的众筹实验,提醒应用者在业务和运营层面都要谨慎处理。 +* 征信和权属管理:征信和权属的数字化管理是大型社交平台和保险公司都梦寐以求的。目前该领域的主要技术问题包括缺乏足够的数据和分析能力;缺乏可靠的平台支持以及有效的数据整合管理等。区块链被认为可以促进数据交易和流动,提供安全可靠的支持。征信行业的门槛比较高,需要多方资源共同推动。 +* 资源共享:以 Airbnb 为代表的分享经济公司将欢迎去中心化应用,可以降低管理成本。该领域主题相对集中,设计空间大,受到大量的投资关注。 +* 贸易管理:区块链技术可以帮助自动化国际贸易和物流供应链领域中繁琐的手续和流程。基于区块链设计的贸易管理方案会为参与的多方企业带来极大的便利。另外,贸易中销售和法律合同的数字化、货物监控与检测、实时支付等方向都可能成为创业公司的突破口。 +* 物联网:物联网也是很适合应用区块链技术的一个领域,预计未来几年内会有大量应用出现,特别是租赁、物流等特定场景,都是很合适结合区块链技术的场景。但目前阶段,物联网自身的技术局限将造成短期内不会出现大规模应用。 + +这些行业各有不同的特点,但或多或少都需要第三方担保机构的参与,因此都可能从区块链技术中获得益处。 + +当然,对于商业系统来说,技术支持只是一种手段,根本上需要满足业务需求。区块链作为一个底层的平台技术,要利用好它,需要根据行业特性进行综合考量设计,对其上的业务系统和商业体系提供合理的支持。 + +有理由相信,区块链技术落地的案例会越来越多。这也会进一步促进新技术在传统行业中的应用,带来更多的创新业务和场景。 \ No newline at end of file diff --git a/chainbrock-learning/03_scenario/iot.md b/chainbrock-learning/03_scenario/iot.md new file mode 100644 index 00000000..2aa98dd8 --- /dev/null +++ b/chainbrock-learning/03_scenario/iot.md @@ -0,0 +1,33 @@ +## 物联网 +曾有人认为,物联网是大数据时代的基础。 + +笔者认为,区块链技术是物联网时代的基础。 + +### 典型应用场景分析 +一种可能的应用场景为:物联网络中每一个设备分配地址,给该地址所关联一个账户,用户通过向账户中支付费用可以租借设备,以执行相关动作,从而达到租借物联网的应用。 + +典型的应用包括对大量分散监测点的数据获取、温度检测服务、服务器租赁、网络摄像头数据调用等等。 + +另外,随着物联网设备的增多、边沿计算需求的增强,大量设备之间形成分布式自组织的管理模式,并且对容错性要求很高。区块链自身分布式和抗攻击的特点可以很好地融合到这一场景中。 + +### IBM +IBM 在物联网领域已经持续投入了几十年的研发,目前正在探索使用区块链技术来降低物联网应用的成本。 + +2015 年初,IBM 与三星宣布合作研发“去中心化的 P2P 自动遥测系统(Autonomous Decentralized Peer-to-Peer Telemetry)”系统,使用区块链作为物联网设备的共享账本,打造去中心化的物联网。 + +2017 年,IBM 和哥伦比亚物流解决方案供应商 AOS 合作,共同为物流行业开发新的区块链和物联网解决方案。方案通过物联网传感器采集货车可用空间、负载信息、天气温度等信息,并将货物、货主、司机、物流行为等信息上链,实现对货物状态和相关方行为的完整追溯。 + +### Filament +美国的 Filament 公司以区块链为基础提出了一套去中心化的物联网软件堆栈。通过创建一个智能设备目录,Filament 的物联网设备可以进行安全沟通、执行智能合约以及发送小额交易。 + +基于上述技术,Filament 能够通过远程无线网络将辽阔范围内的工业基础设备沟通起来,其应用包括追踪自动售货机的存货和机器状态、检测铁轨的损耗、基于安全帽或救生衣的应急情况监测等。 + +### NeuroMesh +2017 年 2 月,源自 MIT 的 NeuroMesh 物联网安全平台获得了 MIT 100K Accelerate 竞赛的亚军。该平台致力于成为“物联网疫苗”,能够检测和消除物联网中的有害程序,并将攻击源打入黑名单。 + +所有运行 NeuroMesh 软件的物联网设备都通过访问区块链账本来识别其他节点和辨认潜在威胁。如果一个设备借助深度学习功能检测出可能的威胁,可通过发起投票的形式告知全网,由网络进一步对该威胁进行检测并做出处理。 + +### 公共网络服务 +现有的互联网能正常运行,离不开很多近乎免费的网络服务,例如域名服务(DNS)。任何人都可以免费查询到域名,没有 DNS,现在的各种网站将无法访问。因此,对于网络系统来说,类似的基础服务必须要能做到安全可靠,并且低成本。 + +区块链技术恰好具备这些特点,基于区块链打造的分布式 DNS 系统,将减少错误的记录和查询,并且可以更加稳定可靠地提供服务。 diff --git a/chainbrock-learning/03_scenario/logistics.md b/chainbrock-learning/03_scenario/logistics.md new file mode 100644 index 00000000..6ffd0b32 --- /dev/null +++ b/chainbrock-learning/03_scenario/logistics.md @@ -0,0 +1,28 @@ +## 物流与供应链 + +物流与供应链行业被认为是区块链一个很有前景的应用方向。Gartner 一项调查显示,接近 60% 的物流相关企业计划考虑使用分布式账本技术。 + +该行业往往涉及到诸多实体,包括物流、资金流、信息流等,这些实体之间存在大量复杂的协作和沟通。传统模式下,不同实体各自保存各自的供应链信息,严重缺乏透明度,造成了较高的时间成本和金钱成本,而且一旦出现问题(冒领、货物假冒等),难以追查和处理。 + +通过区块链,各方可以获得一个透明可靠的统一信息平台,可以实时查看状态,降低物流成本,追溯物品的生产和运送全过程,从而提高供应链管理的效率。当发生纠纷时,举证和追查也变得更加清晰和容易。 + +例如,运送方通过扫描二维码来证明货物到达指定区域,并自动收取提前约定的费用;冷链运输过程中通过温度传感器实时检测货物的温度信息并记录在链等。 + +来自美国加州的 Skuchain 公司创建基于区块链的新型供应链解决方案,实现商品流与资金流的同步,同时缓解假货问题。 + +### 马士基推出基于区块链的跨境供应链解决方案 + +2017 年 3 月,马士基和 IBM 宣布,计划与由货运公司、货运代理商、海运承运商、港口和海关当局构成的物流网络合作,构建一个新型全球贸易数字化解决方案 TradeLens。该方案利用区块链技术在各方之间实现信息透明性,降低贸易成本和复杂性,旨在帮助企业减少欺诈和错误,缩短产品在运输和海运过程中所花的时间,改善库存管理,最终减少浪费并降低成本。 + +马士基在 2014 年发现,仅仅是将冷冻货物从东非运到欧洲,就需要经过近 30 个人员和组织进行超过 200 次的沟通和交流,大量文书工作可以替换为无法篡改的数字记录,类似问题都有望借助区块链进行解决。 + +基于区块链的供应链方案,预计每年可为全球航运业节省数十亿美元。 + +### 国际物流区块链联盟 + +2017 年 8 月,国际物流区块链联盟(Blockchain In Transport Alliance,BiTA)正式成立。 + +该联盟目标为利用分布式账本技术来提高物流和货运效率,并探索新的行业标准。 + +目前,联盟已经发展为超过 25 个国家,500 多家会员企业,包括联合包裹(UPS)、联邦快递(FedEx)、施耐德卡车运输公司(Schneider Trucking)、SAP 等。 + diff --git a/chainbrock-learning/03_scenario/nft.md b/chainbrock-learning/03_scenario/nft.md new file mode 100644 index 00000000..1698bf80 --- /dev/null +++ b/chainbrock-learning/03_scenario/nft.md @@ -0,0 +1,83 @@ +## 数字艺术品和 NFT + +过去几年里,数字艺术品探索了采用 NFT(非同质化代币,Non Fungible Token)这一新的数字媒介形式进行资产交易的可能性。 + +未来大量的物品交易,都可以通过 NFT 形式进行。另外,NFT 可以将资产所有权进行数字化,方便更充分地实现价值。 + +NFT 的出现,代表了交易者从基于纸质合约转变为基于数字合约交易的迫切需求。 + +### 数字艺术品 + +数字艺术品是指利用计算机技术生成的具备某种艺术价值的一组数据。类似于传统的物理创作的艺术品,数字艺术品被认为具备唯一性和收藏价值。由于数字艺术品的交易多通过加密货币进行,因此也被称为密码艺术品(CryptoArt)。 + +早在 1993 年,Hal Finney(也是比特币早期专家)就在密码论坛 Cypherpunks 上讨论了关于“加密交易卡”的想法,这可能是最早的关于密码艺术品和 NFT 的讨论。 + +数字艺术品主要包括如下特点: + +* 基于区块链平台,生成规则一旦确定,艺术品无法增发或修改,也无法造假; +* 多使用加密货币交易,所有记录公开可见,可以有效追溯; +* 用户购买后所有权被记录在分布式账本上,无法被篡改或造假; +* 艺术品交易都是直接立刻完成,不存在传统的第三方; +* 数字艺术品自身并不稀缺,甚至很容易被复制,但是其所有权唯一,并且得到市场的认可。 + + +2014 年,Robby Dermody、Adam Krellenstein、Ouziel Slama 等基于比特币网络上线了 Counterparty 交易平台。该平台通过元数据代币协议提供点对点金融交易,支持创建代币、去中心化资产交易等。2016 年 9 月,上线了“稀有的 Pepe 蛙(Rare Pepe)”项目,成为早期的数字艺术品。 + +2017 年 6 月 23 日,Larva Labs 上线了 CryptoPunks 项目。该项目创建了 10000 个朋克头像,每个头像都是独一无二的 24x24 的 8 位像素图。最初,该项目在以太网络上免费发行,希望纪念朋克精神。后来随着爱好者们的宣传和参与,项目吸引了大量用户甚至投资机构的关注,至今仍然十分活跃,单个售价往往在数万美金。2021 年 6 月,编号 7523 的头像售价达到了 1180 万美金。CryptoPunks 作为收藏品具有独特的文化趣味,被认为是后来加密数字艺术品潮流的开端。此后,Larva Labs 还开发了 Autoglyphs 和 Meebits 项目,也都引起了市场的追捧。 + +2017 年 11 月 28 日,Axiom Zen 团队(后孵化了 Dapper Labs 公司)推出基于以太币交易的 CryptoKitties 游戏。每个玩家可以通过以太币来购买一只数字猫咪,繁殖后代,并且可以出售。所有的记录都在以太网络上公开可见。通过该游戏,玩家可以学习掌握以太币的基本使用方法。该游戏一度十分火爆,单只数字猫咪售价曾超过 10 万美元,相关交易占据以太网络近 2 成的交易流量,造成了交易延迟和堵塞。游戏的成功,也启发了众多的模仿者。项目遵循的 ERC-721 标准得到广泛采用。 + +2021 年 4 月,Yuga Labs 在以太坊网络上推出了 Bored Ape Yacht Club 项目,该项目包括 10000 个不相同的猿猴画像,由计算机生成。其中编号 8817 的画像,曾被拍卖出 340 万美金的高价。 + + +### NFT + +虽然目前很多 NFT 都是数字艺术品,但是 NFT 的 内涵实际上要更为广泛。任何可以在数字世界流通的东西,都可以认为是 NFT。包括画作、摄影、音乐、书籍、游戏等。 + +NFT 的字面意思是非同质化代币。传统的加密数字货币是同质(Fungible Token)的,任意两枚之间并无差别,可以相互替换,并且往往可以拆分为更小的单位,例如比特币。而 NFT 则是唯一的,不能被其它 NFT 替换,并且往往不能分割为更小的单位。例如一个画作 NFT,代表该画作自身,并不能被其它的 NFT 所替代。 + +目前 NFT 产品往往具有如下特点: + +* 不可相互替换; +* 不可拆分为更小单位; +* 往往唯一存在。 + +NFT 的非同质化的特点,使得其可以容易锚定到物理世界中的物品上,例如房产、汽车、收藏品等。任何现实物品的产权都可以绑定到一个 NFT 上。因此,NFT 被认为具备巨大的潜力。 + +2020 年,随着全球范围内主权货币的大量增发,NFT 开始受到越来越多的追捧。2021 年,NFT 项目更是迎来了大爆发,因此 2021 年也被不少人称为“NFT 元年”。目前,大部分的 NFT 都通过 Opensea、Rarible、Nifty Gateway 等平台交易,并依托以太网络和 IPFS 进行存储。 + +NFT 想法的出现十分自然,其最早的原型,可以追溯到 2012 年出现的基于比特币的彩色币(ColoredCoin)。彩色币带有颜色属性,可以用颜色来代表不同的资产。这为现实资产上链提供了可行性。 + +但比特币网络不支持智能合约,限制了其表达能力。2015 年 7 月上线的以太坊网络,加强了对智能合约的支持,使得 NFT 的大量出现成为现实。特别是 2017 年 9 月,ERC-721 规范正式被提出,成为大量基于以太坊项目实现的 NFT 的参考标准。这一年里加密猫项目上线,非同质化代币这一概念也被正式确立。2018 年,以太坊社区还提出了支持批量交易的 ERC-1155 标准,目前已经被交易市场 Rarible 支持。 + +Sky Mavis于 2018 年开发了游戏 Axie Infinity,后来成为以太坊网络上的热门游戏之一。它支持通过 NFT 方式让玩家交易其中的虚拟宠物和土地资源,同时,玩家可以通过玩游戏来获取积分并兑换。部分虚拟宠物价格高达 300 个以太币(约一百万美金)。 + +2020 年 10 月,Dapper Labs 公司与 NBA 合作,推出了 NBA Top Shot 游戏项目。它将某位球员在比赛中的精彩视频片段上传到 Dapper Labs 研发的公链 Flow 上,制作为 NFT 产品。NBA Top Shot 项目上线后,吸引了大量用户的参与。总成交额已经超过 2 亿美金,部分产品如球员 LeBron James 的灌篮视频的 NFT 价格一度飙升到 40 万美金。 + +此外,大英博物馆、俄罗斯冬宫博物馆等也对世界名画的 NFT 产品进行了拍卖。 + +2021 年 2 月,林肯公园(Linkin Park)乐队成员 Mike Shinoda 在平台 Zora 上发行了一款 NFT 音乐作品,售价高达 40 万美元。 + +2021 年 2 月,数字艺术家 Mike Winkelmann(又名 Beeple)自 2007 年 5 月起耗时十三年半创作的 5000 副数字画作 “Everydays – The First 5000 Days”,拼接为一个 316 MB 大小的图片 NFT,以历史性价格 6934 万美元(42329 个以太币)在佳士得(Christie's)售出,购买者为加密货币投资人 Vignesh Sundaresan。 + +2021 年 4 月,Centrifuge 公司使用房屋作为抵押,成功获取了一笔 MakerDAO 贷款。 + +2021 年 12 月,代号 Pak 的数字艺术家将包括 312686 个数字画作集 “The Merge”,在数字艺术品拍卖平台 NiftyGateway 售出,28983 位买家参与购买,成交总价为 9180 万美元。这也是目前售价最高的 NFT 作品。 + + +### NFT 的优势 + +使用 NFT 来达成交易包括如下优势: + +* 即时交易:买卖双方从平台达成交易并写入区块链后,NFT 所有权即得到转移,交易记录保存在分布式账本上,无法被篡改; +* 不易作假:一旦 NFT 产品被确认后,其交易历史会被完整记录,其他人很难伪造; +* 提高效率:基于 NFT 的交易,都是通过智能合约进行自动化处理,处理效率远高于人工操作; +* 降低成本:NFT 平台的手续费通常远低于现实交易的中介费,降低交易成本也可促进市场的繁荣。 + +### NFT 的问题 + +NFT 的快速发展,也导致一些问题的出现: + +* NFT 的审计问题:在成为 NFT 并被交易之前,平台或审计方需要确认所绑定物品的实际权属。一旦出现虚假产权情况,需要能有办法进行回退,这对目前的分布式账本技术提出了新的需求; +* 市场的理性回归问题:目前,优秀的 NFT 产品十分稀缺,导致很多产品上线后被炒作出虚高的价格。新生事物发展初期的过度繁荣往往导致泡沫的快速产生和破灭。交易平台应设计更为理性的拍卖机制,并提高参与门槛。 +* 不同平台之间的互联问题:基于不同平台实现的 NFT 往往采用了不同的标准,彼此之间很难互联互通,这限制了 NFT 在更大市场上的流通。 \ No newline at end of file diff --git a/chainbrock-learning/03_scenario/others.md b/chainbrock-learning/03_scenario/others.md new file mode 100644 index 00000000..3e4c7cbd --- /dev/null +++ b/chainbrock-learning/03_scenario/others.md @@ -0,0 +1,51 @@ +## 其它场景 + +区块链还有一些很有趣的应用场景,包括但不限于云存储、医疗、社交、游戏等多个方面。 + +### 云存储 + +Storj 项目提供了基于区块链的安全的分布式云存储服务。服务保证只有用户自己能看到自己的数据,并号称提供高速的下载速度和 99.99999% 的高可用性。用户还可以“出租”自己的额外硬盘空间来获得报酬。 + +协议设计上,Storj 网络中的节点可以传递数据、验证远端数据的完整性和可用性、复原数据,以及商议合约和向其他节点付费。数据的安全性由数据分片(Data Sharding)和端到端加密提供,数据的完整性由可复原性证明(Proof of Retrievability)提供。 + +### 医疗 + +医院与医保医药公司,不同医院之间,甚至医院里不同部门之间的数据流动性往往很差。考虑到医疗健康数据的敏感性,笔者认为,如果能够满足数据访问权、使用权等规定的基础上促进医疗数据的提取和流动,健康大数据行业将迎来春天。 + +目前,全球范围内的个人数据市场估值每年在 2000 亿美金左右。 + +GemHealth 项目由区块链公司 Gem 于 2016 年 4 月提出,其目标除了用区块链存储医疗记录或数据,还包括借助区块链增强医疗健康数据在不同机构不同部门间的安全可转移性、促进全球病人身份识别、医疗设备数据安全收集与验证等。项目已与医疗行业多家公司签订了合作协议。 + +Hu.Manity 是一家创业公司,提供健康数据的匿名出售服务。用户可以选择售卖个人健康数据,但这些数据会消除掉个人的隐私信息。 + +麻省理工学院媒体实验室也在建立一个医疗数据的共享系统,允许病人自行选择分享哪些数据给医疗机构。 + +### 通信和社交 + +BitMessage 是一套去中心化通信系统,在点对点通信的基础上保护用户的匿名性和信息的隐私。BitMessage 协议在设计上充分参考了比特币,二者拥有相似的地址编码机制和消息传递机制。BitMessage 也用工作量证明(Proof-of-Work)机制防止通信网络受到大量垃圾信息的冲击。 + +类似的,Twister 是一套去中心化的“微博”系统,Dot-Bit 是一套去中心化的 DNS 系统。 + +### 投票 + +Follow My Vote 项目致力于提供一个安全、透明的在线投票系统。通过使用该系统进行选举投票,投票者可以随时检查自己选票的存在和正确性,看到实时记票结果,并在改变主意时修改选票。 + +该项目使用区块链进行记票,并开源其软件代码供社区用户审核。项目也为投票人身份认证、防止重复投票、投票隐私等难点问题提供了解决方案。 + +### 在线音乐 + +Ujo 音乐平台通过使用智能合约来创建一个透明的、去中心化的版权和版权所有者数据库来进行音乐版权税费的自动支付。 + +### 预测 + +Augur 是一个运行在以太坊上的预测市场平台。使用 Augur,来自全球不同地方的任何人都可发起自己的预测话题市场,或随意加入其它市场,来预测一些事件的发展结果。预测结果和奖金结算由智能合约严格控制,使得在平台上博弈的用户不用为安全性产生担忧。 + +### 电子游戏 + +2017 年 3 月,来自马来西亚的电子游戏工作室 Xhai Studios 宣布将区块链技术引入其电子游戏平台。工作室旗下的一些游戏将支持与 NEM 区块链的代币 XEM 整合。通过这一平台,游戏开发者可以在游戏架构中直接调用支付功能,消除对第三方支付的依赖;玩家则可以自由地将 XEM 和游戏内货币、点数等进行双向兑换。 + +### 存证 +TODO:展开解释存证或版权案例 +“纸贵版权” 引入公证处、版权局、知名高校作为版权存证联盟链的存证和监管节点,所有上链的版权存证信息都会经过多个节点的验证和监管,保证任何时刻均可出具具备国家承认的公证证明,具有最高司法效力。同时,通过在公证处部署联盟链存证节点服务器,存证主体即可视为公证处。在遭遇侵权行为时,区块链版权登记证书可作为证据证明版权归属,得到法院的采信。 + +2018 年 12 月 22 日,北京互联网法院“天平链”正式发布。该区块链平台融合了司法鉴定中心、公证处、行业机构等,三个月时间内发展到 17 个节点,采集数据超过一百万条。这些存证数据有望提高电子诉讼的采证效率。 diff --git a/chainbrock-learning/03_scenario/ownership.md b/chainbrock-learning/03_scenario/ownership.md new file mode 100644 index 00000000..db95a606 --- /dev/null +++ b/chainbrock-learning/03_scenario/ownership.md @@ -0,0 +1,37 @@ +### 权属管理与溯源 + +区块链技术可以用于产权、版权等所有权的管理和追踪。其中包括汽车、房屋、艺术品等各种贵重物品的交易等,也包括数字出版物,以及可以标记的数字资源。 + +目前权属管理领域存在的几个难题是: + +* 物品所有权的确认和管理; +* 交易的安全性和可靠性保障; +* 必要的隐私保护机制。 + +以房屋交易为例。买卖双方往往需要依托中介机构来确保交易的进行,并通过纸质的材料证明房屋所有权。但实际上,很多时候中介机构也无法确保交易的正常进行。 + +而利用区块链技术,物品的所有权是写在数字链上的,谁都无法修改。并且一旦出现合同中约定情况,区块链技术将确保合同能得到准确执行。这能有效减少传统情况下纠纷仲裁环节的人工干预和执行成本。 + +例如,公正通(Factom)尝试使用区块链技术来革新商业社会和政府部门的数据管理和数据记录方式。包括审计系统、医疗信息记录、供应链管理、投票系统、财产契据、法律应用、金融系统等。它将待确权数据的指纹存放到基于区块链的分布式账本中,可以提供资产所有权的追踪服务。 + +区块链账本共享、信息可追踪溯源且不可篡改的特性同样可用于打击造假和防范欺诈。Everledger 自 2016 年起就研究基于区块链技术实现贵重资产检测系统,将钻石或者艺术品等的数字指纹信息(包括钻石超过40个数据点的颜色、清晰度、切割和重量等信息)记录在区块链上。并于 2017 年宣布与 IBM 合作,实现生产商、加工商、运送方、零售商等多方之间的可信高效协作。 + +类似地,针对食品造假这一难题,IBM、沃尔玛、清华大学于 2016 年底共同宣布将在食品安全领域展开合作,将用区块链技术搭建透明可追溯的跨境食品供应链。这一全新的供应链将改善食品的溯源和物流环节,打造更为安全的全球食品市场。 + +### 存证 + +### 溯源 + +### 数据协作 + +### 其他项目 + +在人力资源和教育领域,MIT 研究员朱莉安娜·纳扎雷(Juliana Nazaré)和学术创新部主管菲利普·施密特(Philipp Schmidt)发表了文章[《MIT Media Lab Uses the Bitcoin Blockchain for Digital Certificates》](http://quarktalk.cc/threads/mit-media-lab-uses-the-bitcoin-blockchain-for-digital-certificates.1553/),介绍基于区块链的学历认证系统。基于该系统,用人单位可以确认求职者的学历信息是真实可靠的。2018 年 2 月,麻省理工学院向应届毕业生颁发了首批基于区块链的数字学位证书。 + +此外,还包括一些其他相关的应用项目: + +* Chronicled:基于区块链的球鞋鉴定方案,为正品球鞋添加电子标签,记录在区块链上。 +* Mediachain:通过 metadata 协议,将内容创造者与作品唯一对应。 +* Mycelia:区块链产权保护项目,为音乐人实现音乐的自由交易。 +* Tierion: 将用户数据锚定在比特币或以太坊区块链上,并生成“区块链收据”。 +* Ziggurat:基于区块链提供文字、图片、音视频版权资产的登记和管理服务。 diff --git a/chainbrock-learning/03_scenario/sharing.md b/chainbrock-learning/03_scenario/sharing.md new file mode 100644 index 00000000..51d14bd5 --- /dev/null +++ b/chainbrock-learning/03_scenario/sharing.md @@ -0,0 +1,58 @@ +## 资源共享 + +当前,以 Uber、Airbnb 为代表的共享经济模式正在多个垂直领域冲击传统行业。这一模式鼓励人们通过互联网的方式共享闲置资源。资源共享目前面临的问题主要包括: + +* 共享过程成本过高; +* 用户行为评价难; +* 共享服务管理难。 + +区块链技术为解决上述问题提供了更多可能。相比于依赖于中间方的资源共享模式,基于区块链的模式有潜力更直接的连接资源的供给方和需求方,其透明、不可篡改的特性有助于减小摩擦。 + +有人认为区块链技术会成为新一代共享经济的基石。笔者认为,区块链在资源共享领域是否存在价值,还要看能否比传统的专业供应者或中间方形式实现更高的效率和更低的成本,同时不能损害用户体验。 + +### 短租共享 +大量提供短租服务的公司已经开始尝试用区块链来解决共享中的难题。 + +高盛在报告《Blockchain: Putting Theory into Practice》中宣称: + +> Airbnb 等 P2P 住宿平台已经开始通过利用私人住所打造公开市场来变革住宿行业,但是这种服务的接受程度可能会因人们对人身安全以及财产损失的担忧而受到限制。而如果通过引入安全且无法篡改的数字化资质和信用管理系统,我们认为区块链就能有助于提升 P2P 住宿的接受度。 + +该报告还指出,可能采用区块链技术的企业包括 Airbnb、HomeAway 以及 OneFineStay 等,市场规模为 30~90 亿美元。 + +### 社区能源共享 + +在纽约布鲁克林的一个街区,已有项目尝试将家庭太阳能发的电通过社区的电力网络直接进行买卖。具体的交易不再经过电网公司,而是通过区块链执行。 + +与之类似,ConsenSys 和微电网开发商 LO3 提出共建光伏发电交易网络,实现点对点的能源交易。 + +这些方案的主要难题包括: + +* 太阳能电池管理; +* 社区电网构建; +* 电力储备系统搭建; +* 低成本交易系统支持。 + +现在已经有大量创业团队在解决这些问题,特别是硬件部分已经有了不少解决方案。而通过区块链技术打造的平台可以解决最后一个问题,即低成本地实现社区内的可靠交易系统。 + +### 电商平台 + +传统情况下,电商平台起到了中介的作用。一旦买卖双方发生纠纷,电商平台会作为第三方机构进行仲裁。这种模式存在着周期长、缺乏公证、成本高等缺点。OpenBazaar 试图在无中介的情形下,实现安全电商交易。 + +具体地,OpenBazaar 提供的分布式电商平台,通过多方签名机制和信誉评分机制,让众多参与者合作进行评估,实现零成本解决纠纷问题。 + +### 大数据共享 +大数据时代里,价值来自于对数据的挖掘,数据维度越多,体积越大,潜在价值也就越高。 + +一直以来,比较让人头疼的问题是如何评估数据的价值,如何利用数据进行交换和交易,以及如何避免宝贵的数据在未经许可的情况下泄露出去。 + +区块链技术为解决这些问题提供了潜在的可能。 + +利用共同记录的共享账本,数据在多方之间的流动将得到实时的追踪和管理。通过对敏感信息的脱敏处理和访问权限的设定,区块链可以对大数据的共享授权进行精细化管控,规范和促进大数据的交易与流通。 + +### 减小共享风险 + +传统的资源共享平台在遇到经济纠纷时会充当调解和仲裁者的角色。对于区块链共享平台,目前还存在线下复杂交易难以数字化等问题。除了引入信誉评分、多方评估等机制,也有方案提出引入保险机制来对冲风险。 + +2016 年 7 月,德勤、Stratumn 和 LemonWay 共同推出一个为共享经济场景设计的“微保险”概念平台,称为 LenderBot。针对共享经济活动中临时交换资产可能产生的风险,LenderBot 允许用户在区块链上注册定制的微保险,并为共享的资产(如相机、手机、电脑)投保。区块链在其中扮演了可信第三方和条款执行者的角色。 + + diff --git a/chainbrock-learning/03_scenario/summary.md b/chainbrock-learning/03_scenario/summary.md new file mode 100644 index 00000000..c9ab7c38 --- /dev/null +++ b/chainbrock-learning/03_scenario/summary.md @@ -0,0 +1,8 @@ +## 本章小结 +本章介绍了大量基于区块链技术的应用案例和场景,展现了区块链以及基于区块链的分布式账本技术所具有的巨大市场潜力。 + +当然,任何事物的发展都不是一帆风顺的。 + +目前来看,制约区块链技术进一步落地的因素有很多。比如如何来为区块链上的合同担保?特别在金融、法律等领域,实际执行的时候往往还需要线下机制来配合;另外就是基于区块链系统的价值交易,必须要实现物品价值的数字化,非数字化的物品很难直接放到数字世界中进行管理。 + +这些问题看起来都不容易很快得到解决。但笔者相信,一门新的技术能否站住脚,根本上还是看它能否最终提高生产力,而区块链技术已经证明了这一点。随着生态的进一步成熟,区块链技术必将在更多领域获得用武之地。 \ No newline at end of file diff --git a/chainbrock-learning/03_scenario/trust.md b/chainbrock-learning/03_scenario/trust.md new file mode 100644 index 00000000..9f0802aa --- /dev/null +++ b/chainbrock-learning/03_scenario/trust.md @@ -0,0 +1,26 @@ +## 征信管理 + +征信管理是一个巨大的潜在市场,据称超过千亿规模(可参考美国富国银行报告和平安证券报告),也是目前大数据应用领域最有前途的方向之一。 + +目前征信相关的大量有效数据集中在少数机构手中。由于这些数据太过敏感,并且具备极高的商业价值,往往会被严密保护起来,形成很高的行业门槛。 + +虽然现在大量的互联网企业(包括各类社交网站)尝试从各种维度获取了海量的用户信息,但从征信角度看,这些数据仍然存在若干问题。这些问题主要包括: + +* 数据量不足:数据量越大,能获得的价值自然越高,过少的数据量无法产生有效价值; +* 相关度较差:最核心的数据也往往是最敏感的。在隐私高度敏感的今天,用户都不希望暴露过多数据给第三方,因此企业获取到数据中有效成分往往很少; +* 时效性不足:企业可以从明面上获取到的用户数据往往是过时的,甚至存在虚假信息,对相关分析的可信度造成严重干扰。 + +区块链天然存在着无法篡改、不可抵赖的特性。同时,区块链平台将可能提供前所未有规模的相关性极高的数据,这些数据可以在时空中准确定位,并严格关联到用户。因此,基于区块链提供数据进行征信管理,将大大提高信用评估的准确率,同时降低评估成本。 + +另外,跟传统依靠人工的审核过程不同,区块链中交易处理完全遵循约定自动化执行。基于区块链的信用机制将天然具备稳定性和中立性。 + +目前,包括 IDG、腾讯、安永、普华永道等都已投资或进入基于区块链的征信管理领域,特别是跟保险和互助经济相关的应用场景。 + +### 保险行业 + +保险行业区块链倡议组织(Blockchain +Insurance Industry Initiative,B3i)诞生于 2016 年下半年,面向保险行业,探索基于分布式账本的新型技术。 + +分布式账本带来的可信能力,将有望给保险行业带来新的变革。 + +目前,B3i 已经包括超过 40 家会员企业,包括美国国际集团、友邦保险、安联保险、瑞士再保险等保险行业巨头。 diff --git a/chainbrock-learning/04_distributed_system/README.md b/chainbrock-learning/04_distributed_system/README.md new file mode 100644 index 00000000..f4e489ec --- /dev/null +++ b/chainbrock-learning/04_distributed_system/README.md @@ -0,0 +1,11 @@ +# 分布式系统核心技术 + +** 万法皆空,因果不空。 ** + +随着摩尔定律碰到瓶颈,分布式架构逐渐流行起来。 + +从单点演变到分布式结构,重要问题之一就是数据一致性。很显然,如果分布式集群中多个节点处理结果无法保证一致,那么在其上的业务系统将无法正常工作。 + +区块链系统是一个典型的分布式系统,必然也会碰到这些经典问题。 + +本章将介绍分布式系统领域的核心技术,包括一致性、共识,介绍这些概念的定义、基本原理和常见算法,最后还介绍了评估分布式系统可靠性的指标。 diff --git a/chainbrock-learning/04_distributed_system/acid.md b/chainbrock-learning/04_distributed_system/acid.md new file mode 100644 index 00000000..eddfb7af --- /dev/null +++ b/chainbrock-learning/04_distributed_system/acid.md @@ -0,0 +1,46 @@ +## ACID 原则与多阶段提交 + +### ACID 原则 +ACID,即 Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)四种特性的缩写。 + +ACID 也是一种比较出名的描述一致性的原则,通常出现在分布式数据库等基于事务过程的系统中。 + +具体来说,ACID 原则描述了分布式数据库需要满足的一致性需求,同时允许付出可用性的代价。 + +* Atomicity:每次事务是原子的,事务包含的所有操作要么全部成功,要么全部不执行。一旦有操作失败,则需要回退状态到执行事务之前; +* Consistency:数据库的状态在事务执行前后的状态是一致的和完整的,无中间状态。即只能处于成功事务提交后的状态; +* Isolation:各种事务可以并发执行,但彼此之间互相不影响。按照标准 SQL 规范,从弱到强可以分为未授权读取、授权读取、可重复读取和串行化四种隔离等级; +* Durability:状态的改变是持久的,不会失效。一旦某个事务提交,则它造成的状态变更就是永久性的。 + +与 ACID 相对的一个原则是 eBay 技术专家 Dan Pritchett 提出的 BASE(Basic Availability,Soft-state,Eventual Consistency)原则。BASE 原则面向大型高可用分布式系统,主张牺牲掉对强一致性的追求,而实现最终一致性,来换取一定的可用性。 + +*注:ACID 和 BASE 在英文中分别是“酸”和“碱”,看似对立,实则是对 CAP 三特性的不同取舍。* + +### 两阶段提交 + +对于分布式事务一致性的研究成果包括著名的两阶段提交算法(Two-phase Commit,2PC)和三阶段提交算法(Three-phase Commit,3PC)。 + +两阶段提交算法最早由 Jim Gray 于 1979 年在论文《Notes on Database Operating Systems》中提出。其基本思想十分简单,既然在分布式场景下,直接提交事务可能出现各种故障和冲突,那么可将其分解为预提交和正式提交两个阶段,规避风险。 + +* 预提交(PreCommit):协调者(Coordinator)发起执行某个事务的执行并等待结果。各参与者(Participant)执行事务但不提交,反馈是否能完成,并阻塞等待协调者指令; +* 正式提交(DoCommit):协调者如果得到所有参与者的成功答复,则发出正式提交指令,否则发出状态回滚指令。 + +两阶段提交算法因为其简单容易实现的优点,在关系型数据库等系统中被广泛应用。当然,其缺点也很明显。 + +* 第一阶段时,各参与者同步阻塞等待时无法处理请求,会导致系统性较差; +* 存在协调者单点故障问题,最坏情况下协调者总是在第二阶段故障,无法完成提交; +* 可能产生数据不一致的情况。例如第二个阶段时,协调者将正式提交请求发给部分参与者后发生故障。 + +### 三阶段提交 + +三阶段提交算法针对两阶段提交算法第一阶段中参与者阻塞问题进行了优化。具体来说,将预提交阶段进一步拆成两个步骤:询问提交和预提交。 + +完整过程如下: + +* 询问提交(CanCommit):协调者询问参与者是否能进行某个事务的提交。参与者需要返回答复是否准备好,但无需执行提交,也无需阻塞。这就避免出现参与者被阻塞的情况; +* 预提交(PreCommit):协调者检查收集到的答复,如果全部为真,则发起执行事务请求。各参与参与者(Participant)需要执行事务但不提交,并反馈能否完成。注意此时说明所有参与者都已经处于准备好状态。; +* 正式提交(DoCommit):协调者如果得到所有参与者的成功答复,则发出正式提交请求,否则发出状态回滚指令。本阶段时,如果参与者一直收不到请求,则超时后继续提交。 + +三阶段提交主要解决了阻塞问题和协调者单点故障问题。第三阶段时,如果参与者无法及时收到协调者的消息,可以在超时后自动进行提交。但是当协调者发出的回滚消息未被部分参与者收到时,会出现不一致的情况。 + +其实,无论两阶段还是三阶段提交,都只是一定程度上缓解了提交冲突的问题,并无法确保系统的一致性。首个有效的共识算法是后来提出的 Paxos 算法。 diff --git a/chainbrock-learning/04_distributed_system/algorithms.md b/chainbrock-learning/04_distributed_system/algorithms.md new file mode 100644 index 00000000..5a2c4cda --- /dev/null +++ b/chainbrock-learning/04_distributed_system/algorithms.md @@ -0,0 +1,55 @@ +## 共识算法 + +共识(Consensus)这个术语很多时候会与一致性(Consistency)术语放在一起讨论。严谨地讲,两者的含义并不完全相同。 + +一致性的含义比共识宽泛,在不同场景(基于事务的数据库、分布式系统等)下意义不同。具体到分布式系统场景下,一致性指的是多个副本对外呈现的状态。如前面提到的顺序一致性、线性一致性,描述了多节点对数据状态的共同维护能力。而共识,则特指在分布式系统中多个节点之间对某个事情(例如多个事务请求,先执行谁?)达成一致看法的过程。因此,达成某种共识并不意味着就保障了一致性。 + +实践中,要保障系统满足不同程度的一致性,往往需要通过共识算法来达成。 + +共识算法解决的是分布式系统对某个提案(Proposal),大部分节点达成一致意见的过程。提案的含义在分布式系统中十分宽泛,如多个事件发生的顺序、某个键对应的值、谁是主节点……等等。可以认为任何可以达成一致的信息都是一个提案。 + +对于分布式系统来讲,各个节点通常都是相同的确定性状态机模型(又称为状态机复制问题,State-Machine Replication),从相同初始状态开始接收相同顺序的指令,则可以保证相同的结果状态。因此,系统中多个节点最关键的是对多个事件的顺序进行共识,即排序。 + +*注:计算机世界里采用的是典型的“多数人暴政”,足够简单、高效。* + +### 问题与挑战 + +无论是在现实生活中,还是计算机世界里,达成共识都要解决两个基本的问题: + +* 首先,如何提出一个待共识的提案?如通过令牌传递、随机选取、权重比较、求解难题等; +* 其次,如何让多个节点对该提案达成共识(同意或拒绝),如投票、规则验证等。 + +理论上,如果分布式系统中各节点都能以十分“理想”的性能(瞬间响应、超高吞吐)稳定运行,节点之间通信瞬时送达(如量子纠缠),则实现共识过程并不十分困难,简单地通过广播进行瞬时投票和应答即可。 + +可惜的是,现实中这样的“理想”系统并不存在。不同节点之间通信存在延迟(光速物理限制、通信处理延迟),并且任意环节都可能存在故障(系统规模越大,发生故障可能性越高)。如通信网络会发生中断、节点会发生故障、甚至存在被入侵的节点故意伪造消息,破坏正常的共识过程。 + +一般地,把出现故障(Crash 或 Fail-stop,即不响应)但不会伪造信息的情况称为“非拜占庭错误(Non-Byzantine Fault)”或“故障错误(Crash Fault)”;伪造信息恶意响应的情况称为“拜占庭错误”(Byzantine Fault),对应节点为拜占庭节点。显然,后者场景中因为存在“捣乱者”更难达成共识。 + +此外,任何处理都需要成本,共识也是如此。当存在一定信任前提(如接入节点都经过验证、节点性能稳定、安全保障很高)时,达成共识相对容易,共识性能也较高;反之在不可信的场景下,达成共识很难,需要付出较大成本(如时间、经济、安全等),而且性能往往较差(如工作量证明算法)。 + +*注:非拜占庭场景的典型例子是通过报数来统计人数,即便偶有冲突(如两人同时报一个数)也能很快解决;拜占庭场景的一个常见例子是“杀人游戏”,当参与者众多时很难快速达成共识。* + +### 常见算法 +根据解决的场景是否允许拜占庭错误情况,共识算法可以分为 Crash Fault Tolerance (CFT) 和 Byzantine Fault Tolerance(BFT)两类。 + +对于非拜占庭错误的情况,已经存在不少经典的算法,包括 Paxos(1990 年)、Raft(2014 年)及其变种等。这类容错算法往往性能比较好,处理较快,容忍不超过一半的故障节点。 + +对于要能容忍拜占庭错误的情况,包括 PBFT(Practical Byzantine Fault Tolerance,1999 年)为代表的确定性系列算法、PoW(1997 年)为代表的概率算法等。确定性算法一旦达成共识就不可逆转,即共识是最终结果;而概率类算法的共识结果则是临时的,随着时间推移或某种强化,共识结果被推翻的概率越来越小,最终成为事实上结果。拜占庭类容错算法往往性能较差,容忍不超过 1/3 的故障节点。 + +此外,XFT(Cross Fault Tolerance,2015 年)等最近提出的改进算法可以提供类似 CFT 的处理响应速度,并能在大多数节点正常工作时提供 BFT 保障。 + +Algorand 算法(2017 年)基于 PBFT 进行改进,通过引入可验证随机函数解决了提案选择的问题,理论上可以在容忍拜占庭错误的前提下实现更好的性能(1000+ TPS)。 + +*注:实践中,对客户端来说要拿到共识结果需要自行验证,典型地,可访问足够多个服务节点来比对结果,确保获取结果的准确性。* + +### 理论界限 + +科学家都喜欢探寻问题最坏情况的理论界限。那么,共识问题的最坏界限在哪里呢?很不幸,在推广到任意情况时,分布式系统的共识问题无通用解。 + +这似乎很容易理解,当多个节点之间的通信网络自身不可靠情况下,很显然,无法确保实现共识(例如,所有涉及共识的消息都丢失)。那么,对于一个设计得当,可以大概率保证消息正确送达的网络,是不是一定能获得共识呢? + +理论证明告诉我们,**即便在网络通信可靠情况下,一个可扩展的分布式系统的共识问题通用解法的下限是——没有下限(无解)。** + +这个结论,被称为“FLP 不可能原理”。该原理极其重要,可以看做是分布式领域里的“测不准原理”。 + +*注:不光分布式系统领域,实际上很多领域都存在类似测不准原理的约束,或许说明世界本源就存在限制。* diff --git a/chainbrock-learning/04_distributed_system/availability.md b/chainbrock-learning/04_distributed_system/availability.md new file mode 100644 index 00000000..3b11e0b8 --- /dev/null +++ b/chainbrock-learning/04_distributed_system/availability.md @@ -0,0 +1,44 @@ +## 可靠性指标 + +可靠性(Availability),或者说可用性,是描述系统可以提供服务能力的重要指标。高可靠的分布式系统往往需要各种复杂的机制来进行保障。 + +通常情况下,服务的可用性可以用服务承诺(Service Level Agreement,SLA)、服务指标(Service Level Indicator,SLI)、服务目标(Service Level Objective,SLO)等方面进行衡量。 + +### 几个 9 的指标 + +完美的可靠性是不存在的。很多领域里谈到服务的高可靠性,通常都会用“几个 9”的指标来进行衡量。 + +“几个 9”的指标,其实是概率意义上粗略反映了系统能提供服务的可靠性指标,最初是电信领域提出的概念。 + +下表给出不同指标下,每年允许服务出现不可用时间的参考值。 + +| 指标 | 概率可靠性 | 每年允许不可用时间 | 典型场景 | +|--------|-----------:|-------------------:|----------| +| 一个 9 | 90% | 1.2 个月 | 简单测试 | +| 二个 9 | 99% | 3.6 天 | 普通单点 | +| 三个 9 | 99.9% | 8.6 小时 | 普通集群 | +| 四个 9 | 99.99% | 51.6 分钟 | 高可用 | +| 五个 9 | 99.999% | 5 分钟 | 电信级 | +| 六个 9 | 99.9999% | 31 秒 | 极高要求 | +| 七个 9 | 99.99999% | 3 秒 | N/A | + +一般来说,单点的服务器系统至少应能满足两个 9;普通企业信息系统应能满足三个 9;少数领先企业(如亚马逊、甲骨文)产品能实现四个 9 甚至更多。大型金融和电信系统指标是五个 9,意味着每年最多允许出现五分钟左右的服务故障。五个 9 以上的系统十分罕见,要实现往往意味着极高的成本。 + +### 两个核心时间 + +一般地,描述系统出现故障的可能性和故障出现后的恢复能力,有两个基础的指标:MTBF 和 MTTR。 + +* MTBF:Mean Time Between Failures,平均故障间隔时间,即系统可以无故障运行的预期时间。 +* MTTR:Mean Time To Repair,平均修复时间,即发生故障后,系统可以恢复到正常运行的预期时间。 + +MTBF 衡量了系统发生故障的频率,如果一个系统的 MTBF 很短,则往往意味着该系统可用性低;而 MTTR 则反映了系统碰到故障后服务的恢复能力,如果系统的 MTTR 过长,则说明系统一旦发生故障,需要较长时间才能恢复服务。 + +一个高可用的系统应该是具有尽量长的 MTBF 和尽量短的 MTTR。 + +### 提高可靠性 + +那么,该如何提升可靠性呢?有两个基本思路:一是让系统中的单个组件都变得更可靠;二是干脆消灭单点。 + +IT 从业人员大都有类似的经验,普通笔记本电脑,基本上是过一阵可能就要重启下;而运行 Linux/Unix 系统的专用服务器,则可能连续运行几个月甚至几年时间都不出问题。另外,普通的家用路由器,跟生产级别路由器相比,更容易出现运行故障。这些都是单个组件可靠性不同导致的例子,可以通过简单升级单点的软硬件来改善可靠性。 + +然而,依靠单点实现的可靠性毕竟是有限的。要想进一步的提升,那就只好消灭单点,通过主从、多活等模式让多个节点集体完成原先单点的工作。这可以从概率意义上改善服务对外整体的可靠性,这也是分布式系统的一个重要用途。 diff --git a/chainbrock-learning/04_distributed_system/bft.md b/chainbrock-learning/04_distributed_system/bft.md new file mode 100644 index 00000000..5af3c4af --- /dev/null +++ b/chainbrock-learning/04_distributed_system/bft.md @@ -0,0 +1,88 @@ +## 拜占庭问题与算法 + +拜占庭问题(Byzantine Problem)又叫拜占庭将军(Byzantine Generals Problem)问题,讨论的是在少数节点有可能作恶(消息可能被伪造)的场景下,如何达成共识问题。拜占庭容错(Byzantine Fault Tolerant,BFT)讨论的是容忍拜占庭错误的共识算法。 + +### 两将军问题 + +拜占庭问题之前,早在 1975 年,学术界就已经开始两将军问题的讨论(《Some constraints and tradeofis in the design of network communications》):两个将军要通过信使来达成进攻还是撤退的约定,但信使可能迷路或被敌军阻拦(消息丢失或伪造),如何达成一致?这是典型的异步双方共识模型,根据 FLP 不可能原理,这个问题不存在通用解。 + +### 拜占庭问题 + +拜占庭问题最早由 Leslie Lamport 等学者于 1982 年在论文《The Byzantine Generals Problem》中正式提出,是用来解释异步系统中共识问题的一个虚构模型。拜占庭是古代东罗马帝国的首都,由于地域宽广,假设其守卫边境的多个将军(系统中的多个节点)需要通过信使来传递消息,达成某些一致决定。但由于将军中可能存在叛徒(系统中节点出错),这些叛徒将向不同的将军发送不同的消息,试图干扰共识的达成。 + +拜占庭问题即讨论在此情况下,如何让忠诚的将军们能达成行动的一致。 + +一般分布式场景下,拜占庭需求并不多见,但在特定场景下会有较大意义。例如容易匿名参与的系统(如比特币),或是出现欺诈可能造成巨大损失的情况(金融系统)。 + +### 问题的解决 + +论文中指出,对于拜占庭问题来说,假如节点总数为 N,故障节点数为 F,则当 N >= 3F + 1 时,问题才能有解,由 BFT 算法进行保证。 + +例如,N = 3,F = 1 时。 + +若提案人不是叛变者,提案人发送一个提案出来,收到的叛变者可以宣称收到的是相反的命令。则对于第三个人(忠诚者)会收到两个相反的消息,无法判断谁是叛变者,则系统无法达到一致。 + +若提案人是叛变者,发送两个相反的提案分别给另外两人,另外两人都收到两个相反的消息,无法判断究竟谁是叛变者,则系统无法达到一致。 + +更一般的,当提案人不是叛变者,提案人提出提案信息 1,则对于合作者来看,系统中会有 N - F 份确定的信息 1,和 F 份不确定的信息(可能为 0 或 1,假设叛变者会尽量干扰一致的达成),N − F > F,即 N > 2F 情况下才能达成一致。 + +当提案人是叛变者,会尽量发送相反的提案给 N - F 个合作者,从收到 1 的合作者看来,系统中会存在 (N - F)/2 个信息 1,以及 (N - F)/2 个信息 0;从收到 0 的合作者看来,系统中会存在 (N - F)/2 个信息 0,以及 (N - F)/2 个信息 1; + +另外存在 F − 1 个不确定的信息。合作者要想达成一致,必须进一步的对所获得的消息进行判定,询问其他人某个被怀疑对象的消息值,并通过取多数来作为被怀疑者的信息值。这个过程可以进一步递归下去。 + +1980 年,Leslie Lamport 等人在论文《Reaching agreement in the presence of faults》中证明,当叛变者不超过 1/3 时,存在有效的拜占庭容错算法(最坏需要 F+1 轮交互)。反之,如果叛变者过多,超过 1/3,则无法保证一定能达到一致结果。 + +那么,当存在多于 1/3 的叛变者时,有没有可能存在解决方案呢? + +设想 F 个叛变者和 L 个忠诚者,叛变者故意使坏,可以给出错误的结果,也可以不响应。某个时候 F 个叛变者都不响应,则 L 个忠诚者取多数既能得到正确结果。当 F 个叛变者都给出一个恶意的提案,并且 L 个忠诚者中有 F 个离线时,剩下的 L - F 个忠诚者此时无法分别是否混入了叛变者,仍然要确保取多数能得到正确结果,因此,L - F > F,即 L > 2F 或 N - F > 2F,所以系统整体规模 N 要大于 3F。 + +能确保达成共识的拜占庭系统节点数至少为 4,此时最多允许出现 1 个坏的节点。 + +### 拜占庭容错算法 + +拜占庭容错算法(Byzantine Fault Tolerant)是面向拜占庭问题的容错算法,解决的是在网络通信可靠,但节点可能故障和作恶情况下如何达成共识。 + +拜占庭容错算法最早的讨论可以追溯到 Leslie Lamport 等人 1982 年 发表的论文《The Byzantine Generals Problem》,之后出现了大量的改进工作,代表性成果包括《Optimal Asynchronous Byzantine Agreement》(1992 年)、《Fully Polynomial Byzantine Agreement for n>3t Processors in t+1 Rounds》(1998 年)等。长期以来,拜占庭问题的解决方案都存在运行过慢,或复杂度过高的问题,直到“实用拜占庭容错算法”(Practical Byzantine Fault Tolerance,PBFT) 算法的提出。 + +1999 年,PBFT 算法由 Miguel Castro 和 Barbara Liskov + 于论文《Practical Byzantine Fault Tolerance》中提出。该算法基于前人工作(特别是 Paxos 相关算法,因此也被称为 Byzantine Paxos)进行了优化,首次将拜占庭容错算法复杂度从指数级降低到了多项式(平方)级,目前已得到广泛应用。其可以在恶意节点不超过总数 1/3 的情况下同时保证 Safety 和 Liveness。 + +PBFT 算法采用密码学相关技术(RSA 签名算法、消息验证编码和摘要)确保消息传递过程无法被篡改和破坏。 + +算法的基本过程如下: + +* 首先,通过轮换或随机算法选出某个节点为主节点,此后只要主节点不切换,则称为一个视图(View)。 +* 在某个视图中,客户端将请求 `` 发送给主节点(如果客户端发给从节点,从节点可以转发给主节点),主节点负责广播请求到所有其它从节点并完成共识。 +* 所有节点处理完成请求,将处理结果 `` 返回给客户端。客户端检查是否收到了至少 f+1 个来自不同节点的相同结果,作为最终结果。 + +主节点广播过程包括三个阶段的处理:预准备(Pre-Prepare)、准备(Prepare)和提交(Commit)。预准备和准备阶段确保在同一个视图内请求发送的顺序正确;准备和提交阶段则确保在不同视图之间的确认请求是保序的。 + +* 预准备阶段:主节点为从客户端收到的请求分配提案编号,然后发出预准备消息 `<,message>` 给各从节点,主节点需要对预准备消息进行签名。其中 n 是主节点为这个请求分配的序号,message 是客户端的请求消息,digest 是消息的摘要。这一步的目的是为请求分配序号并通知其他节点,因此可以不包括原始的请求消息,可以通过其他方式将请求同步到从节点。 +* 准备阶段:从节点收到预准备消息后,检查消息(包括核对签名、视图、编号)。如消息合法,则向其它节点发送准备消息 ``,带上自己的 id 信息,并添加签名。收到准备消息的节点同样对消息进行合法性检查。节点集齐至少 2f+1 个验证过的消息则认为验证通过,把这个准备消息写入本地提交消息日志中。这一步是为了确认大多数节点已经对序号达成共识,本节点已经准备好进行提交了。 +* 提交阶段:广播 commit 消息 `` 并添加自己签名,告诉其它节点某个编号为 n 的提案在视图 v 里已经处于提交状态。如果集齐至少 2f+1 个验证过的 commit 消息,则说明提案被整个系统接受。 + +PBFT 算法和 Raft 算法的过程十分类似。区别在于 PBFT 算法中并不假设主节点一定是可靠的,因此增加了额外的从节点之间的交互,当发现主节点不可靠时通过重新选举选出新的主节点。 + +具体实现上还包括 checkpoint(同步节点状态和清理本地日志数据)、视图切换(重新选举主节点)等机制,读者可自行参考论文内容,在此不再赘述。 + +拜占庭容错类的算法因为要考虑最恶意的存在“捣乱”者的情况,在大规模场景下共识性能往往会受到影响。 + +### 新的解决思路 + +拜占庭问题之所以难解,在于任何时候系统中都可能存在多个提案(因为提案成本很低),并且在大规模场景下要完成最终确认的过程容易受干扰,难以达成共识。 + +2014 年,斯坦福大学的 Christopher Copeland 和 Hongxia Zhong 在论文《Tangaroa: a byzantine fault tolerant raft》中提出在 Raft 算法基础上借鉴 PBFT 算法的一些特性(包括签名、恶意领导探测、选举校验等)来实现拜占庭容错性,兼顾可实现性和鲁棒性。该论文也启发了 Kadena 等项目的出现,实现更好性能的拜占庭算法。 + +2017 年,MIT 计算机科学与人工智能实验室(CSAIL)的 Yossi Gilad 和 Silvio Micali 等人在论文《Algorand: Scaling Byzantine Agreements for Cryptocurrencies》中针对 PBFT 算法在很多节点情况下性能不佳的问题,提出先选出少量记账节点,然后再利用可验证随机函数(Verifiable Random Function,VRF)来随机选取领导节点,避免全网直接做共识,将拜占庭算法扩展到了支持较大规模的应用场景,同时保持较好的性能(1000+ tps)。 + +此外,康奈尔大学的 Rafael Pass 和 Elaine Shi 在论文《The Sleepy Model of Consensus》中探讨了在动态场景(大量节点离线情况)下如何保障共识的安全性,提出的 Sleepy Consensus 算法可以在活跃诚实节点达到一半以上时确保完成拜占庭共识。 + +2018 年,清华大学的 Chenxing Li 等在论文《Scaling Nakamoto Consensus to Thousands of Transactions per Second》中提出了 Conflux 共识协议。该协议在 GHOST 算法基础上改善了安全性,面向公有区块链场景,理论上能达到 6000+ tps。 + +2019 年,康奈尔大学和 VMWare 研究院的 Maofan Yin 等在论文《HotStuff: BFT Consensus with Linearity and Responsiveness》中对 PBFT 算法进行了改进:利用主节点来简化通信量,同时将视图切换与共识操作进行统一。值得一提的是,Facebook Libra 白皮书中采用了该成果。 + +比特币网络在设计时使用了 PoW(Proof of Work)的概率型算法思路,从如下两个角度解决大规模场景下的拜占庭容错问题。 + +首先,限制一段时间内整个网络中出现提案的个数(通过工作量证明来增加提案成本);其次是丢掉最终确认的约束,约定好始终沿着已知最长的链进行拓展。共识的最终确认是概率意义上的存在。这样,即便有人试图恶意破坏,也会付出相应的经济代价(超过整体系统一半的工作量)。后来的各种 PoX 系列算法,也都是沿着这个思路进行改进,采用经济博弈来制约攻击者。 + +另外,由于要处理的场景比较苛刻,BFT 类算法的吞吐量往往不高。除了可以放宽约束外(例如通常情况下信任主节点,出现问题再回滚),还可以引入多个互不影响的主节点进行并行处理。 diff --git a/chainbrock-learning/04_distributed_system/cap.md b/chainbrock-learning/04_distributed_system/cap.md new file mode 100644 index 00000000..5e0cca82 --- /dev/null +++ b/chainbrock-learning/04_distributed_system/cap.md @@ -0,0 +1,44 @@ +## CAP 原理 + +CAP 原理最早出现在 2000 年,由加州大学伯克利分校的 Eric Brewer 教授在 ACM 组织的 Principles of Distributed Computing(PODC)研讨会上提出的猜想。两年后,麻省理工学院的 Nancy Lynch 等学者进行了理论证明。 + +该原理被认为是分布式系统领域的重要原理之一,深刻影响了分布式计算与系统设计的发展。 + +### 定义 +**CAP 原理**:分布式系统无法同时确保一致性(Consistency)、可用性(Availability)和分区容忍性(Partition),设计中往往需要弱化对某个特性的需求。 + +一致性、可用性和分区容忍性的具体含义如下: + +* 一致性(Consistency):任何事务应该都是原子的,所有副本上的状态都是事务成功提交后的结果,并保持强一致; +* 可用性(Availability):系统(非失败节点)能在有限时间内完成对操作请求的应答; +* 分区容忍性(Partition):系统中的网络可能发生分区故障(成为多个子网,甚至出现节点上线和下线),即节点之间的通信无法保障。而网络故障不应该影响到系统正常服务。 + +CAP 原理认为,分布式系统最多只能保证三项特性中的两项特性。 + +比较直观地理解,当网络可能出现分区时候,系统是无法同时保证一致性和可用性的。要么,节点收到请求后因为没有得到其它节点的确认而不应答(牺牲可用性),要么节点只能应答非一致的结果(牺牲一致性)。 + +由于大部分时候网络被认为是可靠的,因此系统可以提供一致可靠的服务;当网络不可靠时,系统要么牺牲掉一致性(多数场景下),要么牺牲掉可用性。 + +*注意:网络分区是可能存在的,出现分区情况后很可能会导致发生“脑裂”现象。* + +### 应用场景 + +既然 CAP 三种特性不可同时得到保障,则设计系统时候必然要弱化对某个特性的支持。 + +#### 弱化一致性 +对结果一致性不敏感的应用,可以允许在新版本上线后过一段时间才最终更新成功,期间不保证一致性。 + +例如网站静态页面内容、实时性较弱的查询类数据库等,简单分布式同步协议如 Gossip,以及 CouchDB、Cassandra 数据库等,都为此设计。 + +#### 弱化可用性 +对结果一致性很敏感的应用,例如银行取款机,当系统故障时候会拒绝服务。MongoDB、Redis、MapReduce 等为此设计。 + +Paxos、Raft 等共识算法,主要处理这种情况。在 Paxos 类算法中,可能存在着无法提供可用结果的情形,同时允许少数节点离线。 + +#### 弱化分区容忍性 +现实中,网络分区出现概率较小,但很难完全避免。 + +两阶段的提交算法,某些关系型数据库以及 ZooKeeper 主要考虑了这种设计。 + +实践中,网络可以通过双通道等机制增强可靠性,实现高稳定的网络通信。 + diff --git a/chainbrock-learning/04_distributed_system/flp.md b/chainbrock-learning/04_distributed_system/flp.md new file mode 100644 index 00000000..7bad9de1 --- /dev/null +++ b/chainbrock-learning/04_distributed_system/flp.md @@ -0,0 +1,38 @@ +## FLP 不可能原理 + +### 定义 + +**FLP 不可能原理**:在网络可靠、但允许节点失效(即便只有一个)的最小化异步模型系统中,不存在一个可以解决一致性问题的确定性共识算法(No completely asynchronous consensus protocol can tolerate even a single unannounced process death)。 + +提出并证明该定理的论文《Impossibility of Distributed Consensus with One Faulty Process》是由 Fischer、Lynch 和 Patterson 三位科学家于 1985 年发表,该论文后来获得了 Dijkstra(就是发明最短路径算法的那位计算机科学家)奖。 + +FLP 不可能原理告诉我们,**不要浪费时间去试图为异步分布式系统设计面向任意场景的共识算法**。 + +### 如何理解 + +要正确理解 FLP 不可能原理,首先要弄清楚“异步”的含义。 + +在分布式系统中,同步和异步这两个术语存在特殊的含义: + +* 同步,是指系统中的各个节点的时钟误差存在上限;并且消息传递必须在一定时间内完成,否则认为失败;同时各个节点完成处理消息的时间是一定的。因此同步系统可以轻易判断是节点宕机还是传输消息丢失; +* 异步,则意味着系统中各个节点可能存在较大的时钟差异;同时消息传输时间是任意长的;各节点对消息进行处理的时间也可能是任意长的。这就造成无法判断某个消息迟迟没有被响应是哪里出了问题(节点故障还是传输故障?)。不幸地是,现实生活中的系统往往都是异步系统。 + +FLP 不可能原理在论文中以图论的形式进行了严格证明。要理解其基本原理并不复杂,一个不严谨的例子如下。 + +三个人在不同房间进行投票(投票结果是 0 或者 1),彼此可以通过电话进行沟通,但经常有人会时不时睡着。比如某个时候,A 投票 0,B 投票 1,C 收到了两人的投票,然后 C 睡着了。此时,A 和 B 将永远无法在有限时间内获知最终的结果,因为他们无法判断究竟是 C 没有应答还是应答的时间过长。如果可以重新投票,则类似情形可以在每次取得结果前发生,这将导致共识过程永远无法完成。 + +FLP 不可能原理实际上说明对于允许节点失效情况下,纯粹异步系统无法确保共识在有限时间内完成。即便对于非拜占庭错误的前提下,包括 Paxos、Raft 等算法也都存在无法达成共识的极端情况,只是在工程实践中这种情况出现的概率很小。 + +那么,这是否意味着研究共识算法压根没有意义? + +不必如此悲观。学术研究,往往考虑地是数学和物理意义上理想化的情形,很多时候现实世界要稳定得多(感谢这个世界如此鲁棒!)。例如,上面例子中描述的最坏情形,每次都发生的概率其实并没有那么大。工程实现上,若某次共识失败,再尝试几次,很大可能就成功了。 + +**科学告诉你,什么是不可能的;工程则告诉你,付出一些代价,可以把它变成可行。** + +这就是科学和工程不同的魅力。FLP 不可能原理告诉大家不必浪费时间去追求完美的共识方案,而要根据实际情况设计可行的工程方案。 + +那么,退一步讲,在付出一些代价的情况下,共识能做到多好? + +回答这一问题的是另一个很出名的原理:CAP 原理。 + +*注:科学告诉你去赌场是愚蠢的,因为最终总会输钱;工程则告诉你,如果你愿意接受最终输钱的风险,中间说不定能偶尔小赢几笔呢!* diff --git a/chainbrock-learning/04_distributed_system/paxos.md b/chainbrock-learning/04_distributed_system/paxos.md new file mode 100644 index 00000000..31fc1e08 --- /dev/null +++ b/chainbrock-learning/04_distributed_system/paxos.md @@ -0,0 +1,102 @@ +## Paxos 算法与 Raft 算法 + +Paxos 问题是指分布式的系统中存在故障(crash fault),但不存在恶意(corrupt)节点的场景(即可能消息丢失或重复,但无错误消息)下如何达成共识。这也是分布式共识领域最为常见的问题。因为最早是 Leslie Lamport 用 Paxos 岛的故事对该算法进行描述的,因而得名。解决 Paxos 问题的算法主要有 Paxos 系列算法和 Raft 算法。 + +### Paxos 算法 + +1988 年,Brian M. Oki 和 Barbara H. Liskov 在论文《Viewstamped Replication: A New Primary Copy Method to +Support Highly-Available Distributed Systems》中首次提出了解决 Paxos 问题的算法。 + +1990 年由 Leslie Lamport 在论文《The Part-time Parliament》中提出的 [Paxos](http://research.microsoft.com/users/lamport/pubs/lamport-paxos.pdf) 共识算法,在工程角度实现了一种最大化保障分布式系统一致性(存在极小的概率无法实现一致)的机制。Paxos 算法本质上与前者相同,被广泛应用在 Chubby、ZooKeeper 这样的分布式系统中。Leslie Lamport 作为分布式系统领域的早期研究者,因为相关杰出贡献获得了 2013 年度图灵奖。 + +论文中为了描述问题编造了一个虚构故事:在古代爱琴海的 Paxos 岛,议会如何通过表决来达成共识。议员们通过信使传递消息来对议案进行表决。但议员可能离开,信使可能走丢,甚至重复传递消息。 + +Paxos 是首个得到证明并被广泛应用的共识算法,其原理类似于 [两阶段提交](https://en.wikipedia.org/wiki/Two-phase_commit_protocol) 算法,进行了泛化和扩展,通过消息传递来逐步消除系统中的不确定状态。 + +作为后来很多共识算法(如 Raft、ZAB 等)的基础,Paxos 算法基本思想并不复杂,但最初论文中描述比较难懂,甚至连发表也几经波折。2001 年,Leslie Lamport 还专门发表论文《Paxos Made Simple》进行重新解释。 + +*注:Leslie Lamport 对密码学也有研究,1979 年提出的多 Hash 签名机制,具备抗量子计算攻击特性。* + +#### 基本原理 + +算法中存在三种逻辑角色的节点,在实现中同一节点可以担任多个角色: + +* 提案者(Proposer):提出一个提案,等待大家批准(Chosen)为决议(Value)。系统中提案都拥有一个自增的唯一提案号。往往由客户端担任该角色; +* 接受者(Acceptor):负责对提案进行投票,接受(Accept)提案。往往由服务端担任该角色; +* 学习者(Learner):获取批准结果,并帮忙传播,不参与投票过程。可为客户端或服务端。 + +算法需要满足安全性(Safety) 和存活性(Liveness)两方面的约束要求。实际上这两个基础属性也是大部分分布式算法都该考虑的: + +* Safety:保证决议(Value)结果是对的,无歧义的,不会出现错误情况。 +    * 只有是被提案者提出的提案才可能被最终批准; + * 在一次执行中,只批准(chosen)一个最终决议。被多数接受(accept)的结果成为决议。 +* Liveness:保证决议过程能在有限时间内完成。 + * 决议总会产生,并且学习者能获得被批准的决议。 + +基本思路类似两阶段提交:多个提案者先要争取到提案的权利(得到大多数接受者的支持);成功的提案者发送提案给所有人进行确认,得到大部分人确认的提案成为批准的决议。 + +Paxos 并不保证系统总处在一致的状态。但由于每次达成共识至少有超过一半的节点参与,这样最终整个系统都会获知共识结果。一个潜在的问题是提案者在提案过程中出现故障,这可以通过超时机制来缓解。极为凑巧的情况下,每次新一轮提案的提案者都恰好故障,又或者两个提案者恰好依次提出更新的提案,则导致活锁,系统会永远无法达成共识(实际发生概率很小)。 + +Paxos 能保证在超过一半的节点正常工作时,系统总能以较大概率达成共识。读者可以试着自己设计一套非拜占庭容错下基于消息传递的异步共识方案,会发现在满足各种约束情况下,算法过程总会十分类似 Paxos 的过程。这也是为何 Google Chubby 的作者 Mike Burrows 说:“这个世界上只有一种一致性算法,那就是 Paxos(There is only one consensus protocol, and that's Paxos)”。 + +下面,由简单情况逐步推广到一般情况来探讨算法过程。 + +#### 单个提案者+多接受者 +如果系统中限定只允许某个特定节点是提案者,那么共识结果很容易能达成(只有一个方案,要么达成,要么失败)。提案者只要收到了来自多数接受者的投票,即可认为通过,因为系统中不存在其他的提案。 + +但此时一旦提案者故障,则整个系统无法工作。 + +#### 多个提案者+单个接受者 +限定某个特定节点作为接受者。这种情况下,共识也很容易达成,接受者收到多个提案,选第一个提案作为决议,发送给其它提案者即可。 + +缺陷也是容易发生单点故障,包括接受者故障或首个提案者节点故障。 + +以上两种情形其实类似主从模式,虽然不那么可靠,但因为原理简单而被广泛采用。 + +当提案者和接受者都推广到多个的情形,会出现一些挑战。 + +#### 多个提案者+多个接受者 +既然限定单提案者或单接受者都会出现故障,那么就得允许出现多个提案者和多个接受者。问题一下子变得复杂了。 + +一种情况是同一时间片段(如一个提案周期)内只有一个提案者,这时可以退化到单提案者的情形。需要设计一种机制来保障提案者的正确产生,例如按照时间、序列、或者大家猜拳(出一个参数来比较)之类。考虑到分布式系统要处理的工作量很大,这个过程要尽量高效,满足这一条件的机制非常难设计。 + +另一种情况是允许同一时间片段内可以出现多个提案者。那同一个节点可能收到多份提案,怎么对它们进行区分呢?如果一个节点只接受它收到的首个提案,将导致不同节点可能接受不同的提案。很自然地,提案需要带上不同的序号。节点根据序号来判断接受哪个提案。通常采用递增序号,选择接受序号最大的提案。这是因为旧提案可能基于过期数据,导致失败概率更大。 + +如何为提案分配序号呢?一种可能方案是每个节点的提案数字区间彼此隔离开,互相不冲突。为了满足递增的需求可以配合用时间戳作为前缀字段。 + +同时允许多个提案,意味着很可能单个提案人无法集齐足够多的投票;另一方面,提案者即便收到了多数接受者的投票,也不敢说就一定通过。因为在此过程中投票者无法获知其它投票人的结果,也无法确认提案人是否收到了自己的投票。因此,需要实现两个阶段的提交过程。 + +#### 两阶段的提交 +提案者发出提案申请之后,会收到来自接受者的反馈。一种结果是提案被大多数接受者接受了,一种结果是没被接受。没被接受的话,可以过会再重试。即便收到来自大多数接受者的答复,也不能认为就最终确认了。因为这些接受者自己并不知道自己刚答复的提案可以构成大多数的一致意见。 + +很自然的,需要引入新的一个阶段,即提案者在第一阶段拿到所有的反馈后,需要再次判断这个提案是否得到大多数的支持,如果支持则需要对其进行最终确认。 + +Paxos 里面对这两个阶段分别命名为准备(Prepare)和提交(Commit)。准备阶段通过锁来解决对哪个提案内容进行确认的问题,提交阶段解决大多数确认最终值的问题。 + +**准备阶段**: + +* 提案者向多个接受者发送计划提交的提案编号 n,试探是否可以锁定多数接受者的支持; +* 接受者 i 收到提案编号 n,检查回复过的提案的最大编号 M_i。如果 n > M_i,则向提案者返回准备接受(accept)提交的最大编号的提案 P_i(如果还未接受过任何提案,则为空),并不再接受小于 n 的提案,同时更新 M_i = n。这一步是让接受者筛选出它收到的最大编号的提案,接下来只接受其后续提交。 + +**提交阶段**: + +* 某个提案者如果收到大多数接受者的回复(表示大部分人收到了 n),则准备发出带有 n 的提交消息。如果收到的回复中带有提案 P_i(说明自己看到的信息过期),则替换选编号最大的 P_i 的值为提案值;否则指定一个新提案值。如果没收到大多数回复,则再次发出请求; +* 接受者 i 收到序号为 n 的提交消息,如果发现 n >= P_i 的序号,则接受提案,并更新 P_i 序号为 n。 + +一旦多数接受者接受了共同的提案值,则形成决议,成为最终确认。之后可以开始新一轮的提交确认。 + +需要注意,Paxos 并不一定能保证每一轮都能提交提案。 + +### Raft 算法 +Paxos 算法虽然给出了共识设计,但并没有讨论太多实现细节,也并不重视工程上的优化,因此后来在学术界和工程界出现了一些改进工作,包括 Fast Paxos、Multi-Paxos,Zookeeper Atomic Broadcast(ZAB)和 Raft 等。这些算法重点在于改进执行效率和可实现性。 + +其中,[Raft](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf) 算法由斯坦福大学的 Diego Ongaro 和 John Ousterhout 于 2014 年在论文《In Search of an Understandable Consensus Algorithm》中提出,基于 Multi-Paxos 算法进行重新简化设计和实现,提高了工程实践性。Raft 算法的主要设计思想与 ZAB 类似,通过先选出领导节点来简化流程和提高效率。实现上解耦了领导者选举、日志复制和安全方面的需求,并通过约束减少了不确定性的状态空间。 + +算法包括三种角色:领导者(Leader)、候选者(Candidate) 和跟随者(Follower),每个任期内选举一个全局的领导者。领导者角色十分关键,决定日志(log)的提交。每个日志都会路由到领导者,并且只能由领导者向跟随者单向复制。 + +典型的过程包括两个主要阶段: + +* 领导者选举:开始所有节点都是跟随者,在随机超时发生后未收到来自领导者或候选者消息,则转变角色为候选者(中间状态),提出选举请求。最近选举阶段(Term)中得票超过一半者被选为领导者;如果未选出,随机超时后进入新的阶段重试。领导者负责从客户端接收请求,并分发到其他节点; +* 同步日志:领导者会决定系统中最新的日志记录,并强制所有的跟随者来刷新到这个记录,数据的同步是单向的,确保所有节点看到的视图一致。 + +此外,领导者会定期向所有跟随者发送心跳消息,跟随者如果发现心跳消息超时未收到,则可以认为领导者已经下线,尝试发起新的选举过程。 diff --git a/chainbrock-learning/04_distributed_system/problem.md b/chainbrock-learning/04_distributed_system/problem.md new file mode 100644 index 00000000..fad2cb9e --- /dev/null +++ b/chainbrock-learning/04_distributed_system/problem.md @@ -0,0 +1,74 @@ +## 一致性问题 + +一致性问题是分布式领域最基础、最重要的问题,也是半个世纪以来的研究热点。 + +随着业务场景越来越复杂,计算规模越来越庞大,单点系统往往难以满足高可扩展(Scalability)和高容错(Fault-tolerance)两方面的需求。此时就需要多台服务器通过组成集群,构建更加强大和稳定的“虚拟超级服务器”。 + +任务量越大,处理集群的规模越大,设计和管理的挑战也就越高。谷歌公司的全球搜索集群系统,包括数十万台服务器,每天响应百亿次的互联网搜索请求。 + +集群系统要实现一致性不是一件容易的事。不同节点可能处于不同的状态,不同时刻收到不同的请求,而且随时可能有节点出现故障。要保持对外响应的“一致性”,好比训练一群鸭子齐步走,难度可想而知。 + +### 定义与重要性 + +**定义** 一致性(Consistency),早期也叫(Agreement),在分布式系统领域中是指对于多个服务节点,给定一系列操作,在约定协议的保障下,使得它们对处理结果达成“某种程度”的协同。 + +理想情况(不考虑节点故障)下,如果各个服务节点严格遵循相同的处理协议(即构成相同的状态机逻辑),则在给定相同的初始状态和输入序列时,可以确保处理过程中的每个步骤的执行结果都相同。因此,传统分布式系统中讨论一致性,往往是指在外部任意发起请求(如向多个节点发送不同请求)的情况下,确保系统内大部分节点实际处理请求序列的一致,即对请求进行全局排序。 + +那么,为什么说一致性问题十分重要呢? + +举个现实生活中的例子,多个售票处同时出售某线路上的火车票,该线路上存在多个经停站,怎么才能保证在任意区间都不会出现超售(同一个座位卖给两个人)的情况? + +这个问题看起来似乎没那么难,现实生活中经常通过分段分站售票的机制。然而,要支持海量的用户进行并行购票,并非易事(如 12306 网站高峰期日均访问量超过 500 亿次)。特别是计算机系统往往需要达到远超物理世界的高性能和高可扩展性需求,挑战会变得更大。这也是为何每年到了促销季,各大电商平台都要提前完善系统。 + +*注:一致性关注的是系统呈现的状态,并不关注结果是否正确;例如,所有节点都对某请求达成否定状态也是一种一致性。* + +### 问题挑战 + +计算机固然很快,但在很多地方都比人类世界脆弱的多。典型的,在分布式系统中,存在不少挑战: + +* 节点完成请求的时间无法保障,处理的结果可能是错误的,甚至节点自身随时可能发生故障; +* 为了实现可扩展性,集群往往要采用异步设计,依靠网络消息交互,意味着不可预测的通信延迟、丢失或错误。 + +仍以火车票售卖问题为例,愿意动脑筋的读者可能已经想到了一些不错的解决思路,例如: + +* 要出售任意一张票前,先打电话给其他售票处,确认下当前这张票不冲突。即退化为同步调用来避免冲突; +* 多个售票处提前约好隔离的售票时间。比如第一家可以在上午 8 点到 9 点期间卖票,接下来一个小时是另外一家……即通过令牌机制来避免冲突; +* 成立一个第三方的存票机构,票集中存放,每次卖票前找存票机构查询。此时问题退化为中心化中介机制。 + +这些思路假设售票处都能保证正常工作,并且消息传递不会出现错误。 + +当然,还可以设计出更多更完善的方案,但它们背后的核心思想,都是**将可能引发不一致的并行操作进行串行化**。这实际上也是现代分布式系统处理一致性问题的基础思路。另外,由于普通计算机硬件和软件的可靠性不足,在工程实现上还要对核心部件稳定性进行加强。 + +反过来,如果节点都很鲁棒,性能足够强,同时网络带宽足够大、延迟足够低,这样的集群系统往往更容易实现一致性。 + +然而,真实情况可能比人们预期的糟糕。2015年,论文《Taming Uncertainty in Distributed Systems with Help from the Network》中指出,即便部署了专业设备和冗余网络的中等规模的数据中心,每个月发生的网络故障高达 12 次。 + +### 一致性的要求 + +规范来看,分布式系统达成一致的过程,应该满足: + +* 可终止性(Termination):一致的结果在有限时间内能完成; +* 约同性(Agreement):不同节点最终完成决策的结果是相同的; +* 合法性(Validity):决策的结果必须是某个节点提出的提案。 + +可终止性很容易理解。有限时间内完成,意味着可以保障提供服务(Liveness)。这是计算机系统可以被正常使用的前提。需要注意,在现实生活中这点并不是总能得到保障的。例如取款机有时候会出现“服务中断”;拨打电话有时候是“无法连接”的。 + +约同性看似容易,实际上暗含了一些潜在信息。决策的结果相同,意味着算法要么不给出结果,任何给出的结果必定是达成了共识的,即安全性(Safety)。挑战在于算法必须要考虑的是可能会处理任意的情形。凡事一旦推广到任意情形,往往就不像看起来那么简单。例如现在就剩一张某区间(如北京 --> 南京)的车票了,两个售票处也分别刚通过某种方式确认过这张票的存在。这时,两家售票处几乎同时分别来了一个乘客要买这张票,从各自“观察”看来,自己一方的乘客都是先到的……这种情况下,怎么能达成对结果的共识呢?看起来很容易,卖给物理时间上率先提交请求的乘客即可。然而,对于两个来自不同位置的请求来说,要判断在时间上的“先后”关系并不是那么容易。两个车站的时钟时刻可能是不一致的;时钟计时可能不精确的……根据相对论的观点,不同空间位置的时间是不一致的。因此追求绝对时间戳的方案是不可行的,能做的是要对事件的发生进行排序。 + +事件发生的相对先后顺序(逻辑时钟)十分重要,确定了顺序,就没有了分歧。这也是解决分布式系统领域很多问题的核心秘诀:**把不同时空发生的多个事件进行全局唯一排序,而且这个顺序还得是大家都认可的**。 + +如果存在可靠的物理时钟,实现排序往往更为简单。高精度的石英钟的漂移率为 $$10^{-7}$$,最准确的原子震荡时钟的漂移率为 $$10^{-13}$$。Google 曾在其分布式数据库 Spanner 中采用基于原子时钟和 GPS 的“TrueTime”方案,能够将不同数据中心的时间偏差控制在 10ms 置信区间。在不考虑成本的前提下,这种方案简单、有效。然而,计算机系统的时钟误差要大得多,这就造成分布式系统达成一致顺序十分具有挑战。 + +*注:Leslie Lamport 在 1978 年发表的论文《Time, Clocks and the Ordering of Events in a Distributed System》中将分布式系统中顺序与相对论进行对比,提出了偏序关系的观点。而根据相对论,并不存在绝对的时间。因此,先后顺序可能更有意义。* + +最后的合法性看似绕口,但其实比较容易理解,即达成的结果必须是节点执行操作的结果。仍以卖票为例,如果两个售票处分别决策某张票出售给张三和李四,那么最终达成一致的结果要么是张三,要么是李四,而不能是其他人。 + +### 带约束的一致性 +从前面的分析可以看出,要实现理想的严格一致性(Strict Consistency)代价很大。除非系统所有节点都不发生任何故障,而且节点间通信没有延迟,此时整个系统等价于一台机器。实际上,实现较强的一致性要求同步操作,容错性差,同时会牺牲部分性能和可扩展性。实际系统往往会选择不同强度的一致性,主要包括强一致性(Strong Consistency)和弱一致性(Weak Consistency)两大类。 + +强一致性主要包括顺序一致性([Sequential Consistency](https://en.wikipedia.org/wiki/Sequential_consistency))和线性一致性([Linearizability Consistency](https://en.wikipedia.org/wiki/Linearizability): + +* 顺序一致性:又叫因果一致性,最早由 Leslie Lamport 1979 年经典论文《How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs》中提出,是一种较强的约束。所有进程看到的全局执行顺序(total order)一致(否则数据副本就不一致了);并且每个进程看自身操作的顺序(local order)跟实际发生顺序一致。例如,某进程先执行 A,后执行 B,则实际得到的全局结果(其它进程也看到这个结果)中就应该为 A 在 B 前面,而不能反过来。如果另一个进程先后执行了C、D操作,则全局顺序可以共识为 A、B、C、D 或 A、C、B、D 或 C、A、B、D 或 C、D、A、B 的一种(即 A、B 和 C、D 的组合),决不能出现 B、A 或 D、C。顺序一致性实际上限制了各进程自身指令的偏序关系,但不需要在进程间按照物理时间进行全局排序,属于实践中应用较多的强一致性。以算盘为例,每个进程的事件是某根横轴上的算珠,它们可以前后拨动(改变不同进程之间先后顺序),但同一个横轴上的算珠的相对先后顺序无法改变。 +* 线性一致性:由 Maurice P. Herlihy 与 Jeannette M. Wing 在 1990 年经典论文《Linearizability: A Correctness Condition for Concurrent Objects》中共同提出,是最强的一致性。它在顺序一致性前提下增加了进程间的操作顺序要求,形成理想化完全一致的全局顺序。线性一致性要求系统看起来似乎只有一个数据副本,客户端操作都是原子的,并且顺序执行;所有进程的操作似乎是实时同步的,并且跟实际发生顺序一致。例如某个客户端写入成功,则其它客户端将立刻看到最新的值。线性一致性下所有进程的所有事件似乎都处于同一个横轴,存在唯一的先后顺序。线性一致性较难实现,目前基本上要么依赖于全局的时钟或锁,要么通过一些共识算法,性能往往不高。 + +强一致性比较难实现,很多场景下可以放宽对一致性的要求,采用部分异步操作,从而提升性能、可扩展性,降低响应延迟,这些在某些方面弱化的一致性都笼统称为弱一致性。例如互联网领域常用的最终一致性(Eventual Consistency),允许出现临时不一致或看到过时数据,但在经历一段时间后可以达到一致的状态。例如电商购物时将某物品放入购物车,但是可能在最终付款时才提示物品已经售罄了。 diff --git a/chainbrock-learning/04_distributed_system/summary.md b/chainbrock-learning/04_distributed_system/summary.md new file mode 100644 index 00000000..d30d7d3d --- /dev/null +++ b/chainbrock-learning/04_distributed_system/summary.md @@ -0,0 +1,7 @@ +## 本章小结 + +分布式系统是计算机学科中十分重要的一个领域。随着集群规模的不断增长,所处理的数据量越来越大,对于性能、可靠性的要求越来越高,分布式系统相关技术已经变得越来越重要,起到的作用也越来越关键。 + +分布式系统中如何保证共识是个经典问题,无论在学术上还是在工程上都存在很高的研究价值。令人遗憾的是,理想的(各项指标均最优)解决方案并不存在,在现实各种约束条件下,往往需要通过牺牲掉某些需求,来设计出满足特定场景的协议。通过本章的学习,读者可以体会到在工程应用中的类似设计技巧。 + +实际上,工程领域中不少问题都不存在一劳永逸的通用解法;而实用的解决思路都是合理地在实际需求和条件限制之间进行灵活的取舍(trade-off)。 diff --git a/chainbrock-learning/05_crypto/README.md b/chainbrock-learning/05_crypto/README.md new file mode 100644 index 00000000..51f83f42 --- /dev/null +++ b/chainbrock-learning/05_crypto/README.md @@ -0,0 +1,7 @@ +# 密码学与安全技术 + +** 工程领域从来没有黑科技;密码学不仅是工程。 ** + +密码学作为核心的安全技术在信息科技领域的重要性无需多言。离开现代密码学和信息安全技术,人类社会将无法全面步入信息时代。区块链和分布式账本中大量使用了密码学和安全技术的最新成果,特别是身份认证和隐私保护相关技术。 + +从数学定理到工程实践,密码学和信息安全所涉及的知识体系十分繁杂。本章将介绍与区块链密切相关的安全知识,包括 Hash 算法与摘要、加密算法、数字签名和证书、PKI 体系、Merkle 树、布隆过滤器、同态加密等。通过本章,读者可以了解常见安全技术体系,以及如何实现信息安全的核心要素:机密性、完整性、可认证性和不可抵赖性,为后续理解区块链的设计奠定基础。 diff --git a/chainbrock-learning/05_crypto/_images/Merkle_tree.png b/chainbrock-learning/05_crypto/_images/Merkle_tree.png new file mode 100644 index 00000000..01dd48b2 Binary files /dev/null and b/chainbrock-learning/05_crypto/_images/Merkle_tree.png differ diff --git a/chainbrock-learning/05_crypto/_images/basic_flow.png b/chainbrock-learning/05_crypto/_images/basic_flow.png new file mode 100644 index 00000000..320172b8 Binary files /dev/null and b/chainbrock-learning/05_crypto/_images/basic_flow.png differ diff --git a/chainbrock-learning/05_crypto/_images/bloom_filter.png b/chainbrock-learning/05_crypto/_images/bloom_filter.png new file mode 100644 index 00000000..3d3b3d27 Binary files /dev/null and b/chainbrock-learning/05_crypto/_images/bloom_filter.png differ diff --git a/chainbrock-learning/05_crypto/_images/tls_handshake.png b/chainbrock-learning/05_crypto/_images/tls_handshake.png new file mode 100644 index 00000000..7613293e Binary files /dev/null and b/chainbrock-learning/05_crypto/_images/tls_handshake.png differ diff --git a/chainbrock-learning/05_crypto/algorithm.md b/chainbrock-learning/05_crypto/algorithm.md new file mode 100644 index 00000000..4ccf047e --- /dev/null +++ b/chainbrock-learning/05_crypto/algorithm.md @@ -0,0 +1,148 @@ +## 加解密算法 + +加解密算法是现代密码学核心技术,从设计理念和应用场景上可以分为两大基本类型:对称加密、非对称加密,如下表所示。 + +算法类型 | 特点 | 优势 | 缺陷 | 代表算法 +------ | --- | --- | --- | ------- +对称加密 | 加解密的密钥相同 | 计算效率高,加密强度高 | 需提前共享密钥,易泄露 | DES、3DES、AES、IDEA +非对称加密 | 加解密的密钥不相同 | 无需提前共享密钥 | 计算效率低,存在中间人攻击可能 | RSA、ElGamal、椭圆曲线算法 + +### 加解密系统基本组成 + +现代加解密系统的典型组件包括算法和密钥,密钥包括加密密钥、解密密钥。 + +其中,加解密算法自身是固定不变的,并且一般是公开可见的;密钥则是最关键的信息,需要安全地保存起来,甚至通过特殊硬件进行保护。一般来说,密钥需要在加密前按照特定算法随机生成,长度越长,则加密强度越大。 + +加解密的典型过程如下图所示。加密过程中,通过加密算法和加密密钥,对明文进行加密,获得密文;解密过程中,通过解密算法和解密密钥,对密文进行解密,获得明文。 + +![加解密的基本过程](_images/basic_flow.png) + +根据加解密过程中所使用的密钥是否相同,算法可以分为对称加密(Symmetric Cryptography,又称共有密钥加密,Common-key cryptography)和非对称加密(Asymmetric Cryptography,又称公钥加密,Public-key Cryptography)。两种模式适用于不同的需求,形成互补。某些场景下可以组合使用,形成混合加密机制。 + +### 对称加密算法 +对称加密算法,顾名思义,加密和解密过程的密钥是相同的。 + +该类算法优点是加解密效率(速度快,空间占用小)和加密强度都很高。 + +缺点是参与方需要提前持有密钥,一旦有人泄露则系统安全性被破坏;另外如何在不安全通道中提前分发密钥也是个问题,需要借助额外的 Diffie–Hellman 协商协议或非对称加密算法来实现。 + +对称密码从实现原理上可以分为两种:分组加密和序列加密。前者将明文切分为定长数据块作为基本加密单位,应用最为广泛。后者则每次只对一个字节或字符进行加密处理,且密码不断变化,只用在一些特定领域(如数字媒介的加密)。 + +**分组加密**的代表算法包括 DES、3DES、AES、IDEA 等。 + +* DES(Data Encryption Standard):经典的分组加密算法,最早是美国联邦信息处理标准(FIPS)在 1977 年采用(FIPS-46-3),将 64 位明文加密为 64 位的密文,其密钥长度为 64 位(包括 8 位校验码),现在已经很容易被暴力破解; +* 3DES:三重 DES 操作:加密 --> 解密 --> 加密,处理过程和加密强度优于 DES,但现在也被认为不够安全; +* AES(Advanced Encryption Standard):由美国国家标准研究所(NIST)采用,取代 DES 成为对称加密实现的标准,1997~2000 年 NIST 从 15 个候选算法中评选 Rijndael 算法(由比利时密码学家 Joan Daemon 和 Vincent Rijmen 发明)作为 AES,标准为 FIPS-197。AES 也是分组算法,分组长度为 128、192、256 位三种。AES 的优势在于处理速度快,整个过程可以数学化描述,目前尚未有有效的破解手段; +* IDEA(International Data Encryption Algorithm):1991 年由密码学家 James Massey 与来学嘉共同提出,设计类似于 3DES,密钥长度增加到 128 位,具有更好的加密强度。 + +**序列加密**又称流加密。1949 年,Claude Elwood Shannon(信息论创始人)首次证明,要实现绝对安全的完善保密性(Perfect Secrecy),可以通过“一次性密码本”的对称加密处理。即通信双方每次使用跟明文等长的随机密钥串对明文进行加密处理。序列密码采用了类似的思想,每次通过伪随机数生成器来生成伪随机密钥串。代表算法包括 RC4 等。 + +总结一下,对称加密算法适用于大量数据的加解密过程,不能用于签名场景,并且需要提前安全地分发密钥。 + +*注:分组加密每次只能处理固定长度的明文,因此对于过长的内容需要采用一定模式进行分割,《实用密码学》一书中推荐使用密文分组链(Cipher Block Chain,CBC,支持串行化加解密)、计数器(Counter,CTR,支持并行化加解密)等模式。* + +### 非对称加密算法 +非对称加密是现代密码学的伟大发明,它有效解决了对称加密需要安全分发密钥的问题。 + +顾名思义,非对称加密中,加密密钥和解密密钥是不同的,分别称为公钥(Public Key)和私钥(Private Key)。私钥一般通过随机数算法生成,公钥可以根据私钥生成。 + +其中,公钥一般是公开的,他人可获取的;私钥则是个人持有并且要严密保护,不能被他人获取。 + +非对称加密算法优点是公私钥分开,无需安全通道来分发密钥。缺点是处理速度(特别是生成密钥和解密过程)往往比较慢,一般比对称加解密算法慢 2~3 个数量级;同时加密强度也往往不如对称加密。 + +非对称加密算法的安全性往往基于数学问题,包括大数质因子分解、离散对数、椭圆曲线等经典数学难题。 + +代表算法包括:RSA、ElGamal、椭圆曲线、SM2 等系列算法。 + +* RSA:经典的公钥算法,1978 年由 Ron Rivest、Adi Shamir、Leonard Adleman 共同提出,三人于 2002 年因此获得图灵奖。算法利用了对大数进行质因子分解困难的特性,但目前还没有数学证明两者难度等价,或许存在未知算法可以绕过大数分解而进行解密。 +* ElGamal:由 Taher ElGamal 设计,利用了模运算下求离散对数困难的特性,比 RSA 产生密钥更快。被应用在 PGP 等安全工具中。 +* 椭圆曲线算法(Elliptic Curve Cryptography,ECC):应用最广也是强度最高的系列算法,基于对椭圆曲线上特定点进行特殊乘法逆运算(求离散对数)难以计算的特性。最早在 1985 年由 Neal Koblitz 和 Victor Miller 分别独立提出。ECC 系列算法具有多种国际标准(包括 ANSI X9.63、NIST FIPS 186-2、IEEE 1363-2000、ISO/IEC 14888-3 等),一般被认为具备较高的安全性,但加解密过程比较费时。其中,密码学家 Daniel J.Bernstein 于 2006 年提出的 Curve25519/Ed25519/X25519 等算法(分别解决加密、签名和密钥交换),由于其设计完全公开、性能突出等特点,近些年引起了广泛关注和应用。 +* SM2(ShangMi 2):中国国家商用密码系列算法标准,由中国密码管理局于 2010 年 12 月 17 日发布,同样基于椭圆曲线算法,一般认为其安全强度优于 RSA 系列算法。 + +非对称加密算法适用于签名场景或密钥协商过程,但不适于大量数据的加解密。除了 SM2 之外,大部分算法的签名速度要比验签速度慢(1~2个数量级)。 + +RSA 类算法被认为已经很难抵御现代计算设备的破解,一般推荐商用场景下密钥至少为 2048 位。如果采用安全强度更高的椭圆曲线算法,256 位密钥即可满足绝大部分安全需求。 + +#### 选择明文攻击 +细心的读者可能会想到,非对称加密中公钥是公开的,因此任何人都可以利用它加密给定明文,获取对应的密文,这就带来选择明文攻击的风险。 + +为了规避这种风险,现代的非对称加密算法(如 RSA、ECC)都引入了一定的保护机制:对同样的明文使用同样密钥进行多次加密,得到的结果完全不同,这就避免了选择明文攻击的破坏。 + +在实现上可以有多种思路。一种是对明文先进行变形,添加随机的字符串或标记,再对添加后结果进行处理。另外一种是先用随机生成的临时密钥对明文进行对称加密,然后再将对称密钥进行加密,即利用多层加密机制。 + +### 混合加密机制 + +混合加密机制同时结合了对称加密和非对称加密的优点。 + +该机制的主要过程为:先用非对称加密(计算复杂度较高)协商出一个临时的对称加密密钥(或称会话密钥),然后双方再通过对称加密算法(计算复杂度较低)对所传递的大量数据进行快速的加密处理。 + +典型的应用案例是网站中使用越来越普遍的通信协议 -- 安全超文本传输协议(Hyper Text Transfer Protocol Secure,HTTPS)。 + +与以明文方式传输数据的 HTTP 协议不同,HTTPS 在传统的 HTTP 层和 TCP 层之间引入 Transport Layer Security/Secure Socket Layer(TLS/SSL)加密层来实现安全传输。 + +SSL 协议是 HTTPS 初期采用的标准协议,最早由 Netscape 于 1994 年设计实现,其两个主要版本(包括 v2.0 和 v3.0)曾得到大量应用。SSL 存在安全缺陷易受攻击(如 POODLE 和 DROWN 攻击),无法满足现代安全需求,已于 2011 和 2015 年被 IETF 宣布废弃。基于 SSL 协议(v3.1),IETF 提出了改善的安全标准协议 TLS,成为目前广泛采用的方案。2008 年 8 月,TLS 1.2 版本(RFC 5246)发布,修正了之前版本的不少漏洞,极大增强了安全性;2018 年 8 月,TLS 1.3 版本(RFC 8446)发布,提高了握手性能同时增强了安全性。商用场景推荐使用这两个版本。除了 Web 服务外,TLS 协议也被广泛应用到 FTP、Email、实时消息、音视频通话等场景中。 + +采用 HTTPS 建立安全连接(TLS 握手协商过程)的基本步骤如下: + +![TLS 握手协商过程](_images/tls_handshake.png) + +1)客户端浏览器发送握手信息到服务器,包括随机数 R1、支持的加密算法套件(Cipher Suite)类型、协议版本、压缩算法等。注意该过程传输为明文。 +2)服务端返回信息,包括随机数 R2、选定加密算法套件、协议版本,以及服务器证书。注意该过程为明文。 +3)浏览器检查带有该网站公钥的证书。该证书需要由第三方 CA 来签发,浏览器和操作系统会预置权威 CA 的根证书。如果证书被篡改作假(中间人攻击),很容易通过 CA 的证书验证出来。 +4)如果证书没问题,则客户端用服务端证书中公钥加密随机数 R3(又叫 Pre-MasterSecret),发送给服务器。此时,只有客户端和服务器都拥有 R1、R2 和 R3 信息,基于随机数 R1、R2 和 R3,双方通过伪随机数函数来生成共同的对称会话密钥 MasterSecret。 +5)后续客户端和服务端的通信都通过协商后的对称加密(如 AES)进行保护。 + +可以看出,该过程是实现防止中间人窃听和篡改的前提下完成会话密钥的交换。为了保障前向安全性(Perfect Forward Secrecy),TLS 对每个会话连接都可以生成不同的密钥,避免某个会话密钥泄露后对其它会话连接产生安全威胁。需要注意,选用合适的加密算法套件对于 TLS 的安全性十分重要。要合理选择安全强度高的算法组合,如 ECDHE-RSA 和 ECDHE-ECDSA 等,而不要使用安全性较差的 DES/3DES 等。 + +示例中对称密钥的协商过程采用了 RSA 非对称加密算法,实践中也可以通过 Diffie–Hellman(DH)协议来完成。 + +加密算法套件包括一组算法,包括交换、认证、加密、校验等: + +* 密钥交换算法:负责协商对称密钥,常见类型包括 RSA、DH、ECDH、ECDHE 等; +* 证书签名算法:负责验证身份,常见类型包括 RSA、DSA、ECDSA 等; +* 加密数据算法:对建立连接的通信内容进行对称加密,常见类型包括 AES 等; +* 消息认证信息码(MAC)算法:创建报文摘要,验证消息的完整性,常见类型包括 SHA 等。 + +一个典型的 TLS 密码算法套件可能为 “TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384”,意味着: + +* 协商过程算法是 ECDHE(Elliptic Curve Diffie–Hellman Ephemeral),基于椭圆曲线的短期 EH 交换,每次交换都用新的密钥,保障前向安全性; +* 证书签名算法是 ECDSA(Elliptic Curve Digital Signature Algorithm),基于椭圆曲线的签名; +* 加密数据算法是 AES,密钥的长度和初始向量的长度都是 256,模式是 CBC; +* 消息认证信息码算法是 SHA,结果是 384 位。 + +目前,推荐选用如下的加密算法套件: + +* TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 +* TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 +* TLS_RSA_WITH_AES_256_GCM_SHA384 +* TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 +* TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 +* TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + +*注:TLS 1.0 版本已被发现存在安全漏洞,NIST、HIPAA 于 2014 年公开建议停用该版本的 TLS 协议。* + +### 离散对数与 Diffie–Hellman 密钥交换协议 + +Diffie–Hellman(DH)密钥交换协议是一个应用十分广泛的协议,最早由惠特菲尔德·迪菲(Bailey Whitfield Diffie)和马丁·赫尔曼(Martin Edward Hellman)于 1976 年提出。该协议可以实现在不安全信道中协商对称密钥。 + +DH 协议的设计基于著名的离散对数问题(Discrete Logarithm Problem,DLP)。离散对数问题是指对于一个很大的素数 p,已知 g 为 p 的模循环群的原根,给定任意 x,求解 X=g^x mod p 是可以很快获取的。但在已知 p,g 和 X 的前提下,逆向求解 x 很难(目前没有找到多项式时间实现的算法)。该问题同时也是 ECC 类加密算法的基础。 + +DH 协议的基本交换过程如下,以 Alice 和 Bob 两人协商为例: + +* Alice 和 Bob 两个人协商密钥,先公开商定 p,g; +* Alice 自行选取私密的整数 x,计算 X=g^x mod p,发送 X 给 Bob; +* Bob 自行选取私密的整数 y,计算 Y=g^y mod p,发送 Y 给 A; +* Alice 根据 x 和 Y,求解共同密钥 Z_A=Y^x mod p; +* Bob 根据 X 和 y,求解共同密钥 Z_B=X^y mod p。 + +实际上,Alice 和 Bob 计算出来的结果将完全相同,因为在 mod p 的前提下,Y^x =(g^y)^x =g^(xy) = (g^x)^y=X^y。而信道监听者在已知 p,g,X,Y 的前提下,无法求得 Z。 + +### 安全性 + +虽然很多加密算法的安全性建立在数学难题基础之上,但并非所有算法的安全性都可以从数学上得到证明。 + +公认高安全性的加密算法和实现往往是经过长时间充分实践论证后,才被大家所认可,但不代表其绝对不存在漏洞。使用方式和参数不当,也会造成安全强度下降。 + +另一方面,自行设计和发明的未经过大规模验证的加密算法是一种不太明智的行为。即便不公开算法加密过程,也很容易被分析和攻击,无法在安全性上得到足够保障。 + +实际上,现代密码学算法的安全性是通过数学难题来提供的,并非通过对算法自身的实现过程进行保密。 diff --git a/chainbrock-learning/05_crypto/bloom_filter.md b/chainbrock-learning/05_crypto/bloom_filter.md new file mode 100644 index 00000000..f4a566be --- /dev/null +++ b/chainbrock-learning/05_crypto/bloom_filter.md @@ -0,0 +1,27 @@ +## 布隆过滤器 + +布隆过滤器(Bloom Filter)是在 1970 年由 Burton Howard Bloom 在论文《Space/Time Trade-offs in Hash Coding with Allowable Errors》提出的。布隆过滤器是一种基于 Hash 的高效查找结构,能够快速(常数时间内)回答“某个元素是否在一个集合内”的问题。 + +该结构因为具有高效性而广泛应用到网络和安全领域,例如信息检索(BigTable 和 HBase)、垃圾邮件规则、注册管理等。 + +### 基于 Hash 的快速查找 + +在介绍布隆过滤器之前,先来看看基于 Hash 的快速查找算法。在前面的讲解中,我们提到,Hash 可以将任意内容映射到一个固定长度的字符串,而且不同内容映射到相同串的概率很低。因此,这就构成了一个很好的“内容 -> 索引”的生成关系。 + +试想,如果给定一个内容和存储数组,通过构造 Hash 函数,让映射后的 Hash 值总不超过数组的大小,则可以实现快速的基于内容的查找。例如,内容 “hello world” 的 Hash 值如果是 “100”,则存放到数组的第 100 个单元上去。如果需要快速查找任意内容,如 “hello world” 字符串是否在存储系统中,只需要将其在常数时间内计算 Hash 值,并用 Hash 值查看系统中对应元素即可。该系统“完美地”实现了常数时间内的查找。 + +然而,令人遗憾的是,当映射后的值限制在一定范围(如总数组的大小)内时,会发现 Hash 冲突的概率会变高,而且范围越小,冲突概率越大。很多时候,存储系统的大小又不能无限扩展,这就造成算法效率的下降。为了提高空间利用率,后来人们基于 Hash 算法的思想设计出了布隆过滤器结构。 + +### 更高效的布隆过滤器 + +![布隆过滤器](_images/bloom_filter.png) + +布隆过滤器采用了多个 Hash 函数来提高空间利用率。 + +对同一个给定输入来说,多个 Hash 函数计算出多个地址,分别在位串的这些地址上标记为 1。在查找时,进行同样的计算过程,并查看对应元素,如果都为 1,则说明较大概率是存在该输入。 + +布隆过滤器与单个 Hash 算法查找相比,大大提高了空间利用率,可以使用较少的空间来表示较大集合的存在关系。 + +实际上,无论是 Hash 还是布隆过滤器,基本思想是一致的,都是基于内容的编址。Hash 函数存在冲突,布隆过滤器也存在冲突,即这两种方法都存在着误报(False Positive)的情况,但绝对不会漏报(False Negative)。 + +布隆过滤器在应用中误报率往往很低,例如,在使用 7 个不同 Hash 函数的情况下,记录 100 万个数据,采用 2 MB 大小的位串,整体的误判率将低于 1%。而传统的 Hash 查找算法的误报率将接近 10%。 diff --git a/chainbrock-learning/05_crypto/cert.md b/chainbrock-learning/05_crypto/cert.md new file mode 100644 index 00000000..ca38ae46 --- /dev/null +++ b/chainbrock-learning/05_crypto/cert.md @@ -0,0 +1,116 @@ +## 数字证书 + +对于非对称加密算法和数字签名来说,很重要的步骤就是公钥的分发。理论上任何人都可以获取到公开的公钥。然而这个公钥文件有没有可能是伪造的呢?传输过程中有没有可能被篡改呢?一旦公钥自身出了问题,则整个建立在其上的的安全性将不复成立。 + +数字证书机制正是为了解决这个问题,它就像日常生活中的证书一样,可以确保所记录信息的合法性。比如证明某个公钥是某个实体(个人或组织)拥有,并且确保任何篡改都能被检测出来,从而实现对用户公钥的安全分发。 + +根据所保护公钥的用途,数字证书可以分为加密数字证书(Encryption Certificate)和签名验证数字证书(Signature Certificate)。前者往往用于保护用于加密用途的公钥;后者则保护用于签名用途的公钥。两种类型的公钥也可以同时放在同一证书中。 + +一般情况下,证书需要由证书认证机构(Certification Authority,CA)来进行签发和背书。权威的商业证书认证机构包括 DigiCert、GlobalSign、VeriSign 等。用户也可以自行搭建本地 CA 系统,在私有网络中进行使用。 + +### X.509 证书规范 +一般的,一个数字证书内容可能包括证书域(证书的版本、序列号、签名算法类型、签发者信息、有效期、被签发主体、**签发的公开密钥**)、CA 对证书的签名算法和签名值等。 + +目前使用最广泛的标准为 ITU 和 ISO 联合制定的 X.509 的 v3 版本规范(RFC 5280),其中定义了如下证书信息域: + +* 版本号(Version Number):规范的版本号,目前为版本 3,值为 0x2; +* 序列号(Serial Number):由 CA 维护的为它所颁发的每个证书分配的唯一的序列号,用来追踪和撤销证书。只要拥有签发者信息和序列号,就可以唯一标识一个证书。最大不能超过 20 个字节; +* 签名算法(Signature Algorithm):数字签名所采用的算法,如 sha256WithRSAEncryption 或 ecdsa-with-SHA256; +* 颁发者(Issuer):颁发证书单位的信息,如 “C=CN, ST=Beijing, L=Beijing, O=org.example.com, CN=ca.org.example.com”; +* 有效期(Validity):证书的有效期限,包括起止时间(如 Not Before 2018-08-08-00-00UTC,Not After 2028-08-08-00-00UTC); +* 被签发主体(Subject):证书拥有者的标识信息(Distinguished Name),如 “C=CN, ST=Beijing, L=Beijing, CN=personA.org.example.com”; +* 主体的公钥信息(Subject Public Key Info):所保护的公钥相关的信息; + * 公钥算法(Public Key Algorithm):公钥采用的算法; + * 主体公钥(Subject Public Key):公钥的内容; +* 颁发者唯一号(Issuer Unique Identifier,可选):代表颁发者的唯一信息,仅 2、3 版本支持,可选; +* 主体唯一号(Subject Unique Identifier,可选):代表拥有证书实体的唯一信息,仅 2、3 版本支持,可选; +* 扩展(Extensions,可选):可选的一些扩展。可能包括: + * Subject Key Identifier:实体的密钥标识符,区分实体的多对密钥; + * Basic Constraints:一般指明该证书是否属于某个 CA; + * Authority Key Identifier:颁发这个证书的颁发者的公钥标识符; + * Authority Information Access:颁发相关的服务地址,如颁发者证书获取地址和吊销证书列表信息查询地址; + * CRL Distribution Points:证书注销列表的发布地址; + * Key Usage: 表明证书的用途或功能信息,如 Digital Signature、Key CertSign; + * Subject Alternative Name:证书身份实体的别名,如该证书可以同样代表 *.org.example.com,org.example.com,*.example.com,example.com 身份等。 + +此外,证书的颁发者还需要对证书内容利用自己的私钥进行签名,以防止他人篡改证书内容。 + +### 证书格式 + +X.509 规范中一般推荐使用 PEM(Privacy Enhanced Mail)格式来存储证书相关的文件。证书文件的文件名后缀一般为 `.crt` 或 `.cer`,对应私钥文件的文件名后缀一般为 `.key`,证书请求文件的文件名后缀为 `.csr`。有时候也统一用 `.pem` 作为文件名后缀。 + +PEM 格式采用文本方式进行存储,一般包括首尾标记和内容块,内容块采用 base64 编码。 + +例如,一个示例证书文件的 PEM 格式如下所示: + +``` +-----BEGIN CERTIFICATE----- +MIICMzCCAdmgAwIBAgIQIhMiRzqkCljq3ZXnsl6EijAKBggqhkjOPQQDAjBmMQsw +CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy +YW5jaXNjbzEUMBIGA1UEChMLZXhhbXBsZS5jb20xFDASBgNVBAMTC2V4YW1wbGUu +Y29tMB4XDTE3MDQyNTAzMzAzN1oXDTI3MDQyMzAzMzAzN1owZjELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x +FDASBgNVBAoTC2V4YW1wbGUuY29tMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMG +ByqGSM49AgEGCCqGSM49AwEHA0IABCkIHZ3mJCEPbIbUdh/Kz3zWW1C9wxnZOwfy +yrhr6aHwWREW3ZpMWKUcbsYup5kbouBc2dvMFUgoPBoaFYJ9D0SjaTBnMA4GA1Ud +DwEB/wQEAwIBpjAZBgNVHSUEEjAQBgRVHSUABggrBgEFBQcDATAPBgNVHRMBAf8E +BTADAQH/MCkGA1UdDgQiBCBIA/DmemwTGibbGe8uWjt5hnlE63SUsXuNKO9iGEhV +qDAKBggqhkjOPQQDAgNIADBFAiEAyoMO2BAQ3c9gBJOk1oSyXP70XRk4dTwXMF7q +R72ijLECIFKLANpgWFoMoo3W91uzJeUmnbJJt8Jlr00ByjurfAvv +-----END CERTIFICATE----- +``` + +可以通过 openssl 工具来查看其内容。 + +```bash +# openssl x509 -in example.com-cert.pem -noout -text +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 22:13:22:47:3a:a4:0a:58:ea:dd:95:e7:b2:5e:84:8a + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=US, ST=California, L=San Francisco, O=example.com, CN=example.com + Validity + Not Before: Apr 25 03:30:37 2017 GMT + Not After : Apr 23 03:30:37 2027 GMT + Subject: C=US, ST=California, L=San Francisco, O=example.com, CN=example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:29:08:1d:9d:e6:24:21:0f:6c:86:d4:76:1f:ca: + cf:7c:d6:5b:50:bd:c3:19:d9:3b:07:f2:ca:b8:6b: + e9:a1:f0:59:11:16:dd:9a:4c:58:a5:1c:6e:c6:2e: + a7:99:1b:a2:e0:5c:d9:db:cc:15:48:28:3c:1a:1a: + 15:82:7d:0f:44 + ASN1 OID: prime256v1 + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + Any Extended Key Usage, TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 48:03:F0:E6:7A:6C:13:1A:26:DB:19:EF:2E:5A:3B:79:86:79:44:EB:74:94:B1:7B:8D:28:EF:62:18:48:55:A8 + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:ca:83:0e:d8:10:10:dd:cf:60:04:93:a4:d6: + 84:b2:5c:fe:f4:5d:19:38:75:3c:17:30:5e:ea:47:bd:a2:8c: + b1:02:20:52:8b:00:da:60:58:5a:0c:a2:8d:d6:f7:5b:b3:25: + e5:26:9d:b2:49:b7:c2:65:af:4d:01:ca:3b:ab:7c:0b:ef +``` + +此外,还有 DER(Distinguished Encoding Rules)格式,是采用二进制对证书进行保存,可以与 PEM 格式互相转换。 + +### 证书信任链 + +证书中记录了大量信息,其中最重要的包括 `签发的公开密钥` 和 `CA 数字签名` 两个信息。因此,只要使用 CA 的公钥再次对这个证书进行签名比对,就能证明所记录的公钥是否合法。 + +读者可能会想到,怎么证明用来验证对实体证书进行签名的 CA 公钥自身是否合法呢?毕竟在获取 CA 公钥的过程中,它也可能被篡改掉。 + +实际上,CA 的公钥是否合法,一方面可以通过更上层的 CA 颁发的证书来进行认证;另一方面某些根 CA(Root CA)可以通过预先分发证书来实现信任基础。例如,主流操作系统和浏览器里面,往往会提前预置一些权威 CA 的证书(通过自身的私钥签名,系统承认这些是合法的证书)。之后所有基于这些 CA 认证过的中间层 CA(Intermediate CA)和后继 CA 都会被验证合法。这样就从预先信任的根证书,经过中间层证书,到最底下的实体证书,构成一条完整的证书信任链。 + +某些时候用户在使用浏览器访问某些网站时,可能会被提示是否信任对方的证书。这说明该网站证书无法被当前系统中的证书信任链进行验证,需要进行额外检查。另外,当信任链上任一证书不可靠时,则依赖它的所有后继证书都将失去保障。 + +可见,证书作为公钥信任的基础,对其生命周期进行安全管理十分关键。后面章节将介绍的 PKI 体系提供了一套完整的证书管理的框架,包括生成、颁发、撤销过程等。 diff --git a/chainbrock-learning/05_crypto/hash.md b/chainbrock-learning/05_crypto/hash.md new file mode 100644 index 00000000..f52dd278 --- /dev/null +++ b/chainbrock-learning/05_crypto/hash.md @@ -0,0 +1,64 @@ +## Hash 算法与数字摘要 + +### 定义 +Hash(哈希或散列)算法,又常被称为指纹(fingerprint)或摘要(digest)算法,是非常基础也非常重要的一类算法。可以将任意长度的二进制明文串映射为较短的(通常是固定长度的)二进制串(Hash 值),并且不同的明文很难映射为相同的 Hash 值。 + +例如计算 “hello blockchain world, this is yeasy@github” 的 SHA-256 Hash 值。 + +```bash +$ echo "hello blockchain world, this is yeasy@github"|shasum -a 256 +db8305d71a9f2f90a3e118a9b49a4c381d2b80cf7bcef81930f30ab1832a3c90 +``` + +对于某个文件,无需查看其内容,只要其 SHA-256 Hash 计算后结果同样为 `db8305d71a9f2f90a3e118a9b49a4c381d2b80cf7bcef81930f30ab1832a3c90`,则说明文件内容(极大的概率)就是 “hello blockchain world, this is yeasy@github”。 + +除了快速对比内容外,Hash 思想也经常被应用到基于内容的编址或命名算法中。 + +一个优秀的 Hash 算法,将能满足: + +* 正向快速:给定原文和 Hash 算法,在有限时间和有限资源内能计算得到 Hash 值; +* 逆向困难:给定(若干)Hash 值,在有限时间内无法(基本不可能)逆推出原文; +* 输入敏感:原始输入信息发生任何改变,新产生的 Hash 值都应该发生很大变化; +* 碰撞避免:很难找到两段内容不同的明文,使得它们的 Hash 值一致(即发生碰撞)。 + +碰撞避免有时候又被称为“抗碰撞性”,可分为“弱抗碰撞性”和“强抗碰撞性”。给定原文前提下,无法找到与之碰撞的其它原文,则算法具有“弱抗碰撞性”;更一般地,如果无法找到任意两个可碰撞的原文,则称算法具有“强抗碰撞性”。 + +很多场景下,也往往要求算法对于任意长的输入内容,输出为定长的 Hash 结果。 + +### 常见算法 + +目前常见的 Hash 算法包括国际上的 Message Digest(MD)系列和 Secure Hash Algorithm(SHA)系列算法,以及国内的 SM3 算法。 + +MD 算法主要包括 MD4 和 MD5 两个算法。MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,其输出为 128 位。MD4 已证明不够安全。MD5(RFC 1321)是 Rivest 于 1991 年对 MD4 的改进版本。它对输入仍以 512 位进行分组,其输出是 128 位。MD5 比 MD4 更加安全,但过程更加复杂,计算速度要慢一点。MD5 已于 2004 年被成功碰撞,其安全性已不足应用于商业场景。 + +SHA 算法由美国国家标准与技术院(National Institute of Standards and Technology,NIST)征集制定。首个实现 SHA-0 算法于 1993 年问世,1998 年即遭破解。随后的修订版本 SHA-1 算法在 1995 年面世,它的输出为长度 160 位的 Hash 值,安全性更好。SHA-1 设计采用了 MD4 算法类似原理。SHA-1 已于 2005 年被成功碰撞,意味着无法满足商用需求。 + +为了提高安全性,NIST 后来制定出更安全的 SHA-224、SHA-256、SHA-384 和 SHA-512 算法(统称为 SHA-2 算法)。新一代的 SHA-3 相关算法也正在研究中。 + +此外,中国密码管理局于 2010 年 12 月 17 日发布了 GM/T 0004-2012 《SM3 密码杂凑算法》,建立了国内商用密码体系中的公开 Hash 算法标准,已经被广泛应用在数字签名和认证等场景中。 + +*注:MD5 和 SHA-1 算法的破解工作都是由清华大学教授、中国科学院院士王小云主导完成。* + +### 性能 + +大多数 Hash 算法都是计算敏感型算法,在强大的计算芯片上完成得更快。因此要提升 Hash 计算的性能可以考虑硬件加速。例如采用普通 FPGA 来计算 SHA-256 值,可以轻易达到数 Gbps 的吞吐量,使用专用芯片吞吐量甚至会更高。 + +也有一些 Hash 算法不是计算敏感型的。例如 scrypt 算法,计算过程需要大量的内存资源,因此很难通过选用高性能芯片来加速 Hash 计算。这样的算法可以有效防范采用专用芯片进行算力攻击。 + +### 数字摘要 +数字摘要是 Hash 算法重要用途之一。顾名思义,数字摘要是对原始的数字内容进行 Hash 运算,获取唯一的摘要值。 + +利用 Hash 函数抗碰撞性特点,数字摘要可以检测内容是否被篡改过。 + +细心的读者可能会注意到,有些网站在提供文件下载时,会同时提供相应的数字摘要值。用户下载原始文件后可以在本地自行计算摘要值,并与所提供摘要值进行比对,以确保文件内容没有被篡改过。 + +### Hash 攻击与防护 +Hash 算法并不是一种加密算法,不能用于对信息的保护。 + +但 Hash 算法可被应用到对登录口令的保存上。例如网站登录时需要验证用户名和密码,如果网站后台直接保存用户的口令原文,一旦发生数据库泄露后果不堪设想(事实上,网站数据库泄露事件在国内外都不少见)。 + +利用 Hash 的防碰撞特性,后台数据库可以仅保存用户口令的 Hash 值,这样每次通过 Hash 值比对,即可判断输入口令是否正确。即便数据库泄露了,攻击者也无法轻易从 Hash 值还原出口令。 + +然而,有时用户设置口令的安全强度不够,采用了一些常见的字符串,如 password、123456 等。有人专门搜集了这些常见口令,计算对应的 Hash 值,制作成字典。这样通过 Hash 值可以快速反查到原始口令。这一类型以空间换时间的攻击方法包括字典攻击和彩虹表攻击(只保存一条 Hash 链的首尾值,相对字典攻击可以节省存储空间)等。 + +为了防范这一类攻击,可以采用加盐(Salt)的方法。保存的不是原文的直接 Hash 值,而是原文再加上一段随机字符串(即“盐”)之后的 Hash 值。Hash 结果和“盐”分别存放在不同的地方,这样只要不是两者同时泄露,攻击者就很难进行破解。 diff --git a/chainbrock-learning/05_crypto/history.md b/chainbrock-learning/05_crypto/history.md new file mode 100644 index 00000000..fb2fd211 --- /dev/null +++ b/chainbrock-learning/05_crypto/history.md @@ -0,0 +1,21 @@ +## 密码学简史 + +从历史角度看,密码学可以大致分为古典密码学和近现代密码学两个阶段。两者以现代信息技术的诞生为分界点,现在所讨论的密码学多是指后者,建立在信息论和数学成果基础之上。 + +古典密码学源自数千年前。最早在公元前 1900 年左右的古埃及,就出现过使用特殊字符和简单替换式密码来保护信息。美索不达米亚平原上曾出土一个公元前 1500 年左右的泥板,其上记录了加密描述的陶器上釉工艺配方。古希腊时期(公元前 800 ~ 前 146 年)还发明了通过物理手段来隐藏信息的“隐写术”,例如使用牛奶书写、用蜡覆盖文字等。后来在古罗马时期还出现了基于替换加密的凯撒密码,据称凯撒曾用此方法与其部下通信而得以命名。 + +这些手段多数是采用简单的机械工具来保护秘密,在今天看来毫无疑问是十分简陋,很容易破解的。严格来看,可能都很难称为密码科学。 + +近现代密码的研究源自第一、二次世界大战中对军事通信进行保护和破解的需求。 + +1901 年 12 月,意大利工程师 Guglielmo Marconi(奎里亚摩·马可尼)成功完成了跨越大西洋的无线电通信实验,在全球范围内引发轰动,推动了无线电通信时代的带来。无线电极大提高了远程通信的能力,但存在着天然缺陷——它很难限制接收方,这意味着要想保护所传递信息的安全,必须采用可靠的加密技术。 + +对无线电信息进行加密以及破解的过程直接促进了近现代密码学和计算机技术的出现。反过来,这些科技进步也影响了时代的发展。一战时期德国外交部长 Arthur Zimmermann(阿瑟·齐默尔曼)拉拢墨西哥构成抗美军事同盟的电报(1917 年 1 月 16 日)被英国情报机构 —— 40 号办公室破译,直接导致了美国的参战;二战时期德国使用的恩尼格玛(Enigma)密码机(当时最先进的加密设备)被盟军成功破译(1939 年到 1941 年),导致大西洋战役德国失败。据称,二战时期光英国从事密码学研究的人员就达到 7000 人,而他们的成果使二战结束的时间至少提前了一到两年时间。 + +1945 年 9 月 1 日,Claude Elwood Shannon(克劳德·艾尔伍德·香农)完成了划时代的内部报告《A Mathematical Theory of Cryptography(密码术的一个数学理论)》,1949 年 10 月,该报告以《Communication Theory of Secrecy Systems(保密系统的通信理论)》为题在 Bell System Technical Journal(贝尔系统技术期刊)上正式发表。这篇论文首次将密码学和信息论联系到一起,为对称密码技术提供了数学基础。这也标志着近现代密码学的正式建立。 + +1976 年 11 月,Whitfield Diffie 和 Martin E.Hellman 在 IEEE Transactions on Information Theory 上发表了论文《New Directions in Cryptography(密码学的新方向)》,探讨了无需传输密钥的保密通信和签名认证体系问题,正式开创了现代公钥密码学体系的研究。 + +现代密码学的发展与电气技术特别是计算机信息理论和技术关系密切,已经发展为包括随机数、Hash 函数、加解密、身份认证等多个课题的庞大领域,相关成果为现代信息系统特别是互联网奠定了坚实的安全基础。 + +*注:Enigma 密码机的加密消息在当年需要数年时间才能破解,而今天使用最新的人工智能技术进行破译只需要 10 分钟左右。* \ No newline at end of file diff --git a/chainbrock-learning/05_crypto/homoencryption.md b/chainbrock-learning/05_crypto/homoencryption.md new file mode 100644 index 00000000..26851708 --- /dev/null +++ b/chainbrock-learning/05_crypto/homoencryption.md @@ -0,0 +1,43 @@ +## 同态加密 + +### 定义 + +同态加密(Homomorphic Encryption)是一种特殊的加密方法,允许对密文进行处理得到仍然是加密的结果。即对密文直接进行处理,跟对明文进行处理后再对处理结果加密,得到的结果相同。从抽象代数的角度讲,保持了同态性。 + +同态加密可以保证实现处理者无法访问到数据自身的信息。 + +如果定义一个运算符 $$\triangle{}$$,对加密算法 `E` 和 解密算法 `D`,满足: + +$$E(X\triangle{}Y) = E(X)\triangle{} E(Y)$$ + +则意味着对于该运算满足同态性。 + +同态性来自代数领域,一般包括四种类型:加法同态、乘法同态、减法同态和除法同态。同时满足加法同态和乘法同态,则意味着是代数同态,即全同态(Full Homomorphic)。同时满足四种同态性,则被称为算数同态。 + +对于计算机操作来讲,实现了全同态意味着对于所有处理都可以实现同态性。只能实现部分特定操作的同态性,被称为特定同态(Somewhat Homomorphic)。 + +### 问题与挑战 + +同态加密的问题最早在 1978 年由 Ron Rivest、Leonard Adleman 和 Michael L. Dertouzos 提出(同年 Ron Rivest、Adi Shamir 和 Leonard Adleman 还共同发明了 RSA 算法)。但第一个“全同态”的算法直到 2009 年才被克雷格·金特里(Craig Gentry)在论文《Fully Homomorphic Encryption Using Ideal Lattices》中提出并进行数学证明。 + +仅满足加法同态的算法包括 Paillier 和 Benaloh 算法;仅满足乘法同态的算法包括 RSA 和 ElGamal 算法。 + +同态加密在云计算和大数据的时代意义十分重大。目前,虽然云计算带来了包括低成本、高性能和便捷性等优势,但从安全角度讲,用户还不敢将敏感信息直接放到第三方云上进行处理。如果有了比较实用的同态加密技术,则大家就可以放心地使用各种云服务了,同时各种数据分析过程也不会泄露用户隐私。加密后的数据在第三方服务处理后得到加密后的结果,这个结果只有用户自身可以进行解密,整个过程第三方平台无法获知任何有效的数据信息。 + +另一方面,对于区块链技术,同态加密也是很好的互补。使用同态加密技术,运行在区块链上的智能合约可以处理密文,而无法获知真实数据,极大的提高了隐私安全性。 + +目前全同态的加密方案主要包括如下三种类型: + +* 基于理想格(ideal lattice)的方案:Gentry 和 Halevi 在 2011 年提出的基于理想格的方案可以实现 72 bit 的安全强度,对应的公钥大小约为 2.3 GB,同时刷新密文的处理时间需要几十分钟。 +* 基于整数上近似 GCD 问题的方案:Dijk 等人在 2010 年提出的方案(及后续方案)采用了更简化的概念模型,可以降低公钥大小至几十 MB 量级。 +* 基于带扰动学习(Learning With Errors,LWE)问题的方案:Brakerski 和 Vaikuntanathan 等在 2011 年左右提出了相关方案;Lopez-Alt A 等在 2012 年设计出多密钥全同态加密方案,接近实时多方安全计算的需求。 + +目前,已知的同态加密技术往往需要较高的计算时间或存储成本,相比传统加密算法的性能和强度还有差距,但该领域关注度一直很高,笔者相信,在不远的将来会出现接近实用的方案。 + +### 函数加密 +与同态加密相关的一个问题是函数加密。 + +同态加密保护的是数据本身,而函数加密顾名思义保护的是处理函数本身,即让第三方看不到处理过程的前提下,对数据进行处理。 + +该问题已被证明不存在对多个通用函数的任意多密钥的方案,目前仅能做到对某个特定函数的一个密钥的方案。 + diff --git a/chainbrock-learning/05_crypto/merkle_trie.md b/chainbrock-learning/05_crypto/merkle_trie.md new file mode 100644 index 00000000..8f5e2e88 --- /dev/null +++ b/chainbrock-learning/05_crypto/merkle_trie.md @@ -0,0 +1,40 @@ +## Merkle 树结构 + +[默克尔树](https://en.wikipedia.org/wiki/Merkle_tree)(又叫哈希树)是一种典型的二叉树结构,由一个根节点、一组中间节点和一组叶节点组成。默克尔树最早由 Merkle Ralf 在 1980 年提出,曾广泛用于文件系统和 P2P 系统中。 + +其主要特点为: + +* 最下面的叶节点包含存储数据或其哈希值; +* 非叶子节点(包括中间节点和根节点)都是它的两个孩子节点内容的哈希值。 + +进一步地,默克尔树可以推广到多叉树的情形,此时非叶子节点的内容为它所有的孩子节点的内容的哈希值。 + +默克尔树逐层记录哈希值的特点,让它具有了一些独特的性质。例如,底层数据的任何变动,都会传递到其父节点,一层层沿着路径一直到树根。这意味树根的值实际上代表了对底层所有数据的“数字摘要”。 + +目前,默克尔树的典型应用场景包括如下几种。 + +### 证明某个集合中存在或不存在某个元素 + +通过构建集合的默克尔树,并提供该元素各级兄弟节点中的 Hash 值,可以不暴露集合完整内容而证明某元素存在。 + +另外,对于可以进行排序的集合,可以将不存在元素的位置用空值代替,以此构建稀疏默克尔树(Sparse Merkle Tree)。该结构可以证明某个集合中不包括指定元素。 + +### 快速比较大量数据 + +对每组数据排序后构建默克尔树结构。当两个默克尔树根相同时,则意味着所代表的两组数据必然相同。否则,必然不同。 + +由于 Hash 计算的过程可以十分快速,预处理可以在短时间内完成。利用默克尔树结构能带来巨大的比较性能优势。 + +### 快速定位修改 + +以下图为例,基于数据 D0……D3 构造默克尔树,如果 D1 中数据被修改,会影响到 N1,N4 和 Root。 + +![Merkle 树示例](_images/Merkle_tree.png) + +因此,一旦发现某个节点如 Root 的数值发生变化,沿着 Root --> N4 --> N1,最多通过 O(lgN) 时间即可快速定位到实际发生改变的数据块 D1。 + +### 零知识证明 + +仍以上图为例,如何向他人证明拥有某个数据 D0 而不暴露其它信息。挑战者提供随机数据 D1,D2 和 D3,或由证明人生成(需要加入特定信息避免被人复用证明过程)。 + +证明人构造如图所示的默克尔树,公布 N1,N5,Root。验证者自行计算 Root 值,验证是否跟提供值一致,即可很容易检测 D0 存在。整个过程中验证者无法获知与 D0 相关的额外信息。 diff --git a/chainbrock-learning/05_crypto/others.md b/chainbrock-learning/05_crypto/others.md new file mode 100644 index 00000000..1c47b955 --- /dev/null +++ b/chainbrock-learning/05_crypto/others.md @@ -0,0 +1,88 @@ +## 其它技术 + +密码学领域涉及到的技术还有许多,这里总结一些还在发展和探讨中的话题。 + +### 零知识证明 + +零知识证明(Zero Knowledge Proof),是这样的一个过程,证明者在不向验证者提供任何额外信息的前提下,使验证者相信某个论断(Statement)是正确的。 + +证明过程包括交互式(Interactive)和非交互式(Non-interactive)两种。 + +零知识证明的研究始于 Shafi Goldwasser,Silvio Micali 和 Charles Rackoff 在 1985 年提交的开创性论文《The Knowledge Complexity of Interactive Proof-Systems》,三位作者也因此在 1993 年获得首届哥德尔奖。 + +论文中提出了零知识证明要满足三个条件: + +* 完整性(Completeness):真实的证明可以让验证者成功验证; +* 可靠性(Soundness):虚假的证明无法保证通过验证。但理论上可以存在小概率例外; +* 零知识(Zero-Knowledge):如果得到证明,无法(或很难)从证明过程中获知除了所证明命题之外的任何信息,分为完美零知识、概率零知识两种。 + +交互式零知识证明相对容易构造,需要通过证明人和验证人之间一系列交互完成。一般为验证人提出一系列问题,证明人如果能都回答正确,则有较大概率确实知道论断。 + +例如,证明人 Alice 向验证人 Bob 证明两个看起来一样的图片有差异,并且自己能识别这个差异。Bob 将两个图片在 Alice 无法看到的情况下更换或保持顺序,再次让 Alice 识别是否顺序调整。如果 Alice 每次都能正确识别顺序是否变化,则 Bob 会以较大概率认可 Alice 的证明。此过程中,Bob 除了知道 Alice 确实能识别差异这个论断外,自己无法获知或推理出任何额外信息(包括该差异本身),也无法用 Alice 的证明(例如证明过程的录像)去向别人证明。注意这个过程中 Alice 如果提前猜测出 Bob 的更换顺序,则存在作假的可能性。 + +非交互式零知识证明(NIZK)则复杂的多。实际上,通用的非交互式完美或概率零知识证明(Proof)系统并不存在,但可以设计出计算安全的非交互式零知识论证(Argument)系统,具有广泛的应用价值。 + +Manuel Blum、Alfredo De Santis、Silvio Micali 和 Giuseppe Persiano 在 1991 年发表的论文《Noninteractive Zero-Knowledge》中提出了首个面向“二次非连续问题”的非交互的完美零知识证明(NIPZK)系统。 + +2012 年,Nir Bitansky、Ran Caneetti 等在论文《From extractable collision resistance to succinct non-interactive arguments of knowledge, and back again》中提出了实用的非交互零知识论证方案 zk-SNARKs,后来在 Z-cash 等项目中得到广泛应用。目前,进行非交互式零知识论证的主要思路为利用所证明论断创造一个难题(一般为 NP 完全问题如 SAT,某些情况下需要提前或第三方提供随机数作为参数)。如果证明人确实知道论断,即可在一定时间内解决该难题,否则很难解答难题。验证人可以通过验证答案来验证证明人是否知晓论断。 + +零知识证明如果要能普及,还需要接受实践检验,另外需要考虑减少甚至无需预备阶段计算、提高可扩展性,同时考虑抵御量子计算攻击。 + +### 可验证随机函数 + +可验证随机函数(Verifiable Random Function,VRF)最早由 Silvio Micali(麻省理工学院)、Michael Rabiny(哈佛大学)、Salil Vadha(麻省理工学院)于 1999 年在论文《Verifiable Random Functions》中提出。 + +它讨论的是一类特殊的伪随机函数,其结果可以在某些场景下进行验证。一般可以通过签名和哈希操作来构建。 + +例如,Alice 拥有公钥 Pk 和对应私钥 Sk。Alice 宣称某可验证随机函数 F 和一个输入 x,并计算 y = F(Sk, x)。Bob 可以使用 Alice 公钥 Pk,对同样的 x 和 F 进行验证,证明其结果确实为 y。注意该过程中,因为 F 的随机性,任何人都无法预测 y 的值。 + +可见,VRF 提供了一种让大家都认可并且可以验证的随机序列,可以用于分布式系统中进行投票的场景。 + +### 安全多方计算 + +安全多方计算(Secure Multi-Party Computation,SMPC 或 SMC)由 Andrew Chi-Chih Yao(姚期智)于 1986 年在论文《How to generate and exchange secrets》中提出。其假设的场景为多个参与方都拥有部分数据,在不泄露自己数据的前提下,实现利用多方的数据进行计算。这一问题在多方彼此互不信任而又需要进行某些合作时(如保护隐私的前提下进行数据协同),十分有用,有时候也被称为隐私保护计算(Privacy-preserving Computation)。 + +根据参与方的个数,可以分为双方计算或多方计算;根据实现方法,可以分为基于噪音(如 differential privacy,差分隐私)、基于秘密共享(Secret Sharing)、基于混淆电路(Garbled Circuit)和基于同态加密(Homomorphic Encryption)。 + +一般来说,基于噪音的方案容易实现,但使用场景局限,基于密码学技术的方案更通用,但往往需要较大计算成本。 + +### 不经意传输 + +不经意传输(Oblivious Transfer,OT)协议由 S. Even,O. Goldreich,A. Lempel 等人 1983 年在论文《A Randomized Protocol for Signing Contracts》中提出。后来应用在安全多方计算等场景下。 + +该协议所解决的问题是发送方将信息发送给接收方,但要保护双方的隐私:发送方无法获知接收方最终接收了哪些信息;接收方除了能获知自己所需的信息外,无法获得额外的信息。 + +例如,银行向征信公司查询某个客户的征信情况以决定是否进行贷款,银行不希望征信公司知道该客户来到该银行申请贷款(属于客户隐私),同时,征信公司不希望银行拿到其它客户的征信数据。 + +一种简单的实现是发送方发送 N 个公钥给接收方,接收方随机选择一个公钥加密一个对称密钥并将结果返回发送方。发送方分别用 N 个私钥进行解密,其中 1 个结果为对称密钥,N-1 个为随机串,但发送方无法区别。发送方用 N 个解密结果分别加密 1 条消息(共计 N 条)并返回给接收方。接收方只能解密其中 1 条消息。如果双方提前约定好 N 对结果进行盲化的随机串,接收方还可以挑选只接收某个特定信息。 + +另外一种简单实现是接收方提供 N 个随机串作为公钥,并证明自己只知道其中 K 个串对应的私钥。发送方采用这些随机串加密 N 个信息,然后发给接收方。这样,接收方只能解开其中的 K 条信息。 + +### 差分隐私 + +差分隐私(Differential Privacy)是一种相对实用的隐私保护机制。 + +最初问题是研究如何分享一个数据集而保护数据集中个体的隐私,在 2006 年由 Cynthia Dwork、Frank McSherry、 Kobbi Nissim 和 Adam Smith 在论文《Calibrating Noise to Sensitivity in Private Data Analysis》中提出。由于在隐私保护问题上的应用前景,近些年成为研究热点。 + +主要思想是在数据集中巧妙的添加一些噪音扰动,使得对修改后数据集进行计算不太影响统计结果,但无法将其中任意个体追溯回原始个体信息。例如,将数据集中删掉任意一条记录,查询结果不受影响。 + +目前可行的方案主要包括添加拉普拉斯噪音(适合于数值型)和指数噪音(适合于非数值型)等。 + +### 量子密码学 +量子密码学(Quantum Cryptography)随着量子计算和量子通信的研究而被受到越来越多的关注,被认为会在未来对已有的密码学安全机制产生较大的影响。 + +量子计算的概念最早是物理学家费曼于 1981 年提出,基本原理是利用量子比特可以同时处于多个相干叠加态,理论上可以同时用少量量子比特来表达大量的信息,并同时进行处理,大大提高计算速度。量子计算目前在某些特定领域已经展现出超越经典计算的潜力。如基于量子计算的 Shor 算法(1994 年提出),理论上可以实现远超经典计算速度的大数因子分解。2016 年 3 月,人类第一次以可扩展的方式,用 Shor 算法完成对数字 15 的质因数分解。 + +这意味着目前广泛应用的非对称加密算法,包括基于大整数分解的 RSA、基于椭圆曲线离散对数问题的 ECC 等将来都将很容易被破解。当然,现代密码学体系并不会因为量子计算的出现而崩溃。一方面,量子计算设备离实际可用的通用计算机还有较大距离,密码学家可以探索更安全的密码算法。另一方面,很多安全机制尚未发现能被量子算法攻破,包括基于 Hash 的数字签名、格(Lattice)密码、基于编码的密码,以及随机数生成和密钥派生等。 + +量子通信则可以提供对密钥进行安全协商的机制,有望实现无条件安全的“一次性密码”。量子通信基于量子纠缠效应,两个发生纠缠的量子可以进行远距离的实时状态同步。攻击者窃听信道时会改变量子状态,通信双方可以发现并选择丢弃此次传输的信息。该性质十分适合进行大量的密钥分发,如 1984 年提出的 BB84 协议,结合量子通道和公开信道,可以实现安全的密钥分发。但要注意,量子通信无法避免协议层面的攻击,如经典的中间人攻击,可以对通信双方发送不同的量子对,实现在不被发现的情况下窃听信息。此外,量子信道易受干扰,对传输环境要求很高。 + +*注:一次性密码:最早由香农提出,实现理论上绝对安全的对称加密。其特点为密钥真随机且只使用一次;密钥长度跟明文一致,加密过程为两者进行二进制异或操作。* + +### 社交工程学 + +密码学与安全问题,一直是学术界和工业界都十分关心的重要话题,相关的技术也一直在不断发展和完善。然而,**即便存在理论上完美的技术,也不存在完美的系统**。无数例子证实,看起来设计十分完善的系统最后被攻破,并非是因为设计上出现了深层次的漏洞。而问题往往出在事后看来十分浅显的一些方面。 + +例如,系统管理员将登陆密码贴到电脑前;财务人员在电话里泄露用户的个人敏感信息;公司职员随意运行来自不明邮件的附件;不明人员借推销或调查问卷的名义进入办公场所窃取信息…… + +著名计算机黑客和安全顾问 Kevin David Mitnick 曾在 15 岁时成功入侵北美空中防务指挥系统,在其著作《The Art of Deception》中揭示了大量通过社交工程学的手段轻易获取各种安全信息的案例。 diff --git a/chainbrock-learning/05_crypto/pki.md b/chainbrock-learning/05_crypto/pki.md new file mode 100644 index 00000000..9d7dfa68 --- /dev/null +++ b/chainbrock-learning/05_crypto/pki.md @@ -0,0 +1,128 @@ +## PKI 体系 + +按照 X.509 规范,公钥可以通过证书机制来进行保护,但证书的生成、分发、撤销等步骤并未涉及。 + +实际上,要实现安全地管理、分发证书需要遵循 PKI(Public Key Infrastructure)体系。该体系解决了证书生命周期相关的认证和管理问题。 + +需要注意,PKI 是建立在公私钥基础上实现安全可靠传递消息和身份确认的一个通用框架,并不代表某个特定的密码学技术和流程。实现了 PKI 规范的平台可以安全可靠地管理网络中用户的密钥和证书。目前包括多个具体实现和规范,知名的有 RSA 公司的 PKCS(Public Key Cryptography Standards)标准和 OpenSSL 等开源工具。 + +### PKI 基本组件 + +一般情况下,PKI 至少包括如下核心组件: + +* CA(Certification Authority):负责证书的颁发和吊销(Revoke),接收来自 RA 的请求,是最核心的部分; +* RA(Registration Authority):对用户身份进行验证,校验数据合法性,负责登记,审核过了就发给 CA; +* 证书数据库:存放证书,多采用 X.500 系列标准格式。可以配合LDAP 目录服务管理用户信息。 + +其中,CA 是最核心的组件,主要完成对证书信息的维护。 + +常见的操作流程为,用户通过 RA 登记申请证书,提供身份和认证信息等;CA 审核后完成证书的制造,颁发给用户。用户如果需要撤销证书则需要再次向 CA 发出申请。 + +### 证书的签发 + +CA 对用户签发证书实际上是对某个用户公钥,使用 CA 的私钥对其进行签名。这样任何人都可以用 CA 的公钥对该证书进行合法性验证。验证成功则认可该证书中所提供的用户公钥内容,实现用户公钥的安全分发。 + +用户证书的签发可以有两种方式。可以由用户自己生成公钥和私钥,然后 CA 来对公钥内容进行签名(只有用户持有私钥);也可以由 CA 直接来生成证书(内含公钥)和对应的私钥发给用户(用户和 CA 均持有私钥)。 + +前者情况下,用户一般会首先自行生成一个私钥和证书申请文件(Certificate Signing Request,即 csr 文件),该文件中包括了用户对应的公钥和一些基本信息,如通用名(common name,即 cn)、组织信息、地理位置等。CA 只需要对证书请求文件进行签名,生成证书文件,颁发给用户即可。整个过程中,用户可以保持私钥信息的私密性,不会被其他方获知(包括 CA 方)。 + +生成证书申请文件的过程并不复杂,用户可以很容易地使用开源软件 openssl 来生成 csr 文件和对应的私钥文件。 + +例如,安装 openssl 后可以执行如下命令来生成私钥和对应的证书请求文件: + +```bash +$ openssl req -new -keyout private.key -out for_request.csr +Generating a 1024 bit RSA private key +...........................++++++ +............................................++++++ +writing new private key to 'private.key' +Enter PEM pass phrase: +Verifying - Enter PEM pass phrase: +----- +You are about to be asked to enter information that will be incorporated +into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. +----- +Country Name (2 letter code) [AU]:CN +State or Province Name (full name) [Some-State]:Beijing +Locality Name (eg, city) []:Beijing +Organization Name (eg, company) [Internet Widgits Pty Ltd]:Blockchain +Organizational Unit Name (eg, section) []:Dev +Common Name (e.g. server FQDN or YOUR name) []:example.com +Email Address []: + +Please enter the following 'extra' attributes +to be sent with your certificate request +A challenge password []: +An optional company name []: +``` + +生成过程中需要输入地理位置、组织、通用名等信息。生成的私钥和 csr 文件默认以 PEM 格式存储,内容为 base64 编码。 + +如生成的 csr 文件内容可能为: + +```bash +$ cat for_request.csr +-----BEGIN CERTIFICATE REQUEST----- +MIIBrzCCARgCAQAwbzELMAkGA1UEBhMCQ04xEDAOBgNVBAgTB0JlaWppbmcxEDAO +BgNVBAcTB0JlaWppbmcxEzARBgNVBAoTCkJsb2NrY2hhaW4xDDAKBgNVBAsTA0Rl +djEZMBcGA1UEAxMQeWVhc3kuZ2l0aHViLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA8fzVl7MJpFOuKRH+BWqJY0RPTQK4LB7fEgQFTIotO264ZlVJVbk8 +Yfl42F7dh/8SgHqmGjPGZgDb3hhIJLoxSOI0vJweU9v6HiOVrFWE7BZEvhvEtP5k +lXXEzOewLvhLMNQpG0kBwdIh2EcwmlZKcTSITJmdulEvoZXr/DHXnyUCAwEAAaAA +MA0GCSqGSIb3DQEBBQUAA4GBAOtQDyJmfP64anQtRuEZPZji/7G2+y3LbqWLQIcj +IpZbexWJvORlyg+iEbIGno3Jcia7lKLih26lr04W/7DHn19J6Kb/CeXrjDHhKGLO +I7s4LuE+2YFSemzBVr4t/g24w9ZB4vKjN9X9i5hc6c6uQ45rNlQ8UK5nAByQ/TWD +OxyG +-----END CERTIFICATE REQUEST----- +``` + +openssl 工具提供了查看 PEM 格式文件明文的功能,如使用如下命令可以查看生成的 csr 文件的明文: + +```bash +$ openssl req -in for_request.csr -noout -text +Certificate Request: + Data: + Version: 0 (0x0) + Subject: C=CN, ST=Beijing, L=Beijing, O=Blockchain, OU=Dev, CN=yeasy.github.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:f1:fc:d5:97:b3:09:a4:53:ae:29:11:fe:05:6a: + 89:63:44:4f:4d:02:b8:2c:1e:df:12:04:05:4c:8a: + 2d:3b:6e:b8:66:55:49:55:b9:3c:61:f9:78:d8:5e: + dd:87:ff:12:80:7a:a6:1a:33:c6:66:00:db:de:18: + 48:24:ba:31:48:e2:34:bc:9c:1e:53:db:fa:1e:23: + 95:ac:55:84:ec:16:44:be:1b:c4:b4:fe:64:95:75: + c4:cc:e7:b0:2e:f8:4b:30:d4:29:1b:49:01:c1:d2: + 21:d8:47:30:9a:56:4a:71:34:88:4c:99:9d:ba:51: + 2f:a1:95:eb:fc:31:d7:9f:25 + Exponent: 65537 (0x10001) + Attributes: + a0:00 + Signature Algorithm: sha1WithRSAEncryption + eb:50:0f:22:66:7c:fe:b8:6a:74:2d:46:e1:19:3d:98:e2:ff: + b1:b6:fb:2d:cb:6e:a5:8b:40:87:23:22:96:5b:7b:15:89:bc: + e4:65:ca:0f:a2:11:b2:06:9e:8d:c9:72:26:bb:94:a2:e2:87: + 6e:a5:af:4e:16:ff:b0:c7:9f:5f:49:e8:a6:ff:09:e5:eb:8c: + 31:e1:28:62:ce:23:bb:38:2e:e1:3e:d9:81:52:7a:6c:c1:56: + be:2d:fe:0d:b8:c3:d6:41:e2:f2:a3:37:d5:fd:8b:98:5c:e9: + ce:ae:43:8e:6b:36:54:3c:50:ae:67:00:1c:90:fd:35:83:3b: + 1c:86 +``` + +需要注意,用户自行生成私钥情况下,私钥文件一旦丢失,CA 方由于不持有私钥信息,无法进行恢复,意味着通过该证书中公钥加密的内容将无法被解密。 + +### 证书的吊销 + +证书超出有效期后会作废,用户也可以主动向 CA 申请吊销某证书文件。 + +由于 CA 无法强制收回已经颁发出去的数字证书,因此为了实现证书的作废,往往还需要维护一个吊销证书列表(Certificate Revocation List,CRL),用于记录已经吊销的证书序号。 + +因此,通常情况下,当对某个证书进行验证时,需要首先检查该证书是否已经记录在列表中。如果存在,则该证书无法通过验证。如果不在,则继续进行后续的证书验证过程。 + +为了方便同步吊销列表信息,IETF 提出了在线证书状态协议(Online Certificate Status Protocol,或 OCSP),支持该协议的服务可以实时在线查询吊销的证书列表信息。 diff --git a/chainbrock-learning/05_crypto/signature.md b/chainbrock-learning/05_crypto/signature.md new file mode 100644 index 00000000..1e55d026 --- /dev/null +++ b/chainbrock-learning/05_crypto/signature.md @@ -0,0 +1,64 @@ +## 消息认证码与数字签名 + +消息认证码和数字签名技术通过对消息的摘要进行加密,可以防止消息被篡改和认证身份。 + +### 消息认证码 +消息认证码(Hash-based Message Authentication Code,HMAC),利用对称加密,对消息完整性(Integrity)进行保护。 + +基本过程为对某个消息,利用提前共享的对称密钥和 Hash 算法进行处理,得到 HMAC 值。该 HMAC 值持有方可以向对方证明自己拥有某个对称密钥,并且确保所传输消息内容未被篡改。 + +典型的 HMAC 生成算法包括 K,H,M 三个参数。K 为提前共享的对称密钥,H 为提前商定的 Hash 算法(如 SHA-256),M 为要传输的消息内容。三个参数缺失了任何一个,都无法得到正确的 HMAC 值。 + +消息认证码可以用于简单证明身份的场景。如 Alice、Bob 提前共享了 K 和 H。Alice 需要知晓对方是否为 Bob,可发送一段消息 M 给 Bob。Bob 收到 M 后计算其 HMAC 值并返回给 Alice,Alice 检验收到 HMAC 值的正确性可以验证对方是否真是 Bob。 + +*注:例子中并没有考虑中间人攻击的情况,并假定信道是安全的。* + +消息认证码的主要问题是需要提前共享密钥,并且当密钥可能被多方同时拥有(甚至泄露)的场景下,无法追踪消息的真实来源。如果采用非对称加密算法,则能有效地解决这个问题,即数字签名。 + +### 数字签名 +类似在纸质合同上进行签名以确认合同内容和证明身份,数字签名既可以证实某数字内容的完整性,又可以确认其来源(即不可抵赖,Non-Repudiation)。 + +一个典型的场景是,Alice 通过信道发给 Bob 一个文件(一份信息),Bob 如何获知所收到的文件即为 Alice 发出的原始版本?Alice 可以先对文件内容进行摘要,然后用自己的私钥对摘要进行加密(签名),之后同时将文件和签名都发给 Bob。Bob 收到文件和签名后,用 Alice 的公钥来解密签名,得到数字摘要,与对文件进行摘要后的结果进行比对。如果一致,说明该文件确实是 Alice 发过来的(因为别人无法拥有 Alice 的私钥),并且文件内容没有被修改过(摘要结果一致)。 + +理论上所有的非对称加密算法都可以用来实现数字签名,实践中常用算法包括 1991 年 8 月 NIST 提出的 DSA(Digital Signature Algorithm,基于 ElGamal 算法)和安全强度更高的 ECDSA(Elliptic Curve Digital Signature Algorithm,基于椭圆曲线算法)等。 + +除普通的数字签名应用场景外,针对一些特定的安全需求,产生了一些特殊数字签名技术,包括盲签名、多重签名、群签名、环签名等。 + +#### 盲签名 + +盲签名(Blind Signature),1982 年由 David Chaum 在论文《Blind Signatures for Untraceable Payment》中[提出](http://www.hit.bme.hu/~buttyan/courses/BMEVIHIM219/2009/Chaum.BlindSigForPayment.1982.PDF)。签名者需要在无法看到原始内容的前提下对信息进行签名。 + +盲签名可以实现对所签名内容的保护,防止签名者看到原始内容;另一方面,盲签名还可以实现防止追踪(Unlinkability),签名者无法将签名内容和签名结果进行对应。典型的实现包括 RSA 盲签名算法等。 + +#### 多重签名 +多重签名(Multiple Signature),即 n 个签名者中,收集到至少 m 个(n >= m >= 1)的签名,即认为合法。 + +其中,n 是提供的公钥个数,m 是需要匹配公钥的最少的签名个数。 + +多重签名可以有效地应用在多人投票共同决策的场景中。例如双方进行协商,第三方作为审核方。三方中任何两方达成一致即可完成协商。 + +比特币交易中就支持多重签名,可以实现多个人共同管理某个账户的比特币交易。 + +#### 群签名 + +群签名(Group Signature),即某个群组内一个成员可以代表群组进行匿名签名。签名可以验证来自于该群组,却无法准确追踪到签名的是哪个成员。 + +群签名需要一个群管理员来添加新的群成员,因此存在群管理员可能追踪到签名成员身份的风险。 + +群签名最早在 1991 年由 David Chaum 和 Eugene van Heyst 提出。 + +#### 环签名 + +环签名(Ring Signature),由 Rivest,Shamir 和 Tauman 三位密码学家在 2001 年首次提出。环签名属于一种简化的群签名。 + +签名者首先选定一个临时的签名者集合,集合中包括签名者自身。然后签名者利用自己的私钥和签名集合中其他人的公钥就可以独立地产生签名,而无需他人的帮助。签名者集合中的其他成员可能并不知道自己被包含在最终的签名中。 + +环签名在保护匿名性方面也具有很多用途。 + +### 安全性 + +数字签名算法自身的安全性由数学问题进行保护。但在实践中,各个环节的安全性都十分重要,一定要严格遵循标准流程。 + +例如,目前常见的数字签名算法需要选取合适的随机数作为配置参数,配置参数使用不当或泄露都会造成安全漏洞和风险。 + +2010 年 8 月,SONY 公司因为其 PS3 产品在采用十分安全的 ECDSA 进行签名时不慎使用了重复的随机参数,导致私钥被最终破解,造成重大经济损失。 diff --git a/chainbrock-learning/05_crypto/summary.md b/chainbrock-learning/05_crypto/summary.md new file mode 100644 index 00000000..0dc0e6e9 --- /dev/null +++ b/chainbrock-learning/05_crypto/summary.md @@ -0,0 +1,9 @@ +## 本章小结 + +本章总结了密码学与安全领域中的一些核心问题和经典算法。通过阅读本章内容,相信读者已经对现代密码学的发展状况和关键技术有了初步了解。掌握这些知识,对于理解区块链系统如何实现隐私保护和安全防护都很有好处。 + +现代密码学安全技术在设计上大量应用了十分专业的现代数学知识,如果读者希望能够深入学习其原理,则需要进一步学习并掌握近现代的数学科学,特别是数论、抽象代数等相关内容。 + +从应用的角度来看,完善的安全系统除了核心算法外,还需要包括协议、机制、系统、人员等多个方面。任何一个环节出现漏洞都将带来巨大的安全风险。因此,实践中要实现真正高安全可靠的系统是十分困难的。 + +区块链中大量利用了现代密码学的已有成果;反过来,区块链在诸多场景中的应用也提出了很多新的需求,促进了安全学科的进一步发展。 diff --git a/chainbrock-learning/06_bitcoin/README.md b/chainbrock-learning/06_bitcoin/README.md new file mode 100644 index 00000000..8b24d249 --- /dev/null +++ b/chainbrock-learning/06_bitcoin/README.md @@ -0,0 +1,12 @@ +# 比特币 —— 区块链思想诞生的摇篮 + +** 之所以看得更远,是因为站在了巨人的肩膀上。** + +作为区块链思想的源头,比特币项目值得区块链技术爱好者们仔细学习和研究。 + +比特币网络是首个得到大规模部署的区块链平台,也是首个得到长时间实践检验的加密货币实现,无论在科技史还是金融史上都将具有十分重要的意义。比特币项目在诞生和发展过程中,借鉴了加密货币、密码学、博弈论、分布式系统、控制论等多个领域的技术成果,可谓博采众家之长于一身,是集大成者。 + +后来的区块链技术应用已经超越了加密货币的范畴,但探索比特币项目的发展历程和设计思路,对于深刻理解区块链技术的来龙去脉有着重要的价值。 + +本章将介绍比特币项目的来源、核心原理设计、相关的工具,以及关键的技术话题。 + diff --git a/chainbrock-learning/06_bitcoin/_images/bitcoin_logo.png b/chainbrock-learning/06_bitcoin/_images/bitcoin_logo.png new file mode 100644 index 00000000..0c928691 Binary files /dev/null and b/chainbrock-learning/06_bitcoin/_images/bitcoin_logo.png differ diff --git a/chainbrock-learning/06_bitcoin/_images/bitcoin_price.png b/chainbrock-learning/06_bitcoin/_images/bitcoin_price.png new file mode 100644 index 00000000..8b59b085 Binary files /dev/null and b/chainbrock-learning/06_bitcoin/_images/bitcoin_price.png differ diff --git a/chainbrock-learning/06_bitcoin/_images/bitcoin_wp.png b/chainbrock-learning/06_bitcoin/_images/bitcoin_wp.png new file mode 100644 index 00000000..551e897e Binary files /dev/null and b/chainbrock-learning/06_bitcoin/_images/bitcoin_wp.png differ diff --git a/chainbrock-learning/06_bitcoin/_images/block_example.png b/chainbrock-learning/06_bitcoin/_images/block_example.png new file mode 100644 index 00000000..8db389ce Binary files /dev/null and b/chainbrock-learning/06_bitcoin/_images/block_example.png differ diff --git a/chainbrock-learning/06_bitcoin/_images/block_size.png b/chainbrock-learning/06_bitcoin/_images/block_size.png new file mode 100644 index 00000000..47432918 Binary files /dev/null and b/chainbrock-learning/06_bitcoin/_images/block_size.png differ diff --git a/chainbrock-learning/06_bitcoin/_images/coins.png b/chainbrock-learning/06_bitcoin/_images/coins.png new file mode 100644 index 00000000..eca7e4b1 Binary files /dev/null and b/chainbrock-learning/06_bitcoin/_images/coins.png differ diff --git a/chainbrock-learning/06_bitcoin/_images/pow.png b/chainbrock-learning/06_bitcoin/_images/pow.png new file mode 100644 index 00000000..9f8be011 Binary files /dev/null and b/chainbrock-learning/06_bitcoin/_images/pow.png differ diff --git a/chainbrock-learning/06_bitcoin/_images/sidechain.png b/chainbrock-learning/06_bitcoin/_images/sidechain.png new file mode 100644 index 00000000..e56cf4ae Binary files /dev/null and b/chainbrock-learning/06_bitcoin/_images/sidechain.png differ diff --git a/chainbrock-learning/06_bitcoin/_images/sidechain_workflow.png b/chainbrock-learning/06_bitcoin/_images/sidechain_workflow.png new file mode 100644 index 00000000..32ea32ba Binary files /dev/null and b/chainbrock-learning/06_bitcoin/_images/sidechain_workflow.png differ diff --git a/chainbrock-learning/06_bitcoin/_images/transaction_example.png b/chainbrock-learning/06_bitcoin/_images/transaction_example.png new file mode 100644 index 00000000..77add9ba Binary files /dev/null and b/chainbrock-learning/06_bitcoin/_images/transaction_example.png differ diff --git a/chainbrock-learning/06_bitcoin/consensus.md b/chainbrock-learning/06_bitcoin/consensus.md new file mode 100644 index 00000000..bb22a354 --- /dev/null +++ b/chainbrock-learning/06_bitcoin/consensus.md @@ -0,0 +1,40 @@ +## 共识机制 + +比特币网络是完全公开的,任何人都可以匿名接入,因此共识协议的稳定性和防攻击性十分关键。 + +比特币区块链采用了 Proof of Work(PoW)机制来实现共识,该机制最早于 1998 年在 [B-money](http://www.weidai.com/bmoney.txt) 设计中提出。 + +目前,Proof of X 系列中比较出名的一致性协议包括 PoW、PoS 和 DPoS 等,都是通过经济惩罚来限制恶意参与。 + +### 工作量证明 + +工作量证明是通过计算来猜测一个数值(nonce),使得拼凑上交易数据后内容的 Hash 值满足规定的上限(来源于 hashcash)。由于 Hash 难题在目前计算模型下需要大量的计算,这就保证在一段时间内,系统中只能出现少数合法提案。反过来,如果谁能够提出合法提案,也证明提案者确实已经付出了一定的工作量。 + +同时,这些少量的合法提案会在网络中进行广播,收到的用户进行验证后,会基于用户认为的最长链基础上继续难题的计算。因此,系统中可能出现链的分叉(Fork),但最终会有一条链成为最长的链。 + +Hash 问题具有不可逆的特点,因此,目前除了暴力计算外,还没有有效的算法进行解决。反之,如果获得符合要求的 nonce,则说明在概率上是付出了对应的算力。谁的算力多,谁最先解决问题的概率就越大。当掌握超过全网一半算力时,从概率上就能控制网络中链的走向。这也是所谓 `51%` 攻击的由来。 + +参与 PoW 计算比赛的人,将付出不小的经济成本(硬件、电力、维护等)。当没有最终成为首个算出合法 nonce 值的“幸运儿”时,这些成本都将被沉没掉。这也保障了,如果有人尝试恶意破坏,需要付出大量的经济成本。也有人考虑将后算出结果者的算力按照一定比例折合进下一轮比赛。 + +有一个很直观的超市付款的例子,可以说明为何这种经济博弈模式会确保系统中最长链的唯一性。 + +![Pow 保证一致性](_images/pow.png) + +假定超市只有一个出口,付款时需要排成一队,可能有人不守规矩要插队。超市管理员会检查队伍,认为最长的一条队伍是合法的,并让不合法的分叉队伍重新排队。新到来的人只要足够理智,就会自觉选择最长的队伍进行排队。这是因为,多条链的参与者看到越长的链越有可能胜出,从而更倾向于选择长的链。 + +可以看到,最长链机制可以提高很好地抗攻击性,同时其代价是浪费掉了非最长链上的计算资源。部分改进工作是考虑以最长链为基础,引入树形结构以提高整体的交易性能,如 GHOST 协议(《Secure high-rate transaction processing in bitcoin》)和 Conflux 算法(《Scaling Nakamoto Consensus to Thousands of Transactions per Second》)。 + +### 权益证明 + +权益证明(Proof of Stake,PoS)最早在 2013 年被提出,最早在 [Peercoin]() 系统中被实现,类似于现实生活中的股东机制,拥有股份越多的人越容易获取记账权(同时越倾向于维护网络的正常工作)。 + +典型的过程是通过保证金(代币、资产、名声等具备价值属性的物品即可)来对赌一个合法的块成为新的区块,收益为抵押资本的利息和交易服务费。提供证明的保证金(例如通过转账货币记录)越多,则获得记账权的概率就越大。合法记账者可以获得收益。 + +PoS 试图解决在 PoW 中大量资源被浪费的问题,因而受到了广泛关注。恶意参与者将存在保证金被罚没的风险,即损失经济利益。 + +一般情况下,对于 PoS 来说,需要掌握超过全网 1/3 的资源,才有可能左右最终的结果。这也很容易理解,三个人投票,前两人分别支持一方,这时候,第三方的投票将决定最终结果。 + +PoS 也有一些改进的算法,包括授权股权证明机制(DPoS),即股东们投票选出一个董事会,董事会中成员才有权进行代理记账。这些算法在实践中得到了不错的验证,但是并没有理论上的证明。 + +2017 年 8 月,来自爱丁堡大学和康涅狄格大学的 Aggelos Kiayias 等学者在论文《Ouroboros: A Provably Secure Proof-of-Stake Blockchain Protocol》中提出了 Ouroboros 区块链共识协议,该协议可以达到诚实行为的近似纳什均衡,被认为是首个可证实安全的 PoS 协议。 + diff --git a/chainbrock-learning/06_bitcoin/currency.md b/chainbrock-learning/06_bitcoin/currency.md new file mode 100644 index 00000000..a52e0b9d --- /dev/null +++ b/chainbrock-learning/06_bitcoin/currency.md @@ -0,0 +1,64 @@ +## 实体货币到加密数字货币 + +区块链最初的思想,诞生于无数先哲对于用加密数字货币替代实体货币的探讨和设计中。 + +### 货币的历史演化 +众所周知,货币是人类文明发展过程中的一大发明。其最重要的职能包括价值尺度、流通手段、贮藏手段等。很难想象离开了货币,现代社会庞大而复杂的经济和金融体系如何保持运转。也正是因为它如此重要,货币的设计和发行机制是关系到国计民生的大事。 + +历史上,在自然和人为因素的干预下,货币的形态经历了多个阶段的演化,包括实物货币、金属货币、代用货币、信用货币、电子货币、数字货币等。近代之前相当长的一段时间里,货币的形态一直是以实体的形式存在,可统称为“实体货币”。计算机诞生后,为货币的虚拟化提供了可能性。 + +同时,货币自身的价值依托也不断发生演化,从最早的实物价值依托、功能价值依托、发行方信用价值依托,直到今天的对信息科技(包括软件、系统、算法等)的信任价值依托。 + +*注:中国最早关于货币的确切记载“夏后以玄币”,出现在恒宽《盐铁论·错币》。TBD* + +### 从纸币到数字货币 + +理论上任何事物都可以作为货币,只要使用者愿意接受。例如在随便一张纸上注明代表若干金额,只要交易各方都认可,这张纸就可以起到货币职能。实际上如今世界最常见的货币流通形式就是纸币,既方便携带、不易仿制,又相对容易辩伪。 + +或许有人会认为信用卡等电子方式,相对于纸币等货币形式使用起来更为方便。确实,信用卡在某些场景下会更为便捷,但它依赖背后的集中式支付体系,一旦碰到支付系统故障、断网、缺乏支付终端等情况,信用卡就无法使用;另外,信用卡形式往往还需要额外的终端设备支持。 + +目前,无论是货币形式,还是信用卡形式,都需要额外的支持机构(例如银行)来完成生产、分发、管理等操作。“中心化”的结构带来了管理和监管上的便利,但系统安全性方面存在很大挑战。诸如伪造、信用卡诈骗、盗刷、转账等安全事件屡见不鲜。 + +很显然,如果能实现一种数字货币,保持既有货币方便易用的特性,同时消除纸质货币的缺陷,无疑将极大提高社会整体经济活动的运作效率。 + +让我们来对比现有的数字货币(以比特币为例)和现实生活中的纸币,两者的优劣如下表所示。 + +| 属性 | 分析 | 优势方 | +| --- | --- | --- | +| 便携 | 大部分场景(特别大额支付)下数字货币将具备更好的便携性。 | 数字货币 | +| 防伪 | 两者各有千秋,但数字货币整体上会略胜一筹。纸币依靠的是各种设计(纸张、油墨、暗纹、夹层等)上的精巧,数字货币依靠的则是密码学上的保障。事实上,纸币的伪造时有发生,但数字货币的伪造目前还无法实现。 | 数字货币 | +| 辩伪 | 纸币即使依托验钞机等专用设备仍会有误判情况,数字货币依靠密码学易于校验。数字货币胜出。 | 数字货币 | +| 匿名 | 比特币利用化名(Pseudonymity)来隐藏身份,但账目公开可见。两者都无法阻止有意的追踪。 | 持平 | +| 交易 | 对纸币来说,谁物理持有纸币谁就是合法拥有者,交易通过纸币自身的转移即可完成,无法复制。对数字货币来说则复杂得多,因为任何数字物品都是可以被复制的,但数字形式也意味着转移成本会更低。总体看,两者适用不同的情景。 | 持平 | +| 资源 | 通常情况下,纸币的生产成本要远低于面额。数字货币消耗资源的计算则复杂的多。以比特币为例,最坏情况下可能需要消耗接近其面值的电能。 | 纸币 | +| 发行 | 纸币的发行需要第三方机构的参与;数字货币则通过分布式算法来完成发行。历史上,通胀和通缩往往是不合理地发行货币造成的;数字货币尚缺乏大规模验证,还有待观察。 | 持平 | +| 管理 | 纸币发行和回收往往通过统一机构,易于监管和审计;而目前数字货币在这方面还缺乏足够支持和验证。 | 纸币 | + +可见,数字货币并非在所有领域都优于已有的货币形式。要比较两者的优劣应该针对具体情况具体分析。不带前提地鼓吹数字货币并不是一种科学和严谨的态度。实际上,仔细观察数字货币的应用情况就会发现,虽然以比特币为代表的数字货币已在众多领域得到应用,但还没有任何一种数字货币能完全替代已有货币。目前,世界各国央行都在密切关注和探索数字货币应用。 + +虽然当前的数字货币“实验”已经取得了不小影响,但可见的局限也很明显:其依赖的区块链和分布式账本技术还缺乏大规模场景的考验;系统的性能和安全性还有待提升;资源的消耗过高;对监管和审计支持不足等。这些问题的解决,都有待金融科技的进一步发展。 + +*注:严格来讲,货币(money)不仅局限于现金或通货(cash/currency),货币的含义范围更广。* + +### “非中心化”的技术难关 + +虽然数字货币带来的预期优势可能很美好,但要设计和实现一套能经得住实用考验的数字货币并非易事。任何货币系统,首先要解决如何发行、如何流通和如何确定价值三个基本问题。 + +现实生活中常用的纸币具备良好的可转移性,可以相对容易地完成价值的交割。但是对于数字货币来说,因为数字化内容容易被复制,数字货币持有人可以试图将同一份货币发给多个接收者,这种攻击被称为“双重支付攻击(Double-spend Attack)”。 + +也许有人会想到,银行中的货币实际上也是数字化的,因为通过电子账号里面的数字记录了客户的资产。说的没错,这种电子货币模式有人称为“数字货币 1.0”,它实际上依赖了一个前提:假定存在一个安全可靠的第三方记账机构负责记账,这个机构负责所有的担保所有的环节,最终完成交易。 + +中心化控制下,数字货币的实现相对容易。但是,有些时候很难找到一个安全可靠的第三方机构,来充当这个记账者角色。 + +例如,发生贸易的两国可能缺乏足够的外汇储备用以支付;汇率的变化等导致双方对合同有不同意见;网络上的匿名双方进行直接买卖而不通过电子商务平台;交易的两个机构彼此互不信任,找不到双方都认可的第三方担保;使用第三方担保系统,但某些时候可能无法连接;第三方的系统可能会出现故障或被篡改攻击…… + +这个时候,就只有实现非中心化(De-centralized)或多中心化(Multi-centralized)的数字货币系统。在“非中心化”的场景下,实现数字货币存在如下几个难题: + +* 货币的发行:如何合理发行货币,避免导致通货膨胀或其他经济问题; +* 货币的防伪:如何确保和检验货币的真实性,防止被伪造或篡改; +* 货币的交易:如何确保随时随地可以从支付方安全转移到接收方; +* 避免双重支付:电子数据很容易被复制,如何避免同一个数字货币被多次支付。 + +可见,在不存在第三方记账机构的情况下,实现一个数字货币系统的挑战着实不小。 + +能否通过技术创新来解决这个难题呢?比特币融合了数十年在金融、密码学和分布式系统领域的科技成果,终于实现了在全球范围内运行的大规模加密货币系统。 diff --git a/chainbrock-learning/06_bitcoin/design.md b/chainbrock-learning/06_bitcoin/design.md new file mode 100644 index 00000000..775a92c1 --- /dev/null +++ b/chainbrock-learning/06_bitcoin/design.md @@ -0,0 +1,177 @@ +## 基本原理和设计 + +从分布式系统角度看,比特币网络是一个典型的分布式点对点网络,网络中的矿工通过“挖矿”来完成对交易记录的记账过程,维护网络的正常运行。 + +区块链网络提供一个公共可见的记账本,该记账本记录网络中所有的交易历史,而并非记录各个账户的余额。该设计可以避免重放攻击,即某个交易被多次重复提交。 + +### 基本交易过程 + +比特币中没有账户的概念。因此,每次发生交易,用户需要将交易记录写到比特币网络账本中,等网络确认后即可认为交易完成。 + +除了挖矿获得奖励的 coinbase 交易只有输出,正常情况下每个交易需要包括若干输入和输出,未经使用(引用)的交易的输出(Unspent Transaction Outputs,UTXO)可以被新的交易引用作为其合法的输入。被使用过的交易的输出(Spent Transaction Outputs,STXO),则无法被引用作为合法输入。 + +因此,比特币网络中一笔合法的交易,必须是引用某些已存在交易的 UTXO(必须是属于付款方才能合法引用)作为新交易的输入,并生成新的 UTXO(将属于收款方)。 + +那么,在交易过程中,付款方如何证明自己所引用的 UTXO 合法?比特币中通过“签名脚本”来实现,并且指定“输出脚本”来限制将来能使用新 UTXO 者只能为指定收款方。对每笔交易,付款方需要进行签名确认。并且,对每一笔交易来说,总输入不能小于总输出。总输入相比总输出多余的部分称为交易费用(Transaction Fee),为生成包含该交易区块的矿工所获得。目前规定每笔交易的交易费用不能小于 0.0001 BTC,交易费用越高,越多矿工愿意包含该交易,也就越早被放到网络中。交易费用在奖励矿工的同时,也避免了网络受到大量攻击。 + +交易中金额的最小单位是“聪”,即一亿分之一(10^-8)比特币。 + +下图展示了一些简单的示例交易。更一般情况下,交易的输入、输出可以为多方。 + +| 交易 | 目的 | 输入 | 输出 | 签名 | 差额 | +| --- | --- | --- | --- | --- | --- | +| T0 | A 转给 B | 他人向 A 交易的输出 | B 账户可以使用该交易 | A 签名确认 | 输入减输出,为交易服务费 | +| T1 | B 转给 C | T0 的输出 | C 账户可以使用该交易 | B 签名确认 | 输入减输出,为交易服务费 | +| ... | X 转给 Y | 他人向 X 交易的输出 | Y 账户可以使用该交易 | X 签名确认 | 输入减输出,为交易服务费 | + +需要注意,刚放进网络中的交易(深度为 0)并非是实时得到确认的。进入网络中的交易存在被推翻的可能性,一般要再生成几个新的区块后(深度大于 0)才认为该交易被确认。 + +比特币采用了 UTXO 模型,相对账户模型,UTXO 模型可以更容易实现并行处理和隐私保护,并追踪完整交易路径;但由于需要存储和检索所有交易记录,对节点存储压力较大。 + +下面分别介绍比特币网络中的重要概念和主要设计思路。 + +### 重要概念 + +#### 账户/地址 + +比特币采用了非对称的加密算法,用户自己保留私钥,对自己发出的交易进行签名确认,并公开公钥。 + +比特币的账户地址其实就是用户公钥经过一系列 Hash(HASH160,或先进行 SHA256,然后进行 RIPEMD160)及编码运算后生成的 160 位(20 字节)的字符串。 + +一般地,也常常对账户地址串进行 Base58Check 编码,并添加前导字节(表明支持哪种脚本)和 4 字节校验字节,以提高可读性和准确性。 + +*注:账户并非直接是公钥内容,而是 Hash 后的值,避免公钥过早公开后导致被破解出私钥。* + +#### 交易 + +交易是完成比特币功能的核心概念,一条交易可能包括如下信息: + +* 付款人地址:合法的地址,公钥经过 SHA256 和 RIPEMD160 两次 Hash,得到 160 位 Hash 串; +* 付款人对交易的签字确认:确保交易内容不被篡改; +* 付款人资金的来源交易 ID:从哪个交易的输出作为本次交易的输入; +* 交易的金额:多少钱,跟输入的差额为交易的服务费; +* 收款人地址:合法的地址; +* 时间戳:交易何时能生效。 + +网络中节点收到交易信息后,将进行如下检查: + +* 交易是否已经处理过; +* 交易是否合法。包括地址是否合法、发起交易者是否是输入地址的合法拥有者、是否是 UTXO; +* 交易的输入之和是否大于输出之和。 + +检查都通过,则将交易标记为合法的未确认交易,并在网络内进行广播。 + +用户可以从 blockchain.info 网站查看实时的交易信息,一个示例交易的内容如下图所示。 + +![比特币交易的例子](_images/transaction_example.png) + +#### 交易脚本 + +[脚本(Script)](https://en.bitcoin.it/wiki/Script) 是保障交易完成(主要用于检验交易是否合法)的核心机制,当所依附的交易发生时被触发。通过脚本机制而非写死交易过程,比特币网络实现了一定的可扩展性。比特币脚本语言是一种非图灵完备的语言,类似 [Forth](https://en.wikipedia.org/wiki/Forth_programming_language) 语言。 + +一般每个交易都会包括两个脚本:负责输入的解锁脚本(scriptSig)和负责输出的锁定脚本(scriptPubKey)。 + +输出脚本一般由付款方对交易设置锁定,用来对能动用这笔交易的输出(例如,要花费该交易的输出)的对象(收款方)进行权限控制,例如限制必须是某个公钥的拥有者才能花费这笔交易。 + +认领脚本则用来证明自己可以满足交易输出脚本的锁定条件,即对某个交易的输出(比特币)的拥有权。 + +输出脚本目前支持两种类型: + +* [P2PKH](https://en.bitcoin.it/wiki/Script#Standard_Transaction_to_Bitcoin_address_.28pay-to-pubkey-hash.29):Pay-To-Public-Key-Hash,允许用户将比特币发送到一个或多个典型的比特币地址上(证明拥有该公钥),前导字节一般为 0x00; +* P2SH:Pay-To-Script-Hash,支付者创建一个输出脚本,里边包含另一个脚本(认领脚本)的哈希,一般用于需要多人签名的场景,前导字节一般为 0x05; + +以 P2PKH 为例,输出脚本的格式为 + +``` +scriptPubKey: OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG +``` + +其中,OP_DUP 是复制栈顶元素;OP_HASH160 是计算 hash 值;OP_EQUALVERIFY 判断栈顶两元素是否相等;OP_CHECKSIG 判断签名是否合法。这条指令实际上保证了只有 pubKey 的拥有者才能合法引用这个输出。 + +另外一个交易如果要花费这个输出,在引用这个输出的时候,需要提供认领脚本格式为 + +``` +scriptSig: +``` + +其中, 是拿 pubKey 对应的私钥对交易(全部交易的输出、输入和脚本)Hash 值进行签名,pubKey 的 Hash 值需要等于 pubKeyHash。 + +进行交易验证时,会按照先 scriptSig 后 scriptPubKey 的顺序进行依次入栈处理,即完整指令为: + +``` + OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG +``` + +读者可以按照栈的过程来进行推算,理解整个脚本的验证过程。 + +引入脚本机制带来了灵活性,但也引入了更多的安全风险。比特币脚本支持的指令集十分简单,基于栈的处理方式,并且非图灵完备,此外还添加了额外的一些限制(大小限制等)。 + +#### 区块 + +比特币区块链的一个区块不能超过 1 MB,将主要包括如下内容: + +* 区块大小:4 字节; +* 区块头:80 字节: +* 交易个数计数器:1~9 字节; +* 所有交易的具体内容,可变长,匹配 Merkle 树叶子节点顺序。 + +其中,区块头信息十分重要,包括: + +* 版本号:4 字节; +* 上一个区块头的 Hash 值:链接到上一个合法的块上,对其区块头进行两次 SHA256 操作,32 字节; +* 本区块所包含的所有交易的 Merkle 树根的哈希值:两次 SHA256 操作,32 字节; +* 时间戳:4 字节; +* 难度指标:4 字节; +* Nonce:4 字节,PoW 问题的答案。 + +可见,要对区块链的完整性进行检查,只需要检验各个区块头部信息即可,无需获取到具体的交易内容,这也是简单交易验证(Simple Payment Verification,SPV)的基本原理。另外,通过头部的链接,提供时序关系的同时加大了对区块中数据进行篡改的难度。 + +一个示例区块如下图所示。 + +![比特币区块的例子](_images/block_example.png) + +### 创新设计 + +比特币在设计上提出了很多创新点,主要考虑了避免作恶、采用负反馈调节和基于概率的共识机制等三个方面。 + +#### 如何避免作恶 + +基于经济博弈原理。在一个开放的网络中,无法通过技术手段保证每个人都是合作的。但可以通过经济博弈来让合作者得到利益,让非合作者遭受损失和风险。 + +实际上,博弈论早已被广泛应用到众多领域。 + +一个经典的例子是两个人来分一个蛋糕,如果都想拿到较大的一块,在没有第三方的前提下,该怎么制定规则才公平? + +最简单的一个方案是任意一个人负责分配蛋糕,并且这个人后挑选。 + +*注:如果推广到 N 个人呢?* + +比特币网络中所有试图参与者(矿工)都首先要付出挖矿的代价,进行算力消耗,越想拿到新区块的决定权,意味着抵押的算力越多。一旦失败,这些算力都会被没收掉,成为沉没成本。当网络中存在众多参与者时,个体试图拿到新区块决定权要付出的算力成本是巨大的,意味着进行一次作恶付出的代价已经超过可能带来的好处。 + +#### 负反馈调节 + +比特币网络在设计上,很好的体现了负反馈的控制论基本原理。 + +比特币网络中矿工越多,系统就越稳定,比特币价值就越高,但挖到矿的概率会降低。 + +反之,网络中矿工减少,会让系统更容易导致被攻击,比特币价值越低,但挖到矿的概率会提高。 + +因此,比特币的价格理论上应该稳定在一个合适的值(网络稳定性也会稳定在相应的值),这个价格乘以挖到矿的概率,恰好达到矿工的收益预期。 + +从长远角度看,硬件成本是下降的,但每个区块的比特币奖励每隔 4 年减半,最终将在 2140 年达到 2100 万枚,之后将完全依靠交易的服务费来鼓励矿工对网络的维护。 + +*注:比特币最小单位是“聪”,即 10^(-8) 比特币,总“聪”数为 2.1E15。对于 64 位处理器来说,高精度浮点计数的限制导致单个数值不能超过 2^53 约等于 9E15。* + +#### 共识机制 + +传统共识问题往往是考虑在一个相对封闭的分布式系统中,允许同时存在正常节点、故障节点,如何快速达成一致。 + +对于比特币网络来说,它是完全开放的,可能面向各种攻击情况,同时基于 Internet 的网络质量只能保证“尽力而为”,导致问题更加复杂,传统的一致性算法在这种场景下难以实用。 + +因此,比特币网络不得不对共识的目标和过程都进行了一系列限制,提出了基于 Proof of Work(PoW)的共识机制。 + +首先是不实现面向最终确认的共识,而是基于概率、随时间逐步增强确认的共识。现有达成的结果在理论上都可能被推翻,只是攻击者要付出的代价随时间而指数级上升,被推翻的可能性随之指数级的下降。 + +此外,考虑到 Internet 的尺度,达成共识的时间相对比较长。按照区块(一组交易)来进行阶段性的确认(快照),提高网络整体的可用性。 + +最后,限制网络中共识的噪音。通过进行大量的 Hash 计算和少数的合法结果来限制合法提案的个数,进一步提高网络中共识的稳定性。 diff --git a/chainbrock-learning/06_bitcoin/hot_topics.md b/chainbrock-learning/06_bitcoin/hot_topics.md new file mode 100644 index 00000000..20fcb0f8 --- /dev/null +++ b/chainbrock-learning/06_bitcoin/hot_topics.md @@ -0,0 +1,99 @@ +## 热点问题 + +### 设计中的权衡 + +比特币的设计目标在于支持一套安全、开放、分布式的数字货币系统。围绕这一目标,比特币协议的设计中很多地方都体现了权衡(trade-off)的思想。 + +* 区块容量:更大的区块容量可以带来更高的交易吞吐率,但会增加挖矿成本,带来中心化的风险,同时增大存储的代价。兼顾多方面的考虑,当前的区块容量上限设定为 1MB。 +* 出块间隔时间:更短的出块间隔可以缩短交易确认的时间,但也可能导致分叉增多,降低网络可用性。 +* 脚本支持程度:更强大的脚本指令集可以带来更多灵活性,但也会引入更多安全风险。 + +### 分叉 + +比特币协议不会一成不变。当需要修复漏洞、扩展功能或调整结构时,比特币需要在全网的配合下进行升级。升级通常涉及更改交易的数据结构或区块的数据结构。 + +由于分布在全球的节点不可能同时完成升级来遵循新的协议,因此比特币区块链在升级时可能发生分叉(Fork)。对于一次升级,如果把网络中升级了的节点称为新节点,未升级的节点称为旧节点,根据新旧节点相互兼容性上的区别,可分为软分叉(Soft Fork)和硬分叉(Hard Fork)。 + +* 如果旧节点仍然能够验证接受新节点产生的交易和区块,则称为软分叉。旧节点可能不理解新节点产生的一部分数据,但不会拒绝。网络既向后和向前兼容,因此这类升级可以平稳进行。 +* 如果旧节点不接受新节点产生的交易和区块,则称为硬分叉。网络只向后兼容,不向前兼容。这类升级往往引起一段时间内新旧节点所认可的区块不同,分出两条链,直到旧节点升级完成。 + +尽管通过硬分叉升级区块链协议的难度大于软分叉,但软分叉能做的事情毕竟有限,一些大胆的改动只能通过硬分叉完成。 + +### 交易延展性 + +交易延展性(Transaction Malleablility)是比特币的一个设计缺陷。简单来讲,是指当交易发起者对交易签名(sign)之后,交易 ID 仍然可能被改变。 + +下面是一个比特币交易的例子。 + +```json +{ + "txid": "f200c37aa171e9687452a2c78f2537f134c307087001745edacb58304053db20", + "version": 1, + "locktime": 0, + "vin": [ + { + "txid": "21f10dbfb0ff49e2853629517fa176dc00d943f203aae3511288a7dd89280ac2", + "vout": 0, + "scriptSig": { + "asm": "304402204f7fb0b1e0d154db27dbdeeeb8db7b7d3b887a33e712870503438d8be2d66a0102204782a2714215dc0d581e1d435b41bc6eced2c213c9ba0f993e7fcf468bb5d311[ALL] 025840d511c4bc6690916270a54a6e9290fab687f512c18eb2df0428fa69a26299", + "hex": "47304402204f7fb0b1e0d154db27dbdeeeb8db7b7d3b887a33e712870503438d8be2d66a0102204782a2714215dc0d581e1d435b41bc6eced2c213c9ba0f993e7fcf468bb5d3110121025840d511c4bc6690916270a54a6e9290fab687f512c18eb2df0428fa69a26299" + }, + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 0.00167995, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 7c4338dea7964947b3f0954f61ef40502fe8f791 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a9147c4338dea7964947b3f0954f61ef40502fe8f79188ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "1CL3KTtkN8KgHAeWMMWfG9CPL3o5FSMU4P" + ] + } + } + ] +} +``` + +发起者对交易的签名(scriptSig)位于交易的输入(vin)当中,属于交易内容的一部分。交易 ID(txid)是整个交易内容的 Hash 值。这就造成了一个问题:攻击者(尤其是签名方)可以通过改变 scriptSig 来改变 txid,而交易仍旧保持合法。例如,反转 ECDSA 签名过程中的 S 值,签名仍然合法,交易仍然能够被传播。 + +这种延展性攻击能改变交易 ID,但交易的输入和输出不会被改变,所以攻击者不会直接盗取比特币。这也是为什么这一问题能在比特币网络中存在如此之久,而仍未被根治。 + +然而,延展性攻击仍然会带来一些问题。比如,在原始交易未被确认之前广播 ID 改变了的交易可能误导相关方对交易状态的判断,甚至发动拒绝服务攻击;多重签名场景下,一个签名者有能力改变交易 ID,给其他签名者的资产带来潜在风险。同时,延展性问题也会阻碍闪电网络等比特币扩展方案的实施。 + +### 扩容之争 + +比特币当前将区块容量限制在 1MB 以下。如图所示,随着用户和交易量的增加,这一限制已逐渐不能满足比特币的交易需求,使得交易日益拥堵、交易手续费不断上涨。 + +![日益增加的区块容量](_images/block_size.png) + +关于比特币扩容的持续争论从 2015 年便已开始,期间有一系列方案被摆上台面,包括各种链上扩容提议、用侧链或闪电网络扩展比特币等。考虑到比特币复杂的社区环境,其扩容方案早已不是一方能说了算;而任何一个方案想让要达成广泛共识都比较困难,不同的方案之间也很难调和。 + +当前,扩容之争主要集中在两派:代表核心开发者的 Bitcoin Core 团队主推的隔离见证方案,和 Bitcoin Unlimited 团队推出的方案。 + +#### 隔离见证方案 + +隔离见证(Segregated Witness,简称 SegWit)是指将交易中的签名部分从交易的输入中隔离出来,放到交易末尾的被称为见证(Witness)的字段当中。 + +对交易 ID 的计算将不再包含这一签名部分,所以这也是延展性问题的一种解法,给引入闪电网络等第二层协议增强了安全性。 + +同时,隔离见证会将区块容量上限理论上提高到 4MB。对隔离见证的描述可详见五个比特币改进协议(Bitcoin Improvement Proposal):BIP 141 ~ BIP 145。 + +#### Bitcoin Unlimited 方案 + +Bitcoin Unlimited 方案(简称 BU)是指扩展比特币客户端,使矿工可以自由配置他们想要生成和验证的区块的容量。 + +根据方案的设想,区块容量的上限会根据众多节点和矿工的配置进行自然收敛。Bitcoin Unlimited Improvement Proposal(BUIP) 001 中表述了这一对比特币客户端的拓展提议,该方案已获得一些大型矿池的支持和部署。 + +### 比特币的监管和追踪 + +比特币的匿名特性,使得对其交易进行监管并不容易。 + +不少非法分子利用这一点,通过比特币转移资金。例如 WannaCry 网络病毒向受害者勒索比特币,短短三天时间里传播并影响到全球 150 多个国家。尽管这些不恰当的行为与比特币项目自身并无直接关系,但都或多或少给比特币社区带来了负面影响。 + +实际上,认为通过比特币就可以实现完全匿名化并不现实。虽然交易账户自身是匿名的 Hash 地址,但一些研究成果(如《An analysis of anonymity in the bitcoin system》)表明,通过分析大量公开可得的交易记录,有很大概率可以追踪到比特币的实际转移路线,甚至可以追踪到真实用户。 + diff --git a/chainbrock-learning/06_bitcoin/intro.md b/chainbrock-learning/06_bitcoin/intro.md new file mode 100644 index 00000000..320aa3a8 --- /dev/null +++ b/chainbrock-learning/06_bitcoin/intro.md @@ -0,0 +1,126 @@ +## 比特币项目简介 + +![比特币项目](_images/bitcoin_logo.png) + +比特币(BitCoin,BTC)是基于区块链技术的一种加密货币;比特币网络是首个经过大规模、长时间检验的公有区块链系统。 + +自 2009 年 1 月 3 日正式上线以来,比特币价格经历了数次的震荡,目前每枚比特币市场价格超过 7000 美金。 + +比特币网络在功能上具有如下特点: + +* 非中心化:意味着没有任何独立个体可以对网络造成有效破坏,交易请求需要大多数参与者进行共识才能被接受; +* 隐私性:网络中账户地址是化名的,很难从交易信息直接关联到具体的个体,但交易记录是公开可查的; +* 通胀预防:比特币的发行通过挖矿实现,发行量每四年减半,总量上限为 2100 万枚,不会出现通胀。 + +下图来自 [blockchain.info](https://blockchain.info/charts/market-price?timespan=all) 网站,可以看到比特币字诞生以来的汇率(以美元为单位)变化历史。 + +![比特币汇率历史](_images/bitcoin_price.png) + +### 比特币大事记 + +#### 2008 ~ 2013 + +![比特币白皮书邮件](_images/bitcoin_wp.png) + +2008 年 11 月 1 日 19:16:33,中本聪在 metzdowd 的加密技术邮件列表发布比特币白皮书:“比特币:一种点对点的电子现金系统(Bitcoin: A Peer-to-Peer Electronic Cash System)”。 + +2009 年 1 月 3 日 18:15:05,中本聪在位于芬兰赫尔辛基(Helsinki)的一个小型服务器上挖出了首批 50 个比特币,并在首个区块中记录了当天泰晤士报的头版标题:“The Times 03/Jan/2009 Chancellor on brink of second bailout for banks(财政大臣考虑再次紧急援助银行危机)”。首个区块也被称为创世区块或初始区块(Genesis Block),可以通过 [https://blockchain.info/block-index/14849](https://blockchain.info/block-index/14849) 查看其详细内容。 + +2009 年 1 月 12 日,中本聪将 10 枚比特币转账给开发者 Hal Finney,这也是首笔比特币转账(位于区块 170)。 + +2010 年 5 月 21 日,第一次比特币交易:佛罗里达程序员 Laszlo Hanyecz 用 1 万 BTC 购买了价值 25 美元的披萨优惠券。这是比特币的首个兑换汇率:1: 0.0025 美金。这些比特币在今日价值超过 8000 万美金。 + +2010 年 7 月 17 日,第一个比特币交易平台 Mt.Gox 成立。 + +2011 年 4 月,首个有官方正式记载的版本 0.3.21 发布,支持普通用户参与到 P2P 网络中,并开始支持最小单位 “聪”。 + +2011 年 4 月 26 日,比特币宏大网络缺失的最后一块砖被砌好。中本聪发出一封简短的邮件之后,从此不再现身。 + +2011 年初,开始出现基于显卡的挖矿设备。2011 年年底,比特币价格约为 2 美元。 + +2012 年 6 月,Coinbase 成立,支持比特币相关交易。公司目前已经发展为全球数字资产交易平台,同时支持包括比特币、以太币等数字货币。 + +2011 年 6 月 19 日,由于安全事故,Mt.Gox 数据库发生泄漏,其宣称所保管的部分比特币被盗走。 + +2012 年 9 月 27 日,比特币基金创立,此时比特币价格为 12.46 美元。 + +2012 年 11 月 28 日,比特币产量第一次减半,单个区块产生的比特币从 50 个减半到 25 个。 + +2013 年 3 月,三分之一的专业矿工已经开始采用专用 ASIC 矿机进行挖矿。 + +2013 年 3 月 11 日,比特币发布 0.8.0 版本,大量完善了节点内部管理和网络通信,使得比特币有能力支持后来大规模的 P2P 网络。该版本包含一个严重的 bug,虽然后来被紧急修复,仍造成比特币价格大幅下跌。 + +2013年 4 月 10 日,BTC 创下历史新高,266 美元。 + +2013 年 6 月 27 日,德国会议作出决定:持有比特币一年以上将予以免税,被业内认为此举变相认可了比特币的法律地位,此时比特币价格为 102.24 美元。 + +2013 年 10 月 29 日,世界第一台可以兑换比特币的 ATM 在加拿大上线。 + +2013 年 11 月 29 日,比特币的交易价格创下 1242 美元的历史新高,而同时黄金价格为一盎司 1241.98 美元,比特币价格首度超过黄金。 + + +#### 2014 ~ 2019 + +2014 年 2 月 24 日,全球最大比特币交易平台 Mt.Gox 因 85 万个比特币被盗而宣告破产并关闭,造成大量投资者的损失,比特币价格一度暴跌。 + +2014 年 3 月,中国第一台可以兑换比特币的 ATM 在香港上线。 + +2014 年 6 月,美国加州通过 AB-129 法案,允许比特币等数字货币在加州进行流通。 + +2015 年 6 月 3 日,纽约成为美国第一个正式进行数字货币监管的州。 + +2015 年 10 月 22 日,欧盟司法部宣布比特币和其它加密货币为货币而非商品,欧盟法院裁定比特币交易免征增值税。 + +2015 年 10 月 31 日,《经济学人》杂志发表封面文章《信任机器》,开始关注比特币网络背后的区块链技术。 + +2016 年 1 月,中国人民银行在京召开了数字货币研讨会,会后发布公告宣称或推出数字货币。 + +2016 年 7 月 9 日,比特币产量第二次减半,每个区块产出从 25 枚比特币减少为 12.5 枚。 + +2016 年 8 月 2 日,知名比特币交易所 Bitfinex 遭遇安全攻击,按照当时市值计算,损失超过 6000 万美金。 + +2017 年 1 月 24 日,中国部分交易所(Okcoin、火币、BTCC)开始收取比特币交易手续费(为成交金额的 0.2%)。 + +2017 年 3 月,美国证券交易监督委员会(U.S. Securities and Exchange Commission,SEC)连续否决了比特币 ETF 申请。 + +2017 年 4 月 1 日,日本通过法案,正式将数字货币交易所纳入监管体系,承认比特币是合法的预付款工具。 + +2017 年 7 月,比特币网络全网算力首次突破 6 exahash/s(即每秒10的18次方哈希),创下历史新高。 + +2017 年 9 月 4 日,北京市互联网金融风险专项整治工作领导小组办公室下发通知,停止各类 ICO 和代币发行活动。之后,国内各大交易所和矿池陆续终止境内业务。 + +2017 年 10 月 13 日,比特币的价格首次突破 5000 美元。 + +2017 年 12 月 11 日,全球首个比特币期货合约在芝加哥期权交易所(Chicago Board Options Exchange,CBOE)上市。 + +2017 年 12 月 17 日,比特币期货在芝加哥商品交易所(Chicago Mercantile Exchange,CME)上市,当天单个比特币价格一度冲破 20000 美元(总市值超过 2000 亿美金),创下历史新高。 + +2018 年 3 月 6 日,韩国政府发布禁令,禁止公职人员持有和交易加密货币。彼时比特币价格已经长期在 5000 美金左右波动。 + +2018 年 3 月 7 日,美国证券交易监督委员会发布了《关于可能违法的数字资产交易平台的声明》,规定数字货币交易所必须通过注册。 + +2018 年 6 月 21 日,受美联储降息和 Facebook 发币消息的影响,比特币价格重新攀升超过 10000 美金,并一度接近 13000 美金。 + +2019 年 6 月,由于交易量不足以及来自芝加哥商品交易所的竞争,芝加哥期权交易所决定暂停比特币期货合约交易。 + +2018 年 12 月,受到行业周期和社区内部冲突的影响,比特币价格一路下跌,迫近 3000 美金关口。 + +2019 年 6 月 18 日,Facebook 发布了加密货币项目 Libra 的白皮书,宣布要打造简单的、无国界的为数十亿普通人服务的金融基础设施。 + +2019 年 9 月 23 日,比特币期货交易平台 Bakkt 上线,支持以比特币实物进行结算。 + +2019 年 10 月 26 日,受到一系列利好消息影响,比特币价格暴涨,单日从 7600 美元涨到 10800 美元。但随后逐步跌破 7000 美金。 + +目前,比特币区块链已经生成了超过 60 万个区块,完整存储需要约 250 GB 的空间,每天平均完成 20 万笔交易。 + +### 其它数字货币 + +比特币的“成功”,刺激了相关的生态和社区发展,大量类似数字货币(超过 1000 种)纷纷出现,比较出名的包括以太币和瑞波(Ripple)币等。 + + + +这些数字货币大部分复用已有的区块链(例如比特币网络)系统,少数建立在自己独立的区块链网络上。全球活跃的数字货币用户据称在 290 万 ~ 580 万之间(参考剑桥大学 Judge 商学院 2017 年 4 月发表的《全球加密货币基准研究(Global Cryptocurrency Benchmarking Study)》报告)。 + +*注:通过 [www.blockchain.com](www.blockchain.com) 网站可以实时查询到比特币网络的信息,包括区块、交易、价格等在内的详细数据。* diff --git a/chainbrock-learning/06_bitcoin/lightning_network.md b/chainbrock-learning/06_bitcoin/lightning_network.md new file mode 100644 index 00000000..ac2930f8 --- /dev/null +++ b/chainbrock-learning/06_bitcoin/lightning_network.md @@ -0,0 +1,38 @@ +## 闪电网络 + +比特币的交易网络最为人诟病的一点便是交易性能:全网每秒 7 笔左右的交易速度,远低于传统的金融交易系统;同时,等待 6 个块的可信确认将导致约 1 个小时的最终确认时间。 + +为了提升性能,社区提出了闪电网络等创新的设计。 + +闪电网络的主要思路十分简单——将大量交易放到比特币区块链之外进行,只把关键环节放到链上进行确认。该设计最早于 2015 年 2 月在论文《The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments》中提出。 + +比特币的区块链机制自身已经提供了很好的可信保障,但是相对较慢;另一方面考虑,对于大量的小额交易来说,是否真需要这么高的可信性? + +闪电网络主要通过引入智能合约的思想来完善链下的交易渠道。核心的概念主要有两个:RSMC(Recoverable Sequence Maturity Contract)和 HTLC(Hashed Timelock Contract)。前者解决了链下交易的确认问题,后者解决了支付通道的问题。 + +### RSMC + +Recoverable Sequence Maturity Contract,即“可撤销的顺序成熟度合同”。这个词很绕,其实主要原理很简单,类似资金池机制。 + +首先假定交易双方之间存在一个“微支付通道”(资金池)。交易双方先预存一部分资金到“微支付通道”里,初始情况下双方的分配方案等于预存的金额。每次发生交易,需要对交易后产生资金分配结果共同进行确认,同时签字把旧版本的分配方案作废掉。任何一方需要提现时,可以将他手里双方签署过的交易结果写到区块链网络中,从而被确认。从这个过程中可以可以看到,只有在提现时候才需要通过区块链。 + +任何一个版本的方案都需要经过双方的签名认证才合法。任何一方在任何时候都可以提出提现,提现时需要提供一个双方都签名过的资金分配方案(意味着肯定是某次交易后的结果,被双方确认过,但未必是最新的结果)。在一定时间内,如果另外一方拿出证明表明这个方案其实之前被作废了(非最新的交易结果),则资金罚没给质疑方;否则按照提出方的结果进行分配。罚没机制可以确保了没人会故意拿一个旧的交易结果来提现。 + +另外,即使双方都确认了某次提现,首先提出提现一方的资金到账时间要晚于对方,这就鼓励大家尽量都在链外完成交易。通过 RSMC,可以实现大量中间交易发生在链外。 + +### HTLC + +微支付通道是通过 Hashed Timelock Contract 来实现的,中文意思是“哈希的带时钟的合约”。这个其实就是限时转账。理解起来也很简单,通过智能合约,双方约定转账方先冻结一笔钱,并提供一个哈希值,如果在一定时间内有人能提出一个字符串,使得它哈希后的值跟已知值匹配(实际上意味着转账方授权了接收方来提现),则这笔钱转给接收方。 + +不太恰当的例子,约定一定时间内,有人知道了某个暗语(可以生成匹配的哈希值),就可以拿到这个指定的资金。 + +推广一步,甲想转账给丙,丙先发给甲一个哈希值。甲可以先跟乙签订一个合同,如果你在一定时间内能告诉我一个暗语,我就给你多少钱。乙于是跑去跟丙签订一个合同,如果你告诉我那个暗语,我就给你多少钱。丙于是告诉乙暗语,拿到乙的钱,乙又从甲拿到钱。最终达到结果是甲转账给丙。这样甲和丙之间似乎构成了一条完整的虚拟的“支付通道”。 + +HTLC 机制可以扩展到多个人的场景。 + +### 闪电网络 + +RSMC 保障了两个人之间的直接交易可以在链下完成,HTLC 保障了任意两个人之间的转账都可以通过一条“支付”通道来完成。闪电网络整合这两种机制,就可以实现任意两个人之间的交易都在链下完成了。 + +在整个交易中,智能合约起到了中介的重要角色,而区块链网络则确保最终的交易结果被确认。 + diff --git a/chainbrock-learning/06_bitcoin/mining.md b/chainbrock-learning/06_bitcoin/mining.md new file mode 100644 index 00000000..19015a26 --- /dev/null +++ b/chainbrock-learning/06_bitcoin/mining.md @@ -0,0 +1,38 @@ +## 挖矿过程 + +### 基本原理 + +比特币中最独特的一个概念就是“挖矿”。挖矿是指网络中的维护节点,通过协助生成和确认新区块来获取一定量新增比特币的过程。 + +当用户向比特币网络中发布交易后,需要有人将交易进行记录和确认,形成新的区块,并串联到区块链中。在一个互相不信任的分布式系统中,该由谁来完成这件事情呢?比特币网络采用了“挖矿”的方式来解决这个问题。 + +目前,每 10 分钟左右生成一个不超过 1 MB 大小的区块(记录了这 10 分钟内发生的验证过的交易内容),串联到最长的链尾部,每个区块的成功提交者可以得到系统 12.5 个比特币的奖励(该奖励作为区块内的第一个交易,一定区块数后才能使用),以及用户附加到交易上的支付服务费用。即便没有任何用户交易,矿工也可以自行产生合法的区块并获得奖励。 + +每个区块的奖励最初是 50 个比特币,每隔 21 万个区块自动减半,即 4 年时间,最终比特币总量稳定在 2100 万个。因此,比特币是一种通缩的货币。 + +### 挖矿过程 + +挖矿的具体过程为:参与者综合上一个区块的 Hash 值,上一个区块生成之后的新的验证过的交易内容,再加上自己猜测的一个随机数 X,一起打包到一个候选新区块,让新区块的 Hash 值小于比特币网络中给定的一个数。这是一道面向全体矿工的“计算题”,这个数越小,计算出来就越难。 + +系统每隔两周(即经过 2016 个区块)会根据上一周期的挖矿时间来调整挖矿难度(通过调整限制数的大小),来调节生成区块的时间稳定在 10 分钟左右。为了避免震荡,每次调整的最大幅度为 4 倍。历史上最快的出块时间小于 10s,最慢的出块时间超过 1 个小时。 + +为了挖到矿,参与处理区块的用户端往往需要付出大量的时间和计算力。算力一般以每秒进行多少次 Hash 计算为单位,记为 h/s。目前,比特币网络算力峰值已经达到了每秒数百亿亿次。 + +汇丰银行分析师 Anton Tonev 和 Davy Jose 在 2016 年一份客户报告中曾表示,比特币区块链(通过挖矿)提供了一个局部的、迄今为止最优的解决方案:如何在分散的系统中验证信任。这就意味着,区块链本质上解决了传统依赖于第三方的问题,因为这个协议不只满足了中心化机构追踪交易的需求,还使得陌生人之间产生信任。区块链的技术和安全的过程使得陌生人之间在没有被信任的第三方时产生信任。 + +### 如何看待挖矿 + +2010 年以前,挖矿还是一个非常热门的盈利行业。 + +但是随着相关技术和设备的发展,现在个人进行挖矿的收益已经降得很低。从概率上说,由于当前参与挖矿的计算力实在过于庞大(已经超出了大部分的超算中心),一般的算力已经不可能挖到比特币。特别是利用虚拟机来挖矿的想法,已经基本不可能了。 + +从普通的 CPU(2009 年)、到后来的 GPU(2010 年) 和 FPGA(2011 年末)、到后来的 ASIC 矿机(2013 年年初,目前单片算力已达每秒数百亿次 Hash 计算)、再到现在众多矿机联合组成矿池(知名矿池包括 F2Pool、BitFury 等)。短短数年间,比特币矿机的技术走完了过去几十年的集成电路的进化历程,甚至还颇有创新之处。高回报刺激了科技的飞速发展。目前,矿机主要集中在少数矿池手中,全网的算力已超过每秒 10^20 次 Hash 计算。如果简单认为一次 Hash 计算等同于一次浮点运算,那么比特币全网算力将等同于 500 台 Summit 超级计算机(目前最快的超级计算机,由 IBM 和 Nvidia 于 2018 年研制)。 + +很自然地,读者可能会想到,如果有人掌握了强大的计算力,计算出所有的新区块,并且拒不承认他人的交易内容,那是不是就能破坏掉比特币网络。确实如此,基本上个体达到 1/3 的计算力,比特币网络就存在被破坏的风险了;达到 1/2 的算力,从概率上就掌控整个网络了。但是要实现这么大的算力,将需要付出巨大的经济成本。 + +那么有没有办法防护呢?除了尽量避免计算力放到同一个组织手里,没太好的办法,这是目前 PoW 机制自身造成的。 + +也有人认为为了共识区块的生成,大部分计算力(特别是最终未能算出区块的算力)其实都浪费了。有人提出用 PoS(Proof of Stake)和 DPoS 等协议,利用权益证明(例如持有货币的币龄)作为衡量指标进行投票,相对 PoW 可以节约大量的能耗。PoS 可能会带来囤积货币的问题。除此之外,还有活跃度证明(Proof of Activity,PoA)、消耗证明(Proof of Burn,PoB)、能力证明(Proof of Capacity, PoC)、消逝时间证明(Proof of Elapsed Time)、股权速率证明(Proof of Stake Velocity,PoSV)等,采用了不同的衡量指标。 + +当然,无论哪种机制,都无法解决所有问题。一种可能的优化思路是引入随机代理人制度,通过算法在某段时间内确保只让部分节点参加共识的提案,并且要发放一部分“奖励”给所有在线贡献的节点。 + diff --git a/chainbrock-learning/06_bitcoin/sidechain.md b/chainbrock-learning/06_bitcoin/sidechain.md new file mode 100644 index 00000000..20ce1399 --- /dev/null +++ b/chainbrock-learning/06_bitcoin/sidechain.md @@ -0,0 +1,45 @@ +## 侧链 + +侧链(Sidechain)协议允许资产在比特币区块链和其他区块链之间互转。这一项目也来自比特币社区,最早是在 2013 年 12 月提出,2014 年 4 月立项,由 Blockstream 公司(由比特币核心开发者 Adam Back、Matt Corallo 等共同发起成立)主导研发。侧链协议于 2014 年 10 月在白皮书《Enabling Blockchain Innovations with Pegged Sidechains》中公开。 + +侧链诞生前,众多“山寨币”的出现正在碎片化整个数字货币市场,再加上以太坊等项目的竞争,一些比特币开发者希望能借助侧链的形式扩展比特币的底层协议。 + +简单来讲,以比特币区块链作为主链(Parent chain),其他区块链作为侧链,二者通过双向挂钩(Two-way peg),可实现比特币从主链转移到侧链进行流通。 + +![比特币侧链](_images/sidechain.png) + +侧链可以是一个独立的区块链,有自己按需定制的账本、共识机制、交易类型、脚本和合约的支持等。侧链不能发行比特币,但可以通过支持与比特币区块链挂钩来引入和流通一定数量的比特币。当比特币在侧链流通时,主链上对应的比特币会被锁定,直到比特币从侧链回到主链。可以看到,侧链机制可将一些定制化或高频的交易放到比特币主链之外进行,实现了比特币区块链的扩展。侧链的核心原理在于能够冻结一条链上的资产,然后在另一条链上产生,可以通过多种方式来实现。这里讲解 Blockstream 提出的基于简单支付验证(Simplified Payment Verification,SPV)证明的方法。 + +### SPV 证明 + +如前面章节所述,在比特币系统中验证交易时,涉及到交易合法性检查、双重花费检查、脚本检查等。由于验证过程需要完整的 UTXO 记录,通常要由运行着完整功能节点的矿工来完成。 + +而很多时候,用户只关心与自己相关的那些交易,比如当用户收到其他人号称发来的比特币时,只希望能够知道交易是否合法、是否已在区块链中存在了足够的时间(即获得足够的确认),而不需要自己成为完整节点做出完整验证。 + +中本聪设计的简单支付验证(Simplified Payment Verification,SPV)可以实现这一点。SPV 能够以较小的代价判断某个支付交易是否已经被验证过(存在于区块链中),以及得到了多少算力保护(定位包含该交易的区块在区块链中的位置)。SPV 客户端只需要下载所有区块的区块头(Block Header),并进行简单的定位和计算工作就可以给出验证结论。 + +侧链协议中,用 SPV 来证明一个交易确实已经在区块链中发生过,称为 SPV 证明(SPV Proof)。一个 SPV 证明包括两部分内容:一组区块头的列表,表示工作量证明;一个特定输出(output)确实存在于某个区块中的密码学证明。 + +### 双向挂钩 + +侧链协议的设计难点在于如何让资产在主链和侧链之间安全流转。简而言之,接受资产的链必须确保发送资产的链上的币被可靠锁定。 + +![侧链双向挂钩的过程](_images/sidechain_workflow.png) + +具体,协议采用双向挂钩机制实现比特币向侧链转移和返回。主链和侧链需要对对方的特定交易做 SPV 验证。完整过程如下: + +* 当用户要向侧链转移比特币时,首先在主链创建交易,待转移的比特币被发往一个特殊的输出。这些比特币在主链上被锁定。 +* 等待一段确认期,使得上述交易获得足够的工作量确认。 +* 用户在侧链创建交易提取比特币,需要在这笔交易的输入指明上述主链被锁定的输出,并提供足够的 SPV 证明。 +* 等待一段竞争期,防止双重花费攻击。 +* 比特币在侧链上自由流通。 +* 当用户想让比特币返回主链时,采取类似的反向操作。首先在侧链创建交易,待返回的比特币被发往一个特殊的输出。先等待一段确认期后,在主链用足够的对侧链输出的 SPV 证明来解锁最早被锁定的输出。竞争期过后,主链比特币恢复流通。 + +### 最新进展 + +侧链技术最早由 Blockstream 公司进行探索,于 2015 年 10 月联合合作伙伴发布了基于侧链的商业化应用 Liquid。 + +基于一年多的探索,Blockstream 于 2017 年 1 月发表文章《Strong Federations: An Interoperable Blockchain Solution to Centralized Third Party Risks》,被称为对侧链早期白皮书的补充和改良。白皮书中着重描述了联合挂钩(Federated Pegs)的相关概念和应用。 + +此外,还有一些其他公司或组织也在探索如何合理地应用侧链技术,包括 ConsenSys、Rootstock、Lisk 等。 + diff --git a/chainbrock-learning/06_bitcoin/summary.md b/chainbrock-learning/06_bitcoin/summary.md new file mode 100644 index 00000000..6c93abdf --- /dev/null +++ b/chainbrock-learning/06_bitcoin/summary.md @@ -0,0 +1,7 @@ +## 本章小结 + +本章介绍了比特币项目的相关知识,包括起源、核心原理和设计、重要机制,以及最新的闪电网络、侧链和扩容讨论等进展。 + +比特币自身作为数字货币领域的重大突破,对分布式记账领域有着很深远的影响。尤其是其底层的区块链技术,已经受到金融和信息行业的重视,在许多场景下都得到应用。 + +通过本章的剖析,可以看出,比特币网络系统中并非是全新出现的技术,而是有机地组合了密码学、博弈论、记账技术、分布式系统和网络、控制论等领域的已有成果。比特币发明者能从如此广博的多个领域进行了恰当的选取,有效吸收前人的研究成果,这是真正的大师境界。正是如此巧妙的组合,让比特币项目产生了广泛且深远的影响。 diff --git a/chainbrock-learning/06_bitcoin/tools.md b/chainbrock-learning/06_bitcoin/tools.md new file mode 100644 index 00000000..7c065f9d --- /dev/null +++ b/chainbrock-learning/06_bitcoin/tools.md @@ -0,0 +1,37 @@ +## 相关工具 + +比特币相关工具包括客户端、钱包和矿机等。 + +### 客户端 + +比特币客户端用于和比特币网络进行交互,同时可以参与到网络的维护。 + +客户端分为三种:完整客户端、轻量级客户端和在线客户端。 + +* 完整客户端:存储所有的交易历史记录,功能完备; +* 轻量级客户端:不保存交易副本,交易需要向别人查询; +* 在线客户端:通过网页模式来浏览第三方服务器提供的服务。 + +比特币客户端可以从 https://bitcoin.org/en/download 下载到。 + +基于比特币客户端,可以很容易实现用户钱包功能。 + +### 钱包 + +比特币钱包存储和保护用户的私钥,并提供查询比特币余额、收发比特币等功能。根据私钥存储方式不同,钱包主要分为以下几种: + +* 离线钱包:离线存储私钥,也称为“冷钱包”。安全性相对最强,但无法直接发送交易,便利性差。 +* 本地钱包:用本地设备存储私钥。可直接向比特币网络发送交易,易用性强,但本地设备存在被攻击风险。 +* 在线钱包:用钱包服务器存储经用户口令加密过的私钥。易用性强,但钱包服务器同样可能被攻击。 +* 多重签名钱包:由多方共同管理一个钱包地址,比如 2 of 3 模式下,集合三位管理者中的两位的私钥便可以发送交易。 + +比特币钱包可以从 https://bitcoin.org/en/choose-your-wallet 获取到。 + +### 矿机 + +比特币矿机是专门为“挖矿”设计的硬件设备,目前主要包括基于 GPU 和 ASIC 芯片的专用矿机。这些矿机往往采用特殊的设计来加速挖矿过程中的计算处理。 + +矿机最重要的属性是可提供的算力(通常以每秒可进行 Hash 计算的次数来表示)和所需要的功耗。当算力足够大,可以在概率意义上挖到足够多的新的区块,来弥补电力费用时,该矿机是可以盈利的;当单位电力产生的算力不足以支付电力费用时,该矿机无法盈利,意味着只能被淘汰。 + +目前,比特币网络中的全网算力仍然在快速增长中,矿工需要综合考虑算力变化、比特币价格、功耗带来的电费等许多问题,需要算好“经济账”。 + diff --git a/chainbrock-learning/07_ethereum/README.md b/chainbrock-learning/07_ethereum/README.md new file mode 100644 index 00000000..b6cfe6ad --- /dev/null +++ b/chainbrock-learning/07_ethereum/README.md @@ -0,0 +1,9 @@ +# 以太坊 —— 挣脱数字货币的枷锁 + +** 君子和而不同。 ** + +在区块链领域,以太坊项目同样是十分出名的开源项目。作为公有区块链平台,以太坊将比特币针对数字货币交易的功能进一步进行拓展,面向更为复杂和灵活的应用场景,支持了智能合约(Smart Contract)这一重要特性。 + +从此,区块链技术的应用场景,从单一基于 UTXO 的数字货币交易,延伸到图灵完备的通用计算领域。用户不再受限于仅能使用比特币脚本所支持的简单逻辑,而是可以自行设计任意复杂的合约逻辑。这就为构建各种多样化的上层应用开启了大门,可谓意义重大。 + +本章将参照比特币项目来介绍以太坊项目的核心概念和改进设计,以及如何安装客户端和使用智能合约等内容。 diff --git a/chainbrock-learning/07_ethereum/_images/dapps.png b/chainbrock-learning/07_ethereum/_images/dapps.png new file mode 100644 index 00000000..682018d7 Binary files /dev/null and b/chainbrock-learning/07_ethereum/_images/dapps.png differ diff --git a/chainbrock-learning/07_ethereum/_images/ethereum_logo.png b/chainbrock-learning/07_ethereum/_images/ethereum_logo.png new file mode 100644 index 00000000..f146232d Binary files /dev/null and b/chainbrock-learning/07_ethereum/_images/ethereum_logo.png differ diff --git a/chainbrock-learning/07_ethereum/_images/mist.png b/chainbrock-learning/07_ethereum/_images/mist.png new file mode 100644 index 00000000..d2425f27 Binary files /dev/null and b/chainbrock-learning/07_ethereum/_images/mist.png differ diff --git a/chainbrock-learning/07_ethereum/concept.md b/chainbrock-learning/07_ethereum/concept.md new file mode 100644 index 00000000..3890971a --- /dev/null +++ b/chainbrock-learning/07_ethereum/concept.md @@ -0,0 +1,54 @@ +## 核心概念 + +基于比特币网络的核心思想,以太坊项目提出了许多创新的技术概念,包括智能合约、基于账户的交易、以太币和燃料等。 + +### 智能合约 + +智能合约(Smart Contract)是以太坊中最为重要的一个概念,即以计算机程序的方式来缔结和运行各种合约。最早在上世纪 90 年代,Nick Szabo 等人就提出过类似的概念,但一直依赖因为缺乏可靠执行智能合约的环境,而被作为一种理论设计。区块链技术的出现,恰好补充了这一缺陷。 + +以太坊支持通过图灵完备的高级语言(包括 Solidity、Serpent、Viper)等来开发智能合约。智能合约作为运行在以太坊虚拟机(Ethereum Virual Machine,EVM)中的应用,可以接受来自外部的交易请求和事件,通过触发运行提前编写好的代码逻辑,进一步生成新的交易和事件,可以进一步调用其它智能合约。 + +智能合约的执行结果可能对以太坊网络上的账本状态进行更新。这些修改由于经过了以太坊网络中的共识,一旦确认后无法被伪造和篡改。 + +### 账户 + +在之前章节中,笔者介绍过比特币在设计中并没有账户(Account)的概念,而是采用了 UTXO 模型记录整个系统的状态。任何人都可以通过交易历史来推算出用户的余额信息。而以太坊则采用了不同的做法,直接用账户来记录系统状态。每个账户存储余额信息、智能合约代码和内部数据存储等。以太坊支持在不同的账户之间转移数据,以实现更为复杂的逻辑。 + +具体来看,以太坊账户分为两种类型:合约账户(Contracts Accounts)和外部账户(Externally Owned Accounts,或 EOA)。 + +* 合约账户:存储执行的智能合约代码,只能被外部账户来调用激活; +* 外部账户:以太币拥有者账户,对应到某公钥。账户包括 nonce、balance、storageRoot、codeHash 等字段,由个人来控制。 + +当合约账户被调用时,存储其中的智能合约会在矿工处的虚拟机中自动执行,并消耗一定的燃料。燃料通过外部账户中的以太币进行购买。 + +### 交易 + +交易(Transaction),在以太坊中是指从一个账户到另一个账户的消息数据。消息数据可以是以太币或者合约执行参数。 + +以太坊采用交易作为执行操作的最小单位。每个交易包括如下字段: + +* to:目标账户地址。 +* value:可以指定转移的以太币数量。 +* nonce:交易相关的字串,用于防止交易被重放。 +* gasPrice:执行交易需要消耗的 Gas 价格。 +* gasLimit:交易消耗的最大 Gas 值。 +* data: 交易附带字节码信息,可用于创建/调用智能合约。 +* signature:基于椭圆曲线加密的签名信息,包括R,S,V 三个字段。。 + +类似比特币网络,在发送交易时,用户需要缴纳一定的交易费用,通过以太币方式进行支付和消耗。目前,以太坊网络可以支持超过比特币网络的交易速率(可以达到每秒几十笔)。 + +### 以太币 + +以太币(Ether)是以太坊网络中的货币。 + +以太币主要用于购买燃料,支付给矿工,以维护以太坊网络运行智能合约的费用。以太币最小单位是 wei,一个以太币等于 10^18 个 wei。 + +以太币同样可以通过挖矿来生成。成功生成新区块的以太坊矿工可以获得 2 个以太币的奖励,以及包含在区块内的燃料费用和发现叔块(Uncle block)获得的奖励。用户也可以通过交易市场来直接购买以太币。 + +目前每年大约可以通过挖矿生成超过一千万个以太币,单个以太币的市场价格目前超过 300 美金。 + +### 燃料 + +燃料(Gas),控制某次交易执行指令的上限。每执行一条合约指令会消耗固定的燃料。当某个交易还未执行结束,而燃料消耗完时,合约执行终止并回滚状态。 + +Gas 可以跟以太币进行兑换。需要注意的是,以太币的价格是波动的,但运行某段智能合约的燃料费用可以是固定的,通过设定 Gas 价格等进行调节。 diff --git a/chainbrock-learning/07_ethereum/contract_example.md b/chainbrock-learning/07_ethereum/contract_example.md new file mode 100644 index 00000000..8c64b80d --- /dev/null +++ b/chainbrock-learning/07_ethereum/contract_example.md @@ -0,0 +1,194 @@ +## 智能合约案例:投票 + +本节将介绍一个用 Solidity 语言编写的智能合约案例。代码来源于 [Solidity 官方文档](https://solidity.readthedocs.io/en/latest/index.html) 中的示例。 + +该智能合约实现了一个自动化的、透明的投票应用。投票发起人可以发起投票,将投票权赋予投票人;投票人可以自己投票,或将自己的票委托给其他投票人;任何人都可以公开查询投票的结果。 + +### 智能合约代码 + +实现上述功能的合约代码如下所示,并不复杂,语法跟 JavaScript 十分类似。 + +```js +pragma solidity ^0.4.11; + +contract Ballot { + struct Voter { + uint weight; + bool voted; + address delegate; + uint vote; + } + + struct Proposal { + bytes32 name; + uint voteCount; + } + + address public chairperson; + mapping(address => Voter) public voters; + Proposal[] public proposals; + + // Create a new ballot to choose one of `proposalNames` + function Ballot(bytes32[] proposalNames) { + chairperson = msg.sender; + voters[chairperson].weight = 1; + + for (uint i = 0; i < proposalNames.length; i++) { + proposals.push(Proposal({ + name: proposalNames[i], + voteCount: 0 + })); + } + } + + // Give `voter` the right to vote on this ballot. + // May only be called by `chairperson`. + function giveRightToVote(address voter) { + require((msg.sender == chairperson) && !voters[voter].voted); + voters[voter].weight = 1; + } + + // Delegate your vote to the voter `to`. + function delegate(address to) { + Voter sender = voters[msg.sender]; + require(!sender.voted); + require(to != msg.sender); + + while (voters[to].delegate != address(0)) { + to = voters[to].delegate; + + // We found a loop in the delegation, not allowed. + require(to != msg.sender); + } + + sender.voted = true; + sender.delegate = to; + Voter delegate = voters[to]; + if (delegate.voted) { + proposals[delegate.vote].voteCount += sender.weight; + } else { + delegate.weight += sender.weight; + } + } + + // Give your vote (including votes delegated to you) + // to proposal `proposals[proposal].name`. + function vote(uint proposal) { + Voter sender = voters[msg.sender]; + require(!sender.voted); + sender.voted = true; + sender.vote = proposal; + + proposals[proposal].voteCount += sender.weight; + } + + // @dev Computes the winning proposal taking all + // previous votes into account. + function winningProposal() constant + returns (uint winningProposal) + { + uint winningVoteCount = 0; + for (uint p = 0; p < proposals.length; p++) { + if (proposals[p].voteCount > winningVoteCount) { + winningVoteCount = proposals[p].voteCount; + winningProposal = p; + } + } + } + + // Calls winningProposal() function to get the index + // of the winner contained in the proposals array and then + // returns the name of the winner + function winnerName() constant + returns (bytes32 winnerName) + { + winnerName = proposals[winningProposal()].name; + } +} +``` + +### 代码解析 + +#### 指定版本 + +在第一行,`pragma` 关键字指定了和该合约兼容的编译器版本。 + +``` +pragma solidity ^0.4.11; +``` + +该合约指定,不兼容比 `0.4.11` 更旧的编译器版本,且 `^` 符号表示也不兼容从 `0.5.0` 起的新编译器版本。即兼容版本范围是 `0.4.11 <= version < 0.5.0`。该语法与 npm 的版本描述语法一致。 + +#### 结构体类型 + +Solidity 中的合约(contract)类似面向对象编程语言中的类。每个合约可以包含状态变量、函数、事件、结构体类型和枚举类型等。一个合约也可以继承另一个合约。 + +在本例命名为 `Ballot` 的合约中,声明了 2 个结构体类型:`Voter` 和 `Proposal`。 + +* `struct Voter`:投票人,其属性包括 `uint weight`(该投票人的权重)、`bool voted`(是否已投票)、`address delegate`(如果该投票人将投票委托给他人,则记录受委托人的账户地址)和 `uint vote`(投票做出的选择,即相应提案的索引号)。 +* `struct Proposal`:提案,其属性包括 `bytes32 name`(名称)和 `uint voteCount`(已获得的票数)。 + +需要注意,`address` 类型记录了一个以太坊账户的地址。`address` 可看作一个数值类型,但也包括一些与以太币相关的方法,如查询余额 `
.balance`、向该地址转账 `
.transfer(uint256 amount)` 等。 + +#### 状态变量 + +合约中的状态变量会长期保存在区块链中。通过调用合约中的函数,这些状态变量可以被读取和改写。 + +本例中定义了 3 个状态变量:`chairperson`、`voters`、`proposals`。 + +* `address public chairperson`:投票发起人,类型为 `address`。 +* `mapping(address => Voter) public voters`:所有投票人,类型为 `address` 到 `Voter` 的映射。 +* `Proposal[] public proposals`:所有提案,类型为动态大小的 `Proposal` 数组。 + +3 个状态变量都使用了 `public` 关键字,使得变量可以被外部访问(即通过消息调用)。事实上,编译器会自动为 `public` 的变量创建同名的 getter 函数,供外部直接读取。 + +状态变量还可设置为 `internal` 或 `private`。`internal` 的状态变量只能被该合约和继承该合约的子合约访问,`private` 的状态变量只能被该合约访问。状态变量默认为 `internal`。 + +将上述关键状态信息设置为 `public` 能够增加投票的公平性和透明性。 + +#### 函数 + +合约中的函数用于处理业务逻辑。函数的可见性默认为 `public`,即可以从内部或外部调用,是合约的对外接口。函数可见性也可设置为 `external`、`internal` 和 `private`。 + +本例实现了 6 个 `public` 函数,可看作 6 个对外接口,功能分别如下。 + +##### 创建投票 +函数 `function Ballot(bytes32[] proposalNames)` 用于创建一个新的投票。 + +所有提案的名称通过参数 `bytes32[] proposalNames` 传入,逐个记录到状态变量 `proposals` 中。同时用 `msg.sender` 获取当前调用消息的发送者的地址,记录为投票发起人 `chairperson`,该发起人投票权重设为 1。 + +##### 赋予投票权 + +函数 `function giveRightToVote(address voter)` 实现给投票人赋予投票权。 + +该函数给 `address voter` 赋予投票权,即将 `voter` 的投票权重设为 1,存入 `voters` 状态变量。 + +这个函数只有投票发起人 `chairperson` 可以调用。这里用到了 `require((msg.sender == chairperson) && !voters[voter].voted)` 函数。如果 `require` 中表达式结果为 `false`,这次调用会中止,且回滚所有状态和以太币余额的改变到调用前。但已消耗的 Gas 不会返还。 + +##### 委托投票权 + +函数 `function delegate(address to)` 把投票委托给其他投票人。 + +其中,用 `voters[msg.sender]` 获取委托人,即此次调用的发起人。用 `require` 确保发起人没有投过票,且不是委托给自己。由于被委托人也可能已将投票委托出去,所以接下来,用 `while` 循环查找最终的投票代表。找到后,如果投票代表已投票,则将委托人的权重加到所投的提案上;如果投票代表还未投票,则将委托人的权重加到代表的权重上。 + +该函数使用了 `while` 循环,这里合约编写者需要十分谨慎,防止调用者消耗过多 Gas,甚至出现死循环。 + +##### 进行投票 + +函数 `function vote(uint proposal)` 实现投票过程。 + +其中,用 `voters[msg.sender]` 获取投票人,即此次调用的发起人。接下来检查是否是重复投票,如果不是,进行投票后相关状态变量的更新。 + +##### 查询获胜提案 + +函数 `function winningProposal() constant returns (uint winningProposal)` 将返回获胜提案的索引号。 + +这里,`returns (uint winningProposal)` 指定了函数的返回值类型,`constant` 表示该函数不会改变合约状态变量的值。 + +函数通过遍历所有提案进行记票,得到获胜提案。 + +##### 查询获胜者名称 + +函数 `function winnerName() constant returns (bytes32 winnerName)` 实现返回获胜者的名称。 + +这里采用内部调用 `winningProposal()` 函数的方式获得获胜提案。如果需要采用外部调用,则需要写为 `this.winningProposal()`。 diff --git a/chainbrock-learning/07_ethereum/design.md b/chainbrock-learning/07_ethereum/design.md new file mode 100644 index 00000000..bf5ecbbf --- /dev/null +++ b/chainbrock-learning/07_ethereum/design.md @@ -0,0 +1,66 @@ +## 主要设计 + +以太坊项目的基本设计与比特币网络类似。为了支持更复杂的智能合约,以太坊在不少地方进行了改进,包括交易模型、共识、对攻击的防护和可扩展性等。 + +### 智能合约相关设计 + +#### 运行环境 + +以太坊采用以太坊虚拟机作为智能合约的运行环境。以太坊虚拟机是一个隔离的轻量级虚拟机环境,运行在其中的智能合约代码无法访问本地网络、文件系统或其它进程。 + +对同一个智能合约来说,往往需要在多个以太坊虚拟机中同时运行多份,以确保整个区块链数据的一致性和高度的容错性。另一方面,这也限制了整个网络的容量。 + +#### 开发语言 + +以太坊为编写智能合约设计了图灵完备的高级编程语言,降低了智能合约开发的难度。 + +目前 Solidity 是最常用的以太坊合约编写语言之一。 + +智能合约编写完毕后,用编译器编译为以太坊虚拟机专用的二进制格式(EVM bytecode),由客户端上传到区块链当中,之后在矿工的以太坊虚拟机中执行。 + +### 交易模型 + +出于智能合约的便利考虑,以太坊采用了账户的模型,状态可以实时的保存到账户里,而无需像比特币的 UXTO 模型那样去回溯整个历史。 + +UXTO 模型和账户模型的对比如下。 + +| 特性 |UXTO 模型|账户模型| +|--|--|--| +|状态查询和变更|需要回溯历史|直接访问| +|存储空间|较大|较小| +|易用性|较难处理|易于理解和编程| +|安全性|较好|需要处理好重放攻击等情况| +|可追溯性|支持历史|不支持追溯历史| + +### 共识 + +以太坊目前采用了基于成熟的 PoW 共识的变种算法 Ethash 协议作为共识机制。 + +为了防止 ASIC 矿机矿池的算力攻击,跟原始 PoW 的计算密集型 Hash 运算不同,Ethash 在执行时候需要消耗大量内存,反而跟计算效率关系不大。这意味着很难制造出专门针对 Ethash 的芯片,反而是通用机器可能更加有效。 + +虽然,Ethash 相对原始的 PoW 进行了改进,但仍然需要进行大量无效的运算,这也为人们所诟病。 + +社区已经有计划在未来采用更高效的 Proof-of-Stake(PoS)作为共识机制。相对 PoW 机制来讲,PoS 机制无需消耗大量无用的 Hash 计算,但其共识过程的复杂度要更高一些,还有待进一步的检验。 + +### 降低攻击 + +以太坊网络中的交易更加多样化,也就更容易受到攻击。 + +以太坊网络在降低攻击方面的核心设计思想,仍然是通过经济激励机制防止少数人作恶: + +* 所有交易都要提供交易费用,避免 DDoS 攻击; +* 程序运行指令数通过 Gas 来限制,所消耗的费用超过设定上限时就会被取消,避免出现恶意合约。 + +这就确保了攻击者试图消耗网络中虚拟机的计算资源时,需要付出经济代价(支付大量的以太币);同时难以通过构造恶意的循环或不稳定合约代码来对网络造成破坏。 + +### 提高扩展性 + +可扩展性是以太坊网络承接更多业务量的最大制约。 + +以太坊项目未来希望通过分片(sharding)机制来提高整个网络的扩展性。 + +分片是一组维护和执行同一批智能合约的节点组成的子网络,是整个网络的子集。 + +支持分片功能之前,以太坊整个网络中的每个节点都需要处理所有的智能合约,这就造成了网络的最大处理能力会受限于单个节点的处理能力。 + +分片后,同一片内的合约处理是同步的,彼此达成共识,不同分片之间则可以是异步的,可以提高网络整体的可扩展性。 diff --git a/chainbrock-learning/07_ethereum/install.md b/chainbrock-learning/07_ethereum/install.md new file mode 100644 index 00000000..2d643c78 --- /dev/null +++ b/chainbrock-learning/07_ethereum/install.md @@ -0,0 +1,115 @@ +## 安装客户端 + +本节将介绍如何安装 Geth,即 Go 语言实现的以太坊客户端。这里以 Ubuntu 16.04 操作系统为例,介绍从 PPA 仓库和从源码编译这两种方式来进行安装。 + +### 从 PPA 直接安装 + +首先安装必要的工具包。 + +```sh +$ apt-get install software-properties-common +``` + +之后用以下命令添加以太坊的源。 + +```sh +$ add-apt-repository -y ppa:ethereum/ethereum +$ apt-get update +``` + +最后安装 go-ethereum。 + +```sh +$ apt-get install ethereum +``` + +安装成功后,则可以开始使用命令行客户端 Geth。可用 `geth --help` 查看各命令和选项,例如,用以下命令可查看 Geth 版本为 1.6.1-stable。 + +```sh +$ geth version + +Geth +Version: 1.6.1-stable +Git Commit: 021c3c281629baf2eae967dc2f0a7532ddfdc1fb +Architecture: amd64 +Protocol Versions: [63 62] +Network Id: 1 +Go Version: go1.8.1 +Operating System: linux +GOPATH= +GOROOT=/usr/lib/go-1.8 +``` + +### 从源码编译 + +也可以选择从源码进行编译安装。 + +#### 安装 Go 语言环境 + +Go 语言环境可以自行访问 [golang.org](https://golang.org) 网站下载二进制压缩包安装。注意不推荐通过包管理器安装版本,往往比较旧。 + +如下载 Go 1.8 版本,可以采用如下命令。 + +```bash +$ curl -O https://storage.googleapis.com/golang/go1.8.linux-amd64.tar.gz +``` + +下载完成后,解压目录,并移动到合适的位置(推荐为 /usr/local 下)。 + +```bash +$ tar -xvf go1.8.linux-amd64.tar.gz +$ sudo mv go /usr/local +``` + +安装完成后记得配置 GOPATH 环境变量。 + +```bash +$ export GOPATH=YOUR_LOCAL_GO_PATH/Go +$ export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin +``` + +此时,可以通过 `go version` 命令验证安装 是否成功。 + +```bash +$ go version + +go version go1.8 linux/amd64 +``` + +#### 下载和编译 Geth + +用以下命令安装 C 的编译器。 + +```sh +$ apt-get install -y build-essential +``` + +下载选定的 go-ethereum 源码版本,如最新的社区版本: + +```bash +$ git clone https://github.com/ethereum/go-ethereum +``` + +编译安装 Geth。 + +```bash +$ cd go-ethereum +$ make geth +``` + +安装成功后,可用 `build/bin/geth --help` 查看各命令和选项。例如,用以下命令可查看 Geth 版本为 1.6.3-unstable。 + +```bash +$ build/bin/geth version +Geth +Version: 1.6.3-unstable +Git Commit: 067dc2cbf5121541aea8c6089ac42ce07582ead1 +Architecture: amd64 +Protocol Versions: [63 62] +Network Id: 1 +Go Version: go1.8 +Operating System: linux +GOPATH=/usr/local/gopath/ +GOROOT=/usr/local/go +``` + diff --git a/chainbrock-learning/07_ethereum/intro.md b/chainbrock-learning/07_ethereum/intro.md new file mode 100644 index 00000000..abc552dd --- /dev/null +++ b/chainbrock-learning/07_ethereum/intro.md @@ -0,0 +1,56 @@ +## 以太坊项目简介 + +![以太坊项目](_images/ethereum_logo.png) + +以太坊(Ethereum)项目的最初目标,是打造一个运行智能合约的平台(Platform for Smart Contract)。该平台支持图灵完备的应用,按照智能合约的约定逻辑自动执行,理想情况下将不存在故障停机、审查、欺诈,以及第三方干预等问题。 + +以太坊平台目前支持 Golang、C++、Python 等多种语言实现的客户端。由于核心实现上基于比特币网络的核心思想进行了拓展,因此在很多设计特性上都与比特币网络十分类似。 + +基于以太坊项目,以太坊团队目前运营了一条公开的区块链平台——以太坊网络。智能合约开发者使用官方提供的工具和以太坊专用应用开发语言 Solidity,可以很容易开发出运行在以太坊网络上的“去中心化”应用(Decentralized Application,DApp)。这些应用将运行在以太坊的虚拟机(Ethereum Virtual Machine,EVM)里。用户通过以太币(Ether)来购买燃料(Gas),维持所部署应用的运行。 + +以太坊项目的官网网站为 [ethereum.org](https://ethereum.org),代码托管在 [github.com/ethereum](github.com/ethereum)。 + + +### 以太坊项目简史 + +相对比特币网络自 2009 年上线的历史,以太坊项目要年轻的多。 + +2013 年底,比特币开发团队中有一些开发者开始探讨将比特币网络中的核心技术,主要是区块链技术,拓展到更多应用场景的可能性。以太坊的早期发明者 Vitalik Buterin 提出应该能运行任意形式(图灵完备)的应用程序,而不仅仅是比特币中受限制的简单脚本。该设计思想并未得到比特币社区的支持,后来作为以太坊白皮书发布。 + +2014 年 2 月,更多开发者(包括 Gavin Wood、Jeffrey Wilcke 等)加入以太坊项目,并计划在社区开始以众筹形式募集资金,以开发一个运行智能合约的信任平台。 + +2014 年 7 月,以太币预售,经过 42 天,总共筹集到价值超过 1800 万美金的比特币。随后在瑞士成立以太坊基金会,负责对募集到的资金进行管理和运营;并组建研发团队以开源社区形式进行平台开发。 + +2015 年 7 月底,以太坊第一阶段 Frontier 正式发布,标志着以太坊区块链网络的正式上线。这一阶段采用类似比特币网络的 PoW 共识机制,参与节点以矿工挖矿形式维护网络;支持上传智能合约。Frontier 版本实现了计划的基本功能,在运行中测试出了一些安全上的漏洞。这一阶段使用者以开发者居多。 + +2016 年 3 月,第二阶段 Homestead 开始运行(区块数 1150000),主要改善了安全性,同时开始提供图形界面的客户端,提升了易用性,更多用户加入进来。 + +2016 年 6 月,DAO 基于以太坊平台进行众筹,受到漏洞攻击,造成价值超过 5000 万美金的以太币被冻结。社区最后通过硬分叉(Hard Fork)进行解决。 + +2017 年 3 月,以太坊成立以太坊企业级联盟(Enterprise Ethereum Alliance,EEA),联盟成员主要来自摩根大通,微软,芝加哥大学和部分创业企业等。 + +2017 年 11 月,再次暴露多签名钱包漏洞,造成价值 2.8 亿美元的以太币被冻结。 + +目前,以太坊网络支持了接近比特币网络的交易量,成为广受关注的公有链项目。 + +后续按照计划将发布第三阶段 Metropolis 和第四阶段 Serenity,主要特性包括支持 PoS 股权证明的共识机制,以降低原先 PoW 机制造成的能耗浪费;以及图形界面的钱包,以提升易用性。 + +包括 DAO 在内,以太坊网络已经经历了数次大的硬分叉,注意每次硬分叉后的版本对之前版本并不兼容。 + +### 主要特点 + +以太坊区块链底层也是一个类似比特币网络的 P2P 网络平台,智能合约运行在网络中的以太坊虚拟机里。网络自身是公开可接入的,任何人都可以接入并参与网络中数据的维护,提供运行以太坊虚拟机的资源。 + +跟比特币项目相比,以太坊区块链的技术特点主要包括: + +* 支持图灵完备的智能合约,设计了编程语言 Solidity 和虚拟机 EVM; +* 选用了内存需求较高的哈希函数,避免出现强算力矿机、矿池攻击; +* 叔块(Uncle Block)激励机制,降低矿池的优势,并减少区块产生间隔(10 分钟降低到 15 秒左右); +* 采用账户系统和世界状态,而不是 UTXO,容易支持更复杂的逻辑; +* 通过 Gas 限制代码执行指令数,避免循环执行攻击; +* 支持 PoW 共识算法,并计划支持效率更高的 PoS 算法。 + +此外,开发团队还计划通过分片(Sharding)方式来解决网络可扩展性问题。 + +这些技术特点,解决了比特币网络在运行中被人诟病的一些问题,让以太坊网络具备了更大的应用潜力。 + diff --git a/chainbrock-learning/07_ethereum/smart_contract.md b/chainbrock-learning/07_ethereum/smart_contract.md new file mode 100644 index 00000000..aa0c20ed --- /dev/null +++ b/chainbrock-learning/07_ethereum/smart_contract.md @@ -0,0 +1,187 @@ +## 使用智能合约 + +以太坊社区有不少提供智能合约编写、编译、发布、调用等功能的工具,用户和开发者可以根据需求或开发环境自行选择。 + +本节将向开发者介绍使用 Geth 客户端搭建测试用的本地区块链,以及如何在链上部署和调用智能合约。 + +### 搭建测试用区块链 + +由于在以太坊公链上测试智能合约需要消耗以太币,所以对于开发者开发测试场景,可以选择本地自行搭建一条测试链。开发好的智能合约可以很容易的切换接口部署到公有链上。注意测试链不同于以太坊公链,需要给出一些非默认的手动配置。 + +#### 配置初始状态 + +首先配置私有区块链网络的初始状态。新建文件 `genesis.json`,内容如下。 + +```json +{ + "config": { + "chainId": 22, + "homesteadBlock": 0, + "eip155Block": 0, + "eip158Block": 0 + }, + "alloc" : {}, + "coinbase" : "0x0000000000000000000000000000000000000000", + "difficulty" : "0x400", + "extraData" : "", + "gasLimit" : "0x2fefd8", + "nonce" : "0x0000000000000038", + "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp" : "0x00" +} +``` + +其中,`chainId` 指定了独立的区块链网络 ID,不同 ID 网络的节点无法互相连接。配置文件还对当前挖矿难度 `difficulty`、区块 Gas 消耗限制 `gasLimit` 等参数进行了设置。 + +#### 启动区块链 + +用以下命令初始化区块链,生成创世区块和初始状态。 + +```bash +$ geth --datadir /path/to/datadir init /path/to/genesis.json +``` + +其中,`--datadir` 指定区块链数据的存储位置,可自行选择一个目录地址。 + +接下来用以下命令启动节点,并进入 Geth 命令行界面。 + +```bash +$ geth --identity "TestNode" --rpc --rpcport "8545" --datadir /path/to/datadir --port "30303" --nodiscover console +``` + +各选项的含义如下。 + +* `--identity`:指定节点 ID; +* `--rpc`: 表示开启 HTTP-RPC 服务; +* `--rpcport`: 指定 HTTP-RPC 服务监听端口号(默认为 8545); +* `--datadir`: 指定区块链数据的存储位置; +* `--port`: 指定和其他节点连接所用的端口号(默认为 30303); +* `--nodiscover`: 关闭节点发现机制,防止加入有同样初始配置的陌生节点; + +#### 创建账号 + +用上述 `geth console` 命令进入的命令行界面采用 JavaScript 语法。可以用以下命令新建一个账号。 + +``` +> personal.newAccount() + +Passphrase: +Repeat passphrase: +"0x1b6eaa5c016af9a3d7549c8679966311183f129e" +``` + +输入两遍密码后,会显示生成的账号,如`"0x1b6eaa5c016af9a3d7549c8679966311183f129e"`。可以用以下命令查看该账号余额。 + +``` +> myAddress = "0x1b6eaa5c016af9a3d7549c8679966311183f129e" +> eth.getBalance(myAddress) +0 +``` + +看到该账号当前余额为 0。可用 `miner.start()` 命令进行挖矿,由于初始难度设置的较小,所以很容易就可挖出一些余额。`miner.stop()` 命令可以停止挖矿。 + +### 创建和编译智能合约 + +以 Solidity 编写的智能合约为例。为了将合约代码编译为 EVM 二进制,需要安装 Solidity 编译器 solc。 + +```bash +$ apt-get install solc +``` + +新建一个 Solidity 智能合约文件,命名为 `testContract.sol`,内容如下。该合约包含一个方法 multiply,作用是将输入的整数乘以 7 后输出。 + +``` +pragma solidity ^0.4.0; +contract testContract { + function multiply(uint a) returns(uint d) { + d = a * 7; + } +} +``` + +用 solc 获得合约编译后的 EVM 二进制码。 + +```bash +$ solc --bin testContract.sol + +======= testContract.sol:testContract ======= +Binary: +6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a72305820748467daab52f2f1a63180df2c4926f3431a2aa82dcdfbcbde5e7d036742a94b0029 +``` + +再用 solc 获得合约的 JSON ABI(Application Binary Interface),其中指定了合约接口,包括可调用的合约方法、变量、事件等。 + +```bash +$ solc --abi testContract.sol + +======= testContract.sol:testContract ======= +Contract JSON ABI +[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"type":"function"}] +``` + +下面回到 Geth 的 JavaScript 环境命令行界面,用变量记录上述两个值。注意在 code 前加上 `0x` 前缀。 + +``` +> code = "0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a72305820748467daab52f2f1a63180df2c4926f3431a2aa82dcdfbcbde5e7d036742a94b0029" +> abi = [{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"type":"function"}] +``` + +### 部署智能合约 + +在 Geth 的 JavaScript 环境命令行界面,首先用以下命令解锁自己的账户,否则无法发送交易。 + +``` +> personal.unlockAccount(myAddress) + +Unlock account 0x1b6eaa5c016af9a3d7549c8679966311183f129e +Passphrase: +true +``` + +接下来发送部署合约的交易。 + +``` +> myContract = eth.contract(abi) +> contract = myContract.new({from:myAddress,data:code,gas:1000000}) +``` + +如果此时没有在挖矿,用 `txpool.status` 命令可看到本地交易池中有一个待确认的交易。可用以下命令查看当前待确认的交易。 + +``` +> eth.getBlock("pending",true).transactions + +[{ + blockHash: "0xbf0619ca48d9e3cc27cd0ab0b433a49a2b1bed90ab57c0357071b033aca1f2cf", + blockNumber: 17, + from: "0x1b6eaa5c016af9a3d7549c8679966311183f129e", + gas: 90000, + gasPrice: 20000000000, + hash: "0xa019c2e5367b3ad2bbfa427b046ab65c81ce2590672a512cc973b84610eee53e", + input: "0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60006007820290505b9190505600a165627a7a72305820748467daab52f2f1a63180df2c4926f3431a2aa82dcdfbcbde5e7d036742a94b0029", + nonce: 1, + r: "0xbcb2ba94f45dfb900a0533be3c2c603c2b358774e5fe89f3344031b202995a41", + s: "0x5f55fb1f76aa11953e12746bc2d19fbea6aeb1b9f9f1c53a2eefab7058515d99", + to: null, + transactionIndex: 0, + v: "0x4f", + value: 0 +}] +``` + +可以用 `miner.start()` 命令挖矿,一段时间后,交易会被确认,即随新区块进入区块链。 + +### 调用智能合约 + +用以下命令可以发送交易,其中 sendTransaction 方法的前几个参数与合约中 multiply 方法的输入参数对应。这种方式,交易会通过挖矿记录到区块链中,如果涉及状态改变也会获得全网共识。 + +``` +> contract.multiply.sendTransaction(10, {from:myAddress}) +``` + +如果只是想本地运行该方法查看返回结果,可采用如下方式获取结果。 + +``` +> contract.multiply.call(10) +70 +``` diff --git a/chainbrock-learning/07_ethereum/summary.md b/chainbrock-learning/07_ethereum/summary.md new file mode 100644 index 00000000..9cfa57c7 --- /dev/null +++ b/chainbrock-learning/07_ethereum/summary.md @@ -0,0 +1,7 @@ +## 本章小结 + +以太坊项目将区块链技术在数字货币的基础上进行了延伸,提出打造更为通用的智能合约平台的宏大构想,并基于开源技术构建了以太坊为核心的开源生态系统。 + +本章内容介绍了以太坊的相关知识,包括核心概念、设计、工具,以及客户端的安装、智能合约的使用和编写等。 + +比照比特币项目,读者通过学习可以掌握以太坊的相关改进设计,并学习智能合约的编写。实际上,智能合约并不是一个新兴概念,但区块链技术的出现为智能合约的“代码即律法”提供提供了信任基础和实施架构。通过引入智能合约,区块链技术释放了支持更多应用领域的巨大潜力。 diff --git a/chainbrock-learning/07_ethereum/tools.md b/chainbrock-learning/07_ethereum/tools.md new file mode 100644 index 00000000..e0ff94aa --- /dev/null +++ b/chainbrock-learning/07_ethereum/tools.md @@ -0,0 +1,52 @@ +## 相关工具 + +### 客户端和开发库 + +以太坊客户端可用于接入以太坊网络,进行账户管理、交易、挖矿、智能合约等各方面操作。 + +以太坊社区现在提供了多种语言实现的客户端和开发库,支持标准的 JSON-RPC 协议。用户可根据自己熟悉的开发语言进行选择。 + +* [go-ethereum](https://github.com/ethereum/go-ethereum):Go 语言实现; +* [Parity](https://github.com/ethcore/parity):Rust 语言实现; +* [cpp-ethereum](https://github.com/bobsummerwill/cpp-ethereum):C++ 语言实现; +* [ethereumjs-lib](https://github.com/ethereumjs/ethereumjs-lib):javascript 语言实现; +* [Ethereum(J)](https://github.com/ethereum/ethereumj):Java 语言实现; +* [ethereumH](https://github.com/blockapps/ethereumH):Haskell 语言实现; +* [pyethapp](https://github.com/ethereum/pyethapp):Python 语言实现; +* [ruby-ethereum](https://github.com/janx/ruby-ethereum):Ruby 语言实现。 + +#### Geth + +上述实现中,go-ethereum 的独立客户端 Geth 是最常用的以太坊客户端之一。 + +用户可通过安装 Geth 来接入以太坊网络并成为一个完整节点。Geth 也可作为一个 HTTP-RPC 服务器,对外暴露 JSON-RPC 接口,供用户与以太坊网络交互。 + +Geth 的使用需要基本的命令行基础,其功能相对完整,源码托管于 github.com/ethereum/go-ethereum。 + +### 以太坊钱包 + +对于只需进行账户管理、以太坊转账、DApp 使用等基本操作的用户,则可选择直观易用的钱包客户端。 + +Mist 是官方提供的一套包含图形界面的钱包客户端,除了可用于进行交易,也支持直接编写和部署智能合约。 + +![Mist 浏览器](_images/mist.png) + +所编写的代码编译发布后,可以部署到区块链上。使用者可通过发送调用相应合约方法的交易,来执行智能合约。 + +### IDE + +对于开发者,以太坊社区涌现出许多服务于编写智能合约和 DApp 的 IDE,例如: + +* [Truffle](http://truffleframework.com/):一个功能丰富的以太坊应用开发环境。 +* [Embark](https://github.com/iurimatias/embark-framework):一个 DApp 开发框架,支持集成以太坊、IPFS 等。 +* [Remix](http://remix.ethereum.org):一个用于编写 Solidity 的 IDE,内置调试器和测试环境。 + +### 网站资源 + +已有一些网站提供对以太坊网络的数据、运行在以太坊上的 DApp 等信息进行查看,例如: + +* ethstats.net:实时查看网络的信息,如区块、价格、交易数等。 +* ethernodes.org:显示整个网络的历史统计信息,如客户端的分布情况等。 +* dapps.ethercasts.com:查看运行在以太坊上的 DApp 的信息,包括简介、所处阶段和状态等。 + +![以太坊网络上的 Dapp 信息](_images/dapps.png) \ No newline at end of file diff --git a/chainbrock-learning/08_hyperledger/README.md b/chainbrock-learning/08_hyperledger/README.md new file mode 100644 index 00000000..8e93ff44 --- /dev/null +++ b/chainbrock-learning/08_hyperledger/README.md @@ -0,0 +1,10 @@ +# 超级账本 —— 面向企业的分布式账本 + +** 欲戴王冠,必承其重(Uneasy lies the head that wears a crown)。 ** + +超级账本(Hyperledger)项目是全球最大的开源企业级分布式账本平台。 + +在 Linux 基金会的支持下,超级账本项目吸引了包括 IBM、Intel、Cisco、DAH、摩根大通、R3、甲骨文、百度、腾讯等在内的众多科技和金融巨头的参与贡献,以及在银行、供应链等领域的应用实践。成立两年多时间以来,超级账本得到了广泛的关注和飞速发展,目前囊括十大顶级项目,拥有近三百家企业会员。超级账本的开源代码和技术,也成为分布式账本领域的首选。 + +本章将介绍超级账本项目的发展历史和社区组织,以及旗下的多个顶级开源项目的情况,还将展示开源社区提供的多个高效开发工具。最后介绍如何参与到超级账本项目中,进行代码贡献。 + diff --git a/chainbrock-learning/08_hyperledger/_images/aries.png b/chainbrock-learning/08_hyperledger/_images/aries.png new file mode 100644 index 00000000..2594f11c Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/aries.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/avalon.png b/chainbrock-learning/08_hyperledger/_images/avalon.png new file mode 100644 index 00000000..6a81d0ea Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/avalon.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/besu.png b/chainbrock-learning/08_hyperledger/_images/besu.png new file mode 100644 index 00000000..f6970ab8 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/besu.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/burrow.png b/chainbrock-learning/08_hyperledger/_images/burrow.png new file mode 100644 index 00000000..fd0503f2 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/burrow.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/caliper.png b/chainbrock-learning/08_hyperledger/_images/caliper.png new file mode 100644 index 00000000..eac0cfb5 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/caliper.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/cello.png b/chainbrock-learning/08_hyperledger/_images/cello.png new file mode 100644 index 00000000..29fbe7db Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/cello.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/community_growth.png b/chainbrock-learning/08_hyperledger/_images/community_growth.png new file mode 100644 index 00000000..3796a3c3 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/community_growth.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/composer.png b/chainbrock-learning/08_hyperledger/_images/composer.png new file mode 100644 index 00000000..fa3893c2 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/composer.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/explorer.png b/chainbrock-learning/08_hyperledger/_images/explorer.png new file mode 100644 index 00000000..2a426605 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/explorer.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/fabric.png b/chainbrock-learning/08_hyperledger/_images/fabric.png new file mode 100644 index 00000000..07915cc3 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/fabric.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/github.png b/chainbrock-learning/08_hyperledger/_images/github.png new file mode 100644 index 00000000..9c9e6f17 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/github.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/grid.png b/chainbrock-learning/08_hyperledger/_images/grid.png new file mode 100644 index 00000000..656b323a Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/grid.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/hyperledger.png b/chainbrock-learning/08_hyperledger/_images/hyperledger.png new file mode 100644 index 00000000..9ef283b0 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/hyperledger.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/hyperledger_logo.png b/chainbrock-learning/08_hyperledger/_images/hyperledger_logo.png new file mode 100644 index 00000000..39adb6d9 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/hyperledger_logo.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/indy.png b/chainbrock-learning/08_hyperledger/_images/indy.png new file mode 100644 index 00000000..a912d484 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/indy.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/iroha.png b/chainbrock-learning/08_hyperledger/_images/iroha.png new file mode 100644 index 00000000..611288d9 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/iroha.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/jira.png b/chainbrock-learning/08_hyperledger/_images/jira.png new file mode 100644 index 00000000..d149c3c0 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/jira.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/network_topo.png b/chainbrock-learning/08_hyperledger/_images/network_topo.png new file mode 100644 index 00000000..e2220336 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/network_topo.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/orgnization.png b/chainbrock-learning/08_hyperledger/_images/orgnization.png new file mode 100644 index 00000000..2887a23d Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/orgnization.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/patchset-lifecycle.png b/chainbrock-learning/08_hyperledger/_images/patchset-lifecycle.png new file mode 100644 index 00000000..e35d29d3 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/patchset-lifecycle.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/quilt.png b/chainbrock-learning/08_hyperledger/_images/quilt.png new file mode 100644 index 00000000..cbbc6a9c Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/quilt.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/rocket_chat.png b/chainbrock-learning/08_hyperledger/_images/rocket_chat.png new file mode 100644 index 00000000..b375f4eb Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/rocket_chat.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/sawtooth.png b/chainbrock-learning/08_hyperledger/_images/sawtooth.png new file mode 100644 index 00000000..d571a0c2 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/sawtooth.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/top_projects.png b/chainbrock-learning/08_hyperledger/_images/top_projects.png new file mode 100644 index 00000000..1a926180 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/top_projects.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/transact.png b/chainbrock-learning/08_hyperledger/_images/transact.png new file mode 100644 index 00000000..3a24cee9 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/transact.png differ diff --git a/chainbrock-learning/08_hyperledger/_images/ursa.png b/chainbrock-learning/08_hyperledger/_images/ursa.png new file mode 100644 index 00000000..85914f33 Binary files /dev/null and b/chainbrock-learning/08_hyperledger/_images/ursa.png differ diff --git a/chainbrock-learning/08_hyperledger/community.md b/chainbrock-learning/08_hyperledger/community.md new file mode 100644 index 00000000..1530a05a --- /dev/null +++ b/chainbrock-learning/08_hyperledger/community.md @@ -0,0 +1,34 @@ +## 社区组织结构 + +每个成功的开源项目都离不开一个健康开发、不断繁荣的社区生态。 + +超级账本社区自成立之日起就借鉴了众多开源社区组织的经验,形成了技术开发为主体、积极结合应用的体系结构。 + +超级账本社区的项目开发工作由技术委员会(Technical Steering Committee,TSC)指导,首任主席Chris Ferris 来自 IBM ,是 IBM 开源技术部门的 CTO ;管理委员会主席则由来自 Digital Asset Holdings 的 CEO Blythe Masters 担任。另外,自 2016 年 5 月起,Apache 基金会创始人 Brian Behlendorf 担任超级账本项目的执行总监(Executive Director)。 + +社区十分重视大中华地区的应用落地和开发情况,2016 年 12 月,[中国技术工作组](ttps://wiki.hyperledger.org/display/TWGC) 正式成立,负责推动社区组织建设和开源技术的发展和应用。 + +### 基本结构 + +![Hyperledger 社区组织结构](_images/orgnization.png) + +社区目前主要是三驾马车领导的结构: + +* Technical Steering Committee(技术委员会):负责领导社区技术,指导各个开源项目的发展方向,下设多个技术工作组(如 Architecture、Identity、Learning Materials Development、Performance and Scale、Smart Contracts)和兴趣小组(如 Healthcare、Public Sector、Social Impact、Telecom、Trade Finance)。每年由社区开发者进行换届选举; +* Governing Board(管理董事会):负责整体社区的组织决策,从超级账本会员中推选出代表座位成员; +* Linux Foundation(Linux 基金会):负责基金管理和大型活动组织,协助社区在 Linux 基金会的支持下健康发展。 + +### 大中华区技术工作组 + +随着开源精神和开源文化在中国的普及,越来越多的企业和组织开始意识到共建一个健康生态系统的重要性,也愿意为开源事业做出一定贡献。 + +Linux 基金会和超级账本社区十分重视项目在大中华区的应用和落地情况,并希望能为开发者们贡献开源社区提供便利。在此背景下,超级账本首任执行董事 Brian Behlendorf 于 2016 年 12 月 1 日 [提议](https://lists.hyperledger.org/pipermail/hyperledger-tsc/2016-December/000504.html) 成立 [大中华区技术工作组(TWG-China)](https://wiki.hyperledger.org/groups/tsc/technical-working-group-china),并得到了 TSC 成员们的一致支持和通过。笔者也有幸参与了工作组的创建,并担任首届联席主席。 + +技术工作组的 [主要职责](https://docs.google.com/document/d/1sXVltDZxnlB5Srd1A-EW0jtTz7P2cDLG8JmgaAYvMzU) 包括: + +* 带领和引导大中华区的技术开发相关活动,包括贡献代码、文档、项目提案等。 +* 推动技术相关的交流,促进会员企业之间的合作和实践案例的落地; +* 通过邮件列表、RocketChat、论坛等方式促进社区开发者们的技术交流; +* 协助举办社区活动,包括 Meetup、黑客松、Hackfest、技术分享、培训等。 + +目前,工作组由来自各个成员企业的数十名技术专家组成,并得到了来自社区的众多志愿者的支持。工作组每两周举行在线例会,每个月定期在各大城市举办技术交流沙龙,各项会议和活动内容都是开放的,可以在 Wiki 首页(https://wiki.hyperledger.org/display/TWGC)上找到相关参与方式。 diff --git a/chainbrock-learning/08_hyperledger/contribute.md b/chainbrock-learning/08_hyperledger/contribute.md new file mode 100644 index 00000000..a8d2125e --- /dev/null +++ b/chainbrock-learning/08_hyperledger/contribute.md @@ -0,0 +1,206 @@ +## 贡献代码 + +超级账本的各个子项目,都提供了十分丰富的开发和提交代码的指南和文档,一般可以在代码的 `docs` 目录下找到。所有项目都使用 Github 来管理代码和进行集成测试。 + +这里以 Fabric 项目为例讲解代码贡献流程。 + +### 安装环境 + +推荐在 Linux(如 Ubuntu 18.04+)或 macOS 环境中开发 Hyperledger 项目代码。 + +不同项目会依赖不同的环境,可以从项目文档中找到。以 Fabric 项目为例,开发者需要安装如下依赖。 + +* Git:用来从代码仓库获取代码并进行版本管理; +* Hub:Github 官方开发的基于 Git 命令的工具,可以替代 Git 命令,更方便操作 Github 仓库; +* Golang 1.12+:访问 golang.org 进行安装,之后需要配置 `$GOPATH` 环境变量,注意不同项目可能需要不同语言环境; +* Docker 1.18+:用来支持容器环境,macOS 下推荐使用 [Docker for Mac](https://docs.docker.com/docker-for-mac)。 + +如果是首次使用 Git,可能还会提示配置默认的用户名和 Email 地址等信息。通过如下命令进行简单配置即可: + +```bash +$ git config user.name "Your name" +$ git config user.email "Your-addr@some-email-server" +``` + +安装 hub 工具,方便与 Github 的仓库进行交互。 + +Linux 下可以直接从 https://github.com/github/hub/releases 下载工具使用。 + +macOS 下可以通过 homebrew 工具来安装: + +```bash +$ brew install hub +``` + +### 获取代码 + +如果没有 Linux Foundation(LF)ID,可通过 https://identity.linuxfoundation.org 免费注册。 + +注册并登录 Github 个人账号,添加个人 ssh 公钥,否则每次访问仓库可能需要手动输入用户名和密码。 + +开启双重验证(Two-factor authentication,2FA)后,在 https://github.com/hyperledger 页面申请加入到社区组织内。 + +如果是首次下载项目,则需要从官方仓库获取源码,然后 fork 到自己的仓库中: + +```sh +$ hub clone https://github.com/hyperledger/.git +$ cd +$ hub fork --remote-name=origin +$ git branch master --set-upstream-to origin/master +``` + +此时,项目下会包括两个仓库: + +* `origin` 仓库:会指向用户仓库。master 分支会追踪本仓库; +* `upstream` 仓库:会指向官方仓库,供后续同步更新使用。 + +### 编译和测试 + +大部分编译和安装过程都可以利用 Makefile 来执行,具体以项目代码为准。 + +以 Fabric 项目为例,包括如下常见操作。 + +#### 生成命令文档 +执行如下命令: + +```sh +$ make help-docs +``` + +#### 安装 go tools +执行如下命令: + +```sh +$ make gotools +``` + +#### 语法格式检查 + +执行如下命令: + +```sh +$ make linter +``` + +#### 编译二进制文件 + +执行如下命令: + +```sh +$ make native +``` + +会自动生成 orderer、peer、configtxgen、configtxlator、cryptogen、doscover、idemixgen 等可执行文件。 + +用户也可以使用对应的可执行文件名称来单独编译,例如,执行如下命令会自动编译生成 Docker 镜像,并生成本地 peer 可执行文件: + +```sh +$ make peer +``` + +*注意:有时会因网络不稳定而报错,可以进行 `make clean` 后再次执行。* + +#### 生成 Docker 镜像 +执行如下命令: + +```sh +$ make docker +``` + +#### 执行所有的检查和测试 +执行如下命令: + +```sh +$ make checks +``` + +#### 执行单元测试 + +执行如下命令: + +```sh +$ make unit-test +``` + +如果要运行某个特定单元测试,则可以通过类似如下格式: + +```sh +$ go test -v -run=TestGetFoo +``` + +### 提交代码 + +使用 LF ID 登录 [jira.hyperledger.org](http://jira.hyperledger.org) 或 Github Issue,查看有没有未分配(unassigned)的任务,如果对某个任务感兴趣,可以添加自己为任务的 assignee。任何人都可以自行创建新的任务。如果是较大的特性,还需要先撰写 rfc 来描述设计,可以参考 https://github.com/hyperledger/fabric-rfcs。 + +初始创建的任务处于 `TODO` 状态;开始工作后可以标记为 `In Progress` 状态;提交对应补丁后需要更新为 `In Review` 状态;任务完成后更新为 `Done` 状态。 + +如果希望完成某个任务(如 FAB-XXX),则在 Clone 下来的代码上创建新的分支 FAB-XXX: + +```sh +$ git checkout -b FAB-XXX +``` + +实现任务代码,完成后,执行语法格式检查和测试等,确保所有检查和测试都通过。 + +提交代码到本地仓库: + +```sh +$ git commit -a -s +``` + +会自动打开一个编辑器窗口,需要填写 commit 信息,格式一般要求如下: + +```bash +[FAB-XXX] Quick brief on the change + +This pathset fixes a duplication msg bug in gossip protocol. + +A more detailed description can be here, with several paragraphs and +sentences, including issue to fix, why to fix, what is done in the +patchset and potential remaining issues... +``` + +提交消息中要写清楚所解决的问题、为何进行修改、主要改动内容、遗留问题等,并且首行宽不超过 50 个字符,详情段落行宽不要超过 72 个字符。 + +将代码所在的分支推送到 Github 上自己的仓库中,例如: + +```bash +$ git push --set-upstream origin FAB-XXX +``` + +创建合并请求(Pull Request),例如: + +```bash +$ hub pull-request [-b upstream:master] [-r ] +``` + +### 评审代码 + +提交成功后,可以打开项目在 Github 上的页面,查看自己最新提交的合并请求。新提交的请求会自动触发 CI 的测试任务,测试都通过后可邀请项目的维护者(maintainer)进行评审。为了引起关注,可将链接添加到对应的 Jira 任务,并在 RocketChat 上对应项目频道内贴出。 + +如果评审通过,则会被合并到主分支;否则还需要针对审阅意见进一步的修正。修正过程跟提交代码过程类似,唯一不同是,提交时需要添加 `-a --amend` 参数: + +```sh +$ git commit -a --amend +``` + +表示这个提交是对旧提交的一次修订。 + +一般情况下,为了方便评审,尽量保证每个 patchset 完成的改动不要太多(最好不要超过 5 个文件,200 行),并且实现功能要明确,集中在对应 Jira 任务定义的范围内。 + +补丁被接收后可以删除对应的分支: + +```bash +$ git fetch upstream master && git rebase FETCH_HEAD && git push -f origin +$ git push -d origin issue-xxx +$ git branch -d issue-xxx +``` + +### 完整流程 + +![代码提交流程](_images/patchset-lifecycle.png) + +总结一下,完整的流程如上图所示,开发者用 git 进行代码的版本管理,用 gerrit 进行代码的评审合作。 + +如果需要修复某个提交补丁的问题,则通过 `git commit -a --amend` 进行修复,并作为补丁的新版本再次提交审阅。每次通过 `git review` 提交时,应当通过 `git log` 查看,确保本地只有一条提交记录。 + diff --git a/chainbrock-learning/08_hyperledger/intro.md b/chainbrock-learning/08_hyperledger/intro.md new file mode 100644 index 00000000..b573726e --- /dev/null +++ b/chainbrock-learning/08_hyperledger/intro.md @@ -0,0 +1,26 @@ +## 超级账本项目简介 + +![超级账本项目](_images/hyperledger_logo.png) + +2015 年 12 月,开源世界的旗舰组织 —— [Linux 基金会](http://www.linuxfoundation.org) 牵头,联合 30 家初始企业成员(包括 IBM、Accenture、Intel、J.P.Morgan、R3、DAH、DTCC、FUJITSU、HITACHI、SWIFT、Cisco 等),共同 [宣布](https://www.hyperledger.org/news/announcement/2016/02/hyperledger-project-announces-30-founding-members) 超级账本(Hyperledger)联合项目成立。超级账本项目致力为透明、公开、去中心化的企业级分布式账本技术提供开源参考实现,并推动区块链和分布式账本相关协议、规范和标准的发展。项目官方网站为 [hyperledger.org](https://www.hyperledger.org)。 + +成立之初,项目就收到了众多开源技术贡献。IBM 贡献了 4 万多行已有的 [Open Blockchain](https://github.com/openblockchain) 代码,Digital Asset 贡献了企业和开发者相关资源,R3 贡献了新的金融交易架构,Intel 贡献了分布式账本相关的代码。 + +作为一个联合项目(Collaborative Project),超级账本由面向不同目的和场景的子项目构成。目前包括 Fabric、SawToothLake、Iroha、Blockchain Explorer、Cello、Indy、Composer、Burrow、Quilt、Caliper、Ursa、Grid、Transact、Aries、Besu、Avalon 等顶级项目,所有项目都遵守 Apache v2 许可,并约定共同遵守如下的 [基本原则](https://github.com/hyperledger/hyperledger): + +* 重视模块化设计:包括交易、合同、一致性、身份、存储等技术场景; +* 重视代码可读性:保障新功能和模块都可以很容易添加和扩展; +* 可持续的演化路线:随着需求的深入和更多的应用场景,不断增加和演化新的项目。 + +超级账本项目的企业会员和技术项目发展都十分迅速,如下图所示。 + +![Hyperledger 项目快速成长](_images/community_growth.png) + +社区目前拥有近 300 家全球知名企业和机构(大部分均为各自行业的领导者)会员,其中包括 60 多家来自中国本土的企业,早期包括艾亿数融科技公司([2016.05.19](https://www.hyperledger.org/news/announcement/2016/05/hyperledger-project-announces-addition-eight-new-members))、Onchain([2016.06.22](https://www.hyperledger.org/news/announcement/2016/06/hyperledger-projects-maintains-strong-momentum-new-members))、比邻共赢(Belink)信息技术有限公司(2016.06.22)、BitSE(2016.06.22)等,另外还包括华为([2016.10.24](https://www.hyperledger.org/announcements/2016/10/24/hyperledger-reaches-95-members-ahead-of-money2020))、百度(2017.10.17)、腾讯(2018.01.25)等行业领军企业。此外,还有大量机构和高校成为超级账本联合会员,如英格兰银行、MIT 连接科学研究院、UCLA 区块链实验室、伊利诺伊区块链联盟、北京大学、浙江大学等。 + +如果说比特币为代表的加密货币提供了区块链技术应用的原型,以太坊为代表的智能合约平台延伸了区块链技术的适用场景,那么面向企业场景的超级账本项目则开拓了区块链技术的全新阶段。超级账本首次将区块链技术引入到了联盟账本的应用场景,引入权限控制和安全保障,这就为基于区块链技术的未来全球商业网络打下了坚实的基础。 + +超级账本项目的出现,实际上证实区块链技术已经不局限在单一应用场景中,也不限于完全开放匿名的公有链模式下,而是有更多的可能性,也说明区块链技术已经被主流企业市场正式认可和实践。同时,超级账本项目中提出和实现了许多创新的设计和理念,包括权限和审查管理、多通道、细粒度隐私保护、背书-共识-提交模型,以及可拔插、可扩展的实现框架,对于区块链相关技术和产业的发展都将产生十分深远的影响。 + +*注:Apache v2 许可协议是商业友好的知名开源协议,鼓励代码共享,尊重原作者的著作权,允许对代码进行修改和再发布(作为开源或商业软件)。因其便于商业公司使用而得到业界的拥护。* + diff --git a/chainbrock-learning/08_hyperledger/project.md b/chainbrock-learning/08_hyperledger/project.md new file mode 100644 index 00000000..fe343fa1 --- /dev/null +++ b/chainbrock-learning/08_hyperledger/project.md @@ -0,0 +1,199 @@ +## 顶级项目介绍 + +Hyperledger 所有项目代码托管在 [Github](https://github.com/hyperledger/)上。目前,主要包括如下顶级项目(按时间顺序)。 + +* [Fabric](https://github.com/hyperledger/fabric):包括 [Fabric](https://github.com/hyperledger/fabric)、[Fabric CA](https://github.com/hyperledger/fabric-ca)、Fabric SDK(包括 Node.Js、Java、Python 和 Go 语言)等,目标是区块链的基础核心平台,支持 PBFT 等新的共识机制,支持权限管理,最早由 IBM 和 DAH 于 2015 年底发起; +* [Sawtooth](https://github.com/hyperledger/sawtooth-core):包括 arcade、[core](https://github.com/hyperledger/sawtooth-core)、dev-tools、[validator](https://github.com/hyperledger/sawtooth-validator)、mktplace 等。是 Intel 主要发起和贡献的区块链平台,支持全新的基于硬件芯片的共识机制 Proof of Elapsed Time(PoET), 2016 年 4 月贡献到社区; +* [Blockchain Explorer](https://github.com/hyperledger/blockchain-explorer):提供 Web 操作界面,通过界面快速查看查询绑定区块链的状态(区块个数、交易历史)信息等,由 DTCC、IBM、Intel 等开发支持,2016 年 8 月贡献到社区; +* [Iroha](https://github.com/hyperledger/Iroha):账本平台项目,基于 C++ 实现,带有不少面向 Web 和 Mobile 的特性,主要由 Soramitsu 于 2016 年 10 月发起和贡献; +* [Cello](https://github.com/hyperledger/cello):提供区块链平台的部署和运行时管理功能。使用 Cello,管理员可以轻松部署和管理多条区块链;应用开发者可以无需关心如何搭建和维护区块链,由 IBM 团队于 2017 年 1 月贡献到社区; +* [Indy](https://github.com/hyperledger/indy):提供基于分布式账本技术的数字身份管理机制,由 Sovrin 基金会发起,2017 年 3 月底正式贡献到社区; +* [Composer](https://github.com/hyperledger/composer):提供面向链码开发的高级语言支持,自动生成链码代码等,由 IBM 团队发起并维护,2017 年 3 月底贡献到社区。目前已经成熟,处于 Deprecate 阶段,仅考虑修正可能的严重缺陷; +* [Burrow](https://github.com/hyperledger/burrow):提供以太坊虚拟机的支持,实现支持高效交易的带权限的区块链平台,由 Monax 公司发起支持,2017 年 4 月贡献到社区; +* [Quilt](https://github.com/hyperledger/quilt):对 W3C 支持的跨账本协议 Interledger 的 Java 实现。2017 年 10 月正式贡献到社区; +* [Caliper](https://github.com/hyperledger/burrow):提供对区块链平台性能的测试工具,由华为公司发起支持,2018 年 3 月正式贡献到社区。 +* [Ursa](https://github.com/hyperledger/burrow):提供一套密码学相关组件,初始贡献者包括来自 Fujitsu、Sovrin、Intel、DFINITY、State Street、IBM、Bitwise IO 等企业的开发者,2018 年 11 月正式被接收到社区; +* [Grid](https://github.com/hyperledger/burrow):提供帮助快速构建供应链应用的框架,由 Cargill、Intel 和 Bitwise IO 公司发起支持,2018 年 12 月正式贡献到社区; +* [Transact](https://github.com/hyperledger/transact):提供运行交易的引擎和框架,由 Bitwise IO、Cargill、Intel、IBM、HACERA 等公司发起支持,2019 年 5 月正式贡献到社区; +* [Aries](https://github.com/hyperledger/aries):为客户端提供共享的密码学钱包,由 Sovrin、C3I 和 Evernym 等公司发起支持,2019 年 5 月正式贡献到社区; +* [Besu](https://github.com/hyperledger/besu):作为企业级的以太坊客户端支持,由 Consensys、Hacera、JPM 和 Redhat 等公司发起支持,2019 年 8 月正式贡献到社区; +* [Avalon](https://github.com/hyperledger/avalon):提供链下计算支持,增强安全性和可扩展性,由 Intel、IEX、IBM 和 Consensys 等公司发起支持,2019 年 9 月正式贡献到社区。 + +这些顶级项目分别从平台、工具和类库三个层次相互协作,构成了完善的生态系统,如下图所示。 + +![Hyperledger 顶级项目](_images/top_projects.png) + +所有项目一般都需要经历提案(Proposal)、孵化(Incubation)、活跃(Active)、退出(Deprecated)、终结(End of Life)等 5 个生命周期。 + +任何希望加入到 Hyperledger 社区中的项目,必须首先由发起人编写提案。描述项目的目的、范围、参与者和开发计划等重要信息,并由全球技术委员会来进行评审投票,评审通过则可以进入到社区内进行孵化。项目成熟后可以申请进入到活跃状态,发布正式的版本。项目不再活跃后可以进入维护阶段,最终结束生命周期。 + +### Fabric 项目 + +![Hyperledger Fabric 项目](_images/fabric.png) + +作为最早加入到超级账本项目中的顶级项目,Fabric 由 IBM、DAH 等企业于 2015 年底联合贡献到社区。项目在 Github 上地址为 https://github.com/hyperledger/fabric。 + +该项目的定位是面向企业的分布式账本平台,其创新地引入了权限管理支持,设计上支持可插拔、可扩展,是首个面向联盟链场景的开源项目。 + +Fabric 项目基于 Go 语言实现,贡献者超过 200 人,总提交次数已经超过 15000 次,核心代码数超过 15 万行。 + +Fabric 项目目前处于活跃状态,已发布 2.0.0 版本,同时包括 Fabric CA、Fabric SDK 等多个相关的子项目。 + +项目的邮件列表地址为 fabric@lists.hyperledger.org。 + +### Sawtooth 项目 + +![Hyperledger Sawtooth 项目](_images/sawtooth.png) + +Sawtooth 项目由 Intel 等企业于 2016 年 4 月提交到社区,包括 sawtooth-core、sawtooth-supply-chain、sawtooth-marketplace、sawtooth-seth、sawtooth-next-directory、sawtooth-explorer 等数十个子项目。核心代码在 Github 上地址为 https://github.com/hyperledger/sawtooth-core。 + +该项目的定位也是分布式账本平台,基于 Python 语言实现。目前目前处于 Active 阶段,核心项目的贡献者超过 70 人,提交次数已经超过 8000 次。 + +Sawtooth 项目利用 Intel 芯片的专属功能,实现了低功耗的 Proof of Elapsed Time(PoET)共识机制,并支持交易族(Transaction Family),方便用户使用它来快速开发应用。 + +项目的邮件列表地址为 sawtooth@lists.hyperledger.org。 + +### Iroha 项目 + +![Hyperledger Iroha 项目](_images/iroha.png) + +Iroha 项目由 Soramitsu 等企业于 2016 年 10 月提交到社区,包括 iroha、iroha-android、iroha-ios、iroha-python、iroha-javascript 等子项目。核心代码在 Github 上地址为 https://github.com/hyperledger/iroha。 + +该项目的定位是分布式账本平台框架,基于 C++ 语言实现。目前目前处于 Active 阶段,贡献者超过 50 人,提交次数已经超过 7000 次。 + +Iroha 项目在设计上类似 Fabric,同时提供了基于 C++ 的区块链开发环境,并考虑了移动端和 Web 端的一些需求。 + +项目的邮件列表地址为 iroha@lists.hyperledger.org。 + +### Explorer 项目 + +![Hyperledger Explorer 项目](_images/explorer.png) + +Explorer 项目由 Intel、DTCC、IBM 等企业于 2016 年 8 月提交到社区。核心代码在 Github 上地址为 https://github.com/hyperledger/blockchain-explorer,目前贡献者超过 40 人,提交次数超过 350 次。 + +该项目的定位是区块链平台的浏览器,基于 Node.js 语言实现,提供 Web 操作界面。用户可以使用它来快速查看底层区块链平台的运行信息,如区块个数、交易情况、网络状况等。 + +项目的邮件列表地址为 explorer@lists.hyperledger.org。 + +### Cello 项目 + +![Hyperledger Cello 项目](_images/cello.png) + +Cello 项目由笔者领导的技术团队于 2017 年 1 月贡献到社区。Github 上仓库地址为 https://github.com/hyperledger/cello(核心代码)和 https://github.com/hyperledger/cello-analytics(侧重数据分析)。 + +该项目的定位为区块链网络的操作系统,实现区块链网络自动化部署,以及对区块链网络的运行时管理。使用 Cello,可以让区块链应用人员专注到应用开发,而无需关心底层平台的管理和维护。已有一些企业基于 Cello 项目代码构建了区块链即服务(Blockchain-as-a-Service)平台。 + +Cello 的主要开发语言为 Python 和 JavaScript 等,底层支持包括裸机、虚拟机、容器云(包括 Swarm、Kubernetes)等多种基础架构。目前贡献者超过 40 人,提交次数超过 1000 次。 + +项目的邮件列表地址为 cello@lists.hyperledger.org。 + +### Indy 项目 + +![Hyperledger Indy 项目](_images/indy.png) + +Indy 项目由 Sovrin 基金会牵头进行开发,致力于打造一个基于区块链和分布式账本技术的数字身份管理平台。该平台支持去中心化,支持跨区块链和跨应用的操作,实现全球化的身份管理。Indy 项目于 2017 年 3 月底正式加入到超级账本项目。目前包括 indy-node、indy-sdk、indy-plenum、indy-hipe、indy-crypto、indy-agent 等项目。 + +该项目主要由 Python 语言开发,包括服务节点、客户端和通用库等。目前处于 Active 阶段,贡献者超过 60人,已有超过 5000 次提交。 + +项目的邮件列表地址为 indy@lists.hyperledger.org。 + +### Composer 项目 + +![Hyperledger Composer 项目](_images/composer.png) + +Composer 项目由 IBM 团队于 2017 年 3 月底贡献到社区,试图提供一个 Hyperledger Fabric 的开发辅助框架。使用 Composer,开发人员可以使用 Javascript 语言定义应用逻辑,再加上资源、参与者、交易等模型和访问规则,生成 Hyperledger Fabric 支持的链码。 + +该项目主要由 Node.Js 语言开发,贡献者超过 80人,已有超过 5000 次提交。该项目已经成熟,处于 Deprecate 阶段,仅考虑修正可能的严重缺陷。 + +项目的邮件列表地址为 composer@lists.hyperledger.org。 + +### Burrow 项目 + +![Hyperledger Burrow 项目](_images/burrow.png) + +Burrow 项目由 Monax、Intel 等企业于 2017 年 4 月提交到社区。核心代码在 Github 上地址为 https://github.com/hyperledger/burrow。 + +该项目的前身为 eris-db,基于 Go 语言实现的以太坊虚拟机,目前贡献者超过 20人,提交次数已经超过 2000 次。 + +Burrow 项目提供了支持以太坊虚拟机的智能合约区块链平台,并支持 Proof-of-Stake 共识机制(Tendermint)和权限管理,可以提供快速的区块链交易。 + +项目的邮件列表地址为 burrow@lists.hyperledger.org。 + +### Quilt 项目 + +![Hyperledger Quilt 项目](_images/quilt.png) + +Quilt 项目由 NTT、Ripple 等企业于 2017 年 10 月提交到社区。核心代码在 Github 上地址为 https://github.com/hyperledger/quilt。 + +Quilt 项目前身为 W3C 支持的 Interledger 协议的 Java 实现,主要试图为转账服务提供跨多个区块链平台的支持。目前贡献者超过 10人,提交次数已经超过 100 次。 + +项目的邮件列表地址为 quilt@lists.hyperledger.org。 + +### Caliper 项目 + +![Hyperledger Caliper 项目](_images/caliper.png) + +Caliper 项目由华为于 2018 年 3 月提交到社区。核心代码在 Github 上地址为 https://github.com/hyperledger/caliper。 + +Caliper 项目希望能为评测区块链的性能(包括吞吐、延迟、资源使用率等)提供统一的工具套装,主要基于 Node.js 语言实现,支持对 Fabric、Sawtooth、Burrow 等项目进行性能测试。目前贡献者超过 20人,提交次数超过 400 次。 + +项目的邮件列表地址为 caliper@lists.hyperledger.org。 + +### Ursa 项目 + +![Hyperledger Ursa 项目](_images/ursa.png) + +Ursa 项目前身为加密实现库项目,由 Fujitsu、Sovrin、Intel、DFINITY、State Street、IBM、Bitwise IO 等企业的开发者于 2018 年 11 月正式贡献到社区。核心代码在 Github 上地址为 https://github.com/hyperledger/ursa。 + +Ursa 项目希望提供一套方便、安全的密码学软件库(包括加解密、零知识证明等),为实现区块链平台实现提供便利。主要基于 Rust 语言实现,目前包括两个子组件(基础密码实现库 Base Crypto 和零知识证明库 Z-Mix)。参与贡献者超过 10人,提交次数超过 400 次。 + +项目的邮件列表地址为 ursa@lists.hyperledger.org。 + +### Grid 项目 + +![Hyperledger Grid 项目](_images/grid.png) + +Grid 项目由 Cargill、Intel 和 Bitwise IO 公司于 2018 年 12 月提交到社区。核心代码在 Github 上地址为 https://github.com/hyperledger/grid。 + +Grid 项目为开发基于区块链的供应链场景应用提供框架支持和参考实现,包括智能合约、数据模型、领域模型、样例应用等。 +,主要基于 Python 语言实现,并使用 Sabre(基于 WebAssembly/WASM 的智能合约引擎)来运行智能合约。目前贡献者超过 40人,提交次数超过 5000 次。 + +项目的邮件列表地址为 grid@lists.hyperledger.org。 + +### Transact 项目 + +![Hyperledger Transact 项目](_images/transact.png) + +Transact 项目由 Bitwise IO、Cargill、Intel、IBM、HACERA 等公司于 2019 年 5 月提交到社区。核心代码在 Github 上地址为 https://github.com/hyperledger/transact。 + +Transact 项目为区块链提供交易执行的平台和代码库,其他的框架性项目可以基于 Transact 来管理交易的执行过程和状态。Transact 项目试图打造一个通用的智能合约引擎来支持包括 EVM、WebAssembly 等合约的运行。目前包括 transact、transact-rfcs、transact-contrib 等子项目。 + +项目的邮件列表地址为 transact@lists.hyperledger.org。 + +### Aries 项目 + +![Hyperledger Aries 项目](_images/aries.png) + +Aries 项目由 Sovrin、C3I、和 Evernym 等公司于 2019 年 5 月提交到社区。核心代码在 Github 上地址为 https://github.com/hyperledger/aries。 + +Aries 项目希望能为客户端提供共享的密码学钱包和相关的代码库(包括零知识证明),以及对于链下交互的消息支持,以简化区块链客户端的开发。 + +项目的邮件列表地址为 aries@lists.hyperledger.org。 + +### Besu 项目 + +![Hyperledger Besu 项目](_images/besu.png) + +* Besu 项目由 Consensys、Hacera、JPM 和 Redhat 等公司于 2019 年 8 月正式贡献到社区。核心代码在 Github 上地址为 https://github.com/hyperledger/besu。 + +Besu 提供对以太坊协议的支持,由 Java 实现。 + +项目的邮件列表地址为 besu@lists.hyperledger.org。 + +### Avalon 项目 + +![Hyperledger Avalon 项目](_images/avalon.png) + +* Avalon 项目由 Intel、IEX、IBM 和 Consensys 等公司于 2019 年 9 月正式贡献到社区。主要提供链下的安全计算支持,重点考虑了安全性和可扩展性。项目核心代码在 https://github.com/hyperledger/avalon。 + +项目的邮件列表地址为 avalon@lists.hyperledger.org。 diff --git a/chainbrock-learning/08_hyperledger/summary.md b/chainbrock-learning/08_hyperledger/summary.md new file mode 100644 index 00000000..f53693cc --- /dev/null +++ b/chainbrock-learning/08_hyperledger/summary.md @@ -0,0 +1,6 @@ +## 本章小结 +超级账本项目是 Linux 基金会重点支持的面向企业的分布式账本平台。它同时也是开源界和工业界颇有历史意义的合作成果,将为分布式账本技术提供了在代码实现、协议和规范标准上的技术参考。 + +成立两年多时间以来,超级账本社区已经吸引了国内外各行业的大量关注,并获得了飞速发展。社区的开源项目、工作组和会员企业,共同构造了完善的企业级区块链生态。同时,超级账本项目中提出的许多创新技术和设计,也得到了来自业界和开源界的认可。 + +超级账本社区也十分重视应用落地。目前基于超级账本相关技术,已经出现了大量的企业应用案例,这为更多企业使用区块链技术提供了很好的应用参考。 diff --git a/chainbrock-learning/08_hyperledger/tools.md b/chainbrock-learning/08_hyperledger/tools.md new file mode 100644 index 00000000..50a75c57 --- /dev/null +++ b/chainbrock-learning/08_hyperledger/tools.md @@ -0,0 +1,70 @@ +## 开发必备工具 + +工欲善其事,必先利其器。开源社区提供了大量易用的开发协作工具。掌握好这些工具,对于高效的开发来说十分重要。 + +### Linux Foundation ID + +超级账本项目受到 Linux 基金会的支持,采用 Linux Foundation ID(LF ID)作为社区唯一的 ID。 + +个人申请 ID 是完全免费的。可以到 https://identity.linuxfoundation.org/ 进行注册。 + +用户使用该 ID 即可访问到包括 Jira、RocketChat 等社区的开发工具。 + +### Jira - 任务和进度管理 + +![Jira 任务管理](_images/jira.png) + +Jira 是 Atlassian 公司开发的一套任务管理和事项跟踪的追踪平台,提供 Web 操作界面,使用十分方面。 + +社区采用 jira.hyperledger.org 作为所有项目开发计划和任务追踪的入口,使用 LF ID 即可登录。 + +登录之后,可以通过最上面的 Project 菜单来查看某个项目相关的事项,还可以通过 Create 按钮来快速创建事项(常见的包括 task、bug、improvement 等)。 + +用户打开事项后可以通过 assign 按钮分配给自己来领取该事项。 + +一般情况下,事项分为 TODO(待处理)、In Process(处理中)、In Review(补丁已提交、待审查)、Done(事项已完成)等多个状态,由事项所有者来进行维护。 + +### Github - 代码仓库和 Review 管理 + +![Github 代码仓库管理](_images/github.png) + +Github 是全球最大的开源代码管理仓库服务,微软公司于 2018 年 7 月以 75 亿美金价格纳入旗下。 + +超级账本社区目前所有项目都通过 Github 进行管理。早期 Fabric、Cello、Explorer 等项目采用了自建的 Gerrit 服务作为官方的代码仓库,2019 年下半年也都陆续迁移到了 Github 服务器上。 + +用户使用自己的账号登录之后,可以查看所有项目信息,也可以查看自己提交的补丁等信息。每个补丁的页面上会自动追踪修改历史,审阅人可以通过页面进行审阅操作,赞同提交则可以批准,发现问题则可以进行批注。 + +### RocketChat - 在线沟通 + +![RocketChat 在线沟通](_images/rocket_chat.png) + +除了邮件列表外,社区也为开发者们提供了在线沟通的渠道—— RocketChat。 + +RocketChat 是一款功能十分强大的在线沟通软件,支持多媒体消息、附件、提醒、搜索等功能,虽然是开源软件,但在体验上可以跟商业软件 Slack 媲美。支持包括网页、桌面端、移动端等多种客户端。 + +社区采用 chat.hyperledger.org 作为服务器。最简单的,用户直接使用自己的 LF ID 登录该网站,即可访问。之后可以自行添加感兴趣项目的频道。 + +用户也可以下载 RocketChat 客户端,添加 chat.hyperledger.org 作为服务器即可访问社区内的频道,跟广大开发者进行在线交流。 + +通常,每个项目都有一个同名的频道作为主频道,例如 `#Fabric`,`#Cello` 等。同时,各个工作组也往往有自己的频道,例如大中华区技术工作组的频道为 `#twg-china`。 + +### 邮件列表 - 常见渠道 + +各个项目和工作组都建立了专门的邮件列表,作为常见的交流渠道。当发现问题不知道往哪里报告时,可以先发到邮件列表进行询问,一般都能获得及时的回答。 + +例如,大中华区技术工作组的频道为 `twg-china@lists.hyperledger.org`。 + +用户在 https://lists.hyperledger.org/g/main/subgroups 看到社区已有的邮件列表并选择加入。 + +### 提问的智慧 + +为什么我在社区提出的问题会过了很长时间也无人回应? + +开源社区是松散自组织形式,大部分开发者都是利用业余时间进行开发和参与社区工作。因此,在社区提出问题时就必须要注意问题的质量和提问的方式。碰到上述情况,首先要先从自身找原因。 + +如果能做到下面几点,会使你提出的问题得到更多的关注: + +* 正确的渠道:这点十分重要。不同项目和领域有各自的渠道,一定要在相关的渠道进行提问,而不要问跟列表主题不相关的话题,例如,每个项目相关问题应该发送到对应的邮件列表。 +* 问题的新颖性:在提问之前,应该利用包括搜索引擎、技术文档、邮件列表等常见方式进行查询,确保提出的问题是新颖的,有价值的,而不是已经被回答过多遍的常识性问题。 +* 适当的上下文:不少提问者的问题中只包括一条很简单的错误信息,这样会让社区的开发者有心帮忙也无力回答。良好的上下文包括完整的环境信息、所使用的软件版本、所进行操作的详细步骤、问题相关的日志、自己对问题的思考等。这些都可以帮助他人快速重现问题并帮忙回答。 +* 注意礼仪:虽然技术社区里大家沟通方式会更为直接一些,但懂得礼仪毫无疑问是会受到欢迎的。要牢记,别人的帮助并非是义务的,要对任何来自他人的帮助心存感恩。 diff --git a/chainbrock-learning/09_fabric_deploy/README.md b/chainbrock-learning/09_fabric_deploy/README.md new file mode 100644 index 00000000..be9d1a46 --- /dev/null +++ b/chainbrock-learning/09_fabric_deploy/README.md @@ -0,0 +1,7 @@ +# Fabric 安装与部署 + +** 纸上得来终觉浅,绝知此事要躬行。 ** + +作为被广泛应用的联盟链项目,Fabric 吸取了来自科技界和金融界的最新成果,提供面向企业场景的开放分布式账本平台实现。 + +本章将带领读者动手实践,学习如何从源码进行编译、安装 Fabric ,如何使用官方容器镜像,以及在多服务器环境下部署一个典型的 Fabric 网络,同时,还将介绍通道的相关实践操作。 diff --git a/chainbrock-learning/09_fabric_deploy/_images/docker_images.png b/chainbrock-learning/09_fabric_deploy/_images/docker_images.png new file mode 100644 index 00000000..7f296ce7 Binary files /dev/null and b/chainbrock-learning/09_fabric_deploy/_images/docker_images.png differ diff --git a/chainbrock-learning/09_fabric_deploy/_images/network_bootup.png b/chainbrock-learning/09_fabric_deploy/_images/network_bootup.png new file mode 100644 index 00000000..c5d34a51 Binary files /dev/null and b/chainbrock-learning/09_fabric_deploy/_images/network_bootup.png differ diff --git a/chainbrock-learning/09_fabric_deploy/_images/network_topology.png b/chainbrock-learning/09_fabric_deploy/_images/network_topology.png new file mode 100644 index 00000000..5388ad12 Binary files /dev/null and b/chainbrock-learning/09_fabric_deploy/_images/network_topology.png differ diff --git a/chainbrock-learning/09_fabric_deploy/install_docker.md b/chainbrock-learning/09_fabric_deploy/install_docker.md new file mode 100644 index 00000000..b01b5dee --- /dev/null +++ b/chainbrock-learning/09_fabric_deploy/install_docker.md @@ -0,0 +1,399 @@ +## 容器方式获取 + +除了手动进行本地编译外,还可以采用容器(Docker)镜像的方式快速获取和运行 Fabric 网络,节约本地编译等待的时间。 + +### 安装 Docker 服务 + +Docker 支持 Linux 常见的发行版(如 Redhat/Centos/Ubuntu)和 MacOS 等,推荐使用 1.18 或者更新的版本。 + +Linux 操作系统下可以通过如下命令来快速安装 Docker: + +```sh +$ curl -fsSL https://get.docker.com/ | sh +``` + +Ubuntu 18.04 中默认采用了 systemd 管理启动服务,配置文件在 `/lib/systemd/system/docker.service`。 + +对服务配置修改后,需要通过如下命令重启 Docker 服务: + +```sh +$ sudo systemctl daemon-reload +$ sudo systemctl restart docker.service +``` + +对于使用 upstart 管理启动服务的操作系统(如旧版本的 Ubuntu、Debian),则可以采用如下命令重启 Docker 服务: + +```sh +$ sudo service docker restart +``` + +MacOS 下可以通过访问 https://docs.docker.com/docker-for-mac/install 下载 Docker for Mac 安装包进行安装,在此不再赘述。 + +### 安装 docker-compose +docker-compose 是 Docker 官方推出的服务模板引擎,可以快速管理由多个 Docker 容器组成的服务。 + +首先,安装 python-pip 软件包: + +```sh +$ sudo aptitude install python-pip +``` + +安装 docker-compose(推荐为 1.10.0 及以上版本): + +```sh +$ sudo pip install docker-compose>=1.10.0 +``` + +### 获取 Docker 镜像 + +Docker 镜像可以自行从源码编译,或通过从 DockerHub 仓库下载等方式。 + +目前,Fabric 项目相关的 Docker 镜像有十几个,这些镜像都在 `hyperledger` 仓库中,它们之间的相互依赖关系如下图所示。 + +![镜像之间的依赖关系](_images/docker_images.png) + +从用途上,可以可以大致分为三类:核心镜像、辅助镜像和第三方镜像。 + +#### 核心镜像 + +提供 Fabric 网络运行的核心功能,目前包括 fabric-peer、fabric-orderer、fabric-ca、fabric-baseos、fabric-ccenv、fabric-javaenv、fabric-nodeenv 共 7 种镜像。如下表所示。 + +镜像名称 | 父镜像 | 功能描述 + -- | -- | -- +fabric-peer | alpine:3.10 | peer 节点镜像,安装了 peer 相关文件。生成过程使用 golang:1.13.4-alpine3.10 镜像。 +fabric-orderer | alpine:3.10 | orderer 节点镜像,安装了 orderer 相关文件。生成过程使用 golang:1.13.4-alpine3.10 镜像。 +fabric-ca | alpine:3.10 | fabric-ca 镜像,安装了 fabric-ca 相关文件。生成过程使用 golang:1.13.4-alpine 镜像。 +fabric-baseos | alpine:3.10 | 基础镜像,用来生成其它镜像(包括 Peer、Orderer、fabric-ca),并作为 Go 链码的默认运行时镜像。 +fabric-ccenv | golang:1.13.4-alpine3.10 | 支持 Go 语言的链码基础镜像,其中安装了 g++、gcc、git、musl-dev 等,并创建 chaincode 存放目录。在链码实例化过程中作为默认编译环境将链码编译为二进制文件。 +fabric-javaenv | adoptopenjdk/openjdk11:jdk-11.0.4_11-alpine |支持 Java 语言的链码基础镜像,其中安装了 Gradle、Maven、Java 链码 shim 层等,作为 Java 链码的默认运行时镜像。 +fabric-nodeenv | node:12.13.0-alpine | 支持 Node.Js 语言的链码基础镜像,其中安装了 make、python、g++。在链码实例化过程中作为默认编译环境生成 Node.Js 链码镜像,同时作为 Node.Js 链码运行环境。 + +#### 辅助镜像 + +提供支持功能,目前包括 fabric-baseimage、fabric-tools 镜像。如下表所示。 + +镜像名称 | 父镜像 | 功能描述 + -- | -- | -- +fabric-baseimage | adoptopenjdk:8u222-b10-jdk-openj9-0.15.1 | 基础镜像,安装了 wget、Golang、Node.JS、Python、Protocol buffer 支持等,用来生成其它镜像。作为运行时可以用来生成 Node.Js 链码镜像。 +fabric-tools | golang:1.13.4-alpine |安装了 bash、jq、peer、cryptogen、configtxgen 等常见命令,可以作为测试客户端使用。 + +#### 第三方镜像 + +主要是一些第三方开源软件,提供支持功能,目前包括 coudhdb、kafka、zookeeper 共 3 种镜像。如下表所示。 + +镜像名称 | 父镜像 | 功能描述 + -- | -- | -- +fabric-couchdb | debian:stretch-20190910-slim | couchdb 镜像,可以启动 couchdb 服务,供 peer 使用。 +fabric-kafka | adoptopenjdk:8u222-b10-jre-openj9-0.15.1 | kafka 镜像,可以启动 kafka 服务,供 orderer 在 kafka 模式下使用。已经不再支持。 +fabric-zookeeper | adoptopenjdk:8u222-b10-jre-openj9-0.15.1 | zookeeper 镜像,可以启动 zookeeper 服务,供 orderer 在 kafka 模式下使用。已经不再支持。 + +#### 从源码生成镜像 + +可以通过如下命令在本地快速生成包括 fabric-baseos、fabric-peer、fabric-orderer、fabric-ccenv、fabric-tools 等多个 Docker 镜像: + +```bash +$ make docker +``` + +注意,从源码直接生成的镜像,除了版本标签外,还会带有所编译版本快照信息的标签,例如 `amd64-2.0.0-snapshot123456`。 + +#### 从 Dockerhub 获取镜像 + +除了从源码编译外,还可以直接从 Dockerhub 来拉取相关的镜像,命令格式为 `docker pull `。 + +例如,从社区仓库直接获取 fabric-peer、fabric-orderer、fabric-ca、fabric-tools 等镜像的 2.0.0 版本可以使用如下命令: + +```bash +$ ARCH=amd64 +$ BASEIMAGE_RELEASE=0.4.18 +$ PROJECT_VERSION=2.0.0 + +# 拉取镜像 +$ docker pull hyperledger/fabric-peer:$ARCH-$PROJECT_VERSION \ + && docker pull hyperledger/fabric-orderer:$ARCH-$PROJECT_VERSION \ + && docker pull hyperledger/fabric-ca:$ARCH-$PROJECT_VERSION \ + && docker pull hyperledger/fabric-tools:$ARCH-$PROJECT_VERSION \ + && docker pull hyperledger/fabric-ccenv:$ARCH-$PROJECT_VERSION \ + && docker pull hyperledger/fabric-baseimage:$ARCH-$BASEIMAGE_RELEASE \ + && docker pull hyperledger/fabric-baseos:$ARCH-$PROJECT_VERSION +``` + +此外,还可以从第三方仓库获取镜像,拉取后可以添加默认的镜像标签别名。 + +例如,笔者仓库中构建了基于 Golang 基础镜像的相关 fabric 镜像,可以通过如下命令获取: + +```bash + +# 拉取镜像 +$ docker pull yeasy/hyperledger-fabric-base:$PROJECT_VERSION \ + && docker pull yeasy/hyperledger-fabric-peer:$PROJECT_VERSION \ + && docker pull yeasy/hyperledger-fabric-orderer:$PROJECT_VERSION \ + && docker pull yeasy/hyperledger-fabric-ca:$PROJECT_VERSION + +# 添加标签 +$ docker tag yeasy/hyperledger-fabric-peer:$PROJECT_VERSION hyperledger/fabric-peer:$ARCH-$PROJECT_VERSION \ + && docker tag yeasy/hyperledger-fabric-orderer:$PROJECT_VERSION hyperledger/fabric-orderer:$ARCH-$PROJECT_VERSION \ + && docker tag yeasy/hyperledger-fabric-ca:$PROJECT_VERSION hyperledger/fabric-ca:$ARCH-$PROJECT_VERSION \ + && docker tag yeasy/hyperledger-fabric-peer:$PROJECT_VERSION hyperledger/fabric-tools:$ARCH-$PROJECT_VERSION \ + && docker tag yeasy/hyperledger-fabric-base:$PROJECT_VERSION hyperledger/fabric-ccenv:$ARCH-$PROJECT_VERSION \ + && docker tag yeasy/hyperledger-fabric-base:$PROJECT_VERSION hyperledger/fabric-baseimage:$ARCH-$BASEIMAGE_RELEASE \ + && docker tag yeasy/hyperledger-fabric-base:$PROJECT_VERSION hyperledger/fabric-baseos:$ARCH-$PROJECT_VERSION +``` + +*注:BASEIMAGE_RELEASE 是基础镜像 fabric-baseimage 的版本号;PROJECT_VERSION 是具体版本号。这些版本号需要跟所使用的 Fabric 配置中保持一致。* + +### 镜像 Dockerfile + +读者也可自行通过编写 Dockefile 的方式来生成相关镜像。 + +Dockerfile 中指令跟本地编译过程十分类似,这里给出笔者编写的 fabric-base 镜像、fabric-orderer 镜像和 fabric-peer 镜像等关键镜像的 Dockerfile,供读者参考使用。 + +#### fabric-base 镜像 + +笔者提供的 fabric-base 镜像基于 golang:1.13 镜像生成,可以作为 Go 链码容器的基础镜像。该镜像中包含了 Fabric 相关的代码,并安装了一些有用的工具,包括 gotools、 configtxgen、configtxlator、cryptogen、discover、token、idemixgen 等。 + +该 Dockerfile 内容如下,也可从 https://github.com/yeasy/docker-hyperledger-fabric-base 下载获取: + +```yaml +# https://github.com/yeasy/docker-hyperledger-fabric-base +# +# Dockerfile for Hyperledger fabric base image. +# If you only need quickly deploy a fabric network, please see +# * yeasy/hyperledger-fabric-peer +# * yeasy/hyperledger-fabric-orderer +# * yeasy/hyperledger-fabric-ca + +# Workdir is set to $GOPATH/src/github.com/hyperledger/fabric +# Data is stored under /var/hyperledger/production + +FROM golang:1.13 +LABEL maintainer "Baohua Yang " + +ENV DEBIAN_FRONTEND noninteractive + +# Only useful for this Dockerfile +ENV FABRIC_ROOT=$GOPATH/src/github.com/hyperledger/fabric +ENV CHAINTOOL_RELEASE=1.1.3 + +# version for the base images (baseos, baseimage, ccenv, etc.) +ENV BASEIMAGE_RELEASE=0.4.18 +# BASE_VERSION is used in metadata.Version as major version +ENV BASE_VERSION=2.0.0 +# PROJECT_VERSION is required in core.yaml for fabric-baseos and fabric-ccenv +ENV PROJECT_VERSION=2.0.0 +# generic golang cc builder environment (core.yaml): builder: $(DOCKER_NS)/fabric-ccenv:$(ARCH)-$(PROJECT_VERSION) +ENV DOCKER_NS=hyperledger +# for golang or car's baseos for cc runtime: $(BASE_DOCKER_NS)/fabric-baseos:$(ARCH)-$(BASEIMAGE_RELEASE) +ENV BASE_DOCKER_NS=hyperledger +ENV LD_FLAGS="-X github.com/hyperledger/fabric/common/metadata.Version=${PROJECT_VERSION} \ + -X github.com/hyperledger/fabric/common/metadata.BaseDockerLabel=org.hyperledger.fabric \ + -X github.com/hyperledger/fabric/common/metadata.DockerNamespace=hyperledger \ + -X github.com/hyperledger/fabric/common/metadata.BaseDockerNamespace=hyperledger" + +# -X github.com/hyperledger/fabric/common/metadata.Experimental=true \ +# -linkmode external -extldflags '-static -lpthread'" + +# Peer config path +ENV FABRIC_CFG_PATH=/etc/hyperledger/fabric +RUN mkdir -p /var/hyperledger/production \ + $GOPATH/src/github.com/hyperledger \ + $FABRIC_CFG_PATH \ + /chaincode/input \ + /chaincode/output + +# Install development dependencies +RUN apt-get update \ + && apt-get install -y apt-utils python-dev \ + && apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev libyaml-dev libltdl-dev libtool \ + && apt-get install -y python-pip \ + && apt-get install -y vim tree jq unzip \ + && rm -rf /var/cache/apt + +# Install chaintool +#RUN curl -L https://github.com/hyperledger/fabric-chaintool/releases/download/v0.10.3/chaintool > /usr/local/bin/chaintool \ +RUN curl -fL https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric/hyperledger-fabric/chaintool-${CHAINTOOL_RELEASE}/hyperledger-fabric-chaintool-${CHAINTOOL_RELEASE}.jar > /usr/local/bin/chaintool \ + && chmod a+x /usr/local/bin/chaintool + +# install gotools +RUN go get github.com/golang/protobuf/protoc-gen-go \ + && go get github.com/maxbrunsfeld/counterfeiter \ + && go get github.com/axw/gocov/... \ + && go get github.com/AlekSi/gocov-xml \ + && go get golang.org/x/tools/cmd/goimports \ + && go get golang.org/x/lint/golint \ + && go get github.com/estesp/manifest-tool \ + && go get github.com/client9/misspell/cmd/misspell \ + && go get github.com/estesp/manifest-tool \ + && go get github.com/onsi/ginkgo/ginkgo + +# Clone the Hyperledger Fabric code and cp sample config files +RUN cd $GOPATH/src/github.com/hyperledger \ + && wget https://github.com/hyperledger/fabric/archive/v${PROJECT_VERSION}-beta.zip \ + && unzip v${PROJECT_VERSION}-beta.zip \ + && rm v${PROJECT_VERSION}-beta.zip \ + && mv fabric-${PROJECT_VERSION}-beta fabric \ + && echo "* hard nofile 65536" >> /etc/security/limits.conf \ + && echo "* soft nofile 65536" >> /etc/security/limits.conf \ + && cp -r $FABRIC_ROOT/sampleconfig/* $FABRIC_CFG_PATH/ + +# Add external farbric chaincode dependencies +RUN go get github.com/hyperledger/fabric-chaincode-go/shim \ + && go get github.com/hyperledger/fabric-protos-go/peer + +# Install configtxgen, cryptogen, configtxlator, discover and idemixgen +RUN cd $FABRIC_ROOT/ \ + && CGO_CFLAGS=" " go install -tags "" github.com/hyperledger/fabric/cmd/configtxgen \ + && CGO_CFLAGS=" " go install -tags "" github.com/hyperledger/fabric/cmd/cryptogen \ + && CGO_CFLAGS=" " go install -tags "" github.com/hyperledger/fabric/cmd/configtxlator \ + && CGO_CFLAGS=" " go install -tags "" -ldflags "-X github.com/hyperledger/fabric/cmd/discover/metadata.Version=2.0.0" github.com/hyperledger/fabric/cmd/discover \ +#&& CGO_CFLAGS=" " go install -tags "" -ldflags "-X github.com/hyperledger/fabric/cmd/token/metadata.Version=2.0.0" github.com/hyperledger/fabric/cmd/token \ + && CGO_CFLAGS=" " go install -tags "" github.com/hyperledger/fabric/cmd/idemixgen + +# The data and config dir, can map external one with -v +VOLUME /var/hyperledger + +# Temporarily fix the `go list` complain problem, which is required in chaincode packaging, see core/chaincode/platforms/golang/platform.go#GetDepoymentPayload +ENV GOROOT=/usr/local/go + +WORKDIR $FABRIC_ROOT + +# This is only a workaround for current hard-coded problem when using as the fabric-baseimage. +RUN ln -s $GOPATH /opt/gopath + +LABEL org.hyperledger.fabric.version=${PROJECT_VERSION} \ + org.hyperledger.fabric.base.version=${BASEIMAGE_RELEASE} + +``` + +该镜像也可以用作替代 `hyperledger/fabric-baseimage:latest` 镜像。 + +#### fabric-orderer 镜像 + +fabric-orderer 镜像基于 fabric-base 生成,编译安装了 orderer 组件。 + +参考 Dockerfile 内容如下,可从 https://github.com/yeasy/docker-hyperledger-fabric-orderer 下载获取: + +```yaml +# https://github.com/yeasy/docker-hyperledger-fabric-orderer +# +# Dockerfile for Hyperledger fabric-orderer image. + +FROM yeasy/hyperledger-fabric-base:2.0.0 +LABEL maintainer "Baohua Yang " + +EXPOSE 7050 + +ENV ORDERER_GENERAL_LOCALMSPDIR $FABRIC_CFG_PATH/msp +ENV ORDERER_GENERAL_LISTENADDRESS 0.0.0.0 +# ENV CONFIGTX_ORDERER_ORDERERTYPE=etcdraft + +RUN mkdir -p $FABRIC_CFG_PATH $ORDERER_GENERAL_LOCALMSPDIR + +# Install fabric orderer +RUN CGO_CFLAGS=" " go install -tags "" -ldflags "$LD_FLAGS" github.com/hyperledger/fabric/cmd/orderer \ + && go clean + +CMD ["orderer", "start"] +``` + +#### fabric-peer 镜像 + +fabric-peer 镜像基于 fabric-base 生成,编译安装了 peer 命令。 + +Dockerfile 内容如下,可从 https://github.com/yeasy/docker-hyperledger-fabric-peer 下载获取: + +```yaml +# https://github.com/yeasy/docker-hyperledger-fabric-peer +# +# Dockerfile for Hyperledger peer image. This actually follow yeasy/hyperledger-fabric +# image and add default start cmd. +# Data is stored under /var/hyperledger/production + +FROM yeasy/hyperledger-fabric-base:2.0.0 +LABEL maintainer "Baohua Yang " + +# Peer +EXPOSE 7051 + +# ENV CORE_PEER_MSPCONFIGPATH $FABRIC_CFG_PATH/msp + +# Install fabric peer +RUN CGO_CFLAGS=" " go install -tags "" -ldflags "$LD_FLAGS" github.com/hyperledger/fabric/cmd/peer \ + && go clean + +# First need to manually create a chain with `peer channel create -c test_chain`, then join with `peer channel join -b test_chain.block`. +CMD ["peer","node","start"] +``` + +#### fabric-ca 镜像 + +fabric-ca 镜像基于 golang:1.13 镜像生成,提供对证书的签发功能。 + +Dockerfile 内容如下,可从 https://github.com/yeasy/docker-hyperledger-fabric-ca 下载获取。 + +```yaml +# https://github.com/yeasy/docker-hyperledger-fabric-ca +# +# Dockerfile for Hyperledger fabric-ca image. +# If you need a peer node to run, please see the yeasy/hyperledger-peer image. +# Workdir is set to $GOPATH/src/github.com/hyperledger/fabric-ca +# More usage infomation, please see https://github.com/yeasy/docker-hyperledger-fabric-ca. + +FROM golang:1.13 +LABEL maintainer "Baohua Yang " + +ENV PROJECT_VERSION 2.0.0 + +# ca-server and ca-client will check the following env in order, to get the home cfg path +ENV FABRIC_CA_HOME /etc/hyperledger/fabric-ca-server +ENV FABRIC_CA_SERVER_HOME /etc/hyperledger/fabric-ca-server +ENV FABRIC_CA_CLIENT_HOME $HOME/.fabric-ca-client +ENV CA_CFG_PATH /etc/hyperledger/fabric-ca + +# This is to simplify this Dockerfile +ENV FABRIC_CA_ROOT $GOPATH/src/github.com/hyperledger/fabric-ca + +# Usually the binary will be installed into $GOPATH/bin, but we add local build path, too +ENV PATH=$FABRIC_CA_ROOT/bin:$PATH + +#ARG FABRIC_CA_DYNAMIC_LINK=false + +# fabric-ca-server will open service to '0.0.0.0:7054/api/v1/' +EXPOSE 7054 + +RUN mkdir -p $GOPATH/src/github.com/hyperledger \ + $FABRIC_CA_SERVER_HOME \ + $FABRIC_CA_CLIENT_HOME \ + $CA_CFG_PATH \ + /var/hyperledger/fabric-ca-server + +# Need libtool to provide the header file ltdl.h +RUN apt-get update \ + && apt-get install -y libtool unzip \ + && rm -rf /var/cache/apt + +# Install yq to update config for fabric-ca +RUN wget -O /go/bin/yq https://github.com/mikefarah/yq/releases/download/2.4.1/yq_linux_amd64 \ + && chmod a+x /go/bin/yq + +# clone and build ca +RUN cd $GOPATH/src/github.com/hyperledger \ + && wget https://github.com/hyperledger/fabric-ca/archive/v${PROJECT_VERSION}.zip \ + && unzip v${PROJECT_VERSION}.zip \ + && rm v${PROJECT_VERSION}.zip \ + && mv fabric-ca-${PROJECT_VERSION} fabric-ca \ +# This will install fabric-ca-server and fabric-ca-client into $GOPATH/bin/ + && go install -ldflags "-X github.com/hyperledger/fabric-ca/lib/metadata.Version=$PROJECT_VERSION -linkmode external -extldflags '-static -lpthread'" github.com/hyperledger/fabric-ca/cmd/... \ +# Copy example ca and key files +#&& cp $FABRIC_CA_ROOT/images/fabric-ca/payload/*.pem $FABRIC_CA_HOME/ \ + && go clean + +VOLUME $FABRIC_CA_SERVER_HOME +VOLUME $FABRIC_CA_CLIENT_HOME + +WORKDIR $FABRIC_CA_ROOT + +# if no config exists under $FABRIC_CA_HOME, will init fabric-ca-server-config.yaml and fabric-ca-server.db +CMD ["bash", "-c", "fabric-ca-server start -b admin:adminpw"] +#CMD ["bash", "-c", "fabric-ca-server start --ca.certfile $FABRIC_CA_HOME/ca-cert.pem --ca.keyfile $FABRIC_CA_HOME/ca-key.pem -b admin:adminpw -n test_ca"] +``` diff --git a/chainbrock-learning/09_fabric_deploy/install_local.md b/chainbrock-learning/09_fabric_deploy/install_local.md new file mode 100644 index 00000000..7ba550dc --- /dev/null +++ b/chainbrock-learning/09_fabric_deploy/install_local.md @@ -0,0 +1,221 @@ +## 本地编译组件 + +本地编译生成 Fabric 网络的各个组件,可以形成更直观的认识。Fabric 采用 Go 语言实现,推荐使用 Golang 1.10+ 版本进行编译。 + +下面将讲解如何编译生成 fabric-peer、fabric-orderer 和 fabric-ca 等组件的二进制文件,以及如何安装一些配置和开发辅助工具。如果用户在多服务器环境下进行部署,需要注意将文件复制到对应的服务器上。 + +### 环境配置 + +#### 操作系统 + +常见的 Linux 操作系统发行版(包括 Ubuntu、Redhat、CentOS 等)和 macOS 等都可以支持 Fabric。 + +内核推荐 3.10+ 版本,支持 64 位环境。下面将默认以 Ubuntu 18.04 操作系统为例进行讲解。 + +*注:运行 Fabric 节点需要的资源并不苛刻,作为实验,Fabric 节点甚至可以在树莓派(Raspberry Pi)上正常运行。但生产环境中往往需要较高的 CPU 和内存资源。* + +#### 安装 Go 语言环境 + +可以访问 [golang.org](https://golang.org) 网站下载压缩包进行安装。不推荐使用自带的包管理器安装,版本往往比较旧。 + +如下载最新的 Go 1.13.4 稳定版本,可以采用如下命令: + +```bash +$ curl -O https://dl.google.com/go/go1.13.4.linux-amd64.tar.gz +``` + +下载完成后,解压目录,并移动到合适的位置(如 /usr/local): + +```bash +$ tar -xvf go1.13.4.linux-amd64.tar.gz +$ sudo mv go /usr/local +``` + +配置 GOPATH 环境变量,同时可以加入 .bash_profile 文件中以长期生效: + +```bash +export GOPATH=YOUR_LOCAL_GO_PATH/Go +export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin +``` + +此时,可以通过 `go version` 命令验证安装是否成功: + +```bash +$ go version + +go version go1.13.4 linux/amd64 +``` + +#### 安装依赖包 + +编译 Fabric 代码依赖一些开发库,可以通过如下命令安装: + +```bash +$ sudo apt-get update \ + && sudo apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev libyaml-dev libltdl-dev libtool +``` + +#### 安装 Docker 环境 + +Fabric 目前采用 Docker 容器作为链码执行环境,因此即使在本地运行,Peer 节点上也需要安装 Docker 环境,推荐使用 1.18 或者更新的版本。 + +Linux 操作系统下可以通过如下命令来安装 Docker 最新版本: + +```bash +$ curl -fsSL https://get.docker.com/ | sh +``` + +macOS 可以访问 https://docs.docker.com/docker-for-mac/install 下载 `Docker for Mac` 安装包自行安装: + +### 获取代码 + +目前,Fabric 官方仓库托管在 Github 仓库(github.com/hyperledger/fabric)中供下载使用。 + +如果使用 1.13 之前版本的 Go 环境,需要将 Fabric 项目放到 $GOPATH 路径下。如下命令所示,创建 `$GOPATH/src/github.com/hyperledger` 目录结构并切换到该路径: + +```bash +$ mkdir -p $GOPATH/src/github.com/hyperledger +$ cd $GOPATH/src/github.com/hyperledger +``` + +获取 Peer 和 Orderer 组件编译所需要的代码,两者目前在同一个 fabric 仓库中: + +```bash +$ git clone https://github.com/hyperledger/fabric.git +``` + +为节约下载时间,读者可以指定 `--single-branch -b master --depth 1` 命令选项来指定只获取 master 分支最新代码: + +```bash +$ git clone --single-branch -b master --depth 1 https://github.com/hyperledger/fabric.git +``` + +Fabric CA 组件在独立的 fabric-ca 仓库中,可以通过如下命令获取: + +```bash +$ git clone https://github.com/hyperledger/fabric-ca.git +``` + +读者也可以直接访问 https://github.com/hyperledger/fabric/releases 和 https://github.com/hyperledger/fabric-ca/releases 来下载特定的 fabric 和 fabric-ca 发行版。 + +最后,检查确认 fabric 和 fabric-ca 两个仓库下载成功: + +```bash +$ ls $GOPATH/src/github.com/hyperledger +fabric fabric-ca +``` + +### 编译安装 Peer 组件 + +配置版本号和编译参数: + +```bash +$ PROJECT_VERSION=2.0.0 +$ LD_FLAGS="-X github.com/hyperledger/fabric/common/metadata.Version=${PROJECT_VERSION} \ + -X github.com/hyperledger/fabric/common/metadata.BaseDockerLabel=org.hyperledger.fabric \ + -X github.com/hyperledger/fabric/common/metadata.DockerNamespace=hyperledger \ + -X github.com/hyperledger/fabric/common/metadata.BaseDockerNamespace=hyperledger" +``` + +通过如下命令编译并安装 fabric 的 peer 组件到 $GOPATH/bin 下: + +```bash +$ CGO_CFLAGS=" " go install -tags "" -ldflags "$LD_FLAGS" \ + github.com/hyperledger/fabric/cmd/peer +``` + +当然,用户也可直接使用源码中的 Makefile 来进行编译,相关命令如下: + +```bash +$ make peer +``` + +这种情况下编译生成的 peer 组件会默认放在 build/bin 路径下。 + +### 编译安装 Orderer 组件 +通过如下命令编译并安装 fabric orderer 组件到 $GOPATH/bin 下: + +```bash +$ CGO_CFLAGS=" " go install -tags "" -ldflags "$LD_FLAGS" \ + github.com/hyperledger/fabric/cmd/orderer +``` + +同样的,也可使用 Makefile 来编译安装 orderer 组件到 build/bin 路径下: + +```bash +$ make orderer +``` + +### 编译安装 Fabric CA 组件 +采用如下命令编译并安装 fabric-ca 相关组件到 $GOPATH/bin 下: + +```bash +$ go install -ldflags "-X github.com/hyperledger/fabric-ca/lib/metadata.Version=$PROJECT_VERSION -linkmode external -extldflags '-static -lpthread'" \ + github.com/hyperledger/fabric-ca/cmd/... +``` + +### 编译安装配置辅助工具 + +Fabric 中还提供了一系列配置辅助工具,包括 cryptogen(本地生成组织结构和身份文件)、configtxgen(生成配置区块和配置交易)、configtxlator(解析转换配置信息)、discover(拓扑探测)、idemixgen(Idemix 证书生成)等,可以通过如下命令来快速编译和安装: + +```bash + +# 编译安装 cryptogen,等价于执行 make cryptogen +$ CGO_CFLAGS=" " \ + go install -tags "" -ldflags "$LD_FLAGS" \ + github.com/hyperledger/fabric/cmd/cryptogen + +# 编译安装 configtxgen,等价于执行 make configtxgen +$ CGO_CFLAGS=" " \ + go install -tags "" -ldflags "$LD_FLAGS" \ + github.com/hyperledger/fabric/cmd/configtxgen + +# 编译安装 configtxlator,等价于执行 make configtxlator +$ CGO_CFLAGS=" " \ + go install -tags "" -ldflags "$LD_FLAGS" \ + github.com/hyperledger/fabric/cmd/configtxlator + +# 编译安装 discover,等价于执行 make discover +$ CGO_CFLAGS=" " \ + go install -tags "" -ldflags "$LD_FLAGS" \ + github.com/hyperledger/fabric/cmd/discover + +# 编译安装 idemixgen,等价于执行 make idemixgen +$ CGO_CFLAGS=" " \ + go install -tags "" -ldflags "$LD_FLAGS" \ + github.com/hyperledger/fabric/cmd/idemixgen +``` + +另外,fabric 项目还提供了不少常见的编译命令,可以参考 Makefile 文件,例如编译所有的二进制文件可以使用如下命令: + +```bash +$ make native +``` + +### 安装 Protobuf 支持和 Go 语言相关工具 + +Fabric 代码由 Go 语言构建,开发者可以选择安装如下的 Go 语言相关工具,方便开发和调试: + +```bash +$ go get github.com/golang/protobuf/protoc-gen-go \ + && go get github.com/maxbrunsfeld/counterfeiter/v6 \ + && go get github.com/axw/gocov/... \ + && go get github.com/AlekSi/gocov-xml \ + && go get golang.org/x/tools/cmd/goimports \ + && go get golang.org/x/lint/golint \ + && go get github.com/estesp/manifest-tool \ + && go get github.com/client9/misspell/cmd/misspell \ + && go get github.com/onsi/ginkgo/ginkgo +``` + +### 示例配置 + +sampleconfig 目录下包括了一些示例配置文件,可以作为参考,包括: + +* configtx.yaml:示例配置区块生成文件夹; +* orderer.yaml:示例 Orderer 节点配置文件; +* core.yaml:示例 Peer 节点配置文件; +* msp/config.yaml:示例组织身份配置文件; +* msp/:示例证书和秘钥文件。 + +可以将它们复制到默认的配置目录(/etc/hyperledger/fabric)下进行使用。 diff --git a/chainbrock-learning/09_fabric_deploy/intro.md b/chainbrock-learning/09_fabric_deploy/intro.md new file mode 100644 index 00000000..a3e53d50 --- /dev/null +++ b/chainbrock-learning/09_fabric_deploy/intro.md @@ -0,0 +1,33 @@ +## 简介 + +Fabric 是超级账本社区首个项目也是最流行的分布式账本实现,由 IBM、DAH 等会员企业于 2015 年底贡献到社区。 + +作为面向企业场景的联盟链,Fabric 中有许多经典的设计和先进的理念。包括多通道、身份证书机制、隐私保护、运维管理接口等。另外,其可扩展的架构可以满足不同场景下的性能需求,如虚拟机部署场景下可以达到 3500 tps 的吞吐量和小于 1 秒的延迟(参考《Hyperledger Fabric: A Distributed Operating System for Permissioned Blockchains》),更多物理资源情况下可以达到更大的(10 K+)的吞吐量。 + +### 主要版本历史 + +Fabric 首个主版本 1.0.0 于 2017 年 7 月发布,该版本根据之前测试版的应用反馈,在架构上进行了重新设计,在可扩展性和可插拔性方面都有了不少改进。后续版本基本上按照每季度一个小版本的节奏发布。重点对性能和安全性、隐私性进行了完善和提升。目前最新大版本为 2.0.0 版本。Fabric 的主要版本历史总结如下表所示,也可在 https://github.com/hyperledger/fabric/releases 找到。 + +版本 | 发布时间 | 新特性 | 增强和改善 +--- | ------- | ---- | ---- +1.0.0 | 2017-07-11 | 重新设计架构,支持多通道、Kafka 共识机制、系统链码、分角色节点 | 大幅度提升性能和可扩展性 +1.1.0 | 2018-03-15 | Node.Js 链码,链码加密库,链码中基于证书属性的访问控制,节点之间的双向 TLS,Fabric CA 中对 CRL 的支持。部分实验特性,如 sideDB、idemix、细粒度的权限控制。| 大幅优化了性能,某些场景下可提升一个数量级;提供基于通道的事件通知模型 +1.2.0 | 2018-07-04 | 正式支持私有数据库(Private Data),提供可插拔的 ESCC 和 VSCC,细粒度访问控制,服务自动发现 | 提高了稳定性和易用性 +1.3.0 | 2018-10-11 | 正式支持 Java 链码;提供细粒度的基于状态的背书策略;支持 idemix 增强隐私保护| 部分重构链码生命周期管理;通过分页机制优化链码中对大量数据的查询 +1.4.0 | 2019-01-09 | 提供运维相关的 RESTful API(统计、健康检查、日志级别);使用新的日志控制环境变量 | 增强私有数据:新 Peer 自动获取缺失私有数据,客户端层面对私有数据的权限控制;开始支持新的 RAFT 排序机制 +2.0.0 | 2020-03-TBD | 新的面向通道的链码生命周期管理;独立 shim 库等 | 增强私有数据支持;增强排序服务;改进性能 + +### 网络基本结构 + +Fabric 网络中存在四种不同种类的服务节点,彼此协作完成整个区块链系统的记账功能: + +* 背书节点(Endorser Peer):一类特殊的 Peer,对交易提案(Transaction Proposal)进行检查,通过执行智能合约计算交易执行结果(读写集合)并对其进行背书; +* 记账节点(Committer Peer):负责维护账本,检查排序后交易结果合法性,接受合法修改,并写入到本地账本结构,目前所有 Peer 默认都是记账节点; +* 排序节点(Orderer):正式交易会发给排序节点,排序节点负责对网络中所有交易进行排序处理,并整理为区块结构,之后被记账节点拉取提交到本地账本; +* 证书节点(CA):提供标准的 PKI 服务,负责对网络中所有的证书进行管理,包括签发和撤销。 + +节点角色是 Fabric 设计中的一大创新。根据性能和安全需求,不同的节点可以由组织分别管理,共同构建联盟链。 + +此外,网络账本的基本单位是通道(Channel),每个通道内的成员可以共享账本,不同通道内账本则彼此隔离。客户端可以向网络内发送交易,交易经过共识后被通道内的 Peer 节点接收并更新本地对应的账本。 + +本章后续将详细介绍安装、部署 Fabric 网络并进行启动的操作过程,建议读者跟随步骤进行实践学习。 diff --git a/chainbrock-learning/09_fabric_deploy/start_docker.md b/chainbrock-learning/09_fabric_deploy/start_docker.md new file mode 100644 index 00000000..3bef07a9 --- /dev/null +++ b/chainbrock-learning/09_fabric_deploy/start_docker.md @@ -0,0 +1,83 @@ +## 容器方式启动 Fabric 网络 + +除了上面讲解的手动部署的方式,读者还可以基于容器方式来快速部署 Fabric 网络并验证功能。 + +首先,按照如下命令下载 Docker-Compose 模板文件,并进入 `hyperledger_fabric` 目录,可以看到有对应多个 Fabric 版本的项目,用户可以根据需求选用特定版本: + +```sh +$ git clone https://github.com/yeasy/docker-compose-files +$ cd docker-compose-files/hyperledger_fabric +``` + +以 Fabric 2.0.0 版本为例,进入到对应目录下,并先下载所需镜像文件: + +```bash +$ cd v2.0.0 +$ make download +``` + +查看目录下内容,主要包括若干 Docker-Compose 模板文件,主要包括: + +* docker-compose-2orgs-4peer-raft.yaml:包括 4 个 peer 节点(属于两个组织)、3 个 Orderer 节点(Raft 模式)、2 个 CA 节点、1 个客户端节点; +* docker-compose-1orgs-1peers-dev.yaml:包括 1 个 peer 节点、1 个 Orderer 节点、1 个 CA 节点、1 个客户端节点。本地 Fabric 源码被挂载到了客户端节点中,方便进行调试; +* docker-compose-2orgs-4peer-kafka.yaml:包括 4 个 peer 节点(属于两个组织)、3 个 Orderer 节点(Kafka 模式)、2 个 CA 节点、1 个客户端节点; +* docker-compose-2orgs-4peer-couchdb.yaml:包括 4 个 peer 节点(属于两个组织,启用 couchDB 作为状态数据库)、2 个 Orderer 节点、1 个 CA 节点、1 个客户端节点。 + +使用 Make 命令进行操作。例如使用 HLF_MODE 指定排序服务为 Raft 模式,快速启动网络并执行一系列测试: + +```bash +$ HLF_MODE=raft make test +``` + +`make test` 实际上自动执行了一系列指令: + +* make gen_config_crypto:生成网络需要的身份文件; +* make gen_config_channel:生成网络需要的配置文件; +* make start:启动网络; +* make channel_test:执行通道创建和加入通道; +* make update_anchors:更新锚节点信息; +* make cc_test:执行链码相关测试,包括安装、实例化和调用; +* make test_lscc:测试系统链码 LSCC 调用(使用 2.0 中新的链码生命周期则不支持); +* make test_qscc:测试系统链码 QSCC 调用; +* make test_cscc:测试系统链码 CSCC 调用; +* make test_fetch_blocks:获取通道内的区块; +* make test_config_update:生成新版本配置; +* make test_channel_update:测试更新通道配置; +* make test_configtxlator:测试 configtxlator 转换; +* make test_channel_list:测试列出 Peer 加入的通道; +* make test_channel_getinfo:测试获取通道信息; +* make stop:停止网络。 + +运行过程中会自动创建网络并逐个完成通道和链码的相关测试,注意查看输出日志中无错误信息。 + +网络启动后,可以通过 `docker ps` 命令查看本地系统中运行的容器信息: + +```bash +$ docker ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +1ee7db027b3f yeasy/hyperledger-fabric-peer:2.0.0 "peer node start" 27 seconds ago Up 22 seconds 9443/tcp, 0.0.0.0:8051->7051/tcp peer1.org1.example.com +8f7bffcd14b3 yeasy/hyperledger-fabric-peer:2.0.0 "peer node start" 27 seconds ago Up 22 seconds 9443/tcp, 0.0.0.0:10051->7051/tcp peer1.org2.example.com +8a4e9aaec7ba yeasy/hyperledger-fabric-peer:2.0.0 "peer node start" 27 seconds ago Up 22 seconds 9443/tcp, 0.0.0.0:9051->7051/tcp peer0.org2.example.com +7b9d394f26c0 yeasy/hyperledger-fabric-peer:2.0.0 "peer node start" 27 seconds ago Up 23 seconds 0.0.0.0:7051->7051/tcp, 9443/tcp peer0.org1.example.com +ce9ca6c7b672 yeasy/hyperledger-fabric-orderer:2.0.0 "orderer start" 30 seconds ago Up 27 seconds 8443/tcp, 0.0.0.0:8050->7050/tcp orderer1.example.com +2646b7f0e462 yeasy/hyperledger-fabric:2.0.0 "bash -c 'cd /tmp; s…" 30 seconds ago Up 15 seconds 7050-7054/tcp fabric-cli +c35e8694c634 yeasy/hyperledger-fabric-orderer:2.0.0 "orderer start" 30 seconds ago Up 27 seconds 8443/tcp, 0.0.0.0:9050->7050/tcp orderer2.example.com +1d6dd5009141 yeasy/hyperledger-fabric-orderer:2.0.0 "orderer start" 30 seconds ago Up 27 seconds 0.0.0.0:7050->7050/tcp, 8443/tcp orderer0.example.com +``` + +用户如果希望在客户端、Peer 或 Orderer 容器内执行命令,可以通过 `make cli|peer|orderer` 命令进入到容器中。 + +例如,如下命令可以让用户登录到客户端节点,在其中以指定身份发送网络请求: + +```bash +$ make cli +``` + +用户也可以通过如下命令来查看日志输出: + +```bash +$ make logs +``` + +更多操作命令用户可以参考 Makefile 内容,在此不再赘述。 + diff --git a/chainbrock-learning/09_fabric_deploy/start_local.md b/chainbrock-learning/09_fabric_deploy/start_local.md new file mode 100644 index 00000000..c87c284a --- /dev/null +++ b/chainbrock-learning/09_fabric_deploy/start_local.md @@ -0,0 +1,603 @@ +## 本地启动 Fabric 网络 + +启动一个 Fabric 网络主要包括如下步骤: + +* **规划初始网络拓扑**:根据联盟的需求规划拓扑信息,包括联盟成员、排序服务集群、应用通道的初始成员等; +* **准备网络配置**:包括网络中组织结构和对应的身份证书(可使用 cryptogen 工具或 fabric-ca 完成),系统通道的初始配置区块文件、新建应用通道的配置更新交易文件以及可能需要的锚节点配置更新交易文件(可使用 configtxgen 工具完成); +* **启动 Orderer 节点**:使用系统通道的初始区块文件启动排序服务,排序服务启动后自动按照指定配置创建系统通道; +* **启动 Peer 节点**:不同的组织按照预置角色分别启动 Peer 节点; +* **创建通道**:客户端使用新建应用通道的配置更新交易文件,向系统通道发送交易,创建新的应用通道; +* **加入通道**:Peer 节点利用初始区块加入到所创建的应用通道。 + + + +主要步骤如下图所示,下面进行具体讲解。 + +![网络启动步骤](_images/network_bootup.png) + +### 规划初始网络拓扑 + +示例网络拓扑如下图所示,包括 3 个 Orderer 节点和 4 个 Peer 节点,以及 1 个客户端操作节点(负责生成相关启动文件,在网络启动后作为客户端执行命令)。 + +![网络拓扑结构](_images/network_topology.png) + +其中,排序服务采用 Raft 模式,所有节点都加入到新建的 businesschannel 中。4 个 Peer 节点分属两个组织:Org1 和 Org2,也都是应用通道成员。每个组织中的 peer0 节点作为锚节点(Anchor Peer)负责与其它组织节点分享信息。 + +### 准备启动配置文件 + +Fabric 网络在启动之前,需要提前生成一些用于启动的配置文件,主要包括 MSP 相关身份文件(`msp/*`)、TLS 相关身份文件(`tlsca/*`)、系统通道初始区块(`orderer.genesis.block`)、新建应用通道交易文件(`businesschannel.tx`)、锚节点配置更新交易文件( `Org1MSPanchors.tx` 和 `Org2MSPanchors.tx`)等。 + +各个文件的功能如下表所示。 + +启动配置 | 使用者 | 依赖文件 | 主要功能 +-- | -- | -- | -- +MSP 相关文件 `msp/*` | Peer、Orderer、客户端 | crypto-config.yaml | 包括证书文件、签名私钥等,代表实体身份相关信息 +TLS 相关文件 `tls/*` | Peer、Orderer、客户端 | crypto-config.yaml | 启用 TLS 时用于验证 +系统通道初始区块文件 `orderer.genesis.block` | Orderer | configtx.yaml | 用于创建系统通道,配置网络中策略 +新建应用通道交易文件 `businesschannel.tx` | 客户端 | configtx.yaml | 用于新建应用通道,其中指定通道成员、访问策略等 +锚节点配置更新交易文件 `Org1MSPanchors.tx` 和 `Org2MSPanchors.tx` | 客户端 | configtx.yaml | 用于更新通道中各组织的锚节点信息 + +下面主要描述这些配置文件的生成过程,后续相关章节将具体介绍其功能。 + +#### 生成组织关系和身份证书 +Fabric 网络作为联盟链,需要多个成员组织共同维护。成员之间通过身份来进行鉴权,网络通过身份来实现资源访问的权限管理。因此各成员组织都需要提前准备对应的身份文件,并部署到其所拥有的节点和客户端上。 + +用户可通过标准 PKI 服务(如使用 Fabric CA 实现)或 OpenSSL 工具来手动生成各个实体的证书和私钥。Fabric 项目还提供了 cryptogen 工具(基于 Golang crypto 标准库)在本地生成,需要提前准备 crypto-config.yaml 配置文件。 + +crypto-config.yaml 配置文件的结构十分简单,支持定义两种类型(OrdererOrgs 和 PeerOrgs)的若干组织。每个组织中又可以定义多个节点(Spec)和用户(User)。 + +一个示例的 crypto-config.yaml 配置文件内容如下,其中定义了一个 OrdererOrgs 类型的组织 example.com,包括 3 个节点;两个 PeerOrgs 类型的组织 org1.example.com 和 org2.example.com,分别包括 2 个节点和 1 个普通用户身份: + +```yaml +OrdererOrgs: + - Name: Orderer + Domain: example.com + CA: + Country: US + Province: California + Locality: San Francisco + Specs: + - Hostname: orderer0 + - Hostname: orderer1 + - Hostname: orderer2 +PeerOrgs: + - Name: Org1 + Domain: org1.example.com + EnableNodeOUs: true + CA: + Country: US + Province: California + Locality: San Francisco + Template: + Count: 2 + Users: + Count: 1 + - Name: Org2 + Domain: org2.example.com + EnableNodeOUs: true + CA: + Country: US + Province: California + Locality: San Francisco + Template: + Count: 2 + Users: + Count: 1 +``` + +使用该配置文件,通过如下命令可生成指定组织结构的身份文件,并存放到 crypto-config 目录下: + +```bash +$ cryptogen generate \ + --config=./crypto-config.yaml \ + --output ./crypto-config +``` + +用户修改配置后,还可以通过 extend 子命令来更新 crypto-config 目录: + +```bash +$ cryptogen extend \ + --config=./crypto-config.yaml \ + --input ./crypto-config +``` + +查看刚生成的 crypto-config 目录,结构如下所示: + +```bash +$ tree -L 4 crypto-config +crypto-config +|-- ordererOrganizations +| `-- example.com +| |-- ca +| | |-- 293def0fc6d07aab625308a3499cd97f8ffccbf9e9769bf4107d6781f5e8072b_sk +| | `-- ca.example.com-cert.pem +| |-- msp +| | |-- admincerts/ +| | |-- cacerts/ +| | `-- tlscacerts/ +| |-- orderers +| | `-- orderer0.example.com/ +| | `-- orderer1.example.com/ +| | `-- orderer2.example.com/ +| |-- tlsca +| | |-- 2be5353baec06ca695f7c3b04ca0932912601a4411939bfcfd44af18274d5a65_sk +| | `-- tlsca.example.com-cert.pem +| `-- users +| `-- Admin@example.com/ +`-- peerOrganizations + |-- org1.example.com + | |-- ca + | | |-- 501c5f828f58dfa3f7ee844ea4cdd26318256c9b66369727afe8437c08370aee_sk + | | `-- ca.org1.example.com-cert.pem + | |-- msp + | | |-- admincerts/ + | | |-- cacerts/ + | | `-- tlscacerts/ + | |-- peers + | | |-- peer0.org1.example.com/ + | | `-- peer1.org1.example.com/ + | |-- tlsca + | | |-- 592a08f84c99d6f083b3c5b9898b2ca4eb5fbb9d1e255f67df1fa14c123e4368_sk + | | `-- tlsca.org1.example.com-cert.pem + | `-- users + | |-- Admin@org1.example.com/ + | `-- User1@org1.example.com/ + `-- org2.example.com + |-- ca + | |-- 86d97f9eb601868611eab5dc7df88b1f6e91e129160651e683162b958a728162_sk + | `-- ca.org2.example.com-cert.pem + |-- msp + | |-- admincerts/ + | |-- cacerts/ + | `-- tlscacerts/ + |-- peers + | |-- peer0.org2.example.com/ + | `-- peer1.org2.example.com/ + |-- tlsca + | |-- 4b87c416978970948dffadd0639a64a2b03bc89f910cb6d087583f210fb2929d_sk + | `-- tlsca.org2.example.com-cert.pem + `-- users + |-- Admin@org2.example.com/ + `-- User1@org2.example.com/ +``` + +按照 crypto-config.yaml 中定义,crypto-config 目录下包括多级目录结构。其中 ordererOrganizations 下包括构成 Orderer 组织(包括 3 个 Orderer 节点)的身份信息;peerOrganizations 下为所有的 Peer 节点组织(包括2 个组织,4 个节点)的相关身份信息。各个实体都含有 msp 和 tls 目录,分别包括对应的认证身份文件和 TLS 身份文件(公钥证书、私钥等)。 + +对于 Orderer 节点来说,需要将 `ordererOrganizations/example.com/orderers/ordererX.example.com` 目录下内容(包括 msp 和 tls 两个子目录)复制到对应 Orderer 节点的配置路径(默认为 `/etc/hyperledger/fabric`)下。 + +对于 Peer 节点来说,则需要复制 peerOrganizations 下对应的身份证书文件。以 org1 的 peer0 为例,将 `peerOrganizations/org1.example.com/peers/peer0.org1.example.com` 目录下内容(包括 msp 和 tls)复制到 Peer0 节点的配置路径(默认为 `/etc/hyperledger/fabric`)下。 + +对于客户端节点来说,需要复制对应身份的用户目录,例如 Org1 的管理员身份为 peerOrganizations/org1.example.com/users/Admin@org1.example.com/。 + +#### 生成系统通道初始区块 + +系统通道是网络启动后的首个通道,负责管理网络整体配置。排序节点在启动后,可以使用初始区块文件来创建一个新的网络。 + +初始区块中包括了排序服务的相关配置信息(如排序节点信息、块大小、最大通道数、默认策略等)和示例联盟配置。可以使用 configtxgen 工具生成。生成过程依赖 `configtx.yaml` 文件。 + +configtx.yaml 配置文件定义了整个网络中的相关配置和拓扑结构信息,用户可参考 `sampleconfig/configtx.yaml` 示例文件进行编写。这里采用如下内容,各个字段含义可参考后续配置说明章节: + +```yaml +Profiles: + TwoOrgsOrdererGenesis: + <<: *ChannelDefaults + Capabilities: + <<: *ChannelCapabilities + Orderer: + <<: *OrdererDefaults + Organizations: + - *OrdererOrg + Capabilities: + <<: *OrdererCapabilities + Consortiums: + SampleConsortium: + Organizations: + - *Org1 + - *Org2 + TwoOrgsChannel: + Consortium: SampleConsortium + <<: *ChannelDefaults + Capabilities: + <<: *ChannelCapabilities + Application: + <<: *ApplicationDefaults + Organizations: + - *Org1 + - *Org2 + Capabilities: + <<: *ApplicationCapabilities +Organizations: + - &OrdererOrg + Name: OrdererOrg + SkipAsForeign: false + ID: OrdererMSP + MSPDir: msp + Policies: + Readers: + Type: Signature + Rule: "OR('OrdererMSP.member')" + Writers: + Type: Signature + Rule: "OR('OrdererMSP.member')" + Admins: + Type: Signature + Rule: "OR('OrdererMSP.admin')" + OrdererEndpoints: + - "orderer0.example.com:7050" + - "orderer1.example.com:7050" + - "orderer2.example.com:7050" + + - &Org1 + Name: Org1MSP + SkipAsForeign: false + ID: Org1MSP + MSPDir: msp + Policies: + Readers: + Type: Signature + Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')" + Writers: + Type: Signature + Rule: "OR('Org1MSP.admin', 'Org1MSP.client')" + Admins: + Type: Signature + Rule: "OR('Org1MSP.admin')" + Endorsement: + Type: Signature + Rule: "OR('Org1MSP.member')" + AnchorPeers: + - Host: peer0.org1.example.com + Port: 7051 + - &Org2 + Name: Org2MSP + SkipAsForeign: false + ID: Org2MSP + MSPDir: msp + Policies: + Readers: + Type: Signature + Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')" + Writers: + Type: Signature + Rule: "OR('Org2MSP.admin', 'Org2MSP.client')" + Admins: + Type: Signature + Rule: "OR('Org2MSP.admin')" + Endorsement: + Type: Signature + Rule: "OR('Org2MSP.member')" + AnchorPeers: + - Host: peer0.org2.example.com + Port: 7051 +Capabilities: + Channel: &ChannelCapabilities + V2_0: true + Orderer: &OrdererCapabilities + V2_0: true + Application: &ApplicationCapabilities + V2_0: true +Application: &ApplicationDefaults + ACLs: &ACLsDefault + _lifecycle/CommitChaincodeDefinition: /Channel/Application/Writers + _lifecycle/QueryChaincodeDefinition: /Channel/Application/Readers + _lifecycle/QueryNamespaceDefinitions: /Channel/Application/Readers + lscc/ChaincodeExists: /Channel/Application/Readers + lscc/GetDeploymentSpec: /Channel/Application/Readers + lscc/GetChaincodeData: /Channel/Application/Readers + lscc/GetInstantiatedChaincodes: /Channel/Application/Readers + qscc/GetChainInfo: /Channel/Application/Readers + qscc/GetBlockByNumber: /Channel/Application/Readers + qscc/GetBlockByHash: /Channel/Application/Readers + qscc/GetTransactionByID: /Channel/Application/Readers + qscc/GetBlockByTxID: /Channel/Application/Readers + cscc/GetConfigBlock: /Channel/Application/Readers + peer/Propose: /Channel/Application/Writers + peer/ChaincodeToChaincode: /Channel/Application/Readers + event/Block: /Channel/Application/Readers + event/FilteredBlock: /Channel/Application/Readers + Organizations: + Policies: + LifecycleEndorsement: + Type: ImplicitMeta + Rule: "MAJORITY Endorsement" + Endorsement: + Type: ImplicitMeta + Rule: "MAJORITY Endorsement" + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + Capabilities: + <<: *ApplicationCapabilities +Orderer: &OrdererDefaults + OrdererType: etcdraft + Addresses: + - orderer0.example.com:7050 + - orderer1.example.com:7050 + - orderer2.example.com:7050 + BatchTimeout: 2s + BatchSize: + MaxMessageCount: 500 + AbsoluteMaxBytes: 10 MB + PreferredMaxBytes: 2 MB + MaxChannels: 0 + EtcdRaft: + Consenters: + - Host: orderer0.example.com + Port: 7050 + ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer0.example.com/tls/server.crt + ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer0.example.com/tls/server.crt + - Host: orderer1.example.com + Port: 7050 + ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt + ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer1.example.com/tls/server.crt + - Host: orderer2.example.com + Port: 7050 + ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt + ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/server.crt + Options: + TickInterval: 500ms + ElectionTick: 10 + HeartbeatTick: 1 + MaxInflightBlocks: 5 + SnapshotIntervalSize: 16 MB + Organizations: + Policies: + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + BlockValidation: + Type: ImplicitMeta + Rule: "ANY Writers" + Capabilities: + <<: *OrdererCapabilities +Channel: &ChannelDefaults + Policies: + Readers: + Type: ImplicitMeta + Rule: "ANY Readers" + Writers: + Type: ImplicitMeta + Rule: "ANY Writers" + Admins: + Type: ImplicitMeta + Rule: "MAJORITY Admins" + Capabilities: + <<: *ChannelCapabilities +``` + +该配置文件中定义了两个模板:TwoOrgsOrdererGenesis 和 TwoOrgsChannel,其中前者定义了系统通道配置,可以用来创建系统通道所需初始区块文件;后者定义了应用通道配置,可以用来新建应用通道。排序服务的共识类型采用了 Raft 模式。 + +可通过如下命令指定使用 configtx.yaml 文件中定义的 TwoOrgsOrdererGenesis 模板,来生成系统通道的初始区块文件: + +```bash +$ export SYS_CHANNEL=testchainid +$ export ORDERER_GENESIS_PROFILE=TwoOrgsOrdererGenesis +$ export ORDERER_GENESIS=orderer.genesis.block +$ configtxgen \ + -configPath ./ \ + -channelID ${SYS_CHANNEL} \ + -profile ${ORDERER_GENESIS_PROFILE} \ + -outputBlock ${ORDERER_GENESIS} +``` + +将所生成的初始区块文件复制到排序节点上 ORDERER_GENERAL_BOOTSTRAPFILE 指定路径(默认为 /etc/hyperledger/fabric)下,供启动排序节点使用。 + +#### 生成新建应用通道配置交易 + +新建应用通道需要先生成配置交易文件,其中包括了属于该通道的组织结构信息,这些信息会写入到该应用通道的初始区块中。 + +同样使用 configtx.yaml 配置文件和 configtxgen 工具,注意这里使用 TwoOrgsChannel 模板。 + +采用如下命令来生成配置交易文件,通道中包括两个初始成员:Org1 和 Org2: + +```bash +$ export APP_CHANNEL=businesschannel +$ export APP_CHANNEL_PROFILE=TwoOrgsChannel +$ configtxgen \ + -configPath ./ \ + -channelID ${APP_CHANNEL} \ + -profile ${APP_CHANNEL_PROFILE} \ + -outputCreateChannelTx ${APP_CHANNEL}.tx +``` + +所生成的配置交易文件在后续步骤被客户端所使用,需要复制到客户端节点上。 + +*注:状态数据库如果选择 CouchDB 类型,应用通道名称只能包括小写的 ASCII 字符、点或中划线,并且首字符必须为字母,总长度不超过 249 个字符。该限制详情可参考 FAB-2487。* + +#### 生成锚节点配置更新文件 + +锚节点用来辅助通道内多个组织之间的节点发现,修改锚节点需要发送更新通道配置交易。 + +同样,基于 configtx.yaml 配置文件,为每个组织都生成配置交易文件,注意需要需要使用对应的组织身份: + +```bash +$ export UPDATE_ANCHOR_ORG1_TX=Org1MSPanchors.tx +$ export UPDATE_ANCHOR_ORG2_TX=Org2MSPanchors.tx +$ configtxgen \ + -configPath ./ \ + -channelID ${APP_CHANNEL} \ + -profile ${APP_CHANNEL_PROFILE} \ + -asOrg Org1MSP \ + -outputAnchorPeersUpdate ${UPDATE_ANCHOR_ORG1_TX} +$ configtxgen \ + -configPath ./ \ + -channelID ${APP_CHANNEL} \ + -profile ${APP_CHANNEL_PROFILE} \ + -asOrg Org2MSP \ + -outputAnchorPeersUpdate ${UPDATE_ANCHOR_ORG1_TX} +``` + +所生成的锚节点配置更新文件会在后续步骤被客户端所使用,因此需要复制到客户端节点上。 + +所有配置文件都准备完毕后,即可启动网络。首先要启动 Orderer 节点,然后启动 Peer 节点。 + +### 启动 Orderer 节点 + +首先,检查配置路径( 默认为 `/etc/hyperledger/fabric` )下相关文件是否就绪: + +* 配置文件 orderer.yaml(可参考 sampleconfig/orderer.yaml),指定了节点相关配置; +* 生成的 msp 文件目录、tls 文件目录,存放身份信息; +* 系统通道的初始区块文件文件,用来启动系统通道。 + +排序节点自身配置可通过配置文件或环境变量方式指定,部分常见配置如下表所示。 + +配置(以环境变量为例) | 功能 | 说明 +-- | -- | -- +FABRIC_LOGGING_SPEC="info:orderer.common.blockcutter,orderer.operations=warning:orderer.common.cluster=debug" | 输出日志的级别 | 建议至少为 INFO。可按模块指定,用冒号分割 +ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 | 服务监听的地址 | 建议指定网络地址 +ORDERER_GENERAL_LISTENPORT=7050 | 服务监听的端口 | 默认为 7050 +ORDERER_GENERAL_BOOTSTRAPMETHOD=file | 初始区块的提供方式 | 推荐采用文件方式提供 +ORDERER_GENERAL_BOOTSTRAPFILE=/etc/hyperledger/fabric/orderer.genesis.block | 启动区块文件路径 | 提前使用 configtxgen 生成 +ORDERER_GENERAL_LOCALMSPID=OrdererMSP | MSP 的 ID | 建议根据实际情况更新 +ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/fabric/msp | MSP 文件路径 | cryptogen 提前生成,需要跟实际路径一致 +ORDERER_GENERAL_LEDGERTYPE=file | 账本类型 | 建议使用 file 支持持久化 +ORDERER_GENERAL_TLS_ENABLED=true | 是否启用 TLS | 建议开启,提高安全 +ORDERER_GENERAL_TLS_PRIVATEKEY=/etc/hyperledger/fabric/tls/server.key | TLS 开启时指定签名私钥位置 | cryptogen 提前生成,需要跟实际路径一致 +ORDERER_GENERAL_TLS_CERTIFICATE=/etc/hyperledger/fabric/tls/server.crt| TLS 开启时指定身份证书位置 | cryptogen 提前生成,需要跟实际路径一致 +ORDERER_GENERAL_TLS_ROOTCAS=[/etc/hyperledger/fabric/tls/ca.crt] | TLS 开启时指定信任的根 CA 证书位置 | cryptogen 提前生成,需要跟实际路径一致 +ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key |与其它排序节点进行双向 TLS 认证时的客户端私钥| 仅在 Raft 模式下使用 +ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt |与其它排序节点进行双向 TLS 认证时的客户端证书| 仅在 Raft 模式下使用 +ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] |与其它排序节点进行双向 TLS 认证时的信任的服务端的根证书| 仅在 Raft 模式下使用 +CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:8443 | 运营管理 REST 服务的监听地址 | 推荐开启,方便监控 +CORE_METRICS_PROVIDER=prometheus | 开启统计功能后,指定的采集器机制 | statsd、prometheus 或 disabled + +之后,用户可以采用如下命令来启动 Orderer 节点。启动成功后可以看到本地输出的开始提供服务的消息,此时 Orderer 采用指定的初始区块文件成功创建了系统通道: + +```bash +$ orderer start +[orderer/common/server] prettyPrintStruct -> INFO 002 Orderer config values: + General.LedgerType = "file" + General.ListenAddress = "0.0.0.0" + General.ListenPort = 7050 + General.TLS.Enabled = true +... +[orderer/common/server] Start -> INFO 007 Beginning to serve requests +... +``` + +### 启动 Peer 节点 + +首先,检查配置路径( 默认为 `/etc/hyperledger/fabric` )下相关文件是否就绪: + +* 配置文件 core.yaml(可以参考 sampleconfig/core.yaml),指定了节点相关配置; +* 生成的 msp 文件目录、tls 文件目录,存放身份信息。 + +Peer 节点的配置可通过配置文件或环境变量方式进行指定,场景设置如下表所示。 + +配置(以环境变量为例) | 功能 | 说明 +-- | -- | -- +FABRIC_LOGGING_SPEC="info:msp,gossip=warning:chaincode=debug" | 输出日志的级别 | 建议至少为 INFO。可按模块指定,用冒号分割 +CORE_PEER_ID=peer0.org1.example.com | Peer 的 ID | 不同节点分别指定唯一的 ID +CORE_PEER_LISTENADDRESS=0.0.0.0:7051 | 本地监听服务地址 | 可指定只从某网络地址监听 +CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051 | 对组织外节点发布的地址 | 不同节点分别指定,不指定则组织外节点无法连接到该节点 +CORE_PEER_GOSSIP_USELEADERELECTION=true | 是否自动选举代表节点 | 建议开启 +CORE_PEER_GOSSIP_ORGLEADER= false | 是否作为组织代表节点从排序服务拉取区块 | 建议关闭,进行自动选举 +CORE_PEER_LOCALMSPID=Org1MSP | 所属组织 MSP 的 ID | 不同节点分别指定,根据实际情况更新 +CORE_PEER_MSPCONFIGPATH=msp | msp 文件所在的相对路径 | cryptogen 提前生成,需要跟实际路径一致 +CORE_VM_ENDPOINT=unix:///var/run/docker.sock | Docker 服务地址 | 根据实际情况配置 +CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=host | 链码容器使用的网络方式 | 如果进行配置,需要跟 Peer 在同一个网络上,以进行通信 +CORE_PEER_TLS_ENABLED=true | 是否启用服务端的 TLS | 建议开启,提高安全 +CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt | TLS 开启时指定服务端身份证书位置 | cryptogen 提前生成,需要跟实际路径一致 +CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key | TLS 开启时指定服务端签名私钥位置 | cryptogen 提前生成,需要跟实际路径一致 +CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt | TLS 开启时指定信任的服务端根 CA 证书位置 | cryptogen 提前生成,需要跟实际路径一致 +CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:9443 | 运营管理 REST 服务的监听地址 | 推荐开启,方便监控 +CORE_METRICS_PROVIDER=prometheus | 开启统计功能后,指定的采集器机制 | statsd、prometheus 或 disabled + +配置完成后,用户可以采用如下命令在多个服务器上分别启动 Peer 服务,启动成功后可以看到本地输出的日志消息: + +```bash +$ peer node start +UTC [ledgermgmt] initialize -> INFO 002 Starting peer: + Version: 2.0.0 + Commit SHA: development build + Go version: go1.13.4 + OS/Arch: linux/amd64 + Chaincode: + Base Docker Namespace: hyperledger + Base Docker Label: org.hyperledger.fabric + Docker Namespace: hyperledger" +... +UTC [nodeCmd] serve -> INFO 01e Started peer with ID=[name:"peer0.org1.example.com" ], network ID=[dev], address=[peer0.org1.example.com:7051] +... +``` + +此时,Peer 节点已经启动起来,会尝试通过 gossip 发现邻居节点。 + +### 创建通道 + +Peer 节点启动后,由于尚未跟 Orderer 建立连接,暂时还未加入网络中的应用通道。 + +下面在客户端发送请求给 Orderer 创建应用通道,并让 Peer 节点加入到通道中。 + +默认情况下,只有联盟中成员组织的管理员身份才可以创建应用通道。例如使用 Org1 的管理员身份来创建新的应用通道,需要指定 msp 的 ID、msp 文件所在路径、排序服务地址、应用通道名称和新建通道交易文件,如果启用了 TLS,还需要指定排序服务的 TLSCA 的证书位置: + +```bash +$ APP_CHANNEL=businesschannel +$ TIMEOUT=30 +$ CORE_PEER_LOCALMSPID="Org1MSP" \ + CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp \ + peer channel create \ + -o orderer.example.com:7050 \ + -c ${APP_CHANNEL} \ + -f ./$APP_CHANNEL.tx \ + --timeout "${TIMEOUT}s" \ + --tls \ + --cafile /etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem +``` + +通道创建成功后,会在本地生成其初始区块文件(businesschannel.block),其中带有通道的初始配置信息和排序服务信息等。只有拥有该文件的 Peer 节点才可能加入到对应的通道中。 + +### 加入通道 + +应用通道的成员组织的 Peer 都可以加入到通道中。 + +在客户端使用管理员身份依次让组织 Org1 和 Org2 中所有节点都加入新的应用通道。操作需要指定所操作的 Peer 的地址,以及通道的初始区块。 + +以 Org1 中的 peer0 节点为例,可以执行如下操作: + +```bash +$ CORE_PEER_LOCALMSPID="Org1MSP" \ + CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp \ + CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \ + peer channel join \ + -b ${APP_CHANNEL}.block + +Peer joined the channel! +``` + +此时,所操作的 Peer(如果成为组织的 Gossip Leader)会自动连接到应用通道指定的排序服务,开始接收区块。 + +### 更新锚节点配置 + +锚节点(作为组织内成员代表)负责跟其它组织节点进行信息交换。通道配置内会记录各组织的锚节点列表信息,Peer 通过访问其他组织的锚节点来获取其他组织内的 Peer 信息。 + +使用锚节点配置更新文件,组织管理员可以更新通道中相关配置。 + +例如,在客户端使用 Org1 的管理员身份来更新锚节点,如下所示: + +```bash +$ CORE_PEER_LOCALMSPID="Org1MSP" \ + CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp \ + peer channel update \ + -o orderer.example.com:7050 \ + -c ${APP_CHANNEL} \ + -f ${UPDATE_ANCHOR_ORG1_TX} \ + --tls \ + --cafile /etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem +``` + +锚节点配置更新后,同一通道内不同组织之间的 Peer 也可以进行 Gossip 通信,共同维护通道账本。后续,用户可以在通道内通过智能合约更新账本记录。 diff --git a/chainbrock-learning/09_fabric_deploy/summary.md b/chainbrock-learning/09_fabric_deploy/summary.md new file mode 100644 index 00000000..0bc2b4f4 --- /dev/null +++ b/chainbrock-learning/09_fabric_deploy/summary.md @@ -0,0 +1,5 @@ +## 本章小结 + +本章详细讲解了 Fabric 网络生成和启动的主要步骤,包括如何本地编译、安装并进行各种组件的配置,以及如何启动 Fabric 网络。同时,还介绍了如何对通道进行操作并让 Peer 加入到通道。生产环境中推荐通过容器方式来启动和管理网络。 + +通过本章内容的学习和实践,相信读者可以掌握部署 Fabric 网络的步骤,同时也对 Fabric 网络的主要功能特别是通道有了初步了解。后续章节将介绍更多的网络操作,包括智能合约和网络管理等。 diff --git a/chainbrock-learning/10_fabric_op/README.md b/chainbrock-learning/10_fabric_op/README.md new file mode 100644 index 00000000..8088f3b9 --- /dev/null +++ b/chainbrock-learning/10_fabric_op/README.md @@ -0,0 +1,5 @@ +# 操作 Fabric 网络 + +** 万事万物皆系统。可观,然后可以控。 ** + +本章将讲解使用和管理 Fabric 网络的常见操作,包括管理通道、链码等资源,利用事件监听和网络发现来提高使用效率等,还介绍了 SDK 项目,运维和升级网络的操作。最后,本章探讨了生产环境部署管理的注意事项。 diff --git a/chainbrock-learning/10_fabric_op/_images/ChaincodeInvocationSpec.png b/chainbrock-learning/10_fabric_op/_images/ChaincodeInvocationSpec.png new file mode 100644 index 00000000..f81af2e6 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/ChaincodeInvocationSpec.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_install_flow.png b/chainbrock-learning/10_fabric_op/_images/chaincode_install_flow.png new file mode 100644 index 00000000..35fbb7b6 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_install_flow.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_install_structure.png b/chainbrock-learning/10_fabric_op/_images/chaincode_install_structure.png new file mode 100644 index 00000000..72fb4292 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_install_structure.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_instantiate_Envelope.png b/chainbrock-learning/10_fabric_op/_images/chaincode_instantiate_Envelope.png new file mode 100644 index 00000000..2f4cf778 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_instantiate_Envelope.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_instantiate_flow.png b/chainbrock-learning/10_fabric_op/_images/chaincode_instantiate_flow.png new file mode 100644 index 00000000..23b33c3e Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_instantiate_flow.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_instantiate_signedproposal.png b/chainbrock-learning/10_fabric_op/_images/chaincode_instantiate_signedproposal.png new file mode 100644 index 00000000..c579a17f Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_instantiate_signedproposal.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_invoke_Envelope.png b/chainbrock-learning/10_fabric_op/_images/chaincode_invoke_Envelope.png new file mode 100644 index 00000000..125320b7 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_invoke_Envelope.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_invoke_flow.png b/chainbrock-learning/10_fabric_op/_images/chaincode_invoke_flow.png new file mode 100644 index 00000000..1d0305af Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_invoke_flow.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_invoke_signedproposal.png b/chainbrock-learning/10_fabric_op/_images/chaincode_invoke_signedproposal.png new file mode 100644 index 00000000..54d0a90e Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_invoke_signedproposal.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_lifecycle.png b/chainbrock-learning/10_fabric_op/_images/chaincode_lifecycle.png new file mode 100644 index 00000000..4d8c1f35 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_lifecycle.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_list_flow.png b/chainbrock-learning/10_fabric_op/_images/chaincode_list_flow.png new file mode 100644 index 00000000..031abf52 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_list_flow.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_package_Envelope.png b/chainbrock-learning/10_fabric_op/_images/chaincode_package_Envelope.png new file mode 100644 index 00000000..43deb335 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_package_Envelope.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/chaincode_upgrade_flow.png b/chainbrock-learning/10_fabric_op/_images/chaincode_upgrade_flow.png new file mode 100644 index 00000000..5ba55f1b Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/chaincode_upgrade_flow.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_create_flow.png b/chainbrock-learning/10_fabric_op/_images/channel_create_flow.png new file mode 100644 index 00000000..108000a2 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_create_flow.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_create_tx.png b/chainbrock-learning/10_fabric_op/_images/channel_create_tx.png new file mode 100644 index 00000000..28102ce7 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_create_tx.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_fetch_envelope.png b/chainbrock-learning/10_fabric_op/_images/channel_fetch_envelope.png new file mode 100644 index 00000000..c87d3027 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_fetch_envelope.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_fetch_flow.png b/chainbrock-learning/10_fabric_op/_images/channel_fetch_flow.png new file mode 100644 index 00000000..d2b204f7 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_fetch_flow.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_getinfo_flow.png b/chainbrock-learning/10_fabric_op/_images/channel_getinfo_flow.png new file mode 100644 index 00000000..b1c16e24 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_getinfo_flow.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_getinfo_signed_proposal.png b/chainbrock-learning/10_fabric_op/_images/channel_getinfo_signed_proposal.png new file mode 100644 index 00000000..c830d0de Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_getinfo_signed_proposal.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_join_flow.png b/chainbrock-learning/10_fabric_op/_images/channel_join_flow.png new file mode 100644 index 00000000..701819eb Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_join_flow.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_join_signed_proposal.png b/chainbrock-learning/10_fabric_op/_images/channel_join_signed_proposal.png new file mode 100644 index 00000000..c3e101bd Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_join_signed_proposal.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_list_flow.png b/chainbrock-learning/10_fabric_op/_images/channel_list_flow.png new file mode 100644 index 00000000..672d9ec8 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_list_flow.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_list_signed_proposal.png b/chainbrock-learning/10_fabric_op/_images/channel_list_signed_proposal.png new file mode 100644 index 00000000..d13e0085 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_list_signed_proposal.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_update_flow.png b/chainbrock-learning/10_fabric_op/_images/channel_update_flow.png new file mode 100644 index 00000000..f699aba4 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_update_flow.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/channel_update_tx.png b/chainbrock-learning/10_fabric_op/_images/channel_update_tx.png new file mode 100644 index 00000000..05a36dd5 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/channel_update_tx.png differ diff --git a/chainbrock-learning/10_fabric_op/_images/prometheus.png b/chainbrock-learning/10_fabric_op/_images/prometheus.png new file mode 100644 index 00000000..b2e75246 Binary files /dev/null and b/chainbrock-learning/10_fabric_op/_images/prometheus.png differ diff --git a/chainbrock-learning/10_fabric_op/best_practice.md b/chainbrock-learning/10_fabric_op/best_practice.md new file mode 100644 index 00000000..a72e679c --- /dev/null +++ b/chainbrock-learning/10_fabric_op/best_practice.md @@ -0,0 +1,68 @@ +## 注意事项与最佳实践 + +区块链分布式结构的特点,使得其在管理上相对单点系统要复杂的多,需要从多个角度进行仔细考量和论证。这里总结一些在生产环境中使用 Fabric 网络需要注意的地方和最佳实践技巧。 + +### 节点角色差异 + +Fabric 网络中各个节点可以拥有不同的角色。不同角色的众多节点负责整个网络功能中不同环节的工作负载,呈现出了差异化的处理特性。 + +Ordering 服务需要排序整个网络中所有的交易消息,是全网的关键组件。Orderer 维护网络中所有通道的区块链结构,往往大量吞吐区块文件。因此,对于 Orderer 节点来讲需要加强网络(至少千兆网络)、存储和内存方面的配置,并且采用集群部署的方式提高其可靠性。 + +Peer 节点除了处理区块和背书交易(Endorser)之外,还需要对账本状态进行更新(Committer),对身份进行验证。同时,对于每个通道来说,加入通道的节点都需要维护一个针对该通道的账本结构(存放在数据库中)和区块链结构(存放在文件系统)。因此,Peer 节点需要加强CPU、内存、存储等资源配置,Endorser 还可以在签名处理方面进行加权。对于打开文件句柄较多的节点(如配置使用 CouchDB 作为状态数据库时),可能还需要对系统的 ulimit 等参数进行调整。 + +而对于链码容器来说,自身不需要维护太多状态信息,但是需要执行计算操作,因此需要提高较好的计算能力支持。 + +一般来讲,链码容器常常跟 Peer 节点在同一服务器上,建议为 Peer 服务预留 2 GB 以上的空闲内存,4 CPU 以上资源,并且一般每个链码容器分配 256 MB 运行内存和 1/10 的 CPU 核资源(根据链码逻辑进行调整)。 + +### 日志级别 + +日志级别越低,输出日志内容越详细,出现问题后方便进行调试。但输出过多日志会拖慢系统的吞吐性能,严重时甚至能降低几个数量级。 + +因此,在生产环境中必须要仔细调整日志级别。对于关键路径上的系统,通常要配置不低于 Warning 级别的日志输出;对于非关键路径上的系统,则可以采用不低于 Info 级别的日志输出。 + +Fabric 在日志级别上,支持对不同组件提供不同的级别。推荐将全局配置为 warning 级别,gRPC 组件由于需要处理大量交互消息,可以配置为更高的 error 级别。 + +如果要追踪区块链网络中的状态变化,可以通过事件监听等方式,降低对网络处理的压力。 + +### 链码升级 + +Fabric 目前已经支持了链码升级特性,升级时会调用链码中的 Init 方法。通过合适地设计链码,对其进行升级操作可以保护旧版本链码所关联的状态数据不被破坏。 + +但是注意目前升级操作并不需要整个网络的共识,因此对部分节点上链码版本升级后,未被升级的节点上仍然会运行旧版本的链码。 + +从数据一致性上考虑,在对某链码代码进行升级前,推荐先将所有该链码的容器停止,并从 Peer 上备份并移除旧链码部署文件。之后先在个别 Peer 节点上部署新链码,对原有数据进行测试,成功后再在其它节点上进行升级操作。 + +另外,在一开始编写链码过程中,就需要考虑链码升级操作,通过传入 Init 参数指定特定的升级方法来保护原有数据。 + +### 组织结构 + +组织代表了维护网络的独立成员身份。一般来说,组成联盟链的各个成员,每个都拥有代表自己身份的组织。一个组织可以进一步包括多个资源实体,这些资源实体彼此具有较强的信任度,并且对外都呈现为同一组织身份。 + +由于 Gossip 协议目前在 MSP 范围内进行传播,因此,一般建议将组织与 MSP 一一对应,即每个组织拥有自己专属的 MSP。当一个组织拥有多个 MSP 时,不同成员之间的交互可能会带来障碍;当多个组织同属于一个 MSP 时,可能会发生不希望的跨组织的数据泄露。 + +另外,一个组织可以包括多个成员身份,多个 Peer 可以通过使用同一成员身份来提高高可用性。 + +### 证书管理 + +Fabric 网络中,CA 负责证书的管理。用户虽然可以通过 cryptogen 工具提前分配好各组织的身份证书,但对于加入到网络中的用户,以及未来支持的交易证书,都需要 Fabric CA 来进行统一管理。 + +Fabric CA 占据网络中安全和隐私的最核心位置,因此需要加强安全方面的防护。CA 不应该暴露在公共网络域中,并且只能由有限个具备权限的用户可以访问。 + +另外,根证书往往要进行离线保护处理,减少接触和泄露的可能性。通常使用中间层证书来完成实体证书的签发。同时,绝对不能直接用根证书作为组织管理员的身份证书。 + +### 账本备份和裁剪 + +目前,Fabric 自身并未考虑对账本结构的备份和裁剪操作。在生产环境中,需要用户自己进行处理。 + +一方面,推荐用户根据业务需求和吞吐量来估算所需磁盘的大小。一般的,在平均每秒百次 TPS、交易消息不太大情况下,每年大约产生 3 TB 左右数据。 + +账本文件一般位于默认的 /var/hyperledger/production 目录下,包括区块链结构(文件存储)和相关状态(数据库存储)。大部分操作只与数据库存储相关,因此,对于旧的区块链文件,可以考虑从本地移除,备份到容量更大的持久化存储中。当需要时,再从大容量存储中恢复到本地。 + +### 系统优化 + +区块链作为分布式系统,对系统的计算、网络、存储等资源都有所需求,优化的系统配置可以有效提高资源效率。 + +例如,可以调整系统缓存策略、允许打开的文件句柄数、调整 TCP 连接超时时间等网络参数等。如果使用容器,还可以调整容器的资源限额和访问权限等。 + +此外,对于第三方软件也应该根据对应文档进行调整和优化。例如使用 Kafka 共识机制,在 Kafka 2.0 版本默认保留日志时间为 7 天,应当调整为更长,但同时注意要预留足够的系统存储空间。 + diff --git a/chainbrock-learning/10_fabric_op/chaincode.md b/chainbrock-learning/10_fabric_op/chaincode.md new file mode 100644 index 00000000..95496ddd --- /dev/null +++ b/chainbrock-learning/10_fabric_op/chaincode.md @@ -0,0 +1,467 @@ +## 管理链上代码 + +链上代码(Chaincode),简称链码,一般指的是用户编写的用来实现智能合约的应用代码。 + +链码被部署在 Peer 节点上,运行在独立的沙盒(目前为 Docker 容器)中,并通过 gRPC 协议来与相应的 Peer 节点进行交互。链码被调用时,会按照预定逻辑根据当前账本状态来计算对账本的更新(读写集合)。 + +启动 Fabric 网络后,可以通过命令行或 SDK 进行链码调用。 + +*注:用户链码有别于系统链码(System Chaincode)。系统链码指的是 Fabric Peer 中负责系统配置、背书、验证等平台功能的代码逻辑,运行在 Peer 进程内,将在后续章节予以介绍。* + +### 客户端链码操作命令 + +用户可以通过命令行方式来管理链码,支持的链码子命令包括 install、instantiate、invoke、query、upgrade、list、package、signpackage 等。大部分命令(除了 package、signpackage 外)的处理过程都是类似的,创建签名提案消息,发给 Peer 进行背书,获取 ProposalResponse 消息。 + +特别地,instantiate、invoke、upgrade 等子命令还需要根据 ProposalResponse 消息创建交易,发送给 Orderer 进行排序后被全网接受。package、signpackage 子命令作为本地操作,无需跟 Peer 或 Orderer 打交道。 + +各个命令的功能总结如下表所示: + +命令 | 发往组件 | 功能 +-- | -- | -- +install | Peer 节点 | 将链码信息打包并安装到 Peer +query | Peer 节点 | 查询链码 +list | Peer 节点 | 列出链码信息,包括某个 Peer 上安装过的链码或通道内实例化过的链码 +instantiate | Peer 节点和排序服务 | 在通道中实例化链码 +invoke | Peer 节点和排序服务 | 调用链码 +upgrade | Peer 节点和排序服务 | 升级链码 +package | 本地操作 | 打包本地链码为部署 Spec 包 +signpackage | 本地操作 | 为给定链码包添加签名 + +可以通过 `peer chaincode --help` 来查看具体的命令使用说明。 + +这些操作管理了链码的整个生命周期,如下图所示。 + +![链码生命周期](_images/chaincode_lifecycle.png) + +首先,用户需要将链码安装到 Peer 节点,之后可以在 Peer 所属的某个通道内实例化链码容器。此时链码处于运行状态,应用可以通过 invoke 或 query 来调用链码。链码在一定时间(环境变量 CRC_MAX_IDLE_TIME 指定)内不被调用会处于空闲状态,自动被停止删除;如果被调用则重新实例化。此外,用户还可以升级链码到新的版本。 + +后面将以 Fabric 项目中自带的 Go 语言 example02 链码(路径在 examples/chaincode/go/chaincode_example02)为例进行相关命令讲解。 + +### 命令选项 + +链码操作支持如下全局命令选项,对应的功能如下表所示。 + +全局选项 | 类型 | 含义 +--- | --- | --- +--connTimeout | int | 客户端连接超时,默认为 3 秒 +--keyfile | string | 与排序服务双向 TLS 认证时使用的私钥文件 +-o, --orderer | string | Orderer 服务地址 +--transient | string | JSON 格式的临时数据,仅供 Peer 在背书环节使用 +--tls | bool | 连接到 Orderer 服务时是否启用 TLS +--cafile | string | 信任的排序服务的 TLSCA 证书,PEM 编码格式 +--certfile | string | 与排序服务双向 TLS 认证时使用的证书文件 +--clientauth | bool | 与排序服务通信时是否启用双向 TLS 认证 +--ordererTLSHostnameOverride | string | 验证 Orderer TLS 时候覆盖所校验的主机名 + +此外,不同子命令还可能支持一些子选项,如下表所示。 + +子命令选项 | 类型 | 含义 +--- | --- | --- +--connectionProfile | string | 指定连接配置(Connection Profile)文件 +-C, --chainID | string | 所面向的通道,默认为 "testchainid" +-c, --ctor | string | 指定链码命令的参数信息,Json 格式,默认为 "{}" +-E, --escc | string | 指定所用背书系统链码的名称,默认为 "escc" +-l, --lang | string | 链码实现语言,默认为 "golang" +-n, --name | string | 链码名称 +--peerAddresses | string list | Peer 节点地址,可以指定多个 +-o, --orderer | string | 排序服务地址 +--tlsRootCertFiles | string list | 采用 TLS 时,信任的 Peer 的根证书列表,需要跟 Peer 节点地址列表给出的顺序一致 +-p, --path | string | 所操作链码的本地路径,如果是 Go 语言为包路径(相对于 $GOPAH/src),如果是其它语言则为绝对路径 +-P, --policy | string | 链码所关联的背书策略,例如 -P "OR ('Org1MSP.member','Org2MSP.member')" +-t, --tid | string | ChaincodeInvocationSpec 中的 ID 生成算法和编码,目前支持默认的 sha256+base64 +-v, --version | string | install/instantiate/upgrade 等命令中指定的版本信息 +-V, --vscc | string | 指定所使用验证系统链码的名称,默认为 "vscc" + +注意,不同子命令具体支持不同的参数,总结如下表所示。 + +命令 |-C 通道| -c cc 参数| -E escc | -l 语言 | -n 名称 | -o Orderer | -p 路径 | -P policy | -v 版本 | -V vscc | +-- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | +install |不支持| 支持 |不支持 | 支持 |必需|不支持|必需|不支持| 必需 | 不支持 | +instantiate|必需| 必需 |支持 | 支持 |必需|支持|不支持|支持|必需 | 支持 | +invoke |支持| 必需 |不支持 | 支持 |必需|支持|不支持|不支持|不支持|不支持 | +query |支持| 必需 |不支持 | 支持 |必需|不支持|不支持|不支持|不支持|不支持 | +upgrade |必需| 必需 |支持 | 支持 |必需|支持|不支持|支持| 必需| 支持 | +list |支持| 不支持 |不支持 | 不支持 |不支持|不支持|不支持|不支持|不支持|不支持 | +package |不支持| 支持 |不支持 | 支持 |必需|不支持|必需|不支持|必需 | 不支持| +signpackage |不支持| 支持 |不支持 | 支持 |必需|不支持|必需|不支持|必需 | 不支持| + +其中,必需、支持和不支持三种情况的含义为: + +* 必需:该参数必需被指定,包括通过命令行、环境变量、配置等。 +* 支持:该参数可以被使用。某些时候如果不指定,可能采取默认值或自动获取。 +* 不支持:该参数不应该使用。 + +### 安装链码 +install 命令将链码的源码和环境等内容封装为一个链码安装打包文件(Chaincode Install Package,CIP),并传输到指定的 Peer 节点。 + +此过程只需要跟 Peer 节点打交道,无需修改账本状态,并不产生交易。只有安装过链码的节点才能进行链码实例化和进行背书处理。默认情况下,执行者需要为该 Peer 节点的管理员角色。 + +例如,采用如下命令可以部署 test_cc.1.0 的链码打包文件到指定的 Peer 节点。 + +```bash +$ CORE_PEER_ADDRESS=peer.your_domain.com:7051 # 设置默认的 Peer 地址 +$ peer chaincode install \ + -n test_cc \ + -v 1.0 \ + -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 +``` + +Peer 节点收到请求,检查和解析后将 CIP 文件保存在 `${CORE_PEER_FILESYSTEMPATH}/chaincodes/` 目录下(一般以 cc_name.version 格式命名,如 /var/hyperledger/production/chaincodes/testcc.1.0),供后续操作(如重新创建和启动链码容器)使用。 + +CIP 文件中主要包括如下数据。 + +* `ChaincodeDeploymentSpec`:链码的源码和一些关联环境,如名称和版本。 +* 链码实例化策略,默认是任意通道上的 MSP 管理员身份均可。 +* 拥有这个链码的实体的证书和签名。 +* 安装时,添加本地 MSP 管理员的签名。 + +其中,ChaincodeDeploymentSpec(CDS)结构最为核心,主要包括 ChaincodeSpec(CS)数据结构(链码部署信息)和 CodePackage(链码源代码相关数据)。CDS 和 CS 结构同时也大量在其他链码命令(如实例化命令和升级命令)中使用。 + +链码安装的整体实现流程如下图所示。 + +![链码安装过程](_images/chaincode_install_flow.png) + +主要步骤包括: + +* 首先是构造带签名的提案结构(SignedProposal)。 + * 调用 `InitCmdFactory(isEndorserRequired, isOrdererRequired bool) (*ChaincodeCmdFactory, error)` 方法,初始化 EndoserClient(跟 Peer 通信)、BroadcastClient(跟 Orderer 通信)、Signer(签名操作)等辅助结构体。所有链码子命令都会执行该过程,会根据需求具体初始化不同的结构。 + * 然后根据命令行参数进行解析,判断是根据传入的打包文件来直接读取 ChaincodeDeploymentSpec(CDS)结构,还是根据传入参数从本地链码源代码文件来构造生成。 + * 以本地重新构造情况为例,首先根据命令行中传入的路径、名称等信息,构造生成 ChaincodeSpec(CS)结构。 + * 利用 ChaincodeSpec 结构,结合链码包数据生成一个 ChaincodeDeploymentSpec 结构(chainID 为空),调用本地的 `install(msg proto.Message, cf *ChaincodeCmdFactory) error` 方法。 + * install 方法基于传入的 ChaincodeDeploymentSpec 结构,构造一个对生命周期管理系统链码(LSCC)调用的 ChaincodeSpec 结构,其中,Type 为 ChaincodeSpec_GOLANG,ChaincodeId.Name 为“lscc”,Input 为 “install”+ChaincodeDeploymentSpec。进一步地,构造了一个 LSCC 的 ChaincodeInvocationSpec(CIS)结构,对 ChaincodeSpec 结构进行封装。 + * 基于 LSCC 的 ChaincodeInvocationSpec 结构,添加头部结构,生成一个提案(Proposal)结构。其中,通道头部中类型为 ENDORSER_TRANSACTION,TxID 为对随机数+签名实体,进行 Hash。 + * 对 Proposal 进行签名,转化为一个签名后的提案消息结构 SignedProposal。 +* 将带签名的提案结构通过 EndorserClient 经由 gRPC 通道发送给 Peer 的 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 接口。 +* Peer 模拟运行生命周期链码的调用交易进行处理,检查格式、签名和权限等,通过则保存到本地文件系统。 + +下图给出了链码安装过程中最为重要的 SignedProposal 数据结构,该结构对于大部分链码操作命令都是类似的,其中最重要的是 ChannelHeader 结构和 ChaincodeSpec 结构中参数的差异。 + +![链码安装过程中所涉及的数据结构](_images/chaincode_install_structure.png) + +### 实例化链码 +instantiate 命令通过构造生命周期管理系统链码(Lifecycle System Chaincode,LSCC)的交易,将安装过的链码在指定通道上进行实例化部署调用,在节点上创建容器启动,并执行初始化操作。实例化链码需要同时跟 Peer 和 Orderer 打交道。 + +执行 instantiate 命令的用户身份必须满足实例化的策略(默认为通道内 MSP 管理员角色),并且在所指定的通道上拥有写(Write)权限。在 instantiate 命令中可以通过 `-P` 参数指定链码调用的背书策略(Endorsement Policy),在 Commit 阶段会进行策略检查。 + +例如,如下命令会启动 test_cc.1.0 链码,会将参数 `'{"Args":["init","a","100","b","200"]}'` 传入链码中的 `Init()` 方法执行。命令会生成一笔交易,因此需指定排序节点地址。 + +```bash +$ APP_CHANNEL="businesschannel" # 设置默认的通道名称 +$ peer chaincode instantiate \ + -o orderer0:7050 \ + -C ${APP_CHANNEL} \ + -n test_cc \ + -v 1.0 \ + -c '{"Args":["init","a","100","b","200"]}' \ + -P "OR ('Org1MSP.member','Org2MSP.member')" \ + --collections-config collection.json \ + --tls \ + --cafile ${ORDERER_TLS_CA} +``` + +其中,collection.json 为私密账本(sideDB)特性中使用(Fabric v1.1.0 开始支持),可以实现在同一通道内实现私密数据局部共享。如果不指定该参数则默认不启用该特性,意味着通道内所有成员都可以看到链码调用结果。 + +collection.json 的一个示例如下所示。 + +```json +[ + { + "name": "public", // 集合名称 + "policy": "OR('Org1MSP.member', 'Org2MSP.member')", // 集合成员 + "requiredPeerCount": 1, // 至少扩散私密数据到几个节点 + "maxPeerCount": 3, // 最大扩散节点个数 + "blockToLive":99999, //私密数据存货时长 + "memberOnlyRead": true // 是否只允许集合的成员访问私密数据 +}, + { + "name": "private", + "policy": "OR('Org1MSP.member')", + "requiredPeerCount": 1, + "maxPeerCount": 3, + "blockToLive":3, + "memberOnlyRead": false + } +] +``` + +其中定义了 public 和 private 两个集合,分别包括两个组织和单个组织。当在链码逻辑中指定某个键值属于特定集合时,只有集合内成员能看到明文的读写集合,非集合成员即便在同一通道内也无法获取隐私数据。对应 policy 只支持 OR 语法,指定哪些组织可以看到隐私数据集合。 + +链码实例化实现的整体流程如下图所示。 + +![链码实例化过程](_images/chaincode_instantiate_flow.png) + +主要步骤包括: + +* 首先,类似链码安装命令,需要创建一个 SignedProposal 消息。注意 instantiate 和 upgrade 支持 policy、escc、vscc 等参数。LSCC 的 ChaincodeSpec 结构中,Input 中包括类型(“deploy”)、通道 ID、ChaincodeDeploymentSpec 结构、背书策略、escc 和 vscc 等。 +* 调用 EndorserClient,发送 gRPC 消息,将签名后的 Proposal 发给指定的 Peer 节点(Endorser),调用 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 方法,进行背书处理。节点会模拟运行 LSCC 的调用交易,启动链码容器。实例化成功后会返回 ProposalResponse 消息(其中包括背书签名)。 +* 根据 Peer 返回的 ProposalResponse 消息,创建一个 SignedTX(Envelop 结构的交易,带有签名)。 +* 使用 BroadcastClient 将交易消息通过 gRPC 通道发给 Orderer,Orderer 会进行全网排序,并广播给 Peer 进行确认提交。 + +其中,SignedProposal 结构如下图所示。 + +![链码实例化时的 SignedProposal 结构](_images/chaincode_instantiate_signedproposal.png) + +交易 Envelope 结构如下图所示。 + +![交易 Envelope 结构](_images/chaincode_instantiate_Envelope.png) + +Peer 返回的 ProposalResponse 消息定义如下。 + +```go +type ProposalResponse struct { + // 消息协议版本 + Version int32 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"` + // 消息创建时的时间戳 + Timestamp *google_protobuf1.Timestamp `protobuf:"bytes,2,opt,name=timestamp" json:"timestamp,omitempty"` + // 返回消息,包括状态、消息、元数据载荷等 + Response *Response `protobuf:"bytes,4,opt,name=response" json:"response,omitempty"` + // 数据载荷,包括提案的 Hash 值,和扩展的行动等 + Payload []byte `protobuf:"bytes,5,opt,name=payload,proto3" json:"payload,omitempty"` + // 背书信息列表,包括背书者的证书,以及其对“载荷+背书者证书”的签名 + Endorsement *Endorsement `protobuf:"bytes,6,opt,name=endorsement" json:"endorsement,omitempty"` +} +``` + +*注:目前命令行下的 instantiate 命令还不支持指定实例化策略,Peer 会采用默认的实例化策略(组织管理员身份)。* + +### 调用链码 + +通过 invoke 命令可以调用运行中的链码的方法。`-c` 参数指定的函数名和参数会被传入到链码的 Invoke() 方法进行处理。调用链码操作需要同时跟 Peer 和 Orderer 打交道。 + +例如,对部署成功的链码执行调用操作,由 `a` 向 `b` 转账 10 元。 + +在 peer0 容器中执行如下操作,注意验证最终结果状态正常 `response:`。 + +```bash +$ peer chaincode invoke \ + -o orderer0:7050 \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["invoke","a","b","10"]}' \ + --tls \ + --cafile ${ORDERER_TLS_CA} +``` + +这一命令会调用最新版本的 test_cc 链码,将参数 `'{"Args":["invoke","a","b","10"]}'` 传入链码中的 `Invoke()` 方法执行。命令会生成一笔交易,需指定排序者地址。 + +需要注意,invoke 命令不支持指定链码版本,默认调用最新版本的链码。 + +实现上,基本过程如下图所示。 + +![链码调用过程](_images/chaincode_invoke_flow.png) + +实现上,基本过程如下: + +* 首先,也是要创建一个 SignedProposal 消息。根据传入的各种参数,生成 ChaincodeSpec 结构(其中,Input 为传入的调用参数)。然后,根据 ChaincodeSpec、chainID、签名实体等,生成 ChaincodeInvocationSpec 结构。进而封装生成 Proposal 结构(通道头部中类型为 ENDORSER_TRANSACTION),并进行签名。 +* 调用 EndorserClient,发送 gRPC 消息,将签名后的 Proposal 发给指定的 Peer 节点(Endorser),调用 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 方法,进行背书处理。节点会模拟运行链码调用交易,成功后会返回 ProposalResponse 消息(带有背书签名)。 +* 根据 Peer 返回的 ProposalResponse 消息,创建一个 SignedTX(Envelop 结构的交易,带有签名)。 +* 调用 BroadcastClient 将交易消息通过 gRPC 通道发给 Orderer 进行全网排序并广播给 Peer 进行确认提交。 + +在此过程中,发给 Peer 节点的交易提案数据结构如下图所示。 + +![链码调用过程发给 Peer 节点的交易提案](_images/chaincode_invoke_signedproposal.png) + +发给排序服务的交易数据结构如下图所示。 + +![链码调用过程发给排序服务的交易结构](_images/chaincode_invoke_Envelope.png) + +注意 invoke 是异步操作,invoke 成功只能保证交易已经进入 Orderer 进行排序,但无法保证最终写到账本中(例如交易未通过 Committer 验证而被拒绝)。需要通过 eventHub 或查询方式来进行确认交易是否最终写入到账本上。 + +### 查询链码 + +查询链码可以通过 query 子命令。 + +该子命令实际上是 invoke 操作与 Peer 打交道的部分,即将签名后的 Proposal 发给指定的 Peer 节点的 ProcessProposal() gRPC 接口。最终将 `-c` 指定的命令参数发送给了链码中的 `Invoke()` 方法执行。 + +与 invoke 操作的区别在于,query 操作用来查询 Peer 上账本状态(需要链码支持查询逻辑),不生成交易,也不需要与 Orderer 打交道。 + +例如,执行如下命令会向 Peer 查询状态 `a` 的值,并返回查询结果。 + +```bash +$ peer chaincode query \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["query","a"]}' +``` + +在实例化链码容器后,可以在 peer0 容器中执行如下命令,注意输出无错误信息,最后的结果为初始值 `Query Result: 100`。 + +```bash +$ peer chaincode query \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["query","a"]}' +Query Result: 100 +[main] main -> INFO 001 Exiting..... +``` + +类似的,查询 `b` 的余额,注意最终返回结果为初始值 `Query Result: 200`。 + +```bash +$ peer chaincode query \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["query","b"]}' +Query Result: 200 +[main] main -> INFO 001 Exiting..... +``` + +在执行完 a 向 b 转账 10 的交易后,再次查询 `a` 和 `b` 的余额,发现发生变化。 + +`a` 的新余额为 90。 + +```bash +$ peer chaincode query \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["query","a"]}' +Query Result: 90 +[main] main -> INFO 001 Exiting..... +``` + +`b` 的新余额为 210。 + +```bash +$ peer chaincode query \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["query","b"]}' +Query Result: 210 +[main] main -> INFO 001 Exiting..... +``` + +query 的主要实现过程如下所示。 + +* 根据传入的各种参数,最终构造签名提案,通过 endorserClient 发送给指定的 Peer。 +* 成功的话,获取到 ProposalResponse,打印出 proposalResp.Response.Payload 内容。 + +注意 invoke 和 query 的区别,query 子命令会返回从 Peer 的查询结果,但不创建 SignedTx 发送到 Orderer。 + +### 升级链码 + +当需要修复链码漏洞或进行功能拓展时,可以对链码进行升级,部署新版本的链码。Fabric 支持在保留现有状态的前提下对链码进行升级。 + +假设某通道上正在运行中的链码为 test_cc,版本为 1.0,可以通过如下步骤进行升级操作。 + +首先,安装新版本的链码,打包到 Peer 节点。 + +```bash +$ peer chaincode install \ + -n test_cc \ + -v 1.1 \ + -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02_new +``` + +运行以下 upgrade 命令升级指定通道上的链码,需要指定相同的链码名称 test_cc。 + +```bash +$ peer chaincode upgrade \ + -o orderer0:7050 \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -v 1.1 \ + -c '{"Args":["re-init","c","60"]}' \ + -P "${policy}" \ + --collections-config "${collection_config}" \ + --tls \ + --cafile ${ORDERER_TLS_CA} +``` + +这一命令会在通道 test_cc 上实例化新版本链码 test_cc.1.1 并启动一个新容器。运行在其他通道上的旧版本的链码将不受影响。升级操作跟实例化操作十分类似,唯一区别在于不改变实例化的策略。这就保证了只有拥有实例化权限的用户才能进行升级操作。 + +升级过程会将给定的参数(如例子中的 `'{"Args":["re-init","c","60"]}'`)传入新链码的 `Init()` 方法中执行。只要 `Init()` 方法中对应的逻辑不改写状态,则升级前后链码的所有状态值可以保持不变。因此,如果链码将来要考虑在保留状态情况下升级,需要在编写 `Init()` 方法时妥善处理升级时的逻辑。 + +链码实例化实现的整体流程如下图所示,十分类似实例化过程。 + +![链码升级过程](_images/chaincode_upgrade_flow.png) + +* 首先,需要创建一个封装了 LSCC 调用交易的 SignedProposal 消息。注意 instantiate 和 upgrade 支持指定 policy、escc、vscc 等参数。LSCC 的 ChaincodeSpec 结构中,Input 中包括类型(“upgrade”)、通道 ID、ChaincodeDeploymentSpec 结构、背书策略、escc 和 vscc 等。 +* 调用 EndorserClient,发送 gRPC 消息,将签名后的 Proposal 发给指定的 Peer 节点(Endorser),调用 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 方法,进行背书处理。节点会模拟运行 LSCC 的调用交易,启动链码容器。实例化成功后会返回 ProposalResponse 消息(其中包括背书签名)。 +* 根据 Peer 返回的 ProposalResponse 消息,创建一个 SignedTX(Envelop 结构的交易,带有签名)。 +* 使用 BroadcastClient 将交易消息通过 gRPC 通道发给 Orderer,Orderer 会进行全网排序,并广播给 Peer 进行确认提交。 + +### 查询链码安装和实例化信息 + +list 子命令支持查询某个节点上已经安装的链码信息(--installed)或某个通道内已经实例化的链码信息(--instantiated)。请求发送到 Peer 节点,调用 LSCC 系统链码提供的接口进行查询。 + +例如,如下命令查询默认 Peer 上安装的链码情况,返回结果显示已安装链码 exp02 的 v1.0 版本。 + +```bash +$ peer chaincode list \ + --installed \ + +Get installed chaincodes on peer: +Name: exp02, Version: 1.0, Path: examples/chaincode/go/chaincode_example02, Id: 08ca675c39a8bae2631847a521fc92e12969fe122bd4a9df0a707cf1059e8730 +``` + +例如,如下命令查询通道 ${APP_CHANNEL} 内实例化的链码情况,返回结果显示已实例化链码 exp02 的 v1.0 版本。 + +```bash +$ peer chaincode list \ + --instantiated \ + -C ${APP_CHANNEL} + +Get instantiated chaincodes on channel businesschannel: +Name: exp02, Version: 1.0, Path: examples/chaincode/go/chaincode_example02, Escc: escc, Vscc: vscc +``` + +链码列出安装和实例化过程的实现流程如下图所示。 + +![链码列出安装和实例化过程](_images/chaincode_list_flow.png) + +* 首先,根据输入参数创建一个 LSCC 的链码调用规范。LSCC 的 ChaincodeSpec 结构中,Input 参数根据查询类型设置为 getinstalledchaincodes 或 getchaincodes。 +* 根据 LSCC 的链码调用规范封装为一个 Proposal 结构,头部类型为 ENDORSER_TRANSACTION,通道 ID 设置为空(查询安装信息)或给定的通道(查询实例化信息)。 +* 调用 EndorserClient,发送 gRPC 消息,将签名后的 Proposal 发给指定的 Peer 节点(Endorser),调用 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 方法,进行背书处理。节点会运行 LSCC 的相应逻辑,成功后会返回 ProposalResponse 消息。 +* 客户端解析 Peer 返回的 ProposalResponse 消息,如果成功则打印查询结果。 + +### 打包链码和签名 + +通过将链码相关的数据进行封装,可以实现对其进行打包和签名操作。 + +打包命令支持三个特定参数: + +* -s, --cc-package:表示创建完整打包格式,而不是仅打包 ChaincodeDeploymentSpec 结构。 +* -S, --sign:对打包的文件使用本地的 MSP(core.yaml 中的 localMspid 指定)进行签名。 +* -i --instantiate-policy string:指定实例化策略。可选参数。 + +例如,通过如下命令创建一个本地的打包文件 ccpack.out。 + +```bash +$ peer chaincode package \ + -n test_cc -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 \ + -v 1.0 \ + -s \ + -S \ + -i "AND('Org1.admin')" \ + ccpack.out +``` + +打包后的文件,也可以直接用于 install 操作,如 + +```bash +$ peer chaincode install ccpack.out +``` + +签名命令则对一个打包文件进行签名操作(添加当前 MSP 签名到签名列表中)。 + +```bash +$ peer chaincode signpackage ccpack.out signedccpack.out +``` + +其中,打包文件结构主要包括三部分的信息: + +* ChaincodeDeploymentSpec 结构; +* 实例化策略信息; +* 拥有者的签名列表。 + +实现的整体流程如下: + +* 首先会调用 `InitCmdFactory(isEndorserRequired, isOrdererRequired bool) (*ChaincodeCmdFactory, error)` 方法初始化 Signer 等结构。对于打包命令来说纯属本地操作,不需要 Endorser 和 Orderer 的连接。 +* 调用 getChaincodeSpec() 方法,解析命令行参数,根据所指定的数据生成 ChaincodeSpec 结构。 +* 根据 ChaincodeSpec 结构,结合链码相关数据构造 ChaincodeDeploymentSpec 结构,并传入 getChaincodeInstallPackage 方法。 +* getChaincodeInstallPackage 方法基于传入的 ChaincodeDeploymentSpec 结构,添加实例化策略和签名信息等,生成一个 SignedChaincodeDeploymentSpec,并进一步作为 Data 生成一个 Envelope 结构,其中 ChannelHeader 指定为 CHAINCODE_PACKAGE。 +* 将 Envelope 结构序列化,写到指定的本地文件。 + +其中,Envelope 结构如下图所示。 + +![打包过程中的 Envelope 结构](_images/chaincode_package_Envelope.png) diff --git a/chainbrock-learning/10_fabric_op/chaincode_v2.md b/chainbrock-learning/10_fabric_op/chaincode_v2.md new file mode 100644 index 00000000..74646eca --- /dev/null +++ b/chainbrock-learning/10_fabric_op/chaincode_v2.md @@ -0,0 +1,465 @@ +## 管理链上代码 + +链上代码(Chaincode),简称链码,一般指的是用户编写的用来实现智能合约的应用代码。 + +链码被部署在 Peer 节点上,运行在独立的沙盒(目前为 Docker 容器)中,并通过 gRPC 协议来与相应的 Peer 节点进行交互。链码被调用时,会按照预定逻辑根据当前账本状态来计算对账本的更新(读写集合)。 + +启动 Fabric 网络后,可以通过命令行或 SDK 进行链码调用。 + +*注:用户链码有别于系统链码(System Chaincode)。系统链码指的是 Fabric Peer 中负责系统配置、查询、背书、验证等平台功能的代码逻辑,运行在 Peer 进程内,将在后续章节予以介绍。* + +### 客户端链码操作命令 + +用户可以通过命令行方式来管理链码。自 2.0 开始正式使用新的 peer lifecycle chaincode 命令来维护链码的生命周期,所支持的链码子命令包括 package(打包)、install(安装)、queryinstalled(查询已安装)、approveformyorg(批准提交)、commit(提交)、querycommitted(查询已提交)。原有的 peer chaincode 系列命令仍然支持。 + +各个命令的功能总结如下表所示: + +命令 | 发往组件 | 功能 +-- | -- | -- +package | 本地操作 | 打包本地链码为部署 Spec 包 +install | Peer 节点 | 将链码信息打包并安装到 Peer +list | Peer 节点 | 列出链码信息,包括某个 Peer 上安装过的链码或通道内实例化过的链码 +instantiate | Peer 节点和排序服务 | 在通道中实例化链码 +invoke | Peer 节点和排序服务 | 调用链码 +upgrade | Peer 节点和排序服务 | 升级链码 +query | Peer 节点 | 查询链码 + +可以通过 `peer chaincode --help` 来查看具体的命令使用说明。 + +这些操作管理了链码的整个生命周期,如下图所示。 + +![链码生命周期](_images/chaincode_lifecycle.png) + +首先,用户需要将链码安装到 Peer 节点,之后可以在 Peer 所属的某个通道内实例化链码容器。此时链码处于运行状态,应用可以通过 invoke 或 query 来调用链码。链码在一定时间(环境变量 CRC_MAX_IDLE_TIME 指定)内不被调用会处于空闲状态,自动被停止删除;如果被调用则重新实例化。此外,用户还可以升级链码到新的版本。 + +后面将以 Fabric 项目中自带的 Go 语言 example02 链码(路径在 examples/chaincode/go/chaincode_example02)为例进行相关命令讲解。 + +*说明:这些命令的实现位于 `github.com/hyperledger/fabric/internal/peer/lifecycle`。* + +### 命令选项 + +链码操作支持如下全局命令选项,对应的功能如下表所示。 + +全局选项 | 类型 | 含义 +--- | --- | --- +--cafile | string | 信任的排序服务的 TLS CA 的证书(PEM 编码格式)路径 +--certfile | string | 与排序服务进行双向 TLS 认证时使用的本地证书文件路径 +--clientauth | bool | 与排序服务通信时是否启用双向 TLS 认证 +--connTimeout | duration | 客户端连接超时,默认为 3 秒 +--keyfile | string | 与排序服务双向 TLS 认证时使用的本地私钥文件路径 +-o, --orderer | string | Orderer 服务地址 +--ordererTLSHostnameOverride | string | 验证 Orderer TLS 时候覆盖所校验的主机名 +--tls | bool | 连接到 Orderer 服务时是否启用 TLS + +此外,不同子命令还可能支持一些子选项,如下表所示。 + +子命令选项 | 类型 | 含义 +--- | --- | --- +--connectionProfile | string | 指定连接配置(Connection Profile)文件 +-C, --chainID | string | 所面向的通道,默认为 "testchainid" +-c, --ctor | string | 指定链码命令的参数信息,Json 格式,默认为 "{}" +-E, --escc | string | 指定所用背书系统链码的名称,默认为 "escc" +-l, --lang | string | 链码实现语言,默认为 "golang" +-n, --name | string | 链码名称 +--peerAddresses | string list | Peer 节点地址,可以指定多个 +-o, --orderer | string | 排序服务地址 +--tlsRootCertFiles | string list | 采用 TLS 时,信任的 Peer 的根证书列表,需要跟 Peer 节点地址列表给出的顺序一致 +-p, --path | string | 所操作链码的本地路径,如果是 Go 语言为包路径(相对于 $GOPAH/src),如果是其它语言则为绝对路径 +-P, --policy | string | 链码所关联的背书策略,例如 -P "OR ('Org1MSP.member','Org2MSP.member')" +-t, --tid | string | ChaincodeInvocationSpec 中的 ID 生成算法和编码,目前支持默认的 sha256+base64 +-v, --version | string | install/instantiate/upgrade 等命令中指定的版本信息 +-V, --vscc | string | 指定所使用验证系统链码的名称,默认为 "vscc" + +注意,不同子命令具体支持不同的参数,总结如下表所示。 + +命令 |-C 通道| -c cc 参数| -E escc | -l 语言 | -n 名称 | -o Orderer | -p 路径 | -P policy | -v 版本 | -V vscc | +-- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | +install |不支持| 支持 |不支持 | 支持 |必需|不支持|必需|不支持| 必需 | 不支持 | +instantiate|必需| 必需 |支持 | 支持 |必需|支持|不支持|支持|必需 | 支持 | +invoke |支持| 必需 |不支持 | 支持 |必需|支持|不支持|不支持|不支持|不支持 | +query |支持| 必需 |不支持 | 支持 |必需|不支持|不支持|不支持|不支持|不支持 | +upgrade |必需| 必需 |支持 | 支持 |必需|支持|不支持|支持| 必需| 支持 | +list |支持| 不支持 |不支持 | 不支持 |不支持|不支持|不支持|不支持|不支持|不支持 | +package |不支持| 支持 |不支持 | 支持 |必需|不支持|必需|不支持|必需 | 不支持| +signpackage |不支持| 支持 |不支持 | 支持 |必需|不支持|必需|不支持|必需 | 不支持| + +其中,必需、支持和不支持三种情况的含义为: + +* 必需:该参数必需被指定,包括通过命令行、环境变量、配置等。 +* 支持:该参数可以被使用。某些时候如果不指定,可能采取默认值或自动获取。 +* 不支持:该参数不应该使用。 + +### 打包链码 + +通过将链码相关的数据进行封装,可以实现对其进行打包操作,生成 .tar.gz 文件,供安装使用。 + +打包命令支持三个特定参数: + +* -p, --path string:要安装的链码包的路径。 +* -l, --lang string:链码语言类型,默认为 golang。 +* --label string:链码包的标签。 + +例如,通过如下命令创建一个本地的链码打包文件 test_cc.tar.gz。 + +```bash +$ peer lifecycle chaincode package test_cc.tar.gz \ + -p \ + -l golang \ + --label testcc_v1.0 + test_cc.tar.gz +``` + +打包后的文件,也可以直接用于 install 操作,如 + +```bash +$ peer chaincode install ccpack.out +``` + +签名命令则对一个打包文件进行签名操作(添加当前 MSP 签名到签名列表中)。 + +```bash +$ peer chaincode signpackage ccpack.out signedccpack.out +``` + +其中,打包文件结构主要包括三部分的信息: + +* ChaincodeDeploymentSpec 结构; +* 实例化策略信息; +* 拥有者的签名列表。 + +实现的整体流程如下: + +* 首先会调用 `InitCmdFactory(isEndorserRequired, isOrdererRequired bool) (*ChaincodeCmdFactory, error)` 方法初始化 Signer 等结构。对于打包命令来说纯属本地操作,不需要 Endorser 和 Orderer 的连接。 +* 调用 getChaincodeSpec() 方法,解析命令行参数,根据所指定的数据生成 ChaincodeSpec 结构。 +* 根据 ChaincodeSpec 结构,结合链码相关数据构造 ChaincodeDeploymentSpec 结构,并传入 getChaincodeInstallPackage 方法。 +* getChaincodeInstallPackage 方法基于传入的 ChaincodeDeploymentSpec 结构,添加实例化策略和签名信息等,生成一个 SignedChaincodeDeploymentSpec,并进一步作为 Data 生成一个 Envelope 结构,其中 ChannelHeader 指定为 CHAINCODE_PACKAGE。 +* 将 Envelope 结构序列化,写到指定的本地文件。 + +其中,Envelope 结构如下图所示。 + +![打包过程中的 Envelope 结构](_images/chaincode_package_Envelope.png) + +### 安装链码 +install 命令将链码的源码和环境等内容封装为一个链码安装打包文件(Chaincode Install Package,CIP),并传输到指定的 Peer 节点。 + +此过程只需要跟 Peer 节点打交道,无需修改账本状态,并不产生交易。只有安装过链码的节点才能进行链码实例化和进行背书处理。默认情况下,执行者需要为该 Peer 节点的管理员角色。 + +例如,采用如下命令可以部署 test_cc.1.0 的链码打包文件到指定的 Peer 节点。 + +```bash +$ CORE_PEER_ADDRESS=peer.your_domain.com:7051 # 设置默认的 Peer 地址 +$ peer chaincode install \ + -n test_cc \ + -v 1.0 \ + -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 +``` + +Peer 节点收到请求,检查和解析后将 CIP 文件保存在 `${CORE_PEER_FILESYSTEMPATH}/chaincodes/` 目录下(一般以 cc_name.version 格式命名,如 /var/hyperledger/production/chaincodes/testcc.1.0),供后续操作(如重新创建和启动链码容器)使用。 + +CIP 文件中主要包括如下数据。 + +* `ChaincodeDeploymentSpec`:链码的源码和一些关联环境,如名称和版本。 +* 链码实例化策略,默认是任意通道上的 MSP 管理员身份均可。 +* 拥有这个链码的实体的证书和签名。 +* 安装时,添加本地 MSP 管理员的签名。 + +其中,ChaincodeDeploymentSpec(CDS)结构最为核心,主要包括 ChaincodeSpec(CS)数据结构(链码部署信息)和 CodePackage(链码源代码相关数据)。CDS 和 CS 结构同时也大量在其他链码命令(如实例化命令和升级命令)中使用。 + +链码安装的整体实现流程如下图所示。 + +![链码安装过程](_images/chaincode_install_flow.png) + +主要步骤包括: + +* 首先是构造带签名的提案结构(SignedProposal)。 + * 调用 `InitCmdFactory(isEndorserRequired, isOrdererRequired bool) (*ChaincodeCmdFactory, error)` 方法,初始化 EndoserClient(跟 Peer 通信)、BroadcastClient(跟 Orderer 通信)、Signer(签名操作)等辅助结构体。所有链码子命令都会执行该过程,会根据需求具体初始化不同的结构。 + * 然后根据命令行参数进行解析,判断是根据传入的打包文件来直接读取 ChaincodeDeploymentSpec(CDS)结构,还是根据传入参数从本地链码源代码文件来构造生成。 + * 以本地重新构造情况为例,首先根据命令行中传入的路径、名称等信息,构造生成 ChaincodeSpec(CS)结构。 + * 利用 ChaincodeSpec 结构,结合链码包数据生成一个 ChaincodeDeploymentSpec 结构(chainID 为空),调用本地的 `install(msg proto.Message, cf *ChaincodeCmdFactory) error` 方法。 + * install 方法基于传入的 ChaincodeDeploymentSpec 结构,构造一个对生命周期管理系统链码(LSCC)调用的 ChaincodeSpec 结构,其中,Type 为 ChaincodeSpec_GOLANG,ChaincodeId.Name 为“lscc”,Input 为 “install”+ChaincodeDeploymentSpec。进一步地,构造了一个 LSCC 的 ChaincodeInvocationSpec(CIS)结构,对 ChaincodeSpec 结构进行封装。 + * 基于 LSCC 的 ChaincodeInvocationSpec 结构,添加头部结构,生成一个提案(Proposal)结构。其中,通道头部中类型为 ENDORSER_TRANSACTION,TxID 为对随机数+签名实体,进行 Hash。 + * 对 Proposal 进行签名,转化为一个签名后的提案消息结构 SignedProposal。 +* 将带签名的提案结构通过 EndorserClient 经由 gRPC 通道发送给 Peer 的 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 接口。 +* Peer 模拟运行生命周期链码的调用交易进行处理,检查格式、签名和权限等,通过则保存到本地文件系统。 + +下图给出了链码安装过程中最为重要的 SignedProposal 数据结构,该结构对于大部分链码操作命令都是类似的,其中最重要的是 ChannelHeader 结构和 ChaincodeSpec 结构中参数的差异。 + +![链码安装过程中所涉及的数据结构](_images/chaincode_install_structure.png) + +### 实例化链码 +instantiate 命令通过构造生命周期管理系统链码(Lifecycle System Chaincode,LSCC)的交易,将安装过的链码在指定通道上进行实例化部署调用,在节点上创建容器启动,并执行初始化操作。实例化链码需要同时跟 Peer 和 Orderer 打交道。 + +执行 instantiate 命令的用户身份必须满足实例化的策略(默认为通道内 MSP 管理员角色),并且在所指定的通道上拥有写(Write)权限。在 instantiate 命令中可以通过 `-P` 参数指定链码调用的背书策略(Endorsement Policy),在 Commit 阶段会进行策略检查。 + +例如,如下命令会启动 test_cc.1.0 链码,会将参数 `'{"Args":["init","a","100","b","200"]}'` 传入链码中的 `Init()` 方法执行。命令会生成一笔交易,因此需指定排序节点地址。 + +```bash +$ APP_CHANNEL="businesschannel" # 设置默认的通道名称 +$ peer chaincode instantiate \ + -o orderer0:7050 \ + -C ${APP_CHANNEL} \ + -n test_cc \ + -v 1.0 \ + -c '{"Args":["init","a","100","b","200"]}' \ + -P "OR ('Org1MSP.member','Org2MSP.member')" \ + --collections-config collection.json \ + --tls \ + --cafile ${ORDERER_TLS_CA} +``` + +其中,collection.json 为私密账本(sideDB)特性中使用(Fabric v1.1.0 开始支持),可以实现在同一通道内实现私密数据局部共享。如果不指定该参数则默认不启用该特性,意味着通道内所有成员都可以看到链码调用结果。 + +collection.json 的一个示例如下所示。 + +```json +[ + { + "name": "public", // 集合名称 + "policy": "OR('Org1MSP.member', 'Org2MSP.member')", // 集合成员 + "requiredPeerCount": 1, // 至少扩散私密数据到几个节点 + "maxPeerCount": 3, // 最大扩散节点个数 + "blockToLive":99999, //私密数据存货时长 + "memberOnlyRead": true // 是否只允许集合的成员访问私密数据 +}, + { + "name": "private", + "policy": "OR('Org1MSP.member')", + "requiredPeerCount": 1, + "maxPeerCount": 3, + "blockToLive":3, + "memberOnlyRead": false + } +] +``` + +其中定义了 public 和 private 两个集合,分别包括两个组织和单个组织。当在链码逻辑中指定某个键值属于特定集合时,只有集合内成员能看到明文的读写集合,非集合成员即便在同一通道内也无法获取隐私数据。对应 policy 只支持 OR 语法,指定哪些组织可以看到隐私数据集合。 + +链码实例化实现的整体流程如下图所示。 + +![链码实例化过程](_images/chaincode_instantiate_flow.png) + +主要步骤包括: + +* 首先,类似链码安装命令,需要创建一个 SignedProposal 消息。注意 instantiate 和 upgrade 支持 policy、escc、vscc 等参数。LSCC 的 ChaincodeSpec 结构中,Input 中包括类型(“deploy”)、通道 ID、ChaincodeDeploymentSpec 结构、背书策略、escc 和 vscc 等。 +* 调用 EndorserClient,发送 gRPC 消息,将签名后的 Proposal 发给指定的 Peer 节点(Endorser),调用 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 方法,进行背书处理。节点会模拟运行 LSCC 的调用交易,启动链码容器。实例化成功后会返回 ProposalResponse 消息(其中包括背书签名)。 +* 根据 Peer 返回的 ProposalResponse 消息,创建一个 SignedTX(Envelop 结构的交易,带有签名)。 +* 使用 BroadcastClient 将交易消息通过 gRPC 通道发给 Orderer,Orderer 会进行全网排序,并广播给 Peer 进行确认提交。 + +其中,SignedProposal 结构如下图所示。 + +![链码实例化时的 SignedProposal 结构](_images/chaincode_instantiate_signedproposal.png) + +交易 Envelope 结构如下图所示。 + +![交易 Envelope 结构](_images/chaincode_instantiate_Envelope.png) + +Peer 返回的 ProposalResponse 消息定义如下。 + +```go +type ProposalResponse struct { + // 消息协议版本 + Version int32 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"` + // 消息创建时的时间戳 + Timestamp *google_protobuf1.Timestamp `protobuf:"bytes,2,opt,name=timestamp" json:"timestamp,omitempty"` + // 返回消息,包括状态、消息、元数据载荷等 + Response *Response `protobuf:"bytes,4,opt,name=response" json:"response,omitempty"` + // 数据载荷,包括提案的 Hash 值,和扩展的行动等 + Payload []byte `protobuf:"bytes,5,opt,name=payload,proto3" json:"payload,omitempty"` + // 背书信息列表,包括背书者的证书,以及其对“载荷+背书者证书”的签名 + Endorsement *Endorsement `protobuf:"bytes,6,opt,name=endorsement" json:"endorsement,omitempty"` +} +``` + +*注:目前命令行下的 instantiate 命令还不支持指定实例化策略,Peer 会采用默认的实例化策略(组织管理员身份)。* + +### 调用链码 + +通过 invoke 命令可以调用运行中的链码的方法。`-c` 参数指定的函数名和参数会被传入到链码的 Invoke() 方法进行处理。调用链码操作需要同时跟 Peer 和 Orderer 打交道。 + +例如,对部署成功的链码执行调用操作,由 `a` 向 `b` 转账 10 元。 + +在 peer0 容器中执行如下操作,注意验证最终结果状态正常 `response:`。 + +```bash +$ peer chaincode invoke \ + -o orderer0:7050 \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["invoke","a","b","10"]}' \ + --tls \ + --cafile ${ORDERER_TLS_CA} +``` + +这一命令会调用最新版本的 test_cc 链码,将参数 `'{"Args":["invoke","a","b","10"]}'` 传入链码中的 `Invoke()` 方法执行。命令会生成一笔交易,需指定排序者地址。 + +需要注意,invoke 命令不支持指定链码版本,默认调用最新版本的链码。 + +实现上,基本过程如下图所示。 + +![链码调用过程](_images/chaincode_invoke_flow.png) + +实现上,基本过程如下: + +* 首先,也是要创建一个 SignedProposal 消息。根据传入的各种参数,生成 ChaincodeSpec 结构(其中,Input 为传入的调用参数)。然后,根据 ChaincodeSpec、chainID、签名实体等,生成 ChaincodeInvocationSpec 结构。进而封装生成 Proposal 结构(通道头部中类型为 ENDORSER_TRANSACTION),并进行签名。 +* 调用 EndorserClient,发送 gRPC 消息,将签名后的 Proposal 发给指定的 Peer 节点(Endorser),调用 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 方法,进行背书处理。节点会模拟运行链码调用交易,成功后会返回 ProposalResponse 消息(带有背书签名)。 +* 根据 Peer 返回的 ProposalResponse 消息,创建一个 SignedTX(Envelop 结构的交易,带有签名)。 +* 调用 BroadcastClient 将交易消息通过 gRPC 通道发给 Orderer 进行全网排序并广播给 Peer 进行确认提交。 + +在此过程中,发给 Peer 节点的交易提案数据结构如下图所示。 + +![链码调用过程发给 Peer 节点的交易提案](_images/chaincode_invoke_signedproposal.png) + +发给排序服务的交易数据结构如下图所示。 + +![链码调用过程发给排序服务的交易结构](_images/chaincode_invoke_Envelope.png) + +注意 invoke 是异步操作,invoke 成功只能保证交易已经进入 Orderer 进行排序,但无法保证最终写到账本中(例如交易未通过 Committer 验证而被拒绝)。需要通过 eventHub 或查询方式来进行确认交易是否最终写入到账本上。 + +### 查询链码 + +查询链码可以通过 query 子命令。 + +该子命令实际上是 invoke 操作与 Peer 打交道的部分,即将签名后的 Proposal 发给指定的 Peer 节点的 ProcessProposal() gRPC 接口。最终将 `-c` 指定的命令参数发送给了链码中的 `Invoke()` 方法执行。 + +与 invoke 操作的区别在于,query 操作用来查询 Peer 上账本状态(需要链码支持查询逻辑),不生成交易,也不需要与 Orderer 打交道。 + +例如,执行如下命令会向 Peer 查询状态 `a` 的值,并返回查询结果。 + +```bash +$ peer chaincode query \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["query","a"]}' +``` + +在实例化链码容器后,可以在 peer0 容器中执行如下命令,注意输出无错误信息,最后的结果为初始值 `Query Result: 100`。 + +```bash +$ peer chaincode query \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["query","a"]}' +Query Result: 100 +[main] main -> INFO 001 Exiting..... +``` + +类似的,查询 `b` 的余额,注意最终返回结果为初始值 `Query Result: 200`。 + +```bash +$ peer chaincode query \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["query","b"]}' +Query Result: 200 +[main] main -> INFO 001 Exiting..... +``` + +在执行完 a 向 b 转账 10 的交易后,再次查询 `a` 和 `b` 的余额,发现发生变化。 + +`a` 的新余额为 90。 + +```bash +$ peer chaincode query \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["query","a"]}' +Query Result: 90 +[main] main -> INFO 001 Exiting..... +``` + +`b` 的新余额为 210。 + +```bash +$ peer chaincode query \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -c '{"Args":["query","b"]}' +Query Result: 210 +[main] main -> INFO 001 Exiting..... +``` + +query 的主要实现过程如下所示。 + +* 根据传入的各种参数,最终构造签名提案,通过 endorserClient 发送给指定的 Peer。 +* 成功的话,获取到 ProposalResponse,打印出 proposalResp.Response.Payload 内容。 + +注意 invoke 和 query 的区别,query 子命令会返回从 Peer 的查询结果,但不创建 SignedTx 发送到 Orderer。 + +### 升级链码 + +当需要修复链码漏洞或进行功能拓展时,可以对链码进行升级,部署新版本的链码。Fabric 支持在保留现有状态的前提下对链码进行升级。 + +假设某通道上正在运行中的链码为 test_cc,版本为 1.0,可以通过如下步骤进行升级操作。 + +首先,安装新版本的链码,打包到 Peer 节点。 + +```bash +$ peer chaincode install \ + -n test_cc \ + -v 1.1 \ + -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02_new +``` + +运行以下 upgrade 命令升级指定通道上的链码,需要指定相同的链码名称 test_cc。 + +```bash +$ peer chaincode upgrade \ + -o orderer0:7050 \ + -n test_cc \ + -C ${APP_CHANNEL} \ + -v 1.1 \ + -c '{"Args":["re-init","c","60"]}' \ + -P "${policy}" \ + --collections-config "${collection_config}" \ + --tls \ + --cafile ${ORDERER_TLS_CA} +``` + +这一命令会在通道 test_cc 上实例化新版本链码 test_cc.1.1 并启动一个新容器。运行在其他通道上的旧版本的链码将不受影响。升级操作跟实例化操作十分类似,唯一区别在于不改变实例化的策略。这就保证了只有拥有实例化权限的用户才能进行升级操作。 + +升级过程会将给定的参数(如例子中的 `'{"Args":["re-init","c","60"]}'`)传入新链码的 `Init()` 方法中执行。只要 `Init()` 方法中对应的逻辑不改写状态,则升级前后链码的所有状态值可以保持不变。因此,如果链码将来要考虑在保留状态情况下升级,需要在编写 `Init()` 方法时妥善处理升级时的逻辑。 + +链码实例化实现的整体流程如下图所示,十分类似实例化过程。 + +![链码升级过程](_images/chaincode_upgrade_flow.png) + +* 首先,需要创建一个封装了 LSCC 调用交易的 SignedProposal 消息。注意 instantiate 和 upgrade 支持指定 policy、escc、vscc 等参数。LSCC 的 ChaincodeSpec 结构中,Input 中包括类型(“upgrade”)、通道 ID、ChaincodeDeploymentSpec 结构、背书策略、escc 和 vscc 等。 +* 调用 EndorserClient,发送 gRPC 消息,将签名后的 Proposal 发给指定的 Peer 节点(Endorser),调用 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 方法,进行背书处理。节点会模拟运行 LSCC 的调用交易,启动链码容器。实例化成功后会返回 ProposalResponse 消息(其中包括背书签名)。 +* 根据 Peer 返回的 ProposalResponse 消息,创建一个 SignedTX(Envelop 结构的交易,带有签名)。 +* 使用 BroadcastClient 将交易消息通过 gRPC 通道发给 Orderer,Orderer 会进行全网排序,并广播给 Peer 进行确认提交。 + +### 查询链码安装和实例化信息 + +list 子命令支持查询某个节点上已经安装的链码信息(--installed)或某个通道内已经实例化的链码信息(--instantiated)。请求发送到 Peer 节点,调用 LSCC 系统链码提供的接口进行查询。 + +例如,如下命令查询默认 Peer 上安装的链码情况,返回结果显示已安装链码 exp02 的 v1.0 版本。 + +```bash +$ peer chaincode list \ + --installed \ + +Get installed chaincodes on peer: +Name: exp02, Version: 1.0, Path: examples/chaincode/go/chaincode_example02, Id: 08ca675c39a8bae2631847a521fc92e12969fe122bd4a9df0a707cf1059e8730 +``` + +例如,如下命令查询通道 ${APP_CHANNEL} 内实例化的链码情况,返回结果显示已实例化链码 exp02 的 v1.0 版本。 + +```bash +$ peer chaincode list \ + --instantiated \ + -C ${APP_CHANNEL} + +Get instantiated chaincodes on channel businesschannel: +Name: exp02, Version: 1.0, Path: examples/chaincode/go/chaincode_example02, Escc: escc, Vscc: vscc +``` + +链码列出安装和实例化过程的实现流程如下图所示。 + +![链码列出安装和实例化过程](_images/chaincode_list_flow.png) + +* 首先,根据输入参数创建一个 LSCC 的链码调用规范。LSCC 的 ChaincodeSpec 结构中,Input 参数根据查询类型设置为 getinstalledchaincodes 或 getchaincodes。 +* 根据 LSCC 的链码调用规范封装为一个 Proposal 结构,头部类型为 ENDORSER_TRANSACTION,通道 ID 设置为空(查询安装信息)或给定的通道(查询实例化信息)。 +* 调用 EndorserClient,发送 gRPC 消息,将签名后的 Proposal 发给指定的 Peer 节点(Endorser),调用 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 方法,进行背书处理。节点会运行 LSCC 的相应逻辑,成功后会返回 ProposalResponse 消息。 +* 客户端解析 Peer 返回的 ProposalResponse 消息,如果成功则打印查询结果。 + + diff --git a/chainbrock-learning/10_fabric_op/channel.md b/chainbrock-learning/10_fabric_op/channel.md new file mode 100644 index 00000000..6253cb02 --- /dev/null +++ b/chainbrock-learning/10_fabric_op/channel.md @@ -0,0 +1,281 @@ +## 使用多通道 + +### 通道操作命令 + +命令行下 `peer channel` 命令支持包括 create、fetch、join、list、update、getinfo、signconfigtx 等子命令。其中,create、fetch、update 命令主要与排序服务打交道;join、list、getinfo 与 Peer 节点打交道,signconfigtx 为本地处理。 + +各个命令的功能如下表所示: + +命令 | 发往组件 | 功能 +-- | -- | -- +create | 排序服务 | 创建一个新的应用通道。 +fetch | 排序服务 | 从排序服务获取指定区块。 +update | 排序服务 | 更新通道的配置信息,如组织、锚节点配置等。 +join | Peer 节点 | 将 Peer 节点加入到某个应用通道中。 +list | Peer 节点 | 列出 Peer 已经加入的所有的应用通道。 +getinfo | Peer 节点 | 获取通道的基本信息,包括高度、当前 Hash、前导区块 Hash。 +signconfigtx | 本地操作 | 为本地的通道配置更新添加签名。 + +可以通过 `peer channel --help` 来查看具体的命令使用说明。 + +### 命令选项 + +`peer channel` 命令支持的全局选项如下。 + +全局选项 | 类型 | 含义 +--- | --- | --- +--connTimeout | int | 客户端连接超时,默认为 3 秒 +--keyfile | string | 与排序服务双向 TLS 认证时使用的私钥文件 +-o, --orderer | string | Orderer 服务地址 +--tls | bool | 连接到 Orderer 服务时是否启用 TLS +--cafile | string | 信任的排序服务的 TLSCA 证书,PEM 编码格式 +--certfile | string | 与排序服务双向 TLS 认证时使用的证书文件 +--clientauth | bool | 与排序服务通信时是否启用双向 TLS 认证 +--ordererTLSHostnameOverride | string | 验证 Orderer TLS 时候覆盖所校验的主机名 + +默认情况下,客户端会从环境变量中读取操作的 Peer 地址和客户端身份信息,因此需要提前指定。 + +例如,下面命令指定了对 org1 的 peer1 节点执行相关操作命令,身份为组织的管理员 Admin@org1。 + +```bash +$ CORE_PEER_ADDRESS=peer1:7051 \ + CORE_PEER_LOCALMSPID="org1" \ + CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto/org1/users/Admin@org1/msp \ + CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/crypto/org1/peers/peer1/tls/ca.cert \ + peer channel +``` + +### 创建通道 + +create 子命令由拥有创建通道权限的组织的管理员身份来调用,在指定的排序服务上创建新的应用通道,需要提供排序服务地址。 + +该子命令支持选项包括: + +* -c, --channelID string:所创建通道的名称; +* -f, --file string:指定创建通道所用的交易文件; +* --outputBlock string:创建通道成功后,将初始区块写到本地指定文件,默认为 ./.block; +* -t, --timeout duration:创建超时,默认为 5 秒。 + +一般情况下,通过提前创建的通道配置交易文件来指定配置信息。如果不指定通道配置文件,则默认采用 SampleConsortium 配置和本地的 MSP 组织来构造配置交易结构。 + +例如,下面命令利用事先创建的配置交易文件 channel.tx 来创建新的应用通道 businesschannel。 + +```bash +$ APP_CHANNEL="businesschannel" +$ peer channel create \ + -o orderer:7050 \ + -c ${APP_CHANNEL} \ + -f ./channel.tx \ + --timeout 30 +``` + +加入成功后,本地会产生该应用通道的初始区块文件 businesschannel.block。Ordering 服务端也会输出类似 `orderer | UTC [orderer/multichain] newChain -> INFO 004 Created and starting new chain newchannel` 的成功消息。 + +创建应用通道的主要过程如下图所示。 + +![创建应用通道过程](_images/channel_create_flow.png) + +主要步骤包括: + +* 客户端调用 sendCreateChainTransaction(),检查指定的配置交易文件,或者利用默认配置,构造一个创建应用通道的配置交易结构,封装为 Envelope,指定 channel 头部类型为 CONFIG_UPDATE。 +* 客户端发送配置交易到排序服务。 +* Orderer 收到 CONFIG_UPDATE 消息后,检查指定的通道还不存在,则开始创建通道,并构造该应用通道的初始区块。 + * Orderer 首先检查通道应用(Application)配置中的组织都在创建的联盟(Consortium)配置组织中。 + * 之后从系统通道中获取 Orderer 相关的配置,并创建应用通道配置,对应 mod_policy 为系统通道配置中的联盟指定信息。 + * 接下来根据 CONFIG_UPDATE 消息的内容更新获取到的配置信息。所有配置发生变更后版本号都要更新。 + * 创建签名 Proposal 消息(头部类型为 ORDERER_TRANSACTION),发送到后端队列(如 Kafka),指定目标为系统通道; + * Orderer 从后端队列收到对应消息,初始化本地账本结构,完成应用通道的创建过程。 +* 客户端从 Orderer Deliver gRPC 服务获取应用通道的初始区块(具体过程类似 fetch 命令),请求类型为 CONFIG_UPDATE,负载为 SeekInfo。 +* 客户端将收到的区块写入到本地的 chainID + ".block" 文件。这个文件后续会被需要加入到通道的节点使用。 + +其中,最关键的数据结构是配置交易相关的 Envelope 结构,如下图所示。 + +![通道配置交易结构](_images/channel_create_tx.png) + +### 加入通道 + +join 子命令会让指定的 Peer 节点加入到指定的应用通道。需要提前拥有所加入应用通道的初始区块文件,并且只有属于通道的某个组织的管理员身份可以成功执行该操作。加入通道命令主要通过调用 Peer 的配置系统链码进行处理。 + +例如,通过如下命令将本地 Peer 加入到应用通道 businesschannel 中。 + +该子命令支持选项包括: + +* -b, --blockpath string:指定初始区块文件的路径 + +```bash +$ peer channel join \ + -b ${APP_CHANNEL}.block + +Peer joined the channel! +``` + +加入应用通道的主要过程如下图所示。 + +![加入应用通道过程](_images/channel_join_flow.png) + +主要步骤包括: + +* 客户端首先创建一个 ChaincodeSpec 结构,其 input 中的 Args 第一个参数是 CSCC.JoinChain(指定调用配置链码的操作),第二个参数为所加入通道的配置区块。 +* 利用 ChaincodeSpec 构造一个 ChaincodeInvocationSpec 结构。 +* 利用 ChaincodeInvocationSpec,创建 Proposal 结构并进行签名,channel 头部类型为 CONFIG。 +* 客户端通过 gRPC 将 Proposal 签名后发给 Endorser(所操作的 Peer),调用 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 方法进行处理,主要通过配置系统链码从配置区块中读取通道内已有成员的 TLS CA 根证书,加入到本地的根证书信任结构中,并进行本地链结构的初始化工作。 +* 初始化完成后,即可收到来自通道内的 Gossip 消息等。 + +其中,比较重要的数据结构包括 ChaincodeSpec、ChaincodeInvocationSpec、Proposal 等,它们的具体结构如下图所示。 + +![加入通道时的 Signed Proposal 结构](_images/channel_join_signed_proposal.png) + +*注:权限不足情况下,执行加入通道命令可能不会报错,但实际上并没有加入到通道,也不会获取到通道内的数据。* + +### 列出所加入的通道 + +list 子命令会列出指定的 Peer 节点已经加入的所有应用通道的列表。加入通道命令也是主要通过调用 Peer 的配置系统链码进行处理。 + +例如通过如下命令,可以列出本地 Peer 已经加入的所有应用通道。 + +```bash +$ peer channel list +Channels peers has joined to: + businesschannel + businesschannel2 +``` + +列出所加入应用通道的主要过程如下图所示。 + +![列出所加入应用通道过程](_images/channel_list_flow.png) + +主要步骤包括: + +* 客户端首先创建一个 ChaincodeSpec 结构,其 input 中的 Args 第一个参数是 CSCC.GetChannels(指定调用配置链码的操作)。 +* 利用 ChaincodeSpec 构造一个 ChaincodeInvocationSpec 结构。 +* 利用 ChaincodeInvocationSpec,创建 Proposal 结构并进行签名,channel 头部类型为 ENDORSER_TRANSACTION。 +* 客户端通过 gRPC 将 Proposal 发给 Endorser(所操作的 Peer),调用 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 方法进行处理,主要是通过配置系统链码查询本地链信息并返回。 +* 命令执行成功后,客户端会受到来自 Peer 端的回复消息,从其中提取出应用通道列表信息并输出。 + +其中,比较重要的数据结构同样也包括 ChaincodeSpec、ChaincodeInvocationSpec、Proposal 等,注意 channel 头部类型和 ChaincodeSpec 结构中数据与加入通道的消息中略有差异。 + +![列出通道时的 Signed Proposal 结构](_images/channel_list_signed_proposal.png) + +### 获取某区块 + +fetch 子命令会向排序服务进行查询,获取到指定通道的指定区块。并将收到的区块写入到本地的文件(默认为 chainID_序号.block)。 + +命令格式为 `peer channel fetch [outputfile] [flags]`。 + +该子命令支持选项包括: + +* -c, --channelID string:所获取的通道的名称; + +例如通过如下命令,可以获取到已存在的 businesschannel 应用通道的初始区块,并保存到本地的 businesschannel.block 文件。 + +```bash +$ peer channel fetch oldest businesschannel_0.block \ + -c businesschannel \ + -o orderer:7050 + +$ peer channel fetch 1 businesschannel_1.block \ + -c businesschannel \ + -o orderer:7050 +``` + +获取区块的主要过程如下图所示。 + +![获取区块过程](_images/channel_fetch_flow.png) + +主要步骤包括: + +* 客户端构造 SeekInfo 结构,该结构可以指定要获取的区块范围。这里 Start、Stop 指定为目标区块; +* 客户端利用 SeekInfo 结构,构造 Envelope 并进行签名,通过deliverClient经 gRPC 通道发给排序服务接口; +* 从 Orderer 获取指定通道的区块后,写到本地文件中。 + +其中,比较重要的数据结构包括 SeekInfo、Envelope 结构等,它们的具体结构如下图所示。 + +![获取区块的请求消息](_images/channel_fetch_envelope.png) + +### 更新通道配置 + +update 子命令的执行过程与 create 命令类似,会向排序服务发起更新配置交易请求。 + +该命令执行也需要提前创建的通道更新配置交易文件来指定配置信息。 + +该子命令支持选项包括: + +* -c, --channelID string:所更新通道的名称; +* -f, --file string:指定更新通道所用的交易文件。 + +例如,通过如下操作来更新通道中的锚节点配置,首先利用 configtxgen 来创建锚节点配置更新文件,之后使用该更新文件对通道进行配置更新操作。 + +```bash +$ configtxgen \ + -profile APP_CHANNEL_PROFILE \ + -outputAnchorPeersUpdate ./update_anchors.tx \ + -channelID businesschannel \ + -asOrg Org1MSP +$ peer channel update \ + -c businesschannel \ + -o orderer:7050 \ + -f ./update_anchors.tx +``` + +更新应用通道的主要过程如下图所示。 + +![更新应用通道过程](_images/channel_update_flow.png) + +主要步骤包括: + +* 客户端读取指定的配置交易文件,构造一个更新应用通道的配置交易信封结构,确认通道头部类型为 CONFIG_UPDATE,通道 ID 存在且与命令行参数一致。 +* 客户端对更新信封结构进行签名,最终构造签名信封结构,通道头部类型为 CONFIG_UPDATE。 +* 客户端通过 gRPC 发送配置交易到排序服务的 Broadcast 接口。 +* Orderer 收到 CONFIG_UPDATE 消息后,判断是配置消息,则进行配置相关处理: + * 调用 ProcessConfigUpdateMsg() 尝试接受配置,计算新配置结构(封装为 CONFIG 类型的信封结构)和对应的序号; + * Orderer 将新的配置信封结构发送给后端队列(如 Kafka)进行排序,并响应客户端答复; + * 排序完成后,Orderer 将新的配置交易存放到账本结构中等待 Peer 节点获取。 +* 客户端在发出请求后会接收到响应,但实际请求仍在 Orderer 端异步进行。 + +其中,最关键的数据结构是配置交易相关的 Envelope 结构,如下图所示。 + +![通道配置交易结构](_images/channel_update_tx.png) + +### 获取通道基本信息 + +getinfo 可以向指定的 Peer 节点获取某个通道的基本信息,包括高度、当前 Hash、前导区块 Hash 等。 + +该子命令支持选项包括: + +* -c, --channelID string:所获取信息的通道的名称。 + +例如,查询默认 Peer 节点上 businesschannel 通道的信息: + +```bash +$ peer channel getinfo -c businesschannel +Blockchain info: {"height":7,"currentBlockHash":"bHlVT/swOzeJ8JaTXyhStu40QL4JBxZBD695FISJf2o=","previousBlockHash":"ViDfGewz/GRg3wDz68dtg4s9NNojtq3ciBB4VcpGBuk="} +``` + +获取通道基本信息的主要过程如下图所示。 + +![获取通道基本信息过程](_images/channel_getinfo_flow.png) + +主要步骤包括: + +* 客户端首先创建一个 ChaincodeSpec 结构,其 input 中的 Args 第一个参数是 CSCC.Getchannels(指定调用配置链码的操作),第二个参数为所加入通道的配置区块; +* 利用 ChaincodeSpec 构造一个 ChaincodeInvocationSpec 结构; +* 利用 ChaincodeInvocationSpec,创建 Proposal 结构并进行签名,channel 头部类型为 CONFIG。 +* 客户端通过 gRPC 将 Proposal 签名后发给 Endorser(所操作的 Peer),调用 `ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, error)` 方法进行处理,主要通过配置系统链码获取对应账本的基本信息并返回客户端。 + +其中,比较重要的数据结构包括 ChaincodeSpec、ChaincodeInvocationSpec、Proposal 等,它们的具体结构如下图所示。 + +![获取通道基本信息时的 Signed Proposal 结构](_images/channel_join_signed_proposal.png) + +### 对通道配置更新添加签名 + +signconfigtx 可以为本地的通道更新交易进行签名,属于客户端本地操作,不跟 Peer 或 Orderer 打交道。 + +该子命令支持选项包括: + +* -f, --file string:指定所签名的通道配置更新交易文件。 + +例如,对本地的通道配置更新添加签名。 + +```bash +$ peer channel signconfigtx -f config_delta_env.pb +``` diff --git a/chainbrock-learning/10_fabric_op/discover.md b/chainbrock-learning/10_fabric_op/discover.md new file mode 100644 index 00000000..4a276d2a --- /dev/null +++ b/chainbrock-learning/10_fabric_op/discover.md @@ -0,0 +1,326 @@ +## 自动探测网络信息 + +客户端要往 Fabric 网络中发送请求,首先需要知道网络的相关信息,如网络中成员、背书节点的地址、链码安装信息等。 + +在 Fabric v1.2.0 版本之前这些信息需要使用者来手动采集提供。这种方式下需要提前指定,容易出错,另外是当网络中信息变更后(如节点上下线)还需要再次更新。 + +为了解决这些问题,社区自 v1.2.0 版本开始在 Peer 节点上提供了 Discovery 服务,并编写了 discover 客户端工具(位于 discovery/cmd)。该工具可以访问 Peer 节点提供的 Discovery 服务,查询获取指定信息。 + +### 主要功能 + +discover 工具目前提供如下的查询功能: + +* 节点信息查询:使用 `peers` 子命令查询节点的身份、服务等信息; +* 通道配置:使用 `config` 子命令查询通道的配置信息,包括成员组织、排序服务信息等; +* 链码背书信息:使用 `endorsers` 子命令查询对某个链码可以进行背书的节点信息。 + +命令使用格式为 `discover [全局参数] <子命令> [子命令参数列表]`。 + +### 全局参数 + +discover 支持的全局参数和相关说明如下: + +```bash +* --help:输出帮助信息; +* --configFile=CONFIGFILE:指定从配置文件中载入参数配置,则无需从命令行指定参数; +* --peerTLSCA=PEERTLSCA:指定校验 peer 端 TLS 的 CA 证书; +* --tlsCert=TLSCERT:指定客户端使用的 TLS 证书(可选,当 Peer 校验客户端 TLS 时); +* --tlsKey=TLSKEY:指定客户端使用的 TLS 私钥(可选,当 Peer 校验客户端 TLS 时); +* --userKey=USERKEY:客户端签名私钥; +* --userCert=USERCERT:客户端签名证书; +* --MSP=MSP:指定客户端的 MSP ID。 +``` + +### 子命令 + +discover 目前支持四个子命令:`peers`、`config`、`endorsers`、`saveConfig`,可以通过 `help <子命令>` 来查看各子命令的功能和使用方法。 + +#### peers 子命令 + +显示网络中的 Peer 节点信息,包括它们的 MSP Id、gRPC 服务监听地址和身份证书。 + +命令格式为 `peers [参数列表]`,支持参数如下: + +```bash +* --server=SERVER:指定命令连接的 Peer 节点地址; +* --channel=CHANNEL:指定查询某个特定通道内的节点信息。 +``` + +例如,通过 peer0.org1.example.com 节点查询 businesschannel 通道内的 Peer 节点信息,可以执行如下命令: + +```bash +$ discover \ + --peerTLSCA tls/ca.crt \ + --userKey msp/keystore/f76cf3c92dac81103c82d5490c417ac0123c279f93213f65947d8cc69e11fbc5_sk \ + --userCert msp/signcerts/Admin\@org1.example.com-cert.pem \ + --MSP Org1MSP \ + --tlsCert tls/client.crt \ + --tlsKey tls/client.key \ + peers \ + --server peer0.org1.example.com:7051 \ + --channel businesschannel + +[ + { + "MSPID": "Org2MSP", + "Endpoint": "peer1.org2.example.com:7051", + "Identity": "-----BEGIN CERTIFICATE-----\nMIICKD...pVTw==\n-----END CERTIFICATE-----\n" + }, + { + "MSPID": "Org2MSP", + "Endpoint": "peer0.org2.example.com:7051", + "Identity": "-----BEGIN CERTIFICATE-----\nMIICKT...cGaA=\n-----END CERTIFICATE-----\n" + }, + { + "MSPID": "Org1MSP", + "Endpoint": "peer0.org1.example.com:7051", + "Identity": "-----BEGIN CERTIFICATE-----\nMIICKD...mgaA==\n-----END CERTIFICATE-----\n" + }, + { + "MSPID": "Org1MSP", + "Endpoint": "peer1.org1.example.com:7051", + "Identity": "-----BEGIN CERTIFICATE-----\nMIICKD...UO+g==\n-----END CERTIFICATE-----\n" + } +] +``` + +结果显示 businesschannel 通道内目前包括属于 2 个组织的 4 个 Peer 节点成员: + +* Org1MSP + * peer0.org1.example.com + * peer1.org1.example.com +* Org2MSP + * peer0.org2.example.com + * peer1.org2.example.com + +#### config 子命令 + +显示网络中的通道配置信息,包括各个组织的 MSP 信息和排序节点信息。 + +命令格式为 `config [<参数>]`,支持参数如下: + +```bash +* --server=SERVER:指定命令连接的 Peer 节点地址; +* --channel=CHANNEL:指定查询某个特定通道内的配置信息。 +``` + +例如,通过 peer0.org1.example.com 节点查询 businesschannel 通道内的配置信息,可以执行如下命令: + +```bash +$ discover \ + --peerTLSCA tls/ca.crt \ + --userKey msp/keystore/f76cf3c92dac81103c82d5490c417ac0123c279f93213f65947d8cc69e11fbc5_sk \ + --userCert msp/signcerts/Admin\@org1.example.com-cert.pem \ + --MSP Org1MSP \ + --tlsCert tls/client.crt \ + --tlsKey tls/client.key \ + config \ + --server peer0.org1.example.com:7051 \ + --channel businesschannel + +{ + "msps": { + "OrdererMSP": { + "name": "OrdererMSP", + "root_certs": [ + "LS0tLS...tLQo=" + ], + "admins": [ + "LS0tLS...LS0K" + ], + "crypto_config": { + "signature_hash_family": "SHA2", + "identity_identifier_hash_function": "SHA256" + }, + "tls_root_certs": [ + "LS0tLS...0tCg==" + ] + }, + "Org1MSP": { + "name": "Org1MSP", + "root_certs": [ + "LS0tLS...0tCg==" + ], + "admins": [ + "LS0tLS...LS0K" + ], + "crypto_config": { + "signature_hash_family": "SHA2", + "identity_identifier_hash_function": "SHA256" + }, + "tls_root_certs": [ + "LS0tLS...LS0K" + ], + "fabric_node_ous": { + "enable": true, + "client_ou_identifier": { + "certificate": "LS0tLS...0tCg==", + "organizational_unit_identifier": "client" + }, + "peer_ou_identifier": { + "certificate": "LS0tLS...0tCg==", + "organizational_unit_identifier": "peer" + } + } + }, + "Org2MSP": { + "name": "Org2MSP", + "root_certs": [ + "LS0tLS...LS0K" + ], + "admins": [ + "LS0tLS...0tCg==" + ], + "crypto_config": { + "signature_hash_family": "SHA2", + "identity_identifier_hash_function": "SHA256" + }, + "tls_root_certs": [ + "LS0tLS...LS0K" + ], + "fabric_node_ous": { + "enable": true, + "client_ou_identifier": { + "certificate": "LS0tLS...LS0K", + "organizational_unit_identifier": "client" + }, + "peer_ou_identifier": { + "certificate": "LS0tLS...LS0K", + "organizational_unit_identifier": "peer" + } + } + } + }, + "orderers": { + "OrdererMSP": { + "endpoint": [ + { + "host": "orderer.example.com", + "port": 7050 + } + ] + } + } +} +``` + +结果将显示通道内的各个 MSP 的信息和排序服务信息。 + +#### endorsers 子命令 + +显示网络中的背书节点信息,包括它们的 MSP Id、账本高度、服务地址和身份证书等。 + +命令格式为 `endorsers [参数列表]`,支持参数如下: + +```bash +* --server=SERVER:指定命令连接的 Peer 节点地址; +* --channel=CHANNEL:指定查询某个特定通道内的节点信息; +* --chaincode=CHAINCODE:指定链码名称列表; +* --collection=CC:C1,C2...:指定链码中集合信息。 +``` + +例如,查询可以对链码 marblesp 的 collectionMarbles 集合进行背书的节点,可以执行如下命令: + +```bash +$ discover \ + --peerTLSCA tls/ca.crt \ + --userKey msp/keystore/f76cf3c92dac81103c82d5490c417ac0123c279f93213f65947d8cc69e11fbc5_sk \ + --userCert msp/signcerts/Admin\@org1.example.com-cert.pem \ + --MSP Org1MSP \ + --tlsCert tls/client.crt \ + --tlsKey tls/client.key \ + endorsers \ + --server peer0.org1.example.com:7051 \ + --channel businesschannel \ + --chaincode marblesp \ + --collection=marblesp:collectionMarbles + +[ + { + "Chaincode": "marblesp", + "EndorsersByGroups": { + "G0": [ + { + "MSPID": "Org1MSP", + "LedgerHeight": 10, + "Endpoint": "peer1.org1.example.com:7051", + "Identity": "-----BEGIN CERTIFICATE-----\nMIICKD...UO+g==\n-----END CERTIFICATE-----\n" + }, + { + "MSPID": "Org1MSP", + "LedgerHeight": 10, + "Endpoint": "peer0.org1.example.com:7051", + "Identity": "-----BEGIN CERTIFICATE-----\nMIICKD...mgaA==\n-----END CERTIFICATE-----\n" + } + ], + "G1": [ + { + "MSPID": "Org2MSP", + "LedgerHeight": 10, + "Endpoint": "peer0.org2.example.com:7051", + "Identity": "-----BEGIN CERTIFICATE-----\nMIICKT...cGaA=\n-----END CERTIFICATE-----\n" + }, + { + "MSPID": "Org2MSP", + "LedgerHeight": 10, + "Endpoint": "peer1.org2.example.com:7051", + "Identity": "-----BEGIN CERTIFICATE-----\nMIICKD...pVTw==\n-----END CERTIFICATE-----\n" + } + ] + }, + "Layouts": [ + { + "quantities_by_group": { + "G0": 1 + } + }, + { + "quantities_by_group": { + "G1": 1 + } + } + ] + } +] +``` + +结果将按组展示符合要求的背书节点的信息。 + +#### saveConfig 子命令 + +该命令并不与 Peer 节点打交道,它将通过参数指定的变量信息保存为本地文件。这样用户在执行后续命令时候可以指定该文件,而无需再指定各个参数值。 + +需要通过 `--configFile=CONFIGFILE` 来指定所存放的参数信息文件路径。 + +例如,保存指定的参数信息到本地的 discover_config.yaml 文件,可以执行如下命令: + +```bash +$ discover \ + --peerTLSCA tls/ca.crt \ + --userKey msp/keystore/f76cf3c92dac81103c82d5490c417ac0123c279f93213f65947d8cc69e11fbc5_sk \ + --userCert msp/signcerts/Admin\@org1.example.com-cert.pem \ + --MSP Org1MSP \ + --tlsCert tls/client.crt \ + --tlsKey tls/client.key \ + --configFile discover_config.yaml \ + saveConfig +``` + +命令执行完成后,查看本地的 `discover_config.yaml` 文件内容如下: + +```yaml +version: 0 +tlsconfig: + certpath: /etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/tls/client.crt + keypath: /etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/tls/client.key + peercacertpath: /etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/tls/ca.crt + timeout: 0s +signerconfig: + mspid: Org1MSP + identitypath: /etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem + keypath: /etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/f76cf3c92dac81103c82d5490c417ac0123c279f93213f65947d8cc69e11fbc5_sk +``` + +有了这个参数文件,当再使用同样的参数时就无需手动指定,直接使用 `--configFile discover_config.yaml` 即可。 + +当然,用户也可以手动编写参数文件,但直接使用 saveConfig 命令自动生成将更加方便、高效。 diff --git a/chainbrock-learning/10_fabric_op/events.md b/chainbrock-learning/10_fabric_op/events.md new file mode 100644 index 00000000..7aca5712 --- /dev/null +++ b/chainbrock-learning/10_fabric_op/events.md @@ -0,0 +1,124 @@ +## 监听网络事件 + +用户可能注意到,发往网络的请求是异步处理模式,这就意味着客户端无法获知提交的交易是否最终接受。Fabric 在 Peer 节点上提供了事件 gRPC 服务,用户可以通过客户端来监听。 + +下面通过 eventsclient 工具来监听网络中的事件。 + +首先通过如下命令安装 eventsclient 工具。 + +```bash +$ cd $GOPATH/src/hyperledger/fabric/examples/events/eventsclient +$ go install && go clean +``` + +该工具自动封装对 Peer 事件的 gRPC 请求,支持的选项主要包括如下几个: + +* -server "localhost:7053":监听服务地址,一般指定为 Peer 节点的 7053 端口; +* -channelID string:监听指定通道信息,默认为 testchainid; +* -seek int:指定从哪个区块开始监听。-2代表从初始区块(默认),-1代表从当前最新区块; +* -filtered=true:只获取过滤的区块内容,不显示完整内容。 +* -quiet:不打印区块内容,只显示区块号; +* -tls:是否启用 TLS,默认关闭; +* -rootCert string:启用 TLS 时指定信任的根 CA 证书路径; +* -mTls:是否开启双向验证(即服务端也同时验证客户端身份),默认关闭。 +* -clientCert string::启用 TLS 时候客户端证书路径; +* -clientKey string:启用 TLS 时候客户端私钥路径; + +典型地,用户可以通过环境变量指定所需的参数值,使用如下命令启动监听。 + +```bash +$ eventsclient \ + -server=${PEER_URL} \ + -channelID=${APP_CHANNEL} \ + -filtered=true \ + -tls=true \ + -clientKey=${TLS_CLIENT_KEY} \ + -clientCert=${TLS_CLIENT_CERT} \ + -rootCert=${TLS_CA_CERT} +``` + +启动后,该工具会持续监听来自指定通道的事件,并打印出来。 + +例如,监听 businesschannel 通道内区块信息,并对结果进行过滤输出,命令和结果如下所示。 + +```bash +$ CORE_PEER_LOCALMSPID=Org1MSP \ +CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp \ +eventsclient \ + -server=peer0.org1.example.com:7051 \ + -channelID=businesschannel \ + -filtered=true \ + -tls=true \ + -clientKey=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@Org1.example.com/tls/client.key \ + -clientCert=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@Org1.example.com/tls/client.crt \ + -rootCert=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org1.example.com/users/Admin@Org1.example.com/tls/ca.crt + +UTC [eventsclient] readEventsStream -> INFO 001 Received filtered block: +{ + "channel_id": "businesschannel", + "filtered_transactions": [ + { + "tx_validation_code": "VALID", + "txid": "", + "type": "CONFIG" + } + ], + "number": "0" +} +UTC [eventsclient] readEventsStream -> INFO 002 Received filtered block: +{ + "channel_id": "businesschannel", + "filtered_transactions": [ + { + "tx_validation_code": "VALID", + "txid": "", + "type": "CONFIG" + } + ], + "number": "1" +} +UTC [eventsclient] readEventsStream -> INFO 003 Received filtered block: +{ + "channel_id": "businesschannel", + "filtered_transactions": [ + { + "tx_validation_code": "VALID", + "txid": "", + "type": "CONFIG" + } + ], + "number": "2" +} +UTC [eventsclient] readEventsStream -> INFO 004 Received filtered block: +{ + "channel_id": "businesschannel", + "filtered_transactions": [ + { + "transaction_actions": { + "chaincode_actions": [] + }, + "tx_validation_code": "VALID", + "txid": "2832892094f612237b06950b77a6afc13ca9226176e99c2a8577cf4be2074c0a", + "type": "ENDORSER_TRANSACTION" + } + ], + "number": "3" +} +UTC [eventsclient] readEventsStream -> INFO 005 Received filtered block: +{ + "channel_id": "businesschannel", + "filtered_transactions": [ + { + "transaction_actions": { + "chaincode_actions": [] + }, + "tx_validation_code": "VALID", + "txid": "fec547335060bb324e8e4a08067c7fa24092e1295cb62dffb14a93bc77b2fbcf", + "type": "ENDORSER_TRANSACTION" + } + ], + "number": "4" +} +... +``` + diff --git a/chainbrock-learning/10_fabric_op/intro.md b/chainbrock-learning/10_fabric_op/intro.md new file mode 100644 index 00000000..92518f7e --- /dev/null +++ b/chainbrock-learning/10_fabric_op/intro.md @@ -0,0 +1,19 @@ +## 简介 + +Fabric 网络中存在四种不同种类的服务节点,彼此协作完成整个区块链系统的记账功能。 + +* 背书节点(Endorser Peer):一类特殊的 Peer,负责对交易提案(Transaction Proposal)进行检查,计算交易执行结果(读写集合)并进行背书; +* 记账节点(Committer Peer):负责维护账本,检查排序后交易结果合法性,接受合法修改,并写入到本地账本结构。目前所有 Peer 默认都是记账节点; +* 排序节点(Orderer):正式交易会发给排序节点,排序节点负责对网络中所有交易进行排序处理,并整理为区块结构,之后被记账节点拉取提交到本地账本; +* 证书节点(CA):提供标准的 PKI 服务,负责对网络中所有的证书进行管理。 + +对网络中节点角色进行解耦是 Fabric 设计中的一大创新,这也是联盟链场景下的特殊需求和环境所决定的。 + +通道是 Fabric 网络的另一个重要特性,每个通道实际上都是独立的账本。系统通道(System Channel,只有一个)负责管理网络的各种配置(如排序服务、联盟信息);应用通道(Application Channel,可以有任意多个,供用户发送交易使用)负责为不同成员之间的业务合作提供隔离支持。 + +网络启动后,对 Fabric 网络的管理主要包括两大类操作: + +* 通道操作:包括创建、加入通道、查询通道信息、更新通道配置等; +* 链码操作:包括安装、实例化(部署)、调用链码等。 + +为了提高使用网络的效率,Fabric 还提供了时间通知机制和网络发现功能。后面讲具体进行介绍。 \ No newline at end of file diff --git a/chainbrock-learning/10_fabric_op/operation.md b/chainbrock-learning/10_fabric_op/operation.md new file mode 100644 index 00000000..b076a9af --- /dev/null +++ b/chainbrock-learning/10_fabric_op/operation.md @@ -0,0 +1,95 @@ +## 使用运维服务 + +Fabric 自 v1.4.0 版本开始,加强了对运维操作的支持,在 Peer 和 Orderer 上提供了一系列的 RESTful API 来协助监控服务状态。 + +这些 API 主要分为三大类: + +* 获取和配置日志级别,资源为 /logspec; +* 监控系统组件的健康状态,资源为 /healthz; +* 获取系统统计信息,支持外部 Prometheus 拉取,或推送给 StatsD。 + +它们可以通过 Peer 和 Orderer 配置文件中的 operations 字段进行开启和配置。Peer 默认监听端口为 9443,Orderer 默认监听端口为 8443。 + +下面分别进行讲解。 + +### 获取和配置日志级别 + +日志资源为 /logspec。 + +获取日志级别可以发送 GET 请求,返回 JSON 格式对象。例如获取当前日志级别,可以使用如下命令。 + +```bash +$ curl http://orderer:8443/logspec +{"spec":"info"} +$ curl http://peer:9443/logspec +{"spec":"info"} +``` + +修改日志级别可以发送 PUT 请求,消息内容为字典结构:{"spec": "[[,...]=][:[[,...]=]...]"},例如修改 Gossip 模块日志级别为 DEBUG,全局默认级别仍为 INFO。 + +```bash +$ curl -XPUT \ + -d '{"spec":"gossip=debug:info"}' \ + http://peer:9443/logspec +``` + +### 监控系统组件的健康状态 + +资源为 /healthz。 + +可以发送 GET 请求,返回带有健康信息的 JSON 格式对象。例如获取健康状况,可以使用如下命令。 + +```bash +$ curl http://orderer:8443/healthz +{"status":"OK","time":"XXXX-YY-ZZT01:02:03.567890Z"} +$ curl http://peer:9443/healthz +{"status":"OK","time":"XXXX-YY-ZZT01:02:03.567890Z"} +``` + +目前健康状况支持检测链码容器运行的 Docker 服务的状态,未来会扩展支持更多组件健康状态。 + +### 获取系统统计信息 + +资源为 /metrics。 + +可以发送 GET 请求,返回各个指标的统计信息。例如获取当前统计信息,可以使用如下命令。 + +```bash +$ curl http://orderer:8443/metrics +# HELP blockcutter_block_fill_duration The time from first transaction enqueing to the block being cut in seconds. +# TYPE blockcutter_block_fill_duration histogram +blockcutter_block_fill_duration_bucket{channel="businesschannel",le="0.005"} 0 +blockcutter_block_fill_duration_bucket{channel="businesschannel",le="0.01"} 0 +blockcutter_block_fill_duration_bucket{channel="businesschannel",le="0.025"} 0 +... +process_virtual_memory_bytes 3.37268736e+08 +# HELP process_virtual_memory_max_bytes Maximum amount of virtual memory available in bytes. +# TYPE process_virtual_memory_max_bytes gauge +process_virtual_memory_max_bytes -1 + +$ curl http://peer:9443/metrics +# HELP chaincode_launch_duration The time to launch a chaincode. +# TYPE chaincode_launch_duration histogram +chaincode_launch_duration_bucket{chaincode="+lifecycle:1.4.0",success="true",le="0.005"} 1 +chaincode_launch_duration_bucket{chaincode="+lifecycle:1.4.0",success="true",le="0.01"} 1 +chaincode_launch_duration_bucket{chaincode="+lifecycle:1.4.0",success="true",le="0.025"} 1 +... +process_virtual_memory_bytes 4.21298176e+08 +# HELP process_virtual_memory_max_bytes Maximum amount of virtual memory available in bytes. +# TYPE process_virtual_memory_max_bytes gauge +process_virtual_memory_max_bytes -1 +``` + +Orderer 的统计信息包括切块时间、广播队列、校验时间、发送块数量、Go 进程信息、gRPC 请求、系统资源等,可以用来详细了解 Orderer 资源使用和工作情况。 + +Peer 的统计信息包括链码执行情况、Go 进程信息、gRPC 请求、区块处理、账本提交、数据库更新、系统资源等多个指标,可以实时了解 Peer 资源使用和工作情况。 + +当然,直接阅读这些统计指标并不高效,更方便的是通过外部监控工具。如果使用 StatsD 来分析数据,需要在 Peer 和 Orderer 配置文件中指定 StatsD 服务器地址(StatsD 是推送方式);如果使用 Prometheus,直接在其配置中指定 Peer 和 Orderer 的服务地址即可(Prometheus 是推送方式)。 + +以 Prometheus 为例,配置中指定 Peer 和 Orderer 地址后,Prometheus 会主动从 /metrics API 获取统计信息。此时通过 Prometheus 的图形界面(默认监听在 9090 端口)可以查看到这些指标的数据和统计图。 + +下图展示了链码 shim 层请求的执行延迟统计。 + +![使用 prometheus 监控 Fabric 网络](_images/prometheus.png) + +用户也可以集成使用更多第三方系统来监控和分析 Fabric 系统的监控数据,实现自动化的运维管理。 \ No newline at end of file diff --git a/chainbrock-learning/10_fabric_op/sdk.md b/chainbrock-learning/10_fabric_op/sdk.md new file mode 100644 index 00000000..d5a7d602 --- /dev/null +++ b/chainbrock-learning/10_fabric_op/sdk.md @@ -0,0 +1,33 @@ +## SDK 支持 + +除了基于命令行的客户端之外,超级账本 Fabric 提供了多种语言的 SDK,包括 Node.Js、Python、Java、Go 等。它们封装了 Fabric 网络中节点提供的 gRPC 服务接口,可以实现更方便的调用。 + +这些客户端 SDK 允许用户和应用跟 Fabric 网络进行交互,还可以实现更为复杂的操作,实现包括节点的启停、通道的创建和加入、链码的生命周期管理等操作。SDK 项目目前已经初步成熟,更多特性仍在开发中,感兴趣的读者可以通过如下途径获取到 SDK 的源码并进行尝试。 + +### 基于 Node.Js 实现的 SDK + +作为早期创建的 SDK 项目之一,Node.Js 实现的 SDK 目前已经支持了对 Fabric 链码的主要操作,包括安装链码、实例化并进行调用等,以及访问 Fabric CA 服务。内带了不少操作的例子可供参考。 + +源码仓库地址在 github.com/hyperledger/fabric-sdk-node。 + +源码的 test/integration/e2e 目录下包括了大量应用的示例代码,可供参考。 + +### 基于 Python 实现的 SDK + +早期创建的 SDK 项目之一。Python 实现的 SDK 目前已经完成了对 Fabric 链码的主要操作,包括安装链码、实例化并进行调用等,以及使用 Fabric CA 的基础功能。 + +源码仓库地址在 github.com/hyperledger/fabric-sdk-py。 + +源码的 test/integration 目录下包括了大量应用的示例代码,可供参考。 + +### 基于 Java 实现的 SDK + +属于较新的 SDK 项目。Java SDK 目前支持对 Fabric 中链码的主要操作,以及访问 Fabric CA 服务。 + +源码仓库地址在 github.com/hyperledger/fabric-sdk-java。 + +### 基于 Go 实现的 SDK + +属于较新的 SDK 项目。Go SDK 提取了原先 Fabric 中的相关代码,目前支持对 Fabric 中链码的主要操作。将来,Fabric 中的命令行客户端将可能基于该 SDK 重新实现。 + +源码仓库地址在 github.com/hyperledger/fabric-sdk-go。 diff --git a/chainbrock-learning/10_fabric_op/summary.md b/chainbrock-learning/10_fabric_op/summary.md new file mode 100644 index 00000000..da9a61f8 --- /dev/null +++ b/chainbrock-learning/10_fabric_op/summary.md @@ -0,0 +1,5 @@ +## 本章小结 + +本章详细讲解了管理 Fabric 网络的相关话题,包括如何操作和管理通道、链码的相关客户端命令,以及监听网络事件、探测网络信息、SDK 工具、运维服务和升级网络等。最后,对生产环境中部署 Fabric 网络的注意事项进行了讨论。 + +通过本章内容的学习和实践,相信读者可以掌握管理 Fabric 网络的相关技巧。更多的经验需要在生产实践积累和总结。 diff --git a/chainbrock-learning/10_fabric_op/upgrade.md b/chainbrock-learning/10_fabric_op/upgrade.md new file mode 100644 index 00000000..1a47e108 --- /dev/null +++ b/chainbrock-learning/10_fabric_op/upgrade.md @@ -0,0 +1,91 @@ +## 如何升级版本 + +Fabric 保持了较好的向后兼容性,从 v1.0.0 版本开始支持手动升级到更高版本。 + +网络升级主要包括对如下资源进行升级: + +* 核心组件:包括 Peer、Orderer、CA 等核心程序; +* 能力配置:更新通道配置中支持的能力集合版本号,以启动新的特性; +* 第三方资源:包括依赖的 CouchDB、Kafka 等第三方组件。 + +### 能力类型 + +为了避免网络多个节点运行不同版本组件时出现分叉风险,自 1.1.0 版本起在通道配置中引入了能力(Capabilities),标记节点应当支持和启用的特性。如果某节点程序版本低于能力要求则无法加入或自动退出;同时通道内高版本的节点程序在提交校验时只启用指定的特性集合检查(可参考 core/handlers/validation/builtin)。 + +目前能力分为三种类型,分别管理不同范围,如下表所示。 + +类型 | 功能 | 配置路径 +--- | --- | --- +通道(Channel)能力| 通道整体相关能力,排序和 Peer 节点都得满足 | /Channel/Capabilities +排序(Orderer)能力| 排序服务能力,只与排序节点有关 | /Channel/Orderer/Capabilities +应用(Application)能力| 应用相关能力,只与 Peer 节点有关 | /Channel/Application/Capabilities + +如果要启用相应的能力,需要修改通道配置内对应配置。例如,用户可以指定通道能力为 v1.1.0,排序能力为 v1.1.0 模式下,而应用能力为 v1.3.0。此时,只有不低于 v1.1.0 版本(满足通道和排序能力的较大者)的排序节点,以及不低于 v1.3.0 版本(满足通道和应用能力的较大者)的 Peer 节点可以支持该通道。同时,即使排序节点和 Peer 节点程序版本更新(如 v2.x),仍然只会启用指定的能力集合。 + +需要注意能力配置只能调整到更新版本而不应回退,例如可以将能力模式 v1.3.0 更新为更高版本的 v1.4.0,反之无意义。这是因为旧版本的节点即便加入到通道内,仍然无法正常处理其中新版本启用阶段的交易。 + +其中,各能力集合的版本和内容(可参考 common/capabilities)如下表所示,注意并不与程序版本一致。 + +能力版本 | 起始程序版本 | 类型 | 能力内容 +--- | --- | --- | --- +ChannelV1_1 | v1.1.0 | 通道 | 仅供标记,程序版本为 1.1.0+ +ChannelV1_3 | v1.3.0 | 通道 | 支持 idemix +OrdererV1_1 | v1.1.0 | 排序 | 重新提交和身份超时检查 +OrdererV2_0 | v2.0.0 | 排序 | 排序服务支持从 Kafka 切换到 Raft +ApplicationV1_1 |v1.1.0 | 应用 | 禁止区块内重复交易Id +ApplicationV1_2 |v1.2.0 | 应用 | 正式支持私有数据,支持升级私有数据成员组配置,细粒度的通道资源访问控制(ACL) +ApplicationV1_3 |v1.3.0 | 应用 | 支持基于键值的背书 +ApplicationV2_0 |v2.0.0 | 应用 | 新的链码生命周期管理 +ApplicationV2_0 |v2.0.0 | 应用 | 支持 FabToken +ApplicationV2_0 |v2.0.0 | 应用 | 支持链码操作 + + +### 推荐升级步骤 + +#### 升级排序服务 + +对于不改变排序模式的情况下,升级较为简单。 + +逐个停止排序节点,并备份本地数据,包括身份文件、账本数据、配置文件等。 + +升级排序服务程序。重新启动并检查是否工作正常,如获取区块、发送交易等。 + +如果需要改变排序模式(Kafka 变为 Raft)的情况,TBD。 + +#### 升级 Peer 节点 + +逐个停止 Peer 节点,并备份本地数据,包括身份文件、账本数据、链码包、配置文件等。 + +升级 Peer 程序。重新启动并检查是否工作正常,如查询信息、发送交易提案等。 + +链码包如果之前有引入旧的第三方库或者 Shim 包,或者需要启用新的 API,则还要执行链码升级操作。 + +#### 升级 CA 服务 + +停止 Fabric-CA 服务,备份数据库。 + +升级 fabric-ca 程序,重新启动并检查是否工作正常,如获取根证书。 + +```bash +$ fabric-ca-client getcacert -u https://:7054 --tls.certfiles tls-cert.pem +``` + +#### 升级通道配置 + +按照新的格式发送通道更新请求,特别是修改对应能力域值为新的版本。 + +首先升级系统通道,更新通道和排序能力值,之后升级应用通道,更新应用相关能力 + +更新后测试网络功能,如获取新的区块正常。 + +#### 升级第三方组件 + +包括 CouchDB、Kafka 等第三方组件,升级之前最好备份数据文件。 + +CouchDB 版本自 1.x 版本可以很容易升级到高版本,具体操作可以参考项目文档:http://docs.couchdb.org/en/stable/install/upgrading.html。 + +如果仍然使用 Kafka 模式的排序服务,则还可以升级 Kafka。 + +Kafka 自 0.10.0.x 版本开始保持了较好的兼容性,可以较为容易升级到更高版本。之前版本也可执行滚动升级,可参考项目文档:http://docs.couchdb.org/en/stable/install/upgrading.html。 + +Kafka 版本更新后需要更新 orderer.yaml 中的 Kafka.Version 域并重启 Orderer。 diff --git a/chainbrock-learning/11_app_dev/README.md b/chainbrock-learning/11_app_dev/README.md new file mode 100644 index 00000000..89a93adf --- /dev/null +++ b/chainbrock-learning/11_app_dev/README.md @@ -0,0 +1,9 @@ +# 智能合约开发 + +** 代码即律法(Code is law)。 ** + +智能合约丰富了区块链技术的适用范围,让分布式账本支持大规模的商业应用成为可能。 + +区块链应用开发者不光需要理解业务逻辑,还要能够开发智能合约和用户应用。超级账本 Fabric 的链码支持主流编程语言如 Go、Java、Node,并提供了链码开发框架,简化了分布式应用的开发过程。 + +本章将介绍 Fabric 链码的基本概念、结构和核心 API,并通过案例演示如何实现典型区块链应用,最后还介绍了外部链码机制,讨论了应用开发的最佳实践。通过本章学习,读者将掌握设计和开发链码的实践技巧。 \ No newline at end of file diff --git a/chainbrock-learning/11_app_dev/chaincode.md b/chainbrock-learning/11_app_dev/chaincode.md new file mode 100644 index 00000000..57f5b43e --- /dev/null +++ b/chainbrock-learning/11_app_dev/chaincode.md @@ -0,0 +1,77 @@ +## 链码概念与结构 + +超级账本 Fabric 中的链码(Chaincode)延伸自智能合约的概念,负责对应用程序发送的请求做出响应,执行代码逻辑,实现与账本进行交互。 + +区块链网络中成员协商好业务逻辑后,可将其编程到链码中,所有业务流程将遵循合约代码自动执行。 + +链码执行过程中可以创建状态(State)并写入账本中。状态绑定到链码的命名空间,仅限该链码访问。在合适许可下,链码可以调用另一个链码,间接访问其状态。在一些场景下,不仅需要访问状态当前值,还需要查询状态的历史值。 + +原生链码默认在 Docker 容器中执行,2.0 版本中开始支持外部链码。链码通过 gRPC 协议与 Peer 节点进行交互,包括读写账本、返回响应结果等。 + +Fabric 支持多种语言实现的链码,包括 Go、JavaScript、Java 等。下面以 Go 语言为例介绍链码接口和相关结构。 + +### Chaincode 接口 + +每个链码都需要实现以下 Chaincode 接口,包括 Init 和 Invoke 两个方法。 + +```go +type Chaincode interface { + Init(stub ChaincodeStubInterface) pb.Response + Invoke(stub ChaincodeStubInterface) pb.Response +} +``` + +* Init:当链码收到初始化指令时,Init 方法会被调用。 +* Invoke:当链码收到调用(invoke)或查询(query)调用时,Invoke 方法会被调用。 + +### 链码结构 + +一个链码的必要结构如下所示: + +```go +package main + +// 引入必要的包 +import ( + "github.com/hyperledger/fabric-chaincode-go/shim" + pb "github.com/hyperledger/fabric-protos-go/peer" +) + +// 声明一个结构体 +type SimpleChaincode struct {} + +// 为结构体添加 Init 方法 +func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { + // 在该方法中实现链码初始化或升级时的处理逻辑 + // 编写时可灵活使用 stub 中的 API +} + +// 为结构体添加 Invoke 方法 +func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { + // 在该方法中实现链码运行中被调用或查询时的处理逻辑 + // 编写时可灵活使用 stub 中的 API +} + +// 主函数,需要调用 shim.Start() 方法 +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +} +``` + +#### 依赖包 + +从 `import` 代码段可以看到,链码需要引入如下的依赖包。 + +* `"github.com/hyperledger/fabric-chaincode-go/shim"`:shim 包提供了链码与账本交互的中间层。链码通过 `shim.ChaincodeStub` 提供的方法来读取和修改账本状态。 +* `pb "github.com/hyperledger/fabric-protos-go/peer"`: Init 和 Invoke 方法需要返回 `pb.Response` 类型。 + +#### Init 和 Invoke 方法 + +编写链码,关键是要实现 Init 和 Invoke 这两个方法。 + +当初始化链码时,Init 方法会被调用。如同名字所描述的,该方法用来完成一些初始化的工作。当调用链码时,Invoke 方法被调用,主要业务逻辑都需要在该方法中实现。 + +Init 或 Invoke 方法以 `stub shim.ChaincodeStubInterface` 作为传入参数,`pb.Response` 作为返回类型。其中,`stub` 封装了丰富的 API,功能包括对账本进行操作、读取交易参数、调用其它链码等。 diff --git a/chainbrock-learning/11_app_dev/chaincode_example01.go b/chainbrock-learning/11_app_dev/chaincode_example01.go new file mode 100644 index 00000000..3cad0359 --- /dev/null +++ b/chainbrock-learning/11_app_dev/chaincode_example01.go @@ -0,0 +1,115 @@ +/* +Copyright IBM Corp 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "errors" + "fmt" + + "github.com/hyperledger/fabric/core/chaincode/shim" +) + +// SimpleChaincode example simple Chaincode implementation +type SimpleChaincode struct { +} + +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +} + +// Init resets all the things +func (t *SimpleChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting 1") + } + + err := stub.PutState("hello_world", []byte(args[0])) + if err != nil { + return nil, err + } + + return nil, nil +} + +// Invoke isur entry point to invoke a chaincode function +func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { + fmt.Println("invoke is running " + function) + + // Handle different functions + if function == "init" { + return t.Init(stub, "init", args) + } else if function == "write" { + return t.write(stub, args) + } + fmt.Println("invoke did not find func: " + function) + + return nil, errors.New("Received unknown function invocation") +} + +// Query is our entry point for queries +func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { + fmt.Println("query is running " + function) + + // Handle different functions + if function == "read" { //read a variable + return t.read(stub, args) + } + fmt.Println("query did not find func: " + function) + + return nil, errors.New("Received unknown function query") +} + +// write - invoke function to write key/value pair +func (t *SimpleChaincode) write(stub *shim.ChaincodeStub, args []string) ([]byte, error) { + var key, value string + var err error + fmt.Println("running write()") + + if len(args) != 2 { + return nil, errors.New("Incorrect number of arguments. Expecting 2. name of the key and value to set") + } + + key = args[0] //rename for funsies + value = args[1] + err = stub.PutState(key, []byte(value)) //write the variable into the chaincode state + if err != nil { + return nil, err + } + return nil, nil +} + +// read - query function to read key/value pair +func (t *SimpleChaincode) read(stub *shim.ChaincodeStub, args []string) ([]byte, error) { + var key, jsonResp string + var err error + + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting name of the key to query") + } + + key = args[0] + valAsbytes, err := stub.GetState(key) + if err != nil { + jsonResp = "{\"Error\":\"Failed to get state for " + key + "\"}" + return nil, errors.New(jsonResp) + } + + return valAsbytes, nil +} diff --git a/chainbrock-learning/11_app_dev/chaincode_example01.md b/chainbrock-learning/11_app_dev/chaincode_example01.md new file mode 100644 index 00000000..68ba06b6 --- /dev/null +++ b/chainbrock-learning/11_app_dev/chaincode_example01.md @@ -0,0 +1,87 @@ +## 链码示例一:信息公证 +### 简介 + +[chaincode_example01.go](chaincode_example01.go) 主要实现如下的功能: + +* 初始化,以键值形式存放信息; +* 允许读取和修改键值。 + +代码中,首先初始化了 `hello_world` 的值,并根据请求中的参数创建修改查询链上 `key` 中的值,本质上实现了一个简单的可修改的键值数据库。 + +### 主要函数 + +* `read`:读取key `args[0]` 的 value; +* `write`:创建或修改 key `args[0]` 的 value; +* `init`:初始化 key `hello_world` 的 value; +* `invoke`:根据传递参数类型调用执行相应的 `init` 和 `write` 函数; +* `query`:调用 `read` 函数查询 `args[0]` 的 value。 + +### 代码运行分析 + +`main` 函数作为程序的入口,调用 shim 包的 start 函数,启动 chaincode 引导程序的入口节点。如果报错,则返回。 + +```go +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +} +``` + +当智能合约部署在区块链上,可以通过 rest api 进行交互。 + +三个主要的函数是 `init`,`invoke`,`query`。在三个函数中,通过 `stub.PutState`与 `stub.GetState` 存储访问 ledger 上的键值对。 + +### 通过 REST API 操作智能合约 + +假设以 jim 身份登录 pbft 集群,请求部署该 chaincode 的 json 请求格式为: +```json +{ + "jsonrpc": "2.0", + "method": "deploy", + "params": { + "type": 1, + "chaincodeID": { + "path": "https://github.com/ibm-blockchain/learn-chaincode/finished" + }, + "ctorMsg": { + "function": "init", + "args": [ + "hi there" + ] + }, + "secureContext": "jim" + }, + "id": 1 +} +``` + +目前 path 仅支持 github 上的目录,ctorMsg 中为函数 `init` 的传参。 + +调用 invoke 函数的 json 格式为: + +```json +{ + "jsonrpc": "2.0", + "method": "invoke", + "params": { + "type": 1, + "chaincodeID": { + "name": "4251b5512bad70bcd0947809b163bbc8398924b29d4a37554f2dc2b033617c19cc0611365eb4322cf309b9a5a78a5dba8a5a09baa110ed2d8aeee186c6e94431" + }, + "ctorMsg": { + "function": "init", + "args": [ + "swb" + ] + }, + "secureContext": "jim" + }, + "id": 2 +} +``` + +其中 name 字段为 `deploy` 后返回的 message 字段中的字符串。 + +`query` 的接口也是类似的。 diff --git a/chainbrock-learning/11_app_dev/chaincode_example02.go b/chainbrock-learning/11_app_dev/chaincode_example02.go new file mode 100644 index 00000000..d0272985 --- /dev/null +++ b/chainbrock-learning/11_app_dev/chaincode_example02.go @@ -0,0 +1,185 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of +//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has +//to be modified as well with the new ID of chaincode_example02. +//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of +//hard-coding. + +import ( + "errors" + "fmt" + "strconv" + + "github.com/hyperledger/fabric/core/chaincode/shim" +) + +// SimpleChaincode example simple Chaincode implementation +type SimpleChaincode struct { +} + +func (t *SimpleChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { + var A, B string // Entities + var Aval, Bval int // Asset holdings + var err error + + if len(args) != 4 { + return nil, errors.New("Incorrect number of arguments. Expecting 4") + } + + // Initialize the chaincode + A = args[0] + Aval, err = strconv.Atoi(args[1]) + if err != nil { + return nil, errors.New("Expecting integer value for asset holding") + } + B = args[2] + Bval, err = strconv.Atoi(args[3]) + if err != nil { + return nil, errors.New("Expecting integer value for asset holding") + } + fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) + + // Write the state to the ledger + err = stub.PutState(A, []byte(strconv.Itoa(Aval))) + if err != nil { + return nil, err + } + + err = stub.PutState(B, []byte(strconv.Itoa(Bval))) + if err != nil { + return nil, err + } + + return nil, nil +} + +// Transaction makes payment of X units from A to B +func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { + if function == "delete" { + // Deletes an entity from its state + return t.delete(stub, args) + } + + var A, B string // Entities + var Aval, Bval int // Asset holdings + var X int // Transaction value + var err error + + if len(args) != 3 { + return nil, errors.New("Incorrect number of arguments. Expecting 3") + } + + A = args[0] + B = args[1] + + // Get the state from the ledger + // TODO: will be nice to have a GetAllState call to ledger + Avalbytes, err := stub.GetState(A) + if err != nil { + return nil, errors.New("Failed to get state") + } + if Avalbytes == nil { + return nil, errors.New("Entity not found") + } + Aval, _ = strconv.Atoi(string(Avalbytes)) + + Bvalbytes, err := stub.GetState(B) + if err != nil { + return nil, errors.New("Failed to get state") + } + if Bvalbytes == nil { + return nil, errors.New("Entity not found") + } + Bval, _ = strconv.Atoi(string(Bvalbytes)) + + // Perform the execution + X, err = strconv.Atoi(args[2]) + Aval = Aval - X + Bval = Bval + X + fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) + + // Write the state back to the ledger + err = stub.PutState(A, []byte(strconv.Itoa(Aval))) + if err != nil { + return nil, err + } + + err = stub.PutState(B, []byte(strconv.Itoa(Bval))) + if err != nil { + return nil, err + } + + return nil, nil +} + +// Deletes an entity from state +func (t *SimpleChaincode) delete(stub *shim.ChaincodeStub, args []string) ([]byte, error) { + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting 1") + } + + A := args[0] + + // Delete the key from the state in ledger + err := stub.DelState(A) + if err != nil { + return nil, errors.New("Failed to delete state") + } + + return nil, nil +} + +// Query callback representing the query of a chaincode +func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { + if function != "query" { + return nil, errors.New("Invalid query function name. Expecting \"query\"") + } + var A string // Entities + var err error + + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query") + } + + A = args[0] + + // Get the state from the ledger + Avalbytes, err := stub.GetState(A) + if err != nil { + jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}" + return nil, errors.New(jsonResp) + } + + if Avalbytes == nil { + jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}" + return nil, errors.New(jsonResp) + } + + jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}" + fmt.Printf("Query Response:%s\n", jsonResp) + return Avalbytes, nil +} + +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +} diff --git a/chainbrock-learning/11_app_dev/chaincode_example02.md b/chainbrock-learning/11_app_dev/chaincode_example02.md new file mode 100644 index 00000000..dd275037 --- /dev/null +++ b/chainbrock-learning/11_app_dev/chaincode_example02.md @@ -0,0 +1,41 @@ +## 链码示例二:交易资产 + +### 简介 + +[chaincode_example02.go](chaincode_example02.go) 主要实现如下的功能: + +* 初始化 A、B 两个账户,并为两个账户赋初始资产值; +* 在 A、B 两个账户之间进行资产交易; +* 分别查询 A、B 两个账户上的余额,确认交易成功; +* 删除账户。 + +### 主要函数 + +* `init`:初始化 A、B 两个账户; +* `invoke`:实现 A、B 账户间的转账; +* `query`:查询 A、B 账户上的余额; +* `delete`:删除账户。 + +### 依赖的包 +```go +import ( + "errors" + "fmt" + "strconv" + + "github.com/hyperledger/fabric/core/chaincode/shim" +) +``` +`strconv` 实现 int 与 string 类型之间的转换。 + +在invoke 函数中,存在: +```go +X, err = strconv.Atoi(args[2]) + Aval = Aval - X + Bval = Bval + X +``` + +当 `args[2]<0` 时,A 账户余额增加,否则 B 账户余额减少。 + +### 可扩展功能 +实例中未包含新增账户并初始化的功能。开发者可以根据自己的业务模型进行添加。 diff --git a/chainbrock-learning/11_app_dev/chaincode_example03.go b/chainbrock-learning/11_app_dev/chaincode_example03.go new file mode 100644 index 00000000..3d20a3fc --- /dev/null +++ b/chainbrock-learning/11_app_dev/chaincode_example03.go @@ -0,0 +1,722 @@ +/* + author:swb + time:16/7/05 + MIT License +*/ + +package main + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + "time" + + "github.com/hyperledger/fabric/core/chaincode/shim" +) + +var bankNo int = 0 +var cpNo int = 0 +var transactionNo int = 0 + +// SimpleChaincode example simple Chaincode implementation +type SimpleChaincode struct { +} + +type CenterBank struct { + Name string + TotalNumber int + RestNumber int +} + +type Bank struct { + Name string + TotalNumber int + RestNumber int + ID int +} + +type Company struct { + Name string + Number int + ID int +} + +type Transaction struct { + FromType int //CenterBank 0 Bank 1 Company 1 + FromID int + ToType int //Bank 1 Company 2 + ToID int + Time int64 + Number int + ID int +} + +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +} + +// Init resets all the things +func (t *SimpleChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { + if len(args) != 2 { + return nil, errors.New("Incorrect number of arguments. Expecting 2") + } + var totalNumber int + var centerBank CenterBank + var cbBytes []byte + totalNumber, err := strconv.Atoi(args[1]) + if err != nil { + return nil, errors.New("Expecting integer value for asset holding") + } + centerBank = CenterBank{Name: args[0], TotalNumber: totalNumber, RestNumber: 0} + err = writeCenterBank(stub,centerBank) + if err != nil { + return nil, errors.New("write Error" + err.Error()) + } + + cbBytes,err = json.Marshal(¢erBank) + if err!= nil{ + return nil,errors.New("Error retrieving cbBytes") + } + return cbBytes, nil +} + +// Invoke isur entry point to invoke a chaincode function +func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { + if function == "createBank" { + return t.createBank(stub, args) + } else if function == "createCompany" { + return t.createCompany(stub, args) + } else if function == "issueCoin" { + return t.issueCoin(stub, args) + } else if function == "issueCoinToBank" { + return t.issueCoinToBank(stub, args) + } else if function == "issueCoinToCp" { + return t.issueCoinToCp(stub, args) + } else if function =="transfer"{ + return t.transfer(stub,args) + } + + return nil, errors.New("Received unknown function invocation") +} + +func (t *SimpleChaincode) createBank(stub *shim.ChaincodeStub, args []string) ([]byte, error) { + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting 1") + } + var bank Bank + var bankBytes []byte + var centerBank CenterBank + + bank = Bank{Name:args[0],TotalNumber:0,RestNumber:0,ID:bankNo} + + err := writeCenterBank(stub,centerBank) + if err != nil { + return nil, errors.New("write Error" + err.Error()) + } + + bankBytes,err = json.Marshal(&bank) + if err!= nil{ + return nil,errors.New("Error retrieving cbBytes") + } + + bankNo = bankNo +1 + return bankBytes, nil +} + +func (t *SimpleChaincode) createCompany(stub *shim.ChaincodeStub, args []string) ([]byte, error) { + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting 1") + } + var company Company + company = Company{Name:args[0],Number:0,ID:cpNo} + + err := writeCompany(stub,company) + if err != nil{ + return nil, errors.New("write Error" + err.Error()) + } + + cpBytes,err := json.Marshal(&company) + if(err!=nil){ + return nil,err + } + + cpNo = cpNo +1 + return cpBytes, nil +} + +func (t *SimpleChaincode) issueCoin(stub *shim.ChaincodeStub, args []string) ([]byte, error) { + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting 1") + } + var centerBank CenterBank + var tsBytes []byte + + issueNumber ,err:= strconv.Atoi(args[0]) + if err!=nil{ + return nil,errors.New("want Integer number") + } + centerBank,_,err = getCenterBank(stub) + if err !=nil{ + return nil,errors.New("get errors") + } + + centerBank.TotalNumber = centerBank.TotalNumber + issueNumber + centerBank.RestNumber = centerBank.RestNumber + issueNumber + + err = writeCenterBank(stub,centerBank) + if err != nil { + return nil, errors.New("write Error" + err.Error()) + } + + transaction := Transaction{FromType:0,FromID:0,ToType:0,ToID:0,Time:time.Now().Unix(),Number:issueNumber,ID:transactionNo} + err = writeTransaction(stub,transaction) + if err != nil { + return nil, errors.New("write Error" + err.Error()) + } + + tsBytes,err = json.Marshal(&transaction) + if err != nil { + fmt.Println("Error unmarshalling centerBank") + } + + transactionNo = transactionNo +1 + return tsBytes, nil +} + +func (t *SimpleChaincode) issueCoinToBank(stub *shim.ChaincodeStub, args []string) ([]byte, error) { + if len(args) != 2 { + return nil, errors.New("Incorrect number of arguments. Expecting 2") + } + + var centerBank CenterBank + var bank Bank + var bankId string + var issueNumber int + var tsBytes []byte + var err error + var bankIdInt int + + bankId = args[0] + bankIdInt,err = strconv.Atoi(args[0]) + if err!=nil{ + return nil,errors.New("want Integer number") + } + issueNumber,err = strconv.Atoi(args[1]) + if err!=nil{ + return nil,errors.New("want Integer number") + } + + centerBank,_,err = getCenterBank(stub) + if err !=nil{ + return nil,errors.New("get errors") + } + if centerBank.RestNumber + "Gymgle" + MIT License +*/ + +package main + +import ( + "crypto/md5" + "crypto/rand" + "encoding/base64" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "strconv" + "time" + + "github.com/hyperledger/fabric/core/chaincode/shim" + pb "github.com/hyperledger/fabric/protos/peer" +) + +type SimpleChaincode struct { +} + +var BackGroundNo int = 0 +var RecordNo int = 0 + +type School struct { + Name string + Location string + Address string + PriKey string + PubKey string + StudentAddress []string +} + +type Student struct { + Name string + Address string + BackgroundId []int +} + +// 学历信息,当离开学校才能记入 +type Background struct { + Id int + ExitTime int64 + Status string //0:毕业 1:退学 +} + +type Record struct { + Id int + SchoolAddress string + StudentAddress string + SchoolSign string + ModifyTime int64 + ModifyOperation string // 0:正常毕业 1:退学 2:入学 +} + +/* + * 区块链网络实例化"diploma"智能合约时调用该方法 + */ +func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { + return shim.Success(nil) +} + +/* + * 客户端发起请求执行"diploma"智能合约时会调用 Invoke 方法 + */ +func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { + // 获取请求调用智能合约的方法和参数 + function, args := stub.GetFunctionAndParameters() + // Route to the appropriate handler function to interact with the ledger appropriately + if function == "createSchool" { + return t.createSchool(stub, args) + } else if function == "createStudent" { + return t.createStudent(stub, args) + } else if function == "enrollStudent" { + return t.enrollStudent(stub, args) + } else if function == "updateDiploma" { + return t.updateDiploma(stub, args) + } else if function == "getRecords" { + return t.getRecords(stub) + } else if function == "getRecordById" { + return t.getRecordById(stub, args) + } else if function == "getStudentByAddress" { + return t.getStudentByAddress(stub, args) + } else if function == "getSchoolByAddress" { + return t.getSchoolByAddress(stub, args) + } else if function == "getBackgroundById" { + return t.getBackgroundById(stub, args) + } + return shim.Success(nil) +} + +/* + * 添加一所新学校 + * args[0] 学校名称 + * args[1] 学校所在位置 + */ +func (t *SimpleChaincode) createSchool(stub shim.ChaincodeStubInterface, args []string) pb.Response { + if len(args) != 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + var school School + var schoolBytes []byte + var stuAddress []string + var address, priKey, pubKey string + address, priKey, pubKey = GetAddress() + + school = School{Name: args[0], Location: args[1], Address: address, PriKey: priKey, PubKey: pubKey, StudentAddress: stuAddress} + err := writeSchool(stub, school) + if err != nil { + shim.Error("Error write school") + } + + schoolBytes, err = json.Marshal(&school) + if err != nil { + return shim.Error("Error retrieving schoolBytes") + } + + return shim.Success(schoolBytes) +} + +/* + * 添加一名新学生 + * args[0] 学生的姓名 + */ +func (t *SimpleChaincode) createStudent(stub shim.ChaincodeStubInterface, args []string) pb.Response { + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + var student Student + var studentBytes []byte + var stuAddress string + var bgID []int + stuAddress, _, _ = GetAddress() + + student = Student{Name: args[0], Address: stuAddress, BackgroundId: bgID} + err := writeStudent(stub, student) + if err != nil { + return shim.Error("Error write student") + } + + studentBytes, err = json.Marshal(&student) + if err != nil { + return shim.Error("Error retrieving studentBytes") + } + + return shim.Success(studentBytes) +} + +/* + * 学校招生(返回学校信息) + * args[0] 学校账户地址 + * args[1] 学校签名 + * args[2] 学生账户地址 + */ +func (t *SimpleChaincode) enrollStudent(stub shim.ChaincodeStubInterface, args []string) pb.Response { + if len(args) != 3 { + return shim.Error("Incorrect number of arguments. Expecting 3") + } + + schAddress := args[0] + schoolSign := args[1] + stuAddress := args[2] + + var school School + var schBytes []byte + var err error + + // 根据学校账户地址获取学校信息 + schBytes, err = stub.GetState(schAddress) + if err != nil { + return shim.Error("Error retrieving data") + } + err = json.Unmarshal(schBytes, &school) + if err != nil { + return shim.Error("Error unmarshalling data") + } + + var record Record + record = Record{Id: RecordNo, SchoolAddress: schAddress, StudentAddress: stuAddress, SchoolSign: schoolSign, ModifyTime: time.Now().Unix(), ModifyOperation: "2"} // 2 表示入学 + + err = writeRecord(stub, record) + if err != nil { + return shim.Error("Error write record") + } + + school.StudentAddress = append(school.StudentAddress, stuAddress) + err = writeSchool(stub, school) + if err != nil { + return shim.Error("Error write school") + } + + RecordNo = RecordNo + 1 + recordBytes, err := json.Marshal(&record) + if err != nil { + return shim.Error("Error retrieving recordBytes") + } + + return shim.Success(recordBytes) +} + +/* + * 由学校更新学生学历信息,并签名(返回记录信息) + * args[0] 学校账户地址 + * args[1] 学校签名 + * args[2] 待修改学生的账户地址 + * args[3] 对该学生的学历进行怎样的修改,0:正常毕业 1:退学 + */ +func (t *SimpleChaincode) updateDiploma(stub shim.ChaincodeStubInterface, args []string) pb.Response { + if len(args) != 4 { + return shim.Error("Incorrect number of arguments. Expecting 4") + } + + schAddress := args[0] + schoolSign := args[1] + stuAddress := args[2] + modOperation := args[3] + + var recordBytes []byte + var student Student + var stuBytes []byte + var err error + + // 根据学生账户地址获取学生信息 + stuBytes, err = stub.GetState(stuAddress) + if err != nil { + return shim.Error("Error retrieving data") + } + err = json.Unmarshal(stuBytes, &student) + if err != nil { + return shim.Error("Error unmarshalling data") + } + + var record Record + record = Record{Id: RecordNo, SchoolAddress: schAddress, StudentAddress: stuAddress, SchoolSign: schoolSign, ModifyTime: time.Now().Unix(), ModifyOperation: modOperation} + + err = writeRecord(stub, record) + if err != nil { + return shim.Error("Error write record") + } + + var background Background + background = Background{Id: BackGroundNo, ExitTime: time.Now().Unix(), Status: modOperation} + err = writeBackground(stub, background) + if err != nil { + return shim.Error("Error write background") + } + + // 如果学生正常毕业,也要更新学生的教育背景 + if modOperation == "0" { + student.BackgroundId = append(student.BackgroundId, BackGroundNo) + student = Student{Name: student.Name, Address: student.Address, BackgroundId: student.BackgroundId} + err = writeStudent(stub, student) + if err != nil { + return shim.Error("Error write student") + } + } + + BackGroundNo = BackGroundNo + 1 + recordBytes, err = json.Marshal(&record) + if err != nil { + return shim.Error("Error retrieving schoolBytes") + } + + return shim.Success(recordBytes) +} + +/* + * 通过学生的地址获取学生的学历信息 + * args[0] address + */ +func (t *SimpleChaincode) getStudentByAddress(stub shim.ChaincodeStubInterface, args []string) pb.Response { + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + stuBytes, err := stub.GetState(args[0]) + if err != nil { + shim.Error("Error retrieving data") + } + return shim.Success(stuBytes) +} + +/* + * 通过地址获取学校的信息 + * args[0] address + */ +func (t *SimpleChaincode) getSchoolByAddress(stub shim.ChaincodeStubInterface, args []string) pb.Response { + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + schBytes, err := stub.GetState(args[0]) + if err != nil { + shim.Error("Error retrieving data") + } + return shim.Success(schBytes) +} + +/* + * 通过 Id 获取记录 + * args[0] 记录的 Id + */ +func (t *SimpleChaincode) getRecordById(stub shim.ChaincodeStubInterface, args []string) pb.Response { + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + recBytes, err := stub.GetState("Record" + args[0]) + if err != nil { + return shim.Error("Error retrieving data") + } + + return shim.Success(recBytes) +} + +/* + * 获取全部记录(如果记录数大于10,返回前10个) + */ +func (t *SimpleChaincode) getRecords(stub shim.ChaincodeStubInterface) pb.Response { + var records []Record + var number string + var err error + var record Record + var recBytes []byte + if RecordNo < 10 { + i := 0 + for i <= RecordNo { + number = strconv.Itoa(i) + recBytes, err = stub.GetState("Record" + number) + if err != nil { + return shim.Error("Error get detail") + } + err = json.Unmarshal(recBytes, &record) + if err != nil { + return shim.Error("Error unmarshalling data") + } + records = append(records, record) + i = i + 1 + } + } else { + i := 0 + for i < 10 { + number = strconv.Itoa(i) + recBytes, err = stub.GetState("Record" + number) + if err != nil { + return shim.Error("Error get detail") + } + err = json.Unmarshal(recBytes, &record) + if err != nil { + return shim.Error("Error unmarshalling data") + } + records = append(records, record) + i = i + 1 + } + } + recordsBytes, err := json.Marshal(&records) + if err != nil { + shim.Error("Error get records") + } + return shim.Success(recordsBytes) +} + +/* + * 通过 Id 获取所存储的学历信息 + * args[0] ID + */ +func (t *SimpleChaincode) getBackgroundById(stub shim.ChaincodeStubInterface, args []string) pb.Response { + backBytes, err := stub.GetState("BackGround" + args[0]) + if err != nil { + return shim.Error("Error retrieving data") + } + return shim.Success(backBytes) +} + +func writeRecord(stub shim.ChaincodeStubInterface, record Record) error { + var recID string + recordBytes, err := json.Marshal(&record) + if err != nil { + return err + } + + recID = strconv.Itoa(record.Id) + err = stub.PutState("Record"+recID, recordBytes) + if err != nil { + return errors.New("PutState Error" + err.Error()) + } + return nil +} + +func writeSchool(stub shim.ChaincodeStubInterface, school School) error { + schBytes, err := json.Marshal(&school) + if err != nil { + return err + } + + err = stub.PutState(school.Address, schBytes) + if err != nil { + return errors.New("PutState Error" + err.Error()) + } + return nil +} + +func writeStudent(stub shim.ChaincodeStubInterface, student Student) error { + stuBytes, err := json.Marshal(&student) + if err != nil { + return err + } + + err = stub.PutState(student.Address, stuBytes) + if err != nil { + return errors.New("PutState Error" + err.Error()) + } + return nil +} + +func writeBackground(stub shim.ChaincodeStubInterface, background Background) error { + var backID string + backBytes, err := json.Marshal(&background) + if err != nil { + return err + } + + backID = strconv.Itoa(background.Id) + err = stub.PutState("BackGround"+backID, backBytes) + if err != nil { + return errors.New("PutState Error" + err.Error()) + } + return nil +} + +/* + * 生成Address + */ +func GetAddress() (string, string, string) { + var address, priKey, pubKey string + b := make([]byte, 48) + + if _, err := io.ReadFull(rand.Reader, b); err != nil { + return "", "", "" + } + + h := md5.New() + h.Write([]byte(base64.URLEncoding.EncodeToString(b))) + + address = hex.EncodeToString(h.Sum(nil)) + priKey = address + "1" + pubKey = address + "2" + + return address, priKey, pubKey +} + +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +} diff --git a/chainbrock-learning/11_app_dev/chaincode_example04.md b/chainbrock-learning/11_app_dev/chaincode_example04.md new file mode 100644 index 00000000..62199566 --- /dev/null +++ b/chainbrock-learning/11_app_dev/chaincode_example04.md @@ -0,0 +1,166 @@ +### 学历认证 +#### 功能描述 +该 [智能合约](chaincode_example04.go) 实现了一个简单的征信管理的案例。针对于学历认证领域,由于条约公开,在条约外无法随意篡改的特性,天然具备稳定性和中立性。 + +该智能合约中三种角色如下: +- 学校 +- 个人 +- 需要学历认证的机构或公司 + +学校可以根据相关信息在区块链上为某位个人授予学历,相关机构可以查询某人的学历信息,由于使用私钥签名,确保了信息的真实有效。 +为了简单,尽量简化相关的业务,另未完成学业的学生因违纪或外出创业退学,学校可以修改其相应的学历信息。 + +账户私钥应该由安装在本地的客户端生成,本例中为了简便,使用模拟私钥和公钥。 + +#### 数据结构设计 +- 学校 + - 名称 + - 所在位置 + - 账号地址 + - 账号公钥 + - 账户私钥 + - 学校学生 +- 个人 + - 姓名 + - 账号地址 + - 过往学历 +- 学历信息 + - 学历信息编号 + - 就读学校 + - 就读年份 + - 完成就读年份 + - 就读状态 // 0:毕业 1:退学 +- 修改记录(入学也相当于一种修改记录) + - 编号 + - 学校账户地址(一般根据账户地址可以算出公钥地址,然后可以进行校验) + - 学校签名 + - 个人账户地址 + - 个人公钥地址(个人不需要公钥地址) + - 修改时间 + - 修改操作// 0:正常毕业 1:退学 2:入学 + +对学历操作信息所有的操作都归为记录。 +#### function及各自实现的功能 +- `init` 初始化函数 +- `invoke` 调用合约内部的函数 + +- `updateDiploma` 由学校更新学生学历信息,并签名(返回记录信息) +- `enrollStudent` 学校招生(返回学校信息) +- `createSchool` 添加一名新学校 +- `createStudent` 添加一名新学生 +- `getStudentByAddress` 通过学生的账号地址访问学生的学历信息 +- `getRecordById` 通过Id获取记录 +- `getRecords` 获取全部记录(如果记录数大于 10,返回前 10 个) +- `getSchoolByAddress` 通过学校账号地址获取学校的信息 +- `getBackgroundById` 通过学历 Id 获取所存储的学历信息 + +- `writeRecord` 写入记录 +- `writeSchool` 写入新创建的学校 +- `writeStudent` 写入新创建的学生 + +#### 接口设计 + `createSchool` + +request参数: +``` +args[0] 学校名称 +args[1] 学校所在位置 +``` +response参数: +``` +学校信息的字节数组,当创建一所新学校时,该学校学生账户地址列表为空 +``` + +`createStudent` + +request参数: +``` +args[0] 学生的姓名 +``` + +response参数: +``` +学生信息的字节数组表示,刚创建过往学历信息列表为空 +``` + +`updateDiploma` + +request参数 +``` +args[0] 学校账户地址 +args[1] 学校签名 +args[2] 待修改学生的账户地址 +args[3] //对该学生的学历进行怎样的修改,0:正常毕业 1:退学 +``` + +response参数 +``` +返回修改记录的字节数组表示 +``` + +`enrollStudent` + +request参数: +``` +args[0] 学校账户地址 +args[1] 学校签名 +args[2] 学生账户地址 +``` + +response参数 +``` +返回修改记录的字节数组表示 +``` + +`getStudentByAddress` + +request参数 +``` +args[0] address +``` +response参数 +``` +学生信息的字节数组表示 +``` + +`getRecordById` + +request参数 +``` +args[0] 修改记录的ID +``` +response参数 +``` +修改记录的字节数组表示 +``` + +`getRecords` + +response参数 +``` +获取修改记录数组(如果个数大于10,返回前10个) +``` +`getSchoolByAddress` + +request参数 +``` +args[0] address +``` +response参数 +``` +学校信息的字节数组表示 +``` + +`getBackgroundById` + +request参数 +``` +args[0] ID +``` + +response参数 +``` +学历信息的字节数组表示 +``` + +#### 测试 diff --git a/chainbrock-learning/11_app_dev/chaincode_example05.go b/chainbrock-learning/11_app_dev/chaincode_example05.go new file mode 100644 index 00000000..c5789988 --- /dev/null +++ b/chainbrock-learning/11_app_dev/chaincode_example05.go @@ -0,0 +1,396 @@ +/* + author:swb + emial:swbsin@163.com + MIT License +*/ + +package main + +import ( + "errors" + "fmt" + "strconv" + "crypto/md5" + "crypto/rand" + "encoding/json" + "encoding/base64" + "encoding/hex" + "io" + "time" + "github.com/hyperledger/fabric/core/chaincode/shim" +) + +type SimpleChaincode struct { +} + +var homeNo int = 0 +var transactionNo int = 0 + +type Home struct { + Address string + Energy int + Money int + Id int + Status int + PriKey string + PubKey string +} + +type Transaction struct { + BuyerAddress string + BuyerAddressSign string + SellerAddress string + Energy int + Money int + Id int + Time int64 +} + +func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { + if len(args) != 0 { + return nil, errors.New("Incorrect number of arguments. Expecting 0") + } + + fmt.Println("Init success!") + + return nil, nil +} + +func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { + if function == "changeStatus" { + if len(args) != 3 { + return nil, errors.New("Incorrect number of arguments. Expecting 3") + } + return changeStatus(stub, args) + } else if function == "buyByAddress" { + if len(args) != 4 { + return nil, errors.New("Incorrect number of arguments. Expecting 4") + } + return buyByAddress(stub, args) + } else if function == "createUser" { + if len(args) != 2 { + return nil, errors.New("Incorrect number of arguments. Expecting 2") + } + return t.createUser(stub, args) + } + return nil, errors.New("Received unknown function invocation") +} + +func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { + if function == "getHomeByAddress" { + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting 1") + } + _, homeBytes, err := getHomeByAddress(stub, args[0]) + if err != nil { + fmt.Println("Error get home") + return nil, err + } + return homeBytes, nil + } else if function == "getHomes" { + if len(args) != 0 { + return nil, errors.New("Incorrect number of arguments. Expecting 0") + } + homes, err := getHomes(stub) + if err != nil { + fmt.Println("Error unmarshalling") + return nil, err + } + homeBytes, err1 := json.Marshal(&homes) + if err1 != nil { + fmt.Println("Error marshalling banks") + } + return homeBytes, nil + } else if function == "getTransactions" { + if len(args) != 0 { + return nil, errors.New("Incorrect number of arguments. Expecting 0") + } + transactions, err := getTransactions(stub) + if err != nil { + fmt.Println("Error unmarshalling") + return nil, err + } + txBytes, err1 := json.Marshal(&transactions) + if err1 != nil { + fmt.Println("Error marshalling data") + } + return txBytes, nil + } else if function == "getTransactionById" { + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting 1") + } + _, txBytes, err := getTransactionById(stub, args[0]) + if err != nil { + return nil, err + } + return txBytes, nil + } + return nil, errors.New("Received unknown function invocation") +} + +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +} + +// 生成 Address +func GetAddress() (string, string, string) { + var address, priKey, pubKey string + b := make([]byte, 48) + + if _, err := io.ReadFull(rand.Reader, b); err != nil { + return "", "", "" + } + + h := md5.New() + h.Write([]byte(base64.URLEncoding.EncodeToString(b))) + + address = hex.EncodeToString(h.Sum(nil)) + priKey = address + "1" + pubKey = address + "2" + + return address, priKey, pubKey +} + +func (t *SimpleChaincode) createUser(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { + var energy, money int + var err error + var homeBytes []byte + if len(args) != 2 { + return nil, errors.New("Incorrect number of arguments. Expecting 2") + } + address, priKey, pubKey := GetAddress() + energy, err = strconv.Atoi(args[0]) + if err != nil { + return nil, errors.New("want Integer number") + } + money, err = strconv.Atoi(args[1]) + if err != nil { + return nil, errors.New("want Integer number") + } + fmt.Printf("HomeInfo: address = %v, energy = %v, money = %v, homeNo = %v, priKey = %v, pubKey = %v\n", address, energy, money, homeNo, priKey, pubKey) + home := Home{Address: address, Energy: energy, Money: money, Id: homeNo, Status: 1, PriKey: priKey, PubKey: pubKey} + err = writeHome(stub, home) + if err != nil { + return nil, errors.New("write Error" + err.Error()) + } + homeBytes, err = json.Marshal(&home) + if err != nil { + return nil, errors.New("Error retrieve") + } + homeNo = homeNo + 1 + fmt.Println("Create user success!") + return homeBytes, nil +} + +func buyByAddress(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { + if len(args) != 4 { + return nil, errors.New("Incorrect number of arguments. Expecting 4") + } + homeSeller, _, err := getHomeByAddress(stub, args[0]) + homeBuyer, _, err := getHomeByAddress(stub, args[2]) + + if args[1] != args[2]+"11" { + return nil, errors.New("Verify sign data failed!") + } + + buyValue, erro := strconv.Atoi(args[3]) + if erro != nil { + return nil, errors.New("want integer number") + } + if homeSeller.Energy < buyValue && homeBuyer.Money < buyValue { + return nil, errors.New("not enough money or energy") + } + + fmt.Println("Before transaction:") + fmt.Printf(" homeSeller.Energy = %d, homeSeller.Money = %d\n", homeSeller.Energy, homeSeller.Money) + fmt.Printf(" homeBuyer.Energy = %d, homeBuyer.Money = %d\n", homeBuyer.Energy, homeBuyer.Money) + + homeSeller.Energy = homeSeller.Energy - buyValue + homeSeller.Money = homeSeller.Money + buyValue + homeBuyer.Energy = homeBuyer.Energy + buyValue + homeBuyer.Money = homeBuyer.Money - buyValue + + fmt.Println("After transaction:") + fmt.Printf(" homeSeller.Energy = %d, homeSeller.Money = %d\n", homeSeller.Energy, homeSeller.Money) + fmt.Printf(" homeBuyer.Energy = %d, homeBuyer.Money = %d\n", homeBuyer.Energy, homeBuyer.Money) + + err = writeHome(stub, homeSeller) + if err != nil { + return nil, err + } + + err = writeHome(stub, homeBuyer) + if err != nil { + return nil, err + } + + fmt.Println("TransactionInfo:") + fmt.Println(" BuyerAddress:", args[2]) + fmt.Println(" BuyerAddressSign:", args[1]) + fmt.Println(" SellerAddress:", args[0]) + fmt.Println(" Energy:", buyValue) + fmt.Println(" Money:", buyValue) + fmt.Println(" Id:", transactionNo) + + transaction := Transaction{BuyerAddress: args[2], BuyerAddressSign: args[1], SellerAddress: args[0], Energy: buyValue, Money: buyValue, Id: transactionNo, Time: time.Now().Unix()} + err = writeTransaction(stub, transaction) + if err != nil { + return nil, err + } + transactionNo = transactionNo + 1 + txBytes, err := json.Marshal(&transaction) + + if err != nil { + return nil, errors.New("Error retrieving schoolBytes") + } + + return txBytes, nil +} + +func changeStatus(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { + if len(args) != 3 { + return nil, errors.New("Incorrect number of arguments. Expecting 3") + } + home, homeBytes, err := getHomeByAddress(stub, args[0]) + if err != nil { + return nil, err + } + + if args[1] == args[0]+"11" { + status, _ := strconv.Atoi(args[2]) + home.Status = status + err = writeHome(stub, home) + if err != nil { + return homeBytes, nil + } + } + return nil, err +} + +func getHomeByAddress(stub shim.ChaincodeStubInterface, address string) (Home, []byte, error) { + var home Home + homeBytes, err := stub.GetState(address) + if err != nil { + fmt.Println("Error retrieving home") + } + err = json.Unmarshal(homeBytes, &home) + if err != nil { + fmt.Println("Error unmarshalling home") + } + return home, homeBytes, nil +} + +func getHomes(stub shim.ChaincodeStubInterface) ([]Home, error) { + var homes []Home + var number string + var err error + var home Home + if homeNo <= 10 { + i := 0 + for i < homeNo { + number = strconv.Itoa(i) + home, _, err = getHomeById(stub, number) + if err != nil { + return nil, errors.New("Error get detail") + } + homes = append(homes, home) + i = i + 1 + } + } else { + i := 0 + for i < 10 { + number = strconv.Itoa(i) + home, _, err = getHomeById(stub, number) + if err != nil { + return nil, errors.New("Error get detail") + } + homes = append(homes, home) + i = i + 1 + } + return homes, nil + } + return nil, nil +} + +func getHomeById(stub shim.ChaincodeStubInterface, id string) (Home, []byte, error) { + var home Home + // Need to be completed + + return home, nil, nil +} + +func getTransactionById(stub shim.ChaincodeStubInterface, id string) (Transaction, []byte, error) { + var transaction Transaction + txBytes, err := stub.GetState("transaction" + id) + if err != nil { + fmt.Println("Error retrieving home") + } + + err = json.Unmarshal(txBytes, &transaction) + if err != nil { + fmt.Println("Error unmarshalling home") + } + + return transaction, txBytes, nil +} + +func getTransactions(stub shim.ChaincodeStubInterface) ([]Transaction, error) { + var transactions []Transaction + var number string + var err error + var transaction Transaction + if transactionNo <= 10 { + i := 0 + for i < transactionNo { + number = strconv.Itoa(i) + transaction, _, err = getTransactionById(stub, number) + if err != nil { + return nil, errors.New("Error get detail") + } + transactions = append(transactions, transaction) + i = i + 1 + } + return transactions, nil + } else { + i := 0 + for i < 10 { + number = strconv.Itoa(i) + transaction, _, err = getTransactionById(stub, number) + if err != nil { + return nil, errors.New("Error get detail") + } + transactions = append(transactions, transaction) + i = i + 1 + } + return transactions, nil + } + return nil, nil +} + +func writeHome(stub shim.ChaincodeStubInterface, home Home) (error) { + homeBytes, err := json.Marshal(&home) + if err != nil { + return errors.New("Marshalling Error" + err.Error()) + } + err = stub.PutState(home.Address, homeBytes) + if err != nil { + return errors.New("PutState Error" + err.Error()) + } + return nil +} + +func writeTransaction(stub shim.ChaincodeStubInterface, transaction Transaction) (error) { + txBytes, err := json.Marshal(&transaction) + if err != nil { + return errors.New("Marshalling Error" + err.Error()) + } + id := strconv.Itoa(transaction.Id) + err = stub.PutState("transaction"+id, txBytes) + if err != nil { + return errors.New("PutState Error" + err.Error()) + } + return nil +} diff --git a/chainbrock-learning/11_app_dev/chaincode_example05.md b/chainbrock-learning/11_app_dev/chaincode_example05.md new file mode 100644 index 00000000..c4e3bc7a --- /dev/null +++ b/chainbrock-learning/11_app_dev/chaincode_example05.md @@ -0,0 +1,129 @@ +### 社区能源共享 +#### 功能描述 +本 [合约](chaincode_example05.go) 以纽约实验性的能源微电网为例,作为一个简单的案例进行实现。 + +>“在总统大道的一边,五户家庭通过太阳能板发电;在街道的另一边的五户家庭可以购买对面家庭不需要的电力。而连接这项交易的就是区块链网络,几乎不需要人员参与就可以管理记录交易。”但是这个想法是非常有潜力的,能够代表未来社区管理能源系统。” + +布鲁克林微电网开发商 LO3 创始人 Lawrence Orsini 说: + +>“我们正在这条街道上建立一个可再生电力市场,来测试人们对于购买彼此手中的电力是否感兴趣。如果你在很远的地方生产能源,运输途中会有很多损耗,你也得不到这电力价值。但是如果你就在街对面,你就能高效的利用能源。” + +在某一块区域内存在一个能源微电网,每一户家庭可能为生产者也可能为消费者。部分家庭拥有太阳能电池板,太阳能电池板的剩余电量为可以售出的电力的值,为了简化,单位为1.需要电力的家庭可以向有足够余额的电力的家庭购买电力。 + +账户私钥应该由安装在本地的客户端生成,本例中为了简便,使用模拟私钥和公钥。每位用户的私钥为guid+“1”,公钥为guid+“2”。签名方式简化为私钥+"1" + +#### 数据结构设计 +在该智能合约中暂时只有一种角色,为每一户家庭用户。 + +- 家庭用户 + - 账户地址 + - 剩余能量 //部分家庭没有太阳能电池板,值为0 + - 账户余额(电子货币) + - 编号 + - 状态 //0:不可购买, 1:可以购买 + - 账户公钥 + - 账户私钥 +- 交易(一笔交易必须同时具有卖方和买方的公钥签名,方能承认这笔交易。公钥签名生成规则,公钥+待创建交易的ID号,在本交易类型中,只要买家有足够的货币,卖家自动会对交易进行签名) + - 购买方地址 + - 销售方地址 + - 电量销售量 + - 电量交易金额 + - 编号 + - 交易时间 + +#### function及各自实现的功能 +- `init` 初始化操作 +- `invoke` 调用合约内部的函数 +- `query` 查询相关的信息 +- `createUser` 创建新用户,并加入到能源微网中 invoke +- `buyByAddress` 向某一位用户购买一定量的电力 invoke +- `getTransactionById` 通过id获取交易内容 query +- `getTransactions` 获取交易(如果交易数大于10,获取前10个) query +- `getHomes` 获取用户(如果用户数大于10,获取前10个) query +- `getHomeByAddress` 通过地址获取用户 query +- `changeStatus` 某一位用户修改自身的状态 invoke + +- `writeUser` 将新用户写入到键值对中 +- `writeTransaction` 记录交易 +#### 接口设计 +`createUser` + +request参数: +``` +args[0] 剩余能量值 +args[1] 剩余金额 +``` +response参数: +``` +新建家庭用户的json表示 +``` + +`buyByAddress` + +request参数: +``` +args[0] 卖家的账户地址 +args[1] 买家签名 +args[2] 买家的账户地址 +args[3] 想要购买的电量数值 +``` +response参数: +``` +购买成功的话返回该transaction的json串。 +购买失败返回error +``` + +`getTransactionById` + +request参数: +``` +args[0] 交易编号 +``` +response参数: +``` +查询结果的transaction 交易表示 +``` + +`getTransactions` + +request参数: +``` +none + ``` +response参数: +``` +获取所有的交易列表(如果交易大于10,则返回前10个) +``` + +`getHomeByAddress` + +request参数 +``` +args[0] address +``` +response参数 +``` +用户信息的json表示 +``` + +`getHomes` + +response参数 +``` +获取所有的用户列表(如果用户个数大于10,则返回前10个) +``` + +`changeStatus` + +request参数: +``` +args[0] 账户地址 +args[1] 账户签名 +args[2] 对自己的账户进行的操作,0:设置为不可购买 1:设置状态为可购买 +``` +response参数: +``` +修改后的用户信息json表示 +``` + +#### 测试 diff --git a/chainbrock-learning/11_app_dev/chaincode_example06.go b/chainbrock-learning/11_app_dev/chaincode_example06.go new file mode 100644 index 00000000..76cef828 --- /dev/null +++ b/chainbrock-learning/11_app_dev/chaincode_example06.go @@ -0,0 +1,505 @@ +/* + author:swb + emial:swbsin@163.com + MIT License +*/ + +package main + +import ( + "errors" + "fmt" + "strconv" + "crypto/md5" + "crypto/rand" + "encoding/base64" + "encoding/hex" + "io" + "github.com/hyperledger/fabric/core/chaincode/shim" +) + +type SimpleChaincode struct { +} + +var ExpressOrderId int = 0 +var ExpressId int = 0 + +type ExpressOrder struct{ + Id int + SenderLocation string + ReceiverLocation string + SenderAddress string + ReceiverAddress string + SenderPhone string + ReceiverPhone string + ExpressMoney int + ExpressMoneyType string + ExpressMoneySenderPay int + ExpressPointAddress []string + PayingMoney int + ExpressOrderSign string //0:收货方未签名 1:收货方签名 +} + +type User struct{ + Name string + Location string + Address string + PriKey string + PubKey string + Phone string + Money int +} + +type Express struct{ + Name string + Location string + Phone string + Money int + ExpressPointerAddress []string + Address string + PriKey string + PubKey string +} + +type ExpressPointer struct{ + Name string + Location string + Phone string + PriKey string + PubKey string + ExpressAddress string +} + +func (t *SimpleChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { + if function == "createUser"{ + return t.createUser(stub,args) + }else if function == "craeteExpressPointer"{ + return t.createExpressPointer(stub,args) + }else if function == "createExpress"{ + return t.createExpress(stub,args) + }else if function == "createExpressOrder"{ + return t.createExpressOrder(stub,args) + } + return nil,nil +} + +func (t *SimpleChaincode) Invoke(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { + if function == "finishExpressOrder"{ + return t.finishExpressOrder(stub,args) + }else if function == "addExpressPointer"{ + return t.addExpressPointer(stub,args[0]) + }else if function == "updateExpressOrder"{ + return t.updateExpressOrder(stub,args[0]) + } + return nil,nil +} + +func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { + if function == "getExpressOrderById"{ + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting 3") + } + _,eoBytes,err := getExpressOrderById(stub,args[0]) + if err != nil { + fmt.Println("Error get data") + return nil, err + } + return eoBytes,nil + }else if function == "getExpress"{ + if len(args) != 0 { + return nil, errors.New("Incorrect number of arguments. Expecting 0") + } + _,exBytes,err := getExpress(stub) + if err != nil { + fmt.Println("Error get data") + return nil, err + } + return exBytes,nil + }else if function == "getUserByAddress"{ + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting 1") + } + _,userBytes,err := getUserByAddress(stub,args[0]) + if err != nil { + fmt.Println("Error get data") + return nil, err + } + return userBytes,nil + }else if function == "getExpressPointerByAddress"{ + if len(args) != 1 { + return nil, errors.New("Incorrect number of arguments. Expecting 1") + } + _,expressCpBytes,err := getExpressPointerByAddress(stub,args[0]) + if err != nil { + fmt.Println("Error get data") + return nil, err + } + return expressCpBytes,nil + } + return nil,nil +} + +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +} + +//生成Address +func GetAddress() (string,string,string) { + var address,priKey,pubKey string + b := make([]byte, 48) + + if _, err := io.ReadFull(rand.Reader, b); err != nil { + return "","","" + } + + h := md5.New() + h.Write([]byte(base64.URLEncoding.EncodeToString(b))) + + address = hex.EncodeToString(h.Sum(nil)) + priKey = address+"1" + pubKey = address+"2" + + return address,priKey,pubKey +} + +func (t *SimpleChaincode) createUser(stub *shim.ChaincodeStub, args []string) ([]byte, error) { + if len(args) != 4{ + return nil, errors.New("Incorrect number of arguments. Expecting 4") + } + + var user User + var userBytes []byte + var number int + var error err + var address,priKey,pubKey string + address,priKey,pubKey = GetAddress() + + number,err= strconv.Atoi(args[3]) + if err != nil{ + return nil,errors.New("Want integer number") + } + + user = User{Name:args[0],Loction:args[1],Address:address,PriKey:priKey,PubKey:pubKey,Phone:args[2],Money:number} + err = writeUser(stub,user) + if err!= nil{ + return nil,errors.New("write error") + } + + userBytes,err = json.Marshal(&user) + if err!= nil{ + return nil,errors.New("Error retrieve") + } + return userBytes, nil +} + +func(t *SimpleChaincode) createExpressPointer(stub *shim.ChaincodeStub,args[] string)([]byte,error){ + if len(args) != 3{ + return nil, errors.New("Incorrect number of arguments. Expecting 3") + } + + var expressPointer ExpressPointer + var epBytes []byte + var address,priKey,pubKey string + address,priKey,pubKey = GetAddress() + + expressPointer = ExpressPointer{Name:args[0],Location:args[1],ExpressAddress:address,PriKey:priKey,PubKey:pubKey,Phone:phone} + err = writeUser(stub,expressPointer) + if err!= nil{ + return nil,errors.New("write error") + } + + epBytes,err = json.Marshal(&expressPointer) + if err!= nil{ + return nil,errors.New("Error retrieve") + } + return epBytes, nil +} + + +func(t *SimpleChaincode) createExpress(stub *shim.ChaincodeStub,args[] string)([]byte,error){ + if len(args)!= 3{ + return nil,errors.New("Incorrect number of arguments.Expecting 4") + } + + if expressId != 0{ + return nil,errors.New("can not create two express company") + } + + var express Express + var pointerAddress []string + var expressBytes []byte + var money int + var err error + var address,priKey,pubKey string + + money,err= strconv.Atoi(args[3]) + if err != nil{ + return nil,errors.New("Want integer number") + } + + express = Express{Name:args[0],Location:args[1],Phone:args[2],Money:money,Address:address,PriKey:priKey,PubKey:pubKey,ExpressPointerAddress:pointerAddress} + err = writeExpress(stub,express) + + if err!= nil{ + return nil,errors.New("write error") + } + + expressBytes,err = json.Marshal(&express) + if err!= nil{ + return nil,errors.New("Error retrieve") + } + return expressBytes, nil +} + +func(t *SimpleChaincode) createExpressOrder(stub *shim.ChaincodeStub,args[] string)([]byte,error){ + if len(args) !=8{ + return nil,errors.New("Incorrect number of arguments.Expecting 9") + } + + var expressOrder ExpressOrder + var expressPointAddress []string + var eoBytes []byte + var err error + var money int + var payingMoney int + + money,err = strconv.Atoi(args[7]) + if err != nil{ + return nil,errors.New("want integer number") + } + + payingMoney,err = strconv.Atoi(args[8]) + if err != nil{ + return nil,errors.New("want integer number") + } + + expressOrder = ExpressOrder{Id:ExpressOrderId,SenderLocation:args[0],ReceiverLocation:args[1],SenderAddress:args[2],ReceiverAddress:args[3],SenderPhone:args[4],ReceiverPhone:args[5],ExpressMoneyType:args[6],ExpressMoney:args[7],ExpressPointAddress:expressPointAddress,PayingMoney:payingMoney} + err = writeExpressOrder(expressOrder) + + if err!= nil{ + return err + } + + ExpressOrderId = ExpressOrderId + 1 + + eoBytes,err = json.Marshal(&expressOrder) + if err!= nil{ + return nil,errors.New("Error retrieve data") + } + return eoBytes,nil +} + + +func(t *SimpleChaincode) addExpressPointer(stub *shim.ChaincodeStub,address string)([]byte,error){ + express,expressBytes,err := getExpress(stub) + if err != nil{ + return nil,errors.New("Error get data") + } + + expressOrder,eoBytes,error := getExpressPointerByAddress(stub,address) + if error != nil{ + return nil,errors.New("Error get data") + } + + express.ExpressPointerAddress = append(express.ExpressPointerAddress,expressOrder.ExpressAddress) + err = writeExpress(express) + if err != nil{ + return nil,errors.New("Error write data") + } + + expressBytes,err := json.Marshal(&express) + if err != nil{ + return nil + } + return expressBytes,nil +} + +func(t *SimpleChaincode) updateExpressOrder(stub *shim.ChaincodeStub,args[] string)([]byte,error){ + if len(arg) != 2{ + return nil,errors.New("Incorrect number of arguments.Expecting 2") + } + + expressOrder,epBytes,err := getExpressOrderById(args[0]) + if err != nil{ + return nil,errors.New("get error") + } + + expressOrder.ExpressPointAddress = append(expressOrder.ExpressPointAddress,args[1]) + err = writeExpressOrder(expressOrder) + if err != nil{ + return nil,nil + } + + eoBytes,err := json.Marshal(&expressOrder) + if err != nil{ + return nil + } + + return eoBytes,nil +} + +func(t *SimpleChaincode) finishExpressOrder(stub *shim.ChaincodeStub,args[] string)([]byte,error){ + if len(arg)!= 3{ + return nil,errors.New("Incorrect number of arguments.Expecting 3") + } + + user,err := getUserByAddress(stub,args[0]) + if err != nil{ + return err + } + + expressOrder,epBytes,error := getExpressOrderById(args[1]) + if error != nil{ + return error + } + + express,epBytes,errorone := getExpress(stub) + errorone != nil{ + return errorone + } + + if expressOrder.ExpressMoney!=0{ + express.Money = express.Money + expressOrder.ExpressMoney + expressOrder.ExpressMoney = 0 + }else{ + express.Money = express.Money + expressOrder.PayingMoney + user.Money = user.Money -expressOrder.PayingMoney + } + + expressOrder.ExpressOrderSign = args[3] + + err = writeExpress(express) + if err != nil{ + return err + } + + err = writeUser(user) + if err != nil{ + return err + } + + err = writeExpressOrder(expressOrder) + if err != nil{ + return err + } + + eoBytes,err := json.Marshal(&expressOrder) + if err != nil{ + return nil + } + + return eoBytes,nil +} + +func(t *SimpleChaincode) getExpressOrderById(stub *shim.ChaincodeStub,id string)(ExpressOrder,[]byte,error){ + var expressOrder ExpressOrder + eoBytes,err := stub.GetState("expressOrder"+id) + if err != nil{ + fmt.Println("Error retrieving data") + } + + err = json.Unmarshal(eoBygtes,&ExpessOrder) + if err != nil{ + fmt.Println("Error unmarshalling data") + } + return expressOrder,eoByes,nil +} + +func(t *SimpleChaincode) getExpress(stub *shim.ChaincodeStub)(Express,[]byte,error){ + var express Express + exBytes,err := stub.GetState("Express") + if err != nil{ + fmt.Println("Error retrieving data") + } + + err = json.Unmarshal(exBytes,&express) + if err != nil { + fmt.Println("Error unmarshalling data") + } + + return express,exBytes,nil +} + +func(t *SimpleChaincode) getUserByAddress(stub *shim.ChaincodeStub,address string)(User,[]byte,error){ + var user User + userBytes,err := stub.GetState(address) + if err != nil{ + fmt.Println("Error retrieving data") + } + + err = json.Unmarshal(userBytes,&user) + if err != nil { + fmt.Println("Error unmarshalling data") + } + + return user,userBytes,nil +} + +func(t *SimpleChaincode) getExpressPointerByAddress(stub *shim.ChaincodeStub,address string)(ExpressPointer,[]byte,error){ + var expressPointer ExpressPointer + epBytes,err := stub.GetState(address) + if err != nil{ + fmt.Println("Error retrieving data") + } + + err = json.Unmarshal(epBytes,&expressPointer) + if err != nil { + fmt.Println("Error unmarshalling data") + } + + return expressPointer,epBytes,nil +} + +func(t *SimpleChaincode) writeExpress(stub *shim.ChaincodeStub,Express express)(error){ + exBytes,err := json.Marshal(&express) + if err != nil { + return err + } + err = stub.PutState("Express", exBytes) + if err != nil { + return errors.New("PutState Error" + err.Error()) + } + return nil +} + +func(t *SimpleChaincode) writeExpressOrder(stub *shim.ChaincodeStub,ExpressOrder expressOrder)(error){ + eoBytes,err := json.Marshal(&expressOrder) + if err != nil { + return err + } + + id ,_:= strconv.Itoa(expressOrder.Id) + err = stub.PutState("ExpressOrder"+id,eoBytes) + if err != nil { + return errors.New("PutState Error" + err.Error()) + } + return nil +} + +func(t *SimpleChaincode) writeUser(stub *shim.chaincodeStub,User user)(error){ + userBytes,err := json.Marshal(&user) + if err != nil { + return err + } + err = stub.PutState(user.Address, userBytes) + if err != nil { + return errors.New("PutState Error" + err.Error()) + } + return nil +} + +func(t *SimpleChaincdoe) writeExpressPointer(stub *shim.chaincodeStub,ExpressPointer expressPointer)(error){ + epBytes,err := json.Marshal(&expressPointer) + if err != nil { + return err + } + + err = stub.PutState(user.Address, userBytes) + if err != nil { + return errors.New("PutState Error" + err.Error()) + } + return nil +} \ No newline at end of file diff --git a/chainbrock-learning/11_app_dev/chaincode_example06.md b/chainbrock-learning/11_app_dev/chaincode_example06.md new file mode 100644 index 00000000..36373245 --- /dev/null +++ b/chainbrock-learning/11_app_dev/chaincode_example06.md @@ -0,0 +1,244 @@ +### 物流供应链简单案例 +#### 功能描述 +该 [智能合约](chaincode_example06.go) 实现了一个简单的供应链应用案例,针对物流行业的应用场景。由于将合约的协议公开,并且签收快递时需要签名,可以在很大程度上保证不被冒领,实现了一手交钱,一手交货,同时提高了效率,确保了透明。 + +该智能合约中三种角色如下: +- 物流公司(本案例中只有1位) +- 寄货方(本案例中有多位) +- 收货方(本案例中有多位) + +业务流程如下: + +1、寄货方填写寄货单,物流公司根据寄货单寄快递。 + +2、寄快递过程中物流公司各个快递点对快递进行扫描,描述目前快递进度,并更新货单状态。寄货方和收货方可以根据单号进行查询。 + +3、快递到达后,收货方检查商品,确认无误后,扫码并使用私钥签名,支付相关费用,更新订单状态。 + +在实际中,物流费的支付分为两类: +- 1、寄货方支付。收货方签收快递后先预付给物流公司。 +- 2、收货方支付。收货方签收快递后支付给物流公司。 + +在本案例中暂不考虑货物损坏、收货方失联、货物保值等的相关问题。具体实现逻辑如下: + +- 创建账户。为每个用户生成唯一的私钥与地址。 +- 生成寄货单。寄货方填写纸质寄货单,物流公司根据此生成电子单。 +- 更新寄货单。物流公司旗下快递点根据配送信息更新电子寄货单。 +- 收货方签收确认。收货方收到货物后,使用自己的私钥进行签收,完成相应的付款。 + +账户私钥应该由安装在本地的客户端生成,本例中为了简便,使用模拟私钥和公钥。每位用户的私钥为guid+“1”,公钥为guid+“2”。用户签名为私钥+“1” + +#### 数据结构设计 +- 寄货单 + - 寄货单编号 + - 寄货方地址 + - 收货方地址 + - 寄货方联系方式 + - 收货方联系方式 + - 物流费用 + - 物流费用支付类型 //0:寄货方支付 1:收货方支付 + - 寄货方预支付费用 //模拟实际预支付,寄货方支付物流费下值为物流费,否则为0 + - 快递配送信息 // 快递运送状态,所经过快递分拨中心与快递点的数组 + - 收货方签名 + +- 寄货方 + - 姓名 + - 所在地址 + - 账户地址 + - 账户公钥 + - 联系方式 + - 账户余额 +- 收货方 + - 姓名 + - 所在地址 + - 账户地址 + - 账户公钥 + - 账户私钥 + - 联系方式 + - 账户余额 +- 物流公司 + - 账户公钥 + - 账户私钥 + - 名称 + - 地址 + - 联系方式 + - 账户余额 + - 物流公司旗下分拨中心与快递点 +- 快递点 + - 名称 + - 所在地址 + - 联系方式 + - 快递点公钥 + - 快递点私钥 + - 快递点账户地址 + +#### function及各自实现的功能 +- `init` 初始化物流公司及其下相应快递点 +- `invoke` 调用合约内部的函数 +- `query` 查询相关的信息 +- `createUser` 创建用户 init +- `createExpress` 创建物流公司 init +- `createExpressPoint` 创建快递点 init +- `createExpressOrder` 寄货方创建寄货单 init +- `finishExpressOrder` 收货方签收寄货单 invoke +- `addExpressPointer` 物流公司添加新的快递点 invoke +- `updateExpressOrder` 更新物流公司订单,添加快递点的信息 invoke + + +- `getExpressOrderById` 查询订单状态 query +- `getExpress` 获取物流公司信息 query +- `getUserByAddress` 获取用户信息 query +- `getExpressPointByAddress` 获取快递点信息 query + +- `writeExpress` 存储物流公司信息 (以物流公司账户地址进行存储) +- `writeExpressOrder` 存储寄货单 (以“express”+id 进行存储) +- `writeUser` 存储用户信息 (以地址进行存储) +- `writeExpressPoint` 存储物流点信息 (以快递点账户地址进行存储) + +#### 接口设计 + `createUser` + +request参数 +``` +args[0] 姓名 +args[1] 所在地址 +args[2] 联系方式 +args[3] 账户余额 +``` + +response参数 +``` +user信息的json表示 +``` + + `createExpressPointer` + +request参数 +``` +args[0] 姓名 +args[1] 所在地址 +args[2] 联系方式 +``` + +response参数 +``` +物流点的信息的json表示 +``` + + `createExpress` + +request 参数 +``` +args[0] 名称 +args[1] 地址 +args[2] 联系方式 +args[3] 账户余额 +``` +response 参数 +``` +物流公司信息的json表示 +``` + + `addExpressPointer` + +request参数 +``` +args[0] 添加快递点 +``` + +response参数 +``` +物流公司信息的json表示 +``` + + `createExpressOrder` + +request参数 +``` +args[0] 寄货方地址 +args[1] 收货方地址 +args[2] 寄货方账户地址 +args[3] 收货方账户地址 +args[4] 寄货方联系方式 +args[5] 收货方联系方式 +args[6] 物流费用支付类型 +args[7] 寄货方预支付费用 (收货方支付的话值为0) +args[8] 物流费用 +``` + +response 参数 +``` +订单信息的json表示 +``` + + `updateExpressOrder` + +request参数 +``` +args[0] 订单id +args[1] 快递点地址 +``` + +response参数 +``` +订单信息的json表示 +``` + + `finishExpressOrder` + +request参数 +``` +args[0] 收货方账户地址 +args[1] 账户订单编号 +args[2] 收货方签名 +``` + +response参数 +``` +订单信息的json表示 +``` + +`getExpressOrderById` + +request参数: +``` +args[0] id +``` + +response参数: +``` +快递订单的json表示 +``` + +`getExpress` + +response参数: +``` +快递信息的json表示 +``` + +`getUserByAddress` + +request参数 +``` +args[0] address +``` + +response参数 +``` +用户信息的json表示 +``` + +`getExpressPointerByAddress` + +request参数 +``` +args[0] address +``` + +response参数 +``` +快递点的json信息表示 +``` + +#### 测试 diff --git a/chainbrock-learning/11_app_dev/intro.md b/chainbrock-learning/11_app_dev/intro.md new file mode 100644 index 00000000..9dd367d4 --- /dev/null +++ b/chainbrock-learning/11_app_dev/intro.md @@ -0,0 +1,38 @@ +## 简介 + +区块链应用,一般由若干部署在区块链网络中的智能合约,以及调用这些智能合约的用户应用程序组成。典型结构如下图所示。 + +![区块链应用程序](_images/blockchain_application.png) + +其中,用户访问与业务本身相关的上层应用程序,应用程序调用智能合约,智能合约与账本直接交互。 + +开发者除了需要开发传统的上层业务应用,还需要编写区块链智能合约代码。 + +典型的智能合约是无状态的、事件驱动的代码,被调用时自动执行合约内逻辑。智能合约可以创建和操作账本状态,这些链上状态记录业务相关的重要数据(如资产信息和所有权)。区块链网络中可以部署多个智能合约,应用程序通过名称、版本号等来指定调用特定智能合约。 + +在支持访问控制的场景下,应用程序还需提前从 CA 处申请证书,得到访问许可。 + +### 智能合约开发 + +智能合约直接与账本结构打交道,同时支持上层业务逻辑,作用十分关键。设计得当的智能合约可以简化应用开发;反之则可能导致各种问题。 + +为了合理设计智能合约,开发者需要了解区块链平台的智能合约结构、语言特性、状态存储方式等。例如,比特币网络不支持高级语言,所支持的处理逻辑存在限制;超级账本 Fabric 项目支持多种高级语言,支持图灵完备的处理逻辑,可以开发复杂的逻辑。 + +此外,开发者还需要考虑智能合约的生命周期管理,包括代码的编写、版本管理、提交验证、升级等,都需要遵循标准规范。 + +本章后续内容会以超级账本 Fabric 为例,讲解其智能合约的开发过程。 + +### 应用程序开发 + +应用程序通常以 Web、移动端 App 等形式呈现,通过调用智能合约提供的方法接口来实现业务逻辑。应用程序既可以运行在区块链网络的节点上,也可以运行在外部服务器上,但必须可以访问到区块链网络服务。 + +为方便进行身份管理、网络监听、调用智能合约等,应用程序开发通常需要集成区块链 SDK。以超级账本 Fabric 为例,社区提供的 SDK 封装了一系列与区块链网络打交道的基本方法,包括发送交易、监听网络事件、查询区块和交易信息等,能够提高对智能合约进行使用的效率。 + +例如,利用 SDK 可以自动化对智能合约的调用和确认过程: + +* 客户端从 CA 获取合法的身份证书; +* 构造合法的交易提案发送给 Endorser 节点进行背书; +* 收集到足够多背书支持后,构造合法的交易请求,发给排序节点进行排序; +* 监听网络事件,确保交易已经写入账本。 + +Fabric 目前提供了 Node.Js、Python、Java、Go 等语言的 SDK,开发者可以根据需求自行选择。 diff --git a/chainbrock-learning/11_app_dev/summary.md b/chainbrock-learning/11_app_dev/summary.md new file mode 100644 index 00000000..45cd728a --- /dev/null +++ b/chainbrock-learning/11_app_dev/summary.md @@ -0,0 +1 @@ +## 本章小结 \ No newline at end of file diff --git a/chainbrock-learning/13_fabric_design/README.md b/chainbrock-learning/13_fabric_design/README.md new file mode 100644 index 00000000..0a57c1dc --- /dev/null +++ b/chainbrock-learning/13_fabric_design/README.md @@ -0,0 +1 @@ +# Fabric 架构与设计 \ No newline at end of file diff --git a/chainbrock-learning/13_fabric_design/_images/dataflow.png b/chainbrock-learning/13_fabric_design/_images/dataflow.png new file mode 100644 index 00000000..ea68c2a1 Binary files /dev/null and b/chainbrock-learning/13_fabric_design/_images/dataflow.png differ diff --git a/chainbrock-learning/13_fabric_design/_images/refarch.png b/chainbrock-learning/13_fabric_design/_images/refarch.png new file mode 100644 index 00000000..46f7321d Binary files /dev/null and b/chainbrock-learning/13_fabric_design/_images/refarch.png differ diff --git a/chainbrock-learning/13_fabric_design/_images/transaction_flow.png b/chainbrock-learning/13_fabric_design/_images/transaction_flow.png new file mode 100644 index 00000000..04380e46 Binary files /dev/null and b/chainbrock-learning/13_fabric_design/_images/transaction_flow.png differ diff --git a/chainbrock-learning/13_fabric_design/design.md b/chainbrock-learning/13_fabric_design/design.md new file mode 100644 index 00000000..23387590 --- /dev/null +++ b/chainbrock-learning/13_fabric_design/design.md @@ -0,0 +1,258 @@ +## 架构设计 + +整个功能架构如下图所示。 + +![](_images/refarch.png) + +包括三大组件:区块链服务(Blockchain)、链码服务(Chaincode)、成员权限管理(Membership)。 + +### 概念术语 + +* Auditability(审计性):在一定权限和许可下,可以对链上的交易进行审计和检查。 +* Block(区块):代表一批得到确认的交易信息的整体,准备被共识加入到区块链中。 +* Blockchain(区块链):由多个区块链接而成的链表结构,除了首个区块,每个区块都包括前继区块内容的 hash 值。 +* Certificate Authority(CA):负责身份权限管理,又叫 Member Service 或 Identity Service。 +* Chaincode(链上代码或链码):区块链上的应用代码,扩展自“智能合约”概念,支持 golang、nodejs 等,运行在隔离的容器环境中。 +* Committer(提交节点):1.0 架构中一种 peer 节点角色,负责对 orderer 排序后的交易进行检查,选择合法的交易执行并写入存储。 +* Confidentiality(保密):只有交易相关方可以看到交易内容,其它人未经授权则无法看到。 +* Endorser(背书节点):1.0 架构中一种 peer 节点角色,负责检验某个交易是否合法,是否愿意为之背书、签名。 +* Enrollment Certificate Authority(ECA,注册 CA):负责成员身份相关证书管理的 CA。 +* Ledger(账本):包括区块链结构(带有所有的可验证交易信息,但只有最终成功的交易会改变世界观)和当前的世界观(world state)。Ledger 仅存在于 Peer 节点。 +* MSP(Member Service Provider,成员服务提供者):成员服务的抽象访问接口,实现对不同成员服务的可拔插支持。 +* Non-validating Peer(非验证节点):不参与账本维护,仅作为交易代理响应客户端的 REST 请求,并对交易进行一些基本的有效性检查,之后转发给验证节点。 +* Orderer(排序节点):1.0 架构中的共识服务角色,负责排序看到的交易,提供全局确认的顺序。 +* Permissioned Ledger(带权限的账本):网络中所有节点必须是经过许可的,非许可过的节点则无法加入网络。 +* Privacy(隐私保护):交易员可以隐藏交易的身份,其它成员在无特殊权限的情况下,只能对交易进行验证,而无法获知身份信息。 +* Transaction(交易):执行账本上的某个函数调用。具体函数在 chaincode 中实现。 +* Transactor(交易者):发起交易调用的客户端。 +* Transaction Certificate Authority(TCA,交易 CA):负责维护交易相关证书管理的 CA。 +* Validating Peer(验证节点):维护账本的核心节点,参与一致性维护、对交易的验证和执行。 +* World State(世界观):是一个键值数据库,chaincode 用它来存储交易相关的状态。 + +### 区块链服务 + +区块链服务提供一个分布式账本平台。一般地,多个交易被打包进区块中,多个区块构成一条区块链。区块链代表的是账本状态机发生变更的历史过程。 + +#### 交易 + +交易意味着围绕着某个链码进行操作。 + +交易可以改变世界状态。 + +交易中包括的内容主要有: + +* 交易类型:目前包括 Deploy、Invoke、Query、Terminate 四种; +* uuid:代表交易的唯一编号; +* 链码编号 chaincodeID:交易针对的链码; +* 负载内容的 hash 值:Deploy 或 Invoke 时候可以指定负载内容; +* 交易的保密等级 ConfidentialityLevel; +* 交易相关的 metadata 信息; +* 临时生成值 nonce:跟安全机制相关; +* 交易者的证书信息 cert; +* 签名信息 signature; +* metadata 信息; +* 时间戳 timestamp。 + +交易的数据结构(Protobuf 格式)定义为 + +```protobuf +message Transaction { + enum Type { + UNDEFINED = 0; + // deploy a chaincode to the network and call `Init` function + CHAINCODE_DEPLOY = 1; + // call a chaincode `Invoke` function as a transaction + CHAINCODE_INVOKE = 2; + // call a chaincode `query` function + CHAINCODE_QUERY = 3; + // terminate a chaincode; not implemented yet + CHAINCODE_TERMINATE = 4; + } + Type type = 1; + //store ChaincodeID as bytes so its encrypted value can be stored + bytes chaincodeID = 2; + bytes payload = 3; + bytes metadata = 4; + string uuid = 5; + google.protobuf.Timestamp timestamp = 6; + + ConfidentialityLevel confidentialityLevel = 7; + string confidentialityProtocolVersion = 8; + bytes nonce = 9; + + bytes toValidators = 10; + bytes cert = 11; + bytes signature = 12; +} +``` + +在 1.0 架构中,一个 transaction 包括如下信息: + +[ledger] [channel], **proposal:**[chaincode, ] **endorsement:**[proposal hash, simulation result, signature] + +* endorsements: proposal hash, simulation result, signature +* function-spec: function name, arguments +* proposal: [channel,] chaincode, + +#### 区块 + +区块打包交易,确认交易后的世界状态。 + +一个区块中包括的内容主要有: + +* 版本号 version:协议的版本信息; +* 时间戳 timestamp:由区块提议者设定; +* 交易信息的默克尔树的根 hash 值:由区块所包括的交易构成; +* 世界观的默克尔树的根 hash 值:由交易发生后整个世界的状态值构成; +* 前一个区块的 hash 值:构成链所必须; +* 共识相关的元数据:可选值; +* 非 hash 数据:不参与 hash 过程,各个 peer 上的值可能不同,例如本地提交时间、交易处理的返回值等; + +_注意具体的交易信息并不存放在区块中。_ + +区块的数据结构(Protobuf 格式)定义为 + +```protobuf +message Block { + uint32 version = 1; + google.protobuf.Timestamp timestamp = 2; + repeated Transaction transactions = 3; + bytes stateHash = 4; + bytes previousBlockHash = 5; + bytes consensusMetadata = 6; + NonHashData nonHashData = 7; +} +``` + +一个真实的区块内容示例: + +```json +{ + "nonHashData": { + "localLedgerCommitTimestamp": { + "nanos": 975295157, + "seconds": 1466057539 + }, + "transactionResults": [ + { + "uuid": "7be1529ee16969baf9f3156247a0ee8e7eee99a6a0a816776acff65e6e1def71249f4cb1cad5e0f0b60b25dd2a6975efb282741c0e1ecc53fa8c10a9aaa31137" + } + ] + }, + "previousBlockHash": "RrndKwuojRMjOz/rdD7rJD/NUupiuBuCtQwnZG7Vdi/XXcTd2MDyAMsFAZ1ntZL2/IIcSUeatIZAKS6ss7fEvg==", + "stateHash": "TiIwROg48Z4xXFFIPEunNpavMxnvmZKg+yFxKK3VBY0zqiK3L0QQ5ILIV85iy7U+EiVhwEbkBb1Kb7w1ddqU5g==", + "transactions": [ + { + "chaincodeID": "CkdnaXRodWIuY29tL2h5cGVybGVkZ2VyL2ZhYnJpYy9leGFtcGxlcy9jaGFpbmNvZGUvZ28vY2hhaW5jb2RlX2V4YW1wbGUwMhKAATdiZTE1MjllZTE2OTY5YmFmOWYzMTU2MjQ3YTBlZThlN2VlZTk5YTZhMGE4MTY3NzZhY2ZmNjVlNmUxZGVmNzEyNDlmNGNiMWNhZDVlMGYwYjYwYjI1ZGQyYTY5NzVlZmIyODI3NDFjMGUxZWNjNTNmYThjMTBhOWFhYTMxMTM3", + "payload": "Cu0BCAESzAEKR2dpdGh1Yi5jb20vaHlwZXJsZWRnZXIvZmFicmljL2V4YW1wbGVzL2NoYWluY29kZS9nby9jaGFpbmNvZGVfZXhhbXBsZTAyEoABN2JlMTUyOWVlMTY5NjliYWY5ZjMxNTYyNDdhMGVlOGU3ZWVlOTlhNmEwYTgxNjc3NmFjZmY2NWU2ZTFkZWY3MTI0OWY0Y2IxY2FkNWUwZjBiNjBiMjVkZDJhNjk3NWVmYjI4Mjc0MWMwZTFlY2M1M2ZhOGMxMGE5YWFhMzExMzcaGgoEaW5pdBIBYRIFMTAwMDASAWISBTIwMDAw", + "timestamp": { + "nanos": 298275779, + "seconds": 1466057529 + }, + "type": 1, + "uuid": "7be1529ee16969baf9f3156247a0ee8e7eee99a6a0a816776acff65e6e1def71249f4cb1cad5e0f0b60b25dd2a6975efb282741c0e1ecc53fa8c10a9aaa31137" + } + ] +} +``` + +#### 世界观 +世界观用于存放链码执行过程中涉及到的状态变量,是一个键值数据库。典型的元素为 `[chaincodeID, ckey]: value` 结构。 + +为了方便计算变更后的 hash 值,一般采用默克尔树数据结构进行存储。树的结构由两个参数(`numBuckets` 和 `maxGroupingAtEachLevel`)来进行初始配置,并由 `hashFunction` 配置决定存放键值到叶子节点的方式。显然,各个节点必须保持相同的配置,并且启动后一般不建议变动。 + +* `numBuckets`:叶子节点的个数,每个叶子节点是一个桶(bucket),所有的键值被 `hashFunction` 散列分散到各个桶,决定树的宽度; +* `maxGroupingAtEachLevel`:决定每个节点由多少个子节点的 hash 值构成,决定树的深度。 + +其中,桶的内容由它所保存到键值先按照 chaincodeID 聚合,再按照升序方式组成。 + +一般地,假设某桶中包括 $$ M $$ 个 chaincodeID,对于 $$ chaincodeID_i $$,假设其包括 $$ N $$ 个键值对,则聚合 $$G_i$$ 内容可以计算为: + +$$ G_i = Len(chaincodeID_i) + chaincodeID_i + N + \sum_{1}^{N} {len(key_j) + key_j + len(value_j) + value_j} $$ + +该桶的内容则为 + +$$ bucket = \sum_{1}^{M} G_i $$ + +*注:这里的 `+` 代表字符串拼接,并非数学运算。* + +### 链码服务 + +链码包含所有的处理逻辑,并对外提供接口,外部通过调用链码接口来改变世界观。 + +#### 接口和操作 +链码需要实现 Chaincode 接口,以被 VP 节点调用。 + +```go +type Chaincode interface { Init(stub *ChaincodeStub, function string, args []string) ([]byte, error) Invoke(stub *ChaincodeStub, function string, args []string) ([]byte, error) Query(stub *ChaincodeStub, function string, args []string) ([]byte, error)} +``` + +链码目前支持的交易类型包括:部署(Deploy)、调用(Invoke)和查询(Query)。 + +* 部署:VP 节点利用链码创建沙盒,沙盒启动后,处理 protobuf 协议的 shim 层一次性发送包含 ChaincodeID 信息的 REGISTER 消息给 VP 节点,进行注册,注册完成后,VP 节点通过 gRPC 传递参数并调用链码 Init 函数完成初始化; +* 调用:VP 节点发送 TRANSACTION 消息给链码沙盒的 shim 层,shim 层用传过来的参数调用链码的 Invoke 函数完成调用; +* 查询:VP 节点发送 QUERY 消息给链码沙盒的 shim 层,shim 层用传过来的参数调用链码的 Query 函数完成查询。 + +不同链码之间可能互相调用和查询。 + +#### 容器 + +在实现上,链码需要运行在隔离的容器中,超级账本采用了 Docker 作为默认容器。 + +对容器的操作支持三种方法:build、start、stop,对应的接口为 VM。 + +```go +type VM interface { + build(ctxt context.Context, id string, args []string, env []string, attachstdin bool, attachstdout bool, reader io.Reader) error + start(ctxt context.Context, id string, args []string, env []string, attachstdin bool, attachstdout bool) error + stop(ctxt context.Context, id string, timeout uint, dontkill bool, dontremove bool) error +} +``` +链码部署成功后,会创建连接到部署它的 VP 节点的 gRPC 通道,以接受后续 Invoke 或 Query 指令。 + + +#### gRPC 消息 +VP 节点和容器之间通过 gRPC 消息来交互。消息基本结构为 + +```protobuf +message ChaincodeMessage { + + enum Type { UNDEFINED = 0; REGISTER = 1; REGISTERED = 2; INIT = 3; READY = 4; TRANSACTION = 5; COMPLETED = 6; ERROR = 7; GET_STATE = 8; PUT_STATE = 9; DEL_STATE = 10; INVOKE_CHAINCODE = 11; INVOKE_QUERY = 12; RESPONSE = 13; QUERY = 14; QUERY_COMPLETED = 15; QUERY_ERROR = 16; RANGE_QUERY_STATE = 17; } + + Type type = 1; google.protobuf.Timestamp timestamp = 2; bytes payload = 3; string uuid = 4;} +``` + +当发生链码部署时,容器启动后发送 `REGISTER` 消息到 VP 节点。如果成功,VP 节点返回 `REGISTERED` 消息,并发送 `INIT` 消息到容器,调用链码中的 Init 方法。 + +当发生链码调用时,VP 节点发送 `TRANSACTION` 消息到容器,调用其 Invoke 方法。如果成功,容器会返回 `RESPONSE` 消息。 + +类似的,当发生链码查询时,VP 节点发送 `QUERY` 消息到容器,调用其 Query 方法。如果成功,容器会返回 `RESPONSE` 消息。 + +### 成员权限管理 + +通过基于 PKI 的成员权限管理,平台可以对接入的节点和客户端的能力进行限制。 + +证书有三种,Enrollment,Transaction,以及确保安全通信的 TLS 证书。 + +* 注册证书 ECert:颁发给提供了注册凭证的用户或节点,一般长期有效; +* 交易证书 TCert:颁发给用户,控制每个交易的权限,一般针对某个交易,短期有效。 +* 通信证书 TLSCert:控制对网络的访问,并且防止窃听。 + +![](_images/memserv-components.png) + +### 新的架构设计 +目前,VP 节点执行了所有的操作,包括接收交易,进行交易验证,进行一致性达成,进行账本维护等。这些功能的耦合导致节点性能很难进行扩展。 + +新的思路就是对这些功能进行解耦,让每个功能都相对单一,容易进行扩展。社区内已经有了一些讨论。 + +Fabric 1.0 的设计采用了适当的解耦,根据功能将节点角色解耦开,让不同节点处理不同类型的工作负载。 + +![示例工作过程](_images/dataflow.png) + +* 客户端:客户端应用使用 SDK 来跟 Fabric 打交道,构造合法的交易提案提交给 endorser;收集到足够多 endorser 支持后可以构造合法的交易请求,发给 orderer 或代理节点。 +* Endorser peer:负责对来自客户端的交易进行合法性和 ACL 权限检查(模拟交易),通过则签名并返回结果给客户端。 +* Committer peer:负责维护账本,将达成一致顺序的批量交易结果进行状态检查,生成区块,执行合法的交易,并写入账本,同一个物理节点可以同时担任 endorser 和 committer 的 角色。 +* Orderer:仅负责排序,给交易们一个全局的排序,一般不需要跟账本和交易内容打交道。 +* CA:负责所有证书的维护,遵循 PKI。 + +![示例交易过程](_images/transaction_flow.png) diff --git a/chainbrock-learning/13_fabric_design/intro.md b/chainbrock-learning/13_fabric_design/intro.md new file mode 100644 index 00000000..13c78993 --- /dev/null +++ b/chainbrock-learning/13_fabric_design/intro.md @@ -0,0 +1 @@ +## 简介 \ No newline at end of file diff --git a/chainbrock-learning/13_fabric_design/protocol.md b/chainbrock-learning/13_fabric_design/protocol.md new file mode 100644 index 00000000..54872bf6 --- /dev/null +++ b/chainbrock-learning/13_fabric_design/protocol.md @@ -0,0 +1,88 @@ +## 消息协议 + +节点之间通过消息来进行交互,所有消息都由下面的数据结构来实现。 + +```protobuf +message Message { + enum Type { + UNDEFINED = 0; + + DISC_HELLO = 1; + DISC_DISCONNECT = 2; + DISC_GET_PEERS = 3; + DISC_PEERS = 4; + DISC_NEWMSG = 5; + + CHAIN_STATUS = 6; + CHAIN_TRANSACTION = 7; + CHAIN_GET_TRANSACTIONS = 8; + CHAIN_QUERY = 9; + + SYNC_GET_BLOCKS = 11; + SYNC_BLOCKS = 12; + SYNC_BLOCK_ADDED = 13; + + SYNC_STATE_GET_SNAPSHOT = 14; + SYNC_STATE_SNAPSHOT = 15; + SYNC_STATE_GET_DELTAS = 16; + SYNC_STATE_DELTAS = 17; + + RESPONSE = 20; + CONSENSUS = 21; + } + Type type = 1; + bytes payload = 2; + google.protobuf.Timestamp timestamp = 3; +} +``` + +消息分为四大类:Discovery(探测)、Transaction(交易)、Synchronization(同步)、Consensus(一致性)。 + +不同消息类型,对应到 payload 中数据不同,分为对应的子类消息结构。 + +### Discovery + +包括 DISC_HELLO、DISC_GET_PEERS、DISC_PEERS。 + +DISC_HELLO 消息结构如下。 + +```protobuf +message HelloMessage { PeerEndpoint peerEndpoint = 1; uint64 blockNumber = 2;}message PeerEndpoint { PeerID ID = 1; string address = 2; enum Type { UNDEFINED = 0; VALIDATOR = 1; NON_VALIDATOR = 2; } Type type = 3; bytes pkiID = 4;} + +message PeerID { string name = 1;} +``` + +节点新加入网络时,会向 `CORE_PEER_DISCOVERY_ROOTNODE` 发送 `DISC_HELLO` 消息,汇报本节点的信息(id、地址、block 数、类型等),开始探测过程。 + +探测后发现 block 数落后对方,则会触发同步过程。 + +之后,定期发送 `DISC_GET_PEERS` 消息,获取新加入的节点信息。收到 `DISC_GET_PEERS` 消息的节点会通过 `DISC_PEERS` 消息返回自己知道的节点列表。 + +### Transaction + +包括 Deploy、Invoke、Query。消息结构如下: + +```protobuf +message Transaction { enum Type { UNDEFINED = 0; CHAINCODE_DEPLOY = 1; CHAINCODE_INVOKE = 2; CHAINCODE_QUERY = 3; CHAINCODE_TERMINATE = 4; } Type type = 1; string uuid = 5; bytes chaincodeID = 2; bytes payloadHash = 3; + + ConfidentialityLevel confidentialityLevel = 7; bytes nonce = 8; bytes cert = 9; bytes signature = 10; + + bytes metadata = 4; google.protobuf.Timestamp timestamp = 6;} + +message TransactionPayload { bytes payload = 1;} + +enum ConfidentialityLevel { PUBLIC = 0; CONFIDENTIAL = 1;} +``` + +### Synchronization +当节点发现自己 block 落后网络中最新状态,则可以通过发送如下消息(由 consensus 策略决定)来获取对应的返回。 + +* SYNC_GET_BLOCKS(对应 SYNC_BLOCKS):获取给定范围内的 block 数据; +* SYNC_STATE_GET_SNAPSHOT(对应 SYNC_STATE_SNAPSHOT):获取最新的世界观快照; +* SYNC_STATE_GET_DELTAS(对应 SYNC_STATE_DELTAS):获取某个给定范围内的 block 对应的状态变更。 + +### Consensus + +consensus 组件收到 `CHAIN_TRANSACTION` 类消息后,将其转换为 `CONENSUS` 消息,然后向所有的 VP 节点广播。 + +收到 `CONSENSUS` 消息的节点会按照预定的 consensus 算法进行处理。 diff --git a/chainbrock-learning/13_fabric_design/summary.md b/chainbrock-learning/13_fabric_design/summary.md new file mode 100644 index 00000000..45cd728a --- /dev/null +++ b/chainbrock-learning/13_fabric_design/summary.md @@ -0,0 +1 @@ +## 本章小结 \ No newline at end of file diff --git a/chainbrock-learning/17_baas/README.md b/chainbrock-learning/17_baas/README.md new file mode 100644 index 00000000..4845c5c8 --- /dev/null +++ b/chainbrock-learning/17_baas/README.md @@ -0,0 +1,9 @@ +# 区块链服务平台设计 + +** 规模是困难之源。 ** + +信息产业过去的十年,是云计算的十年。云计算技术为传统信息行业带来了前所未有的便捷。用户无需在意底层实现细节,通过简单的操作,即可获得可用的计算资源,节约大量运维管理的时间成本。 + +区块链平台作为分布式基础设施,其部署和维护过程需要多方面的技能,这对很多应用开发者来说都是不小的挑战。为了解决这些问题,区块链即服务(Blockchain as a Service, BaaS)平台应运而生。BaaS 可以利用云服务基础设施的部署和管理优势,为开发者提供创建、使用,甚至安全监控区块链平台的快捷服务。目前,业界已有一些区块链前沿技术团队率先开发并上线了区块链服务平台。 + +本章将首先介绍 BaaS 的概念,之后分别介绍业界领先的 IBM Bluemix 和微软 Azure 云上所提供的区块链服务。最后,还介绍了超级账本的区块链管理平台 —— Cello 项目,以及如何使用它快速搭建一套可以个性化的区块链服务平台。 diff --git a/chainbrock-learning/17_baas/_images/azure_admin.png b/chainbrock-learning/17_baas/_images/azure_admin.png new file mode 100644 index 00000000..b75a9620 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/azure_admin.png differ diff --git a/chainbrock-learning/17_baas/_images/azure_config.png b/chainbrock-learning/17_baas/_images/azure_config.png new file mode 100644 index 00000000..2e845fcf Binary files /dev/null and b/chainbrock-learning/17_baas/_images/azure_config.png differ diff --git a/chainbrock-learning/17_baas/_images/azure_deploy.png b/chainbrock-learning/17_baas/_images/azure_deploy.png new file mode 100644 index 00000000..e7720532 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/azure_deploy.png differ diff --git a/chainbrock-learning/17_baas/_images/azure_marketplace.png b/chainbrock-learning/17_baas/_images/azure_marketplace.png new file mode 100644 index 00000000..0828b1de Binary files /dev/null and b/chainbrock-learning/17_baas/_images/azure_marketplace.png differ diff --git a/chainbrock-learning/17_baas/_images/bluemix_blockchain.png b/chainbrock-learning/17_baas/_images/bluemix_blockchain.png new file mode 100644 index 00000000..624a89f5 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/bluemix_blockchain.png differ diff --git a/chainbrock-learning/17_baas/_images/bluemix_chaincode.png b/chainbrock-learning/17_baas/_images/bluemix_chaincode.png new file mode 100644 index 00000000..822a36dc Binary files /dev/null and b/chainbrock-learning/17_baas/_images/bluemix_chaincode.png differ diff --git a/chainbrock-learning/17_baas/_images/bluemix_dashboard.png b/chainbrock-learning/17_baas/_images/bluemix_dashboard.png new file mode 100644 index 00000000..4aa03bc9 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/bluemix_dashboard.png differ diff --git a/chainbrock-learning/17_baas/_images/bluemix_status.png b/chainbrock-learning/17_baas/_images/bluemix_status.png new file mode 100644 index 00000000..42c28fec Binary files /dev/null and b/chainbrock-learning/17_baas/_images/bluemix_status.png differ diff --git a/chainbrock-learning/17_baas/_images/cello.png b/chainbrock-learning/17_baas/_images/cello.png new file mode 100644 index 00000000..fb9f2b77 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_arch.png b/chainbrock-learning/17_baas/_images/cello_arch.png new file mode 100644 index 00000000..6bebb9f8 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_arch.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_dashboard.png b/chainbrock-learning/17_baas/_images/cello_dashboard.png new file mode 100644 index 00000000..fdf05169 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_dashboard.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_dashboard_activechains.png b/chainbrock-learning/17_baas/_images/cello_dashboard_activechains.png new file mode 100644 index 00000000..1354ffec Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_dashboard_activechains.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_dashboard_addcluster.png b/chainbrock-learning/17_baas/_images/cello_dashboard_addcluster.png new file mode 100644 index 00000000..47d81909 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_dashboard_addcluster.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_dashboard_addhost.png b/chainbrock-learning/17_baas/_images/cello_dashboard_addhost.png new file mode 100644 index 00000000..b1d9163d Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_dashboard_addhost.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_dashboard_hosts.png b/chainbrock-learning/17_baas/_images/cello_dashboard_hosts.png new file mode 100644 index 00000000..20c8fc31 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_dashboard_hosts.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_deployment_topo.png b/chainbrock-learning/17_baas/_images/cello_deployment_topo.png new file mode 100644 index 00000000..11bc0873 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_deployment_topo.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_operate.png b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_operate.png new file mode 100644 index 00000000..34146200 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_operate.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_running.png b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_running.png new file mode 100644 index 00000000..c2098c7e Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_running.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_template.png b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_template.png new file mode 100644 index 00000000..72da9d28 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_template.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_template_info.png b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_template_info.png new file mode 100644 index 00000000..1ca7a5dd Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_code_template_info.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_info.png b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_info.png new file mode 100644 index 00000000..38bfb025 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_info.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_list.png b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_list.png new file mode 100644 index 00000000..d51b4b27 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_user_dashboard_chain_list.png differ diff --git a/chainbrock-learning/17_baas/_images/cello_user_dashboard_login.png b/chainbrock-learning/17_baas/_images/cello_user_dashboard_login.png new file mode 100644 index 00000000..b1e8d24a Binary files /dev/null and b/chainbrock-learning/17_baas/_images/cello_user_dashboard_login.png differ diff --git a/chainbrock-learning/17_baas/_images/refarch.png b/chainbrock-learning/17_baas/_images/refarch.png new file mode 100644 index 00000000..8f666720 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/refarch.png differ diff --git a/chainbrock-learning/17_baas/_images/sv_home.png b/chainbrock-learning/17_baas/_images/sv_home.png new file mode 100644 index 00000000..359b45c9 Binary files /dev/null and b/chainbrock-learning/17_baas/_images/sv_home.png differ diff --git a/chainbrock-learning/17_baas/_images/sv_smart_contract.png b/chainbrock-learning/17_baas/_images/sv_smart_contract.png new file mode 100644 index 00000000..91352b4c Binary files /dev/null and b/chainbrock-learning/17_baas/_images/sv_smart_contract.png differ diff --git a/chainbrock-learning/17_baas/azure.md b/chainbrock-learning/17_baas/azure.md new file mode 100644 index 00000000..282a8a96 --- /dev/null +++ b/chainbrock-learning/17_baas/azure.md @@ -0,0 +1,33 @@ +## 微软 Azure 云区块链服务 + +Azure 是微软推出的云计算平台,向用户提供开放的 IaaS 和 PaaS 服务。 + +Azure 陆续在其应用市场中提供了若干个与区块链相关的服务,分别面向多种不同的区块链底层平台,其中包括以太坊和超级账本 Fabric。 + +可以在应用市场(https://azuremarketplace.microsoft.com/en-us/marketplace/apps)中搜索 “blockchain” 关键字查看这些服务,如下图所示。 + +![Azure 上的区块链服务](_images/azure_marketplace.png) + +下面具体介绍其中的 Azure Blockchain Service。 + +### 使用服务 + +使用 Azure 服务,用户可以在几分钟之内在云中部署一个区块链网络。云平台会将一些耗时的配置流程自动化,使用户专注在上层应用方案。 + +Azure 区块链服务目前支持部署以太坊或超级账本 Fabric 网络。 + +下面以以太坊为例,在 Azure 的仪表盘中,选择创建 Ethereum Consortium Blockchain 后,输入一些配置选项,则可以开始部署该模拟网络,如下图所示。 + +![Azure 区块链配置](_images/azure_config.png) + +部署过程需要几分钟时间。完成后,可进入资源组查看部署结果,如下图所示,成功部署了一个以太坊网络。 + +![Azure 区块链部署结果](_images/azure_deploy.png) + +点击 microsoft-azure-blockchain 开头的链接,可以查看网络的一些关键接口,包括管理网址、RPC 接口地址等。 + +复制管理网址 ADMIN-SITE 的链接,用浏览器打开,可以进入区块链管理界面。界面中可查看网络各节点信息,也可以新建一个账户,并从 admin 账户向其发送 1000 个以太币。结果如下图所示。 + +![Azure 区块链管理界面](_images/azure_admin.png) + +Azure 云平台提供了相对简单的操作界面,更多的是希望用户通过 RPC 接口地址来访问所部署的区块链示例。用户可以自行通过 RPC 接口与以太坊模拟网络交互,部署和测试智能合约,此处不再赘述。 \ No newline at end of file diff --git a/chainbrock-learning/17_baas/bluemix.md b/chainbrock-learning/17_baas/bluemix.md new file mode 100644 index 00000000..0bbd1b60 --- /dev/null +++ b/chainbrock-learning/17_baas/bluemix.md @@ -0,0 +1,35 @@ +## IBM Bluemix 云区块链服务 + +Bluemix 是 IBM 推出的开放的 PaaS 云平台,包含大量平台和软件服务,旨在帮助开发者实现一站式地应用开发与部署管理。 + +2016 年,Bluemix 面向开发者推出了基于超级账本 Fabric 的区块链服务,供全球的区块链爱好者使用。用户可以通过访问 https://console.ng.bluemix.net/catalog/services/blockchain 使用该服务。 + +### 服务介绍 + +Bluemix 为用户提供了在云上灵活管理超级账本 Fabric 区块链网络的能力,让开发者专注于快速创建、操作和监控区块链网络,而无需过多考虑底层硬件资源。同时,Bluemix 云平台本身也提供了安全、隐私性方面的保障,并对相关资源进行了性能优化。 + +Bluemix 目前提供了几种不同类型的区块链网络部署方案,包括免费的基础套餐到收费的高性能方案等。不同方案针对开发者的不同需求,在运行环境、占用资源、配置方式上都有所区别。 + +对于超级账本 Fabric 网络试用者,可选择免费的基础套餐,获得一个包含各类型 Peer 节点和 CA 的完整区块链试用网络,用户可以自行尝试部署链码并实时观察账本状态的变化。 + +### 使用服务 + +Bluemix 云平台提供的仪表盘(Dashboard)提供了十分直观的管理方式,用户可以通过 Web 界面来获取和访问区块链资源。 + +如下图所示,用户创建网络后,可以进入 Dashboard 看到属于自己的区块链网络,同时观察各节点的状态,以及与身份认证相关的服务凭证。 + +![Bluemix 区块链服务仪表盘](_images/bluemix_dashboard.png) + +对于已经申请到的区块链网络,用户可以通过 Dashboard 对其部署并调用链码,并实时查看响应结果。例如,下图中展示了部署自带的 example02 链码。 + +![通过 Dashboard 操作链码](_images/bluemix_chaincode.png) + +对链码的操作会发送交易,进而生成新的区块。可通过 Dashboard 观察与区块链状态、区块内容相关的信息。例如,下图中区块链生成了 4 个区块,并执行了 1 次部署和 2 次调用。 + +![通过 Dashboard 观察区块链](_images/bluemix_blockchain.png) + +平台同时会收集各节点的日志信息,监控和记录服务的运行状态。用户同样可以在 Dashboard 中实时查看。如下图所示,显示了服务和网络的正常运行时间等。 + +![通过 Dashboard 获取服务状态](_images/bluemix_status.png) + +同时,Bluemix 云平台会将与区块链网络交互所需的 gRPC 或 HTTP 接口地址开放给用户,供用户通过 SDK 等进行远程操作,实现更多跟区块链、链码和应用相关的丰富功能。 \ No newline at end of file diff --git a/chainbrock-learning/17_baas/cello.md b/chainbrock-learning/17_baas/cello.md new file mode 100644 index 00000000..d81aa1b1 --- /dev/null +++ b/chainbrock-learning/17_baas/cello.md @@ -0,0 +1,248 @@ +## 使用超级账本 Cello 搭建区块链服务 + +从前面的讲解中可以看到,区块链服务平台能够有效加速对区块链技术的应用,解决企业和开发者进行手动运营管理的负担。但是这些方案都是商业用途,并且只能在线使用。 + +![Cello 典型应用场景](_images/cello.png) + +超级账本的 Cello 项目为本地搭建区块链服务管理平台提供了开源的解决方案,可以实现在多种类型的物理资源上实现区块链网络的生命周期管理。 + +正如 Cello 的名字所蕴意,它就像一把精巧的大提琴,以区块链为琴弦,可以奏出更加动人的乐章。 + +### 基本架构和特性 + +Cello 项目由笔者领导的 IBM 技术团队于 2017 年 1 月贡献到超级账本社区,主要基于 Python 和 Javascript 语言编写。该项目的定位为区块链管理平台,支持部署、运行时管理和数据分析等功能,可以实现一套完整的 BaaS 系统的快速搭建。其基本架构如下图所示。 + +![Cello 基本架构](_images/cello_arch.png) + +在实现区块链环境快速部署的同时,Cello 也提供了不少对区块链平台进行运行时管理的特性,这些特性总结如下。 + +* 管理区块链的全生命周期,包括创建、配置、使用、健康检查、删除等。 +* 支持多种基础架构作为底层资源池,包括裸机、虚拟机、容器云(Docker、Swarm、Kubernetes)等。 +* 支持多种区块链平台及自定义配置(目前以支持超级账本 Fabric 为主)。 +* 支持监控和分析功能,实现对区块链网络和智能合约的运行状况分析。 +* 提供可插拔的框架设计,包括区块链平台、资源调度、监控、驱动代理等都很容易引入第三方实现。 + +下面具体介绍如何以 Docker 主机为资源池,用 Cello 快速搭建一个区块链服务平台。 + +### 环境准备 + +Cello 采用了典型的主从(Master-Worker)架构。用户可以自行准备一个 Master 物理节点和若干个 Worker 节点。 + +其中,Master 节点负责管理(例如,创建和删除)Worker 节点中的区块链集群,其通过 8080 端口对外提供网页 Dashboard,通过 80 端口对外提供 RESTful API。Worker 节点负责提供区块链集群的物理资源,例如基于 Docker 主机或 Swarm 的方式启动多个集群,作为提供给用户可选的多个区块链网络环境。 + +下图中展示了一个典型的 Master-Worker 部署拓扑。每个节点默认为 Linux(如 Ubuntu 16.04)服务器或虚拟机。 + +![Cello 部署拓扑示例](_images/cello_deployment_topo.png) + +为了支持区块链网络,Worker 和 Master 节点需要配备足够的物理资源。例如,如果希望在一个 Worker 节点上能够启动至少 10 个区块链集群,则建议节点配置至少为 8 CPU、16G 内存、100G 硬盘容量。 + +### 下载 Cello 源码 + +Cello 代码的官方仓库在社区的 gerrit 上,并实时同步到 Github 仓库中,读者可以从任一仓库中获取代码。例如通过如下命令从官方仓库下载 Cello 源码。 + +```sh +$ git clone http://gerrit.hyperledger.org/r/cello && cd cello +``` + + +### 配置 Worker 节点 + +#### 安装和配置 Docker 服务 + +首先安装 Docker,推荐使用 1.12 或者更新的版本。可通过如下命令快速安装 Docker。 + +```sh +$ curl -fsSL https://get.docker.com/ | sh +``` +安装成功后,修改 Docker 服务配置。对于 Ubuntu 16.04,更新 `/lib/systemd/system/docker.service` 文件如下。 + +```sh +[Service] +DOCKER_OPTS="$DOCKER_OPTS -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --api-cors-header='*' --default-ulimit=nofile=8192:16384 --default-ulimit=nproc=8192:16384" +EnvironmentFile=-/etc/default/docker +ExecStart= +ExecStart=/usr/bin/dockerd -H fd:// $DOCKER_OPTS +``` + +修改后,需要通过如下命令重启 Docker 服务。 + +```sh +$ sudo systemctl daemon-reload +$ sudo systemctl restart docker.service +``` + + +#### 下载 Docker 镜像 + +对于超级账本 Fabric v1.0 集群所需的镜像,可以使用如下命令进行自动下载。 + +```sh +$ cd scripts/worker_node_setup && bash download_images.sh +``` + +#### 防火墙配置 + +为了确保 Worker 上的容器可以正常访问,通过如下命令确保主机开启 IP 转发。 + +```sh +$ sysctl -w net.ipv4.ip_forward=1 +``` + +同时检查主机的 iptables 设置,确保必要的端口被打开(如 2375、7050~10000 等)。 + +### 配置 Master 节点 + +#### 下载 Docker 镜像 + +使用如下命令下载运行服务所必要的 Docker 镜像。 + +其中,python:3.5 镜像是运行 Cello 核心组件的基础镜像;mongo:3.2 提供了数据库服务;yeasy/nginx:latest 提供了 Nginx 转发功能;mongo-express:0.30 镜像是为了调试数据库,可以选择性安装。 + +```sh +$ docker pull python:3.5 \ + && docker pull mongo:3.2 \ + && docker pull yeasy/nginx:latest \ + && docker pull mongo-express:0.30 +``` + +#### 安装 Cello 服务 + +首次运行时,可以通过如下命令对 Master 节点进行快速配置,包括安装 Docker 环境、创建本地数据库目录、安装依赖软件包等。 + +```sh +$ make setup +``` + +如果安装过程没有提示出现问题,则说明当前环境满足了运行条件。如果出现问题,可通过查看日志信息进行定位。 + +#### 管理 Cello 服务 + +可以通过运行如下命令来快速启动 Cello 相关的组件服务(包括 dashboard、restserver、watchdog、mongo、nginx 等)。 + +```sh +$ make start +``` + +类似地,运行 `make stop` 或 `make restart` 可以停止或重启全部服务。 + +若希望重新部署某个特定服务(如 dashboard),可运行如下命令。 + +```sh +$ make redeploy service=dashboard +``` + +运行如下命令可以实时查看所有服务的日志信息。 + +```sh +$ make logs +``` + +若希望查看某个特定服务的日志,可运行如下命令进行过滤,如只查看 watchdog 组件的日志。 + +```sh +$ make log service=watchdog +``` + +### 使用 Cello 管理区块链 + +Cello 服务启动后,管理员可以通过 Cello 的 Dashboard 页面管理区块链。 + +默认情况下,可通过 Master 节点的 8080 端口访问 Dashboard。默认的登录用户名和密码为 `admin:pass`。 + +![Cello Dashboard](_images/cello_dashboard.png) + +如图,Dashboard 有多个页面,各页面的功能如下。 + +| 页面 | 功能 | +| --- | --- | +| Overview | 展示系统整体状态 | +| System Status | 展示一些统计信息 | +| Hosts | 管理所有主机(Worker 节点) | +| Active Chains | 管理资源池中的所有链 | +| Inused Chains | 管理正在被用户占用的链 | +| Released History | 查看链的释放历史 | + +#### Hosts 页面 + +在 Hosts 页面,管理员可以管理所有资源池中已存在的主机,或添加新主机。表格中会显示主机的类型、状态、正在运行的区块链数量、区块链数量上限等。所有设定为 non-schedulable (不会自动分配给用户)的主机会用灰色背景标识,如下图所示。 + +![Hosts 页面](_images/cello_dashboard_hosts.png) + +点击一个主机的 Action 下拉菜单,有如下选项可供操作该主机。 + +* Fillup:将主机运行的区块链数添加至上限。 +* Clean:清理主机中所有未被用户占用的链。 +* Config:更改主机配置,如名称和链数量上限。 +* Reset:重置该主机,只有当该主机没有用户占用的链时可以使用。 +* Delete:从资源池中删除该主机。 + +点击 Hosts 页面的 Add Host 按钮,可以向资源池中添加主机。需要设定该主机的名称、Daemon URL 地址(例如,Worker 节点的 docker daemon 监听地址和端口)、链数量上限、日志配置、是否启动区块链至数量上限、是否可向用户自动分配,如下图所示。 + +![添加主机](_images/cello_dashboard_addhost.png) + +#### Active Chains 页面 + +Active Chains 页面会显示所有正在运行的链,包括链的名称、类型、状态、健康状况、规模、所属主机等信息。正在被用户占用的链会用灰色背景标识,如下图所示。 + +![Active Chains 页面](_images/cello_dashboard_activechains.png) + +点击一条链的 Actions 下拉菜单,有如下选项可供操作该链。 + +* Start:如果这条链处于停止状态,则启动。 +* Stop:停止运行中的链。 +* Restart:重新启动这条链。 +* Delete:删除这条链。 +* Release:将占用的链释放,随后会被删除。 + +点击 Active Chains 页面的 Add Chain 按钮,可以向资源池中添加更多链(如果还有未被占满的主机),如下图所示。 + +![添加链](_images/cello_dashboard_addcluster.png) + +### 用户控制台,申请使用Chain + +用户可以登录User Dashboard来申请和使用Chain + +![登录页面](_images/cello_user_dashboard_login.png) + +#### Chain列表页面 + +Chain列表页面显示所有用户已经申请的链。 + +![Chain列表页面](_images/cello_user_dashboard_chain_list.png) + +#### Chain详情页面 + +Chain详情页面可以查看链的基本信息(链高度,channel数,链码安装/实例化个数,最近的block/transaction),操作历史记录。 + +![Chain详情页面](_images/cello_user_dashboard_chain_info.png) + +#### 智能合约模板列表页面 + +这个页面列取用户自己上传的智能合约代码模板,支持多个版本管理。 + +![智能合约模板列取页面](_images/cello_user_dashboard_chain_code_template.png) + +#### 智能合约模板详情页面 + +在合约模板详情页面可以查看智能合约模板的详情,包括合约多版本列表,部署列表,部署合约。 + +![智能合约详情页面](_images/cello_user_dashboard_chain_code_template_info.png) + +#### 智能合约操作页面 + +在这个页面可以invoke/query已经部署好的智能合约。 + +![智能合约操作页面](_images/cello_user_dashboard_chain_code_operate.png) + +#### 智能合约运行列表页面 + +这个页面可以查看所有已经部署,包括成功和失败的智能合约的列表。 + +![智能合约运行列表页面](_images/cello_user_dashboard_chain_code_running.png) + +### 基于 Cello 进行功能扩展 +Cello 已经提供了完整的区块链管理功能,并提供了图形界面和 API。 + +用户可以通过向 Cello 的 Master 节点(默认为 80 端口)发送 RESTful API 来申请、释放区块链,或查看区块链相关信息,如其对外开放的接口,可供用户进行远程交互。RESTful API 的说明可在 Cello 的文档中查阅。 + +对于区块链服务提供者,可以利用这些 API 为用户呈现友好的区块链申请和操作界面,在 Cello 的基础之上构建和实现更多功能。 \ No newline at end of file diff --git a/chainbrock-learning/17_baas/intro.md b/chainbrock-learning/17_baas/intro.md new file mode 100644 index 00000000..65570369 --- /dev/null +++ b/chainbrock-learning/17_baas/intro.md @@ -0,0 +1,40 @@ +## 简介 + +区块链即服务(Blockchain as a Service,BaaS),是部署在云计算基础设施之上,对外提供区块链网络的生命周期管理和运行时服务管理等功能的一套工具。 + +构建一套分布式的区块链方案绝非易事,既需要硬件基础设施的投入,也需要全方位的开发和运营管理(DevOps)。BaaS 作为一套工具,可以帮助开发者快速生成必要的区块链环境,进而验证所开发的上层应用。 + +除了区块链平台本身,一套完整的解决方案实际上还可以包括设备接入、访问控制、服务监控等管理功能。这些功能,让 BaaS 平台可以为开发者提供更强大的服务支持。 + +从 2016 年起,业界已有一些前沿技术团队发布了 BaaS 平台,除了商业的方案如 IBM Bluemix 和微软 Azure 云之外,超级账本开源项目也发起了 Cello 项目,以提供一套实现区块链平台运营管理功能的开源框架。 + +### 参考架构 + +下图给出了区块链即服务功能的参考架构,自上而下分为多层结构。最上层面向应用开发者和平台管理员提供不同的操作能力;核心层负责完成包括资源编排、系统监控、数据分析和权限管理等重要功能;下层可以通过多种类型的驱动和代理组件来访问和管理多种物理资源。 + +![区块链服务参考架构](_images/refarch.png) + + +典型地,BaaS 平台所提供的业务能力通常包括: + +* 用户按需申请区块链网络,以及所需的计算、存储与网络连接资源; +* 用户对申请到的区块链进行生命周期管理,甚至支持灵活、弹性的区块链配置; +* 通过提供接口,让用户自由访问所申请到的区块链网络并进行调用; +* 提供直观的区块链可视化监控与操作界面,将区块链应用与底层平台无缝对接; +* 提供简单易用的智能合约开发与测试环境,方便用户对应用代码进行管理; +* 为管理员提供用户管理和资源管理操作; +* 为管理员提供对系统各项健康状态的实时监控; +* 提供对平台内各项资源和应用层的数据分析和响应能力。 + +### 考量指标 + +对于 BaaS 服务提供方,搭建这样一套功能完善、性能稳定的 BaaS 平台存在诸多挑战。可以从如下几个角度进行考量设计。 + +* 性能保障:包括区块链和应用的响应速度,监控实时性等; +* 可扩展性:支持大规模场景下部署和管理的能力,可以快速进行扩展; +* 资源调度:对于非均匀的资源请求类型可以智能的予以平缓化处理,合理分配系统资源; +* 安全性:注意平衡用户操作区块链的自由度与平台自身的安全可控; +* 可感知性:深度感知数据行为,如可以准确实时评估区块链的运行状况,给用户启发; +* 底层资源普适性:底层应当支持多种混合计算架构,容易导入物理资源。 + +此外,对于面向开发者的 BaaS 服务,创建的区块链环境应当尽量贴近实际应用场景,让用户可以将经过检验的区块链模型很容易地迁移到生产环境。甚至可以直接联动支持第三方发布平台,直接将经过验证的应用推向发布环境。 diff --git a/chainbrock-learning/17_baas/summary.md b/chainbrock-learning/17_baas/summary.md new file mode 100644 index 00000000..d31ddd39 --- /dev/null +++ b/chainbrock-learning/17_baas/summary.md @@ -0,0 +1,7 @@ +## 本章小结 + +本章介绍了区块链即服务的概念,阐述了整合云计算技术能够为区块链部署和管理所带来的便捷。接下来提出了区块链服务平台的参考架构,并从功能和性能等实践角度总结了平台设计的考量指标。 + +本章随后还介绍了业界领先的 IBM Bluemix 和微软 Azure 云上提供的区块链服务。最后讲解了如何使用超级账本 Cello 项目快速搭建一套个性化的区块链服务平台。 + +区块链技术的普及离不开生态系统和相关工具的成熟,区块链应用的落地同样离不开完善的 DevOps 支持。本章的内容能够给予读者不同的视角,从系统方案的角度出发,思考如何在新技术变革中保持应对变化的敏捷与高效。 \ No newline at end of file diff --git a/chainbrock-learning/SUMMARY.md b/chainbrock-learning/SUMMARY.md new file mode 100644 index 00000000..eda45469 --- /dev/null +++ b/chainbrock-learning/SUMMARY.md @@ -0,0 +1,128 @@ +# 区块链技术指南 + +* [前言](README.md) +* [修订记录](revision.md) +* [如何贡献](contribute.md) +* [区块链的诞生](01_history/README.md) + * [记账科技的千年演化](01_history/ledger_history.md) + * [分布式记账与区块链](01_history/dlt_problem.md) + * [集大成者的比特币](01_history/bitcoin.md) + * [区块链的商业价值](01_history/business.md) + * [本章小结](01_history/summary.md) +* [核心技术概览](02_overview/README.md) + * [定义与原理](02_overview/definition.md) + * [技术的演化与分类](02_overview/classify.md) + * [关键问题和挑战](02_overview/challenge.md) + * [趋势与展望](02_overview/vision.md) + * [认识上的误区](02_overview/misunderstand.md) + * [本章小结](02_overview/summary.md) +* [典型应用场景](03_scenario/README.md) + * [应用场景概览](03_scenario/glance.md) + * [金融服务](03_scenario/finance.md) + * [征信管理](03_scenario/trust.md) + * [权属管理与溯源](03_scenario/ownership.md) + * [资源共享](03_scenario/sharing.md) + * [物流与供应链](03_scenario/logistics.md) + * [物联网](03_scenario/iot.md) + * [数字艺术品和 NFT](03_scenario/nft.md) + * [其它场景](03_scenario/others.md) + * [本章小结](03_scenario/summary.md) +* [分布式系统核心技术](04_distributed_system/README.md) + * [一致性问题](04_distributed_system/problem.md) + * [共识算法](04_distributed_system/algorithms.md) + * [FLP 不可能原理](04_distributed_system/flp.md) + * [CAP 原理](04_distributed_system/cap.md) + * [ACID 原则与多阶段提交](04_distributed_system/acid.md) + * [Paxos 算法与 Raft 算法](04_distributed_system/paxos.md) + * [拜占庭问题与算法](04_distributed_system/bft.md) + * [可靠性指标](04_distributed_system/availability.md) + * [本章小结](04_distributed_system/summary.md) +* [密码学与安全技术](05_crypto/README.md) + * [密码学简史](05_crypto/history.md) + * [Hash 算法与数字摘要](05_crypto/hash.md) + * [加解密算法](05_crypto/algorithm.md) + * [消息认证码与数字签名](05_crypto/signature.md) + * [数字证书](05_crypto/cert.md) + * [PKI 体系](05_crypto/pki.md) + * [Merkle 树结构](05_crypto/merkle_trie.md) + * [Bloom Filter 结构](05_crypto/bloom_filter.md) + * [同态加密](05_crypto/homoencryption.md) + * [其它技术](05_crypto/others.md) + * [本章小结](05_crypto/summary.md) +* [比特币 —— 初露锋芒的区块链](06_bitcoin/README.md) + * [比特币项目简介](06_bitcoin/intro.md) + * [比特币诞生背景](06_bitcoin/currency.md) + * [工作原理](06_bitcoin/design.md) + * [挖矿过程](06_bitcoin/mining.md) + * [共识机制](06_bitcoin/consensus.md) + * [闪电网络](06_bitcoin/lightning_network.md) + * [侧链](06_bitcoin/sidechain.md) + * [热门问题](06_bitcoin/hot_topics.md) + * [相关工具](06_bitcoin/tools.md) + * [本章小结](06_bitcoin/summary.md) +* [以太坊 —— 挣脱加密货币的枷锁](07_ethereum/README.md) + * [以太坊项目简介](07_ethereum/intro.md) + * [核心概念](07_ethereum/concept.md) + * [主要设计](07_ethereum/design.md) + * [相关工具](07_ethereum/tools.md) + * [安装客户端](07_ethereum/install.md) + * [使用智能合约](07_ethereum/smart_contract.md) + * [智能合约案例:投票](07_ethereum/contract_example.md) + * [本章小结](07_ethereum/summary.md) +* [超级账本 —— 面向企业的分布式账本](08_hyperledger/README.md) + * [超级账本项目简介](08_hyperledger/intro.md) + * [社区组织结构](08_hyperledger/community.md) + * [顶级项目介绍](08_hyperledger/project.md) + * [开发必备工具](08_hyperledger/tools.md) + * [贡献代码](08_hyperledger/contribute.md) + * [本章小结](08_hyperledger/summary.md) +* [Fabric 安装与部署](09_fabric_deploy/README.md) + * [简介](09_fabric_deploy/intro.md) + * [本地编译组件](09_fabric_deploy/install_local.md) + * [容器方式获取](09_fabric_deploy/install_docker.md) + * [本地方式启动 Fabric 网络](09_fabric_deploy/start_local.md) + * [容器方式启动 Fabric 网络](09_fabric_deploy/start_docker.md) + * [本章小结](09_fabric_deploy/summary.md) + * [简介](fabric/intro.md) + * [使用 Fabric 1.0 版本](fabric/1.0.md) + * [使用 Fabric SDK Node](fabric/sdk-node.md) + * [Fabric v0.6](fabric/v0.6/README.md) + * [安装部署](fabric/v0.6/install.md) + * [使用 chaincode](fabric/v0.6/usage.md) + * [权限管理](fabric/v0.6/membersrcv-usage.md) + * [Python 客户端](fabric/v0.6/hyperledger-py.md) + * [小结](fabric/summary.md) +* [智能合约开发](11_app_dev/README.md) + * [简介](11_app_dev/intro.md) + * [链码概念与结构](11_app_dev/chaincode.md) + * [示例一:信息公证](11_app_dev/chaincode_example01.md) + * [示例二:交易资产](11_app_dev/chaincode_example02.md) + * [示例三:数字货币发行与管理](11_app_dev/chaincode_example03.md) + * [示例四:学历认证](11_app_dev/chaincode_example04.md) + * [示例五:社区能源共享](11_app_dev/chaincode_example05.md) + * [小结](11_app_dev/summary.md) +* [Fabric 架构与设计](13_fabric_design/README.md) + * [简介](13_fabric_design/intro.md) + * [架构设计](13_fabric_design/design.md) + * [消息协议](13_fabric_design/protocol.md) + * [小结](13_fabric_design/summary.md) +* [区块链服务平台设计](17_baas/README.md) + * [简介](17_baas/intro.md) + * [IBM Bluemix 云区块链服务](17_baas/bluemix.md) + * [微软 Azure 云区块链服务](17_baas/azure.md) + * [使用超级账本 Cello 搭建区块链服务](17_baas/cello.md) + * [本章小结](17_baas/summary.md) +* [性能与评测](evaluation/README.md) + * [简介](evaluation/intro.md) + * [Hyperledger Fabric v0.6](evaluation/hyperledger.md) + * [小结](evaluation/summary.md) +* [附录](appendix/README.md) + * [术语](appendix/terms.md) + * [常见问题](appendix/faq.md) + * [Go 语言开发相关](appendix/golang/README.md) + * [安装与配置 Golang 环境](appendix/golang/install.md) + * [编辑器与 IDE](appendix/golang/ide.md) + * [高效开发工具](appendix/golang/tools.md) + * [依赖管理](appendix/golang/package.md) + * [ProtoBuf 与 gRPC](appendix/grpc.md) + * [参考资源链接](appendix/resources.md) diff --git a/chainbrock-learning/appendix/README.md b/chainbrock-learning/appendix/README.md new file mode 100644 index 00000000..83a54825 --- /dev/null +++ b/chainbrock-learning/appendix/README.md @@ -0,0 +1 @@ +# 附录 diff --git a/chainbrock-learning/appendix/companies.md b/chainbrock-learning/appendix/companies.md new file mode 100644 index 00000000..91df512f --- /dev/null +++ b/chainbrock-learning/appendix/companies.md @@ -0,0 +1,46 @@ +## 相关企业和组织 + +排名不分先后,大部分信息来自互联网,不保证信息准确性,如有修改意见,欢迎联系。 + +### 国际 + +#### 企业 +* [IBM](https://www.ibm.com): 贡献区块链平台代码到 HyperLedger 项目,推动区块链产业发展,跟多家银行和企业进行区块链项目合作。 +* [DTCC]():贡献区块链代码到 HyperLedger 项目。 +* [Circle]():基于区块链的支付应用公司,已获得 6000 万美元 D 轮投资,投资者包括 IDG、百度、中金甲子、广大投资等,目前年交易额超过 10 亿美金。 +* [Consensus]():区块链创业团队,试图打造区块链平台技术和应用支撑,获得多家投资。 + +#### 组织 +* [R3 CEV](https://r3cev.com):创立于 2015 年 9 月,总部位于纽约的金融联盟组织,专注于研究和评估基于区块链的金融技术解决方案,由 40 多家国际金融机构组成,包括 Citi、BOA、高盛、摩根、瑞银、IBM、微软等。R3 开源技术已经 [宣布](www.newsbtc.com/2016/10/22/r3-corda-hyperledger-open-source/) 加入 HyperLedger 项目。 +* [HyperLedger 社区](https://hyperledger.org):创立于 2015 年 12 月的技术社区,由 Linux 基金会管理,包括 IBM、Accenture、Intel、J.P.Morgan、R3、DAH、DTCC、FUJITSU、HITACHI、SWIFT、Cisco 等多家企业参与成立,试图打造面向企业应用场景的分布式账本平台。 +* [Ethereum 社区](https://ethereum.org): 围绕以太坊区块链平台的开放社区。 +* [DAO](): Distributed Autonomous Organization,基于以太坊平台的公募基金(众筹)组织,或去中心化的风投。众筹资金超过 1.6 亿美金。 + + +### 国内 + +#### 学术界 + +* 清华大学 +* 中科院 +* 上海交通大学 + +#### 企业 + +* [中国电信]():研究区块链相关技术,包括去中心化共享经济平台等。 +* [世纪互联]():投资区块链技术团队,牵头成立“中关村区块链产业联盟”。 +* [银联]():关注区块链相关技术,尝试引入基于区块链的银行业积分系统。 +* [能链]():专注于能源产品相关的区块链应用。 +* [恒生电子]():2016 年牵头成立“金链盟”,希望通过区块链技术为金融行业提供更简单的产品。 +* [布比](https://bubi.cn):主要关注数字资产管理的技术型创业企业,区块链相关平台和产品。 +* [小蚁]():主要关注对资产和权益进行数字化,2014年于上海组建成立。 +* [火币]():国内较大的比特币交易代理平台。 +* [BeLink]():关注保险行业积分系统,主要产品为数贝荷包。 +* [BitSe]():主要产品为唯链(Vechain),面向物品防伪追踪、数字版权管理相关。 +* [万向集团]():投资多家区块链创业团队,致力于推动产业发展。 + +#### 组织 + +* 中关村区块链产业联盟:2016 年 2 月 3 日成立于北京,由世纪互联联合清华大学、北京邮电大学等高校、中国通信学会、中国联通研究院等运营商,及集佳、布比网络等公司发起; +* ChinaLedger:2016 年 4 月成立于上海,成员包括中证机构间报价系统股份有限公司、中钞信用卡产业发展有限公司北京智能卡技术研究院、万向区块链实验室、浙江股权交易中心、深圳招银前海金融资产交易中心、厦门国际金融资产交易中心、大连飞创信息技术有限公司、通联支付网络服务股份有限公司、上海矩真金融信息服务有限公司、深圳瀚德创客金融投资有限公司、乐视金融等; +* 金融区块链合作联盟(金链盟):2016 年 5 月 31 日成立于深圳,包括平安银行、恒生电子、京东金融、腾讯微众银行、华为、南方基金、国信证券、安信证券、招商证券、博时基金等 25 家公司与机构。 diff --git a/chainbrock-learning/appendix/faq.md b/chainbrock-learning/appendix/faq.md new file mode 100644 index 00000000..f93310c8 --- /dev/null +++ b/chainbrock-learning/appendix/faq.md @@ -0,0 +1,80 @@ +## 常见问题 + +### 通用问题 +**问:区块链是谁发明的,有什么特点?** + +答:区块链相关的思想最早由比特币的发明者-中本聪(化名)在白皮书中提出,将其作为比特币网络的核心支持技术。自那以后,区块链技术逐渐脱离比特币项目,成为一种通用的可以支持分布式记账能力的底层技术,具有非中心化和加密安全等特点。 + +**问:区块链和比特币是什么关系?** + +答:比特币是基于区块链技术的一种数字现金(cash)应用;区块链技术最早在比特币网络中得到应用和验证。比特币系统在 2009 年上线后面向全球提供服务,在无中心化管理的情况下运转至今。 + +**问:区块链和分布式数据库是什么关系?** + +答:两者定位完全不同。分布式数据库是解决高可用和可扩展场景下的数据管理问题;区块链则是在多方(无须中心化中介角色存在)之间提供一套可信的记账和合约履行机制。可见,两者完全可以配合使用。 + +**问:区块链有哪些种类?** + +答:根据部署场景公开程度,可以分为公有链(Public Chain)、联盟链(Consortium Chain)和私有链(Private Chain);从功能上看,可以分为以支持数字货币为主的数字货币区块链(如比特币网络)、支持智能合约的通用区块链(如以太坊网络)、面向复杂商业应用场景的分布式账本平台(如超级账本)。 + +**问:区块链是如何保证没有人作恶的? ** + +答:恰恰相反,区块链并没有试图保证每一个人都不作恶。以比特币区块链为例,通过经济博弈手段来容忍部分参与者作恶。参与者默认在最长的链(唯一合法链)上进行扩展。当作恶者尝试延续一个非法链的时候,实际上在跟所有的合作者们进行投票竞争。因此,当作恶者占比不高(如不超过一半)时,概率意义上无法造成破坏。而作恶代价是所付出的资源(例如算力)都将浪费掉。 + +**问:区块链的智能合约应该怎么设计?** + +答:智能合约也是一种应用程序,在架构上即可以采取单体(monolithic)的方式(一个合约针对一个具体商业应用,功能完善而复杂),也可以采取微服务(microservice)的方式(每个合约功能单一,多个合约可相互调用共同构建应用)。 选择哪种模式根本上取决于其上商业应用的特点。从灵活性角度,推荐适当对应用代码进行切分,划分到若干个智能合约,尽量保持智能合约的可复用性。 + +**问:如何查看 PEM 格式证书内容?** + +答:可以通过如下命令转换证书内容进行输出:`openssl x509 -noout -text -in `;例外,还可以通过如下命令来快速从证书文件中提取所证明的公钥内容:`openssl x509 -noout -pubkey -in `。 + +**问:已知私钥,如何生成公钥?** + +答:取决于加密算法。对于椭圆曲线加密算法,可以通过如下命令生成公钥:`openssl ec -pubout -outform PEM -in `。 + +**问:如何校验某证书是否被根证书签名?** + +答:已知根证书文件 和待验证证书文件 情况下,可以使用如下命令进行验证:`openssl verify -CAfile `。 + +**问:为何 Hash 函数将任意长的文本映射到定长的摘要,很少会发生冲突?** + +答:像 SHA-1 这样的 Hash 函数可以将任意长的文本映射到相对很短的定长摘要。从理论上讲,从大的集合映射到小的集合上必然会出现冲突。Hash 函数之所以很少出现冲突的原因在于虽然输入的数据长度可以很大,但其实人类产生的数据并非全空间的,这些数据往往是相对有序(低熵值)的,实际上也是一个相对较小的集合。 + +### 比特币、以太坊相关 + +**问:比特币区块链为何要设计为每 10 分钟才出来一个块,快一些不可以吗?** + +答:这个主要是从公平的角度,当某一个新块被计算出来后,需要在全球比特币网络内公布。临近的矿工将最先拿到消息并开始新一轮的计算,较远的矿工则较晚得到通知。最坏情况下,可能造成数十秒的延迟。为尽量确保矿工们都处在同一起跑线上,这个时间不能太短。但出块时间太长又会导致交易的“最终”确认时间过长。目前看,10 分钟左右是一个相对合适的折中。另外,也是从存储代价的角度,让拥有不太大存储的普通节点可以参与到网络的维护。 + +**问:比特币区块链每个区块大小为何是 1 MB,大一些不可以吗?** + +答:这个也是折中的结果。区块产生的平均时间间隔是固定的 10 分钟,大一些,意味着发生交易的吞吐量可以增加,但节点进行验证的成本会提高(Hash 处理约为 100 MB/s),同时存储整个区块链的成本会快速上升。区块大小为 1 MB,意味着每秒可以记录 `1 MB/(10*60)=1.7 KB` 的交易数据,而一般的交易数据大小在 `0.2 ~ 1 KB`。 + +实际上,之前比特币社区也曾多次讨论过改变区块大小的提案,但都未被最终接受。部分激进的设计者采取了分叉的手段。 + +**问:以太坊网络跟比特币网络有何关系? ** + +答:以太坊网络所采用的区块链结构,源于比特币网络,基于同样设计原理。此外,以太坊提出了许多改善设计,包括支持更灵活的智能合约、支持除了 PoW 之外的更多共识机制(尚未实现)等。 + +### 超级账本项目 + +**问:超级账本项目与传统公有区块链有何不同?** + +答:超级账本是目前全球最大的联盟链开源项目。在联盟场景下,参与多方可以容易达成一定的信任前提。另外,企业十分看重对接入账本各方的权限管理、审计功能、传输数据的安全可靠等特性。超级账本在考虑了商业网络的这些复杂需求后,提出了创新的架构和设计,成为首个在企业应用场景中得到大规模部署和验证的开源项目。 + +**问:区块链最早是公有链形式,为何现在联盟链在很多场景下得到更多应用?** + +答:区块链技术出现以前,人们往往通过中心化的信任机制来实现协作,但一旦中心机制出现故障,则无法进行。区块链技术可以提供无中介化情况下的信任保障。公有链情况下,任何人都可以参与监督,可以实现信任的最大化,但随之而来带来包括性能低下、可扩展性差等问题,特别扩大到互联网尺度时存在许多目前很难解决的技术难题。 + +联盟链在两者之间取得了平衡。多方共识模型中,系统整体可信任度随规模以指数增加;同时,联盟的信任前提,可以选用更高性能的共识机制,并支持权限管理。这些对企业场景来说都是迫切的需求。 + +**问:采用 BFT 类共识算法时,节点掉线后重新加入网络,出现无法同步情况?** + +答:这是某些算法设计导致的情况。掉线后的节点重新加入到网络中,其视图(View)会领先于其它节点。其它节点正常情况下不会发生视图的变更,发生的交易和区块内容不会同步到掉线节点。出现这种情况,可以有两种解决方案:一个是强迫其它节点出现视图变更,例如也发生掉线或者在一段时间内强制变更;另一种情况是等待再次产生足够多的区块后触发状态追赶。 + +**问:超级账本 Fabric 里的安全性和隐私性是如何保证的?** + +答:首先,Fabric 1.0 及往后的版本提供了对多通道的支持,不同通道之间的链码和交易是不可见的,即交易只会发送到该通道内的 Peer 节点。此外,在进行背书阶段,客户端可以根据背书策略来选择性的发送交易到通道内的某些特定 Peer 节点。更进一步的,用户可以对交易的内容进行加密(基于证书的权限管理)或使用私密数据,同时,只有得到授权的节点或用户才能访问到私密数据。另外,排序节点无须访问到交易内容,因此,可以选择不将完整交易(对交易输入数据进行隐藏,或者干脆进行加密或 Hash 处理)发送到排序节点。最后,所有数据在传输过程中可以通过 TLS 来进行安全保护。许多层级的保护需要配合使用来获得不同层级的安全性。 + +实践过程中,也需要对节点自身进行安全保护,通过防火墙、IDS 等防护对节点自身的攻击;另外可以通过审计和分析系统对可疑行为进行探测和响应。 diff --git a/chainbrock-learning/appendix/golang/README.md b/chainbrock-learning/appendix/golang/README.md new file mode 100644 index 00000000..54e929fe --- /dev/null +++ b/chainbrock-learning/appendix/golang/README.md @@ -0,0 +1,5 @@ +## Go 语言开发相关 + +Go 是一门年轻的语言。它在设计上借鉴了传统 C 语言的高性能特性,以及多种现代系统语言的优点,被认为是具有很大潜力的系统开发语言。要使用好 Go 语言,首先要掌握好相关的开发工具。 + +这里介绍如何快速安装和配置 Go 语言环境、选用合适的编辑器和 IDE,以及如何配合使用 Go 的配套开发工具来提高开发效率。 \ No newline at end of file diff --git a/chainbrock-learning/appendix/golang/_images/pprof.png b/chainbrock-learning/appendix/golang/_images/pprof.png new file mode 100644 index 00000000..29076819 Binary files /dev/null and b/chainbrock-learning/appendix/golang/_images/pprof.png differ diff --git a/chainbrock-learning/appendix/golang/ide.md b/chainbrock-learning/appendix/golang/ide.md new file mode 100644 index 00000000..04dbe861 --- /dev/null +++ b/chainbrock-learning/appendix/golang/ide.md @@ -0,0 +1,11 @@ +### 编辑器与 IDE + +使用传统编辑器如 VIM,可以安装相应的 Golang 支持插件,如 [vim-go](https://github.com/fatih/vim-go)。 + +目前支持 Go 语言的 IDE(Integrated Development Environment) 还不是特别丰富。推荐使用 Jet Brains 出品的 Goland 或微软开发的 Visual Studio Code。 + +Goland 是专门针对 Go 语言设计的 IDE,在代码的补全、分析等方面性能更优越。可以从 [https://www.jetbrains.com/go/](https://www.jetbrains.com/go/) 下载获取。 + +Visual Studio Code 是一个通用的 IDE,可以通过安装支持 Go 的插件来进行开发。下载地址为 https://code.visualstudio.com/download。 + +此外,简单的代码逻辑验证也可以通过官方的在线 Playground 平台,地址为 https://play.golang.org/。 \ No newline at end of file diff --git a/chainbrock-learning/appendix/golang/install.md b/chainbrock-learning/appendix/golang/install.md new file mode 100644 index 00000000..a34c6707 --- /dev/null +++ b/chainbrock-learning/appendix/golang/install.md @@ -0,0 +1,33 @@ +### 安装与配置 Golang 环境 + +Go 语言环境安装十分简单,可以通过包管理器或自行下载方式进行,为了使用最新版本的 Go 环境,推荐大家通过下载环境包方式进行安装。 + +首先,从 [https://golang.org/dl/](https://golang.org/dl/) 页面查看最新的软件包,并根据自己的平台进行下载,例如 Linux 环境下,目前最新的环境包为 [https://storage.googleapis.com/golang/go1.13.linux-amd64.tar.gz](https://storage.googleapis.com/golang/go1.13.linux-amd64.tar.gz)。 + +下载后,直接进行环境包的解压,存放到默认的 `/usr/local/go` 目录(否则需要配置 $GOROOT 环境变量指向自定义位置)下。 + +```bash +$ sudo tar -C /usr/local -xzf go1.13.linux-amd64.tar.gz +``` + +此时,查看 `/usr/local/go` 路径下,可能看到如下几个子目录。 + +* api:Go API 检查器的辅助文件,记录了各个版本的 API 特性。 +* bin:Go 语言相关的工具的二进制命令。 +* doc:存放文档。 +* lib:一些第三方库。 +* misc:编辑器和开发环境的支持插件。 +* pkg:存放不同平台的标准库的归档文件(.a 文件)。 +* src:所有实现的源码。 +* test:存放测试文件。 + +安装完毕后,可以添加 Go 工具命令所在路径到系统路径,方便后面使用。创建 `$GOPATH` 环境变量,指向某个本地创建好的目录(如 $HOME/Go),作为后面 Go 项目的存放目录。如果使用 Go 模块模式,则无需进行这些配置。 + +添加如下环境变量到用户启动配置(如 `$HOME/.bashrc`)中。 + +```sh +export PATH=$PATH:/usr/local/go/bin +export GOPATH=$HOME/Go +``` + +其它更多平台下安装,可以参考 [https://golang.org/doc/install](https://golang.org/doc/install)。 diff --git a/chainbrock-learning/appendix/golang/package.md b/chainbrock-learning/appendix/golang/package.md new file mode 100644 index 00000000..e7868a19 --- /dev/null +++ b/chainbrock-learning/appendix/golang/package.md @@ -0,0 +1,119 @@ +### 依赖管理 + +#### govendor 工具 + +长期以来,Go 语言对外部依赖都没有很好的管理方式,只能从 `$GOPATH` 下查找依赖。这就造成不同用户在安装同一个项目时可能从外部获取到不同的依赖库版本,同时当无法联网时,无法编译依赖缺失的项目。 + +Golang 自 1.5 版本开始重视第三方依赖的管理,将项目依赖的外部包统一放到 vendor 目录下(类比 Nodejs 的 node_modules 目录),并通过 vendor.json 文件来记录依赖包的版本,方便用户使用相对稳定的依赖。 + +Daniel Theophanes 等人开发了 govendor 工具,方便对第三方依赖进行管理。 + +govendor 的安装十分简单,可以通过 go get 命令: + +```bash +$ go get -u -v github.com/kardianos/govendor +``` + +对于 govendor 来说,主要存在三种位置的包:项目自身的包组织为本地(local)包;传统的存放在 $GOPATH 下的依赖包为外部(external)依赖包;被 govendor 管理的放在 vendor 目录下的依赖包则为 vendor 包。 + +具体来看,这些包可能的类型如下: + +状态 | 缩写状态 | 含义 +--- | ------- | --- ++local | l | 本地包,即项目自身的包组织 ++external | e | 外部包,即被 $GOPATH 管理,但不在 vendor 目录下 ++vendor | v | 已被 govendor 管理,即在 vendor 目录下 ++std | s | 标准库中的包 ++unused | u | 未使用的包,即包在 vendor 目录下,但项目并没有用到 ++missing | m | 代码引用了依赖包,但该包并没有找到 ++program | p | 主程序包,意味着可以编译为执行文件 ++outside | | 外部包和缺失的包 ++all | | 所有的包 + +常见的命令如下,格式为 `govendor COMMAND`。 + +通过指定包类型,可以过滤仅对指定包进行操作。 + +命令 | 功能 +-- | --- +`init` | 初始化 vendor 目录 +`list` | 列出所有的依赖包 +`add` | 添加包到 vendor 目录,如 govendor add +external 添加所有外部包 +`add PKG_PATH` | 添加指定的依赖包到 vendor 目录 +`update` | 从 $GOPATH 更新依赖包到 vendor 目录 +`remove` | 从 vendor 管理中删除依赖 +`status` | 列出所有缺失、过期和修改过的包 +`fetch` | 添加或更新包到本地 vendor 目录 +`sync` | 本地存在 vendor.json 时候拉去依赖包,匹配所记录的版本 +`get` | 类似 `go get` 目录,拉取依赖包到 vendor 目录 + +#### dep 工具 + +为了方便管理依赖,Go 团队 2016 年 4 月开始开发了 dep 工具,试图进一步简化在 Go 项目中对第三方依赖的管理。该工具目前已经被试验性支持,相信很快会成为官方支持的工具。 + +dep 目前需要 Go 1.7+ 版本,兼容其他依赖管理工具如 glide、godep、vndr、govend、gb、gvt、govendor、glock 等。 + +类似于 govendor 工具,dep 将依赖都放在本地的 vendor 目录下,通过 Gopkg.toml 和 Gopkg.lock 文件来追踪依赖的状态。 + +* Gopkg.toml 文件:手动编写或通过 dep init 命令生成。描述了项目对第三库的依赖规则,例如允许的版本范围等。用户可以通过编辑该文件表达预期的依赖控制目标。 +* Gopkg.lock 文件:通过 dep init 或 dep ensure 命令自动生成。根据项目代码和 Gopkg.toml 文件,计算出一个符合要求的具体的依赖关系并锁定,其中包括每个第三方库的具体版本。vendor 目录下的依赖库需要匹配这些版本。 + +安装可以通过 go get 命令: + +```bash +$ go get -v -u github.com/golang/dep/cmd/dep +``` + +dep 使用保持简洁的原则,包括四个子命令。 + +* init:对一个新的 Go 项目,初始化依赖管理,生成配置文件和 vendor 目录等; +* status:查看当前项目依赖的状态,包括依赖包名称、限制范围、指定版本等。可以通过 -old 参数来只显示过期的依赖; +* ensure:更新依赖,确保满足指定的版本条件。如果本地缺乏某个依赖,会自动安装; +* version:显示 dep 工具的版本信息。 + +其中,ensure 命令最为常用,支持的子命令参数主要包括: + +* -add:添加新的依赖,如 dep ensure -add github.com/pkg/foo@^1.0.0; +* -dry-run:模拟执行,打印参考改动但不实施; +* -no-vendor:根据计算结果更新 Gopkg.lock 文件,但不更新 vendor 中依赖包; +* -update:更新 Gopkg.lock 中的依赖到 Gopkg.toml 中允许的最新版本,默认同时更新 vendor 包中内容; +* -v:输出调试信息方面了解执行过程; +* -vendor-only:按照 Gopkg.lock 中条件更新 vendor 包中内容。 + +#### go module + +Go 自 1.11 版本开始引入模块(module),在 1.13 版本中开始正式支持,以取代传统基于 $GOPATH 的方案。模块作为若干个包(package)的集合,带有语义化版本号,统一管理所有依赖。所有依赖模块缓存在 $GOPATH/pkg 目录下的 `mod` 和 `sum` 子目录中,未来计划迁移到 `$GOCACHE` 目录下。另外,不同项目的相同依赖模块全局只会保存一份,极大节约了存储空间。 + +模块需要两个配置文件,go.mod 和 go.sum。 + +前者管理项目中模块的依赖信息,可以通过 go mod init 命令生成;后者记录当前项目直接或间接依赖的所有模块的路径、版本、校验值等。 + +项目模块可以通过 go mod 子命令来显式操作,也会在编译、测试等命令中被隐式更新。 + +go mod 支持的子命令包括: + +* download:下载依赖模块到本地的缓存; +* edit:编辑 go.mod 文件; +* graph:查看当前的依赖结构; +* init:初始化,创建 go.mod 文件; +* tidy:整理依赖模块:添加新模块,并删除未使用模块; +* vendor:将依赖模块复制到本地的 vendor 目录,方便兼容原来的 vendor 方式(该命令未来会遗弃); +* verify:校验当前依赖是否正确,未被篡改; +* why:解释为何需要某个依赖包。 + +基本使用过程为: + +* 使用 `go mod init ` 来初始化本地的 go.mod 文件; +* 使用 `go get -u @` 来获取某个依赖包(不添加版本号会默认获取当前最新),同时自动更新 go.mod 文件。更新全部模块可以使用 `go get -u all`; +* 编译时使用 `go build -mod=readonly` 可以避免在编译过程中修改 go.mod; +* 如果要使用本地的 vendor 目录进行编译,可以使用 `go build -mod=vendor`; +* 如果要检查可更新的依赖,可以使用 `go list -m -u all`。如果要执行更新,可以使用 `go get -u`; +* 此外,执行 `go` 相关命令(build、get、list、test 等)时,也会自动下载依赖并更新 go.mod 文件。 + +module 的开启可以通过 GO111MODULE=[auto|on|off] 等环境变量来控制。例如始终使用 go module,可以使用如下命令 + +```bash +$ go env -w GO111MODULE=on # 记录到 os.UserConfigDir 指定路径(默认为 $HOME/.config/go/)下的 env 文件中 +``` + +此外,1.13 版本起,Go 还支持 GOPROXY 环境变量来指定拉取包的代理服务,GOPRIVATE 指定私有仓库地址。 diff --git a/chainbrock-learning/appendix/golang/tools.md b/chainbrock-learning/appendix/golang/tools.md new file mode 100644 index 00000000..5c3043c3 --- /dev/null +++ b/chainbrock-learning/appendix/golang/tools.md @@ -0,0 +1,346 @@ +### 高效开发工具 + +Go 语言自带了不少高效的工具和命令,使用好这些工具和命令,可以很方便地进行程序的维护、编译和调试。 + +#### go doc 和 godoc + +go doc 可以快速显示指定软件包的帮助文档。 + +godoc 是一个类似的命令,功能更强大,它以 web 服务的形式提供文档,即允许用户通过浏览器查看软件包的文档。 + +可以通过如下命令进行快速安装。 + +```bash +$ go get golang.org/x/tools/cmd/godoc +``` + +godoc 命令使用格式如下。 + +```bash +$ godoc package [name ...] +``` + +比较有用的命令行参数包括: + +* `-http=:PORT`:指定监听的地址,默认是 `:6060`。 +* `-index`:支持关键词索引。 +* `-play`:支持 Go 语言的 playground,用户可以在浏览器里面对 Go 语言进行测试。 + +例如,下面的命令将在本地快速启动一个类似 [https://golang.org/](https://golang.org/) 的网站,包括本地软件包的文档和 playground 等。 + +```bash +$ godoc -http=:6060 -index -play +``` + +![godoc 启动本地网站](_images/godoc.png) + +#### go build +编译软件包,例如编辑当前软件包内容。 + +```sh +$ go build . +``` + +支持如下参数: + +* `-x` 参数:可以打印出执行过程的详细信息,辅助调试。 +* `-gcflags`:指定编译器参数。 +* `-ldflags`:指定链接器参数,常见的可以通过 -X 来动态指定包变量值。 + +#### go clean +清理项目,删除编译生成的二进制文件和临时文件。使用格式如下 + +```sh +$ go clean +``` + +支持如下参数: + +* `-i` 参数:删除 go install 安装的文件。 +* `-n` 参数:打印删除命令,而不执行,方便进行测试检查。 +* `-r` 参数:递归清除,对依赖包也执行清理工作。 +* `-x` 参数:执行清除过程同时打印执行的删除命令,方便进行测试检查。 + + +#### go env + +打印与 go 相关的环境变量,命令使用格式如下。 + +```bash +$ go env [var ...] +``` + +例如,通过如下命令查看所有跟 go 相关的环境变量。 + +```bash +$ go env + +GOARCH="amd64" +GOBIN="" +GOEXE="" +GOHOSTARCH="amd64" +GOHOSTOS="darwin" +GOOS="darwin" +GOPATH="/opt/Go" +GORACE="" +GOROOT="/usr/local/go/1.8.3/libexec" +GOTOOLDIR="/usr/local/go/1.8.3/libexec/pkg/tool/darwin_amd64" +GCCGO="gccgo" +CC="clang" +GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/d8/3h28zg552853gpp7ymrxl2r80000gn/T/go-build128111214=/tmp/go-build -gno-record-gcc-switches -fno-common" +CXX="clang++" +CGO_ENABLED="1" +PKG_CONFIG="pkg-config" +CGO_CFLAGS="-g -O2" +CGO_CPPFLAGS="" +CGO_CXXFLAGS="-g -O2" +CGO_FFLAGS="-g -O2" +CGO_LDFLAGS="-g -O2" +``` + +#### go fmt 和 gofmt + +两者都是对代码进行格式化检查和修正。 + +go fmt 命令实际上是对 gofmt 工具进行了封装,默认调用 `gofmt -l -w` 命令。 + +gofmt 命令的使用格式如下。 + +```sh +$ gofmt [flags] [path ...] +``` + +支持如下参数: + +* `-d` 参数:仅显示不符合格式规定的地方,不进行修正。 +* `-e` 参数:打印完整错误内容,默认是只打印 10 行。 +* `-l` 参数:列出不符合格式规定的文件路径。 +* `-r` 参数:重写的规则。 +* `-s` 参数:对代码尝试进行简化。 +* `-w` 参数:对不符合默认风格的代码进行修正。 + +#### go get +快速获取某个软件包并执行编译和安装,例如 + +```sh +$ go get github.com/hyperledger/fabric +``` + +支持如下参数: + +* `-u` 参数:可以强制更新到最新版。 +* `-d` 参数:仅获取软件包,不执行编译安装。 + +#### go install +对本地软件包执行编译,并将编译好的二进制文件安装到 $GOPATH/bin。 + +等价于先执行 `go build` 命令,之后执行复制命令。 + +#### go list + +列出本地包中的所有的导入依赖。 + +命令格式为 + +```sh +$ go list [-e] [-f format] [-json] [build flags] [packages] +``` + +其中,-e 可以指定忽略出错的包。 + +#### go run +编译并直接运行某个主程序包。 + +需要注意,该可以执行 `go run` 的程序包必须是主包,意味着包内必须有入口的主函数:main。 + +#### go test +执行软件包内带的测试用例(`*_test.go` 文件),例如递归执行当前包内所有的测试案例。 + +```sh +$ go test ./... +``` + +支持如下参数: + +* `-v` 参数:可以参数来打开详细测试日志,辅助调试。 + +#### golint + +对代码进行格式风格检查,打印出不符合 Go 语言推荐风格的代码。 + +安装该工具十分简单,通过如下命令即可快速安装。 + +```bash +$ go get -u github.com/golang/lint/golint +``` + +使用时,指定软件包路径即可,如对超级账本 Fabric 项目所有代码进行风格检查。 + +```bash +$ golint $GOPATH/src/github.com/hyperledger/fabric/... +``` + +注意后面的 `...` 代表递归检查所有子目录下内容。 + +#### goimports + +也是代码风格检查工具,重点在于对 imports 相关格式进行检查,比较强大的是能自动修正。 + +安装该工具十分简单,通过如下命令即可快速安装。 + +```bash +$ go get golang.org/x/tools/cmd/goimports +``` + +使用时,也是指定软件包路径即可。 + +另外,goimports 支持几个很有用的参数。 + +`-d`:仅显示修订,不实际写入文件。 +`-e`:显示所有的错误。 +`-l`:列出含有错误的文件路径。 +`-w`:将修订直接写入文件,不显示出来。 +`-srcdir`:指定对软件包进行查找的相对路径。 + +#### go vet + +go vet 对代码的准确性进行基本检查,如函数调用参数缺失、不可达代码,或调用格式不匹配等。使用也十分简单,指定要检查的软件包路径作为参数即可。 + +#### go tool + +`go tool` 命令中包括许多有用的工具子命令,包括 addr2line、api、asm、cgo、compile、cover、dist、doc、fix、link、nm、objdump、pack、pprof、trace。 + +其中,比较常用的包括 fix、trace 等。 + +fix 命令可以对自动对旧版本的代码进行升级修复,替换为使用新版本的特性。 + +trace 命令可以通过分析 trace 文件来追踪程序运行过程中的事件(包括 goroutine 的创建、使用和结束,以及系统调用和网络 IO 等底层事件),并提供图形化界面展示。例如如下命令会打开网页提供图形界面,展示程序执行情况。 + +```bash +$ go test -bench=. -trace trace.out +$ go tool trace trace.out +``` + +可以通过 `go tool cmd -h` 命令查看子目录具体支持的相关参数,在此不再赘述。 + +#### pprof 工具包 + +Go 语言自带了方便的性能分析工具,可以查看程序的 CPU、内存等在运行时的使用情况。 + +目前支持两种性能分析工具包。如果希望在程序执行过程中通过 Web 网页试试查看运行信息(go routine、堆栈等),可以导入 `net/http/pprof` 工具包,并在代码中启动 Web 服务,如下所示: + +```go +import ( + "http" + _ "net/http/pprof" +) + +func main() { + // 提供 profiling web 界面 localhost:6060/debug/pprof + go func() { + http.ListenAndServe("localhost:6060", nil) + }() + + // 应用程序代码 +} +``` + +程序运行后,可以通过访问 localhost:6060/debug/pprof 路径来查看 go routine、thread、堆栈使用等实时信息。 + +如果是希望执行完毕后统一进行分析,可以使用 `runtime/pprof` 包,并在代码中启动性能分析功能。 + +例如,编写 main.go 文件,通过 go routine 来启动若干计时器,但并没有进行释放。 + +```go +package main + +import ( + "flag" + "fmt" + "log" + "os" + "runtime" + "runtime/pprof" + "time" + "github.com/pkg/errors" +) + +func testTimeout() error{ + incChan := make(chan int, 1) + errChan := make(chan error, 1) + timeout := 10 * time.Millisecond + + go func() { + incChan <- 1 + }() + + select { + case <-time.NewTicker(timeout).C: + fmt.Println("Ticker") + return errors.Errorf("Timed out waiting for connection message") + case m := <-incChan: + fmt.Printf("incChan: %d\n", m) + return nil + case err := <-errChan: + fmt.Println("errChan") + return errors.WithStack(err) + } +} + +var cpuprofile = flag.String("cpuprofile", "cpu.prof", "write cpu profile to `file`") +var memprofile = flag.String("memprofile", "mem.prof", "write memory profile to `file`") + +func main() { + // 启用 CPU profiling + flag.Parse() + if *cpuprofile != "" { + f, err := os.Create(*cpuprofile) + if err != nil { + log.Fatal("could not create CPU profile: ", err) + } + if err := pprof.StartCPUProfile(f); err != nil { + log.Fatal("could not start CPU profile: ", err) + } + defer pprof.StopCPUProfile() + } + + // 应用代码 + i := 1 + for i = 1; i <= 100; i++ { + fmt.Println(i) + go testTimeout() + time.Sleep(time.Duration(1) * time.Second) + } + + // 导出内存统计 + if *memprofile != "" { + f, err := os.Create(*memprofile) + if err != nil { + log.Fatal("could not create memory profile: ", err) + } + runtime.GC() // get up-to-date statistics + if err := pprof.WriteHeapProfile(f); err != nil { + log.Fatal("could not write memory profile: ", err) + } + f.Close() + } +} +``` + +执行 `go run main.go` 编译和运行程序,观察到 CPU 使用率会逐步上升。 + +程序运行完成后,同一路径下会生成 cpu.prof 和 mem.prof 文件。其中记录了运行过程中的调用信息,之后可以通过 pprof 工具或较新版本的 `go tool pprof` 对其进行分析。这里以分析 CPU 使用为例。 + +*说明:如果没有安装 pprof 工具,可以通过 `go get -u github.com/google/pprof` 快速安装。* + +pprof 工具最常见的功能是提供一个 Web 交互界面,供用户查看调用图、火焰图、CPU 消耗,可以通过如下命令打开 Web 操作界面。 + +```bash +$ pprof -http=localhost:6060 main cpu.prof +``` + +用户可以根据需要从不同角度查看运行信息,并分析程序消耗资源较多的环节。如下图所示。 + +![pprof Web 界面](_images/pprof.png) + +另外,runtime 包中也提供了如 `runtime/trace` 等工具包,可以生成 trace 文件供进行事件追踪分析,使用方法与 `runtime/pprof` 包类似,在此不再赘述。 diff --git a/chainbrock-learning/appendix/grpc.md b/chainbrock-learning/appendix/grpc.md new file mode 100644 index 00000000..baaa2290 --- /dev/null +++ b/chainbrock-learning/appendix/grpc.md @@ -0,0 +1,231 @@ +## ProtoBuf 与 gRPC +[ProtoBuf](https://github.com/google/protobuf) 是一套接口描述语言([Interface Definition Language,IDL](https://en.wikipedia.org/wiki/Interface_description_language)),类似 Apache 的 [Thrift](https://thrift.apache.org/)。 + +相关处理工具主要是 [protoc](https://github.com/google/protobuf),基于 C++ 语言实现。 + +用户写好 `.proto` 描述文件,之后便可以使用 protoc 自动编译生成众多计算机语言(C++、Java、Python、C#、Go 等)的接口代码。这些代码可以支持 gRPC,也可以不支持。 + +[gRPC](https://github.com/grpc/grpc) 是 Google 开源的 RPC 框架和库,已支持主流计算机语言。底层通信采用 HTTP2 协议,比较适合互联网场景。gRPC 在设计上考虑了跟 ProtoBuf 的配合使用。 + +两者分别解决不同问题,可以配合使用,也可以分开单独使用。 + +典型的配合使用场景是,写好 `.proto` 描述文件定义 RPC 的接口,然后用 protoc(带 gRPC 插件)基于 `.proto` 模板自动生成客户端和服务端的接口代码。 + +### ProtoBuf + +需要工具主要包括: + +* 编译工具:[protoc](https://github.com/google/protobuf),以及一些官方没有带的语言插件; +* 运行环境:各种语言的 protobuf 库,不同语言有不同的安装来源; + +语法类似 C++ 语言,可以参考 ProtoBuf 语言规范:https://developers.google.com/protocol-buffers/docs/proto。 + +比较核心的,`message` 是代表数据结构(里面可以包括不同类型的成员变量,包括字符串、数字、数组、字典……),`service` 代表 RPC 接口。变量后面的数字是代表进行二进制编码时候的提示信息,1~15 表示热变量,会用较少的字节来编码。另外,支持导入。 + +默认所有变量都是可选的(optional),repeated 则表示数组。主要 service rpc 接口接受单个 message 参数,返回单个 message。 + +参考官方给出示例,如下所示: + +```protobuf +syntax = "proto3"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} +``` + +编译最关键的参数是输出语言格式参数,例如,python 为 `--python_out=OUT_DIR`。 + +一些还没有官方支持的语言,可以通过安装 protoc 对应的 plugin 来支持。例如,对于 Go 语言,可以安装 + +```sh +$ go get -u github.com/golang/protobuf/{protoc-gen-go,proto} // 前者是 plugin;后者是 go 的依赖库 +``` + +之后,正常使用 `protoc --go_out=./ ./hello.proto` 命令调用 `protoc-gen-go` 插件来生成 hello.pb.go。 + +ProtoBuf 提供了 `Marshal/Unmarshal` 方法来将数据结构进行序列化操作。所生成的二进制文件在存储效率上比 XML 高 3~10 倍,并且处理性能高 1~2 个数量级。 + +### gRPC + +相关工具主要包括: + +* 运行时库:各种不同语言有不同的[安装方法](https://github.com/grpc/grpc/blob/master/INSTALL.md),主流语言的包管理器都已支持。 +* protoc,以及 gRPC 插件和其它插件:采用 ProtoBuf 作为 IDL 时,对 .proto 文件进行编译处理。 + +类似其它 RPC 框架,gRPC 的库在服务端提供一个 gRPC Server,客户端的库是 gRPC Stub。典型的场景是客户端发送请求,同步或异步调用服务端的接口。客户端和服务端之间的通信协议是基于 HTTP2 的 [gRPC](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md) 协议,支持双工的流式保序消息,性能比较好,同时也很轻。 + +采用 ProtoBuf 作为 IDL,则需要定义 service 类型。生成客户端和服务端代码。用户自行实现服务端代码中的调用接口,并且利用客户端代码来发起请求到服务端。一个完整的例子可以参考 [https://github.com/grpc/grpc-go/blob/master/examples/helloworld](https://github.com/grpc/grpc-go/blob/master/examples/helloworld/)。 + +以上面 proto 文件为例,需要执行时添加 gRPC 的 plugin: + +```sh +$ protoc --go_out=plugins=grpc:. hello.proto +``` + +执行后会生成对应的 .pb.go 文件,其中包括了 proto 文件中指定的结构和 protobuf 协议相关转换代码。 + +gRPC 更多原理可以参考[官方文档:http://www.grpc.io/docs](http://www.grpc.io/docs/)。 + +#### 实现服务端代码 + +生成的 .pb.go 文件中,服务端相关的核心代码如下,主要定义了 GreeterServer 接口,用户可以自行修改或编写实现代码。 + +```go +type GreeterServer interface { + SayHello(context.Context, *HelloRequest) (*HelloReply, error) +} + +func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) { + s.RegisterService(&_Greeter_serviceDesc, srv) +} +``` + +用户需要自行实现服务端接口,代码如下。 + +比较重要的,创建并启动一个 gRPC 服务的过程: + +* 创建监听套接字:`lis, err := net.Listen("tcp", port)`; +* 创建服务端:`grpc.NewServer()`; +* 注册服务:`pb.RegisterGreeterServer()`; +* 启动服务端:`s.Serve(lis)`。 + +```go +package main + +import ( + "context" + "fmt" + "log" + "net" + + "google.golang.org/grpc" + pb "hello/hello" + ) + +const ( + port = ":50051" +) + +type server struct{ } + +// 这里实现服务端接口中的方法。 +func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { + log.Printf("Received: %v\n", in.GetName()) + return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil +} + +// 创建并启动一个 gRPC 服务的过程:创建监听套接字、创建服务端、注册服务、启动服务端。 +func main() { + lis, err := net.Listen("tcp", port) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + s := grpc.NewServer() + pb.RegisterGreeterServer(s, &server{}) + fmt.Printf("Starting listen on port: %s", port) + if err := s.Serve(lis); err != nil { + log.Fatalf("failed to serve: %v", err) + } +} +``` + +编译并启动服务端。 + +```bash +$ go run server/server.go +Starting listen on port: :50051 +``` + +#### 生成客户端代码 + +生成的 Go 文件中客户端相关代码如下,主要和实现了 HelloServiceClient 接口。用户可以通过 gRPC 来直接调用这个接口。 + +```go +type GreeterClient interface { + // Sends a greeting + SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) +} + +type greeterClient struct { + cc *grpc.ClientConn +} + +func NewGreeterClient(cc *grpc.ClientConn) GreeterClient { + return &greeterClient{cc} +} + +func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) { + out := new(HelloReply) + err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} +``` + +用户直接调用接口方法:创建连接、创建客户端、调用接口。 + +```go +package main + +import ( + "context" + "log" + "os" + "time" + + "google.golang.org/grpc" + pb "hello/hello" +) + +const ( + address = "localhost:50051" + defaultName = "world" +) + +func main() { + // Set up a connection to the server. + conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock()) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := pb.NewGreeterClient(conn) + + // Contact the server and print out its response. + name := defaultName + if len(os.Args) > 1 { + name = os.Args[1] + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name}) + if err != nil { + log.Fatalf("could not greet: %v", err) + } + log.Printf("Greeting: %s", r.GetMessage()) +} +``` + +编译并启动客户端,可以查看到服务端返回的消息。 + +```bash +$ go run client/client.go +Greeting: Hello world +``` diff --git a/chainbrock-learning/appendix/resources.md b/chainbrock-learning/appendix/resources.md new file mode 100644 index 00000000..2705f913 --- /dev/null +++ b/chainbrock-learning/appendix/resources.md @@ -0,0 +1,43 @@ +## 参考资源链接 + +### 论文 + +* L. Lamport, “Time, Clocks, and the Ordering of Events in a Distributed System,” Commun. ACM, vol. 21, no. 7, pp. 558–565, 1978. +* M Pease, R Shostak, L Lamport. Reaching Agreement in the Presence of Faults. Journal of the ACM, 1980, 27(2): 228-234. +* M. J. Fischer, N. A. Lynch, and M. S. Paterson, “Impossibility of Distributed Consensus with One Faulty Process,” J. ACM, vol. 32, no. 2, pp. 374–382, 1985. +* L. Lamport, “The Part-Time Parliament,” ACM Trans. Comput. Sys-tems, vol. 16, no. 2, pp. 133–169, 1998. +* M. Castro and B. Liskov, “Practical Byzantine Fault Tolerance,” Proc. Symp. Oper. Syst. Des. Implement., no. February, pp. 1–14, 1999. +* Satoshi Nakamoto, "Bitcoin: A Peer-to-Peer Electronic Cash System", https://bitcoin.org/bitcoin.pdf,2008. +A. Back, M. Corallo, L. Dashjr, M. Friedenbach, G. Maxwell, A. Miller, A. Poelstra, J. Timón, and P. Wuille, “Enabling Blockchain Innovations with Pegged Sidechains,” pp. 1–25, 2014. +* T. D. Joseph Poon, “The Bitcoin Lightning Network: Scalable Off-Chain Payments, http://lightning.network/lightning-network-paper.pdf,” pp. 1–59, 2016. +* Gentry C., Halevi S.,"Implementing Gentry’s Fully-Homomorphic Encryption Scheme". In: Paterson K.G. (eds) Advances in Cryptology – EUROCRYPT 2011. EUROCRYPT 2011. Lecture Notes in Computer Science, vol 6632. Springer, Berlin, Heidelberg. +* van Dijk M., Gentry C., Halevi S., Vaikuntanathan V., "Fully Homomorphic Encryption over the Integers". In: Gilbert H. (eds) Advances in Cryptology – EUROCRYPT 2010. EUROCRYPT 2010. Lecture Notes in Computer Science, vol 6110. Springer, Berlin, Heidelberg. +* López-Alt, Adriana, Eran Tromer, and Vinod Vaikuntanathan. "On-the-Fly Multiparty Computation on the Cloud via Multikey Fully Homomorphic Encryption.". Proceeding STOC '12 Proceedings of the forty-fourth annual ACM symposium on Theory of computing, Pages 1219-1234. +* I. Miers, C. Garman, M. Green, and A. D. Rubin, “Zerocoin: Anonymous distributed e-cash from bitcoin,” Proc. - IEEE Symp. Secur. Priv., pp. 397–411, 2013. +* F. Reid and M. Harrigan, “An analysis of anonymity in the bitcoin system,” Secur. Priv. Soc. Networks, pp. 197–223, 2013. +* K. Bhargavan, A. Delignat-Lavaud, C. Fournet, A. Gollamudi, G. Gonthier, N. Kobeissi, A. Rastogi, T. Sibut-Pinote, N. Swamy, and S. Zanella-Béguelin, “Formal Verification of Smart Contracts,” 2016. +* Y. Sompolinsky and A. Zohar, “Secure high-rate transaction processing in bitcoin,” Lect. Notes Comput. Sci. (including Subser. Lect. Notes Artif. Intell. Lect. Notes Bioinformatics), vol. 8975, pp. 507–527, 2015. +* C. Li, P. Li, D. Zhou, W. Xu, F. Long, and A. Yao, “Scaling Nakamoto Consensus to Thousands of Transactions per Second,” 2018. + +### 开源项目 + +* 比特币项目:https://bitcoin.org/。 +* [blockchain.info](https://blockchain.info):比特币信息统计网站。 +* [bitcoin.it](https://en.bitcoin.it):比特币 wiki,相关知识介绍。 +* 以太坊项目:https://www.ethereum.org。 +* 以太坊网络的状态统计:https://etherchain.org/ +* 超级账本项目:[https://hyperledger.org](https://hyperledger.org); +* 超级账本 Docker 镜像:[https://hub.docker.com/r/hyperledger/](https://hub.docker.com/r/hyperledger/)。 + +### 培训课程 + +* [Bitcoin and Cryptocurrency Technologies](https://www.coursera.org/course/bitcointech):https://www.coursera.org/course/bitcointech, Princeton University; +* Blockchain: Understanding Its Uses and Implications:https://www.edx.org/course/understanding-blockchain-and-its-implications, Linux Foundation。 + +### 区块链服务平台 +* [IBM Blockchain](https://www.ibm.com/blockchain):https://www.ibm.com/blockchain; +* [Oracle Blockchain Platform](https://www.oracle.com/cloud/blockchain/):https://www.oracle.com/cloud/blockchain; +* [腾讯云区块链](https://cloud.tencent.com/product/tbaas):https://cloud.tencent.com/product/tbaas; +* [阿里云区块链](https://www.aliyun.com/product/baas):https://www.aliyun.com/product/baas; +* [百度云区块链](https://cloud.baidu.com/solution/blockchain.html):https://cloud.baidu.com/solution/blockchain.html; +* [纸贵科技区块链](https://baas.zhigui.com):https://baas.zhigui.com。 diff --git a/chainbrock-learning/appendix/terms.md b/chainbrock-learning/appendix/terms.md new file mode 100644 index 00000000..04b9335f --- /dev/null +++ b/chainbrock-learning/appendix/terms.md @@ -0,0 +1,87 @@ +## 术语 + +### 通用术语 + +* Blockchain(区块链):基于密码学的可实现信任的信息存储和处理的结构和技术; +* Byzantine Failure(拜占庭错误):指系统中存在除了消息延迟或不可送达的故障以外的错误,包括消息被篡改、节点不按照协议进行处理等,潜在地会对系统造成针对性的破坏; +* CDN:Content Delivery Network,内容分发网络。利用在多个地理位置预先配置的缓存服务器,自动从距离近的缓存服务器进行对请求的响应,以实现资源的快速分发; +* Consensus(共识):分布式系统中多个参与方对某个信息达成一致,多数情况下为对发生事件的顺序达成一致; +* Decentralization(去中心化):无需一个独立第三方的中心机构存在,有时候也叫多中心化; +* Distributed(分布式):非单个节点的实现,通常由多个个体通过某种组织形式联合在一起,对外呈现统一的服务形式; +* Distributed Ledger(分布式账本):由多家联合维护的去中心化(或多中心化)的账本记录平台; +* DLT:Distributed Ledger Technology,分布式账本技术。包括区块链、权限管理等在内的实现分布式账本的技术; +* DTCC:Depository Trust and Clearing Corporation,存托和结算公司。全球最大的金融交易后台服务机构; +* Fintech:Financial Technology,跟金融相关的(信息)技术; +* Gossip:一种 P2P 网络中多个节点之间进行数据同步的协议,如随机选择邻居进行转发; +* LDAP:Lightweight Directory Access Protocol,轻量级目录访问协议,是一种为查询、搜索业务而设计的分布式数据库协议,一般具有优秀的读性能,但写性能往往较差。 +* Market Depth(市场深度):衡量市场承受大额交易后汇率的稳定能力,例如证券交易市场出现大额交易后价格不出现大幅波动; +* MTBF:Mean Time Between Failures,平均故障间隔时间,即系统可以无故障运行的预期时间; +* MTTR:Mean Time to Repair,平均修复时间,即发生故障后,系统可以恢复到正常运行的预期时间; +* MVCC:Multi-Version Concurrency Control,多版本并发控制。数据库领域的技术,通过引入版本来实现并发更新请求的乐观处理,当更新处理时数据版本跟请求中注明版本不一致时则拒绝更新。发生更新成功则将数据的版本递增; +* Non-validating Peer(非验证节点):不参与账本维护,仅作为交易代理响应客户端的请求,并对交易进行一些基本的有效性检查,之后转发给验证节点。 +* P2P:点到点的通信网络,网络中所有节点地位均等,不存在中心化的控制机制; +* SLA/SLI/SLO:Service Level Agreement/Indicator/Objective,分别描述服务可用性对用户的承诺,功能指标和目标值; +* SWIFT:Society for Worldwide Interbank Financial Telecommunication,环球银行金融电信协会,运营世界金融电文网络,服务银行和金融机构; +* Turing-complete(图灵完备):指一个机器或装置能用来模拟图灵机(现代通用计算机的雏形)的功能,图灵完备的机器在可计算性上等价; +* Validating Peer(验证节点):维护账本的核心节点,参与一致性维护、对交易的验证和执行。更进一步可以划分为 Endorser、Committer 等多种角色。 + +### 密码学与安全相关 +* ASN.1:Abstract Syntax Notation One,定义了描述数据的表示、编码、传输、解码的一套标准,被广泛应用在计算机、通信和安全领域; +* CA:Certificate Authority,负责证书的创建、颁发,在 PKI 体系中最为核心的角色; +* CBDC:Central Bank Digital Currency,央行数字货币,由中央银行发行的数字货币,多与已有法币体系挂钩; +* CRL:Certification Revocation List,证书吊销列表,包含所撤销的证书列表; +* CSR:Certificate Signing Request,证书签名申请,包括通用名、名称、主机、生成私钥算法和大小、CA 配置和序列号等信息,用来发给 CA 服务以颁发签名的证书; +* DER:Distinguished Encoding Rules,ASN.1 中定义的一种二进制编码格式,可以用来保存证书或密钥内容。 +* Genesis Block:创世区块,区块链的第一个区块,一般用于初始化,不带有交易信息; +* Hash:哈希算法,任意长度的二进制值映射为较短的固定长度的二进制值的算法; +* IES:Integrated Encryption Scheme,集成加密机制,一种混合加密机制,可以应对选择明文攻击(可以获知任意明文和对应密文)情况下的攻击。包括 DLIES(基于离散对数)和 ECIES(基于椭圆曲线)两种实现; +* Nonce:密码学术语,表示一个临时的值,多为随机字符串; +* OCSP:Online Certificate Status Protocol,在线证书状态协议,通过查询服务来在线确认证书的状态(如是否撤销)。RFC 2560 中定义; +* PKCS:Public-Key Cryptography Standards,公钥密码标准,由 RSA 实验室提出,定义了利用 RSA 算法和相关密码学技术来实现安全的系列规范,目前包括 15 个不同领域的规范。最早的版本在 1991 年提出,目前最新版本为 2012 年提出的 2.2 版本; +* PEM:Privacy Enhanced Mail,用来保存证书和密钥的一种编码格式,RFC 1421-1424 中定义; +* PKI:Public Key Infrastructure,基于公钥体系的安全基础架构; +* SM:ShangMi,国家商用密码算法,2010 年以来陆续由国家密码管理局发布的相关标准和规范,主要包括:SM2(基于椭圆曲线密码的公钥密码算法标准)、SM3(Hash 算法标准)、SM4(基于分组加密的对称密码算法标准)、SM9(基于身份的数字证书体系)。2017 年 10 月 30 日,SM2 与 SM9 的数字签名算法在第 55 次 ISO/IEC 信息安全分技术委员会(SC27)上被正式接纳,成为国际标准之一; +* ZKP:Zero-knowledge proof,零知识证明。在不泄露无关信息的前提下证实某个论断。 + +### 比特币、以太坊相关术语 + +* Bitcoin(比特币):最早由中本聪提出和实现的基于区块链思想的数字货币技术; +* DAO:Decentralized Autonomous Organization,分布式自治组织,基于区块链的按照智能合约联系起来的松散自治群体; +* DApp:Decentralized Application,去中心化应用。部署在区块链中的智能合约; +* Lightning Network(闪电网络):通过链外的微支付通道来增大交易吞吐量的技术; +* Mining(挖矿):通过暴力尝试来找到一个字符串,使得它加上一组交易信息后的 Hash 值符合特定规则(例如前缀包括若干个 0),找到的人可以宣称新区块被发现,并获得系统奖励的数字货币; +* Miner(矿工):参与挖矿的人或组织; +* Mining Machine(矿机):专门为数字货币挖矿而设计的设备,包括基于软件、GPU、FPGA、专用芯片等多种实现; +* Mining Pool(矿池):采用团队协作方式来集中算力进行挖矿,对产出的数字货币进行分配; +* PoS:Proof of Stake,股份持有证明,拥有代币或股权越多的用户,挖到矿的概率越大; +* PoW:Proof of Work,工作量证明,在一定难题前提下求解一个 SHA256 的 Hash 问题; +* Smart Contract(智能合约):运行在区块链上的提前约定的合同; +* Sybil Attack(女巫攻击):少数节点通过伪造或盗用身份伪装成大量节点,进而对分布式系统系统进行破坏。 + +### 超级账本相关术语 + +* Anchor(锚定):某个组织内的节点暴露出来给其它组织看到,作为协助沟通不同组织之间的节点组成 Gossip 的渠道; +* Auditability(审计性):在一定权限和许可下,可以对链上的交易进行审计和检查; +* Block(区块):代表一批得到确认的交易信息的整体,准备被共识加入到区块链中; +* Blockchain(区块链):由多个区块链接而成的链表结构,除了初始区块,每个区块头部都包括前继区块内容的 Hash 值; +* Bootstrap(启动):刚启动的节点可以连接到启动节点列表以获取网络中其它节点信息。启动节点必须为同一组织内节点; +* Chaincode(链码):区块链上的应用代码,扩展自“智能合约”概念,支持 Golang、Nodejs 等语言,多为图灵完备; +* Channel(通道):Fabric 网络上的私有隔离机制。通道中的链码和交易只有加入该通道的节点可见。同一个节点可以加入多个通道,并为每个通道内容维护一个账本; +* Committer(提交节点):一种 Peer 节点角色,负责对 Orderer 排序后的交易进行检查,选择合法的交易执行并写入存储。 +* Commitment(提交):提交节点完成对排序后交易的验证,将交易内容写到区块,并更新世界状态的过程; +* Confidentiality(保密):只有交易相关方可以看到交易内容,其它人未经授权则无法看到; +* Consenter Set(共识组):在 Raft 共识机制中,每个通道可以由指定的若干排序节点来进行维护,这些排序节点构成通道的共识组。特别的,系统通道的共识组包括所有的排序节点; +* Endorser(推荐节点或背书节点):一种 Peer 节点角色,负责检验某个交易是否合法,是否愿意为之背书、签名; +* Endorsement:背书过程。按照链码部署时候的背书策略,相关 Peer 对交易提案进行模拟和检查,决策是否为之背书。如果交易提案获得了足够多的背书,则可以构造正式交易进行进一步的共识; +* Invoke(调用):一种交易类型,对链码中的某个方法进行调用,一般需要包括调用方法和调用参数; +* Ledger(账本):包括区块链结构(带有所有的交易信息)和当前的世界状态(world state); +* Member(成员):代表某个具体的实体身份,在网络中拥有自己的根证书。节点和应用都必须属于某个成员身份。同一个成员可以在同一个通道中拥有多个 Peer 节点,其中一个为 Leader 节点,代表成员与排序节点进行交互,并分发排序后的区块给属于同一成员的其它节点; +* MSP(Member Service Provider,成员服务提供者):抽象的实现成员服务(身份验证,证书管理等)的组件,实现对不同类型的成员服务的可拔插支持; +* Orderer(排序节点):共识服务角色,负责排序看到的交易,提供全局确认的顺序,有时又叫 Ordering Service Node(OSN); +* Permissioned Ledger(带权限的账本):网络中所有节点必须是经过许可的,非许可过的节点则无法加入网络; +* Privacy(隐私保护):交易员可以隐藏交易的身份,其它成员在无特殊权限的情况下,只能对交易进行验证,而无法获知身份信息; +* Private Data(私密数据):通道内只有部分成员组织可以看到原文的数据,可以避免交易数据泄露给其它无关组织或排序节点; +* System Chain(系统链):由对网络中配置进行变更的配置区块组成,一般可以用来作为组成网络成员们形成的联盟约定; +* Transaction(交易):执行账本上的某个函数调用或者部署、更新链码。调用的具体函数在链码中实现; +* Transactor(交易者):发起交易调用的客户端; +* World State(世界状态):即最新的全局账本状态。Fabric 用它来存储历史交易发生后产生的最新的状态,可以用键值或文档数据库实现。 diff --git a/chainbrock-learning/evaluation/README.md b/chainbrock-learning/evaluation/README.md new file mode 100644 index 00000000..4593ee89 --- /dev/null +++ b/chainbrock-learning/evaluation/README.md @@ -0,0 +1,7 @@ +# 性能与评测 + +**过早优化,往往引来各种麻烦。 ** + +一项技术究竟能否实用,有两项基本指标十分关键:一是功能的完备;一是性能的达标。 + +本章将试图对已有区块链技术进行一些评测。所有结果将尽可能保证客观准确,但不保证评测方法是否科学、评测结果是否具备足够参考性。 \ No newline at end of file diff --git a/chainbrock-learning/evaluation/hyperledger.md b/chainbrock-learning/evaluation/hyperledger.md new file mode 100644 index 00000000..f04a02fc --- /dev/null +++ b/chainbrock-learning/evaluation/hyperledger.md @@ -0,0 +1,76 @@ +## Hyperledger Fabric v0.6 性能评测 + +### 环境配置 +| 类型 | 操作系统 | 内核版本 | CPU(GHz) | 内存(GB) | +| :--: | :-------------: | :-----: | :------: | :-----: | +| 物理机 | Ubuntu 14.04.1 | 3.16.0-71-generic | 4x2.0 | 8 | + +每个集群启动后等待 10s 以上,待状态稳定。 + +仅测试单客户端、单服务端的连接性能情况。 + +### 评测指标 + +一般评测系统性能指标包括吞吐量(throughput)和延迟(latency)。对于区块链平台系统来说,实际交易延迟包括客户端到系统延迟(往往经过互联网),再加上系统处理反馈延迟(跟不同 consensus 算法关系很大,跟集群之间互联系统关系也很大)。 + +本次测试仅给出大家最为关注的交易吞吐量(tps)。 + +### 结果 + +#### query 交易 + +##### noops +| clients | VP Nodes | iteration | tps | +| -------- | ------- | --------- | ------ | +| 1 | 1 | 2000 | 195.50 | +| 1 | 4 | 2000 | 187.09 | + +##### pbft:classic +| clients | VP Nodes | iteration | tps | +| -------- | ------- | --------- | ------ | +| 1 | 4 | 2000 | 193.05 | + +##### pbft:batch +| clients | VP Nodes | batch size | iteration | tps | +| -------- | ------- | -------- | ---------- | ------ | +| 1 | 4 | 2 | 2000 | 193.99 | +| 1 | 4 | 4 | 2000 | 192.49 | +| 1 | 4 | 8 | 2000 | 192.68 | + +##### pbft:sieve +| clients | VP Nodes | iteration | tps | +| -------- | ------- | --------- | ------ | +| 1 | 4 | 2000 | 192.86 | + +#### invoke 交易 + +##### noops + +| clients | VP Nodes | iteration | tps | +| -------- | ------- | --------- | ------ | +| 1 | 1 | 2000 | 298.51 | +| 1 | 4 | 2000 | 205.76 | + +##### pbft:classic +| clients | VP Nodes | iteration | tps | +| -------- | ------- | --------- | ------ | +| 1 | 4 | 2000 | 141.34 | + + +##### pbft:batch +| clients | VP Nodes | batch size | iteration | tps | +| -------- | ------- | --------- | --------- | ------ | +| 1 | 4 | 2 | 2000 | 214.36 | +| 1 | 4 | 4 | 2000 | 227.53 | +| 1 | 4 | 8 | 2000 | 237.81 | + + +##### pbft:sieve +| clients | VP Nodes | iteration | tps | +| -------- | ------- | --------- | ------ | +| 1 | 4 | 2000 | 253.49* | + +*注:sieve 算法目前在所有交易完成后较长时间内并没有取得最终的结果,出现大量类似“vp0_1 | 07:49:26.388 [consensus/obcpbft] main -> WARN 23348 Sieve replica 0 custody expired, complaining: 3kwyMkdCSL4rbajn65v+iYWyJ5aqagXvRR9QU8qezpAZXY4y6uy2MB31SGaAiaSyPMM77TYADdBmAaZveM38zA==”警告信息。* + +### 结论 +单客户端连接情况下,tps 基本在 190 ~ 300 范围内。 \ No newline at end of file diff --git a/chainbrock-learning/evaluation/intro.md b/chainbrock-learning/evaluation/intro.md new file mode 100644 index 00000000..97b25384 --- /dev/null +++ b/chainbrock-learning/evaluation/intro.md @@ -0,0 +1,9 @@ +## 简介 + +区块链的平台性能跟很多因素都有关系,特别在实际应用中,根据应用场景的不同和系统设计和使用的不同,可能同一套平台最终在业务体现上会有较大差异。 + +在这里,仅侧重评测一般意义上的平台性能。 + +所有给出指标和结果仅供参考,由于评测环境和方案不同,不保证结果的一致性。 + +**生产环境中应用区块链技术请务必进行充分验证评测。** diff --git a/chainbrock-learning/evaluation/summary.md b/chainbrock-learning/evaluation/summary.md new file mode 100644 index 00000000..f403a1df --- /dev/null +++ b/chainbrock-learning/evaluation/summary.md @@ -0,0 +1,2 @@ +## 小结 + diff --git a/code/gin/.idea/go-file/main.go b/code/gin/.idea/go-file/main.go new file mode 100644 index 00000000..e69de29b diff --git a/code/gin/a b/code/gin/a new file mode 100644 index 00000000..f4b1b090 Binary files /dev/null and b/code/gin/a differ diff --git a/code/gin/main.exe b/code/gin/main.exe new file mode 100644 index 00000000..f4b1b090 Binary files /dev/null and b/code/gin/main.exe differ diff --git a/code/gin/main.go b/code/gin/main.go index 7c9aa741..55f523b9 100644 --- a/code/gin/main.go +++ b/code/gin/main.go @@ -1,21 +1,183 @@ package main import ( - "github.com/gin-gonic/gin" + "bufio" + "bytes" + "context" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "syscall" ) -func sayHello(c *gin.Context) { - c.JSON( - 200, - gin.H, - ) +type Cmd struct { + // Path is the path of the command to run. + // + // This is the only field that must be set to a non-zero + // value. If Path is relative, it is evaluated relative + // to Dir. + Path string + // Args holds command line arguments, including the command as Args[0]. + // If the Args field is empty or nil, Run uses {Path}. + // + // In typical use, both Path and Args are set by calling Command. + Args []string + + // Env specifies the environment of the process. + // Each entry is of the form "key=value". + // If Env is nil, the new process uses the current process's + // environment. + // If Env contains duplicate environment keys, only the last + // value in the slice for each duplicate key is used. + // As a special case on Windows, SYSTEMROOT is always added if + // missing and not explicitly set to the empty string. + Env []string + + // Dir specifies the working directory of the command. + // If Dir is the empty string, Run runs the command in the + // calling process's current directory. + Dir string + + // Stdin specifies the process's standard input. + // + // If Stdin is nil, the process reads from the null device (os.DevNull). + // + // If Stdin is an *os.File, the process's standard input is connected + // directly to that file. + // + // Otherwise, during the execution of the command a separate + // goroutine reads from Stdin and delivers that data to the command + // over a pipe. In this case, Wait does not complete until the goroutine + // stops copying, either because it has reached the end of Stdin + // (EOF or a read error) or because writing to the pipe returned an error. + Stdin io.Reader + + // Stdout and Stderr specify the process's standard output and error. + // + // If either is nil, Run connects the corresponding file descriptor + // to the null device (os.DevNull). + // + // If either is an *os.File, the corresponding output from the process + // is connected directly to that file. + // + // Otherwise, during the execution of the command a separate goroutine + // reads from the process over a pipe and delivers that data to the + // corresponding Writer. In this case, Wait does not complete until the + // goroutine reaches EOF or encounters an error. + // + // If Stdout and Stderr are the same writer, and have a type that can + // be compared with ==, at most one goroutine at a time will call Write. + Stdout io.Writer + Stderr io.Writer + + // ExtraFiles specifies additional open files to be inherited by the + // new process. It does not include standard input, standard output, or + // standard error. If non-nil, entry i becomes file descriptor 3+i. + // + // ExtraFiles is not supported on Windows. + ExtraFiles []*os.File + + // SysProcAttr holds optional, operating system-specific attributes. + // Run passes it to os.StartProcess as the os.ProcAttr's Sys field. + SysProcAttr *syscall.SysProcAttr + + // Process is the underlying process, once started. + Process *os.Process + + // ProcessState contains information about an exited process, + // available after a call to Wait or Run. + ProcessState *os.ProcessState + + ctx context.Context // nil means none + lookPathErr error // LookPath error, if any. + finished bool // when Wait was called + childFiles []*os.File + closeAfterStart []io.Closer + closeAfterWait []io.Closer + goroutine []func() error + errch chan error // one send per goroutine + waitDone chan struct{} } + +func Command(name string, arg ...string) *Cmd { + cmd := &Cmd{ + Path: name, + Args: append([]string{name}, arg...), + } + if filepath.Base(name) == name { + if lp, err := LookPath(name); err != nil { + cmd.lookPathErr = err + } else { + cmd.Path = lp + } + } + return cmd +} + +func cmd1() { + //首先生成cmd结构体,该结构体包含了很多信息,如执行命令的参数,命令的标准输入输出等 + command := exec.Command("ls", "-l") + //给标准输入以及标准错误初始化一个buffer,每条命令的输出位置可能是不一样的, + //比如有的命令会将输出放到stdout,有的放到stderr + command.Stdout = &bytes.Buffer{} + command.Stderr = &bytes.Buffer{} + //执行命令,直到命令结束 + err := command.Run() + if err != nil { + //打印程序中的错误以及命令行标准错误中的输出 + fmt.Println(err) + fmt.Println(command.Stderr.(*bytes.Buffer).String()) + return + } + //打印命令行的标准输出 + fmt.Println(command.Stdout.(*bytes.Buffer).String()) +} + +func cmd2() { + //首先生成cmd结构体 + cmd := exec.Command("strace", "-p", "15284") + //调用stderrPipe生成一个管道,该管道连接到命令行进程的标准错误, 该方法返回一个 + //ReadCloser, 我们可以通过读取返回的ReadCloser来实时读取命令行进程的标准错误 + piper, _ := cmd.StderrPipe() + //开始执行命令 + cmd.Start() + //使用bufio包封装的方法实现对reader的读取 + reader := bufio.NewReader(piper) + for { + //换行分隔 + line, err := reader.ReadString('\n') + if err != nil { + fmt.Println(err) + break + } + //打印内容 + fmt.Println(line) + } + //等待命令结束并回收子进程资源等 + cmd.Wait() +} + func main() { - var r = gin.Default() //返回一个引擎 - r.GET( - "/hello", - sayHello, - ) + fmt.Println("调用cmd1函数:") + cmd1() + + fmt.Println("调用cmd2函数:") + cmd2() + + command := exec.Command("ipconfig") + command.Stdout = &bytes.Buffer{} + command.Stderr = &bytes.Buffer{} + //执行命令,直到命令结束 + err := command.Run() + if err != nil { + //打印程序中的错误以及命令行标准错误中的输出 + fmt.Println(err) + fmt.Println(command.Stderr.(*bytes.Buffer).String()) + return + } + fmt.Println(command.Stdout.(*bytes.Buffer).String()) } diff --git a/code/go-mod/go.mod b/code/go-mod/go.mod new file mode 100644 index 00000000..165fca37 --- /dev/null +++ b/code/go-mod/go.mod @@ -0,0 +1,3 @@ +module github.com/3293172751/go-mod + +go 1.18 diff --git a/code/go-mod/go.sum b/code/go-mod/go.sum new file mode 100644 index 00000000..7ce0f352 --- /dev/null +++ b/code/go-mod/go.sum @@ -0,0 +1,169 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= +github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ= +github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA= +github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= +github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= +github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= +github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= +github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= +github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= +github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI= +github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U= +github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= +github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= +github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= +github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s= +github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= +github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= +github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= +github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= +github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/code/go-mod/hello/hello.go b/code/go-mod/hello/hello.go new file mode 100644 index 00000000..034079ce --- /dev/null +++ b/code/go-mod/hello/hello.go @@ -0,0 +1,7 @@ +package hello + +import "fmt" + +func Hello() { + fmt.Println("hello word") +} diff --git a/code/go-mod/main.go b/code/go-mod/main.go new file mode 100644 index 00000000..6da803e8 --- /dev/null +++ b/code/go-mod/main.go @@ -0,0 +1,14 @@ +package main + +import ( + . "fmt" + "go-mod/hello" + "go-mod/models" +) + +func main() { + Println("main主函数") + hello.Hello() + Println(models.Name) + //hello.Hello() +} diff --git a/code/go-mod/models/task.go b/code/go-mod/models/task.go new file mode 100644 index 00000000..b028ffa6 --- /dev/null +++ b/code/go-mod/models/task.go @@ -0,0 +1,14 @@ +package models + +import "fmt" +import "github.com/astaxie/beego" + +var Name = "test" + +func init() { + fmt.Println("最先开始调用多个") +} + +func main() { + beego.Run() +}