Merge pull request #329 from stevenroose/overloaded-encode-error
Overloaded encode error
This commit is contained in:
commit
fef3390d78
|
@ -21,12 +21,13 @@
|
|||
|
||||
use std::default::Default;
|
||||
|
||||
use hashes::hex::FromHex;
|
||||
|
||||
use blockdata::opcodes;
|
||||
use blockdata::script;
|
||||
use blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn};
|
||||
use blockdata::block::{Block, BlockHeader};
|
||||
use network::constants::Network;
|
||||
use util::misc::hex_bytes;
|
||||
use util::uint::Uint256;
|
||||
|
||||
/// The maximum allowable sequence number
|
||||
|
@ -81,7 +82,7 @@ fn bitcoin_genesis_tx() -> Transaction {
|
|||
|
||||
// Outputs
|
||||
let out_script = script::Builder::new()
|
||||
.push_slice(&hex_bytes("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap())
|
||||
.push_slice(&Vec::<u8>::from_hex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap())
|
||||
.push_opcode(opcodes::all::OP_CHECKSIG)
|
||||
.into_script();
|
||||
ret.output.push(TxOut {
|
||||
|
|
|
@ -626,7 +626,6 @@ mod tests {
|
|||
use consensus::encode::serialize;
|
||||
use consensus::encode::deserialize;
|
||||
use util::hash::BitcoinHash;
|
||||
use util::misc::hex_bytes;
|
||||
|
||||
use hashes::{sha256d, Hash};
|
||||
use hashes::hex::FromHex;
|
||||
|
@ -666,7 +665,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_txin() {
|
||||
let txin: Result<TxIn, _> = deserialize(&hex_bytes("a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff").unwrap());
|
||||
let txin: Result<TxIn, _> = deserialize(&Vec::<u8>::from_hex("a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff").unwrap());
|
||||
assert!(txin.is_ok());
|
||||
}
|
||||
|
||||
|
@ -687,14 +686,14 @@ mod tests {
|
|||
|
||||
let genesis = constants::genesis_block(Network::Bitcoin);
|
||||
assert! (genesis.txdata[0].is_coin_base());
|
||||
let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
|
||||
let hex_tx = Vec::<u8>::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
|
||||
let tx: Transaction = deserialize(&hex_tx).unwrap();
|
||||
assert!(!tx.is_coin_base());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transaction() {
|
||||
let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
|
||||
let hex_tx = Vec::<u8>::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
|
||||
let tx: Result<Transaction, _> = deserialize(&hex_tx);
|
||||
assert!(tx.is_ok());
|
||||
let realtx = tx.unwrap();
|
||||
|
@ -717,7 +716,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn tx_no_input_deserialization() {
|
||||
let hex_tx = hex_bytes(
|
||||
let hex_tx = Vec::<u8>::from_hex(
|
||||
"010000000001000100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"
|
||||
).unwrap();
|
||||
let tx: Transaction = deserialize(&hex_tx).expect("deserialize tx");
|
||||
|
@ -731,7 +730,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_ntxid() {
|
||||
let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
|
||||
let hex_tx = Vec::<u8>::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
|
||||
let mut tx: Transaction = deserialize(&hex_tx).unwrap();
|
||||
|
||||
let old_ntxid = tx.ntxid();
|
||||
|
@ -747,7 +746,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_txid() {
|
||||
// segwit tx from Liquid integration tests, txid/hash from Core decoderawtransaction
|
||||
let hex_tx = hex_bytes(
|
||||
let hex_tx = Vec::<u8>::from_hex(
|
||||
"01000000000102ff34f95a672bb6a4f6ff4a7e90fa8c7b3be7e70ffc39bc99be3bda67942e836c00000000\
|
||||
23220020cde476664d3fa347b8d54ef3aee33dcb686a65ced2b5207cbf4ec5eda6b9b46e4f414d4c934ad8\
|
||||
1d330314e888888e3bd22c7dde8aac2ca9227b30d7c40093248af7812201000000232200200af6f6a071a6\
|
||||
|
@ -784,7 +783,7 @@ mod tests {
|
|||
assert_eq!(tx.get_weight(), 2718);
|
||||
|
||||
// non-segwit tx from my mempool
|
||||
let hex_tx = hex_bytes(
|
||||
let hex_tx = Vec::<u8>::from_hex(
|
||||
"01000000010c7196428403d8b0c88fcb3ee8d64f56f55c8973c9ab7dd106bb4f3527f5888d000000006a47\
|
||||
30440220503a696f55f2c00eee2ac5e65b17767cd88ed04866b5637d3c1d5d996a70656d02202c9aff698f\
|
||||
343abb6d176704beda63fcdec503133ea4f6a5216b7f925fa9910c0121024d89b5a13d6521388969209df2\
|
||||
|
@ -801,15 +800,15 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "serde")]
|
||||
fn test_txn_encode_decode() {
|
||||
let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
|
||||
let hex_tx = Vec::<u8>::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
|
||||
let tx: Transaction = deserialize(&hex_tx).unwrap();
|
||||
serde_round_trip!(tx);
|
||||
}
|
||||
|
||||
fn run_test_sighash(tx: &str, script: &str, input_index: usize, hash_type: i32, expected_result: &str) {
|
||||
let tx: Transaction = deserialize(&hex_bytes(tx).unwrap()[..]).unwrap();
|
||||
let script = Script::from(hex_bytes(script).unwrap());
|
||||
let mut raw_expected = hex_bytes(expected_result).unwrap();
|
||||
let tx: Transaction = deserialize(&Vec::<u8>::from_hex(tx).unwrap()[..]).unwrap();
|
||||
let script = Script::from(Vec::<u8>::from_hex(script).unwrap());
|
||||
let mut raw_expected = Vec::<u8>::from_hex(expected_result).unwrap();
|
||||
raw_expected.reverse();
|
||||
let expected_result = sha256d::Hash::from_slice(&raw_expected[..]).unwrap();
|
||||
|
||||
|
@ -822,7 +821,7 @@ mod tests {
|
|||
#[test]
|
||||
#[cfg(feature = "serde")]
|
||||
fn test_segwit_tx_decode() {
|
||||
let hex_tx = hex_bytes("010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let hex_tx = Vec::<u8>::from_hex("010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let tx: Transaction = deserialize(&hex_tx).unwrap();
|
||||
assert_eq!(tx.get_weight(), 780);
|
||||
serde_round_trip!(tx);
|
||||
|
|
|
@ -38,10 +38,8 @@ use std::io::{Cursor, Read, Write};
|
|||
use hashes::hex::ToHex;
|
||||
|
||||
use hashes::{sha256d, Hash as HashTrait};
|
||||
use secp256k1;
|
||||
|
||||
use util::endian;
|
||||
use util::base58;
|
||||
use util::psbt;
|
||||
|
||||
use blockdata::transaction::{TxOut, Transaction, TxIn};
|
||||
|
@ -53,12 +51,6 @@ use network::address::Address;
|
|||
pub enum Error {
|
||||
/// And I/O error
|
||||
Io(io::Error),
|
||||
/// Base58 encoding error
|
||||
Base58(base58::Error),
|
||||
/// Error from the `byteorder` crate
|
||||
ByteOrder(io::Error),
|
||||
/// secp-related error
|
||||
Secp256k1(secp256k1::Error),
|
||||
/// PSBT-related error
|
||||
Psbt(psbt::Error),
|
||||
/// Network magic was not expected
|
||||
|
@ -82,6 +74,8 @@ pub enum Error {
|
|||
/// The invalid checksum
|
||||
actual: [u8; 4],
|
||||
},
|
||||
/// VarInt was encoded in a non-minimal way
|
||||
NonMinimalVarInt,
|
||||
/// Network magic was unknown
|
||||
UnknownNetworkMagic(u32),
|
||||
/// Parsing error
|
||||
|
@ -90,26 +84,26 @@ pub enum Error {
|
|||
UnsupportedSegwitFlag(u8),
|
||||
/// Unrecognized network command
|
||||
UnrecognizedNetworkCommand(String),
|
||||
/// Unexpected hex digit
|
||||
UnexpectedHexDigit(char),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::Io(ref e) => fmt::Display::fmt(e, f),
|
||||
Error::Base58(ref e) => fmt::Display::fmt(e, f),
|
||||
Error::ByteOrder(ref e) => fmt::Display::fmt(e, f),
|
||||
Error::Secp256k1(ref e) => fmt::Display::fmt(e, f),
|
||||
Error::Psbt(ref e) => fmt::Display::fmt(e, f),
|
||||
Error::UnexpectedNetworkMagic { expected: ref e, actual: ref a } => write!(f, "{}: expected {}, actual {}", error::Error::description(self), e, a),
|
||||
Error::OversizedVectorAllocation { requested: ref r, max: ref m } => write!(f, "{}: requested {}, maximum {}", error::Error::description(self), r, m),
|
||||
Error::InvalidChecksum { expected: ref e, actual: ref a } => write!(f, "{}: expected {}, actual {}", error::Error::description(self), e[..].to_hex(), a[..].to_hex()),
|
||||
Error::UnknownNetworkMagic(ref m) => write!(f, "{}: {}", error::Error::description(self), m),
|
||||
Error::ParseFailed(ref e) => write!(f, "{}: {}", error::Error::description(self), e),
|
||||
Error::UnsupportedSegwitFlag(ref swflag) => write!(f, "{}: {}", error::Error::description(self), swflag),
|
||||
Error::UnrecognizedNetworkCommand(ref nwcmd) => write!(f, "{}: {}", error::Error::description(self), nwcmd),
|
||||
Error::UnexpectedHexDigit(ref d) => write!(f, "{}: {}", error::Error::description(self), d),
|
||||
Error::Io(ref e) => write!(f, "I/O error: {}", e),
|
||||
Error::Psbt(ref e) => write!(f, "PSBT error: {}", e),
|
||||
Error::UnexpectedNetworkMagic { expected: ref e, actual: ref a } => write!(f,
|
||||
"unexpected network magic: expected {}, actual {}", e, a),
|
||||
Error::OversizedVectorAllocation { requested: ref r, max: ref m } => write!(f,
|
||||
"allocation of oversized vector: requested {}, maximum {}", r, m),
|
||||
Error::InvalidChecksum { expected: ref e, actual: ref a } => write!(f,
|
||||
"invalid checksum: expected {}, actual {}", e.to_hex(), a.to_hex()),
|
||||
Error::NonMinimalVarInt => write!(f, "non-minimal varint"),
|
||||
Error::UnknownNetworkMagic(ref m) => write!(f, "unknown network magic: {}", m),
|
||||
Error::ParseFailed(ref e) => write!(f, "parse failed: {}", e),
|
||||
Error::UnsupportedSegwitFlag(ref swflag) => write!(f,
|
||||
"unsupported segwit version: {}", swflag),
|
||||
Error::UnrecognizedNetworkCommand(ref nwcmd) => write!(f,
|
||||
"unrecognized network command: {}", nwcmd),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,53 +112,24 @@ impl error::Error for Error {
|
|||
fn cause(&self) -> Option<&error::Error> {
|
||||
match *self {
|
||||
Error::Io(ref e) => Some(e),
|
||||
Error::Base58(ref e) => Some(e),
|
||||
Error::ByteOrder(ref e) => Some(e),
|
||||
Error::Secp256k1(ref e) => Some(e),
|
||||
Error::Psbt(ref e) => Some(e),
|
||||
Error::UnexpectedNetworkMagic { .. }
|
||||
| Error::OversizedVectorAllocation { .. }
|
||||
| Error::InvalidChecksum { .. }
|
||||
| Error::NonMinimalVarInt
|
||||
| Error::UnknownNetworkMagic(..)
|
||||
| Error::ParseFailed(..)
|
||||
| Error::UnsupportedSegwitFlag(..)
|
||||
| Error::UnrecognizedNetworkCommand(..)
|
||||
| Error::UnexpectedHexDigit(..) => None,
|
||||
| Error::UnrecognizedNetworkCommand(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::Io(ref e) => e.description(),
|
||||
Error::Base58(ref e) => e.description(),
|
||||
Error::ByteOrder(ref e) => e.description(),
|
||||
Error::Secp256k1(ref e) => e.description(),
|
||||
Error::Psbt(ref e) => e.description(),
|
||||
Error::UnexpectedNetworkMagic { .. } => "unexpected network magic",
|
||||
Error::OversizedVectorAllocation { .. } => "allocation of oversized vector requested",
|
||||
Error::InvalidChecksum { .. } => "invalid checksum",
|
||||
Error::UnknownNetworkMagic(..) => "unknown network magic",
|
||||
Error::ParseFailed(..) => "parse failed",
|
||||
Error::UnsupportedSegwitFlag(..) => "unsupported segwit version",
|
||||
Error::UnrecognizedNetworkCommand(..) => "unrecognized network command",
|
||||
Error::UnexpectedHexDigit(..) => "unexpected hex digit",
|
||||
}
|
||||
"Bitcoin encoding error"
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl From<base58::Error> for Error {
|
||||
fn from(e: base58::Error) -> Error {
|
||||
Error::Base58(e)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl From<secp256k1::Error> for Error {
|
||||
fn from(e: secp256k1::Error) -> Error {
|
||||
Error::Secp256k1(e)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl From<io::Error> for Error {
|
||||
|
@ -456,7 +421,7 @@ impl Decodable for VarInt {
|
|||
0xFF => {
|
||||
let x = ReadExt::read_u64(&mut d)?;
|
||||
if x < 0x100000000 {
|
||||
Err(self::Error::ParseFailed("non-minimal varint"))
|
||||
Err(self::Error::NonMinimalVarInt)
|
||||
} else {
|
||||
Ok(VarInt(x))
|
||||
}
|
||||
|
@ -464,7 +429,7 @@ impl Decodable for VarInt {
|
|||
0xFE => {
|
||||
let x = ReadExt::read_u32(&mut d)?;
|
||||
if x < 0x10000 {
|
||||
Err(self::Error::ParseFailed("non-minimal varint"))
|
||||
Err(self::Error::NonMinimalVarInt)
|
||||
} else {
|
||||
Ok(VarInt(x as u64))
|
||||
}
|
||||
|
@ -472,7 +437,7 @@ impl Decodable for VarInt {
|
|||
0xFD => {
|
||||
let x = ReadExt::read_u16(&mut d)?;
|
||||
if x < 0xFD {
|
||||
Err(self::Error::ParseFailed("non-minimal varint"))
|
||||
Err(self::Error::NonMinimalVarInt)
|
||||
} else {
|
||||
Ok(VarInt(x as u64))
|
||||
}
|
||||
|
@ -822,27 +787,27 @@ mod tests {
|
|||
#[test]
|
||||
fn deserialize_nonminimal_vec() {
|
||||
match deserialize::<Vec<u8>>(&[0xfd, 0x00, 0x00]) {
|
||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||
Err(Error::NonMinimalVarInt) => {},
|
||||
x => panic!(x)
|
||||
}
|
||||
match deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]) {
|
||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||
Err(Error::NonMinimalVarInt) => {},
|
||||
x => panic!(x)
|
||||
}
|
||||
match deserialize::<Vec<u8>>(&[0xfe, 0xff, 0x00, 0x00, 0x00]) {
|
||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||
Err(Error::NonMinimalVarInt) => {},
|
||||
x => panic!(x)
|
||||
}
|
||||
match deserialize::<Vec<u8>>(&[0xfe, 0xff, 0xff, 0x00, 0x00]) {
|
||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||
Err(Error::NonMinimalVarInt) => {},
|
||||
x => panic!(x)
|
||||
}
|
||||
match deserialize::<Vec<u8>>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) {
|
||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||
Err(Error::NonMinimalVarInt) => {},
|
||||
x => panic!(x)
|
||||
}
|
||||
match deserialize::<Vec<u8>>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00]) {
|
||||
Err(Error::ParseFailed("non-minimal varint")) => {},
|
||||
Err(Error::NonMinimalVarInt) => {},
|
||||
x => panic!(x)
|
||||
}
|
||||
|
||||
|
|
|
@ -105,9 +105,9 @@ mod tests {
|
|||
use blockdata::transaction::Transaction;
|
||||
use consensus::encode::deserialize;
|
||||
use network::constants::Network;
|
||||
use util::misc::hex_bytes;
|
||||
use util::address::Address;
|
||||
use util::key::PublicKey;
|
||||
use hashes::hex::FromHex;
|
||||
use hex;
|
||||
|
||||
use super::*;
|
||||
|
@ -122,7 +122,7 @@ mod tests {
|
|||
#[test]
|
||||
fn bip143_p2wpkh() {
|
||||
let tx = deserialize::<Transaction>(
|
||||
&hex_bytes(
|
||||
&Vec::<u8>::from_hex(
|
||||
"0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f000000\
|
||||
0000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a01000000\
|
||||
00ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093\
|
||||
|
@ -160,7 +160,7 @@ mod tests {
|
|||
#[test]
|
||||
fn bip143_p2wpkh_nested_in_p2sh() {
|
||||
let tx = deserialize::<Transaction>(
|
||||
&hex_bytes(
|
||||
&Vec::<u8>::from_hex(
|
||||
"0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477010000\
|
||||
0000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac00\
|
||||
08af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000",
|
||||
|
@ -197,7 +197,7 @@ mod tests {
|
|||
#[test]
|
||||
fn bip143_p2wsh_nested_in_p2sh() {
|
||||
let tx = deserialize::<Transaction>(
|
||||
&hex_bytes(
|
||||
&Vec::<u8>::from_hex(
|
||||
"010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000\
|
||||
ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f\
|
||||
05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000").unwrap()[..],
|
||||
|
|
|
@ -17,14 +17,59 @@
|
|||
//!
|
||||
|
||||
use std::fmt::{self, Write};
|
||||
use std::{io, ops};
|
||||
use std::{io, ops, error};
|
||||
use std::str::FromStr;
|
||||
|
||||
use secp256k1::{self, Secp256k1};
|
||||
use consensus::encode;
|
||||
use network::constants::Network;
|
||||
use util::base58;
|
||||
|
||||
/// A key-related error.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Base58 encoding error
|
||||
Base58(base58::Error),
|
||||
/// secp256k1-related error
|
||||
Secp256k1(secp256k1::Error),
|
||||
}
|
||||
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::Base58(ref e) => write!(f, "base58 error: {}", e),
|
||||
Error::Secp256k1(ref e) => write!(f, "secp256k1 error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match *self {
|
||||
Error::Base58(ref e) => Some(e),
|
||||
Error::Secp256k1(ref e) => Some(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
"Bitcoin key error"
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl From<base58::Error> for Error {
|
||||
fn from(e: base58::Error) -> Error {
|
||||
Error::Base58(e)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl From<secp256k1::Error> for Error {
|
||||
fn from(e: secp256k1::Error) -> Error {
|
||||
Error::Secp256k1(e)
|
||||
}
|
||||
}
|
||||
|
||||
/// A Bitcoin ECDSA public key
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct PublicKey {
|
||||
|
@ -53,7 +98,7 @@ impl PublicKey {
|
|||
}
|
||||
|
||||
/// Deserialize a public key from a slice
|
||||
pub fn from_slice(data: &[u8]) -> Result<PublicKey, encode::Error> {
|
||||
pub fn from_slice(data: &[u8]) -> Result<PublicKey, Error> {
|
||||
let compressed: bool = match data.len() {
|
||||
33 => true,
|
||||
65 => false,
|
||||
|
@ -88,8 +133,8 @@ impl fmt::Display for PublicKey {
|
|||
}
|
||||
|
||||
impl FromStr for PublicKey {
|
||||
type Err = encode::Error;
|
||||
fn from_str(s: &str) -> Result<PublicKey, encode::Error> {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<PublicKey, Error> {
|
||||
let key = secp256k1::PublicKey::from_str(s)?;
|
||||
Ok(PublicKey {
|
||||
key: key,
|
||||
|
@ -149,19 +194,19 @@ impl PrivateKey {
|
|||
}
|
||||
|
||||
/// Parse WIF encoded private key.
|
||||
pub fn from_wif(wif: &str) -> Result<PrivateKey, encode::Error> {
|
||||
pub fn from_wif(wif: &str) -> Result<PrivateKey, Error> {
|
||||
let data = base58::from_check(wif)?;
|
||||
|
||||
let compressed = match data.len() {
|
||||
33 => false,
|
||||
34 => true,
|
||||
_ => { return Err(encode::Error::Base58(base58::Error::InvalidLength(data.len()))); }
|
||||
_ => { return Err(Error::Base58(base58::Error::InvalidLength(data.len()))); }
|
||||
};
|
||||
|
||||
let network = match data[0] {
|
||||
128 => Network::Bitcoin,
|
||||
239 => Network::Testnet,
|
||||
x => { return Err(encode::Error::Base58(base58::Error::InvalidVersion(vec![x]))); }
|
||||
x => { return Err(Error::Base58(base58::Error::InvalidVersion(vec![x]))); }
|
||||
};
|
||||
|
||||
Ok(PrivateKey {
|
||||
|
@ -185,8 +230,8 @@ impl fmt::Debug for PrivateKey {
|
|||
}
|
||||
|
||||
impl FromStr for PrivateKey {
|
||||
type Err = encode::Error;
|
||||
fn from_str(s: &str) -> Result<PrivateKey, encode::Error> {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<PrivateKey, Error> {
|
||||
PrivateKey::from_wif(s)
|
||||
}
|
||||
}
|
||||
|
|
112
src/util/misc.rs
112
src/util/misc.rs
|
@ -22,59 +22,6 @@ use consensus::encode;
|
|||
|
||||
static MSG_SIGN_PREFIX: &'static [u8] = b"\x18Bitcoin Signed Message:\n";
|
||||
|
||||
/// Helper function to convert hex nibble characters to their respective value
|
||||
#[inline]
|
||||
fn hex_val(c: u8) -> Result<u8, encode::Error> {
|
||||
let res = match c {
|
||||
b'0' ... b'9' => c - '0' as u8,
|
||||
b'a' ... b'f' => c - 'a' as u8 + 10,
|
||||
b'A' ... b'F' => c - 'A' as u8 + 10,
|
||||
_ => return Err(encode::Error::UnexpectedHexDigit(c as char)),
|
||||
};
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Convert a hexadecimal-encoded string to its corresponding bytes
|
||||
pub fn hex_bytes(data: &str) -> Result<Vec<u8>, encode::Error> {
|
||||
// This code is optimized to be as fast as possible without using unsafe or platform specific
|
||||
// features. If you want to refactor it please make sure you don't introduce performance
|
||||
// regressions (run the benchmark with `cargo bench --features unstable`).
|
||||
|
||||
// If the hex string has an uneven length fail early
|
||||
if data.len() % 2 != 0 {
|
||||
return Err(encode::Error::ParseFailed("hexstring of odd length"));
|
||||
}
|
||||
|
||||
// Preallocate the uninitialized memory for the byte array
|
||||
let mut res = Vec::with_capacity(data.len() / 2);
|
||||
|
||||
let mut hex_it = data.bytes();
|
||||
loop {
|
||||
// Get most significant nibble of current byte or end iteration
|
||||
let msn = match hex_it.next() {
|
||||
None => break,
|
||||
Some(x) => x,
|
||||
};
|
||||
|
||||
// Get least significant nibble of current byte
|
||||
let lsn = match hex_it.next() {
|
||||
None => unreachable!("len % 2 == 0"),
|
||||
Some(x) => x,
|
||||
};
|
||||
|
||||
// Convert bytes representing characters to their represented value and combine lsn and msn.
|
||||
// The and_then and map are crucial for performance, in comparison to using ? and then
|
||||
// using the results of that for the calculation it's nearly twice as fast. Using bit
|
||||
// shifting and or instead of multiply and add on the other hand doesn't show a significant
|
||||
// increase in performance.
|
||||
match hex_val(msn).and_then(|msn_val| hex_val(lsn).map(|lsn_val| msn_val * 16 + lsn_val)) {
|
||||
Ok(x) => res.push(x),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Search for `needle` in the vector `haystack` and remove every
|
||||
/// instance of it, returning the number of instances removed.
|
||||
/// Loops through the vector opcode by opcode, skipping pushed data.
|
||||
|
@ -122,61 +69,10 @@ pub fn signed_msg_hash(msg: &str) -> sha256d::Hash {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature="unstable"))]
|
||||
mod benches {
|
||||
use secp256k1::rand::{Rng, thread_rng};
|
||||
use secp256k1::rand::distributions::Standard;
|
||||
use super::hex_bytes;
|
||||
use test::Bencher;
|
||||
|
||||
fn join<I: Iterator<Item=IT>, IT: AsRef<str>>(iter: I, expected_len: usize) -> String {
|
||||
let mut res = String::with_capacity(expected_len);
|
||||
for s in iter {
|
||||
res.push_str(s.as_ref());
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn bench_from_hex(b: &mut Bencher, data_size: usize) {
|
||||
let data_bytes = thread_rng()
|
||||
.sample_iter(&Standard)
|
||||
.take(data_size)
|
||||
.collect::<Vec<u8>>();
|
||||
let data = join(data_bytes.iter().map(|x| format!("{:02x}", x)), data_size * 2);
|
||||
|
||||
assert_eq!(hex_bytes(&data).unwrap(), data_bytes);
|
||||
|
||||
b.iter(|| {
|
||||
hex_bytes(&data).unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_hex_16_bytes(b: &mut Bencher) {
|
||||
bench_from_hex(b, 16);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_hex_64_bytes(b: &mut Bencher) {
|
||||
bench_from_hex(b, 64);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_hex_256_bytes(b: &mut Bencher) {
|
||||
bench_from_hex(b, 256);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn from_hex_4m_bytes(b: &mut Bencher) {
|
||||
bench_from_hex(b, 1024 * 1024 * 4);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hashes::hex::ToHex;
|
||||
use super::script_find_and_remove;
|
||||
use super::hex_bytes;
|
||||
use super::signed_msg_hash;
|
||||
|
||||
#[test]
|
||||
|
@ -218,14 +114,6 @@ mod tests {
|
|||
assert_eq!(s, vec![33, 3, 132, 121, 160, 250, 153, 140, 211, 82, 89, 162, 239, 10, 122, 92, 104, 102, 44, 20, 116, 248, 140, 203, 109, 8, 167, 103, 123, 190, 199, 242, 32, 65, 173, 33, 3, 132, 121, 160, 250, 153, 140, 211, 82, 89, 162, 239, 10, 122, 92, 104, 102, 44, 20, 116, 248, 140, 203, 109, 8, 167, 103, 123, 190, 199, 242, 32, 65, 173, 81]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hex_bytes() {
|
||||
assert_eq!(&hex_bytes("abcd").unwrap(), &[171u8, 205]);
|
||||
assert!(hex_bytes("abcde").is_err());
|
||||
assert!(hex_bytes("aBcDeF").is_ok());
|
||||
assert!(hex_bytes("aBcD4eFL").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signed_msg_hash() {
|
||||
let hash = signed_msg_hash("test");
|
||||
|
|
|
@ -53,7 +53,7 @@ pub struct PartiallySignedTransaction {
|
|||
impl PartiallySignedTransaction {
|
||||
/// Create a PartiallySignedTransaction from an unsigned transaction, error
|
||||
/// if not unsigned
|
||||
pub fn from_unsigned_tx(tx: Transaction) -> Result<Self, encode::Error> {
|
||||
pub fn from_unsigned_tx(tx: Transaction) -> Result<Self, self::Error> {
|
||||
Ok(PartiallySignedTransaction {
|
||||
inputs: vec![Default::default(); tx.input.len()],
|
||||
outputs: vec![Default::default(); tx.output.len()],
|
||||
|
|
Loading…
Reference in New Issue