GVKun编程网logo

比特币源码解析(11) - 可执行程序 - Bitcoind(比特币源码运行)

26

想了解比特币源码解析(11)-可执行程序-Bitcoind的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于比特币源码运行的相关问题,此外,我们还将为您介绍关于BitCoin比特币的疯狂:如何

想了解比特币源码解析(11) - 可执行程序 - Bitcoind的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于比特币源码运行的相关问题,此外,我们还将为您介绍关于BitCoin比特币的疯狂:如何选择一家合适的比特币交易平台、java使用比特币开源类库bitcoinj开发比特币入门指南、比特币核心程序bitcoind的配置文件bitcoin.conf详解、比特币源码linux下环境配置编译运行bitcoin的新知识。

本文目录一览:

比特币源码解析(11) - 可执行程序 - Bitcoind(比特币源码运行)

比特币源码解析(11) - 可执行程序 - Bitcoind(比特币源码运行)

0x01 AppInit - Continue

对于AppInit中剩下的一部分代码,我们首先浏览一下主要实现的功能,然后再具体介绍每个函数的实现方法。

// src/bitcoind.cpp line 127-185
// -server defaults to true for bitcoind but not for the GUI so do this here
        gArgs.softSetBoolArg("-server",true);
        // Set this early so that parameter interactions go to console
        InitLogging();
        InitParameterInteraction();
        if (!AppInitBasicSetup())
        {
            // InitError will have been called with detailed error,which ends up on console
            exit(EXIT_FAILURE);
        }
        if (!AppInitParameterInteraction())
        {
            // InitError will have been called with detailed error,which ends up on console
            exit(EXIT_FAILURE);
        }
        if (!AppInitSanityChecks())
        {
            // InitError will have been called with detailed error,which ends up on console
            exit(EXIT_FAILURE);
        }
        if (gArgs.GetBoolArg("-daemon",false))
        {
#if HAVE_DECL_DAEMON
            fprintf(stdout,"Bitcoin server starting\n");

            // Daemonize
            if (daemon(1,0)) { // don''t chdir (1),do close FDs (0)
                fprintf(stderr,"Error: daemon() Failed: %s\n",strerror(errno));
                return false;
            }
#else
            fprintf(stderr,"Error: -daemon is not supported on this operating system\n");
            return false;
#endif // HAVE_DECL_DAEMON
        }
        // Lock data directory after daemonization
        if (!AppInitLockDataDirectory())
        {
            // If locking the data directory Failed,exit immediately
            exit(EXIT_FAILURE);
        }
        fRet = AppInitMain(threadGroup,scheduler);
    }
    catch (const std::exception& e) {
        PrintExceptionContinue(&e,"AppInit()");
    } catch (...) {
        PrintExceptionContinue(nullptr,"AppInit()");
    }

    if (!fRet)
    {
        Interrupt(threadGroup);
        threadGroup.join_all();
    } else {
        WaitForShutdown(&threadGroup);
    }
    Shutdown();

    return fRet;

首先通过SoftSetBoolArg()设置了-server参数为trueSoftSetBoolArg()首先判断参数是否已经设置过了,如果是,返回false;否则就设置对应的值,返回true。而-server参数表示是否接收RPC命令,这里因为是bitcoind,默认作为核心服务器接收bitcoin-cli以及bitcoin-tx传送的命令。

接下来包括下面几个函数:

  • InitLogging():初始化日志记录以及打印方式。
  • InitParameterInteraction():初始化网络参数。
  • AppInitBasicSetup():注册相应的消息以及处理方式。
  • AppInitParameterInteraction():设置区块链运行参数,例如交易费等等。
  • AppInitSanityChecks():Sanity Check是用来检查比特币运行时所需要的所有的库是否都运行正常。
  • AppInitMain():初始化主程序。
  • ShutDown():关闭所有后台进程并清理程序。

这几个函数将在后面分章节详细介绍,先介绍这部分代码中的其他部分。在AppInitSanityChecks()之后,程序获取了-daemon参数,如果设置了这个参数,表示bitcoind运行后将以守护进程(后台进程)的方式运行,其中daemon()函数的参数描述如下,

链接: http://man7.org/linux/man-pages/man3/daemon.3.html

The daemon() function is for programs wishing to detach themselves
       from the controlling terminal and run in the background as system
       daemons.

       If nochdir is zero,daemon() changes the process''s current working
       directory to the root directory ("/"); otherwise,the current working
       directory is left unchanged.

       If noclose is zero,daemon() redirects standard input,standard
       output and standard error to /dev/null; otherwise,no changes are
       made to these file descriptors.

