区块链炒作继续困扰着技术世界。与此同时,许多银行和软件公司也意识到了这一点,并试图将相应的产品投放市场。然而,任何对区块链技术有更深理解和了解的人都会意识到它的缺点。尽管被认为是一种破坏性技术,但它可能更适合于特殊应用,而不是普通大众。
与其他IT技术并列,区块链是一个相当难以接近的技术。这部分是由于复杂的底层算法,但也因为区块链中包含了许多不同的概念和技术。尽管如此,这个话题还是因为与普遍存在的比特币现象有直接关系而成为人们关注的焦点。然而,在与同事的多次讨论中,一个印象得到了证实:区块链的基本思想已被理解(分布式、公共等),但有关优缺点、替代方案和具体项目机会的具体问题无法回答。
区块链陡峭的学习曲线是这一点的主要原因。通常平均需要几天的时间,对主题进行严格的检查,直到有人大致了解区块链。这种知识的缺乏往往为高端营销活动提供了温床。因此,大型IT公司已经开始提供区块链即服务。银行尤其对该主题感兴趣,合作项目产生的私有区块链至少正在讨论中。在这里,我们可以观察到类似于大数据主题的并行模式。这尤其反映在我们收到的询问中:“我们想用区块链做点什么”。
首先,你应该知道区块链是什么。区块链是一个公共分类账。这意味着它是一个公共数据库,任何人都可以加入和离开,而且系统可以被任何人读写。此外,只有当许多参与者准备以计算机能力的形式投资资源并生成区块(采矿)时,系统才能运行。这就是为什么必须建立这样做的激励机制。对于比特币而言,这是一种利润分配。如果网络上的参与者太少,那么网络很容易被操纵。如果一个潜在的恶棍控制了超过一半的网络节点,他就能够在区块链中放置不正确的信息,并忽略其网络节点中的一致性检查。另一方面,你与朋友和合作伙伴一起运行的区块链没有抓住重点。
有足够的公共信息来源,但许多信息来源并不让我们满意,要么非常肤浅,要么太详细。因此,为了加深开发人员的理解,我们决定用Java实现一个简单的区块链。这有助于跳出概念性讨论的层面,并使得仅用几行代码就可以演示区块链的基本功能。
JBlockchain:第一步
我们基于Java的区块链只是故意保留的,因此,从用户的角度来看,它只具有发送消息和在区块链中查看消息的功能,非常类似于公共聊天室。您基本上必须区分用户(例如,他们在比特币网络上兑换货币)和提供基础设施、存储数据以及为参与者之间提供通信的网络参与者。必须做不同的事情,这取决于你是什么:用户还是参与者。如果您想尝试实现示例,那么您所需要做的就是克隆GitHub(https://github.com/neozo-software/jblockchain)项目并使用Maven构建它。由于我们还需要与其他用户通信的基础设施,因此我们必须启动一个节点。此命令显示其工作原理:
java -jar node/target/node-0.0.1-SNAPSHOT.jar
您需要一个私钥和一个公钥,以及用户名来和其他参与者通信。这些都是必需的。密钥和用户名稍后将提供一个唯一的公共地址,可以识别我们的消息。此命令在此创建一对密钥:
java -jar client/target/client-0.0.1-SNAPSHOT.jar –keypair
有两个文件key.priv
和key.pub
。接下来是必须生成的唯一公共广播:
java -jar client/target/client-0.0.1-SNAPSHOT.jar --address –-node "http://localhost:8080" --name "Max Mustermann" --publickey key.pub
这需要网络节点的地址、公钥和可自由选择的名称。该调用返回用户的唯一公共地址。检查资源是否可用http://localhost:8080/address
查看它们是否已在系统中创建。
为了向系统发送消息,需要以下信息:在上一步中创建的地址和私钥。清单1显示了消息“helloworld”是如何发送的。在资源下http://localhost:8080/transaction
现在可以查看该消息,直到网络节点将其写入实际的区块链。然后,固定消息在下的资源中可用http://localhost:8080/block
.
清单1:发送helloworld消息
java -jar client/target/client-0.0.1-SNAPSHOT.jar --transaction --node "http://localhost:8080" --sender "Tdz0bKDfca3QjFAe5Ccuj9Noy6ah8n+R8DnZznvjic4=" --message "Hello World" --privatekey key.priv
建立节点通信
网络节点必须相互通信,以便每个节点都具有相同的区块链状态。点对点的方法已经建立起来,以确保它能与大量参与者一起工作。通过这种方法,所有网络节点都具有相同的状态,并且在没有中央控制权限的情况下彼此通信。在我们的示例中,我们使用了通过HTTP的简单通信,而不是对等方法。一旦网络节点接收到新信息,例如新事务或新块,它就会将该信息发送给所有其他网络节点(全部广播)。例如:在清单2中,AddressController
实现了一个方法,如果新地址还不存在,可以使用该方法添加新地址。通过可选参数publish
,可以指示节点将新地址通知所有其他节点。
清单2:AddressController
@RestController()
@RequestMapping("address")
public class AddressController {
private final AddressService addressService;
private final NodeService nodeService;
@RequestMapping(method = RequestMethod.PUT)
void addAddress(@RequestBody Address address, @RequestParam(required = false) Boolean publish, HttpServletResponse response) {
if (addressService.getByHash(address.getHash()) == null) {
addressService.add(address);
if (publish != null && publish) {
nodeService.broadcastPut("address", address);
}
response.setStatus(HttpServletResponse.SC_ACCEPTED);
} else {
response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
}
}
}
NodeService
的broadcastPut
方法的实现只是并行地向所有已知网络节点发送put请求。为了简单起见,我们故意假设节点总是可访问的,并且还处理请求。
public void broadcastPut(String endpoint, Object data) {
knownNodes.parallelStream().forEach(
node -> restTemplate.put(node.getAddress() + "/" + endpoint, data));
}
启动网络节点时,将执行以下初始操作以将本地数据更新为网络的当前状态:
- 主网络节点请求下载以下数据:主节点知道的所有节点、所有客户端地址、区块链(数据库数据)和完整的交易池(尚未写入区块链的临时数据)
- 向所有节点广播系统中存在新的网络节点
节点将准备就绪,并且可以由用户寻址。
发送和验证消息
之前我们展示了如何在客户机的帮助下发送消息。在引擎盖下,消息被打包在一个事务中(清单3)。属性散列形成事务的标识符,并通过将所有属性散列在一起形成。这使得能够唯一地标识事务:如果哈希相同,则内容也必须相同。消息存储在字段文本中,发送者将引用唯一的发送者地址。选择事务创建的时间作为时间戳。清单4中创建的签名存储在signature
属性中。
清单3:传输中的包消息
public class Transaction {
private byte[] hash;
private String text;
private byte[] senderHash;
private long timestamp;
private byte[] signature;
}
签名是根据邮件文本和发件人的私钥创建的。由于私钥只为发送者所知,因此任何人都可以确认消息实际上是从发送者姓名后面的地址发送的。
清单4:签名创建
byte[] signature = SignatureUtils.sign(text.getBytes(), Files.readAllBytes(privateKey));
Transaction transaction = new Transaction(text, senderHash, signature);
然后将事务发送到网络节点。清单5显示了节点如何接受事务,以及如果事务足以进行验证,它如何进入事务池。该池是尚未锚定在区块链中的交易的缓冲区。
清单5:节点接受事务
if (verify(transaction)) {
transactionPool.add(transaction);
return true;
}
return false;
}
清单6中的verify方法首先检查事务的发送者是否已知。在该地址,每个人都可以访问公钥,因此可以与消息文本(getSignableData
)和签名一起确认消息的真实性。最后,系统检查传输的事务哈希是否正确计算。
清单6:“验证”-方法
private boolean verify(Transaction transaction) {
// known address
Address sender = addressService.getByHash(transaction.getSenderHash());
if (sender == null) {
return false;
}
// correct signature
if (!SignatureUtils.verify(transaction.getSignableData(), transaction.getSignature(), sender.getPublicKey())) {
return false;
}
// correct hash
if (!Arrays.equals(transaction.getHash(), transaction.calculateHash())) {
return false;
}
return true;
}
事务池与mining
这些消息将通过INSERT存储在关系数据库中。事务属性(ACID)和事务级别(读取未提交或读取已提交)确保并行写入和读取访问满足特定要求,并定义其安全性。通过这种方式,在插入之前打开一个事务,如果没有发生错误,则使用提交将其写入数据库。
由于数据不是集中存储在区块链中,而是所有数据的副本存储在任意数量的网络节点上,并且任意数量的用户希望并行存储数据,因此我们需要不同的机制来获得交易安全性。这就是事务池和挖掘的用武之地。区块链中基本上有两个数据驻留的区域。一方面,这是仍需写入的数据所在的交易池,另一方面,区块链本身不再需要更改数据(图1)。为了防止网络节点同时将交易写入区块链,我们需要克服一个数学难题。您可以从事务池中获取任意可自由选择的事务,并从中生成哈希。这个散列现在必须以1、2或3个零开始,这取决于难度。
难度取决于实际可用的采矿能力。简单地说:少数网络节点意味着有少量的零,许多网络节点意味着有大量的零。这里的目标是,仅在一定时间后(例如每五分钟)才能找到合适的哈希。清单7显示了如何使用蛮力方法搜索合适的块。只要矿工处于活动状态,就会构造一个新的块对象。矿工引用最后一个区块,该区块已锚定在区块链中,并包含先前选择的交易。此外,每个块都有属性trys,这是一个可自由定义的数字,也用于块哈希的计算。如果新创建的块的散列没有足够的前导零,则只需将trys增加1,然后创建一个新块。
清单7:使用蛮力方法找到合适的块
long tries = 0;
while (runMiner.get()) { // atomicBoolean for controlling from other threads
Block block = new Block(previousBlockHash, transactions, tries);
if (block.getLeadingZerosCount() >= Config.DIFFICULTY) {
return block;
}
tries++;
}
当前的限制和扩展选项
JBlockchain实现保持非常简单,因为对技术的理解应该是这里的主要重点。生产性使用中缺少许多概念。以下是一些例子:
- 对于大量网络节点,all广播不可扩展。在这里,我们需要更智能的消息分发。
- 用户可以连接到的网络中必须至少存在一些主节点(例如:静态存储)。
- 天真地考虑分布式系统,而不考虑并发、消息丢失等,很快就会导致问题。这可以通过一个专门为该领域定制的框架来解决,例如Atomix。
- 一般来说,应该考虑是否应该用GNUnet之类的框架来取代对等组件。
- 数学挑战随着网络节点数量的增加而增加。这是当前静态配置的。
- 必须更详细地说明申请的目的,因为这可能导致额外的要求。例如:交易可能不会合并成一个区块,但某些交易具有更高的优先级(例如,根据接收日期)。
结论
区块链是一项非常有趣和激动人心的技术,它将伴随我们很长一段时间。然而,我们敢于怀疑它会改变世界。至少,不是以目前的形式。某些零件更有可能以其他形式重复使用或用于营销目的。当涉及到具体项目时,决策者还需要忍受很多:对参与者数量的控制很少,参与者的高度波动,复杂的编程模型,外部接口的连接困难,以及必须为系统创建激励和营销。这些要点使得对项目进行现实的评估非常困难,因为大多数公司都希望得到可靠的数据和具体的结果。如果您准备好接受这些挑战,您将获得一个高可用、可扩展的数据库的优势,而无需中央控制点,因此无需您自己的硬件成本。
原文地址:https://blockchainconf.net/blog/java/blockchain-java-developers-build-blockchain-java/
除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/2369.html
暂无评论