如何将比特币区块链导入Neo4j

本指南介绍了将比特币区块链导入Neo4j图形数据库的基本步骤。

整个过程只是从一种格式(区块链数据)中获取数据,并将其转换为另一种格式(图形数据库)。唯一能使这件事比典型的数据转换稍微复杂一点的是,在开始之前需要去理解比特币数据的结构。

但是,一旦将区块链导入Neo4j,就可以对图形数据库执行SQL数据库无法实现的分析。例如,你可以按照比特币的路径查看是否连接了两个不同的地址:

在本指南中,我将介绍:

  • 1.比特币如何运作,以及区块链是什么。
  • 2.区块链数据是什么样的。
  • 3.如何将区块链数据导入Neo4j。

这不是关于如何编写自己的导入工具的完整教程。但是,如果你有兴趣,可以在GitHub上找到我的比特币到neo4j代码,虽然我确信你在阅读本指南后可以写一些更干净的东西。

1.什么是比特币?

比特币是一个计算机程序。

这有点像uTorrent;你运行程序,它连接到运行相同程序的其他计算机,它共享一个文件。然而,比特币的酷炫之处在于任何人都可以向此共享文件添加数据,并且已经写入文件的任何数据都不会被篡改。

因此,比特币创建了一个在分布式网络上共享的安全文件。

你能用这个做什么?

在比特币中,添加到该文件的每个数据都是一个交易。 因此,该去中心化的文件被用作数字货币(即加密货币)的“分类帐”。

该分类帐称为区块链。

我在哪里可以找到区块链?

如果你运行比特币核心程序bitcoin core,区块链将存储在你计算机的文件夹中:

  • Linux:~/.bitcoin/blocks
  • Windows:~/Library/Application Support/Bitcoin/blocks
  • Mac:C:\Users\YourUserName\Appdata\Roaming\Bitcoin\blocks

当你打开此目录时,你应该注意到,你将找到多个名为blkXXXXX.dat的文件,而不是一个大文件。这是区块链数据,但是分成多个较小的文件。

2.区块链看起来像什么?

blk.dat文件包含块和交易的序列化数据。

区块

区块由magic bytes分隔,然后是即将到来的块的大小。

然后每个区块以一个block header开头:

区块基本上是交易列表的容器。区块头header就像顶部的元数据。

区块头示例:

000000206c77f112319ae21489b66774e8acd379044d4a23ea7498000000000000000000821fe1890186779b2cc232d5dbecfb9119fd46f8a9cfd1141649ff1cd907374487d8ae59e93c011832ec0399

交易

在区块头之后,有一个字节告诉你区块中即将发生的交易数。之后,你将获得一个接一个的序列化交易数据。

交易只是另一段代码,但它们在结构上更有趣。

每个交易都具有相同的模式:

  • 1.选择输出(我们称之为输入)。
    • 解锁这些输入以便可以使用它们。
  • 2.创建输出。
    • 将这些输出锁定到一个新地址。

因此,在一系列交易之后,你有一个看起来像这样的交易结构:

这是区块链的简化图。如你所见,它看起来像一个图表。

交易示例:

0200000001f2f7ee9dda0ba82031858d30d50d3205eea07246c874a0488532014d3b653f03000000006a47304402204df1839028a05b5b303f5c85a66affb7f6010897d317ac9e88dba113bb5a0fe9022053830b50204af15c85c9af2b446338d049672ecfdeb32d5124e0c3c2256248b7012102c06aec784f797fb400001c60aede8e110b1bbd9f8503f0626ef3a7e0ffbec93bfeffffff0200e1f505000000001976a9144120275dbeaeb40920fc71cd8e849c563de1610988ac9f166418000000001976a91493fa3301df8b0a268c7d2c3cc4668ea86fddf81588ac61610700

3.如何将区块链导入Neo4j

那么,现在我们知道区块链数据代表什么(并且它看起来很像图表),我们可以继续将其导入Neo4j。我们这样做:

  • 通过blk.dat文件阅读。
  • 解码我们遇到的每个块和交易。
  • 将解码的块/交易转换为Cypher查询。

