区块链系列教程——创建属于自己的区块链
区块链系列教程以以太坊区块链为基础,主要包括若干以太坊区块链的创建使用等,还包括部分原理说明,后期还会加入对其的改进。
本文是区块链系列教程的第一章,主要内容是使用以太坊区块链创建私链,并使用控制台进行一些基本操作。
1. 区块链简介
在正文之前,先简单介绍一下区块链的基本概念。
区块链,顾名思义,其存储形式是若干个区块组成,区块之间通过某种方式联系在一起。如图所示:
实际上,除了区块(区块头)结构,区块链可以抽象出更多的技术,比如共识机制、密码学机制、P2P网络、Hash树、智能合约等,这些可以统称为区块链技术,后续教程会涉及到其中部分的原理。
以太坊区块链的区块结构较为复杂,远远不止示意图中的结构,有兴趣的读者可以去其github上查看详细源码,这是go语言实现版本,也是官方主推的版本。此处大概说明以太坊区块链的区块结构,以太坊的区块结构主要定义在go-ethereum/core/types/block.go文件中,其区块结构为:
type Block struct {
header *Header
uncles []*Header
transactions Transactions
// caches
hash atomic.Value
size atomic.Value
// Td is used by package core to store the total difficulty
// of the chain up to and including the block.
td *big.Int
// These fields are used by package eth to track
// inter-peer block relay.
ReceivedAt time.Time
ReceivedFrom interface{}
}
区块结构中,header表示区块头,是非常重要的参数,其具体结构后面会说明 ;uncles表示该区块的叔块,也就是父区块的兄弟区块(因为以太坊的区块发行时间只有10秒左右,所以矿工之间会存在竞争,两个同时发行的区块将成为兄弟区块);transactions表示区块中装载的交易信息,这也是一个非常重要的参数,在区块链中交易是最为重要的功能。
以太坊区块头格式为:
type Header struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
Coinbase common.Address `json:"miner" gencodec:"required"`
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
Bloom Bloom `json:"logsBloom" gencodec:"required"`
Difficulty *big.Int `json:"difficulty" gencodec:"required"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Time uint64 `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash"`
Nonce BlockNonce `json:"nonce"`
}
- ParentHash表示父区块的Hash值,该值实际上就是所谓的链,用于实现区块链数据不可逆的特性。
- UncleHash是区块结构中uncles经过hash运算得到的结果,用于验证区块数据的正确性。
- Coinbase用于记录该区块的发行者,其可获得区块奖励和矿工费奖励。
- Root用于验证当前区块链的状态,其中状态使用MPT(Merkle-Patricia-Tree)结构存储。
- TxHash用于验证当前区块的交易信息,所有交易使用
MPT结构组织存储。 - ReceiptHash用于验证当前区块的交易收据信息,对于一个交易执行完成后会有相应的收据,其组织形式也是MPT。
- Bloom是当前区块交易执行日志的布隆过滤器,用于快速确定某交易是否存在。
- Difficulty是当前区块链POW的难度值,这与共识机制有关,后文会详细介绍。
- Number是当前区块高度,即区块id,创世区块为0,逐一递增。
- GasLimit是当前区块大小,以太坊使用gas机制来控制区块大小,每个交易(包括转账交易和智能合约交易)都会消耗相应的gas,特别是智能合约交易,消耗的gas大小与其执行步骤和存储消耗有关,因为以太坊是图灵完备的,所以需要此措施来防止出现死循环。
- GasUsed是当前区块所消耗的总的gas大小。
- Time是区块打包时间。
- Extra是额外附加信息。
- MixDigest和Nonce是POW共识机制的结果证明。
2. 开始实践
本文主要使用以太坊geth客户端来创建私链,并基于console进行部分简单操作,让读者可以对区块链有一个大概的直观的感觉。
1.1 安装geth客户端
方法1
可以直接去官网下载对应操作系统的客户端。
方法2
Ubuntu的读者可以通过命令来安装:
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install ethereum
macOS的读者可以通过brew进行安装:
brew tap ethereum/ethereum
brew install ethereum
1.2 创世块文件
在创建私链时,由于我们是从创世块开始,其他区块的内容和创世块会有很大的关系,而创世块是需要我们来设定其中的字段信息的。此处,设置genesis.json文件:
{
"config": {
"chainId": 10,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x2000000",
"extraData" : "",
"gasLimit" : "0x33450",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00"
17 }
1.3 创建数据文件夹
使用命令创建数据文件夹test: 创建数据文件夹1.4 初始化区块链
使用命令初始化区块链:
geth --datadir test/ init genesis.json
得到结果:
INFO [05-01|21:27:32.575] Maximum peer count ETH=25 LES=0 total=25
INFO [05-01|21:27:32.576] Allocated cache and file handles database=/home/hadoop/blockchain/test/geth/chaindata cache=16 handles=16
INFO [05-01|21:27:32.581] Writing custom genesis block
INFO [05-01|21:27:32.581] Persisted trie from memory database nodes=0 size=0.00B time=3.104µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [05-01|21:27:32.581] Successfully wrote genesis state database=chaindata hash=b123b8…4077eb
INFO [05-01|21:27:32.581] Allocated cache and file handles database=/home/hadoop/blockchain/test/geth/lightchaindata cache=16 handles=16
INFO [05-01|21:27:32.584] Writing custom genesis block
INFO [05-01|21:27:32.584] Persisted trie from memory database nodes=0 size=0.00B time=2.105µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [05-01|21:27:32.585] Successfully wrote genesis state database=lightchaindata hash=b123b8…4077eb
1.5 创建区块链私链
使用命令创建区块链私链:
geth --datadir test/ --networkid 10 console
得到结果:
INFO [05-01|21:29:06.015] Maximum peer count ETH=25 LES=0 total=25
INFO [05-01|21:29:06.016] Starting peer-to-peer node instance=Geth/v1.8.17-stable-8bbe7207/linux-amd64/go1.10
INFO [05-01|21:29:06.016] Allocated cache and file handles database=/home/hadoop/blockchain/test/geth/chaindata cache=768 handles=512
INFO [05-01|21:29:06.024] Initialised chain configuration config="{ChainID: 10 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Byzantium: <nil> Constantinople: <nil> Engine: unknown}"
INFO [05-01|21:29:06.024] Disk storage enabled for ethash caches dir=/home/hadoop/blockchain/test/geth/ethash count=3
INFO [05-01|21:29:06.024] Disk storage enabled for ethash DAGs dir=/home/hadoop/.ethash count=2
INFO [05-01|21:29:06.024] Initialising Ethereum protocol versions="[63 62]" network=10
INFO [05-01|21:29:06.025] Loaded most recent local header number=0 hash=b123b8…4077eb td=33554432 age=50y2w3d
INFO [05-01|21:29:06.025] Loaded most recent local full block number=0 hash=b123b8…4077eb td=33554432 age=50y2w3d
INFO [05-01|21:29:06.025] Loaded most recent local fast block number=0 hash=b123b8…4077eb td=33554432 age=50y2w3d
INFO [05-01|21:29:06.025] Regenerated local transaction journal transactions=0 accounts=0
INFO [05-01|21:29:06.025] Starting P2P networking
INFO [05-01|21:29:08.150] UDP listener up self=enode://21d2a8209dc9aeadd15d94c2df30128dd7bd4b772f34e61e8f76afb893a2f7735a77c9061b64076ca61b5635b5d434fa32600af0e56f833fd7e582bff94e679d@222.201.145.179:30303
INFO [05-01|21:29:08.151] RLPx listener up self=enode://21d2a8209dc9aeadd15d94c2df30128dd7bd4b772f34e61e8f76afb893a2f7735a77c9061b64076ca61b5635b5d434fa32600af0e56f833fd7e582bff94e679d@222.201.145.179:30303
INFO [05-01|21:29:08.155] IPC endpoint opened url=/home/hadoop/blockchain/test/geth.ipc
INFO [05-01|21:29:08.169] Mapped network port proto=udp extport=30303 intport=30303 interface="UPNP IGDv1-IP1"
INFO [05-01|21:29:08.189] Mapped network port proto=tcp extport=30303 intport=30303 interface="UPNP IGDv1-IP1"
Welcome to the Geth JavaScript console!
instance: Geth/v1.8.17-stable-8bbe7207/linux-amd64/go1.10
modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
>
1.6 使用区块链
完成步骤1.5后,区块链已经可以使用,1.5中的console命令是指开启控制台用于与区块链进行交互——具体的geth命令后面教程将会详细说明。此处,我们可以控制当前区块链节点做一些操作了。
- 创建一个账户
> personal.newAccount()
Passphrase:
Repeat passphrase:
"0x6393bb737b95465ccd9e4597df0647cdcd09775f"
- 挖矿
> miner.start()
INFO [05-01|21:34:33.568] Updated mining threads threads=8
INFO [05-01|21:34:33.568] Transaction pool price threshold updated price=1000000000
INFO [05-01|21:34:33.568] Etherbase automatically configured address=0x6393Bb737b95465cCD9E4597dF0647CdcD09775f
null
> INFO [05-01|21:34:33.569] Commit new mining work number=1 sealhash=0fcb98…71f1eb uncles=0 txs=0 gas=0 fees=0 elapsed=299.471µs
- 查看余额
> eth.getBalance(eth.coinbase)
5000000000000000000
- 解锁账户
> personal.unlockAccount(eth.coinbase)
Unlock account 0x6393bb737b95465ccd9e4597df0647cdcd09775f
Passphrase:
true
- 转账
需要注意的是,转账操作前需要将账户解锁,在转账操作发起成功后,需要等待一段时间,矿工将该转账交易打包进入新的发行区块后才会生效。
> eth.sendTransaction({from:eth.coinbase, to:personal.listAccounts[1], value:100})
INFO [05-01|21:37:28.223] Setting new local account address=0x6393Bb737b95465cCD9E4597dF0647CdcD09775f
INFO [05-01|21:37:28.223] Submitted transaction fullhash=0xc2479ec79713c9a7bd638146fabf5175eeaad8df87939af83be91ce4218a7c6c recipient=0x5eDcF2B2eFa9500C9F056f58E9C032B375b877E0
"0xc2479ec79713c9a7bd638146fabf5175eeaad8df87939af83be91ce4218a7c6c"
> INFO [05-01|21:37:29.194] Commit new mining work number=6 sealhash=47fb15…84b362 uncles=0 txs=1 gas=21000 fees=2.1e-05 elapsed=601.799µs
随后,检查两者的余额,发现已经转账成功:
> eth.getBalance(eth.coinbase)
29999999999999999900
> eth.getBalance(personal.listAccounts[1])
100
联系与交流
欢迎小伙伴与我讨论哦~
本文欢迎转载,请注明本文地址:https://www.jianshu.com/p/d1ec1cc10355