#![allow(unused_imports)]
use crate::tx::*;
use crate::user::*;
use bitvec::prelude::*;
use ethnum::*;
use k256::PublicKey;
use k256::{
ecdsa::{signature::Signer, signature::Verifier, Signature, SigningKey, VerifyingKey},
elliptic_curve::sec1::*,
Secp256k1, SecretKey,
};
use rand::prelude::*;
use serde::*;
use serde::{Deserialize, Serialize};
use sha3::*;
use std::collections::HashMap;
use std::fs;
use std::hash::Hash;
use std::os;
use std::process::Output;
use std::time::{SystemTime, UNIX_EPOCH};
pub type BlockHash = [u8; 32];
pub const BLANK_BLOCK_HASH: [u8; 32] = [0; 32];
#[derive(Serialize, Deserialize)]
pub struct State {
pub blocks: Vec<Block>,
#[serde(skip)]
pub old_utxo_set: HashMap<Outpoint, TxOutput>,
#[serde(skip)]
pub utxo_set: HashMap<Outpoint, TxOutput>,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct Block {
pub version: u64,
pub prev_hash: BlockHash,
pub time_stamp: u64,
pub nonce: u64,
pub txs: Vec<Tx>,
}
#[derive(Debug)]
pub enum BlockErr {
Nonce(u64),
Sig(Signature),
Overspend(u64, u64),
Supply(u64),
FalseInput,
PrevHash(BlockHash, BlockHash),
GenesisBlock,
TimeStamp(u64, u64),
}
impl State {
pub fn verify_all_blocks(&self) -> Result<HashMap<Outpoint, TxOutput>, BlockErr> {
let mut utxo_set = HashMap::new();
let mut block_iter = self.blocks.iter();
let mut prev_block = block_iter.next().ok_or(BlockErr::GenesisBlock)?;
let root_tx = prev_block.txs[0].clone();
let my_verifying_key: VerifyingKey = vk_from_encoded_str(
"04B0B5D59947A744C8ED5032F8B5EC77F56BFF09A724466397E82\
61ABE15BB1F1EC90871F5034A7B2BBF43F33C99225EF70C6F463B3\
93973C55E85382F90F2935E",
)
.into();
if prev_block.txs.len() > 1
|| root_tx.outputs.len() > 1
|| !my_verifying_key
.verify(&prev_block.txs[0].txid, &prev_block.txs[0].signature)
.is_ok()
{
return Err(BlockErr::GenesisBlock);
}
utxo_set.insert(Outpoint(root_tx.txid, 0), root_tx.outputs[0].clone());
for (i, block) in block_iter.enumerate() {
utxo_set = self.verify_block(&utxo_set, prev_block, block, self.median_time_stamp(Some(i)), false)?;
prev_block = block;
}
Ok(utxo_set)
}
pub fn blank() -> State {
State {
old_utxo_set: HashMap::new(),
utxo_set: HashMap::new(),
blocks: Vec::new(),
}
}
pub fn with_genesis_block() -> State {
let mut utxo_set = HashMap::new();
let block = Block::genesis_block();
utxo_set.insert(
Outpoint(block.txs[0].txid, 0),
block.txs[0].outputs[0].clone(),
);
State {
blocks: vec![block],
old_utxo_set: utxo_set.clone(),
utxo_set,
}
}
pub fn median_time_stamp(&self, idx: Option<usize>) -> u64 {
if self.blocks.len() == 0 { return 0; }
let end_idx = idx.unwrap_or(self.blocks.len()-1);
let start_idx = end_idx.saturating_sub(10); let mut timestamps: Vec<u64> = self.blocks[start_idx..=end_idx]
.iter()
.map(|b| b.time_stamp)
.collect();
timestamps.sort_unstable();
timestamps[timestamps.len() / 2]
}
pub fn verify_block(
&self,
old_utxo_set: &HashMap<Outpoint, TxOutput>,
prev_block: &Block,
block: &Block,
min_time_stamp: u64,
ignore_work: bool,
) -> Result<HashMap<Outpoint, TxOutput>, BlockErr> {
let mut hasher = Sha3_256::new();
let mut utxo_set = old_utxo_set.clone();
let mut input_total: u64 = 0;
let mut output_total: u64 = 0;
for tx in &block.txs{
for input in tx.inputs.iter() {
let Some(prev_out) = utxo_set.get(&input.prev_out) else {
return Err(BlockErr::FalseInput);
};
if !Block::verify_sig(
input.signature,
&TxPredicate::Pubkey(prev_out.recipient),
&input.prev_out,
) {
return Err(BlockErr::Sig(input.signature));
}
hasher.update(&prev_block.as_bytes_no_nonce());
let prev_hash = prev_block.get_hash();
if prev_hash != block.prev_hash {
return Err(BlockErr::PrevHash(block.prev_hash, prev_hash));
}
input_total += prev_out.amount;
}
for (i, output) in tx.outputs.iter().enumerate() {
output_total += output.amount;
utxo_set.insert(Outpoint(tx.txid, i as u16), output.clone());
}
for input in tx.inputs.iter() {
utxo_set.remove(&input.prev_out);
}
if output_total > input_total + Block::MINING_REWARD {
return Err(BlockErr::Overspend(input_total, output_total));
}
}
if !ignore_work && !block.verify_work() {
return Err(BlockErr::Nonce(block.nonce));
}
let max_time_stamp = prev_block.time_stamp + 2*60*60;
if block.time_stamp < min_time_stamp {
return Err(BlockErr::TimeStamp(min_time_stamp, max_time_stamp));
}
Ok(utxo_set)
}
pub fn add_block_if_valid(&mut self, block: Block) -> Result<(), BlockErr> {
let new_utxo_set = self.verify_block(
&self.old_utxo_set,
&self.blocks.last().unwrap(),
&block,
self.median_time_stamp(None),
false,
)?;
self.blocks.push(block);
self.utxo_set = new_utxo_set.clone();
self.old_utxo_set = new_utxo_set;
Ok(())
}
pub fn verify_all_and_update(&mut self) -> Result<(), BlockErr> {
self.utxo_set = self.verify_all_blocks()?;
self.old_utxo_set = self.utxo_set.clone();
Ok(())
}
pub fn get_balance(&self, key: PublicKey) -> u64 {
let mut balance: u64 = 0;
for outpoint in self.utxo_set.keys() {
let prev_out = self.utxo_set.get(outpoint).unwrap();
if prev_out.recipient == key {
balance += prev_out.amount;
}
}
balance
}
pub fn calc_total_work(&self) -> u64 {
let mut work = 0;
for block in &self.blocks {
work += u64::max_value() / block.get_work_amount();
}
work
}
}
impl Block {
pub const WORK_DIFFICULTY: u64 = u64::max_value() / 1_000_000;
pub const MINING_REWARD: u64 = 1_000;
pub const START_SUPPLY: u64 = 69 * 1_000_000;
pub const TOTAL_SUPPLY: u64 = 420 * 1_000_000;
pub fn new() -> Self {
Self {
version: 1,
time_stamp: 0,
prev_hash: BLANK_BLOCK_HASH,
nonce: 0,
txs: Vec::new(),
}
}
pub fn verify_sig(sig: Signature, predicate: &TxPredicate, prev_out: &Outpoint) -> bool {
let verifying_key = VerifyingKey::from(predicate.unwrap_key());
verifying_key.verify(&prev_out.as_bytes(), &sig).is_ok()
}
pub fn transact(
&mut self,
utxo_set: &mut HashMap<Outpoint, TxOutput>,
spender_priv: &SigningKey,
recipient_pub: &VerifyingKey,
amount: u64,
) -> Result<&Tx, ()> {
let spender_pub = PublicKey::from(VerifyingKey::from(spender_priv.clone()));
let recipient_pub = PublicKey::from(VerifyingKey::from(recipient_pub.clone()));
let mut new_tx = Tx::new();
let mut balance: u64 = 0;
let mut spendable: Vec<TxOutput> = Vec::new();
for outpoint in utxo_set.keys() {
let prev_out = utxo_set.get(outpoint).unwrap();
if prev_out.recipient == spender_pub {
new_tx.inputs.push(TxInput {
signature: spender_priv.sign(&outpoint.as_bytes()),
prev_out: outpoint.clone(),
});
spendable.push(prev_out.clone());
balance += prev_out.amount;
if balance >= amount {
break;
}
}
}
if amount > balance {
return Err(());
}
let split_last = balance > amount;
for output in spendable.iter().take(spendable.len() - 1) {
let mut new_output = output.clone();
new_output.spender = TxPredicate::Pubkey(spender_pub.clone());
new_output.recipient = recipient_pub.clone();
new_tx.outputs.push(new_output);
}
if split_last {
let recipient_out = TxOutput {
spender: TxPredicate::Pubkey(spender_pub),
amount: amount - (balance - spendable.last().unwrap().amount),
recipient: recipient_pub,
};
let remainder_out = TxOutput {
spender: TxPredicate::Pubkey(spender_pub),
amount: balance - amount,
recipient: spender_pub,
};
new_tx.outputs.push(recipient_out);
new_tx.outputs.push(remainder_out);
} else {
let output = TxOutput {
spender: TxPredicate::Pubkey(spender_pub),
amount: spendable.last().unwrap().amount,
recipient: recipient_pub,
};
new_tx.outputs.push(output);
}
new_tx.txid = new_tx.get_txid();
new_tx.signature = spender_priv.sign(&new_tx.txid);
for input in new_tx.inputs.iter() {
utxo_set
.remove(&input.prev_out)
.expect("Didn't find prev out");
}
for (i, output) in new_tx.outputs.iter().enumerate() {
utxo_set.insert(Outpoint(new_tx.txid, i as u16), (*output).clone());
}
self.txs.push(new_tx);
Ok(&self.txs.last().unwrap())
}
pub fn verify_work(&self) -> bool {
self.get_work_amount() <= Self::WORK_DIFFICULTY
}
pub fn get_work_amount(&self) -> u64 {
let mut hasher = Sha3_256::new();
let block_hash = self.get_hash();
hasher.update(block_hash);
hasher.update(self.nonce.to_le_bytes());
let work_hash = hasher.finalize();
let work_hash_64 = u64::from_le_bytes(work_hash[0..8].try_into().unwrap());
work_hash_64
}
pub fn mine(&self) -> u64 {
let mut rng = rand::thread_rng();
let mut gold: u64 = rng.gen_range(0..Self::WORK_DIFFICULTY);
let mut hasher = Sha3_256::new();
let block_hash = self.get_hash();
loop {
hasher.update(block_hash);
hasher.update(gold.to_le_bytes());
let work_hash = hasher.finalize_reset();
let work_hash_64 = u64::from_le_bytes(work_hash[0..8].try_into().unwrap());
if work_hash_64 <= Self::WORK_DIFFICULTY {
return gold;
}
gold += 1;
if gold > Self::WORK_DIFFICULTY {
gold = 0;
}
}
}
pub fn genesis_block() -> Self {
let mut utxo_set = HashMap::new();
let my_verifying_key: VerifyingKey = vk_from_encoded_str("04B0B5D59947A744C8ED5032F8B5EC77F56BFF09A724466397E8261AB\
E15BB1F1EC90871F5034A7B2BBF43F33C99225EF70C6F463B393973C55E85382F90F2935E").into();
let mut block = Block::new();
let public_key = PublicKey::from(my_verifying_key);
let root_output = TxOutput {
amount: Block::START_SUPPLY,
spender: TxPredicate::Pubkey(public_key),
recipient: public_key,
};
let my_signature = "fc839fd7d15231a66be4840c1fe916a8f3963367b69f099\
7c032839b5a1533da2859e00ab6e842a4bbce351ca435a281913c58638abe61\
5ff6887ed9a492b9a4";
let my_signature = Signature::from_slice(&(hex::decode(my_signature).unwrap())).unwrap();
let mut root_tx = Tx {
inputs: Vec::new(),
outputs: vec![root_output.clone()],
txid: EMPTY_TXID,
signature: my_signature,
};
root_tx.txid = root_tx.get_txid();
utxo_set.insert(Outpoint(root_tx.txid, 0), root_output.clone());
block.txs.push(root_tx);
block
}
}
impl Hash for Block {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.version.hash(state);
self.prev_hash.hash(state);
self.txs.hash(state);
}
}
impl Block {
pub fn as_bytes_no_nonce(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend_from_slice(&self.version.to_le_bytes());
bytes.extend_from_slice(&self.prev_hash);
bytes.extend_from_slice(&self.time_stamp.to_le_bytes());
for tx in &self.txs {
bytes.extend(tx.as_bytes());
}
bytes
}
pub fn get_hash(&self) -> BlockHash {
let mut hasher = Sha3_256::new();
hasher.update(&self.as_bytes_no_nonce());
let block_hash = hasher.finalize_reset();
block_hash[0..32].try_into().unwrap()
}
}