Skip to content
Permalink
Browse files

split utxo from transaction

  • Loading branch information...
vincenthz committed Mar 12, 2019
1 parent edab38b commit fe0591d0425fbbd7b2db5a2f67b8a85dbcf675fc
@@ -1,3 +1,5 @@
mod transfer;
mod utxo;

use crate::key::{
deserialize_signature, serialize_signature, Hash, SpendingPublicKey, SpendingSecretKey,
@@ -8,68 +10,9 @@ use chain_addr::Address;
use chain_core::property;
use chain_crypto::Verification;

pub type TransactionIndex = u8;

/// Unspent transaction pointer.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UtxoPointer {
/// the transaction identifier where the unspent output is
pub transaction_id: TransactionId,
/// the output index within the pointed transaction's outputs
pub output_index: TransactionIndex,
/// the value we expect to read from this output
///
/// This setting is added in order to protect undesired withdrawal
/// and to set the actual fee in the transaction.
pub value: Value,
}

impl UtxoPointer {
pub fn new(
transaction_id: TransactionId,
output_index: TransactionIndex,
value: Value,
) -> Self {
UtxoPointer {
transaction_id,
output_index,
value,
}
}
}

/// Structure that proofs that certain user agrees with
/// some data. This structure is used to sign `Transaction`
/// and get `SignedTransaction` out.
///
/// It's important that witness works with opaque structures
/// and may not know the contents of the internal transaction.
#[derive(Debug, Clone)]
pub struct Witness(SpendingSignature<TransactionId>);

impl Witness {
/// Creates new `Witness` value.
pub fn new(transaction_id: &TransactionId, secret_key: &SpendingSecretKey) -> Self {
Witness(SpendingSignature::generate(secret_key, transaction_id))
}

/// Verify the given `TransactionId` using the witness.
pub fn verifies(
&self,
public_key: &SpendingPublicKey,
transaction_id: &TransactionId,
) -> Verification {
self.0.verify(public_key, transaction_id)
}
}

/// Information how tokens are spent.
/// A value of tokens is sent to the address.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Output<Address>(pub Address, pub Value);

// FIXME: should this be a wrapper type?
pub type TransactionId = Hash;
// to remove..
pub use transfer::*;
pub use utxo::*;

/// Transaction, transaction maps old unspent tokens into the
/// set of the new addresses.
@@ -87,13 +30,6 @@ pub struct SignedTransaction<OutAddress> {
pub witnesses: Vec<Witness>,
}

impl PartialEq<Self> for Witness {
fn eq(&self, other: &Self) -> bool {
self.0.as_ref() == other.0.as_ref()
}
}
impl Eq for Witness {}

impl property::Serialize for Value {
type Error = std::io::Error;
fn serialize<W: std::io::Write>(&self, writer: W) -> Result<(), Self::Error> {
@@ -103,14 +39,6 @@ impl property::Serialize for Value {
}
}

impl property::Serialize for Witness {
type Error = std::io::Error;

fn serialize<W: std::io::Write>(&self, writer: W) -> Result<(), Self::Error> {
serialize_signature(&self.0, writer)
}
}

impl property::Serialize for Transaction<Address> {
type Error = std::io::Error;

@@ -158,14 +86,6 @@ impl property::Serialize for SignedTransaction<Address> {
}
}

impl property::Deserialize for Witness {
type Error = std::io::Error;

fn deserialize<R: std::io::BufRead>(reader: R) -> Result<Self, Self::Error> {
deserialize_signature(reader).map(Witness)
}
}

impl property::Deserialize for Transaction<Address> {
type Error = std::io::Error;
fn deserialize<R: std::io::BufRead>(reader: R) -> Result<Self, Self::Error> {
@@ -283,16 +203,6 @@ mod test {
use quickcheck::{Arbitrary, Gen, TestResult};

quickcheck! {

/// ```
/// \forall w=Witness(tx) => w.verifies(tx)
/// ```
fn prop_witness_verifies_own_tx(sk: TransactionSigningKey, tx:TransactionId) -> bool {
let pk = sk.0.to_public();
let witness = Witness::new(&tx, &sk.0);
witness.verifies(&pk, &tx) == Verification::Success
}

fn transaction_id_is_unique(tx1: Transaction<Address>, tx2: Transaction<Address>) -> bool {
chain_core::property::testing::transaction_id_is_unique(tx1, tx2)
}
@@ -305,28 +215,6 @@ mod test {
}
}

#[derive(Clone)]
struct TransactionSigningKey(SpendingSecretKey);

impl std::fmt::Debug for TransactionSigningKey {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "TransactionSigningKey(<secret-key>)")
}
}

impl Arbitrary for TransactionSigningKey {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
use rand_chacha::ChaChaRng;
use rand_core::SeedableRng;
let mut seed = [0; 32];
for byte in seed.iter_mut() {
*byte = Arbitrary::arbitrary(g);
}
let mut rng = ChaChaRng::from_seed(seed);
TransactionSigningKey(SpendingSecretKey::generate(&mut rng))
}
}

impl Arbitrary for Value {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
Value(Arbitrary::arbitrary(g))
@@ -343,14 +231,6 @@ mod test {
}
}

impl Arbitrary for Witness {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
let sk = TransactionSigningKey::arbitrary(g);
let txid = TransactionId::arbitrary(g);
Witness(SpendingSignature::generate(&sk.0, &txid))
}
}

impl Arbitrary for Output<Address> {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
Output(Arbitrary::arbitrary(g), Arbitrary::arbitrary(g))
@@ -384,4 +264,4 @@ mod test {
}
}
}
}
}
@@ -0,0 +1,13 @@
use crate::value::*;

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Input {
index_or_account: u8,
value: Value,
input_ptr: [u8; 32],
}

/// Information how tokens are spent.
/// A value of tokens is sent to the address.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Output<Address>(pub Address, pub Value);
@@ -0,0 +1,136 @@
use crate::key::{
deserialize_signature, serialize_signature, Hash, SpendingPublicKey, SpendingSecretKey,
SpendingSignature,
};
use crate::value::*;
use chain_core::property;
use chain_crypto::Verification;

// FIXME: should this be a wrapper type?
pub type TransactionId = Hash;

pub type TransactionIndex = u8;

/// Unspent transaction pointer.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UtxoPointer {
/// the transaction identifier where the unspent output is
pub transaction_id: TransactionId,
/// the output index within the pointed transaction's outputs
pub output_index: TransactionIndex,
/// the value we expect to read from this output
///
/// This setting is added in order to protect undesired withdrawal
/// and to set the actual fee in the transaction.
pub value: Value,
}

impl UtxoPointer {
pub fn new(
transaction_id: TransactionId,
output_index: TransactionIndex,
value: Value,
) -> Self {
UtxoPointer {
transaction_id,
output_index,
value,
}
}
}

/// Structure that proofs that certain user agrees with
/// some data. This structure is used to sign `Transaction`
/// and get `SignedTransaction` out.
///
/// It's important that witness works with opaque structures
/// and may not know the contents of the internal transaction.
#[derive(Debug, Clone)]
pub struct Witness(SpendingSignature<TransactionId>);

impl Witness {
/// Creates new `Witness` value.
pub fn new(transaction_id: &TransactionId, secret_key: &SpendingSecretKey) -> Self {
Witness(SpendingSignature::generate(secret_key, transaction_id))
}

/// Verify the given `TransactionId` using the witness.
pub fn verifies(
&self,
public_key: &SpendingPublicKey,
transaction_id: &TransactionId,
) -> Verification {
self.0.verify(public_key, transaction_id)
}
}

impl PartialEq<Self> for Witness {
fn eq(&self, other: &Self) -> bool {
self.0.as_ref() == other.0.as_ref()
}
}
impl Eq for Witness {}

impl property::Serialize for Witness {
type Error = std::io::Error;

fn serialize<W: std::io::Write>(&self, writer: W) -> Result<(), Self::Error> {
serialize_signature(&self.0, writer)
}
}

impl property::Deserialize for Witness {
type Error = std::io::Error;

fn deserialize<R: std::io::BufRead>(reader: R) -> Result<Self, Self::Error> {
deserialize_signature(reader).map(Witness)
}
}

#[cfg(test)]
pub mod test {
use super::*;
use quickcheck::{Arbitrary, Gen};

#[derive(Clone)]
pub struct TransactionSigningKey(pub SpendingSecretKey);

impl std::fmt::Debug for TransactionSigningKey {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "TransactionSigningKey(<secret-key>)")
}
}

impl Arbitrary for TransactionSigningKey {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
use rand_chacha::ChaChaRng;
use rand_core::SeedableRng;
let mut seed = [0; 32];
for byte in seed.iter_mut() {
*byte = Arbitrary::arbitrary(g);
}
let mut rng = ChaChaRng::from_seed(seed);
TransactionSigningKey(SpendingSecretKey::generate(&mut rng))
}
}

impl Arbitrary for Witness {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
let sk = TransactionSigningKey::arbitrary(g);
let txid = TransactionId::arbitrary(g);
Witness(SpendingSignature::generate(&sk.0, &txid))
}
}

quickcheck! {

/// ```
/// \forall w=Witness(tx) => w.verifies(tx)
/// ```
fn prop_witness_verifies_own_tx(sk: TransactionSigningKey, tx:TransactionId) -> bool {
let pk = sk.0.to_public();
let witness = Witness::new(&tx, &sk.0);
witness.verifies(&pk, &tx) == Verification::Success
}
}
}

0 comments on commit fe0591d

Please sign in to comment.
You can’t perform that action at this time.