The simple structure of a blockchain can be simply understood as countless such blocks connected like a chain to form a blockchain.

The green part is called the block header, including (pre hash, tx hash, time)
The black part and the blue part are called the block body, including (hash, transaction)
Where pre hash is the hash of the previous block
time represents the transaction time, timestamp
The tx hash is used to ensure that the data is not tampered with. The data of each block can theoretically be tampered with, but the hash will not match after the modification.
transaction is transaction information
Finally, there is the hash value of the entire block, which is equivalent to the identification of each block. Similarly, as long as one piece of data in the block is changed, the hash value will change.
On the code! ! !
1.First we need to use the package, open the terminal
cargo add serde
cargo add bincode
cargo add rust-crypto
cargo add chrono
2.The package serde is used for serialization and deserialization. Serialization and deserialization are very common functions, which are extremely common in network transmission and data storage. The general explanation of serialization and deserialization is: seriallization serialization: convert the object into a format that is convenient for transmission, common serialization formats: binary format, byte array, json string, xml string. deseriallization deserialization: the process of restoring serialized data into objects.
The package bincode is a binary encoding format.
The package crypto is for hash
The package chrono is for timestamp
3.Add the following code at the top
use bincode;
use serde::{Deserialize, Serialize};
use crypto::digest::Digest;
use crypto::sha3::Sha3;
use chrono::prelude::*;
4.Define the block header
struct BlockHeader {
time: i64,
tx_hash: String,
pre_hash: String,
}
5.Define blocks
struct Block {
header: BlockHeader,
hash: String,
data: String, //transactions data
}
6.Use the package just added to write two methods for serialization and deserialization.
//Serializatize
fn my_serialize<T: ?Sized>(value: &T) -> Vec<u8>
where T: Serialize,
{
let seialized = bincode::serialize(value).unwrap();
seialized
}
//deserialize
fn my_deserialize<'a, T>(bytes: &'a[u8]) -> T
where T: Deserialize<'a>,
{
let deserialized = bincode::deserialize(bytes).unwrap();
deserialized
}
7.Use the package rust-crypto to find the hash
fn get_hash(value: &[u8]) -> String {
let mut hasher = Sha3::sha3_256();
hasher.input(value);
hasher.result_str()
}
8.Implement these methods for the previously defined Block
impl Block {
fn set_hash(&mut self) {
let header = coder::my_serialize(&(self.header));
self.hash = coder::get_hash(&header[..]);
}
fn new_block(data: String, pre_hash: String) -> Block {
let transactions = coder::my_serialize(&data);
let tx_hash = coder::get_hash(&transactions[..]);
let time = Utc::now().timestamp();
let mut block = Block {
header: BlockHeader {
time: time,
tx_hash: tx_hash, //transactions data merkle root hash
pre_hash: pre_hash,
},
hash: "".to_string(),
data: data,
};
block.set_hash();
block
}
}
9.Define blockchain
struct BlockChain {
blocks: Vec<block::Block>,
}
impl BlockChain {
fn add_block(&mut self, data: String) {
let pre_block = &self.blocks[self.blocks.len() - 1];
let new_block = block::Block::new_block(data, pre_block.hash.clone());
self.blocks.push(new_block);
}
fn new_genesis_block() -> block::Block {
block::Block::new_block("This is genesis block".to_string(), String::from(""))
}
fn new_blockchain() -> BlockChain {
BlockChain {
blocks: vec![BlockChain::new_genesis_block()],
}
}
}
10.Define the main method
fn main() {
let mut bc = blockchain::BlockChain::new_blockchain();
bc.add_block(String::from("a -> b: 5 btc"));
bc.add_block("c -> d: 1 btc".to_string());
for b in bc.blocks {
println!("++++++++++++++++++++++++++++++++++++++++++++");
println!("{:#?}", b);
println!("");
}
}
The final code should look like this.
use bincode;
use serde::{Deserialize, Serialize};
use crypto::digest::Digest;
use crypto::sha3::Sha3;
use chrono::prelude::*;
struct BlockHeader {
time: i64,
tx_hash: String,
pre_hash: String,
}
struct Block {
header: BlockHeader,
hash: String,
data: String, //transactions data
}
impl Block {
fn set_hash(&mut self) {
let header = coder::my_serialize(&(self.header));
self.hash = coder::get_hash(&header[..]);
}
fn new_block(data: String, pre_hash: String) -> Block {
let transactions = coder::my_serialize(&data);
let tx_hash = coder::get_hash(&transactions[..]);
let time = Utc::now().timestamp();
let mut block = Block {
header: BlockHeader {
time: time,
tx_hash: tx_hash, //transactions data merkle root hash
pre_hash: pre_hash,
},
hash: "".to_string(),
data: data,
};
block.set_hash();
block
}
}
fn my_serialize<T: ?Sized>(value: &T) -> Vec<u8>
where T: Serialize,
{
let seialized = bincode::serialize(value).unwrap();
seialized
}
fn my_deserialize<'a, T>(bytes: &'a[u8]) -> T
where T: Deserialize<'a>,
{
let deserialized = bincode::deserialize(bytes).unwrap();
deserialized
}
fn get_hash(value: &[u8]) -> String {
let mut hasher = Sha3::sha3_256();
hasher.input(value);
hasher.result_str()
}
struct BlockChain {
blocks: Vec<block::Block>,
}
impl BlockChain {
fn add_block(&mut self, data: String) {
let pre_block = &self.blocks[self.blocks.len() - 1];
let new_block = block::Block::new_block(data, pre_block.hash.clone());
self.blocks.push(new_block);
}
fn new_genesis_block() -> block::Block {
block::Block::new_block("This is genesis block".to_string(), String::from(""))
}
fn new_blockchain() -> BlockChain {
BlockChain {
blocks: vec![BlockChain::new_genesis_block()],
}
}
}
Cargo run, the effect

If you want to simulate mining, use sleep for about 10s
