04 BTC-实现
Posted YangYi215
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了04 BTC-实现相关的知识,希望对你有一定的参考价值。
《区块链技术与应用》课程链接:https://www.bilibili.com/video/BV1Vt411X7JF/?spm_id_from=333.337.search-card.all.click
04 BTC-实现
比特币系统是 transaction-based ledger
UTXO:Upsent Transaction Output
UTXO中的元素需要给出它所在交易的哈希值,以及它是交易的第几个输出(因为一笔交易可能有多个输出)。
为什么要维护一个UTXO数据结构?
验证交易是否合法,要花的币必须在UTXO中才行,如果不在,要么是不存在的,要么是之前已经被花过了。
全节点要在内存中维护一个UTXO的数据结构,以便快速检测double spending。
每个交易会消耗掉一些UTXO输出,同时也会产生新的UTXO输出。
如果某个人收到一笔比特币转账,始终不花这笔钱(不想花或私钥丢失),那么这笔钱的信息将永久的保存在全节点的UTXO中。【虽然UTXO的大小不断增大,但是目前为止,装在一个服务器的内存中还是完全足够的】
total inputs = total outputs
奖励光有CoinBase Transaction是不是够的,发布区块的节点为什么要把你的交易打包在交易中呢?这样做对它有什么好处吗?
比如:有些自私的节点,只打包与自己相关的交易,其余交易都不管,打包其它交易对它没有任何好处,而且还有一定的代价,因为你要验证交易的合法性,而且区块中的交易多的话,占用的带宽也多,在网络中传播的速度就会慢。
所以,才有了transaction fee。
(21万 * 10 分钟)/ (60分钟 * 24小时 * 365天)≈ 4年
大概每4年交易减半,2140年不发币。
以太坊是account-based ledger。【系统显示的记录每个账户的余额】
每隔2016个区块,需要调整难度Difficulty,保持出块时间在10分钟左右。
区块数据信息:
Block header的数据结构:
需要注意:nNonce是32位的无符号整型,最多有 $2^32$ 的取值,按照比特币目前的挖矿难度,就算把可能的取值都遍历,很可能仍然找不到符合要求的数,因为搜索空间不够大。
比特币系统并不要求非常精确的时间,所以可以进行一定范围的调整,只要别太离谱。
nBits是(目标阈值target,编码之后的结果),不能进行调整。
可以通过修改Merkle root hash值,更进一步,修改的是CoinBase Tranctions的输入。(因为该交易的输入为空)
其中CoinBase Tranctions的输入可以写任何想要值的hash内容。(比如股票预测,生活琐事)
块头中的nNonce不够用,可以使用coinbase中的前8个字节,这样搜索空间增大到了 $2^96$ 。
挖矿的时候执行两层循环。外层循环调整Coinbase中的值之后,算出block header中的根hash值之后,内层循环再计算nonce中的值。
下述为比特币中普通交易结构的示意图:
挖矿过程中每次尝试nonce,可以看作是一个Bernoulli trial:a random experiment with binary outcome.【每次两种可能性,如:扔硬币,因为硬币可能不均匀,所以正面朝上的概率为p,反面朝上的概率为 1-p 】
挖矿中所有的 Bernoulli trial 构成了一个 Bernoulli process:a sequence of independent Bernoulli trial.
Bernoulli process的一个性质是无记忆性(memoryless)。做大量的实验,前面的实验结果,对后面的实验是没有影响的。【比如:掷硬币,10次反面朝上,是不是下一次正面朝上的概率大一些呢?不是的】
对挖矿来说,每次尝试nonce,成功的可能性很小,需要尝试大量的nonce,才有可能找到符合要求的,这种情况下,Bernoulli process 可以用 Poisson process 来近似。
出块时间服从指数分布(exponential distribution)。
将来还要挖多长时间,和过去挖了多长时间,是没有关系的,仍然是服从指数分布的,平均还是要10分钟。
如果不是progress free,过去的计算对未来的计算有影响,那么算力强的矿工会有不成比例的优势,因为算力强的矿工做的工作肯定是多的。
有两个矿工 A 和 B,A的算力是B的10倍,理想情况下,A获得记账权的概率也应该是B的10倍,这才算是公平。现在A尝试了那么多的nonce,之后找到正确nonce的概率就会增大,这就叫做不成比例的优势。
所以,progress free的性质不是无情,恰恰是挖矿公平性的保证。
geometric series
21万 * 50 + 21万 * 25 + 21万 * 12.5 ...... = 2100万
虽然,挖矿计算的东西是没有什么意义的,但是,挖矿的过程,对于维护比特币系统的安全性是至关重要的。
BitCoin is secured by mining.
对于一个去中心化的,没有membership控制的系统来说,挖矿提供了一种凭借算力投票的有效手段,只要大部分算力是掌握在诚实节点的手中(算力大的投票节点,投票权大),系统的安全性就能够得到保证。
虽然出块奖励少,但是比特币价值反而变高。
假如系统中一半以上的节点都是诚实节点,那么我们能不能保证写入区块链的交易都是合法的?
恶意节点也有可能获得记账权,然后强行写了一笔错误的交易,但是诚实节点不认可该区块中的交易,会继续沿着之前的块往后挖。
定义一个有恶意的攻击是否成功的标准,是要看它能不能让诚实节点接受这个交易,如果仅仅是有恶意的节点之间认可,诚实节点之间不认可,那是没有用的。
比特币讲究的是拓展最长合法链,如果区块不合法,不管不合法区块多长都没有用,是作废的。【这样攻击者既投不了币,也白白损失了出块奖励】
区块往哪个位置挖,是从一开始决定的,因为需要设置前一个区块的hash。
使用fork attack达到double spending attack的效果。
为了防止上述攻击,简单的方法,多等几个确认(confirmation)。
six confirmation之后,才能真正确认一笔交易。
区块链是不可篡改的账本,那是不是说,凡是写入区块链中的内容(irrevocable ledger),那是不是说,凡是写入区块链中的内容,就永远都改不了了。
这种不可篡改性,只是一种概率上的保证。
其实还有一种说法,叫做zero confimation。交易发出之后,还没有写入到区块链中。
比特币全节点在缺省条件下,是按照监听到的交易的顺序进行打包的。
获得记账权的全节点,能不能故意不把某些合法的交易包含到区块中?
问题也不大,因为合法交易还可以写到下一个区块中,总有诚实的节点愿意发布这些交易。
比特币协议规定,每个区块的大小不能超过 1M 个字节,交易太多,有些交易只能等到下一个区块中。
selfish mining 的好处和风险:
好处:可能浪费了别人的算力,减少了竞争。
坏处:可能在自己挖下一个区块的时候,别人挖出了上一个区块,这样自己只能赶紧把自己挖出的区块发布出去,形成分叉,说不能还能获得奖励。
[易学易懂系列|rustlang语言|零基础|快速入门|(27)|实战4:从零实现BTC区块链]
[易学易懂系列|rustlang语言|零基础|快速入门|(27)|实战4:从零实现BTC区块链]
项目实战
实战4:从零实现BTC区块链
我们今天来开发我们的BTC区块链系统。
简单来说,从数据结构的角度上来说,区块链,就是区块组成的链。
以下就是BTC区块链典型的结构:
那最小单元就是区块:block。
这个block包含两部分:区块头,区块体。
我们先忽略Merkle树,先简化所有数据结构,只保留最基本的数据结构。
那区块头,就包含:时间截;前一个区块地址
区块体,就包含交易数据,我们用一个vector来存储。
代码如下 :
///交易结构体
#[derive(Clone, Hash, Serialize, Deserialize, Debug)]
pub struct Transaction {
sender: String, //发送者
recipient: String, //接收者
amount: i64, //交易数量
}
/// 区块结构体
#[derive(Clone, Hash, Serialize, Deserialize, Debug)]
pub struct Block {
pub index: u64, //区块高度
timestamp: DateTime<Utc>, //时间截
pub transactions: Vec<Transaction>, //交易
pub proof: u64, //证明
pub previous_hash: String, //上一个区块哈希地址
}
//区块链结构体
#[derive(Default)]
pub struct Blockchain {
pub chain: Vec<Block>, //区块链帐本
current_transactions: Vec<Transaction>, //交易集合
pub nodes: HashSet<String>, //节点集合
}
现在我们创建了一个基本的区块数据结构,现在我们来让矿工来创建区块吧。
怎么让不同的矿工,积极地创建区块呢?
我们引入一个机制叫:POW共识机制。
什么叫POW?简单来说,就是大家根据给定的一个数值proof,进行hash计算,谁最先算出来的结果值符合某个条件,就拥有创建新的区块,并把这个区块连接到原来的区块链上的权力。
比如,困难程度为5,那有个矿工用proof数据进行SHA哈希计算,出如下结果:
0x0000010000000000000000000000000000000000000000000000000000000000
这个结果,前面的0(除了0x外)是5个,则这就是结果值。
如果,没有计算出上面的结果值,矿工将proof自增1,再进行SHA哈希计算,直到计算出这个符合条件的结果值为止。
而那个给定的数据值proof,也要放在区块头,这个值在每次创建新区块的时候由矿工产生并写入区块头。
当然,如果 两个节点都算出结果并加入了新区块,这时,会产生链的分叉,这时如何决定冲突呢?
我们用最长链原则,即给定周期内,哪个节点拥有的链最长,就用哪个。
所以我们的共识机制是:POW+最长链原则
这个共识机制核心 代码如下:
impl Blockchain {
//创建创世区块
pub fn new() -> Blockchain {
let mut blockchain = Blockchain {
chain: vec![],
current_transactions: vec![],
nodes: HashSet::new(),
};
blockchain.new_block(100, Some("1"));
blockchain
}
/// Create a new Block in the Blockchain
///
/// :param proof: The proof given by the Proof of Work algorithm
/// :param previous_hash: (Optional) hash of previous Block
/// :return: New Bloc
/// 创建新区块
pub fn new_block(&mut self, proof: u64, previous_hash: Option<&str>) -> Block {
let block = Block {
index: (self.chain.len() + 1) as u64,
timestamp: Utc::now(),
transactions: self.current_transactions.drain(0..).collect(),
proof,
previous_hash: previous_hash.unwrap_or("0").to_string(),
};
self.chain.push(block.clone());
block
}
/// Creates a new transaction to go into the next mined Block
///
/// :param sender: Address of the ??ender
/// :param recipient: Address of the recipient
/// :param amount: Amount
/// :return: The index of the Block that will hold this transaction
/// 发起一个新交易,将写入下一个区块
pub fn new_transaction(&mut self, sender: &str, recipient: &str, amount: i64) -> u64 {
self.current_transactions.push(Transaction {
sender: sender.to_string(),
recipient: recipient.to_string(),
amount,
});
self.last_block().unwrap().index + 1
}
/// Simple Proof of Work Algorithm:
/// - Find a number p' such that hash(pp') contains 4 leading zeroes,
/// where p is the previous proof, and p' is the new proof
/// POW工作量证明共识机制算法
pub fn proof_of_work(last_block: &Block) -> u64 {
let mut proof = 0;
let last_proof = last_block.proof;
let last_hash = &last_block.previous_hash;
while !Self::valid_proof(last_proof, proof, last_hash) {
proof += 1;
}
proof
}
/// Validates the Proof: Does hash(last_proof, proof, last_hash) containt 4 leading zeroes
//验证工作证明数字
fn valid_proof(last_proof: u64, proof: u64, last_hash: &String) -> bool {
let guess = format!("{}{}{}", last_proof, proof, last_hash);
let guess_hash = hex_digest(Algorithm::SHA256, guess.as_bytes());
guess_hash.ends_with("00000") //困难度为5
}
/// Creates a SHA-256 hash of a Block
///
/// :param block: Block
/// :return hash for the block
/// 创建一个区块 的哈希值,基SHA-256算法
pub fn hash(block: &Block) -> String {
let serialized = serde_json::to_string(&block).unwrap();
hex_digest(Algorithm::SHA256, serialized.as_bytes())
}
/// Returns the last Block in the chain
/// 返回最后一个区块
pub fn last_block(&self) -> Option<&Block> {
self.chain.last()
}
/// Add a new node to the list of nodes
///
/// :param address: Address of the node. Eg. 'http://192.168.0.5:5000'
///
/// 节点注册,即新节点加入区块链网络,注册地址参数为节点服务器地址,如:'http://192.168.0.5:5000‘
pub fn register_node(&mut self, address: &str) {
let parsed_url = urlparse(address);
self.nodes.insert(parsed_url.netloc);
}
/// Determine if a given blockchain is valid
/// 链的验证
fn valid_chain(&self, chain: &[Block]) -> bool {
let mut last_block = &chain[0];
let mut current_index: usize = 1;
while current_index < chain.len() {
let block = &chain[current_index];
println!("{:?}", last_block);
println!("{:?}", block);
println!("-----------");
if block.previous_hash != Blockchain::hash(last_block) {
return false;
}
if !Blockchain::valid_proof(last_block.proof, block.proof, &last_block.previous_hash) {
return false;
}
last_block = block;
current_index += 1;
}
true
}
/// This is our Consensus Algorithm, it resolves conflicts
/// by replacing our chain with the longest one in the network.
///
/// :return True if our chain was replaced and false otherwise
/// 解决冲突的机制,即共识机制,最长链原则处理逻辑,即共识机制为(POw+最长链原则)
pub fn resolve_conflicts(&mut self) -> bool {
let mut max_length = self.chain.len();
let mut new_chain: Option<Vec<Block>> = None;
// Grab and verify the chains from all the nodes in our network
for node in &self.nodes {
let mut response = reqwest::get(&format!("http://{}/chain", node)).unwrap();
if response.status().is_success() {
let node_chain: Chain = response.json().unwrap();
if node_chain.length > max_length && self.valid_chain(&node_chain.chain) {
max_length = node_chain.length;
new_chain = Some(node_chain.chain);
}
}
}
// Replace our chain if we discovered a new, valid chain longer than ours
match new_chain {
Some(x) => {
self.chain = x;
true
}
None => false,
}
}
}
以上代码,我们放在当前工程目录下的src/blockchain.rs,完整代码如下 :
use crate::api::Chain;
use chrono::{DateTime, Utc};
use crypto_hash::{hex_digest, Algorithm};
use reqwest;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use urlparse::urlparse;
///交易结构体
#[derive(Clone, Hash, Serialize, Deserialize, Debug)]
pub struct Transaction {
sender: String, //发送者
recipient: String, //接收者
amount: i64, //交易数量
}
/// 区块结构体
#[derive(Clone, Hash, Serialize, Deserialize, Debug)]
pub struct Block {
pub index: u64, //区块高度
timestamp: DateTime<Utc>, //时间截
pub transactions: Vec<Transaction>, //交易
pub proof: u64, //证明
pub previous_hash: String, //上一个区块哈希地址
}
//区块链结构体
#[derive(Default)]
pub struct Blockchain {
pub chain: Vec<Block>, //区块链帐本
current_transactions: Vec<Transaction>, //交易集合
pub nodes: HashSet<String>, //节点集合
}
impl Blockchain {
//创建创世区块
pub fn new() -> Blockchain {
let mut blockchain = Blockchain {
chain: vec![],
current_transactions: vec![],
nodes: HashSet::new(),
};
blockchain.new_block(100, Some("1"));
blockchain
}
/// Create a new Block in the Blockchain
///
/// :param proof: The proof given by the Proof of Work algorithm
/// :param previous_hash: (Optional) hash of previous Block
/// :return: New Bloc
/// 创建新区块
pub fn new_block(&mut self, proof: u64, previous_hash: Option<&str>) -> Block {
let block = Block {
index: (self.chain.len() + 1) as u64,
timestamp: Utc::now(),
transactions: self.current_transactions.drain(0..).collect(),
proof,
previous_hash: previous_hash.unwrap_or("0").to_string(),
};
self.chain.push(block.clone());
block
}
/// Creates a new transaction to go into the next mined Block
///
/// :param sender: Address of the ??ender
/// :param recipient: Address of the recipient
/// :param amount: Amount
/// :return: The index of the Block that will hold this transaction
/// 发起一个新交易,将写入下一个区块
pub fn new_transaction(&mut self, sender: &str, recipient: &str, amount: i64) -> u64 {
self.current_transactions.push(Transaction {
sender: sender.to_string(),
recipient: recipient.to_string(),
amount,
});
self.last_block().unwrap().index + 1
}
/// Simple Proof of Work Algorithm:
/// - Find a number p' such that hash(pp') contains 4 leading zeroes,
/// where p is the previous proof, and p' is the new proof
/// POW工作量证明共识机制算法
pub fn proof_of_work(last_block: &Block) -> u64 {
let mut proof = 0;
let last_proof = last_block.proof;
let last_hash = &last_block.previous_hash;
while !Self::valid_proof(last_proof, proof, last_hash) {
proof += 1;
}
proof
}
/// Validates the Proof: Does hash(last_proof, proof, last_hash) containt 4 leading zeroes
//验证工作证明数字
fn valid_proof(last_proof: u64, proof: u64, last_hash: &String) -> bool {
let guess = format!("{}{}{}", last_proof, proof, last_hash);
let guess_hash = hex_digest(Algorithm::SHA256, guess.as_bytes());
guess_hash.ends_with("00000") //困难度为5
}
/// Creates a SHA-256 hash of a Block
///
/// :param block: Block
/// :return hash for the block
/// 创建一个区块 的哈希值,基SHA-256算法
pub fn hash(block: &Block) -> String {
let serialized = serde_json::to_string(&block).unwrap();
hex_digest(Algorithm::SHA256, serialized.as_bytes())
}
/// Returns the last Block in the chain
/// 返回最后一个区块
pub fn last_block(&self) -> Option<&Block> {
self.chain.last()
}
/// Add a new node to the list of nodes
///
/// :param address: Address of the node. Eg. 'http://192.168.0.5:5000'
///
/// 节点注册,即新节点加入区块链网络,注册地址参数为节点服务器地址,如:'http://192.168.0.5:5000‘
pub fn register_node(&mut self, address: &str) {
let parsed_url = urlparse(address);
self.nodes.insert(parsed_url.netloc);
}
/// Determine if a given blockchain is valid
/// 链的验证
fn valid_chain(&self, chain: &[Block]) -> bool {
let mut last_block = &chain[0];
let mut current_index: usize = 1;
while current_index < chain.len() {
let block = &chain[current_index];
println!("{:?}", last_block);
println!("{:?}", block);
println!("-----------");
if block.previous_hash != Blockchain::hash(last_block) {
return false;
}
if !Blockchain::valid_proof(last_block.proof, block.proof, &last_block.previous_hash) {
return false;
}
last_block = block;
current_index += 1;
}
true
}
/// This is our Consensus Algorithm, it resolves conflicts
/// by replacing our chain with the longest one in the network.
///
/// :return True if our chain was replaced and false otherwise
/// 最长链原则处理逻辑,即共识机制为(POw+最长链原则)
pub fn resolve_conflicts(&mut self) -> bool {
let mut max_length = self.chain.len();
let mut new_chain: Option<Vec<Block>> = None;
// Grab and verify the chains from all the nodes in our network
for node in &self.nodes {
let mut response = reqwest::get(&format!("http://{}/chain", node)).unwrap();
if response.status().is_success() {
let node_chain: Chain = response.json().unwrap();
if node_chain.length > max_length && self.valid_chain(&node_chain.chain) {
max_length = node_chain.length;
new_chain = Some(node_chain.chain);
}
}
}
// Replace our chain if we discovered a new, valid chain longer than ours
match new_chain {
Some(x) => {
self.chain = x;
true
}
None => false,
}
}
}
现在 我们向外界提供一些可用的API。
我们新建一个文件:src/api.rs,代码如下 :
use crate::blockchain::{Block, Blockchain, Transaction};
use actix_web::{web, HttpRequest, HttpResponse};
use serde::{Deserialize, Serialize};
use std::sync::Mutex;
///返回消息体
#[derive(Serialize, Deserialize)]
pub struct MessageResponse {
message: String,
}
//交易请求信息
#[derive(Serialize, Deserialize)]
pub struct TransactionRequest {
sender: String,
recipient: String,
amount: i64,
}
///挖矿响应消息
#[derive(Serialize)]
pub struct MiningRespose {
message: String,
index: u64,
transactions: Vec<Transaction>,
proof: u64,
previous_hash: String,
}
///链结构体,代表现在网络上的最长链
#[derive(Serialize, Deserialize)]
pub struct Chain {
pub chain: Vec<Block>,
pub length: usize,
}
///节点注册请求信息
#[derive(Deserialize)]
pub struct RegisterRequest {
nodes: Vec<String>,
}
///节点注册响应信息
#[derive(Serialize)]
pub struct RegisterResponse {
message: String,
total_nodes: Vec<String>,
}
//解决冲突响应信息
#[derive(Serialize)]
pub struct ResolveResponse {
message: String,
chain: Vec<Block>,
}
///发起新交易
pub fn new_transaction(
state: web::Data<Mutex<Blockchain>>,
req: web::Json<TransactionRequest>,
) -> HttpResponse {
let sender = req.sender.to_owned();
let recipient = req.recipient.to_owned();
let index = state
.lock()
.unwrap()
.new_transaction(&sender, &recipient, req.amount);
HttpResponse::Created().json(MessageResponse {
message: format! {"Transaction will be added to Block {}", index},
})
}
///矿工挖矿
pub fn mine(
node_identifier: web::Data<String>,
state: web::Data<Mutex<Blockchain>>,
_req: HttpRequest,
) -> HttpResponse {
let (proof, previous_hash) = {
let blockchain = state.lock().unwrap();
let last_block = blockchain.last_block().unwrap();
let proof = Blockchain::proof_of_work(&last_block);
let previous_hash = Blockchain::hash(last_block);
(proof, previous_hash)
};
let mut blockchain = state.lock().unwrap();
blockchain.new_transaction("0", &*node_identifier, 1);
let block = blockchain.new_block(proof, Some(&previous_hash));
HttpResponse::Ok().json(MiningRespose {
message: "New Block Forged".to_string(),
index: block.index,
transactions: block.transactions,
proof,
previous_hash,
})
}
///当前最新链的信息
pub fn chain(state: web::Data<Mutex<Blockchain>>, _req: HttpRequest) -> HttpResponse {
let length = state.lock().unwrap().chain.len();
HttpResponse::Ok().json(Chain {
chain: state.lock().unwrap().chain.clone(),
length,
})
}
///节点注册
pub fn register_node(
state: web::Data<Mutex<Blockchain>>,
req: web::Json<RegisterRequest>,
) -> HttpResponse {
if req.nodes.is_empty() {
return HttpResponse::BadRequest().json(MessageResponse {
message: "Error: Please supply a valid list of nodes".to_string(),
});
}
let mut blockchain = state.lock().unwrap();
for node in req.nodes.iter() {
blockchain.register_node(node)
}
HttpResponse::Created().json(RegisterResponse {
message: "New nodes have been added".to_string(),
total_nodes: blockchain.nodes.iter().cloned().collect(),
})
}
///跟网络上其他节点达成共识,即解决冲突
pub fn resolve_nodes(state: web::Data<Mutex<Blockchain>>, _req: HttpRequest) -> HttpResponse {
let mut blockchain = state.lock().unwrap();
let replaced = blockchain.resolve_conflicts();
let message = if replaced {
"Our chain was replaced"
} else {
"Our chain is authorative"
};
HttpResponse::Ok().json(ResolveResponse {
message: message.to_string(),
chain: blockchain.chain.clone(),
})
}
当然,我们要用到一些好用的库,在我们的Cargo.toml文件,我们加入依赖,完整代码如下:
[dependencies]
chrono = { version = "0.4.6", features = ["serde"] }
crypto-hash = "0.3.3"
serde = { version = "1.0.90", features = ["derive"] }
serde_json = "1.0"
actix-web = "1.0"
uuid = { version = "0.7", features = ["v4"] }
urlparse = "0.7.3"
reqwest = "=0.9.17"
最后我们的主程序 src/main.rs如下:
pub mod api;
pub mod blockchain;
use actix_web::{web, App, HttpServer};
use std::env;
use std::sync::Mutex;
use uuid::Uuid;
fn main() {
let args: Vec<String> = env::args().collect();
let port = match args.as_slice() {
[_, key, value] => {
if key == "--p" {
value
} else {
panic!("Illegal arguments passed to the program.");
}
}
_ => "5000",
};
// TODO: make chain shared across threads
let sharedchain = web::Data::new(Mutex::new(blockchain::Blockchain::new()));
let node_identifier = web::Data::new(Uuid::new_v4().to_simple().to_string());
HttpServer::new(move || {
App::new()
.register_data(sharedchain.clone())
.register_data(node_identifier.clone())
.data(web::JsonConfig::default().limit(4096))
.service(web::resource("/mine").route(web::get().to(api::mine)))
.service(web::resource("/transactions/new").route(web::post().to(api::new_transaction)))
.service(web::resource("/chain").route(web::get().to(api::chain)))
.service(web::resource("/nodes/register").route(web::post().to(api::register_node)))
.service(web::resource("/nodes/resolve").route(web::get().to(api::resolve_nodes)))
})
.bind(format!("127.0.0.1:{}", port))
.unwrap()
.run();
}
然后我们可以用以下命令来调用 :
挖矿:
curl http://localhost:5000/mine
创建新交易:
curl -H "Content-Type: application/json" --request POST --data '{"sender":"e79fcabd1d70433191701d17c4d13112", "recipient":"some-other-address", "amount":5}' http://localhost:5000/transactions/new
查看整条链信息:
curl http://localhost:5000/chain
注册节点:
curl -H "Content-Type: application/json" --request POST --data '{"nodes":["http://localhost:5001"]}' http://localhost:5000/nodes/register
与其他节点达成共识(共识机制):
curl http://localhost:5000/nodes/resolve
以上,希望对你有用。
如果遇到什么问题,欢迎加入:rust新手群,在这里我可以提供一些简单的帮助,加微信:360369487,注明:博客园+rust
https://asymmetric.github.io/2018/02/11/blockchain-rust/
https://jeiwan.net/posts/building-blockchain-in-go-part-1/
https://freestartupkits.com/articles/technology/cryptocurrency-news-and-tips/ultimate-rust-blockchain-tutorial/
https://hackernoon.com/learn-blockchains-by-building-one-117428612f46
https://medium.com/@vanflymen/learn-blockchains-by-building-one-117428612f46?
https://github.com/Koura/blockchain-example
以上是关于04 BTC-实现的主要内容,如果未能解决你的问题,请参考以下文章