Skip to content
This repository has been archived by the owner on May 6, 2020. It is now read-only.

Docs and tests #11

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ version = "0.1.0"
authors = ["Alekos Filini <[email protected]>"]

[dependencies]
bitcoin = "~0.14.2"
bitcoin = "~0.14.2"

[dev-dependencies]
hex = "~0.3.2"
rand = "~0.4.6"
2 changes: 2 additions & 0 deletions src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ use traits::NeededTx;
#[derive(Clone, Debug)]
pub struct Contract {
pub title: String,
/// Will be spent in the contract transaction
pub issuance_utxo: OutPoint,
/// Will own the issued assets
pub initial_owner_utxo: OutPoint,
pub network: Network,
pub total_supply: u32,
Expand Down
9 changes: 8 additions & 1 deletion src/output_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@ use bitcoin::network::serialize::SimpleDecoder;
use bitcoin::network::serialize::SimpleEncoder;
use bitcoin::util::hash::Sha256dHash;

/// RGB output
#[derive(Clone, Debug)]
pub struct OutputEntry(Sha256dHash, u32, Option<u32>); // asset_id, amount -> vout
pub struct OutputEntry(
/// Asset id
Sha256dHash,
/// Asset amount
u32,
/// Vout (optional): the index of this RGB output as bitcoin transaction output (?)
Option<u32>);

impl OutputEntry {
pub fn new(asset_id: Sha256dHash, amount: u32, vout: Option<u32>) -> OutputEntry {
Expand Down
8 changes: 7 additions & 1 deletion src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ use traits::NeededTx;

#[derive(Clone, Debug)]
pub struct Proof {
/// The spent assets are held by these txos
pub bind_to: Vec<OutPoint>,
/// All the proofs of inputs txs
pub input: Vec<Proof>,
/// RGB outputs. If output entry.vout is None then use the index in this vector
pub output: Vec<OutputEntry>,
pub contract: Option<Box<Contract>>, // Only needed for root proofs
/// Issuance contract, only needed for root proofs
pub contract: Option<Box<Contract>>,
}

impl Proof {
Expand All @@ -42,6 +46,8 @@ impl Proof {
return self.contract.is_some() && self.bind_to.len() == 1 && self.bind_to[0] == self.contract.as_ref().unwrap().initial_owner_utxo;
}

/// Look for test_proof OutputEntries spent in the first elements of self.bind_to,
/// if test_proof is a first level parent of the tx associated to this proof (?)
fn get_entries_for_us(&self, test_proof: &Proof, needed_txs: &HashMap<&NeededTx, Transaction>) -> Vec<OutputEntry> {
// We know that [0] is equal to all others (checked in verify)
let committing_tx_this = needed_txs.get(&NeededTx::WhichSpendsOutPoint(self.bind_to[0])).unwrap();
Expand Down
64 changes: 64 additions & 0 deletions src/tests/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use bitcoin::util::hash::Sha256dHash;
use output_entry::OutputEntry;
use contract::Contract;
use bitcoin::OutPoint;
use bitcoin::network::constants::Network;
use bitcoin::Transaction;
use traits::{Verify, NeededTx};
use std::collections::HashMap;
use bitcoin::TxOut;

#[test]
fn output_entry() {
let asset_id = Sha256dHash::from_hex(&hex::encode([0x42; 32])).unwrap();
let output_entry = OutputEntry::new(asset_id, 100, None);
assert_eq!(output_entry.get_asset_id(), asset_id);
assert_eq!(output_entry.get_amount(), 100);
assert_eq!(output_entry.get_vout(), None);
let output_entry = OutputEntry::new(Sha256dHash::default(), 100, Some(7));
match output_entry.get_vout() {
Some(x) => assert_eq!(x, 7),
_ => panic!()
}
}

#[test]
fn verify() {
let issuance_utxo = OutPoint {txid: Sha256dHash::default(), vout: 1000};
let contract = Contract {
title: String::from("title"),
issuance_utxo,
initial_owner_utxo: issuance_utxo,
network: Network::Testnet,
total_supply: 12,
};
let void_tx = Transaction {version: 1, lock_time: 0, input: vec![], output: vec![]};

let needed_txs = contract.get_needed_txs();
assert_eq!(needed_txs.len(), 1);
// let NeededTx::WhichSpendsOutPoint(outpoint) = needed_txs[0];
let outpoint = match needed_txs[0] {
NeededTx::WhichSpendsOutPoint(o) => o,
_ => panic!(),
};
assert_eq!(outpoint, contract.issuance_utxo);

let mut txs: HashMap<&NeededTx, Transaction> = [
(&needed_txs[0], void_tx)
].iter().cloned().collect();

assert_eq!(contract.verify(&txs), false);

let commitment_out: TxOut = TxOut {
script_pubkey: contract.get_expected_script(),
value: 7
};
println!("test: expected {}", contract.get_expected_script());
let issuance_tx = Transaction {version: 1, lock_time: 0, input: vec![], output: vec![commitment_out]};

txs = [
(&needed_txs[0], issuance_tx)
].iter().cloned().collect();

assert_eq!(contract.verify(&txs), true);
}
10 changes: 4 additions & 6 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// TODO!

#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
extern crate hex;
extern crate rand;
mod contract;
mod proof;
82 changes: 82 additions & 0 deletions src/tests/proof.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use bitcoin::OutPoint;
use output_entry::OutputEntry;
use bitcoin::util::hash::Sha256dHash;
use proof::Proof;
use contract::Contract;
use traits::Verify;
use bitcoin::network::constants::Network;
use tests::rand::Rng;


fn make_txid() -> Sha256dHash {
let random_bytes = rand::thread_rng().gen::<[u8; 32]>();
Sha256dHash::from_hex(&hex::encode(random_bytes)).unwrap()
}

fn mock_contract(initial_owner_txid: Sha256dHash) -> Contract {
Contract {
title: "Fake contract".to_string(),
issuance_utxo: OutPoint::default(),
initial_owner_utxo: OutPoint {txid: initial_owner_txid, vout: 42},
network: Network::Testnet,
total_supply: 7
}
}

fn mock_root_proof(contract: Option<Box<Contract>>, initial_owner_txid: Sha256dHash) -> Proof {
Proof {
bind_to: vec![OutPoint {txid: initial_owner_txid, vout: 42}],
input: Vec::new(),
output: Vec::new(),
contract
}
}

fn mock_proof(bind_to: Vec<OutPoint>, input: Vec<Proof>, output: Vec<OutputEntry>) -> Proof {
Proof {bind_to, input, output, contract: None}
}


#[test]
fn get_needed_txs() {
let initial_owner_txid = make_txid();
let contract = mock_contract(initial_owner_txid);
let root = mock_root_proof(Some(Box::new(contract)), initial_owner_txid);

let needed_txs = root.get_needed_txs();
// 1 tx: contract
// 1 tx: root proof
assert_eq!(needed_txs.len(), 2);

// Transaction #2
let root_outpoint_0 = OutPoint {
txid: make_txid(),
vout: 42
};
let proof_1 = mock_proof(vec![root_outpoint_0], vec![root.clone()], vec![]);
assert_eq!(proof_1.get_needed_txs().len(), 3);

// Transaction #3
let root_outpoint_1 = OutPoint {
txid: root_outpoint_0.txid,
vout: 43
};
let proof_2 = mock_proof(vec![root_outpoint_1], vec![root.clone()], vec![]);
assert_eq!(proof_2.get_needed_txs().len(), 3);

// Transaction #4
let outpoint_tx2 = OutPoint {
txid: make_txid(),
vout: 42
};
let outpoint_tx3 = OutPoint {
txid: make_txid(),
vout: 42
};
let bind_to_3 = vec![outpoint_tx2, outpoint_tx3];
let input_3 = vec![proof_1, proof_2];
let proof_3 = mock_proof(bind_to_3, input_3, vec![]);
// The proof_3.get_needed_txs() vector has 2 duplicated entries
// TODO: check this behavior
assert_eq!(proof_3.get_needed_txs().len(), 8);
}