这是我如何在数据库中表示区块,交易和地址的可视指南:

区块

  • 创建一个:block节点,并将其连接到它构建的前一个区块。
    • 将区块头中的每个字段设置为此节点上的属性。
  • 创建一个:coinbase节点关闭每个区块,因为它表示区块提供的“新”比特币。
    • 在此节点上设置value属性,该属性等于此区块的区块奖励。

交易

  • 创建一个:tx节点,并将其连接到我们刚创建的:block
    • 此节点上的SET属性(版本,锁定时间)。
  • MERGE现有:output节点并将它们[:in]与:tx相关联。
    • 将解锁代码设置为关系上的属性。
  • 创建一个新:output,这是交易创建的输出节点。
    • 在这些节点上设置相应的值和锁定代码。

地址

如果:output上的锁定代码包含地址……

  • 创建一个:address节点,并将输出节点连接到它。
    • 将地址设置为此节点上的属性。
    • 注意:如果不同的输出连接到同一地址,则它们将连接到同一地址节点。

4.Cypher查询

以下是一些Cypher示例查询,你可以将这些查询用于将区块和交易插入到Neo4j中。

注意:你需要解码区块头和交易数据以获取Cypher查询的参数。

区块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
MERGE (block:block {hash:$blockhash})
CREATE UNIQUE (block)-[:coinbase]->(:output:coinbase)
SET
block.size=$size,
block.prevblock=$prevblock,
block.merkleroot=$merkleroot,
block.time=$timestamp,
block.bits=$bits,
block.nonce=$nonce,
block.txcount=$txcount,
block.version=$version,

MERGE (prevblock:block {hash:$prevblock})
MERGE (block)-[:chain]->(prevblock)

参数示例:

1
2
3
4
5
6
7
8
9
10
11
{
"blockhash": "00000000000003e690288380c9b27443b86e5a5ff0f8ed2473efbfdacb3014f3",
"version": 536870912,
"prevblock": "000000000000050bc5c1283dceaff83c44d3853c44e004198c59ce153947cbf4",
"merkleroot": "64027d8945666017abaf9c1b7dc61c46df63926584bed7efd6ed11a6889b0bac",
"timestamp": 1500514748,
"bits": "1a0707c7",
"nonce": 2919911776,
"size": 748959,
"txcount": 1926,
}

交易

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MATCH (block :block {hash:$hash})
MERGE (tx:tx {txid:$txid})
MERGE (tx)-[:inc {i:$i}]->(block)
SET tx += {tx}

WITH tx
FOREACH (input in $inputs |
MERGE (in :output {index: input.index})
MERGE (in)-[:in {vin: input.vin, scriptSig: input.scriptSig, sequence: input.sequence, witness: input.witness}]->(tx)
)

FOREACH (output in $outputs |
MERGE (out :output {index: output.index})
MERGE (tx)-[:out {vout: output.vout}]->(out)
SET
out.value= output.value,
out.scriptPubKey= output.scriptPubKey,
out.addresses= output.addresses
FOREACH(ignoreMe IN CASE WHEN output.addresses <> '' THEN [1] ELSE [] END |
MERGE (address :address {address: output.addresses})
MERGE (out)-[:locked]->(address)
)
)

注意:此查询使用FOREACH hack,它充当条件,并且只有在$addresses参数实际包含地址(即,如果它不为空)时才会创建:address节点。