意思是说daemon()可以将当前进程脱离终端的控制,并转为系统后台进程,函数传入两个参数,第一个是nochdir,为0表示将工作目录改为系统根目录/;为1表示将当前路径设为工作目录。第二个参数noclose为0表示重定向stdin、stdout、stderr到/dev/null,即不显示任何信息;为1表示不改变这些文件描述符。

进程后台化之后,通过AppInitLockDataDirectory()来锁定数据目录,防止程序运行期间随意修改数据目录中的内容。在AppInitMain()结束之后,如果返回值fRetfalse,那么强制结束所有线程;否则就等待所有线程运行结束。最后通过ShutDown()完成清理工作。

0x02 InitLogging

InitLogging的实现位于src/util.cpp中,

// src/util.cpp line 807-816
void InitLogging()
{
    fPrintToConsole = gArgs.GetBoolArg("-printtoconsole",false);
    fLogTimestamps = gArgs.GetBoolArg("-logtimestamps",DEFAULT_LOGTIMESTAMPS);
    fLogTimeMicros = gArgs.GetBoolArg("-logtimemicros",DEFAULT_LOGTIMEMICROS);
    fLogIPs = gArgs.GetBoolArg("-logips",DEFAULT_LOGIPS);

    LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
    LogPrintf("Bitcoin version %s\n",FormatFullVersion());
}

首先从命令行参数当中获取三个参数,

  • -printtoconsole:将所有输出信息都直接输出到终端,而不是默认的debug.log文件。
  • -logtimestamps:给每一条输出信息附带时间戳,默认值为附带。
  • -logtimemicros:让时间戳精确到微秒精度,默认不附加。
  • -logips:输出信息中附加ip地址,默认不附加。

再来看看LogPrintf(),它调用了LogPrintstr()来输出信息,

// src/util.cpp line 328-366
int LogPrintStr(const std::string &str)
{
    int ret = 0; // Returns total number of characters written
    static std::atomic_bool fStartednewLine(true);

    std::string strTimestamped = LogTimestampStr(str,&fStartednewLine);

    if (fPrintToConsole)
    {
        // print to console
        ret = fwrite(strTimestamped.data(),1,strTimestamped.size(),stdout);
        fflush(stdout);
    }
    else if (fPrintToDebugLog)
    {
        boost::call_once(&DebugPrintinit,debugPrintinitFlag);
        boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);

        // buffer if we haven''t opened the log yet
        if (fileout == nullptr) {
            assert(vMsgsBeforeOpenLog);
            ret = strTimestamped.length();
            vMsgsBeforeOpenLog->push_back(strTimestamped);
        }
        else
        {
            // reopen the log file,if requested
            if (fReopenDebugLog) {
                fReopenDebugLog = false;
                fs::path pathDebug = GetDataDir() / "debug.log";
                if (fsbridge::freopen(pathDebug,"a",fileout) != nullptr)
                    setbuf(fileout,nullptr); // unbuffered
            }

            ret = FileWriteStr(strTimestamped,fileout);
        }
    }
    return ret;
}

此函数首先判断判断fPrintToConsole是否为true,是的话就直接输出信息到终端;否则再判断fPrintToDebugLog是否为true,是的话就输出信息到debug.log文件中;如果两个都没有定义,那么就不输出任何调试信息。

BitCoin比特币的疯狂:如何选择一家合适的比特币交易平台

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开发比特币入门指南

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由各种层组成,每层都在比最后一层更低的层次上运行。想要发送和接收资金的典型应用程序至少需要BlockChainBlockStorePeerGroupWallet。所有这些对象需要相互连接,以便数据正确流动。阅读如何融合在一起,了解有关数据如何通过基于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详解

比特币核心程序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

比特币源码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

我们今天的关于比特币源码解析(11) - 可执行程序 - Bitcoind比特币源码运行的分享就到这里,谢谢您的阅读,如果想了解更多关于BitCoin比特币的疯狂:如何选择一家合适的比特币交易平台、java使用比特币开源类库bitcoinj开发比特币入门指南、比特币核心程序bitcoind的配置文件bitcoin.conf详解、比特币源码linux下环境配置编译运行bitcoin的相关信息,可以在本站进行搜索。

本文标签: