#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
#![deny(missing_docs)]
#![deny(unsafe_code)]
#![doc = include_str!("../README.md")]
extern crate alloc;
pub mod take;
mod types;
pub use crate::types::*;
pub use bitcoin;
pub use bitcoin::io;
use alloc::vec::Vec;
use bitcoin::consensus::encode::Error;
use bitcoin::consensus::{Decodable, Encodable};
pub fn from_vec<T: Decodable>(v: &mut Vec<u8>) -> Result<T, Error> {
let mut cursor = bitcoin::io::Cursor::new(v);
let res = Decodable::consensus_decode(&mut cursor)?;
let position = cursor.position() as usize;
let v = cursor.into_inner();
v.drain(..position);
Ok(res)
}
pub fn to_vec<T: Encodable>(t: &T) -> Result<Vec<u8>, Error> {
let mut v = Vec::new();
t.consensus_encode(&mut v)?;
Ok(v)
}
#[cfg(test)]
mod tests {
use super::*;
use crate as serde_bolt;
use bitcoin::consensus::{Decodable, Encodable};
use bitcoin::hashes::Hash;
use bitcoin::{BlockHash, OutPoint, ScriptBuf, Sequence, TxIn, Txid};
use bitcoin_consensus_derive::{Decodable, Encodable};
use hex::{decode, encode};
use crate::types::{IgnoredLargeOctets, LargeOctets, Octets, WireString};
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct Thing {
a: u8,
b: u8,
c: u8,
}
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct Test {
x: bool,
a: u32,
b: u8,
c: Option<u16>,
d: Option<u16>,
e: Octets,
f: Thing,
}
#[test]
fn test_u32() {
let test = 0x12345678u32;
let result = to_vec(&test).unwrap();
assert_eq!("78563412", encode(&result));
let decoded: u32 = from_vec(&mut result.clone()).unwrap();
assert_eq!(test, decoded);
}
#[test]
fn test_good() {
let test = Test {
x: true,
a: 65538,
b: 160,
c: None,
d: Some(3),
e: Octets(vec![0x33, 0x44]),
f: Thing {
a: 0x55,
b: 0x66,
c: 0x77,
},
};
let result = to_vec(&test).unwrap();
assert_eq!("0100010002a00001000300023344556677", encode(&result));
let mut result = to_vec(&test).unwrap();
assert_eq!("0100010002a00001000300023344556677", encode(&result));
let decoded: Test = from_vec(&mut result).unwrap();
assert_eq!(test, decoded);
assert!(result.is_empty());
}
#[test]
fn test_bad() {
match from_vec::<Test>(&mut decode("0100010002a000010003000233445566").unwrap().clone()) {
Ok(_) => {
panic!("should fail")
}
Err(Error::Io(_)) => {}
Err(e) => {
panic!("wrong error: {:?}", e)
}
}
}
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct TestWithLargeBytes {
a: LargeOctets,
}
#[test]
fn test_ser_large_octets() {
let test = TestWithLargeBytes {
a: LargeOctets(vec![0x11, 0x22]),
};
let result = to_vec(&test).unwrap();
assert_eq!("000000021122", encode(&result));
let decoded: TestWithLargeBytes = from_vec(&mut result.clone()).unwrap();
assert_eq!(test, decoded);
}
#[test]
fn test_bitcoin_compat() {
let test = BlockHash::all_zeros();
let result = to_vec(&test).unwrap();
let decoded: BlockHash = from_vec(&mut result.clone()).unwrap();
assert_eq!(test, decoded);
}
#[test]
fn test_slice() {
let test = [0x11, 0x22, 0x33, 0x44];
let result = to_vec(&test).unwrap();
assert_eq!("11223344", encode(&result));
let decoded: [u8; 4] = from_vec(&mut result.clone()).unwrap();
assert_eq!(test, decoded);
}
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct TestWithWireString {
a: WireString,
b: Octets,
}
#[test]
fn test_ser_wire_string_and_octets() {
let test = TestWithWireString {
a: WireString("hello".as_bytes().to_vec()),
b: vec![0x11u8].into(),
};
let result = to_vec(&test).unwrap();
assert_eq!("68656c6c6f00000111", encode(&result));
let decoded: TestWithWireString = from_vec(&mut result.clone()).unwrap();
assert_eq!(test, decoded);
}
#[derive(Encodable, Decodable, PartialEq)]
struct TestWithIgnored {
a: u8,
b: IgnoredLargeOctets,
c: u8,
}
#[test]
fn test_ser_ignored_large_octets() {
let test = TestWithIgnored {
a: 1,
b: IgnoredLargeOctets(vec![0x11, 0x22, 0x33]),
c: 2,
};
let result = to_vec(&test).unwrap();
assert_eq!("010000000311223302", encode(&result));
let decoded: TestWithIgnored = from_vec(&mut result.clone()).unwrap();
assert!(decoded.b.0.is_empty());
assert_eq!(decoded.a, 1);
assert_eq!(decoded.c, 2);
}
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct X {
c: Option<ScriptBuf>,
a: u32,
b: TxIn,
d: Option<u16>,
}
#[test]
fn test_x() {
let x = X {
a: 1,
b: TxIn {
previous_output: OutPoint {
txid: Txid::from_slice(&[0x23; 32]).unwrap(),
vout: 0,
},
script_sig: ScriptBuf::default(),
sequence: Sequence::MAX,
witness: Default::default(),
},
c: Some(ScriptBuf::new_op_return(&[0x11, 0x22])),
d: Some(3),
};
let mut buf = Vec::new();
x.consensus_encode(&mut buf).unwrap();
let x2: X = Decodable::consensus_decode(&mut buf.as_slice()).unwrap();
assert_eq!(x, x2);
}
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct Tuple(u8, [u8; 2]);
#[test]
fn test_tuple() {
let test = Tuple(1, [2, 3]);
let result = to_vec(&test).unwrap();
assert_eq!("010203", encode(&result));
let decoded: Tuple = from_vec(&mut result.clone()).unwrap();
assert_eq!(test, decoded);
}
#[derive(Encodable, Decodable, Debug)]
struct TestWithArray {
a: [u8; 111],
b: ArrayBE<u16>,
}
#[test]
fn test_ser_array() {
let test = TestWithArray {
a: [0x12; 111],
b: ArrayBE(vec![0x1234; 2]),
};
let result = to_vec(&test).unwrap();
let expected: String =
std::iter::repeat("12").take(111).collect::<String>() + "000212341234";
assert_eq!(expected, encode(&result));
let decoded: TestWithArray = from_vec(&mut result.clone()).unwrap();
assert_eq!(test.a, decoded.a);
assert_eq!(test.b.0, decoded.b.0);
}
#[test]
fn test_noncontiguous() {
let bytes: &[u8] = &[0, 0, 0, 4, 1, 2, 3, 4];
let mut slice = bytes;
let mut buf = NonContiguousOctets::<4>::consensus_decode(&mut slice).unwrap();
let mut data = NonContiguousOctets::<4>::new();
data.write(&[1, 2, 3, 4]);
assert_eq!(buf.to_vec(), data.to_vec());
let mut wire = [0u8; 8];
let mut slice = &mut wire[..];
assert_eq!(buf.consensus_encode(&mut slice).unwrap(), 8);
assert_eq!(wire, bytes);
assert_eq!(buf.len(), 4);
let mut dest = [0; 4];
assert_eq!(buf.read(&mut dest), 4);
assert_eq!(dest, [1, 2, 3, 4]);
assert_eq!(buf.len(), 0);
assert!(buf.is_empty());
let bytes: &[u8] = &[0, 0, 0, 8, 1, 2, 3, 4, 5, 6, 7, 8];
let mut slice = bytes;
let mut buf = NonContiguousOctets::<8>::consensus_decode(&mut slice).unwrap();
let mut data = NonContiguousOctets::<8>::new();
data.write(&[1, 2, 3, 4, 5, 6, 7, 8]);
assert_eq!(buf.to_vec(), data.to_vec());
let mut wire = [0u8; 12];
let mut slice = &mut wire[..];
assert_eq!(buf.consensus_encode(&mut slice).unwrap(), 12);
assert_eq!(wire, bytes);
assert_eq!(buf.len(), 8);
let mut dest = [0; 8];
assert_eq!(buf.read(&mut dest), 8);
assert_eq!(dest, [1, 2, 3, 4, 5, 6, 7, 8]);
assert_eq!(buf.len(), 0);
assert!(buf.is_empty());
let bytes: &[u8] = &[0, 0, 0, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut slice = bytes;
let mut buf = NonContiguousOctets::<10>::consensus_decode(&mut slice).unwrap();
let mut data = NonContiguousOctets::<10>::new();
data.write(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
assert_eq!(buf.to_vec(), data.to_vec());
let mut wire = [0u8; 14];
let mut slice = &mut wire[..];
assert_eq!(buf.consensus_encode(&mut slice).unwrap(), 14);
assert_eq!(wire, bytes);
assert_eq!(buf.len(), 10);
let mut dest = [0; 10];
assert_eq!(buf.read(&mut dest), 10);
assert_eq!(dest, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
assert_eq!(buf.len(), 0);
assert!(buf.is_empty());
let mut bytes: &[u8] = &[0, 0, 0, 10, 1, 2, 3, 4, 5];
let ret = NonContiguousOctets::<10>::consensus_decode(&mut bytes);
let Err(Error::Io(error)) = ret else {
panic!("Expected an error")
};
assert_eq!(io::ErrorKind::UnexpectedEof, error.kind());
let bytes: &[u8] = &[0, 0, 0, 5, 1, 2, 3, 4, 5, 1, 2, 3];
let mut slice = bytes;
let buf = NonContiguousOctets::<4>::consensus_decode(&mut slice).unwrap();
assert_eq!(buf.to_vec(), &[1, 2, 3, 4, 5]);
assert_eq!(slice, &[1, 2, 3]);
}
#[test]
fn test_cursor() {
use crate::io::{Read, Write};
let bytes: &[u8] = &[1, 2, 3, 4];
let mut buf = NonContiguousOctets::<4>::new();
assert_eq!(buf.write(&bytes).unwrap(), 4);
let mut cursor = NonContiguousOctetsCursor::new(&buf);
let mut dest = [0u8; 4];
assert_eq!(cursor.read(&mut dest).unwrap(), 4);
assert_eq!(dest, bytes);
let bytes: &[u8] = &[1, 2, 3, 4, 5];
let mut buf = NonContiguousOctets::<4>::new();
assert_eq!(buf.write(&bytes).unwrap(), 5);
let mut cursor = NonContiguousOctetsCursor::new(&buf);
let mut dest = [0u8; 5];
assert_eq!(cursor.read(&mut dest).unwrap(), 5);
assert_eq!(dest, bytes);
let bytes: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let mut buf = NonContiguousOctets::<4>::new();
assert_eq!(buf.write(&bytes).unwrap(), 12);
let mut cursor = NonContiguousOctetsCursor::new(&buf);
let mut dest = [0u8; 12];
assert_eq!(cursor.read(&mut dest).unwrap(), 12);
assert_eq!(dest, bytes);
let bytes: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
let mut buf = NonContiguousOctets::<4>::new();
assert_eq!(buf.write(&bytes).unwrap(), 13);
let mut cursor = NonContiguousOctetsCursor::new(&buf);
let mut dest = [0u8; 13];
assert_eq!(cursor.read(&mut dest).unwrap(), 13);
assert_eq!(dest, bytes);
let bytes: &[u8] = &[1, 2, 3, 4];
let mut buf = NonContiguousOctets::<4>::new();
assert_eq!(buf.write(&bytes).unwrap(), 4);
let mut cursor = NonContiguousOctetsCursor::new(&buf);
let mut dest = [0u8; 13];
assert_eq!(cursor.read(&mut dest).unwrap(), 4);
assert_eq!(&dest[..], [bytes, &[0u8; 9]].concat());
let bytes: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
let mut buf = NonContiguousOctets::<4>::new();
assert_eq!(buf.write(&bytes).unwrap(), 13);
let mut cursor = NonContiguousOctetsCursor::new(&buf);
let mut dest = [0u8; 4];
assert_eq!(cursor.read(&mut dest).unwrap(), 4);
assert_eq!(dest, bytes[..4]);
let buf = NonContiguousOctets::<4>::new();
let mut cursor = NonContiguousOctetsCursor::new(&buf);
let want = [7u8; 4];
let mut got = want;
assert_eq!(cursor.read(&mut got).unwrap(), 0);
assert_eq!(got, want);
}
}