参数示例:

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
{
"txid":"2e2c43d9ef2a07f22e77ed30265cc8c3d669b93b7cab7fe462e84c9f40c7fc5c",
"hash":"00000000000003e690288380c9b27443b86e5a5ff0f8ed2473efbfdacb3014f3",
"i":1,
"tx":{
"version":1,
"locktime":0,
"size":237,
"weight":840,
"segwit":"0001"
},
"inputs":[
{
"vin":0,
"index":"0000000000000000000000000000000000000000000000000000000000000000:4294967295",
"scriptSig":"03779c110004bc097059043fa863360c59306259db5b0100000000000a636b706f6f6c212f6d696e65642062792077656564636f646572206d6f6c69206b656b636f696e2f",
"sequence":4294967295,
"witness":"01200000000000000000000000000000000000000000000000000000000000000000"
}
],
"outputs":[
{
"vout":0,
"index":"2e2c43d9ef2a07f22e77ed30265cc8c3d669b93b7cab7fe462e84c9f40c7fc5c:0",
"value":166396426,
"scriptPubKey":"76a91427f60a3b92e8a92149b18210457cc6bdc14057be88ac",
"addresses":"14eJ6e2GC4MnQjgutGbJeyGQF195P8GHXY"
},
{
"vout":1,
"index":"2e2c43d9ef2a07f22e77ed30265cc8c3d669b93b7cab7fe462e84c9f40c7fc5c:1",
"value":0,
"scriptPubKey":"6a24aa21a9ed98c67ed590e849bccba142a0f1bf5832bc5c094e197827b02211291e135a0c0e",
"addresses":""
}
]
}

5.结果

如果你使用上面的Cypher查询插入了块和交易,那么这些是你可以从图形数据库中获得的结果的一些示例。

1
2
3
MATCH (block :block)<-[:inc]-(tx :tx)
WHERE block.hash='$blockhash'
RETURN block, tx

交易

1
2
3
4
5
6
MATCH (inputs)-[:in]->(tx:tx)-[:out]->(outputs)
WHERE tx.txid='$txid'
OPTIONAL MATCH (inputs)-[:locked]->(inputsaddresses)
OPTIONAL MATCH (outputs)-[:locked]->(outputsaddresses)
OPTIONAL MATCH (tx)-[:inc]->(block)
RETURN inputs, tx, outputs, block, inputsaddresses, outputsaddresses

地址

1
2
3
MATCH (address :address {address:'1PNXRAA3dYTzVRLwWG1j3ip9JKtmzvBjdY'})<-[:locked]-(output :output)
WHERE address.address='$address'
RETURN address, output

路径

在比特币区块链的图形数据库中查找交易和地址之间的路径可能是最有趣的事情,所以这里有一些Cypher查询的例子:

在输出之间

1
2
3
MATCH (start :output {index:'$txid:vout'}), (end :output {index:'$txid:out'})
MATCH path=shortestPath( (start)-[:in|:out*]-(end) )
RETURN path

地址之间

1
2
3
MATCH (start :address {address:'$address1'}), (end :address {address:'$address2'})
MATCH path=shortestPath( (start)-[:in|:out|:locked*]-(end) )
RETURN path

结论

这是一个关于如何从blk.dat文件(区块链)获取区块和交易并将它们导入Neo4j数据库的简单指南。

如果你希望对区块链进行严格的图形分析,我认为这是值得的。图形数据库自然适合比特币数据,而使用SQL数据库进行比特币交易感觉就像试图将方形钉推入圆孔一样。

我试图保持这个指南紧凑,所以我没有涵盖如下内容:

  • 1.通过区块链阅读。读取blk.dat文件很简单。但是,关于这些文件的烦人之处在于区块不按顺序写入这些文件,这使得在区块上设置高度或计算交易的费用有点棘手(但你可以围绕它编写代码)。
  • 2.解码区块和交易。如果要使用上面的Cypher查询,则需要通过解码块头和原始交易数据来获取所需的参数。你可以编写自己的解码器,也可以尝试使用现有的比特币库。
  • 3.Segwit(Segregated Witness)隔离认证。我只给了一个Cypher查询“原始”样式的交易,这是在481,824块之前使用的唯一交易结构。但是,segwit交易的结构只是略有不同(但可能需要自己的Cypher查询)。

尽管如此,希望本指南有所帮助。

但与往常一样,如果你了解数据的工作原理,将其转换为不同的格式只需要坐下来编写工具。

祝好运。

======================================================================

分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程:

  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
  • EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
  • tendermint区块链开发详解,本课程适合希望使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。

汇智网原创翻译,转载请标明出处。这里是原文如何将比特币区块链导入Neo4j