【翻译】恒星币和比特币的集成构建

原文-Debugging Stellar and Bitcoin code bases integration build issue
本人水平有限,如发现错误,欢迎在评论区指正!


介绍

目前,我们的区块链团队正在研究Zagg协议,这是一个在公有链上的隐私保护协议,使用使用Account和UTXO的混合模型来跟踪资产和价值。更多关于Zagg的信息可以在其官方网站上了解。最适合Zagg的区块链业务用例是Stellar,但是(基于帐户的模型的)Stellar的生态系统不支持隐私——交易是公开的。Zagg需要隐私,因此需要保障隐私或隔离屏蔽交易,而方法之一就是使用零知识证明的概念(ZKP)。简单来说,就是一方(prover方,证明者)可以向另一方(verifier方,校验者)证明他们知道一个值,没有传达任何额外信息除了这样一个事实:他们知道的值。

为了实现ZKP,我们必须使用基于UTXO的区块链模型。因此,我们决定使用混合模型- Account和UTXO类型。为了实现UTXO功能,我们将Stellar-core和Bitcoin-core区块链代码一起构建。在这个博客里,我想谈谈一下几点:

  • 如何将stellar-core和bitcoin-core一起构建
  • 采用什么方法集成这两个代码库
  • 在将他们一起构建时面临的所有挑战
  • 采用什么方案解决上述问题

注:
如果您想了解区块链模型中UTXO和Account背后的基本概念,您可以在这里查看我的博客,或者在youtube上观看我关于这个主题的演讲。除此之外,那些想了解ZKP的人,可以浏览我的同事Abhijit Sinha写的一个简短但信息量很大的博客。

本文核心点:

从本博客中,您应该了解c++代码库的构建环境(非常基础),并了解集成和构建两个不同代码库所需的流程或操作。把这当作一个例子来理解,您可能没有遇到类似的问题,或者无需处理相同的问题,但是文中的概念和想法可供参考。

如果您是一个经验丰富的c++开发人员,那么这个博客可能对您没有太大帮助,但是您仍然可以阅读、验证并对我们所采用的方法提出有价值的建议或评论:)

问题描述

将Bitcoin-core与Stellar-core集成,以利用Bitcoin-core代码库中的UTXO功能。

