2016-12-13 02:27:45 -08:00
|
|
|
use super::bytes::Bytes;
|
|
|
|
use super::hash::H256;
|
|
|
|
use super::script::ScriptType;
|
2019-06-28 14:27:46 -07:00
|
|
|
use serde::ser::SerializeMap;
|
|
|
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
|
|
use std::fmt;
|
|
|
|
use v1::types;
|
Prefix workspace crates with zebra- (#70)
* Update license and author metadata in workspace crates.
- ensure that the license field is set to GPL-3 for all GPL-3 licensed crates;
- ensure that the author field is set to "Zcash Foundation", responsible for maintenance;
- preserve the original authorship info in AUTHORS.md for human-readable history.
Updating the author field ensures that all of the machine systems that read
crate metadata list the ZF organization, not any single individual, as the
maintainer of the crate.
* Prefix all internal crate names with zebra-.
This does not move the directories containing these crates to also have zebra-
prefixes (for instance, zebra-chain instead of chain). I think that this would
be preferable, but because it's a `git mv`, it will be simple to do later and
leaving it out of this change makes it easier to see the renaming of all of the
internal modules.
* Remove git dependency from eth-secp256k1
* Avoid an error seemingly related to Deref coercions.
This code caused an overflow while evaluating type constraints. As best as I
can determine, the cause of the problem was something like so: the Rust
implementation of the Bitcoin-specific hash function used in the Bloom filter
doesn't operate on byte slices, but only on a `&mut R where R: Read`, so to
hash a byte slice, you need to create a mutable copy of the input slice which
can be consumed as a `Read` implementation by the hash function; the previous
version of this code created a slice copy using a `Deref` coercion instead of
`.clone()`, and when a tokio update added new trait impls, the type inference
for the `Deref` coercion exploded (somehow -- I'm not sure about the last
part?).
This commit avoids the problem by manually cloning the input slice.
2019-07-02 12:07:06 -07:00
|
|
|
use zebra_keys::Address;
|
2016-12-13 02:27:45 -08:00
|
|
|
|
|
|
|
/// Hex-encoded transaction
|
|
|
|
pub type RawTransaction = Bytes;
|
|
|
|
|
|
|
|
/// Transaction input
|
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
|
|
|
pub struct TransactionInput {
|
2019-06-28 14:27:46 -07:00
|
|
|
/// Previous transaction id
|
|
|
|
pub txid: H256,
|
|
|
|
/// Previous transaction output index
|
|
|
|
pub vout: u32,
|
|
|
|
/// Sequence number
|
|
|
|
pub sequence: Option<u32>,
|
2016-12-13 02:27:45 -08:00
|
|
|
}
|
|
|
|
|
2016-12-14 07:00:22 -08:00
|
|
|
/// Transaction output of form "address": amount
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub struct TransactionOutputWithAddress {
|
2019-06-28 14:27:46 -07:00
|
|
|
/// Receiver' address
|
|
|
|
pub address: Address,
|
|
|
|
/// Amount in BTC
|
|
|
|
pub amount: f64,
|
2016-12-13 02:27:45 -08:00
|
|
|
}
|
|
|
|
|
2019-02-02 14:35:00 -08:00
|
|
|
/// Transaction output of form "data": serialized(output script data)
|
2016-12-14 07:00:22 -08:00
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub struct TransactionOutputWithScriptData {
|
2019-06-28 14:27:46 -07:00
|
|
|
/// Serialized script data
|
|
|
|
pub script_data: Bytes,
|
2016-12-14 07:00:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Transaction output
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum TransactionOutput {
|
2019-06-28 14:27:46 -07:00
|
|
|
/// Of form address: amount
|
|
|
|
Address(TransactionOutputWithAddress),
|
|
|
|
/// Of form data: script_data_bytes
|
|
|
|
ScriptData(TransactionOutputWithScriptData),
|
2016-12-14 07:00:22 -08:00
|
|
|
}
|
|
|
|
|
2016-12-13 04:36:35 -08:00
|
|
|
/// Transaction outputs, which serializes/deserializes as KV-map
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub struct TransactionOutputs {
|
2019-06-28 14:27:46 -07:00
|
|
|
/// Transaction outputs
|
|
|
|
pub outputs: Vec<TransactionOutput>,
|
2016-12-13 04:36:35 -08:00
|
|
|
}
|
|
|
|
|
2016-12-13 02:27:45 -08:00
|
|
|
/// Transaction input script
|
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
|
|
|
pub struct TransactionInputScript {
|
2019-06-28 14:27:46 -07:00
|
|
|
/// Script code
|
|
|
|
pub asm: String,
|
|
|
|
/// Script hex
|
|
|
|
pub hex: Bytes,
|
2016-12-13 02:27:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Transaction output script
|
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
|
|
|
pub struct TransactionOutputScript {
|
2019-06-28 14:27:46 -07:00
|
|
|
/// Script code
|
|
|
|
pub asm: String,
|
|
|
|
/// Script hex
|
|
|
|
pub hex: Bytes,
|
|
|
|
/// Number of required signatures
|
|
|
|
#[serde(rename = "reqSigs")]
|
|
|
|
pub req_sigs: u32,
|
|
|
|
/// Type of script
|
|
|
|
#[serde(rename = "type")]
|
|
|
|
pub script_type: ScriptType,
|
|
|
|
/// Array of bitcoin addresses
|
|
|
|
#[serde(with = "types::address::vec")]
|
|
|
|
pub addresses: Vec<Address>,
|
2016-12-13 02:27:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Signed transaction input
|
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
|
|
|
pub struct SignedTransactionInput {
|
2019-06-28 14:27:46 -07:00
|
|
|
/// Previous transaction id
|
|
|
|
pub txid: H256,
|
|
|
|
/// Previous transaction output index
|
|
|
|
pub vout: u32,
|
|
|
|
/// Input script
|
|
|
|
pub script_sig: TransactionInputScript,
|
|
|
|
/// Sequence number
|
|
|
|
pub sequence: u32,
|
2016-12-13 02:27:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Signed transaction output
|
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
|
|
|
pub struct SignedTransactionOutput {
|
2019-06-28 14:27:46 -07:00
|
|
|
/// Output value in BTC
|
|
|
|
pub value: f64,
|
|
|
|
/// Output index
|
|
|
|
pub n: u32,
|
|
|
|
/// Output script
|
|
|
|
#[serde(rename = "scriptPubKey")]
|
|
|
|
pub script: TransactionOutputScript,
|
2016-12-13 02:27:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Transaction
|
|
|
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
|
|
|
pub struct Transaction {
|
2019-06-28 14:27:46 -07:00
|
|
|
/// Raw transaction
|
|
|
|
pub hex: RawTransaction,
|
|
|
|
/// The transaction id (same as provided)
|
|
|
|
pub txid: H256,
|
|
|
|
/// The transaction hash
|
|
|
|
pub hash: H256,
|
|
|
|
/// The serialized transaction size
|
|
|
|
pub size: usize,
|
|
|
|
/// The version
|
|
|
|
pub version: i32,
|
|
|
|
/// The lock time
|
|
|
|
pub locktime: i32,
|
|
|
|
/// Transaction inputs
|
|
|
|
pub vin: Vec<SignedTransactionInput>,
|
|
|
|
/// Transaction outputs
|
|
|
|
pub vout: Vec<SignedTransactionOutput>,
|
|
|
|
/// Hash of the block this transaction is included in
|
|
|
|
pub blockhash: H256,
|
|
|
|
/// Number of confirmations of this transaction
|
|
|
|
pub confirmations: u32,
|
|
|
|
/// The transaction time in seconds since epoch (Jan 1 1970 GMT)
|
|
|
|
pub time: u32,
|
|
|
|
/// The block time in seconds since epoch (Jan 1 1970 GMT)
|
|
|
|
pub blocktime: u32,
|
2016-12-13 02:27:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return value of `getrawtransaction` method
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum GetRawTransactionResponse {
|
2019-06-28 14:27:46 -07:00
|
|
|
/// Return value when asking for raw transaction
|
|
|
|
Raw(RawTransaction),
|
|
|
|
/// Return value when asking for verbose transaction
|
|
|
|
Verbose(Transaction),
|
2016-12-13 02:27:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Serialize for GetRawTransactionResponse {
|
2019-06-28 14:27:46 -07:00
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
|
|
|
match *self {
|
|
|
|
GetRawTransactionResponse::Raw(ref raw_transaction) => {
|
|
|
|
raw_transaction.serialize(serializer)
|
|
|
|
}
|
|
|
|
GetRawTransactionResponse::Verbose(ref verbose_transaction) => {
|
|
|
|
verbose_transaction.serialize(serializer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-13 02:27:45 -08:00
|
|
|
}
|
|
|
|
|
2016-12-13 04:36:35 -08:00
|
|
|
impl TransactionOutputs {
|
2019-06-28 14:27:46 -07:00
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.outputs.len()
|
|
|
|
}
|
2016-12-13 04:36:35 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Serialize for TransactionOutputs {
|
2019-06-28 14:27:46 -07:00
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
|
|
|
let mut state = serializer.serialize_map(Some(self.len()))?;
|
|
|
|
for output in &self.outputs {
|
|
|
|
match output {
|
|
|
|
&TransactionOutput::Address(ref address_output) => {
|
|
|
|
state.serialize_entry(
|
|
|
|
&address_output.address.to_string(),
|
|
|
|
&address_output.amount,
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
&TransactionOutput::ScriptData(ref script_output) => {
|
|
|
|
state.serialize_entry("data", &script_output.script_data)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
state.end()
|
|
|
|
}
|
2016-12-13 04:36:35 -08:00
|
|
|
}
|
|
|
|
|
2017-05-05 05:36:54 -07:00
|
|
|
impl<'a> Deserialize<'a> for TransactionOutputs {
|
2019-06-28 14:27:46 -07:00
|
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
|
|
where
|
|
|
|
D: Deserializer<'a>,
|
|
|
|
{
|
|
|
|
use serde::de::{MapAccess, Visitor};
|
|
|
|
|
|
|
|
struct TransactionOutputsVisitor;
|
|
|
|
|
|
|
|
impl<'b> Visitor<'b> for TransactionOutputsVisitor {
|
|
|
|
type Value = TransactionOutputs;
|
|
|
|
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
formatter.write_str("a transaction output object")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_map<V>(self, mut visitor: V) -> Result<TransactionOutputs, V::Error>
|
|
|
|
where
|
|
|
|
V: MapAccess<'b>,
|
|
|
|
{
|
|
|
|
let mut outputs: Vec<TransactionOutput> =
|
|
|
|
Vec::with_capacity(visitor.size_hint().unwrap_or(0));
|
|
|
|
|
|
|
|
while let Some(key) = try!(visitor.next_key::<String>()) {
|
|
|
|
if &key == "data" {
|
|
|
|
let value: Bytes = try!(visitor.next_value());
|
|
|
|
outputs.push(TransactionOutput::ScriptData(
|
|
|
|
TransactionOutputWithScriptData { script_data: value },
|
|
|
|
));
|
|
|
|
} else {
|
|
|
|
let address = types::address::AddressVisitor::default().visit_str(&key)?;
|
|
|
|
let amount: f64 = try!(visitor.next_value());
|
|
|
|
outputs.push(TransactionOutput::Address(TransactionOutputWithAddress {
|
|
|
|
address: address,
|
|
|
|
amount: amount,
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(TransactionOutputs { outputs: outputs })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
deserializer.deserialize_any(TransactionOutputsVisitor)
|
|
|
|
}
|
2016-12-13 04:36:35 -08:00
|
|
|
}
|
|
|
|
|
2016-12-13 02:27:45 -08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2019-06-28 14:27:46 -07:00
|
|
|
use super::super::bytes::Bytes;
|
|
|
|
use super::super::hash::H256;
|
|
|
|
use super::super::script::ScriptType;
|
|
|
|
use super::*;
|
|
|
|
use serde_json;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn transaction_input_serialize() {
|
|
|
|
let txinput = TransactionInput {
|
|
|
|
txid: H256::from(7),
|
|
|
|
vout: 33,
|
|
|
|
sequence: Some(88),
|
|
|
|
};
|
|
|
|
assert_eq!(serde_json::to_string(&txinput).unwrap(), r#"{"txid":"0700000000000000000000000000000000000000000000000000000000000000","vout":33,"sequence":88}"#);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn transaction_input_deserialize() {
|
|
|
|
let txinput = TransactionInput {
|
|
|
|
txid: H256::from(7),
|
|
|
|
vout: 33,
|
|
|
|
sequence: Some(88),
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(
|
2016-12-13 02:27:45 -08:00
|
|
|
serde_json::from_str::<TransactionInput>(r#"{"txid":"0700000000000000000000000000000000000000000000000000000000000000","vout":33,"sequence":88}"#).unwrap(),
|
|
|
|
txinput);
|
2019-06-28 14:27:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn transaction_outputs_serialize() {
|
|
|
|
let txout = TransactionOutputs {
|
|
|
|
outputs: vec![
|
|
|
|
TransactionOutput::Address(TransactionOutputWithAddress {
|
|
|
|
address: "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi".into(),
|
|
|
|
amount: 123.45,
|
|
|
|
}),
|
|
|
|
TransactionOutput::Address(TransactionOutputWithAddress {
|
|
|
|
address: "t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543".into(),
|
|
|
|
amount: 67.89,
|
|
|
|
}),
|
|
|
|
TransactionOutput::ScriptData(TransactionOutputWithScriptData {
|
|
|
|
script_data: Bytes::new(vec![1, 2, 3, 4]),
|
|
|
|
}),
|
|
|
|
TransactionOutput::ScriptData(TransactionOutputWithScriptData {
|
|
|
|
script_data: Bytes::new(vec![5, 6, 7, 8]),
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
};
|
|
|
|
assert_eq!(serde_json::to_string(&txout).unwrap(), r#"{"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi":123.45,"t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543":67.89,"data":"01020304","data":"05060708"}"#);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn transaction_outputs_deserialize() {
|
|
|
|
let txout = TransactionOutputs {
|
|
|
|
outputs: vec![
|
|
|
|
TransactionOutput::Address(TransactionOutputWithAddress {
|
|
|
|
address: "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi".into(),
|
|
|
|
amount: 123.45,
|
|
|
|
}),
|
|
|
|
TransactionOutput::Address(TransactionOutputWithAddress {
|
|
|
|
address: "t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543".into(),
|
|
|
|
amount: 67.89,
|
|
|
|
}),
|
|
|
|
TransactionOutput::ScriptData(TransactionOutputWithScriptData {
|
|
|
|
script_data: Bytes::new(vec![1, 2, 3, 4]),
|
|
|
|
}),
|
|
|
|
TransactionOutput::ScriptData(TransactionOutputWithScriptData {
|
|
|
|
script_data: Bytes::new(vec![5, 6, 7, 8]),
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
};
|
|
|
|
assert_eq!(
|
2018-12-24 23:38:07 -08:00
|
|
|
serde_json::from_str::<TransactionOutputs>(r#"{"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi":123.45,"t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543":67.89,"data":"01020304","data":"05060708"}"#).unwrap(),
|
2016-12-13 04:36:35 -08:00
|
|
|
txout);
|
2019-06-28 14:27:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn transaction_input_script_serialize() {
|
|
|
|
let txin = TransactionInputScript {
|
|
|
|
asm: "Hello, world!!!".to_owned(),
|
|
|
|
hex: Bytes::new(vec![1, 2, 3, 4]),
|
|
|
|
};
|
|
|
|
assert_eq!(
|
|
|
|
serde_json::to_string(&txin).unwrap(),
|
|
|
|
r#"{"asm":"Hello, world!!!","hex":"01020304"}"#
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn transaction_input_script_deserialize() {
|
|
|
|
let txin = TransactionInputScript {
|
|
|
|
asm: "Hello, world!!!".to_owned(),
|
|
|
|
hex: Bytes::new(vec![1, 2, 3, 4]),
|
|
|
|
};
|
|
|
|
assert_eq!(
|
|
|
|
serde_json::from_str::<TransactionInputScript>(
|
|
|
|
r#"{"asm":"Hello, world!!!","hex":"01020304"}"#
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
txin
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn transaction_output_script_serialize() {
|
|
|
|
let txout = TransactionOutputScript {
|
|
|
|
asm: "Hello, world!!!".to_owned(),
|
|
|
|
hex: Bytes::new(vec![1, 2, 3, 4]),
|
|
|
|
req_sigs: 777,
|
|
|
|
script_type: ScriptType::Multisig,
|
|
|
|
addresses: vec![
|
|
|
|
"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi".into(),
|
|
|
|
"t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543".into(),
|
|
|
|
],
|
|
|
|
};
|
|
|
|
assert_eq!(serde_json::to_string(&txout).unwrap(), r#"{"asm":"Hello, world!!!","hex":"01020304","reqSigs":777,"type":"multisig","addresses":["t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi","t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543"]}"#);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn transaction_output_script_deserialize() {
|
|
|
|
let txout = TransactionOutputScript {
|
|
|
|
asm: "Hello, world!!!".to_owned(),
|
|
|
|
hex: Bytes::new(vec![1, 2, 3, 4]),
|
|
|
|
req_sigs: 777,
|
|
|
|
script_type: ScriptType::Multisig,
|
|
|
|
addresses: vec![
|
|
|
|
"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi".into(),
|
|
|
|
"t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543".into(),
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(
|
2018-12-24 23:38:07 -08:00
|
|
|
serde_json::from_str::<TransactionOutputScript>(r#"{"asm":"Hello, world!!!","hex":"01020304","reqSigs":777,"type":"multisig","addresses":["t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi","t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543"]}"#).unwrap(),
|
2016-12-13 02:27:45 -08:00
|
|
|
txout);
|
2019-06-28 14:27:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn signed_transaction_input_serialize() {
|
|
|
|
let txin = SignedTransactionInput {
|
|
|
|
txid: H256::from(77),
|
|
|
|
vout: 13,
|
|
|
|
script_sig: TransactionInputScript {
|
|
|
|
asm: "Hello, world!!!".to_owned(),
|
|
|
|
hex: Bytes::new(vec![1, 2, 3, 4]),
|
|
|
|
},
|
|
|
|
sequence: 123,
|
|
|
|
};
|
|
|
|
assert_eq!(serde_json::to_string(&txin).unwrap(), r#"{"txid":"4d00000000000000000000000000000000000000000000000000000000000000","vout":13,"script_sig":{"asm":"Hello, world!!!","hex":"01020304"},"sequence":123}"#);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn signed_transaction_input_deserialize() {
|
|
|
|
let txin = SignedTransactionInput {
|
|
|
|
txid: H256::from(77),
|
|
|
|
vout: 13,
|
|
|
|
script_sig: TransactionInputScript {
|
|
|
|
asm: "Hello, world!!!".to_owned(),
|
|
|
|
hex: Bytes::new(vec![1, 2, 3, 4]),
|
|
|
|
},
|
|
|
|
sequence: 123,
|
|
|
|
};
|
|
|
|
assert_eq!(
|
2018-11-14 00:46:02 -08:00
|
|
|
serde_json::from_str::<SignedTransactionInput>(r#"{"txid":"4d00000000000000000000000000000000000000000000000000000000000000","vout":13,"script_sig":{"asm":"Hello, world!!!","hex":"01020304"},"sequence":123}"#).unwrap(),
|
2016-12-13 02:27:45 -08:00
|
|
|
txin);
|
2019-06-28 14:27:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn signed_transaction_output_serialize() {
|
|
|
|
let txout = SignedTransactionOutput {
|
|
|
|
value: 777.79,
|
|
|
|
n: 12,
|
|
|
|
script: TransactionOutputScript {
|
|
|
|
asm: "Hello, world!!!".to_owned(),
|
|
|
|
hex: Bytes::new(vec![1, 2, 3, 4]),
|
|
|
|
req_sigs: 777,
|
|
|
|
script_type: ScriptType::Multisig,
|
|
|
|
addresses: vec![
|
|
|
|
"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi".into(),
|
|
|
|
"t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543".into(),
|
|
|
|
],
|
|
|
|
},
|
|
|
|
};
|
|
|
|
assert_eq!(serde_json::to_string(&txout).unwrap(), r#"{"value":777.79,"n":12,"scriptPubKey":{"asm":"Hello, world!!!","hex":"01020304","reqSigs":777,"type":"multisig","addresses":["t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi","t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543"]}}"#);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn signed_transaction_output_deserialize() {
|
|
|
|
let txout = SignedTransactionOutput {
|
|
|
|
value: 777.79,
|
|
|
|
n: 12,
|
|
|
|
script: TransactionOutputScript {
|
|
|
|
asm: "Hello, world!!!".to_owned(),
|
|
|
|
hex: Bytes::new(vec![1, 2, 3, 4]),
|
|
|
|
req_sigs: 777,
|
|
|
|
script_type: ScriptType::Multisig,
|
|
|
|
addresses: vec![
|
|
|
|
"t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi".into(),
|
|
|
|
"t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543".into(),
|
|
|
|
],
|
|
|
|
},
|
|
|
|
};
|
|
|
|
assert_eq!(
|
2018-12-24 23:38:07 -08:00
|
|
|
serde_json::from_str::<SignedTransactionOutput>(r#"{"value":777.79,"n":12,"scriptPubKey":{"asm":"Hello, world!!!","hex":"01020304","reqSigs":777,"type":"multisig","addresses":["t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi","t2N9PH9Wk9xjqYg9iin1Ua3aekJqfAtE543"]}}"#).unwrap(),
|
2016-12-13 02:27:45 -08:00
|
|
|
txout);
|
2019-06-28 14:27:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn transaction_serialize() {
|
|
|
|
let tx = Transaction {
|
|
|
|
hex: "DEADBEEF".into(),
|
|
|
|
txid: H256::from(4),
|
|
|
|
hash: H256::from(5),
|
|
|
|
size: 33,
|
|
|
|
version: 55,
|
|
|
|
locktime: 66,
|
|
|
|
vin: vec![],
|
|
|
|
vout: vec![],
|
|
|
|
blockhash: H256::from(6),
|
|
|
|
confirmations: 77,
|
|
|
|
time: 88,
|
|
|
|
blocktime: 99,
|
|
|
|
};
|
|
|
|
assert_eq!(serde_json::to_string(&tx).unwrap(), r#"{"hex":"deadbeef","txid":"0400000000000000000000000000000000000000000000000000000000000000","hash":"0500000000000000000000000000000000000000000000000000000000000000","size":33,"version":55,"locktime":66,"vin":[],"vout":[],"blockhash":"0600000000000000000000000000000000000000000000000000000000000000","confirmations":77,"time":88,"blocktime":99}"#);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn transaction_deserialize() {
|
|
|
|
let tx = Transaction {
|
|
|
|
hex: "DEADBEEF".into(),
|
|
|
|
txid: H256::from(4),
|
|
|
|
hash: H256::from(5),
|
|
|
|
size: 33,
|
|
|
|
version: 55,
|
|
|
|
locktime: 66,
|
|
|
|
vin: vec![],
|
|
|
|
vout: vec![],
|
|
|
|
blockhash: H256::from(6),
|
|
|
|
confirmations: 77,
|
|
|
|
time: 88,
|
|
|
|
blocktime: 99,
|
|
|
|
};
|
|
|
|
assert_eq!(
|
2018-11-14 00:46:02 -08:00
|
|
|
serde_json::from_str::<Transaction>(r#"{"hex":"deadbeef","txid":"0400000000000000000000000000000000000000000000000000000000000000","hash":"0500000000000000000000000000000000000000000000000000000000000000","size":33,"version":55,"locktime":66,"vin":[],"vout":[],"blockhash":"0600000000000000000000000000000000000000000000000000000000000000","confirmations":77,"time":88,"blocktime":99}"#).unwrap(),
|
2016-12-13 02:27:45 -08:00
|
|
|
tx);
|
2019-06-28 14:27:46 -07:00
|
|
|
}
|
2016-12-13 02:27:45 -08:00
|
|
|
}
|