正如咱们所知,区块链的设计是不可变的。在这里,咱们将设计一个简单的区块链,它将帮助您理解散列如何使区块链不可变,只需几行Java代码。html
注:这只是一个演示区块链,真正的区块链涉及不少其余东西,如共识机制、数字签名、Merkle树等。。此代码示例将有助于实现理想的目的。java
区块链中的第一个区块是Genesis区块。genesis区块几乎老是硬编码到利用其区块链的应用程序的软件中。算法
对于随后生成的每一个新块,咱们将使用前一个块的哈希以及它本身的事务做为输入来肯定它的块哈希。安全
Object[] contents ={Arrays.hashCode(transactions),previousHash};
blockHash = Arrays.hashCode(contents);
散列函数是一种数学函数,它接受任意长度数值数据的输入,并将其转换为固定长度的数值数据。数据结构
不一样的散列函数使用不一样的算法生成散列值。函数
此外,哈希函数将始终为任何特定输入提供相同的输出。可是,若是您在输入中作了一点小的更改,那么产生的哈希值将与前一个彻底不一样。区块链
记住散列不是加密。ui
在加密中,一旦加密了数据,就能够经过解密将其取回,而在散列中,则没法经过任何方法将输入取回。this
您可能会想知道为何须要像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
这就是块链的造成方式,每一个新块散列都指向它以前的块散列。这种散列系统保证历史记录中的任何事务都不会被篡改,由于若是事务的任何单个部分发生更改,那么它所属的块的散列以及随后任何块的散列也会发生更改。
所以很容易捕获任何篡改,由于您只需比较散列便可。