use std::collections::BTreeMap;
use std::io::{self, Cursor};
use blockdata::transaction::Transaction;
use consensus::{encode, Encodable, Decodable};
use util::psbt::map::Map;
use util::psbt::raw;
use util::psbt;
use util::psbt::Error;
#[derive(Clone, Debug, PartialEq)]
pub struct Global {
pub unsigned_tx: Transaction,
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
}
impl Global {
pub fn from_unsigned_tx(tx: Transaction) -> Result<Self, psbt::Error> {
for txin in &tx.input {
if !txin.script_sig.is_empty() {
return Err(Error::UnsignedTxHasScriptSigs);
}
if !txin.witness.is_empty() {
return Err(Error::UnsignedTxHasScriptWitnesses);
}
}
Ok(Global {
unsigned_tx: tx,
unknown: Default::default(),
})
}
}
impl Map for Global {
fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> {
let raw::Pair {
key: raw_key,
value: raw_value,
} = pair;
match raw_key.type_value {
0u8 => {
return Err(Error::DuplicateKey(raw_key).into());
}
_ => {
if self.unknown.contains_key(&raw_key) {
return Err(Error::DuplicateKey(raw_key).into());
} else {
self.unknown.insert(raw_key, raw_value);
}
}
}
Ok(())
}
fn get_pairs(&self) -> Result<Vec<raw::Pair>, encode::Error> {
let mut rv: Vec<raw::Pair> = Default::default();
rv.push(raw::Pair {
key: raw::Key {
type_value: 0u8,
key: vec![],
},
value: {
let mut ret = Vec::new();
self.unsigned_tx.version.consensus_encode(&mut ret)?;
self.unsigned_tx.input.consensus_encode(&mut ret)?;
self.unsigned_tx.output.consensus_encode(&mut ret)?;
self.unsigned_tx.lock_time.consensus_encode(&mut ret)?;
ret
},
});
for (key, value) in self.unknown.iter() {
rv.push(raw::Pair {
key: key.clone(),
value: value.clone(),
});
}
Ok(rv)
}
fn merge(&mut self, other: Self) -> Result<(), psbt::Error> {
if self.unsigned_tx != other.unsigned_tx {
return Err(psbt::Error::UnexpectedUnsignedTx {
expected: self.unsigned_tx.clone(),
actual: other.unsigned_tx,
});
}
self.unknown.extend(other.unknown);
Ok(())
}
}
impl_psbtmap_consensus_encoding!(Global);
impl Decodable for Global {
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
let mut tx: Option<Transaction> = None;
let mut unknowns: BTreeMap<raw::Key, Vec<u8>> = Default::default();
loop {
match raw::Pair::consensus_decode(&mut d) {
Ok(pair) => {
match pair.key.type_value {
0u8 => {
if pair.key.key.is_empty() {
if tx.is_none() {
let vlen: usize = pair.value.len();
let mut decoder = Cursor::new(pair.value);
tx = Some(Transaction {
version: Decodable::consensus_decode(&mut decoder)?,
input: Decodable::consensus_decode(&mut decoder)?,
output: Decodable::consensus_decode(&mut decoder)?,
lock_time: Decodable::consensus_decode(&mut decoder)?,
});
if decoder.position() != vlen as u64 {
return Err(encode::Error::ParseFailed("data not consumed entirely when explicitly deserializing"))
}
} else {
return Err(Error::DuplicateKey(pair.key).into())
}
} else {
return Err(Error::InvalidKey(pair.key).into())
}
}
_ => {
if unknowns.contains_key(&pair.key) {
return Err(Error::DuplicateKey(pair.key).into());
} else {
unknowns.insert(pair.key, pair.value);
}
}
}
}
Err(::consensus::encode::Error::Psbt(::util::psbt::Error::NoMorePairs)) => break,
Err(e) => return Err(e),
}
}
if let Some(tx) = tx {
let mut rv: Global = Global::from_unsigned_tx(tx)?;
rv.unknown = unknowns;
Ok(rv)
} else {
Err(Error::MustHaveUnsignedTx.into())
}
}
}