前言:

最近区块链技术很火,所以我也就来学习一下,在了解了一些区块链的基本概念后,就学习了一波网上简单的实现区块链的代码。
对区块链的一些基础知识,可以阮老师的这篇文章:http://www.ruanyifeng.com/blog/2017/12/blockchain-tutorial.html

php实现:

参考地址:http://sex.linglingtang.com/forum.php?mod=viewthread&tid=35

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?php
class block{
private $index;
private $timestamp;
private $data;
private $previous_hash;
private $random_str;
private $hash;
public function __construct($index, $timestamp, $data, $random_str, $previous_hash)
{
$this->index = $index;
$this->timestamp = $timestamp;
$this->data = $data;
$this->previous_hash = $previous_hash;
$this->random_str = $random_str;
$this->hash = $this->hash_block();
}
// 得到某个属性的值
public function __get($name) {
return $this->$name;
}
private function hash_block() {
$str = $this->index.$this->timestamp.$this->data.$this->random_str.$this->previous_hash;
return hash("sha256", $str);
}
}
// 创建创世区块
function create_genesis_block() {
return new block(0, time(), "第一个区块", 0, 0);
}
// 产生一个新的块
function dig(block $last_block_obj) {
$random_str = $last_block_obj->hash.get_random();
$index = $last_block_obj->index + 1;
$timestamp = time();
$data = "i am block".$index;
$block_obj = new block($index, $timestamp, $random_str, $last_block_obj->hash);
if (!is_numeric($block_obj->hash{0})) {
return false;
}
return $block_obj;
}
// 验证区块的有效性,此处待补充
function verify(block $last_block_obj) {
return true;
}
function get_random($len = 32) {
$str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$key = "";
for ($i = 0; $i < $len; $i++)
{
$key .= $str{mt_rand(0,32)}
}
return $key;
}
header("Content-type:text/html;charset = utf-8");
$blockchain = [create_genesis_block()];
$previous_block = $blockchain[0];
for($i = 0;$i <= 10; $i++) {
if (!($new_block = dig($previous_block))) {
continue;
}
$blockchain[] = $new_block;
$previous_block = $new_block;
echo "区块已加入链中,新区块是: {$new_block->index}<br/>";
echo "新区块哈希是:{$new_block->hash<br/>}";
print_r($new_block);
echo "<br/><br/>";
}

js实现