解决方法

  • 将Bitcoin-core转换为静态库(.a文件,本质上是目标文件(.o)的存档。
  • 将Bitcoin-core作为Stellar-core的子模块。
  • 将Bitcoin-core库及其依赖项链接到Stellar-core可执行文件。

实现

在第一个版本(v0.1)中,我们希望将比特币代码库集成到Stellar分支中,以实现账户余额和UTXO余额双重模型。以下是该协议的其他版本
的详细信息。在本博客中,我们将只关注v0.1。

让我们先复习一下基础知识!

C++项目结构

通常,使用Autotools进行配置的c++项目具有以下结构:

root\
    lib\
        submodule1\
        submodule2\
        MakeFile.am
    src\
        component1\
            comp1.cpp
            comp1.h
        component2\
        main.cpp
        Makefile.am
    .gitmodules
    .gitignore
    Makefile.am
    configure.ac
    autogen.sh

这是一个非常基本的项目结构,它可能会变得非常复杂,但为了给大家一个概念,让我们忍受一下。我不会提供这些文件的详细信息,但是您可以从我的github代码库下载我的c++样例工程。文件诸如Makefile.amconfigure.ac等是为Autotools或GNU构建工具而存在的。Autotools是一组工具,包括如Autoconf, Automake, make utilityLibtools,用于构建c++项目。

Autotools简介

  • Autoconf根据configure.ac的内容生成configure脚本。
  • ./configure脚本运行时,它生成config.status的脚本。
  • Automake基于Makefile.am文件生成Makefile.in
  • config.status脚本将Makefile.in作为输入,并转化为Makefile文件输出,与构建环境相匹配。
  • 最可执行文件make使用Makefile从源代码生成可执行文件。
    流程如下所示:
configure.ac            Makefile.am              
    | [Autoconf]            | [Automake]
configure               Makefile.in
    | execute               |
configure.status <----------|
    | 
Makefile
    | [make]
(executable)

Configure脚本负责准备为您的特定系统构建软件。它确保其余构建和安装过程部分的所有依赖项都是可用的,并找出使用这些依赖项所需要知道的一切。

正如您所看到的,作为开发人员,我们只需要处理configure.acMakefile.am文件,其余都是由Autotools自动生成的文件。现在,如果您需要理解任何c++项目,您应该从位于根目录中的configure.ac文件开始查看。在该文件中,你将找到一个m4宏,AC_CONFIG_FILES,在这个宏中我们能够了解需要构建的所有Makefile文件。

Makefile指导可执行文件make如何编译和链接程序。在这个文件中,我们可以找到所有与程序相关的依赖项、库和程序文件。通常,这个文件出现在项目的src目录中。看一下比特币代码中的Makefile.am文件,你可以通过这个链接更好地理解Autotools。

Bitcoin-core代码库介绍

比特币代码库本质上是四个程序的组合:bitcoindbitcoin -clibitcoin -txbitcoin -qt。你可以在src/Makefile.am文件中搜索bin_PROGRAMS宏,看到这些程序。

if BUILD_BITCOIND
  bin_PROGRAMS += bitcoind
endif
if BUILD_BITCOIN_CLI
  bin_PROGRAMS += bitcoin-cli
endif
if BUILD_BITCOIN_TX
  bin_PROGRAMS += bitcoin-tx
endif

比特币开发者们已经将模块(consensus、server、cli、wallet、common、crypto等)转换为静态库(.a文件),因此它们可以在所有这些程序之间共享和使用。为了理解这些文件是如何管理的,如前所述,我们需要研究在src目录中的Makefile.am文件。例如:

  • 在比特币的src/Makefile.am文件中,我们有bitcoind,对吧?让我们在那个文件中搜索这个文本。您将获取该程序的源文件(通常为定义main()函数的文件)中的bitcoind_SOURCES宏和链接到bitcoind程序的静态链接库文件(.a文件)的bitcoind_LDADD宏。
  • 现在让我们寻找一个链接库,比如libbitcoin_server,你将找到libbitcoin_server_a_CPPFLAGSlibbitcoin_server_a_CXXFLAGSlibbitcoin_server_a_SOURCES宏。在libbitcoin_server_a_SOURCES宏中,定义了所有.cpp和.h文件。

让我们开始吧!

现在我们已经对比特币代码库有了初步的了解,并且我们也复习了Autools的概念,现在是时候开始将Bitcoin集成到Stellar中了。首先,我们必须把Bitcoin转换成一个库。这样我们就可以将这个库导入到stellar-core代码中并使用它。

识别正确的程序:当我说比特币的时候,我指的是bitcoind,因为这是所需的比特币核心程序,其他像钱包,cli等是代码的外部组件,这是用户与比特币网络交互时需要的。因此,我们通过向./configure脚本传递--disable-*标志位来禁用所有其他要构建的程序。

但正如我所说,整个比特币代码被分成多个子模块,这些子模块被转换成单独的静态库。我们只需要一个库。所以我们从所有这些库中创建一个库,并将其称为静态库libbitcoin_all.a:

libbitcoin_all_a_LIBADD = \
   $(LIBBITCOIN_SERVER) \
   $(LIBBITCOIN_COMMON) \
   $(LIBUNIVALUE) \
   $(LIBBITCOIN_UTIL) \
   $(LIBBITCOIN_CONSENSUS) \
   $(LIBBITCOIN_CRYPTO) \
   $(LIBLEVELDB) \
   $(LIBLEVELDB_SSE42) \
   $(LIBMEMENV) \
   $(LIBSECP256K1)

然后,我们可以使用src/Makefile.am中提供的stellar_LDADD宏将这个库与stellar链接起来。参见下面的示例:

 stellar_core_LDADD = 
    .
    ..
    $(libbitcoin_all_LIBS) 

如果你想学习如何用c++创建一个简单的静态库,可以参考我的这个库。为了生成这个库,我们对bitcoind代码库src/Makefile.am做了必要的修改,并构建了该项目。现在我们有一个静态库文件(libbitcoin_all.a),我们通过Stellar的src/Makefile文件将其链接到stellar-core程序。我们在引入.h文件后,从Stellar代码中调用所需的比特币代码,并试着整体构建这个工程(链接了Bitcoind库的Stellar),但是代码运行不起来。

我们得到了以下错误:

(SET 1)
/home/vishwas/zagg-core/src/main/main.cpp:198: undefined reference to `SendRawTransactionZagg()'
main/stellar_core-main.o: In function `AppInit':
/home/vishwas/zagg-core/src/main/main.cpp:68: undefined reference to `gArgs'
/home/vishwas/zagg-core/src/main/main.cpp:68: undefined reference to `ArgsManager::ParseParameters(int, char const* const*, std::__cxx11::basic_string, std::allocator >&)'
/home/vishwas/zagg-core/src/main/main.cpp:74: undefined reference to `gArgs'
...
..
.
(SET 2)
init.cpp:(.text+0x90c): undefined reference to `fsbridge::fopen(boost::filesystem::path const&, char const*)'
init.cpp:(.text+0xaf2): undefined reference to `GetPidFile()'
../lib/bitcoin/src/libbitcoin_server.a(libbitcoin_server_a-init.o): In function `HandleSIGHUP(int)':
init.cpp:(.text+0xd22): undefined reference to `g_logger'
...
..
.

完整的错误描述请参考链接

调试该错误

我们都知道,当我们遇到一些问题时,我们应该首先理解这个bug,并在坐下来修复它之前找出根本原因。让我们赶紧开始调试吧。

  • 这些错误大多是引用未定义错误。如您所见,当我尝试调用bitcoin中的函数SendRawTransactionZagg()时,我得到了这个错误。这个错误意味着编译器能够找到这个函数的声明(因为我们包含了头文件),但是无法找到它的定义。其他方法也发生了类似的错误。

  • 如果您注意到下一组错误,同样是引用未定义,但这一次它们与boost库有关,这是比特币的一个依赖库,这意味着我没有将boost-filesystem库与Stellar的构建连接起来。

  • 从这些错误中可以明显看出,链接问题是根本原因。从这里,我们有两个努力的方向:

    • 检查libbitcoin_alla是否有任何问题?
    • 我们需要找出比特币的所有依赖库,并将它们与stellar链接起来。这是我们通过研究boost错误所假设的。
步骤1

首先想到的是,我们试图调用的函数SendRawTransactionZagg()是否出现在libbitcoin_all.a库中。正如我所说,这个静态库只是目标文件的存档,因此理想情况下,该函数应该存在于该库中。

我们需要解压它,但在我们这么做之前,首先让我们检查一下这个库是否已经存在或者曾被成功创建。

cd bitcoin
find . -name '*.a'

结果:

./src/.libs/libbitcoinconsensus.a
./src/libbitcoin_util.a
./src/univalue/.libs/libunivalue.a
./src/libbitcoin_wallet.a
./src/libbitcoin_consensus.a
./src/libbitcoin_common.a
./src/libbitcoin_all.a
./src/crypto/libbitcoin_crypto_shani.a
...
..
.

正如你所看到,libbitcoin_all.a库已经存在。现在让我们使用带有grep的工具nm来解压它,看看我们的函数是否存在。

cd src
nm -A libbitcoin_all.a | grep "Zagg"

执行该命令后没有产生任何结果,因此很明显,我们创建的all库有一些错误。

步骤2

接下来,我们试图找出bitcoind使用的所有独立库及其依赖关系,并与stellar一起使用它们。
查找所有单独的库:
当我们运行make -n命令并尝试构建比特币源代码时,请注意,它实际上运行gcc来编译bitcoind的源代码。我们还可以注意到,gcc运行时带有链接的库和依赖项。我们将它们从控制台复制到记事本中,并仔细查看。

查看make -n控制台命令:

.
..
...
bitcoind;/bin/bash ../libtool --silent --tag=CXX --preserve-dup-deps  --mode=link g++ -std=c++11  -Wstack-protector -fstack-protector-all      -fPIE --param ggc-min-expand=1 --param ggc-min-heapsize=32768  -pthread  -Wl,-z,relro -Wl,-z,now -pie      -o bitcoind bitcoind-bitcoind.o  libbitcoin_server.a  libbitcoin_server.a libbitcoin_common.a univalue/libunivalue.la libbitcoin_util.a  libbitcoin_consensus.a crypto/libbitcoin_crypto_base.a crypto/libbitcoin_crypto_sse41.a crypto/libbitcoin_crypto_avx2.a crypto/libbitcoin_crypto_shani.a leveldb/libleveldb.a leveldb/libleveldb_sse42.a leveldb/libmemenv.a secp256k1/libsecp256k1.la libbitcoin_all.a -L/usr/lib/x86_64-linux-gnu -lboost_system -lboost_filesystem -lboost_thread -lboost_chrono  -lcrypto  -levent_pthreads -levent -levent  
...
..
.
  • 您可以看到都链接了哪些库,比如libbitcoin_server.alibbitcoin_common.alibbitcoin_consensus.a等,并注意一些依赖关系,如boostunivaluecryptosecp256k1等。这意味着stellar还需要包含所有这些库。
    在Stellar中使用单独的库和依赖项
    我们首先移除了stellar链接的所有.a库,然后我们添加了上面所有的库和依赖项。这是在stellar代码库中的src/Makefile.am文件中实现的。参见下面的代码片段:
stellar_core_LDADD = \
        .
        ..
        ...
    $(libbitcoin_server_LIBS) \
    $(libbitcoin_consensus_LIBS) \
    $(libbitcoin_common_LIBS) \
        $(libbitcoin_util_LIBS) \
    $(libbitcoin_wallet_a) \
    $(libbitcoin_univalue_LIBS) \
    $(libbitcoin_crypto_base_LIBS) \
    $(libbitcoin_crypto_sse41_LIBS) \
    $(libbitcoin_crypto_avx2_LIBS) \
    $(libbitcoin_crypto_shani_LIBS) \
    $(libbitcoin_leveldb_LIBS) \
    $(libbitcoin_leveldb_sse42_LIBS) \
    $(libbitcoin_memenv_LIBS) \
    $(libbitcoin_secp256k1_LIBS) \
    -lboost_system \
    -lboost_thread \
    -lboost_chrono \
    -lboost_filesystem \
    -lcrypto \
    -levent_pthreads \
    -levent 

可能有更好的方法来添加这些依赖库,但是为了解决这个问题,我们忽略了修饰。我们再次构建了stellar项目,你猜怎么着,这次成功了!我们可以成功地构建以比特币为库的stellar代码,并能够调用比特币中的函数。

结论

我忘记告诉你的一件事是,我们使用了一个demo项目来修复bug,而不是直接使用Stellar。因为这样我们可以更直接地控制makefile和其他源代码。我认为因为对于初学者来说,使用一个小项目总是好的,一流的项目可能看起来很大,我们会更难控制整个代码库。但这同样取决于我们的选择,我们想要如何继续。我相信把一个大问题分成小块总是有帮助的。我希望这个博客能够启发你,关于如何构建和集成c++项目,以及如果你在做的时候遇到了问题要如何处理。希望下次再见到你。

嘿,等等,你构建单个库(libbitcoin_all.a)的方法错在哪,你还没说、

这是你可能想到的问题,对吧?我将把这个问题留给读者思考,并在下面的评论部分告诉我你的答案。谢谢!

你可能感兴趣的:(【翻译】恒星币和比特币的集成构建)