Skip to content

Commit

Permalink
fixup! SFT-UNKN: Add foundation-psbt crate.
Browse files Browse the repository at this point in the history
  • Loading branch information
jeandudey committed Nov 14, 2023
1 parent 9739411 commit 16b54d2
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 53 deletions.
11 changes: 4 additions & 7 deletions psbt/src/parser/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use nom::{
multi::fold_many0,
number::complete::le_u32,
sequence::terminated,
IResult, InputIter, InputLength, Slice, Compare, InputTake,
Compare, IResult, InputIter, InputLength, InputTake, Slice,
};

use foundation_bip32::{
Expand All @@ -36,9 +36,7 @@ where
+ InputIter<Item = u8>
+ Slice<core::ops::RangeFrom<usize>>,
F: FnMut(ExtendedPublicKey, KeySource<I>),
Error: ContextError<I>
+ ParseError<I>
+ FromExternalError<I, secp256k1::Error>
Error: ContextError<I> + ParseError<I> + FromExternalError<I, secp256k1::Error>,
{
let keypairs = fold_many0(
global_key_pair(),
Expand Down Expand Up @@ -93,10 +91,9 @@ where
+ InputLength
+ InputIter<Item = u8>
+ Slice<core::ops::RangeFrom<usize>>,
Error: ParseError<I>
+ FromExternalError<I, secp256k1::Error>
Error: ParseError<I> + FromExternalError<I, secp256k1::Error>,
{
let unsigned_tx = key_pair(0x00, eof, transaction());
let unsigned_tx = key_pair(0x00, eof, transaction);
let xpub = key_pair(0x01, extended_public_key, key_source);
let xpub = verify(xpub, |(k, v)| usize::from(k.depth) == v.path.len());
let tx_version = key_pair(0x02, eof, le_u32);
Expand Down
2 changes: 1 addition & 1 deletion psbt/src/parser/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ where
Error: ParseError<&'a [u8]>,
Error: FromExternalError<&'a [u8], secp256k1::Error>,
{
let non_witness_utxo = key_pair(0x00, eof, transaction()); // TODO
let non_witness_utxo = key_pair(0x00, eof, transaction);
let witness_utxo = key_pair(0x01, eof, witness_utxo);
let partial_sig = key_pair(0x02, public_key, ecdsa_signature);
let sighash_type = key_pair(0x03, eof, le_u32);
Expand Down
62 changes: 31 additions & 31 deletions psbt/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,42 +121,42 @@ mod tests {
use super::*;
use nom::error::VerboseError;

#[test]
#[cfg(feature = "std")]
fn invalid_18() {
let test_vectors = foundation_test_vectors::psbt::TestVectors::new();
let test_vector = &test_vectors.invalid[18];

println!("Test vector 18: {}", test_vector.description);
let mut psbt = psbt::<_, VerboseError<_>>(|_, _| ());
let (_, map) = psbt(&test_vector.data).unwrap();
panic!("{:?}", map.transaction);
}

//#[test]
//#[cfg(feature = "std")]
//fn parse_psbt_invalid_test_vectors() {
//fn invalid_18() {
// let test_vectors = foundation_test_vectors::psbt::TestVectors::new();
// let test_vector = &test_vectors.invalid[18];

// for (i, test_vector) in test_vectors.invalid.iter().enumerate() {
// println!("Test vector {i}: {}", test_vector.description);
// let mut psbt = psbt::<_, VerboseError<_>>(|_, _| ());
// psbt(&test_vector.data).unwrap_err();
// }
// println!("Test vector 18: {}", test_vector.description);
// let mut psbt = psbt::<_, VerboseError<_>>(|_, _| ());
// let (_, map) = psbt(&test_vector.data).unwrap();
// panic!("{:?}", map.transaction);
//}

//#[test]
//#[cfg(feature = "std")]
//fn parse_psbt_valid_test_vectors() {
// let test_vectors = foundation_test_vectors::psbt::TestVectors::new();
#[test]
#[cfg(feature = "std")]
fn parse_psbt_invalid_test_vectors() {
let test_vectors = foundation_test_vectors::psbt::TestVectors::new();

// for (i, test_vector) in test_vectors.valid.iter().enumerate() {
// println!("Test vector {i}: {}", test_vector.description);
// let mut psbt = psbt::<_, VerboseError<_>>(|_, _| ());
// match psbt(&test_vector.data) {
// Err(e) => panic!("{e}"),
// _ => (),
// }
// }
//}
for (i, test_vector) in test_vectors.invalid.iter().enumerate() {
println!("Test vector {i}: {}", test_vector.description);
let mut psbt = psbt::<_, VerboseError<_>>(|_, _| ());
psbt(&test_vector.data).unwrap_err();
}
}

#[test]
#[cfg(feature = "std")]
fn parse_psbt_valid_test_vectors() {
let test_vectors = foundation_test_vectors::psbt::TestVectors::new();

for (i, test_vector) in test_vectors.valid.iter().enumerate() {
println!("Test vector {i}: {}", test_vector.description);
let mut psbt = psbt::<_, VerboseError<_>>(|_, _| ());
match psbt(&test_vector.data) {
Err(e) => panic!("{e}"),
_ => (),
}
}
}
}
71 changes: 57 additions & 14 deletions psbt/src/parser/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@
// SPDX-License-Identifier: GPL-3.0-or-later

use nom::{
combinator::map,
branch::alt,
combinator::{map, verify},
error::{ErrorKind, ParseError},
multi::length_data,
number::complete::le_i64,
number::complete::{le_i32, le_u32},
number::complete::{le_i32, le_i64, le_u32, u8},
sequence::tuple,
Compare, Err, IResult, InputIter, InputLength, InputTake, Slice,
};

use crate::parser::compact_size::compact_size;
use crate::parser::hash::txid;
use crate::transaction::{Input, Inputs, Output, OutputPoint, Transaction};
use crate::transaction::{Input, Inputs, Output, OutputPoint, Outputs, Transaction};

/// Parses a raw bitcoin transaction.
pub fn transaction<I, E>() -> impl FnMut(I) -> IResult<I, Transaction<I>, E>
pub fn transaction<I, E>(i: I) -> IResult<I, Transaction<I>, E>
where
I: for<'a> Compare<&'a [u8]>
+ Clone
Expand All @@ -27,14 +27,18 @@ where
+ InputTake,
E: ParseError<I>,
{
let version = le_i32;

move |i: I| {
let (i, version) = version(i)?;
let (i, inputs) = inputs(i)?;

Ok((i, Transaction { version, inputs }))
}
map(
tuple((le_i32, inputs, outputs, le_u32)),
|(version, inputs, outputs, lock_time)| {
println!("outputs: {}", outputs.len());
Transaction {
version,
inputs,
outputs,
lock_time,
}
}
)(i)
}

pub fn inputs<I, E>(i: I) -> IResult<I, Inputs<I>, E>
Expand All @@ -58,7 +62,9 @@ where
Ok((next_i, _)) => {
i = next_i;
}
Err(Err::Error(e)) => return Err(Err::Error(E::append(i, ErrorKind::Count, e))),
Err(Err::Error(e)) => {
return Err(Err::Error(E::append(i, ErrorKind::Count, e)))
},
Err(e) => return Err(e),
}
}
Expand Down Expand Up @@ -98,6 +104,43 @@ where
parser(i)
}

pub fn outputs<I, E>(i: I) -> IResult<I, Outputs<I>, E>
where
I: for<'a> Compare<&'a [u8]>
+ Clone
+ InputTake
+ InputLength
+ InputIter<Item = u8>
+ Slice<core::ops::RangeFrom<usize>>,
E: ParseError<I>,
{
let (outputs_start, len) = compact_size(i)?;

let mut i = outputs_start.clone();
for _ in 0..len {
let i_ = i.clone();

match output(i_) {
Ok((next_i, _)) => {
i = next_i;
}
Err(Err::Error(e)) => {
println!("here2");
return Err(Err::Error(E::append(i, ErrorKind::Count, e)))
},
Err(e) => return Err(e),
}
}

Ok((
i,
Outputs {
len,
input: outputs_start,
},
))
}

/// Parses a raw bitcoin transaction output.
pub fn output<I, E>(i: I) -> IResult<I, Output<I>, E>
where
Expand Down
80 changes: 80 additions & 0 deletions psbt/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,32 @@

use crate::hash_types::Txid;

/// A raw segwit bitcoin transaction.
#[derive(Debug, Clone)]
pub struct SegwitTransaction<I> {
/// Version of the transaction.
pub version: i32,
/// The inputs of the transaction.
pub inputs: Inputs<I>,
/// The outputs of the transaction.
pub outputs: Outputs<I>,
/// The witness structure serialized as bytes.
pub script_witnesses: I,
/// The lock time.
pub lock_time: u32,
}

/// A raw bitcoin transaction.
#[derive(Debug, Clone)]
pub struct Transaction<I> {
/// Version of the transaction.
pub version: i32,
/// The inputs of the transaction.
pub inputs: Inputs<I>,
/// The outputs of the transaction.
pub outputs: Outputs<I>,
/// The lock time.
pub lock_time: u32,
}

/// A transaction input.
Expand Down Expand Up @@ -98,3 +117,64 @@ where
Some(input)
}
}

