abbshr.github.io
abbshr.github.io copied to clipboard
Biter loggers
Log1:玩BitCoins之前
运行原理
安全性保障
如何使用
优势分析与市场前景
key words:
去中心化,自由货币体制,无金融危机、通货膨胀风险
带给我们什么?
随着BitCoins越来越受人欢迎,其应用价值变得越来越大。对BitCoins的把玩之道更加值得探索也更能发掘有趣的东西。
比如说分析一个账户的消费情况、挖掘某些账户之间千丝万缕的关联、挖矿赚币、加密与解密的研究等等等等。
在对BitCoins的了解过程中,萌生了一个想法incbrain,这个构想也是借鉴了比特币的设计哲学。
Log2:BitCoins基本环境搭建
配置客户端
无论是想写基于BitCoins的app还是做各种数据分析,首先应该将整个网络上的区块链(blockchain)获取下来并与网络保持同步。说的简单点,就是“成为BitCoins网络的一个节点”,没错,挖矿之前也要做这些。
第一步,到BitCoins的官网下载BitCoins挖矿程序——bitcoind。它运行在各个节点上,将会开启一个长期的后台服务进程,用来与全网络的BlockChain保持同步。
Bitcoind is a program that implements the Bitcoin protocol for command line and remote procedure call (RPC) use. It is also the first Bitcoin client in the network's history.
在启动之前需要对其进行一些必要的配置,主要是一个配置文件bitcoin.conf,下面是比较重要的字段:
# 加密 JSON-RPC api 用的id和密码
rpcuser = rpcID
rpcpassword = rpc密码
# 默认情况下允许从localhost发起的RPC连接.
# 也可以通过下面的字段指定其他的host地址,可以使用通配符*
rpcallowip = 192.168.1.*
这个配置文件并不会自动生成,需要手动创建。
启动bitcoind
写好了bitcoin.conf,就可以启动比特币客户端服务进程了:
# 这里假设解压后的目录为bitcoin,系统为64位
cd ~/bitcoin/bin/64
./bitcoind
不过回车之后可能会返回一些信息并终端进程,原因是还需要选择性指定一些参数:
-conf=<file> 设置配置文件(default: bitcoin.conf)
-datadir=<dir> 指定区块存放路径
-testnet 使用测试网络
-daemon 以守护进程启动(等价于nohup &)
-loadblock=<file> 从blk000??.dat文件导入区块信息
-reindex 从当前索引处重建区块
_Note:默认情况下,bitcoind会在数据目录中寻找名为 _bitcoin.conf* 的文件。*
|操作系统| |默认数据目录| |配置文件|
------------------------------------------------------------------------
Windows %APPDATA%\Bitcoin\ (XP) C:\Documents and Settings\username\Application Data\Bitcoin\bitcoin.conf
(Vista, 7) C:\Users\username\AppData\Roaming\Bitcoin\bitcoin.conf
Linux $HOME/.bitcoin/ /home/username/.bitcoin/bitcoin.conf
Mac OSX $HOME/Library/Application Support/Bitcoin/ /Users/username/Library/Application Support/Bitcoin/bitcoin.conf
Note: 如果在testnet测试网络环境下运行bitcoind, 将会自动在数据目录下创建testnet文件夹
为了方便起见,可以将bitcoind添加到alias:
echo "alias runbtc=$HOME/bitcoind -conf=$HOME/bitcoin.conf -daemon -datadir=$HOME/block " >> .bashrc
OK~,现在跑起bitcoind:
sudo runbtc [ -loadblock=$HOME/block/blocks/blk***.dat ]
当终端提示success的时候说明bitcoind已经顺利启动了。
Note:关于配置文件编写以及bitcoind参数设置详见https://en.bitcoin.it/wiki/Running_Bitcoin
数据目录结构
datadir里都是些什么呢?
-
文件
- .lock
BDB数据库lock文件 - bitcoin.conf [可选]
bitcoind启动配置信息 - blkxxxx.dat [Versions prior to v0.8.0]
存储原始的bitcoin block数据. - blkindex.dat [Versions prior to v0.8.0]
blkxxxx.dat的索引信息 - __db.xxx
BDB使用的文件 - debug.log
详细的Bitcoin日志文件. 内容经常自动变更. - wallet.dat
存储了keys, transactions, metadata以及options. 务必确保备份,因为他包含了使用你的bitcoins时必要的keys. - addr.dat [Versions prior to v0.7.0]
存储ip地址以便重建连接 - peers.dat [Versions v0.7.0 and later]
存储配对信息方便重建连接. 这个文件使用了BitCoins的独立文件格式, 与任何其他数据库系统无关.
数据、索引与日志文件以Key-Value的形式存储于Berkeley DB中。
- .lock
-
database 目录 包含BDB journaling文件
-
testnet3 目录 (如果指定参数-testnet)包含测试网络testnet中的文件
-
blocks 目录 [v0.8 and above] 存储区块链blockchain数据.
- blk*.dat 存储原始的bitcoin blocks。只有在重新获取wallet中丢失的tx信息、组建块链的一个不同分支,以及为其他需要同步bitcoins block的节点提供blocks数据的服务时才会用到他们。
- blocks/index 目录 [v0.8 and above] leveldb数据库, 包含所有已知区块的元信息(metadate)、存放在磁盘中的位置。如果没有这些信息的话,查找blocks将会变得很慢。
-
chainstate 目录 [v0.8 and above] leveldb数据库,存储当前所有未使用的交易输出的简洁表示,还有一些包含这些tx来源的元信息。这些数据对于验证新到来的blocks和txs来说是很重要的。理论上,它可以从block数据进行重建(
-reindex
bitcoind参数),但是这会花费更长的时间。 -
locks 目录 [v0.8 and above] Contains "undo" data(未完成的数据).
- rev*.dat
包含未完成的tx数据. 他们对于chainstate的回滚来说很重要, (chainstate在重新组织的情况下是必需的)。
- rev*.dat
-
个人标识数据 [v0.8 and above] This section may be of use to you if you wish to send a friend the blockchain, avoiding them a hefty download.
- wallet.dat
Contains addresses and transactions linked to them. Please be sure to make backups of this file. It contains the keys necessary for spending your bitcoins. You should not transfer this file to any third party or they may be able to access your bitcoins. - db.log
May contain information pertaining to your wallet. It may be safely deleted. - debug.log
May contain IP addresses and transaction ID's. It may be safely deleted. - database/ folder
This should only exist when bitcoin-qt is currently running. It contains information (BDB state) relating to your wallet. - peers.dat
Unknown whether this contains personally identifiable data. It may be safely deleted.
- wallet.dat
-
其他(blocks, blocks/index, chainstate)
may be safely transferred/archived as they contain information pertaining only to the public blockchain.
Note:datadir最新更新
- 替代blk000?.dat,将使用blocks/blk000??.dat,文件大小最大为128MB,初始16MB。
- 替代Berklely DB blkindex.dat,使用LevelDB 目录blktree/. 只包括区块索引,不包括交易索引
- 一个新的LevelDB目录coins/,包括未完成的交易数据。
- 新的blocks/rev000??.dat 包含未完成的区块链数据。
- 保留了区块和区块文件的更多信息。
- 新增了两个RPC模式:gettxout 和 gettxoutsetinfo
JSON-RPC技术
RPC,(远程过程调用),一种应用层协议。
基于JSON数据交换格式的RPC是bitcoind进程与其他hosts进程进行信息交换的一种渠道。下面是一个来自官方的简易描述:
The general mechanism consists of two peers establishing a data connection. During the lifetime of a connection, peers may invoke methods provided by the other peer. To invoke a remote method, a request is sent. Unless the request is a notification it must be replied to with a response.
这个技术可以类比JSONP:客户端提供参数,包含请求的函数和参数;服务器接收并用请求参数调用请求函数,将结果返回给客户端。
提取BlockChain
当我们已经同步了网络上的BitCoins区块——Block Chain之后,就可以对这些原始数据进行“应用级别”的使用了。
作为JavaScript + Node.js发烧友,自然要用JS的方式去完成这一步了~。目前开源社区中有几个比较受欢迎的BitCoins项目,像“bitcoinjs”、“insight”等,可以借助他们的模块实现数据可读性。
- bitcoinjs分为两部分:bitcoinjs-server,bitcoin-explorer。前一个用来处理同步的Raw数据,后者提供数据可视化。
- insight是一个一体化的block chain同步、分析、挖掘、可视化工具。内部的insight-api提供了REST风格的API,核心依赖bitcore模块实现。
他们两个的共同之处是:实时展示block chain中人类可读的交易信息。
考虑代码的质量、结构以及方便今后的修改,我们选择了insight。按照官方的usage,将项目clone下来。如果想直接使用insight就克隆insight项目,如果仅仅是需要RESTful的API,仅克隆insight-api就可以了。
首先确保Node版本 > 0.10.*
这里假设使用了insight。进入项目目录,安装包依赖,
cd insight && sudo npm install
Note:此步若出现问题,详情查看文章最后的解决方案
确保bitcoind已经正确启动。
然后可以现在testnet环境下启动insight,
npm start
报错?没关系。看看提示信息会发现,datadir没有指定。
如果你已经准备好投入使用了,那就换入livenet吧~
在启动之前,我们需要配置一下insight的环境变量和参数,
# 配置信息主要在insight-api的config目录下:
cd node_modules/insight-bitcore-api/config
# 编辑config.js文件
下面是一个完整的config.js:
'use strict';
var path = require('path'),
rootPath = path.normalize(__dirname + '/..'),
env,
db,
port,
b_port,
p2p_port;
if (process.env.INSIGHT_NETWORK === 'livenet') {
env = 'livenet';
db = rootPath + '/db';
port = '3000';
b_port = '8332';
p2p_port = '8333';
}
else {
env = 'testnet';
db = rootPath + '/db/testnet';
port = '3001';
b_port = '18332';
p2p_port = '18333';
}
switch(process.env.NODE_ENV) {
case 'production':
env += '';
break;
case 'test':
env += ' - test environment';
break;
default:
env += ' - development';
break;
}
var network = process.env.INSIGHT_NETWORK || 'testnet';
var dataDir = process.env.BITCOIND_DATADIR;
var isWin = /^win/.test(process.platform);
var isMac = /^darwin/.test(process.platform);
var isLinux = /^linux/.test(process.platform);
if (!dataDir) {
if (isWin) dataDir = '%APPDATA%\\Bitcoin\\';
if (isMac) dataDir = process.env.HOME + '/Library/Application Support/Bitcoin/';
if (isLinux) dataDir = process.env.HOME + '/.bitcoin/';
}
dataDir += network === 'testnet' ? 'testnet3' : '';
module.exports = {
root: rootPath,
publicPath: process.env.INSIGHT_PUBLIC_PATH || false,
appName: 'Insight ' + env,
apiPrefix: '/api',
port: port,
leveldb: db,
bitcoind: {
protocol: process.env.BITCOIND_PROTO || 'http',
user: process.env.BITCOIND_USER || 'user',
pass: process.env.BITCOIND_PASS || 'pass',
host: process.env.BITCOIND_HOST || '127.0.0.1',
port: process.env.BITCOIND_PORT || b_port,
p2pPort: process.env.BITCOIND_P2P_PORT || p2p_port,
dataDir: dataDir,
// DO NOT CHANGE THIS!
disableAgent: true
},
network: network,
disableP2pSync: false,
disableHistoricSync: false,
poolMatchFile: rootPath + '/etc/minersPoolStrings.json',
// Time to refresh the currency rate. In minutes
currencyRefresh: 10,
keys: {
segmentio: process.env.INSIGHT_SEGMENTIO_KEY
}
};
其实也可以通过命令参数来启动insight,不过要是闲启动命令太麻烦,就可以改写上面的文件,
# 注释掉使用环境判断
# 保留livenet的配置:
env = 'livenet';
db = rootPath + '/db'; //leveldb的数据存放位置
port = '3000'; //insight服务进程端口号
b_port = '8332';
p2p_port = '8333';
# network改为livenet
var network = 'livenet';
# 最后在module.exports导出对象中修改
module.exports = {
root: rootPath,
publicPath: process.env.INSIGHT_PUBLIC_PATH || false,
appName: 'Insight ' + env,
apiPrefix: '/api',
port: port,
leveldb: db,
bitcoind: {
protocol: process.env.BITCOIND_PROTO || 'http',
// 这里修改为上面提到的bitcoin.conf中的rpcuser和rpcpassword
user: process.env.BITCOIND_USER || rpcuser,
pass: process.env.BITCOIND_PASS || rpcpassword,
host: process.env.BITCOIND_HOST || '127.0.0.1',
port: process.env.BITCOIND_PORT || b_port,
p2pPort: process.env.BITCOIND_P2P_PORT || p2p_port,
// 如果手动指定过,则改为真实的数据目录位置
dataDir: "xxxx/blocks",
// DO NOT CHANGE THIS!
disableAgent: true
},
network: network,
disableP2pSync: false,
disableHistoricSync: false,
poolMatchFile: rootPath + '/etc/minersPoolStrings.json',
// Time to refresh the currency rate. In minutes
currencyRefresh: 10,
keys: {
segmentio: process.env.INSIGHT_SEGMENTIO_KEY
}
};
改写config.js后就可以启动啦~
npm start
各种同步信息开始滚动了~~,在浏览器里访问:localhost:3000
,即可看到实时的blockchains变化情况。
Issues
这部分记录了我在以上过程中遇到的troubles以及解决方案。
通常情况下,按照上面的操作一步步进行,应该没问题。问题如果有,最可能出现在**安装包依赖#npm install#**那里。由于网络的原因,会导致包下载过程中文件损坏。这是大概是本周最蛋疼的问题没有之一。
当我第一次npm install
时,下载了一小半,突然throw出来几个error,并在结尾有稀里糊涂的报了几个错,总之最后是以not ok结尾的。
error通常如下:
- shasum error
- this is a bug in npm
- this is a bug in node-gyp
- this is a bug in XXX!@#¥%……&
- permisition deiend
- node-gyp configure error
- build error
- common.gypi not found
- binging.gyp not found
我一直纠结问题究竟出现在哪里。因为一是报错不在同一位置(不在同一个包下),二是几乎每次的报错类型都不同!
开始我们怀疑是我的Node版本太高或者是操作系统环境的问题,于是换了台虚拟机,结果同样报错。后来我甚至怀疑起insight包的质量问题了。
但在另外几个师兄的机子上测试却一点问题没有! 十几次的尝试后,基本上就打算放弃了。不过突然发现,问题大多数时候都是与node-gyp相关的!看来事情略有些眉目了~
好几次install时,会停在gyp:GET nodejs.org/dist/node.tar.gz这里,卡个一两天都不是问题。
经过Google和GitHub的搜索,得知node-gyp需要将一部分C/C++ addon编译成内置模块。
再看提示的错误信息“gyp configure error …… common.gypi not found …… binging.gyp not found”,也就是说在编译之前的configure阶段就出了问题。那这个common.gypi和binging.gyp又是个什么呢?
再次经过Google,排除了bingding.gyp的问题:它是动态生成的。应该不会产生这种错误。而common.gypi是Node源码中的一个文件,用于GYP项目构建过程中(v8)的配置参数设定。
莫非node-gyp会需要node源码?果不其然,仔细查看错误信息,configure error 一般发生在 “gyp: GET http://nodejs.org/dist/node源码.tar.gz” 之后!
当时还真没有考虑到这个问题,后再在GitHub一个NPM的issues上发现有人提到了gyp下载node源码时网络的错误导致后续编译过程出错。
这就很有可能是下载文件不全造成的了,可是如何定位下载的node源码的位置呢?我查看了node-gyp的几行源码,没法找啊… 问题的解决还得感谢ak——何不手动修改host来做域名重定向呢? 卧槽!这办法太妙了!既然我的机器里已经有现成的node源码,它还非要从网络上下载,那就把URL重定向到localhost不就成了:
sudo echo "127.0.0.1 nodejs.org" >> /etc/hosts
然后用node写一个简单的静态资源服务器:
require('http').createServer(function(req, res){
require('fs').readFile('node-v0.10.26.tar.gz', function (err, file) {
res.setHeader('Content-Type', 'application/x-compressed-tar');
res.setHeader('Content-Disposition', 'attachment; filename="node-v0.10.26.tar.gz"');
res.writeHead(200, 'OK');
res.end(file);
});
})listen(80);
在本地启动服务器,然后回到insight目录下,重新sudo npm install
这次node-gyp很快完成了node源码的下载,并开始configure & build一些之前下载的模块,终于看到了点曙光。不过插曲还可能会有的,npm install很可能会安装不全,并没有按照package.json描述中的依赖去下载所有包,手动下载没有安装全的包吧。
一切就绪,再次执行npm start
,got it。
享受胜利的喜悦吧~
issues shoot
今天访问web页面时,查找了一个block,突然就崩了,查看一下日志,竟然是语法错误。。
insight-api的lib目录下TransactionsDB.js文件里的223行:
ret.multipleSpentAttempts.each(function(mul) {
改为:
ret.multipleSpentAttempts.forEach(function(mul) {
后记
这个问题在官方的更新中修复了~: https://github.com/bitpay/insight-api/commit/0d303564f9b7a6be9e01145d594884a7c71ef421#diff-2529a889507f364f72e28b86bfda7954R222