在本章中,让我们构建一个区块浏览器,它允许我们与区块链交互。区块浏览器只是一个用户界面,它允许我们探索区块链内部的数据。它允许我们搜索特定区块、特定交易或特定地址,然后以视觉上吸引人的格式显示特定信息
构建区块资源管理器的第一件事是向区块链添加一些新方法和端点,以便搜索数据。然后,让我们向块资源管理器添加一个前端,以便在浏览器中使用它。
在本章中,我们将介绍以下主题:
那么,让我们开始构建块资源管理器
区块浏览器是一个在线平台,允许您在区块链中导航,搜索各种内容,包括地址、区块、交易等。例如,如果您访问https://www.blockchain.com/explorer 您可以看到比特币和以太坊区块链的区块浏览器实用程序,如下所示:
在此块资源管理器内,您可以在整个区块链中搜索特定块、散列或事务,或任何其他所需数据。该实用程序还将结果显示在易于理解的界面上。例如,如果我们在块资源管理器中搜索Block #549897
,您将看到该特定块的所有详细信息,如以下屏幕截图所示:
这正是我们将在本章中为区块链构建的内容
为了使块资源管理器正常工作,我们需要查询区块链中的地址、块哈希和事务 ID,以便我们可以搜索特定参数并获得特定数据。因此,我们需要执行的第一步是构建更多的端点。为此,让我们继续执行以下步骤:
dev/networkNode.js
文件,在/consensus
端点之后,让我们定义块资源管理器的第一个端点/block/:blockHash
,如下所示:app.get('/block/:blockHash', function(req, res) {
});
一个特定的blockHash
将与该端点一起发送,其结果将简单地向我们返回blockHash
的输入对应的块。
/transaction/:transactionId
。其定义如下:app.get('/transaction/:transactionId', function(req, res) {
});
使用这个端点,发送一个transactionId
,在响应中,我们应该期望得到这个 ID 对应的正确事务。
/address/:address
,定义如下:app.get('/address/:address', function(req, res) {
});
有了这个端点,我们将发送一个特定的地址,作为响应,您应该期望每次该特定地址发送或接收比特币响应时,都能获得与该地址对应的所有交易。您还将了解该地址的当前余额,即该地址当前拥有多少比特币。
因此,这是您将在本章中构建的三个端点。对于这些端点中的每一个,我们将在区块链数据结构中构建一个特定的方法,该方法将在区块链中查询正确的数据片段。因此,让我们创建一些方法来查询区块链中的特定块散列、事务和地址。
让我们构建一个名为getBlock
的新方法,它将获取给定的blockHash
并在整个区块链中搜索与该特定散列相关的块。要构建getBlock
方法,请执行以下步骤:
dev/blockchain.js
文件,在chainIsValid
方法之后,定义这个新方法如下:Blockchain.prototype.getBlock = function(blockHash) {
};
blockHash
值的区块。然后,这个方法将把特定的块返回给我们。我们将借助for
循环来完成所有这些:Blockchain.prototype.getBlock = function(blockHash) {
this.chain.forEach(block => {
});
};
在定义for
循环时,我们循环遍历区块链中的每个block
。
if
语句来说明条件,如下所示:Blockchain.prototype.getBlock = function(blockHash) {
this.chain.forEach(block => {
if (block.hash === blockHash)
});
};
Blockchain.prototype.getBlock = function(blockHash) {
let correctBlock = null;
this.chain.forEach(block => {
if (block.hash === blockHash)
});
};
correctBlock
。让我们按如下方式提及此条件:Blockchain.prototype.getBlock = function(blockHash) {
let correctBlock = null;
this.chain.forEach(block => {
if (block.hash === blockHash) correctBlock = block;
});
};
correctBlock
,如下所示:Blockchain.prototype.getBlock = function(blockHash) {
let correctBlock = null;
this.chain.forEach(block => {
if (block.hash === blockHash) correctBlock = block;
});
return correctBlock
};
我们使用/block/:blockHash
端点内部的getBlock
方法,通过其blockHash
来检索特定的块,接下来我们按照以下步骤来构建端点:
/block/:blockHash
请求一起发送的blockHash
值。我们可以在req.params
对象上访问此blockHash
。转到dev/networkNode.js
文件,在前面定义的/block/:blockHash
端点中,添加以下突出显示的代码:app.get('/block/:blockHash', function(req, res) {
const blockHash = req.params.blockHash;
});
本质上,当我们点击/block/:blockHash
端点时,我们正在访问网络中特定节点上存在的块的散列值。我们还使用req.params
对象访问散列值,这将允许我们访问/block/:blockHash
URL 中前面有冒号的任何值。因此,当用户向该端点发出请求时,他们将在 URL 中发送一个blockHash
,然后我们可以在req.params.blockHash
的帮助下获取该blockHash
。然后我们将把该值保存在blockHash
变量中。
getBlock
方法。我们将向端点添加该方法,如以下代码中突出显示的:app.get('/block/:blockHash', function(req, res) {
const blockHash = req.params.blockHash; const correctBlock = bitcoin.getBlock(blockHash);
});
在代码的这一点上,我们正在寻找的块应该出现在correctBlock
变量中。
correctBlock
变量作为响应,因此让我们向端点添加以下突出显示的代码:app.get('/block/:blockHash', function(req, res) {
const blockHash = req.params.blockHash;const correctBlock = bitcoin.getBlock(blockHash);
res.json({
block: correctBlock
});
});
这就是我们使用getBlock
方法构建/block/:blockHash
端点的方式。现在,让我们测试这个端点并验证它是否正常工作
要测试/block/:blockHash
端点,请执行以下步骤:
localhost:3001/blockchain
,然后按输入。您将看到区块链内部的单个 genesis 区块,如下所示:localhost:3001/mine
,然后按输入。使用相同的过程,让我们再生成一个块。我们现在应该在链中有三个块:一个 genesis 块和我们刚才添加的两个块/block/:blockHash
端点,让我们简单地获取其中一个块的哈希值,并使用它来测试端点。让我们复制链中第三个块的哈希值,如以下屏幕截图所示:localhost:3001/block
,然后将我们直接复制的哈希值粘贴到此 URL 之后。为了更好地理解,请查看以下屏幕截图:/block/:blockHash
端点后将第三个块返回给我们。现在按回车键,正确的块应该作为输出返回给我们:从前面的屏幕截图中,我们可以看到返回给我们的是正确的块。返回的块由我们在/block/:blockHash
端点中用于搜索块的哈希值组成
以类似的方式,您现在可以尝试使用端点和该特定块的哈希值从链中搜索另一个块
现在,如果我们要发送错误的散列或端点不存在的散列,那么我们应该期望返回 null 作为输出,而不是返回块。让我们通过向/block/:blockHash
端点发送错误的散列值来尝试这一点。在浏览器的地址栏中,键入localhost:3001/block
,然后向其添加一个伪哈希值,然后按输入。应返回以下输出:
从前面的屏幕截图可以看出,block
等于null
。这意味着用于搜索块的哈希值在链中不存在。因此,从测试中,我们可以得出结论,/block/:blockHash
端点工作正常,符合预期
让我们在区块链数据结构上添加一个名为getTransaction
的新方法。这将允许我们通过transactionId
获得特定交易。我们将在/transaction/:transactionId
端点内部使用此新方法。那么,让我们开始吧!
dev/blockchain.js
文件,在getBlock
方法之后,定义getTransaction
如下:Blockchain.prototype.getTransaction = function(transactionId) {
}):
此方法与getBlock
方法非常相似。在这里,我们将遍历整个链,并将设置一个标志,该标志等于我们正在寻找的正确事务。
forEach
循环:Blockchain.prototype.getTransaction = function(transactionId) {
this.chain.forEach(block => {
});
}):
for
循环中添加另一个for
循环:Blockchain.prototype.getTransaction = function(transactionId) {
this.chain.forEach(block => {
block.transactions.forEach(transaction => {
});
});
});
transactionId
与我们正在寻找的transactionId
进行比较。当两者匹配时,我们就知道找到了正确的交易。让我们在循环中定义此条件,如下所示:Blockchain.prototype.getTransaction = function(transactionId) {
this.chain.forEach(block => {
block.transactions.forEach(transaction => {
if (transaction.transactionId === transactionId) {
};
});
});
});
getBlock
方法中所做的一样,我们想设置一个标志,表明我们在getTransaction
方法中找到了正确的事务。因此,在两个循环的顶部,定义 flag 变量并按如下方式使用它:Blockchain.prototype.getTransaction = function(transactionId) {
let correctTransaction = null;
this.chain.forEach(block => {
block.transactions.forEach(transaction => {
if (transaction.transactionId === transactionId) {
correctTransaction = transaction;
};
});
});
});
let correctBlock = null;
Blockchain.prototype.getTransaction = function(transactionId) {
let correctTransaction = null;
let correctBlock = null;
this.chain.forEach(block => {
block.transactions.forEach(transaction => {
if (transaction.transactionId === transactionId) {
correctTransaction = transaction;
correctBlock = block;
};
});
});
});
return {
transaction: correctTransaction,
block: correctBlock
};
让我们使用上一节中构建的getTransaction
方法来构建/transaction/:transactionId
端点。开始吧:
transactionId
变量中,如下所示:app.get('/transaction/:transactionId', function(req, res) {
const transactionId = req.params.transactionId;
});
getTransaction
方法。为此,请在前面的代码中添加以下内容:app.get('/transaction/:transactionId', function(req, res) {
const transactionId = req.params.transactionId;
bitcoin.getTransaction(transactionId);
});
getTransaction
方法,我们得到一个返回给我们的对象,该对象包含我们正在寻找的事务以及该事务所在的块。我们希望将此数据存储在名为transactionData
的变量中,如下所示:app.get('/transaction/:transactionId', function(req, res) {
const transactionId = req.params.transactionId;
const trasactionData = bitcoin.getTransaction(transactionId);
});
transactionData
变量:app.get('/transaction/:transactionId', function(req, res) {
const transactionId = req.params.transactionId;
const trasactionData = bitcoin.getTransaction(transactionId);
res.json({
transaction: trasactionData.transaction,
block: trasactionData.block
});
});
这就是我们构建/transaction/:transactionId
端点的方式
现在,是测试/transaction/:transactionId
端点的时候了,以验证它是否按预期工作。然而,在这样做之前,我们需要向区块链添加一些交易数据和区块。
与上一节类似,首先,让我们向区块链添加一些交易和区块:
localhost:3001/transaction/broadcast
端点,将事务发送到网络中的所有节点。 "amount": 200
事务并将其发送到网络localhost:3001/mine
,然后将创建新区块:"amount": 300
事务,并使用前面提到的流程将其发送到网络。一旦交易被发送,让我们再次挖掘一个区块,将交易添加到区块链:"amount":
值为400
和500
,并将它们发送到网络。最后,再次挖掘一个区块,将我们现在创建的交易添加到区块链中:现在,如果您转到localhost:3001/blockchain
,您将看到我们刚才添加到区块链的所有区块和交易
在向区块链添加交易和区块后,让我们测试/transaction/:transactionId
端点:
localhost:3001/transaction/
,然后将区块链中存在的任何块中的transactionId
值附加到此 URL 的末尾,然后按输入。请查看以下屏幕截图以供参考:在前面的屏幕截图中,您可以看到我们将与端点传递的transactionId
相关联的事务作为输出返回。我们还返回了区块,其中包括我们正在寻找的特定transactionId
transactionId
执行另一个示例。要执行此操作,请转到浏览器并在地址栏中键入localhost:3001/transaction/
。完成此操作后,向端点添加一个随机哈希值。请看以下屏幕截图:如前一屏幕截图所示,返回的空值向我们表明该transactionId
在区块链中不存在。
从测试中,我们可以得出结论,/transaction/:transactionId
端点和getTransaction
方法正常工作。
我们将在区块链原型上构建一种称为getAddressData
的新方法,我们将在/address/:address
端点内使用该方法获取我们正在搜索的特定地址的数据:
blockchain.js
文件中构建这个新方法。在getTransaction
方法之后,定义getAddressData
方法如下:Blockchain.prototype.getAddressData = function(address) {
});
Blockchain.prototype.getAddressData = function(address) {
const addressTransactions = [];
});
addressTransactions
数组中。让我们定义这个条件如下。第一步是在区块链上的所有区块之间循环:Blockchain.prototype.getAddressData = function(address) {
const addressTransactions = [];
this.chain.forEach(block => {
});
});
forEach
循环内部,我们必须定义另一个forEach
循环,如下所示:Blockchain.prototype.getAddressData = function(address) {
const addressTransactions = [];
this.chain.forEach(block => {
block.transactions.forEach(transaction => {
});
});
});
forEach
循环中,我们可以访问区块链上的每一笔交易。我们只想测试每笔交易,看看发件人或收件人地址是否与我们正在搜索的地址匹配:Blockchain.prototype.getAddressData = function(address) {
const addressTransactions = [];
this.chain.forEach(block => {
block.transactions.forEach(transaction => {
if(transaction.sender === address ||
transaction.recipient === address) {
addressTransactions.push(transaction);
}
});
});
});
在代码的这一点上,我们在区块链内的所有交易中循环。如果我们遇到一个事务,其中发送方地址或接收方地址等于我们要查找的地址,那么我们将该事务推送到addressTransactions
数组中。因此,在两个forEach
循环完成后,我们将拥有一个数组,该数组包含与我们正在数组中搜索的地址相关联的所有事务。
我们要做的下一件事是在addressTransactions
数组中循环,找出我们正在搜索的地址的余额是多少。为了了解余额:
balance
,如下所示:let balance = 0;
addressTransactions
数组中的所有事务。我们将在forEach
循环的帮助下进行如下操作:let balance = 0;
addressTransactions.forEach(transaction => {
});
if
和else-if
语句来说明条件,如下所示:let balance = 0;
addressTransactions.forEach(transaction => {
if (transaction.recipient === address) balance += transaction.amount;
else if (transaction.sender === address) balance -= transaction.amount;
});
forEach
循环的末尾,我们希望返回一个对象,该对象的属性为addressTransactions
,与我们的addressTransactions
数组匹配,并且与addressBalance
相同:let balance = 0;
addressTransactions.forEach(transaction => {
if (transaction.recipient === address) balance += transaction.amount;
else if (transaction.sender === address) balance -= transaction.amount;
});
return {
addressTransactions: addressTransactions,
addressBalance: balance
};
这样,我们就完成了getAddressData
方法的构建。
现在,让我们构建/address/:address
端点,并在该端点内部使用getAddressData
方法。/address/:address
端点与/block/:blockHash
和/transaction/:transactionId
端点非常相似,因此您不应该觉得它太具有挑战性:
app.get('/address/:address', function(req, res) {
const address = req.params.address;
});
getAddressData
方法获取给定地址的所有数据。为此,我们将向端点添加以下突出显示的代码:app.get('/address/:address', function(req, res) {
const address = req.params.address;
bitcoin.getAddressData(address);
});
addressTransactions
和addressBalance
。我们希望将此数据存储在变量中,如下所示:app.get('/address/:address', function(req, res) {
const address = req.params.address;
const addressData = bitcoin.getAddressData(address);
});
app.get('/address/:address', function(req, res) {
const address = req.params.address;
const addressData = bitcoin.getAddressData(address);
res.json({
addressData: addressData
});
});
这就是我们构建/address/:address
端点的方式。现在,让我们测试这个端点,以检查它是否工作正常
为了测试端点,我们需要向区块链添加一些交易数据,让我们按照以下步骤进行操作:
进入浏览器,探索localhost:3001
上的区块链。你会发现这里只有一个街区。因此,让我们向其中添加更多事务数据和块。
要执行此操作,请转到邮递员并将交易数据发送到localhost:3001/transaction/broadcast
。在创建这些事务时,我们希望确保跟踪特定地址,以便在测试/address/:address
端点时检查它。为了跟踪这个特定的地址,让我们将其中一个地址的前三个字母改为 JEN。
让我们创建第一个事务。将"amount":
值设置为100
,并将JEN
添加到本次交易的发送方地址:
3001
。然后,在类似的行中,为amount: 200
进行另一个交易,这一次,将JEN
添加到收件人的地址,并将发件人的地址保留为随机散列:localhost:3001/mine
并在链中挖掘一个新块,如下所示:类似地,您可以通过更改金额值并交换发件人和收件人的地址(地址中有JEN
)来进行更多交易。一旦创建了一些交易,挖掘一个区块,将这些新交易添加到区块链中。然后,再次创建新的交易,并通过交换发送者和接收者的地址为它们提供不同的金额。再次挖掘一个新区块,将交易添加到区块链中
然后,您可以通过进入localhost:3001/blockchain
浏览整个区块链,以及我们添加到其中的新交易和区块。您将看到区块链中的一系列区块和交易
现在,为了测试/address/:address
端点,让我们按照以下步骤进行操作:
localhost:3001/address/
端点。在前面的屏幕截图中,我们得到返回的addressData
属性,它由addressTransactions
数组和addressBalance
属性组成。addressTransactions
数组包含与端点中提到的地址相关联的所有事务。此外,addressBalance
属性包括我们在端点中提到的地址的比特币余额:
/address/:address
端点来检查节点地址的余额,就像我们在前面的示例中所做的那样。/address/:address
端点是如何工作的。从前面的屏幕截图中,我们可以看到addressTransactions
数组是空的,因为没有与我们作为输入的不存在的地址相关联的事务。此外,不存在的地址的addressBalance
值为0
。因此,我们可以从测试中得出结论,/address/:address
端点正常工作
让我们了解如何设置块资源管理器前端。区块资源管理器将是一个用户界面,我们可以通过它从浏览器与区块链进行交互。为了构建这个用户界面并使其功能化,我们需要使用 HTML、CSS 和 JavaScript。
现在,您可以通过以下链接找到一个完整的预构建前端,而不是自己构建所有前端:https://github.com/PacktPublishing/Learn-Blockchain-Programming-with-JavaScript/blob/master/dev/block-explorer/index.html 。在本节中,我们没有构建整个前端,因为这不是本书的重点。
要构建前端,只需从提供的链接复制文件并将其添加到项目的文件结构中。现在,转到dev
文件夹并在其中创建一个名为block-explorer
的新文件夹。在这个block-explorer
文件夹中,创建一个名为index.html
的文件,您需要将提供的前端代码粘贴到其中,然后保存该文件。在下一节中,您将快速了解此前端代码的组成以及代码的功能
让我们构建一个端点,它将为我们检索block-explorer
文件:
dev/networkNode.js
文件,在这里,创建一个新的端点,将此文件发送给我们。按如下方式定义端点:app.get('/block-explorer', function(req, res) {
});
index.html
文件发回给调用这个端点的人:app.get('/block-explorer', function(req, res) {
res.sendFile('./block-explorer/index.html', { root: __dirname });
});
在前面的章节中,您一定注意到我们通常使用res.json
,这是发送 JSON 数据的一种方式。但是,在这个端点中,我们希望发送整个文件,因此我们将使用res.sendFile
方法。请注意,在前面的代码中,我们使用了{ root: __dirname }
。这个代码术语表示我们应该查看项目存储的目录,并在其中搜索具有/block-explorer/index.html
路径的文件。这就是为什么我们将此选项作为第二个参数添加到端点,这就是我们如何构建端点以发送index.html
文件的原因
networkNode.js
文件,并通过在浏览器中点击localhost:3001/block-explorer
来验证该端点是否工作。然后将显示块资源管理器前端,如下所示:您在这个前端看到的所有内容都包含在我们刚刚创建的index.html
文件中。
在本节中,我们将简单地浏览在上一节中创建的index.html
文件。我们将这样做是为了更好地了解正在发生的事情。那么,让我们开始吧。
在index.html
文件中,我们有所有的 HTML 和 JavaScript 代码为块资源管理器提供必要的功能。这段代码还允许我们使用 API,最后,我们只使用了一些 CSS 和样式,使浏览器中的一切看起来都很好。
代码首先导入两个库,例如angular.js
,以使用 API,以及 jQuery、Bootstrap 和一些引导样式,以使一切功能化和美观化:
<head>
<title>Block Explorer</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
接下来,我们将看到 HTML 模型的主体,它由块资源管理器标题组成:
<body ng-app="BlockExplorer">
<div class="container" ng-controller="MainController">
<div class="row">
<div class="col-md-8 offset-md-2">
<h1 id="page-title">Block Explorer</h1>
</div>
</div
然后,我们有一个文本输入表单:
<div class="row">
<div class="col-md-6 offset-md-3">
<form ng-submit="search(searchValue)">
<div class="form-group">
<input type="text" class="form-control" ng-model="searchValue">
</div>
接下来,我们有一个select
输入,其中有三个选项:Block Hash
、Transaction ID
和Address
:
<div class="form-group">
<select class="form-control" ng-model="searchType">
<option value="block">Block Hash</option>
<option value="transaction">Transaction ID</option>
<option value="address">Address</option>
</select>
</div>
要使用此页面,让我们在文本字段中输入块哈希、事务 ID 或地址,然后从下拉菜单中选择要查找的内容,如以下屏幕截图所示:
最后,在 HTML 代码中,我们只有一些表,一旦我们从区块链中获得了一些数据,这些表将为我们显示所有数据。
此外,我们的index.html
文件中还有一些 JavaScript 代码。在这段 JavaScript 代码中,我们使用 Angular 调用 API:
window.app = angular.module('BlockExplorer', []);
app.controller('MainController', function($scope, $http) {
$scope.block = null;
$scope.transaction = null;
$scope.addressData = null;
$scope.initialSearchMade = false;
然后我们有一个方法,每当我们选择块散列选项时,我们都会点击/block/:blockHash
端点:
$scope.fetchBlock = function(blockHash) {
$http.get(`/block/${blockHash}`)
.then(response => {
$scope.block = response.data.block;
$scope.transaction = null;
$scope.addressData = null;
});
};
同样,我们有/transaction/:transactionId
端点的方法:
$scope.fetchTransaction = function(transactionId) {
$http.get(`/transaction/${transactionId}`)
.then(response => {
$scope.transaction = response.data.transaction;
$scope.block = null;
$scope.addressData = null;
});
};
我们还有/address/:address
终点的方法:
$scope.fetchAddressData = function(address) {
$http.get(`/address/${address}`)
.then(response => {
$scope.addressData = response.data.addressData;
if (!$scope.addressData.addressTransactions.length) $scope
.addressData = null;
$scope.block = null;
$scope.transaction = null;
});
};
在本 JavaScript 的其余部分中,我们只是增加了一点功能,然后在代码的末尾添加了 CSS 样式。因此,这段代码包含在index.html
文件中。如果您想更深入地了解这段代码以获得更清晰的理解,请随意这样做。您也可以按自己的意愿对其进行自定义
然后按 Search,如果区块链中存在指定的数据,将显示一个表,显示所有数据。如果数据在我们的区块链上不存在,您将得到未找到数据的结果。这就是块资源管理器前端的工作方式。
在这一点上,我们构建了一个完整的块资源管理器前端,我们有块资源管理器的后端——我们刚刚创建的三个端点,用于搜索整个区块链
在下一节中,我们将测试块资源管理器,以确保其工作正常。
在本节中,我们将测试块资源管理器,以确保其正常工作,并确保我们在上一章中创建的所有端点和方法也正常工作。如果区块资源管理器工作正常,那么我们已经知道整个区块链也在正常工作,并且在分布式区块链网络上运行,因此当我们进入本章的最后一节时,一切都很顺利。因此,这是我们将要进行的最后一次测试。现在让我们按照以下步骤测试块资源管理器:
localhost:3003/block-explorer
打开块资源管理器。实际上,您可以转到托管在网络中任何节点上的块资源管理器,因为区块链托管在整个网络上。这就是块资源管理器的基本工作方式。我们输入一个散列或一段我们正在寻找的数据,作为回报,我们得到这段数据作为输出。从前面的屏幕截图中,我们可以看到,我们返回了块,块的索引为4
,用于输入到块资源管理器的哈希值。我们还得到了与该街区有关的所有细节。此外,正如您可能在本次搜索中看到的,我们正在到达/block/:blockHash
端点
transactionId
来搜索交易。转到块资源管理器并选择事务 ID 选项。然后,转到区块链,从任何块复制一个transactionId
值,并将其输入到块资源管理器:从前面的屏幕截图中,我们可以看到,我们获得了与输入到块资源管理器的transactionId
相关的所有事务详细信息。我们还观察了该特定transactionId
的 400 比特币余额
从前面的屏幕截图中,我们可以看到该地址的余额为 749.35 比特币,我们可以看到与我们输入的地址相关的所有交易
现在,对于这些搜索中的任何一个,如果我们输入一段不存在的数据,我们将返回如下结果:
这证明了块资源管理器可以正常工作。
在本章中,我们构建了一个令人惊叹的用户界面,以探索到目前为止我们在本书中构建的区块链。我们首先定义查询所需数据所需的端点。然后我们构建了getBlock
、getTransaction
、getAddressData
等方法来帮助端点查询数据。此外,我们还开发了/block/:blockHash
、/transaction/:transactionId
和/address/:address
终点。完成此操作后,我们将块资源管理器的前端代码添加到区块链目录中,然后测试块资源管理器和我们开发的所有端点
有了这一章,我们就到了这本书的结尾。至此,我们已经构建了自己的区块链,并为其添加了所有必要的功能。除此之外,我们还建立了我们的分布式网络和一个探索区块链的接口
下一章将快速总结我们在本书中所学到的知识。然后,我们将探索利用我们开发的区块链还能做些什么。