#[derive(Debug, Clone)]
pub struct Outputs<I> {
pub(crate) len: u64,
pub(crate) input: I,
}

impl<I> Outputs<I> {
pub fn len(&self) -> u64 {
self.len
}

/// Returns an iterator over the [`Output`]s.
pub fn iter(&self) -> OutputsIter<I>
where
I: Clone,
{
OutputsIter {
count: 0,
len: self.len,
input: self.input.clone(),
}
}
}

#[derive(Debug, Clone)]
pub struct OutputsIter<I> {
count: u64,
len: u64,
input: I,
}

impl<I> Iterator for OutputsIter<I>
where
I: for<'a> nom::Compare<&'a [u8]>
+ Clone
+ PartialEq
+ core::fmt::Debug
+ nom::InputTake
+ nom::InputIter<Item = u8>
+ nom::InputLength
+ nom::Slice<core::ops::RangeFrom<usize>>,
{
type Item = Output<I>;

fn next(&mut self) -> Option<Self::Item> {
use crate::parser::transaction;

if self.count >= self.len {
return None;
}

let (next_input, output) =
transaction::output::<I, nom::error::Error<I>>(self.input.clone())
.expect("inputs iterator data should be valid at this point");
self.input = next_input;
self.count += 1;

Some(output)
}
}

0 comments on commit 16b54d2

Please sign in to comment.