在本文中,我们将为您详细介绍比特币源码解析(13)-可执行程序-Bitcoind的相关知识,并且为您解答关于比特币源码运行的疑问,此外,我们还会提供一些关于BitCoin比特币的疯狂:如何选择一家合适
在本文中,我们将为您详细介绍比特币源码解析(13) - 可执行程序 - Bitcoind的相关知识,并且为您解答关于比特币源码运行的疑问,此外,我们还会提供一些关于BitCoin比特币的疯狂:如何选择一家合适的比特币交易平台、java使用比特币开源类库bitcoinj开发比特币入门指南、比特币核心程序bitcoind的配置文件bitcoin.conf详解、比特币源码linux下环境配置编译运行bitcoin的有用信息。
本文目录一览:- 比特币源码解析(13) - 可执行程序 - Bitcoind(比特币源码运行)
- BitCoin比特币的疯狂:如何选择一家合适的比特币交易平台
- java使用比特币开源类库bitcoinj开发比特币入门指南
- 比特币核心程序bitcoind的配置文件bitcoin.conf详解
- 比特币源码linux下环境配置编译运行bitcoin
比特币源码解析(13) - 可执行程序 - Bitcoind(比特币源码运行)
0x01 AppInitBasicSetup
本章我们继续分析AppInit()
中的下一个函数AppInitBasicSetup()
,从这个函数开始,源码将变量初始化的过程分了很多个Step,我们也按照这样的顺序来依次分析。
Step 1: Setup
#ifdef _MSC_VER // 如果是VS环境那么就执行 // Turn off Microsoft heap dump noise _CrtSetReportMode(_CRT_WARN,_CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN,CreateFileA("NUL",GENERIC_WRITE,0,nullptr,OPEN_EXISTING,0)); // disable confusing "helpful" text message on abort,Ctrl-C _set_abort_behavior(0,_WRITE_ABORT_MSG | _CALL_REPORTFAULT); #endif
首先的几行代码是针对微软的VS开发环境而设置的,其中_CrtSetReportMode
作用是设置消息的处理方式,该函数的详细介绍参考https://msdn.microsoft.com/zh-cn/library/1y71x448.aspx, 主要包含如下两个参数,
int _CrtSetReportMode( int reportType,// 报告的消息类型 int reportMode // 处理的模式 );
对于第一个参数消息类型包括以下三种,
报表类型 | 描述 |
---|---|
_CRT_WARN |
警告、 消息和不需要立即关注的信息。 |
_CRT_ERROR |
错误、 不可恢复的问题和需要立即关注的问题。 |
_CRT_ASSERT |
断言失败 (断言表达式的计算结果为FALSE )。 |
针对这三种消息类型第二个参数可以指定不同的处理方式,
报告模式 | _CrtDbgReport 行为 |
---|---|
_CRTDBG_MODE_DEBUG |
将消息写入调试器的输出窗口。 |
_CRTDBG_MODE_FILE |
将消息写入用户提供的文件句柄。 _CrtSetReportFile应调用以定义要用作目标流的特定文件。 |
_CRTDBG_MODE_WNDW |
创建一个消息框,以显示该消息以及Abort , Retry ,和Ignore 按钮。 |
_CRTDBG_REPORT_MODE |
返回reportMode 指定reportType :1 _CRTDBG_MODE_FILE 2 _CRTDBG_MODE_DEBUG 4 _CRTDBG_MODE_WNDW
|
对于不同的消息类型我们可以同时指定不同的处理方式,例如对_CRT_WARN
指定输出到终端,对_CRT_ERROR
输出到文件;而如果指定的处理方式为写入文件即_CRTDBG_MODE_FILE
那么还需要调用_CrtSetReportFile
来设定输出的文件句柄,这也是代码的下一句,但是源码却将文件的路径设为NUL
也就是空文件,说明对于警告消息不做任何处理。
接下来一个函数_set_abort_behavior
是制定当程序异常终止时要采取的操作,也就是程序崩溃的时候如何处理。
转载: http://www.cppblog.com/woaidongmao/archive/2009/10/21/99129.html?opt=admin
很多软件通过设置自己的异常捕获函数,捕获未处理的异常,生成报告或者日志(例如生成mini-dump文件),达到Release版本下追踪Bug的目的。但是,到了VS2005(即VC8),Microsoft对CRT(C运行时库)的一些与安全相关的代码做了些改动,典型的,例如增加了对缓冲溢出的检查。新CRT版本在出现错误时强制把异常抛给默认的调试器(如果没有配置的话,默认是Dr.Watson),而不再通知应用程序设置的异常捕获函数,这种行为主要在以下三种情况出现。
(1) 调用abort函数,并且设置了_CALL_REPORTFAULT选项(这个选项在Release版本是默认设置的)。
(2) 启用了运行时安全检查选项,并且在软件运行时检查出安全性错误,例如出现缓存溢出。(安全检查选项 /GS 默认也是打开的)
(3) 遇到
_invalid_parameter
错误,而应用程序又没有主动调用_set_invalid_parameter_handler
设置错误捕获函数。所以结论是,使用VS2005(VC8)编译的程序,许多错误都不能在SetUnhandledExceptionFilter捕获到。这是CRT相对于前面版本的一个比较大的改变,但是很遗憾,Microsoft却没有在相应的文档明确指出。
虽然也可以通过
_set_abort_behavior(0,_WRITE_ABORT_MSG | _CALL_REPORTFAULT)
,signal(SIGABRT,...)
和_set_invalid_parameter_handler(...)
解决(1)(3),但是对于(2),设置api hook是唯一的方式。
通过上述文章我们知道,源码中_set_abort_behavior
其实就是新版本的VS无法捕获到程序异常abort
时的异常,通过这个函数来使得用户可以捕获到从而进行处理。
#ifdef WIN32 // Enable Data Execution Prevention (DEP) // Minimum supported OS versions: WinXP SP3,WinVista >= SP1,Win Server 2008 // A failure is non-critical and needs no further attention! #ifndef PROCESS_DEP_ENABLE // We define this here,because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7), // which is not correct. Can be removed,when GCCs winbase.h is fixed! #define PROCESS_DEP_ENABLE 0x00000001 #endif typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD); PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"),"SetProcessDEPPolicy"); if (setProcDEPPol != nullptr) setProcDEPPol(PROCESS_DEP_ENABLE); #endif
这段代码是针对wiNows 32位系统的系统中的DEP(Data Execution Prevention,数据执行保护),是WinXP SP3,WinVista >= SP1,Win Server 2008中加入为防止缓冲区溢出攻击的一种措施,保护特定内存中的数据不能当成代码一样执行。这里之所以启用的原因是在GCC中的winbase.h
中只有当系统版本满足_WIN32_WINNT >= 0x0601(Win 7)
时才会启用DEP,这就导致低版本就默认没有启用DEP。启用的方法是首先从动态链接库Kernel32.dll
中寻找SetProcessDEPPolicy的函数地址,该函数的介绍如下,
BOOL WINAPI SetProcessDEPPolicy(
_In_ DWORD dwFlags
);
dwFlags 是DWORD类型,可以取以下几种值,
Value | Meaning |
---|---|
0 | 如果DEP系统策略是OptIn或者OptOut并且DEP已经启用,那么将dwFlags设置为0,表示该进程禁用DEP。 |
PROCESS_DEP_ENABLE@H_301_273@ 0x00000001 | 为该进程永久启用DEP,通过设置PROCESS_DEP_ENABLE@H_301_273@启用DEP之后在该进程生命周期内无法再禁用DEP。 |
PROCESS_DEP_disABLE_ATL_THUNK_EMULATION@H_301_273@ 0x00000002 | disables DEP-ATL thunk emulation for the current process,which prevents the system from intercepting NX faults that originate from the Active Template Library (ATL) thunk layer. For more information,see the Remarks section. This flag can be specified only with PROCESS_DEP@H_301_273@ |
源码中通过定义#define PROCESS_DEP_ENABLE 0x00000001
然后传入SetProcessDEPPolicy
中来启用为进程启用DEP。
接下来通过SetupNetworking()
来初始化套接字,该函数的实现位于src/init.cpp line 863
,
// src/init.cpp line 863 bool SetupNetworking() { #ifdef WIN32 // Initialize Windows Sockets WSADATA wsadata; int ret = WSAStartup(MAKEWORD(2,2),&wsadata); if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2) return false; #endif return true; }
在Windows下编写过网络通信程序的同学相信都知道,Windows使用Socket之前都需要先进行初始化,而这个SetupNetworking()
就是起的这个作用。如果不是Windows环境那么就直接返回true
。
#ifndef WIN32 if (!gArgs.GetBoolArg("-sysperms",false)) { umask(077); } // Clean shutdown on SIGTERM registerSignalHandler(SIGTERM,HandleSIGTERM); // 终止信号 registerSignalHandler(SIGINT,HandleSIGTERM); // 中断信号 // Reopen debug.log on SIGHUP registerSignalHandler(SIGHUP,HandleSIGHUP); //挂起信号 // Ignore SIGPIPE,otherwise it will bring the daemon down if the client closes unexpectedly signal(SIGPIPE,SIG_IGN); #endif
接下来这段代码是在非Windows环境下执行的,首先来看看帮助信息对-sysperms
的解释,
Create new files with system default permissions,instead of umask 077 (only effective with disabled wallet functionality)。
以系统的默认权限创建新文件,而不是077,此功能只有在禁用钱包功能的情况下才有效。
如果设置了-sysperms
那么就以系统默认权限创建新的文件,如果没有设置该参数,那么通过umask
来设置创建新文件时的权限,umask(077)
表示创建的文件具有读写权限,创建的目录ower具有所有权限,所属组和其他用户没有任何权限。
然后三行代码分别注册了终止、中断以及挂起信号的处理函数,而这两个函数做的内容就是将相应的变量设置为true
,
// src/init.cpp line 287 static void HandleSIGTERM(int) { fRequestShutdown = true; } static void HandleSIGHUP(int) { fReopenDebugLog = true; }
而fRequestShutdown
在Step 7中我们会发现是一个循环的控制变量while (!fLoaded && !fRequestShutdown) // init.cpp line 1389
,当变量为true
时才终止循环,这也是SIGTERM
信号要做的事。
接下来的signal(SIGPIPE,SIG_IGN);
表示忽略管道断开信号,首先介绍一下signal
函数,
参考: http://www.cplusplus.com/reference/csignal/signal/
signal函数是用来设置对应信号的处理函数,包括两个参数(in sig,void(*func)(int))。
第一个参数sig表示要处理的信号,有以下一些取值(参考:http://www.voidcn.com/article/p-wulstvzj-ta.html),
Signal@H_301_273@ Description@H_301_273@ SIGABRT 由调用abort函数产生,进程非正常退出 SIgalRM 用alarm函数设置的timer超时或setitimer函数设置的interval timer超时 SIGBUS 某种特定的硬件异常,通常由内存访问引起 SIGCANCEL 由Solaris Thread Library内部使用,通常不会使用 SIGCHLD 进程Terminate或Stop的时候,SIGCHLD会发送给它的父进程。缺省情况下该Signal会被忽略 SIGCONT 当被stop的进程恢复运行的时候,自动发送 SIGEMT 和实现相关的硬件异常 SIGFPE 数学相关的异常,如被0除,浮点溢出,等等 SIGFREEZE Solaris专用,Hiberate或者Suspended时候发送 SIGHUP 发送给具有Terminal的Controlling Process,当terminal被disconnect时候发送 SIGILL 非法指令异常 SIGINFO BSD signal。由Status Key产生,通常是CTRL+T。发送给所有Foreground Group的进程 SIGINT 由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程 SIGIO 异步IO事件 SIGIOT 实现相关的硬件异常,一般对应SIGABRT SIGKILL 无法处理和忽略。中止某个进程 SIGLWP 由Solaris Thread Libray内部使用 SIGPIPE 在reader中止之后写Pipe的时候发送 SIGPOLL 当某个事件发送给Pollable Device的时候发送 SIGPROF Setitimer指定的Profiling Interval Timer所产生 SIGPWR 和系统相关。和UPS相关。 SIGQUIT 输入Quit Key的时候(CTRL+\)发送给所有Foreground Group的进程 SIGSEGV 非法内存访问 SIGSTKFLT Linux专用,数学协处理器的栈异常 SIGSTOP 中止进程。无法处理和忽略。 SIGSYS 非法系统调用 SIGTERM 请求中止进程,kill命令缺省发送 SIGTHAW Solaris专用,从Suspend恢复时候发送 SIGTRAP 实现相关的硬件异常。一般是调试异常 SIGTSTP Suspend Key,一般是Ctrl+Z。发送给所有Foreground Group的进程 SIGTTIN 当Background Group的进程尝试读取Terminal的时候发送 SIGTTOU 当Background Group的进程尝试写Terminal的时候发送 SIGURG 当out-of-band data接收的时候可能发送 SIGUSR1 用户自定义signal 1 SIGUSR2 用户自定义signal 2 SIGVTALRM setitimer函数设置的Virtual Interval Timer超时的时候 SIGWAITING Solaris Thread Library内部实现专用 SIGWINCH 当Terminal的窗口大小改变的时候,发送给Foreground Group的所有进程 SIGXcpu 当cpu时间限制超时的时候 SIGXFSZ 进程超过文件大小限制 SIGXRES Solaris专用,进程超过资源限制的时候发送 第二个参数表示处理的函数,取值有以下三种,
SIG_DFL 默认处理,交给系统默认处理方式处理 SIG_IGN 忽略该信号 Function handler 自定义函数处理 再来详细介绍一下SIGPIPE信号,
转载:http://www.cppblog.com/elva/archive/2008/09/10/61544.html
“当服务器close一个连接时,若client端接着发数据。根据TCP协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了。
根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以client会退出。若不想客户端退出可以把SIGPIPE设为SIG_IGN。”
回到我们的源码,现在明白了这里是防止client通过socket连接到daemon之后client断开导致daemon终止的问题,而忽略SIGPIPE这个信号就可以解决。
接下来看最后一句代码,
std::set_new_handler(new_handler_terminate);
参考:http://www.cnblogs.com/lidan/archive/2012/02/18/2357698.html
set_new_handler()
函数的功能是设置当operator new无法满足某一内存分配需求时首先调用的处理函数,而源码中对new_handle_terminate
的定义是[[noreturn]] static void new_handler_terminate() { // Rather than throwing std::bad-alloc if allocation fails,terminate // immediately to (try to) avoid chain corruption. // Since LogPrintf may itself allocate memory,set the handler directly // to terminate first. std::set_new_handler(std::terminate); LogPrintf("Error: Out of memory. Terminating.\n"); // The log was successful,terminate Now. std::terminate(); };我们发现处理方法是直接终止进程,从而避免可能的数据冲突。
BitCoin比特币的疯狂:如何选择一家合适的比特币交易平台
我个人是一位比特币玩家,现在挖矿基本入不敷出了,所以想玩比特币就只能去交易平台了,目前国内平台不下十家之多,良莠不齐,所以选择一家合适的平台显得尤为重要了。我以我的切身经历给大家阐述怎么去选择交易平台,希望对大家有所帮助。我第一次听说比特币的时候是在2011年,那个时候对比特币一点也不了解,于是在网上收集了一些资料,这才对比特币有了一些了解,也对它产生了一些兴趣,于是就像弄几个比特币玩玩,别人介绍去交易所买一些比特币,但是不知道去哪里买,也不了解各个交易平台, 就随便入驻了国的一家交易平台。
从2012年到2013年初比特币呈现出了强劲的上涨势头,我手里的10几个币也有2000美金的样子了,可是平台上交易了一段时间发现平台有很多问题,例如挂单延迟,眼睁睁的看着错过下单机会;继而出现了更多的问题,网站打不开、客服效率低、资金安全、充值提现非常非常慢,更有甚提现好几天都没人理,严重的影响了正常交易,我决定换一家新的平台,必须保证下单准确,快速充值、提现,于是我开始在国内的几个交易所中进行比较,最终我选择了国内另一家比特币交易平台OKCoin(https://okcoin.com)。在这期间我也总结一些选择交易所的原则,不妨在这里介绍给大家,也好给大家一种参考。暂且以OKCoin为例来阐述我的选择原则,首先声明一下,每个人都有自己的判断,OKCoin只是我的选择结果,不具有代表性,我的这篇文章也没有否定其他平台的意思。只要把握住自己的选择原则就可以了。
1.平台交易量
这个肯定排第一,没有交易量的平台就是死盘子,价格不涨不跌,或者暴涨暴跌。几个币就能成庄家了,很容易被庄家操作,所以这个因素非常的重要,目前OKCoin的每天的交易量有500多(https://okcoin.com首页顶部就能看到,一般的交易平台都会给出交易信息来的),相信以后还会更多。所以这个符合我的选择条件。
2.平台运营能力
一个平台没有盈利能力,只能靠吃客户沉淀资金为生,没有背后强大的资金支持,无疑是相当危险的。这个道理大家都应该懂的。据我所了解OKCoin拥有100W美金的天使投资,是公司运营的,有完整的运营团队,来自百度、谷歌、搜狐等团队,相信平台的盈利以及运营能力肯定没有问题。
3.平台交易手续费
这个手续费的问题是比较现实的问题,在可以接受的情况下选择手续费较低的,如果有免费的那就更好了,可是我从来都不相信什么免费的东西。OKCoin的手续费在国内这几家交易平台来说算是可以接受的,只有0.3%,所以在我的选择范围之内。
4.充值取现的便捷度
尽量选择充值自动化一点的平台,取现选择按时到账的,兼顾手续费的考虑,充值提现一定要快捷,否则你会发现你体现了大半天没动静,让你干着急。我在OKCoin进行了几次充值发现他们的充值都是自动化的,根本不需要人工的干预这就大大的提高了效率,也避免了人工出错的情况出现。最重要的是OKCoin充值可以即时到帐,提现第二天到账,这一点我非常喜欢。目前大多数平台能够做到充值即时到帐,但是提现速度就很难说了。
5.交易行情变动情况
从理论上来说,贴近符合MT行情的比较符合,不能MT涨了,半天还没反应,这样盘子不好操作,这个归根还是成交量的问题。OKCoin能够紧跟MT的价格,所以这也是我选择OKCoin的另一个重要原因,这条因素不必细说。
6.交易平台的客服工作
一个交易平台是否把客户当上帝,取决于他们客服团队的素质,有些公司跟客服说话一两个小时回一句,这难免让人有些费解,这也是我选择离开某China的一个重要的原因,人们在涉及到金钱资金的问题大多是人都是比较谨慎,想把问题问的明明白白,这就要求客服有足够的耐心,以及过硬的专业素质。经过几次简单的接触我发现OKCoin的客服也应该是比特币的玩家,因为几次聊天觉得OKCoin客服对比特币了解颇多,希望客服能继续保持。
7.交易平台安全保障
这条原则也是重中之重,不管你买比特币是为了赚钱还是屯着,平台必须得足够的安全,没有安全一切都等于零,没有安全保障前面几条再好也没用。首先OKCoin网站是有国家工信部ICP备案的,而且是企业备案,可信度比较高;再者OKCoin采用了SSL加密,可能有的人不知道什么是SSL,当你打开网站的时候注意地址栏里是https://www.okcoin.com,http后面有一个s,这就是SSL加密,保证信息传输不被窃听;他们采用了分布式服务器技术,这样就具有更强的坑攻击能力;最重要的是他们完全采用冷存储,也就是离线存储,最大限度的保证了资金的安全。
以上就是我总结选择比特币交易平台的原则,还是那句话仁者见仁智者见智,适合自己的才是最好的,说句公道话,OKCoin这家平台的确值得信赖。最后提醒大家比特币交易没有涨停跌停,24小时开放,所以入市要谨慎啊。
java使用比特币开源类库bitcoinj开发比特币入门指南
bitcoinj是一个使用比特币协议的库。它可以维护钱包,发送/接收交易而无需比特币核心的本地副本,并具有许多其他高级功能。它是用Java实现的,但可以通过任何JVM兼容语言中使用:包括Python和JavaScript中的示例。
它附带完整的文档,并建立了许多大型,众所周知的比特币应用程序和服务。下面我们来看看如何使用它。
初始设置
bitcoinj内置了日志记录和断言。无论是否指定了-ea标志,都会默认检查断言。记录由SLF4J库处理。它允许你选择你更喜欢使用的日志系统,例如JDK日志记录,Android日志记录等。默认情况下,我们使用简单的logger来打印stderr
感兴趣的大部分内容。你可以通过切换lib目录中的jar文件来选择一个新的logger。
bitcoinj使用Maven作为其构建系统,并通过git分发。你可以使用源代码/ jar下载,但直接从源存储库获取它更安全。
要获取代码并安装它,请抓取Maven或Gradle,并将其添加到你的路径中。还要确保安装了git。可能你的Java IDE也有一些Maven/Gradle和Git集成,但是通过命令行使用它们还是非常有用。
现在获取最新版本的代码。你可以使用使用Maven或使用Gradle页面上的说明——只需在那里运行命令,你就可以获得正确的代码版本(除非此网站本身已被泄露)。这是为了防止受损镜像或源代码下载——因为git使用源树哈希工作,如果以正确的方式获得源哈希,则可以保证最终得到正确的代码。
你可以在这里阅读完整的程序。
基本结构
bitcoinj应用程序使用以下对象:
NetworkParameters
实例,用于选择你所在的网络(生产或测试)。- 用于存储
ECKeys
和其他数据的Wallet
实例。 - 用于管理网络连接的
PeerGroup
实例。 - 一个
BlockChain
实例,它管理共享的全局数据结构,使比特币工作。 - 一个
BlockStore
实例,它将块链数据结构保存在某个位置,就像在磁盘上一样。 - WalletEventListener实现,用于接收钱包交易。
为了简化设置,还有一个WalletAppKit
对象可以创建上述对象并将它们连接在一起。虽然可以手动执行此操作(对于大多数“真实”应用程序),但此演示应用程序会显示如何使用应用程序工具包。
让我们看看代码,看看它是如何工作的。
设置
我们使用实用程序函数将log4j配置为具有更紧凑,更简洁的日志格式。然后我们检查命令行参数。
BriefLogFormatter.init();
if (args.length < 2) {
System.err.println("Usage: address-to-send-back-to [regtest|testnet]");
return;
}
然后我们根据可选的命令行参数选择我们将要使用的网络:
// Figure out which network we should connect to. Each one gets its own set of files.
NetworkParameters params;
String filePrefix;
if (args[1].equals("testnet")) {
params = TestNet3Params.get();
filePrefix = "forwarding-service-testnet";
} else if (args[1].equals("regtest")) {
params = RegTestParams.get();
filePrefix = "forwarding-service-regtest";
} else {
params = MainNetParams.get();
filePrefix = "forwarding-service";
}
有多个独立的,独立的比特币网络:
- 人们买卖东西的主要或“生产”网络。
- 公共测试网络(testnet)不时被重置并存在以供我们使用新功能。
- 回归测试模式,它不是公共网络,需要你自己运行带有-regtest标志的比特币守护进程。
每个网络都有自己的创世块,自己的端口号和自己的地址前缀字节,以防止你不小心尝试通过网络发送比特币(这将无法正常工作)。这些事实被封装到NetworkParameters
单例对象中。如你所见,每个网络都有自己的类,你可以通过在其中一个对象上调用get()
来获取相关的NetworkParameters
对象。
强烈建议你在testnet上或使用regtest模式开发软件。如果你不小心丢失了测试比特币,这没什么大不了的,因为它们毫无价值,你可以从TestNet Faucet免费获得大量的比特币。确保在完成后将比特币送回水龙头,以便其他人也可以使用它们。
在regtest模式下,没有公共基础设施,但是你可以随时获得一个新的块而不必等待一个通过在regtest模式bitcoind运行的同一台机器上运行bitcoind -regtest setgenerate true
。
密钥和地址
比特币交易通常将钱汇入公共椭圆曲线键。发件人创建包含收件人地址的交易,其中地址是其公钥哈希的编码形式。接收者然后签署一个交易,用他们自己的私钥声明比特币。密钥用ECKey
类表示。ECKey
可以包含私钥,或只包含缺少私有部分的公钥。请注意,在椭圆曲线加密中,公钥是从私钥派生的,因此知道私钥本身也意味着知道公钥。这与你可能熟悉的其他一些加密系统不同,例如RSA。
地址是公钥的文本编码。实际上,它是公钥的160位hash,具有版本字节和一些校验和字节,使用名为base58的比特币特定编码编码到文本中。Base58旨在避免在写下时可能相互混淆的字母和数字,例如1和大写i。
// Parse the address given as the first parameter.
forwardingAddress = new Address(params, args[0]);
由于地址对要为其使用密钥的网络进行编码,因此我们需要在此处传递网络参数。第二个参数只是用户提供的字符串。如果构造函数不可解析或者网络错误,它将抛出钱包应用套件例外。
bitcoinj由各种层组成,每层都在比最后一层更低的层次上运行。想要发送和接收资金的典型应用程序至少需要BlockChain
,BlockStore
,PeerGroup
和Wallet
。所有这些对象需要相互连接,以便数据正确流动。阅读如何融合在一起,了解有关数据如何通过基于bitcoinj的应用程序流动的更多信息。
为了简化这个过程(通常是样板文件),我们提供了一个名为WalletAppKit
的高级打包器。它在简化的支付验证模式(而不是完全验证)中配置bitcoinj,这是此时选择的最合适的模式。除非你是专家并且希望尝试(不完整的,可能是错误的)完整模式,它提供了一些简单的属性和钩子,允许你修改默认配置。
将来,可能会有更多的工具包为不同类型的应用程序配置bitcoinj,这些应用程序可能有不同的需求。但就目前而言,只有一个。
// Start up a basic app using a class that automates some boilerplate. Ensure we always have at least one key.
kit = new WalletAppKit(params, new File("."), filePrefix) {
@Override
protected void onSetupCompleted() {
// This is called in a background thread after startAndWait is called, as setting up various objects
// can do disk and network IO that may cause UI jank/stuttering in wallet apps if it were to be done
// on the main thread.
if (wallet().getKeyChainGroupSize() < 1)
wallet().importKey(new ECKey());
}
};
if (params == RegTestParams.get()) {
// Regression test mode is designed for testing and development only, so there''s no public network for it.
// If you pick this mode, you''re expected to be running a local "bitcoind -regtest" instance.
kit.connectToLocalHost();
}
// Download the block chain and wait until it''s done.
kit.startAsync();
kit.awaitRunning();
该工具包有三个参数 - NetworkParameters(几乎所有库中的API都需要这个),一个用于存储文件的目录,以及一个以任何创建文件为前缀的可选字符串。如果你希望保持分隔的同一目录中有多个不同的bitcoinj应用程序,这将非常有用。在这种情况下,文件前缀是“forwarding-service”加上网络名称,如果不是主网络(参见上面的代码)。
它还提供了一个可覆盖的方法,我们可以将自己的代码放入其中,以自定义它为我们创建的对象。我们在这里覆盖它。请注意,appkit实际上将在后台线程上创建和设置对象,因此也会从后台线程调用onSetupCompleted。
在这里,我们只需检查钱包是否至少有一个密钥,如果没有,我们会添加一个新密钥。如果我们从磁盘加载钱包,那么当然不会采用此代码路径。
接下来,我们检查我们是否使用regtest模式。如果我们是,那么我们告诉套件只连接到本地主机,其中预计会在regtest模式下运行bitcoind。
最后,我们调用kit.startAsync()。 WalletAppKit是一种番石榴服务。 Guava是Google广泛使用的实用程序库,它增加了标准Java库以及一些有用的附加功能。服务是一个可以启动和停止的对象(但只能启动一次),并且可以在完成启动或关闭时接收回调。你也可以阻止调用线程,直到它以awaitRunning()启动,这就是我们在这里所做的。
当块链完全同步时,WalletAppKit将认为自己已经启动,这有时需要一段时间。你可以了解如何加快速度,但对于玩具演示应用程序,不需要实现任何额外的优化。
该工具包上有访问器,可以访问它配置的底层对象。在类启动或启动过程之前,你不能调用它们(它们将断言),因为不会创建对象。
应用程序启动后,你会注意到应用程序运行的目录中有两个文件:.wallet文件和.spvchain文件。他们走在一起,决不能分开。
处理交易
我们想知道什么时候收到钱,所以我们可以转发它。这是一个交易,与bitcoinj中的大多数Java API一样,你通过注册事件侦听器event listeners
来了解交易,事件侦听器只是实现接口的对象。库中有一些交易监听器接口:
WalletEventListener
:用于发生在钱包中的事情。BlockChainListener
:用于与块链相关的交易。PeerEventListener
:用于与网络中的对等方相关的交易。TransactionConfidence.Listener
:用于与交易具有的回滚安全级别相关的交易。
大多数应用程序不需要使用所有这些。因为每个接口都提供一组相关交易,你可能并不关心所有这些交易。
kit.wallet().addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet w, Transaction tx, Coin prevBalance, Coin newBalance) {
// Runs in the dedicated "user thread".
}
});
bitcoinj中的交易在专用的后台线程中运行,该线程仅用于运行事件侦听器,称为user thread
用户线程。这意味着它可以与应用程序中的其他代码并行运行,如果你正在编写GUI应用程序,则意味着你不能直接修改GUI,因为你不在GUI或main
主线程中。但是,事件侦听器本身不需要是线程安全的,因为交易将按顺序排队并执行。你也不必担心使用多线程库时通常会出现的许多其他问题(例如,重新进入库是安全的,并且可以安全地执行阻塞操作)。
关于编写GUI应用程序的说明
大多数小工具工具包(如Swing,JavaFX或Android)都具有所谓的线程关联,这意味着你只能在单个线程中使用它们。要从后台线程返回到主线程,通常会将闭包传递给某个实用程序函数,该函数调度在GUI线程空闲时运行的闭包。
为了简化使用bitcoinj编写GUI应用程序的任务,你可以在注册事件侦听器listener
时指定任意Executor。将要求该执行程序运行事件侦听器。默认情况下,这意味着将给定的Runnable
传递给用户线程,但你可以像这样覆盖:
Executor runInUIThread = new Executor() {
@Override public void execute(Runnable runnable) {
SwingUtilities.invokeLater(runnable); // For Swing.
Platform.runLater(runnable); // For JavaFX.
// For Android: handler was created in an Activity.onCreate method.
handler.post(runnable);
}
};
kit.wallet().addEventListener(listener, runInUIThread);
现在,listener
上的方法将自动在UI线程中调用。
因为这可能会重复且烦人,你还可以更改默认执行程序,因此所有交易始终在你的UI线程上运行:
Threading.USER_THREAD = runInUIThread;
在某些情况下,bitcoinj可以非常快速地生成大量交易,这在将块链与具有大量交易的钱包同步时是典型的,因为每个交易都可以生成交易可信度confidence
更改交易(因为它们隐藏的很深)。未来钱包交易的工作方式很可能会改变以避免这个问题,但是现在这就是API的工作方式。如果用户线程落后,则当事件侦听器listener
调用在堆上排队时,可能会发生内存膨胀。为避免这种情况,你可以使用Threading.SAME_THREAD
作为执行程序注册交易处理程序,在这种情况下,它们将立即在bitcoinj控制的后台线程上运行。但是,在使用此模式时必须格外小心——代码中出现的任何异常都可能会解开bitcoinj堆栈并导致对等断开连接,同样,重新进入库可能会导致锁定反转或其他问题。通常你应该避免这样做,除非你真的需要额外的表现,并确切知道你在做什么。
收钱
kit.wallet().addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet w, Transaction tx, Coin prevBalance, Coin newBalance) {
// Runs in the dedicated "user thread".
//
// The transaction "tx" can either be pending, or included into a block (we didn''t see the broadcast).
Coin value = tx.getValueSentToMe(w);
System.out.println("Received tx for " + value.toFriendlyString() + ": " + tx);
System.out.println("Transaction will be forwarded after it confirms.");
// Wait until it''s made it into the block chain (may run immediately if it''s already there).
//
// For this dummy app of course, we could just forward the unconfirmed transaction. If it were
// to be double spent, no harm done. Wallet.allowSpendingUnconfirmedTransactions() would have to
// be called in onSetupCompleted() above. But we don''t do that here to demonstrate the more common
// case of waiting for a block.
Futures.addCallback(tx.getConfidence().getDepthFuture(1), new FutureCallback<TransactionConfidence>() {
@Override
public void onSuccess(TransactionConfidence result) {
// "result" here is the same as "tx" above, but we use it anyway for clarity.
forwardCoins(result);
}
@Override
public void onFailure(Throwable t) {}
});
}
});
在这里我们可以看到当我们的应用收到钱时会发生什么,我们打印出我们收到了多少,使用静态实用程序方法格式化为文本。
然后我们做了一些更先进的事情。我们称之为这种方法:
ListenableFuture<TransactionConfidence> future = tx.getConfidence().getDepthFuture(1);
每个交易都有一个与之关联的confidence
对象。confidence
的概念体现了比特币是一个全球共识系统这一事实,该系统不断努力就全球交易顺序达成一致。因为这是一个难题(当遇到恶意行为者时),交易可能会被双倍花费(在比特币术语中我们说它已经dead
)。也就是说,我们有可能相信我们已经收到了钱,后来我们发现世界其他地方不同意我们的看法。
Confidence
对象包含我们可以用来做出基于风险的决策的数据,这些决策是关于我们实际收到钱的可能性。它们还可以帮助我们在信心变化或达到某个阈值时学习。
Futures
是并发编程中的一个重要概念,bitcoinj大量使用它们,特别是我们将Guava扩展用于标准的Java Future类,称为ListenableFuture
。ListenableFuture表示未来某种计算或状态的结果。你可以等待它完成(阻止调用线程),或者注册将被调用的回调。期货也可能会失败,在这种情况下,你会收到异常而不是结果。
在这里,我们要求depth future
。当交易被链中的至少那么多块掩埋时,这个future
就完成了。深度为1表示它出现在链中的顶部块中。所以在这里,我们说“当交易至少有一个确认时运行此代码”。通常你会使用一个名为Futures.addCallback
的实用工具方法,虽然还有另一种注册监听器的方法,可以在下面的代码片段中看到。
然后,当发送给我们钱的交易确认时,我们只调用一个我们自己定义的方法叫做forwardCoins
。
这里有一件重要的事情需要注意。depth future
可能会运行,然后交易的depth
变为小于future
的参数。这是因为在任何时候比特币网络都可能经历“重组”,其中最着名的链从一个切换到另一个。如果你的交易出现在新链中的其他位置,则depth
实际上可能会下降而不是向上。处理入库付款时,你应确保如果交易信心下降,你会尝试中止你为该资金提供的任何服务。你可以通过阅读SPV安全模型了解有关此主题的更多信息。
处理re-orgs和double spends是一个复杂的主题,本教程未涉及。你可以通过阅读其他文章了解更多信息。
发送比特币
ForwardingService
的最后一部分是发送我们刚刚收到的比特币。
Coin value = tx.getValueSentToMe(kit.wallet());
System.out.println("Forwarding " + value.toFriendlyString() + " BTC");
// Now send the coins back! Send with a small fee attached to ensure rapid confirmation.
final Coin amountToSend = value.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
final Wallet.SendResult sendResult = kit.wallet().sendCoins(kit.peerGroup(), forwardingAddress, amountToSend);
System.out.println("Sending ...");
// Register a callback that is invoked when the transaction has propagated across the network.
// This shows a second style of registering ListenableFuture callbacks, it works when you don''t
// need access to the object the future returns.
sendResult.broadcastComplete.addListener(new Runnable() {
@Override
public void run() {
// The wallet has changed now, it''ll get auto saved shortly or when the app shuts down.
System.out.println("Sent coins onwards! Transaction hash is " + sendResult.tx.getHashAsString());
}
});
首先,我们查询我们收到多少钱(当然,由于我们的应用程序的性质,这与上面的onCoinsReceived
回调中的newBalance
相同)。
然后我们决定发送多少——它与我们收到的相同,减去费用。我们不需要附加费用,但如果我们不这样做,可能需要一段时间才能确认。默认费用很低。
要发送比特币,我们使用钱包sendCoins
方法。它需要三个参数:TransactionBroadcaster
(通常是PeerGroup
),发送比特币的地址(这里我们使用我们之前从命令行解析的地址)以及要发送多少钱。
sendCoins
返回一个SendResult
对象,该对象包含已创建的交易和一个ListenableFuture
,可用于查明网络何时接受付款。如果钱包没有足够的钱,sendCoins
方法将抛出一个异常,其中包含一些关于缺少多少钱的信息。
自定义发送过程和设置费用
比特币交易可以附加费用。这对于反拒绝服务机制很有用,但它主要是为了在通货膨胀率下降时激励系统后期的采矿。你可以通过自定义发送请求来控制附加到交易的费用:
SendRequest req = SendRequest.to(address, value);
req.feePerKb = Coin.parseCoin("0.0005");
Wallet.SendResult result = wallet.sendCoins(peerGroup, req);
Transaction createdTx = result.tx;
请注意,在这里,我们实际上设置了每千字节创建的交易的费用。这就是比特币的工作原理——交易的优先级由费用除以大小决定,因此较大的交易要求较高的费用被视为与较小的交易“相同”。
写在最后
bitcoinj还有许多其他功能,本教程不涉及这些功能。你可以阅读其他文章以了解有关完整验证,钱包加密等的更多信息,当然JavaDocs还详细介绍了完整的API。
- php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
- java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
汇智网原创翻译,转载请标明出处。这里是原文
比特币核心程序bitcoind的配置文件bitcoin.conf详解
bitcoin.conf是比特币核心程序bitcoind的配置文件,本文将介绍bitcoin.conf的默认路径,并给出主要配置项的说明。
如果要快速掌握比特币的对接与应用开发,推荐汇智网的在线互动课程:
- Java比特币开发详解
- Php比特币开发详解
- C#比特币开发详解
1、bitcoin.conf的默认路径
- 在linux下,bitcoin.conf的默认路径为
$HOME/.bitcoin/bitcoin.conf
- 在windows下,bitcoin.conf的默认路径为
%APPDATA%\bitcoin\bitcoin.conf
- 在mac下,bitcoin.conf的默认路径为
$HOME/Library/Application Support/Bitcoin/bitcoin.conf
默认情况下bitcoind并不会自动创建上述路径下的bitcoin.conf配置文件,因此需要自行制作一份放入上述目录。如果你没有现成的配置文件可用,可以从github拷贝一份: bitcoin.conf。
2、bitcoin.conf配置说明
在bitcoin.conf配置文件中,每行以key=value的形式声明配置项与值,#
之后的内容为注释。
2.1 总体配置
testnet: 连接主网还是测试网:
testnet=0 # 0 - 主网 1 - 测试网
regtest:是否以私有链模式运行
regtest=0 # 0 - 否 1 - 是
proxy:是否使用socks5代理
#proxy=127.0.0.1:9050 # 默认关闭
bind:本地监听地址
#bind=<addr> # 注释此行,表示使用默认监听地址
whitebind:本地白名单监听地址
#whitebind=<addr> # 注释此行,表示使用默认监听地址
addnode:添加种子节点
#addnode=69.164.218.197 # 可添加多个
connect:连接节点地址
#connect=69.164.218.197
listen:是否进入监听模式,默认启用,除非使用了connect配置
#listen=1
maxconnections:入站/出站最大连接数
#maxconnections=
2.2 RPC配置
server: 是否启动JSON-RPC接口
#server=0 # 0 - 不启动 1 - 启动
rpcbind:rpc接口的监听地址,默认绑定到所有IP
#rpcbind=<addr>
rpcport:rpc接口的监听端口
#rpcport=8332
rpcuser:rpc接口的访问用户名
#rpcuser=alice
#rpcpassword=DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E=
rpcclienttimeout:rpc客户端超时秒数
#rpcclienttimeout=30
rpcallowip:rpc访问白名单
#rpcallowip=1.2.3.4/24
rpcconnect:bitcoin-cli的默认连接地址
#rpcconnect=127.0.0.1
2.3 钱包配置
txconfirmtarget:交易最小确认数,默认值:6
#txconfirmtarget=n
paytxfee:每次发送比特币时的交易费
paytxfee=0.000x
2.4 其他配置
keypool: 密钥池大小
#keypool=100
prune:剪枝留存数量,超过此数量的历史区块将从内存中删除
#prune=550
2.5 用户界面选项
min:是否启动后最小化
#min=1
minimizetotray:是否最小化到系统托盘
#minimizetotray=1
3、示例bitcoin.conf文件
注意下面的配置文件中,选项均已注释,需要根据自己的情况取消注释并设置相应的值:
#testnet=0
#regtest=0
#proxy=127.0.0.1:9050
#bind=<addr>
#whitebind=<addr>
#addnode=69.164.218.197
#addnode=10.0.0.2:8333
#connect=69.164.218.197
#listen=1
#maxconnections=
#server=0
#rpcbind=<addr>
#rpcuser=alice
#rpcpassword=DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E=
#rpcclienttimeout=30
#rpcallowip=10.1.1.34/255.255.255.0
#rpcallowip=1.2.3.4/24
#rpcallowip=2001:db8:85a3:0:0:8a2e:370:7334/96
#rpcport=8332
#rpcconnect=127.0.0.1
#txconfirmtarget=n
#paytxfee=0.000x
#keypool=100
#prune=550
#min=1
#minimizetotray=1
比特币源码linux下环境配置编译运行bitcoin
github源码链接(https://github.com/bitcoin/bitcoin/)
由于近期学习区块链,需要学习下比特币源码,所以尝试着在windows和Linux环境下编译运行,但是windows下的环境配置很繁琐总是在装qt的时候报错,下面贴一下在linux环境下的配置和运行步骤(ubuntu)
(1)安装依赖包
用命令apt-get install安装,如果没有找到该命令则安装apt-get(自行搜索,安装后sudo apt-get update更新包),如果显示权限不够则加用sudo apt-get install命令
经过验证:必需的依赖包有:
sudo apt-get install make
sudo apt-get install gcc
sudo apt-get install g++
sudo apt-get install libdb-dev
sudo apt-get install libdb++-dev
sudo apt-get install libdb5.1++-dev
sudo apt-get install libboost-dev
sudo apt-get install libboost-all-dev
sudo apt-get install zlib1g-dev
sudo apt-get install libssl-dev
sudo apt-get install build-essential
sudo apt-get install libminiupnpc-dev
sudo apt-get install autoconf
(2)将github上的源代码克隆下来
Git clone https://github.com/bitcoin/bitcoin.git
注意是https
注:如果没有安装git则先安装(命令:sudo apt-get install git-core)
如果git clone太慢,可以直接上该网址将源码download下来,然后创建文件夹bitcoin,解压到其中
(3)编译运行
cd bitcoin
会看到整个源码的各种文件,其中有可执行文件autogen.sh和配置文件configure
./autogen.sh
如果报错则加sudo
./configure
该过程则是在你的机器中配置与代码运行相关的依赖并检查必要的环境
我所了解到的bitcoin代码运行机制是多线程的,父进程创建子进程,父进程运行过程中返回后子进程继续进行运行过程的初始化,包括下面12个步骤:
Step 1: setup 设置
Step 2: parameter interactions 参数互动(主要是一些参数设置)
Step 3: parameter-to-internal-flags 参数传入内部标记(bool型变量)
Step 4: application initialization: dir lock,daemonize,pidfile,debug log 应用初始化:锁定目录,后台运行,调试信息
Step 5: verify wallet database integrity 确认钱包数据库的完整性
Step 6: network initialization 网络初始化
Step 7: load block chain 加载块链
Step 8: load wallet 加载钱包
Step 9: import blocks 导入块数据
Step 10: load peers 导入peers
Step 11: start node 开始节点(挖矿程序在这里)
Step 12: finished 完成
所以bitcoin需要检查配置信息以及网络情况,才开始加载块链
执行完.configure之后需要看看是否有相应的错误信息或者WARNING一般warning是可以允许的如果对于bitcoin最后的运行而言,但是我们还是最好逐一排除警告
一开始会出现error的信息:
所以我们改成下面的命令跳过DB版本检测重新执行一遍:
./configure –with-incompatible-bdb
接下来应该是没有error的,此时我们需要往上滚动查看执行结果看是否有warning警告信息
如果是warning:libevent not found
则
sudo apt-get install libevent-dev
后重新执行
./configure –with-incompatible-bdb
如果是warning: zmq找不到大于4的版本
则
sudo apt-get install libzmq-dev
一般到这里已经可以显示最后的检查结果信息页面了:
如果warning:缺少qt所需的依赖
则
sudo apt-get install libqt4-dev
如果还显示warning: libprotobuf找不到
则
sudo apt-get install libprotobuf-dev
sudo apt-get install protobuf-compiler
到这里虽然有下面两个警告没解决但已经算配置成功了的
其实如果嫌麻烦,当然可以先把必须的跟不必须的一起装了,省的反复执行.confiure命令
此时最后的输出结果为:
(4)执行make命令
sudo make
sudo make install
运行差不多8分钟就已经编译完成
(5)此时执行:
bitcoin-qt
即可调出客户端
会提示加载区块数据,近120G,全部加载完毕则就是我们所说的全节点,对于区块数据这个问题我还是疑惑,不知有没有大神解释一下为什么非得加载这么大的数据,不应该加载的是区块的头部么,为什么这么大!
转自:http://blog.csdn.net/huangmx1995/article/details/60140062
今天关于比特币源码解析(13) - 可执行程序 - Bitcoind和比特币源码运行的讲解已经结束,谢谢您的阅读,如果想了解更多关于BitCoin比特币的疯狂:如何选择一家合适的比特币交易平台、java使用比特币开源类库bitcoinj开发比特币入门指南、比特币核心程序bitcoind的配置文件bitcoin.conf详解、比特币源码linux下环境配置编译运行bitcoin的相关知识,请在本站搜索。
本文标签: