正如我们所知,区块链的设计是不可变的。在这里,我们将设计一个简单的区块链,它将帮助您理解散列如何使区块链不可变,只需几行Java代码。
注:这只是一个演示区块链,真正的区块链涉及很多其他东西,如共识机制、数字签名、Merkle树等。。此代码示例将有助于实现理想的目的。
区块链中的第一个区块是Genesis区块。genesis区块几乎总是硬编码到利用其区块链的应用程序的软件中。
对于随后生成的每个新块,我们将使用前一个块的哈希以及它自己的事务作为输入来确定它的块哈希。
Object[] contents ={Arrays.hashCode(transactions),previousHash};
blockHash = Arrays.hashCode(contents);
散列函数是一种数学函数,它接受任意长度数值数据的输入,并将其转换为固定长度的数值数据。
不同的散列函数使用不同的算法生成散列值。
此外,哈希函数将始终为任何特定输入提供相同的输出。但是,如果您在输入中做了一点小的更改,那么产生的哈希值将与前一个完全不同。
记住散列不是加密。
在加密中,一旦加密了数据,就可以通过解密将其取回,而在散列中,则无法通过任何方法将输入取回。
您可能会想知道为什么需要像SHA256(安全哈希算法)这样的哈希算法?
最重要的原因是这些算法帮助我们避免冲突(不同输入的哈希值相似)。
现在,让我们通过代码来了解区块链如何使块的散列无法更改,从而使块一旦写入区块链,就无法更改。
我们将创建一个块类。每个块将有:
- 交易清单(int)
- 上一个块哈希(String[])
- 散列(int)
对变量块类应用getter
setter
方法后,如下所示:
import java.util.Arrays;
public class Block
{
private int previousHash;
private String[] transactions;
private int blockHash;
public Block(int previousHash, String[] transactions) {
this.previousHash = previousHash;
this.transactions = transactions;
Object[] contents = {Arrays.hashCode(transactions),previousHash};
this.blockHash = Arrays.hashCode(contents);
}
public int getPreviousHash() {
return previousHash;
}
public String[] getTransactions() {
return transactions;
}
public int getBlockHash() {
return blockHash;
}
public void setPreviousHash(int previousHash) {
this.previousHash = previousHash;
}
public void setTransactions(String[] transactions) {
this.transactions = transactions;
}
public void setBlockHash(int blockHash) {
this.blockHash = blockHash;
}
}
现在让我们创建一个区块链。
我们将从创建Genesis块开始。由于Genesis块是链中的第一个块,我们将硬编码事务和以前的哈希值。
真正的区块链中的交易肯定是某种交易类别,将使用不同的数据结构。为了简单起见,我将它们写成字符串。
主类如下所示:
import java.util.ArrayList;
public class Blockchain {
ArrayList<Block> blockchain = new ArrayList<>();
public static void main(String[] args) {
String[] genesisTransactions = {"Suraj sent Ruja 1542 Bitcoins","Ruja sent 10 Bitcoins to John"};
Block genesisBlock = new Block(0,genesisTransactions);
System.out.println("Genesis Block Hash:"+genesisBlock.getBlockHash());
String[] block2Transactions = {"John sent 10 bitcoins to Suraj","Suraj sent 10 bitcoins to Alex"};
Block block2= new Block(genesisBlock.getBlockHash(), block2Transactions);
System.out.println("Block2 Hash:"+block2.getBlockHash());
String[] block3Transactions = {"Alex sent 999 bitcoins to non"};
Block block3 = new Block(block2.getBlockHash(), block3Transactions);
System.out.println("Block3 Hash:"+block3.getBlockHash());
}
}
输出:
Genesis Block Hash:-1106827926
Block2 Hash:957910147
Block3 Hash:-716750945
您可以输出genesis block的HashCode并更改它,您将看到输出与以前的输出有很大不同,即使您更改事务字符串中单个字母的大小写。
将genesis block事务中“Suraj”的“S”更改为“S”后的输出:
Genesis Block Hash:1528835466
Block2 Hash:-701393757
Block3 Hash:1918912447
这就是块链的形成方式,每个新块散列都指向它之前的块散列。这种散列系统保证历史记录中的任何事务都不会被篡改,因为如果事务的任何单个部分发生更改,那么它所属的块的散列以及随后任何块的散列也会发生更改。
因此很容易捕获任何篡改,因为您只需比较散列即可。