import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"io"
"log"
"net/http"
"os"
"strconv"
"sync"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/gorilla/mux"
"github.com/joho/godotenv"
)
在源代码的开头,是作者引入的一些包,有标准的,也有第三方的。像sha256,hex这些标准包是为了sha-256编码用的,其他还有启动http服务,打印日志的log,并发控制的sync,时间戳的time。
go-spew
是一个变量结构体的调试利器,可以打印出变量结构体对应的数据和结构,调试非常方便
gorilla/mux
是一个web路由服务,可以很简单的帮我们构建web服务。
不过目前用gin的比较多,也推荐使用gin https://github.com/gin-gonic/gin。
godotenv
是一个读取配置文章的库,可以让我们读取.env
格式的配置文件,比如从配置文件里读取IP、PORT等。不过目前配置文件还是推荐YAML和TOML,对应的第三方库是:
gopkg.in/yaml.v21 https://github.com/BurntSushi/toml
既然要写一个区块链,那么肯定的有一个区块的实体,我们通过golang的struct
来实现。
// Block represents each 'item' in the blockchain
type Block struct {
Index int
Timestamp string
BPM int
Hash string
PrevHash string
}
Block
里包含几个字段:
- Index 就是Block的顺序索引
- Timestamp是生成Block的时间戳
- BPM,作者说代表心率,每分钟心跳数
- Hash是通过sha256生成的散列值,对整个Block数据的Hash
- PrevHash 上一个Block的Hash,这样区块才能连在一起构成区块链
有了区块Block了,那么区块链就非常好办了。
代码语言:javascript复制// Blockchain is a series of validated Blocks
var Blockchain []Block
就是这么简单,一个Block数组就是一个区块链。区块链的构成关键在于Hash和PrevHash,通过他们一个个串联起来,就是一串Block,也就是区块链。因为相互之间通过Hash和PrevHash进行关联,所以整个链很难被篡改,链越长被篡改的成本越大,因为要把整个链全部改掉才能完成篡改的目的,这样的话,其他节点验证这次篡改肯定是不能通过的。
既然关键点在于Hash,所以我们要先算出来一个Block的数据的Hash,也就是对Block里的字段进行Hash,计算出一个唯一的Hash值。
代码语言:javascript复制// SHA256 hasing
func calculateHash(block Block) string {
record := strconv.Itoa(block.Index) block.Timestamp strconv.Itoa(block.BPM) block.PrevHash
h := sha256.New()
h.Write([]byte(record))
hashed := h.Sum(nil)
return hex.EncodeToString(hashed)
}
代码语言:javascript复制// create a new block using previous block's hash
func generateBlock(oldBlock Block, BPM int) Block {
var newBlock Block
t := time.Now()
newBlock.Index = oldBlock.Index 1
newBlock.Timestamp = t.String()
newBlock.BPM = BPM
newBlock.PrevHash = oldBlock.Hash
newBlock.Hash = calculateHash(newBlock)
return newBlock
}
因为区块链是顺序相连的,所以我们在生成一个新的区块的时候,必须知道上一个区块,也就是源代码里的oldBlock
。另外一个参数BPM
就是我们需要在区块里存储的数据信息了,这里作者演示的例子是心率,我们可以换成其他业务中想要的数据。
Index
是上一个区块的Index 1
,保持顺序;Timestamp
通过time.Now()
可以得到;Hash通过calculateHash
方法计算出来。这样我们就生成了一个新的区块。
在这里作者并没有使用POW(工作量证明)这类算法来生成区块,而是没有任何条件的,这里主要是为了模拟区块的生成,演示方便。
区块可以生成了,但是生成的区块是否可信,我们还得对他进行校验,不能随便生成一个区块。在比特币(BitCoin)中校验比较复杂,这里作者采用了简单模拟的方式。
代码语言:javascript复制// make sure block is valid by checking index, and comparing the hash of the previous block
func isBlockValid(newBlock, oldBlock Block) bool {
if oldBlock.Index 1 != newBlock.Index {
return false
}
if oldBlock.Hash != newBlock.PrevHash {
return false
}
if calculateHash(newBlock) != newBlock.Hash {
return false
}
return true
}
简单的对比Index
,Hash
是否是正确的,并且重新计算了一遍Hash
,防止被篡改。
到了这里,关于区块链的代码已经全部完成了,剩下的就是把区块链的生成、查看等包装成一个Web服务,可以通过API、浏览器访问查看。因为作者这里没有实现P2P网络,所以采用的是WEB服务的方式。
代码语言:javascript复制// create handlers
func makeMuxRouter() http.Handler {
muxRouter := mux.NewRouter()
muxRouter.HandleFunc("/", handleGetBlockchain).Methods("GET")
muxRouter.HandleFunc("/", handleWriteBlock).Methods("POST")
return muxRouter
}
合约交易的买卖对象是由交易所统一制定的标准化合约,交易所规定了其商品种类,交易时间,数量等标准化信息。合约代表了买卖双方所拥有的权利和义务。
简单点说就是:现在约好未来某个时间地点交易一定数量的某种商品。
合约交易是一种金融衍生品,它是相对于现货市场的交易,用户可以在期货合约交易中通过判断涨跌,选择买入做多或者卖出做空合约,来获得价格上涨或者下跌带来的收益。按照交割方式的不同可以将合约分为永续合约和定期合约。两者间的主要区别就是定期合约有固定交割日,而永续合约没有。