以太坊区块信息保存

以太坊区块信息保存(获取)

用docker 搭建了一个以太坊的轻节点

1
2
3
4
5
//拉取以太坊docker镜像
docker pull ethereum/client-go
//docker运行以太坊节点(以轻节点的模式运行--syncmode "light")
docker run -d --name geth-node -v $HOME/geth-node:/root -p 8454:8545 -p 30303:30303 ethreum/client-go --rpc --syncmode "light"
//docker logs geth-node 可以查看容器日志,轻节点只下载区块头,在需要的时候才回去下载特定的区块数据,所以同步起来非常快,几乎几分钟就能到最新的节点了

搭建好节点之后在本地新建项目,安装依赖

1
2
3
npm i -S web3
npm i -S mongoose
npm i -S ioredis

一个循环抓取想要的数据

app.js 内容

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
let Web3 = require('web3');
let url = 'http://127.0.0.1:8545';
let mongoose = require('mongoose');
let Redis = require('ioredis');
let redis = new Redis();
mongoose.connect('mongodb://127.0.0.1:27017/eth',{ useNewUrlParser: true });
let ethSchema = new mongoose.Schema({
difficulty: String,
extraData: String,
gasLimit: Number,
gasUsed: Number,
hash: String,
logsBloom: String,
miner: String,
mixHash: String,
nonce: String,
number: Number,
parentHash: String,
receiptsRoot: String,
sha3Uncles: String,
size: Number,
stateRoot: String,
timestamp: Number,
totalDifficulty: String,
transactions: [String],
transactionsRoot: String,
uncles: [String]
});
let ethmd = mongoose.model('ethmd',ethSchema);

web3 = new Web3(new Web3.providers.HttpProvider(url));

!(fetch = async () =>{
//这里只获取了交易量比较多的500w到600w的块
for(let a = 5000000; a < 6000000; a++){
let curBlock = await redis.get('currentblock');
console.log('curBlock:',curBlock);
if(curBlock && curBlock > a ) {
a = curBlock;
console.log('skip block to:',curBlock)
continue;
}
await new Promise ((resolve,reject) => {
web3.eth.getBlock (a,(err,data) => {
if(err){
console.log(err);
console.log(`retry....`);
setTimeout(()=>{
fetch();
},12000)
}else{
console.log(data);
ethmd.find({number:a},(err,doc)=>{
if(err) return console.log(err)
if(doc.length!==0){
console.log('block ',a,' exists.');
resolve()
}else{
new ethmd({
difficulty: data.difficulty,
extraData: data.extraData,
gasLimit: data.gasLimit,
gasUsed: data.gasUsed,
hash: data.hash,
logsBloom: data.logsBloom,
miner: data.miner,
mixHash: data.mixHash,
nonce: data.nonce,
number: data.number,
parentHash: data.parentHash,
receiptsRoot: data.receiptsRoot,
sha3Uncles: data.sha3Uncles,
size: data.size,
stateRoot: data.stateRoot,
timestamp: data.timestamp,
totalDifficulty: data.totalDifficulty,
transactions: data.transactions,
transactionsRoot: data.transactionsRoot,
uncles: data.uncles
}).save((err,doc)=>{
if(err) return console.log(err)
console.log(`block ${a} saved.`);
redis.set('currentblock',a,(err,doc)=>{
console.log('update currentblock to: ',a)
if(err) return console.log(err)
resolve();
});
});
}
})
}
})
})
}
process.exit(0);
})();

简单起见,所有的内容都在app.js里边,做了最简单一个错误处理,当然mongodb和redis的操作也可能产生错误,如果想程序更加健壮可以把这部分内容加上.
当然这样跑还是太慢了,主要就是获取区块的速度太慢了,可以考虑用全节点模式,那样节点数据就在本地,而不用从网络获取,另外也可以多跑几个实例,分别跑不同的区段然后汇总到数据库