参考地址:https://github.com/lhartikk/naivechain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
'use strict'
var CryptoJS = require("crypto-js");
var express = require("express");
var bodyParser = require('body-parser');
var WebSocket = require('ws');
var http_port = process.env.HTTP_PORT || 3001;
var p2p_port = process.env.P2P_PORT || 6001;
var initialPeers = process.env.PEERS ? process.env.PEERS.split(',') : [];
// 定义块的结构
class Block {
constructor(index, previousHash, timestamp, data,hash) {
this.index = index;
this.previousHash = previousHash.toString();
this.timestamp = timestamp;
this.data = data;
this.hash = hash.toString();
}
}
// 计算哈希
var calculateHash = (index, previousHash, timestamp, data) => {
return CryptoJS.SHA256(index+previousHash+timestamp+data).toString();
}
// 计算一个区块的哈希
var calculateHashForBlock = (block) => {
return calculateHash(block.index, block.previousHash, block.timestamp, block.data);
}
// 生成区块
var generateNextBlock = (blockData) => {
var previousBlock = getLatestBlock();
var nextIndex = previousBlock.index + 1;
var nextTimestamp = new Date().getTime() / 1000;
var nextHash = calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData);
return new Block(nextIndex,previousBlock.hash,nextTimestamp,blockData,nextHash);
}
//生成第一个区块(起源块)
var getGenesisBlock = () => {
return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7");
}
// 将第一个区块存入数组
var blockchain = [getGenesisBlock()];
// 验证区块是否有效
var isValidNewBlock = (newBlock, previousBlock) => {
if (previousBlock.index + 1 !== newBlock.index) {
console.log('invalid index');
return false;
} else if (previousBlock.hash !== newBlock.previousHash) {
console.log('invalid previousHash');
} else if (calculateHashForBlock(newBlock) !== newBlock.hash) {
console.log('invilid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash);
return false
}
return true;
}
// 得到最新的区块
var getLatestBlock = () => blockchain[blockchain.length - 1]
// 符合要求的新的区块就push到数组blockchain
var addBlock = (newBlock) => {
if (isValidNewBlock(newBlock, getLatestBlock())) {
blockchain.push(newBlock);
}
}
var isValidChain = (blockchainToValidate) => {
// 先判断起源块
if (JSON.stringify(blockchainToValidate[0]) !== JSON.stringify(getGenesisBlock())) {
return false;
}
// 将起源块放入tempBlocks
var tempBlocks = [blockchainToValidate[0]];
// 遍历链,如果符合规范,将块存入tempBlocks
for (var i = 1; i < blockchainToValidate.length; i++) {
if (isValidNewBlock(blockchainToValidate[i], tempBlocks[i-1])) {
tempBlocks.push(blockchainToValidate[i]);
}
} else {
return false;
}
return true;
}
var broadcast = (message) => ws.send(JSON.stringify(message));
// 如果新链的长度长于旧链,则取代旧链
var replaceChain = (newBlocks) => {
if (isValidChain(newBlocks) && newBlocks.length>blockchain.length) {
console.log('Received blockchain is valid. Replaceing current blockchain with received blockchain');
blockchain = newBlocks;
broadcass(responseLatestMsg());
} else {
console.log('Received blockchain invalid');
}
}
// =======================================================================
// =======================================================================
var initHttpServer = () => {
var app = express();// 创建一个express应用
app.use(bodyParser.json());
app.get('/blocks', (req, res) => res.send(JSON,stringify(blockchain)));
app.post('/mineBlock', (req,res) => {
var newBlock = generateNextBlock(req.body.data);
addBlock(newBlock);
broadcast(responseLatestMsg());
console.log('block added: ' + JSON.stringify(newBlock));
res.send();
});
app.get('/peers', (req,res) => {
res.send(sockets.map(s => s._socket.remoteAddress + ':' + s._socket.remotePort));
});
app.post('/addPeer', (req.res) => {
connectToPeers([req.body.peer]);
res.send();
});
app.listen(http_port, () => console.log('Listening http on port: ' + http_port));
}
var initP2PServer = () => {
var server = new WebSocket.Server({port:p2p_port});
server.on('connection', ws => initConnection(ws));
console.log('listening websocket p2p port on: ' + p2p_port);
};
var initErrorHandler = (ws) => {
var closeConnection = (ws) => {
console.log('connection failed to peer: ' + ws.url);
sockets.splice(sockets.indexOf(ws), 1);
};
ws.on('close', () => closeConnection(ws));
ws.on('error', () => closeConnection(ws));
}
var handleBlockchainResponse = (message) => {
var receivedBlocks = JSON.parser(message.data.).sort((b1,b2) => (b1.index - b2.index));
var latestBlockReceived = receivedBlocks[receivedBlocks.length - 1];
var latestBlockHeld = getLatestBlock();
if (latestBlockReceived.index > latestBlockHeld.index ); {
console.log('blockchain possibly behind. we got: ' + latestBlockHeld.index + 'peer got: ' + latestBlockReceived.index);
if (latestBlockHeld.hash === latestBlockReceived.previousHash) {
console.log("we can append the received block to our chain");
blockchain.push(latestBlockReceived);
blockchain.push(latestBlockReceived);
broadcast(responseLatestMsg());
} else if (receivedBlocks.length === 1) {
console.log("we have to query the chain from our peer");
broadcast(queryAllMsg());
} else {
console.log("received blockchain is longer than current blockchain");
replaceChain(receivedBlocks);
}
} else {
console.log('received blockchain is not longer than current blockchain. Do nothing');
}
}
var initMessageHandler = (ws) => {
ws.on('message', (data) => {
var message = JSON.parse(data);
console.log('Received message' + JSOn.stringify(message));
switch (message.type) {
case MEssageType.QUERY_LATEST:
write(ws, responseLatestMsg());
break;
case MessageType.QUERY_ALL:
write(ws, responseChainMsg());
break;
case MessageType.RESPONSE_BLOCKCHAIN:
handleBlockchainResponse(message);
break;
}
});
}
var connectToPeers = (newPeers) => {
newPeers.forEach((peer) => {
var ws = new WebSocket(peer);
ws.on('open', () => initConnection(ws));
ws.on('error', () => {
console.log('connection failed');
});
});
}
var sockets = [];
var MessageType = {
QUERY_LATEST : 0,
QUERY_ALL : 1,
RESPONSE_BLOCKCHAIN : 2
}
var queryChainLengthMsg = () => ({'type' : MessageType.QUERY_LATEST});
var queryAllMsg = () => ({'type' : MessageType.QUERY_ALL});
var responseChainMsg = () => ({
'type' : MessageType.RESPONSE_BLOCKCHAIN, 'data' : JSON.stringify(blockchain)
});
var write = (ws, message) => ws.send(JSON.stringify(message));
var broadcast = (message) => sockets.forEach(socket => write(socket, message));
connect ToPeers(initialPeers);
initHttpServer();
initP2PServer();

python实现

参考地址:http://python.jobbole.com/88248/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#encoding:utf-8
import hashlib as hasher
import datetime as date
class Block:
# 初始化一个区块
def __init__(self, index, timestamp, data, previous_hash):
self.index = index
self.timestamp = timestamp
self.data = data
self.previous_hash = previous_hash
self.hash = self.hash_block()
# 计算当前块的哈希
def hash_block(selfs):
sha = hasher.sha256()
sha.update(str(self.index) + str(self.timestamp) + str(self.data) + str(self.previous_hash))
return sha.hexdigest()
# 创建初始区块
def create_genesis_block():
# 初始区块的索引为0,data是存在里面的数据随便指定,previous_hash设置为"0"
return Block(0, date.datetime.now(), "Genesis Block", "0")
# 生成后续区块
def next_block(last_block):
this_index = last_block.index + 1
this_timestamp = date.datetime.now()
this_data = "hey ! I'm block" + str(this_index)
this_previous_hash = last_block.hash
return Block(this_index, this_timestamp, this_data, this_previous_hash)
blockchain = [create_genesis_block()]
previous_block = blockchain[0]
num_of_blocks_to_add = 20
for i in range(0, num_of_blocks_to_add):
block_to_add = next_block(previous_block)
blockchain.append(block_to_add)
previous_block = block_to_add
print "Block #{} has been added to the blockchain!".format(block_to_add.index)
print "Hash: {}\n".format(block_to_add.hash)

总结

总的来说上面几种方法都大同小异,其基本步骤如下:
1.用一个类来定义区块的结构,其属性包括:由外部传入的(区块的索引,时间戳,写入区块中的数据,上一个区块的哈希),自身计算出来的:(当前区块的哈希)
2.实例化类,创建一个创世区块对象,设定初始索引为0,上一个区块的哈希为0
3.定义函数来计算当前区块的哈希
4.定义函数传入最新区块,返回一个后续区块对象
5.将创世区块作为链(一个数组)的第0号元素,然后将其作为最新区块传入生成后续区块,然后又将后续区块加入链中作为最新区块(这一步之前可以验证区块的有效性,通过和上一个区块的对比)

最后更新: 2018年07月28日 12:30

原始链接: http://drac0nids.top/2018/07/27/用py,js,php实现简单的区块链/

× 请我吃糖~
打赏二维码