use std::{
cmp::Ordering,
io::{self, Error, ErrorKind},
};
use crate::{codec, ids::short};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Eq, Clone)]
pub struct Credential {
pub signatures: Vec<Vec<u8>>,
}
impl Default for Credential {
fn default() -> Self {
Self::default()
}
}
impl Credential {
pub fn default() -> Self {
Self {
signatures: Vec::new(),
}
}
pub fn new(sigs: Vec<Vec<u8>>) -> Self {
Self { signatures: sigs }
}
pub fn type_name() -> String {
"secp256k1fx.Credential".to_string()
}
pub fn type_id() -> u32 {
*(codec::X_TYPES.get(&Self::type_name()).unwrap()) as u32
}
}
impl Ord for Credential {
fn cmp(&self, other: &Credential) -> Ordering {
Signatures::new(&self.signatures).cmp(&Signatures::new(&other.signatures))
}
}
impl PartialOrd for Credential {
fn partial_cmp(&self, other: &Credential) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for Credential {
fn eq(&self, other: &Credential) -> bool {
self.cmp(other) == Ordering::Equal
}
}
#[derive(Eq)]
pub struct Signatures(Vec<Vec<u8>>);
impl Signatures {
pub fn new(sigs: &[Vec<u8>]) -> Self {
Signatures(Vec::from(sigs))
}
}
impl Ord for Signatures {
fn cmp(&self, other: &Signatures) -> Ordering {
let l1 = self.0.len();
let l2 = other.0.len();
l1.cmp(&l2) .then_with(
|| self.0.cmp(&other.0), )
}
}
impl PartialOrd for Signatures {
fn partial_cmp(&self, other: &Signatures) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for Signatures {
fn eq(&self, other: &Signatures) -> bool {
self.cmp(other) == Ordering::Equal
}
}
#[test]
fn test_sort_credentials() {
let mut credentials: Vec<Credential> = Vec::new();
for i in (0..10).rev() {
credentials.push(Credential {
signatures: vec![
vec![i as u8, 1, 2, 3],
vec![i as u8, 2, 2, 3],
vec![i as u8, 4, 2, 3],
],
});
credentials.push(Credential {
signatures: vec![
vec![i as u8, 1, 2, 3],
vec![i as u8, 2, 2, 3],
vec![i as u8, 3, 2, 3],
],
});
credentials.push(Credential {
signatures: vec![vec![i as u8, 1, 2, 3], vec![i as u8, 2, 2, 3]],
});
credentials.push(Credential {
signatures: vec![vec![i as u8, 2, 2, 3]],
});
credentials.push(Credential {
signatures: vec![vec![i as u8, 1, 2, 3]],
});
}
assert!(!cmp_manager::is_sorted_and_unique(&credentials));
credentials.sort();
let mut sorted_credentials: Vec<Credential> = Vec::new();
for i in 0..10 {
sorted_credentials.push(Credential {
signatures: vec![vec![i as u8, 1, 2, 3]],
});
sorted_credentials.push(Credential {
signatures: vec![vec![i as u8, 2, 2, 3]],
});
}
for i in 0..10 {
sorted_credentials.push(Credential {
signatures: vec![vec![i as u8, 1, 2, 3], vec![i as u8, 2, 2, 3]],
});
}
for i in 0..10 {
sorted_credentials.push(Credential {
signatures: vec![
vec![i as u8, 1, 2, 3],
vec![i as u8, 2, 2, 3],
vec![i as u8, 3, 2, 3],
],
});
sorted_credentials.push(Credential {
signatures: vec![
vec![i as u8, 1, 2, 3],
vec![i as u8, 2, 2, 3],
vec![i as u8, 4, 2, 3],
],
});
}
assert!(cmp_manager::is_sorted_and_unique(&sorted_credentials));
assert_eq!(credentials, sorted_credentials);
}
#[derive(Debug, Serialize, Deserialize, Eq, Clone)]
pub struct OutputOwners {
pub locktime: u64,
pub threshold: u32,
pub addrs: Vec<short::Id>,
}
impl Default for OutputOwners {
fn default() -> Self {
Self::default()
}
}
impl OutputOwners {
pub fn default() -> Self {
Self {
locktime: 0,
threshold: 0,
addrs: Vec::new(),
}
}
pub fn new(locktime: u64, threshold: u32, addrs: &[short::Id]) -> Self {
Self {
locktime,
threshold,
addrs: Vec::from(addrs),
}
}
pub fn type_name() -> String {
"secp256k1fx.OutputOwners".to_string()
}
pub fn type_id() -> u32 {
*(codec::P_TYPES.get(&Self::type_name()).unwrap()) as u32
}
}
impl Ord for OutputOwners {
fn cmp(&self, other: &OutputOwners) -> Ordering {
self.locktime
.cmp(&(other.locktime)) .then_with(
|| self.threshold.cmp(&other.threshold), )
.then_with(
|| short::Ids::new(&self.addrs).cmp(&short::Ids::new(&other.addrs)), )
}
}
impl PartialOrd for OutputOwners {
fn partial_cmp(&self, other: &OutputOwners) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for OutputOwners {
fn eq(&self, other: &OutputOwners) -> bool {
self.cmp(other) == Ordering::Equal
}
}
#[test]
fn test_sort_output_owners() {
let mut owners: Vec<OutputOwners> = Vec::new();
for i in (0..10).rev() {
owners.push(OutputOwners {
locktime: i as u64,
threshold: i as u32,
addrs: vec![
short::Id::from_slice(&vec![i as u8, 1, 2, 3]),
short::Id::from_slice(&vec![i as u8, 2, 2, 3]),
],
});
owners.push(OutputOwners {
locktime: i as u64,
threshold: i as u32,
addrs: vec![
short::Id::from_slice(&vec![i as u8, 1, 2, 3]),
short::Id::from_slice(&vec![i as u8, 1, 2, 3]),
],
});
owners.push(OutputOwners {
locktime: i as u64,
threshold: i as u32,
addrs: vec![short::Id::from_slice(&vec![i as u8, 2, 2, 3])],
});
owners.push(OutputOwners {
locktime: i as u64,
threshold: i as u32,
addrs: vec![short::Id::from_slice(&vec![i as u8, 1, 2, 3])],
});
}
assert!(!cmp_manager::is_sorted_and_unique(&owners));
owners.sort();
let mut sorted_owners: Vec<OutputOwners> = Vec::new();
for i in 0..10 {
sorted_owners.push(OutputOwners {
locktime: i as u64,
threshold: i as u32,
addrs: vec![short::Id::from_slice(&vec![i as u8, 1, 2, 3])],
});
sorted_owners.push(OutputOwners {
locktime: i as u64,
threshold: i as u32,
addrs: vec![short::Id::from_slice(&vec![i as u8, 2, 2, 3])],
});
sorted_owners.push(OutputOwners {
locktime: i as u64,
threshold: i as u32,
addrs: vec![
short::Id::from_slice(&vec![i as u8, 1, 2, 3]),
short::Id::from_slice(&vec![i as u8, 1, 2, 3]),
],
});
sorted_owners.push(OutputOwners {
locktime: i as u64,
threshold: i as u32,
addrs: vec![
short::Id::from_slice(&vec![i as u8, 1, 2, 3]),
short::Id::from_slice(&vec![i as u8, 2, 2, 3]),
],
});
}
assert!(cmp_manager::is_sorted_and_unique(&sorted_owners));
assert_eq!(owners, sorted_owners);
}
#[derive(Debug, Serialize, Deserialize, Eq, Clone)]
pub struct TransferOutput {
pub amount: u64,
pub output_owners: OutputOwners,
}
impl Default for TransferOutput {
fn default() -> Self {
Self::default()
}
}
impl TransferOutput {
pub fn default() -> Self {
Self {
amount: 0,
output_owners: OutputOwners::default(),
}
}
pub fn new(amount: u64, output_owners: OutputOwners) -> Self {
Self {
amount,
output_owners,
}
}
pub fn type_name() -> String {
"secp256k1fx.TransferOutput".to_string()
}
pub fn type_id() -> u32 {
*(codec::X_TYPES.get(&Self::type_name()).unwrap()) as u32
}
}
impl Ord for TransferOutput {
fn cmp(&self, other: &TransferOutput) -> Ordering {
self.amount
.cmp(&(other.amount)) .then_with(
|| self.output_owners.cmp(&(other.output_owners)), )
}
}
impl PartialOrd for TransferOutput {
fn partial_cmp(&self, other: &TransferOutput) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for TransferOutput {
fn eq(&self, other: &TransferOutput) -> bool {
self.cmp(other) == Ordering::Equal
}
}
#[test]
fn test_sort_transfer_outputs() {
let mut outputs: Vec<TransferOutput> = Vec::new();
for i in (0..10).rev() {
outputs.push(TransferOutput {
amount: i as u64,
output_owners: OutputOwners {
locktime: (i + 1) as u64,
threshold: (i + 1) as u32,
addrs: vec![
short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5]),
short::Id::from_slice(&vec![i as u8, 2, 2, 3, 4, 5]),
],
..OutputOwners::default()
},
});
outputs.push(TransferOutput {
amount: i as u64,
output_owners: OutputOwners {
locktime: (i + 1) as u64,
threshold: (i + 1) as u32,
addrs: vec![
short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5]),
short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5]),
],
..OutputOwners::default()
},
});
outputs.push(TransferOutput {
amount: i as u64,
output_owners: OutputOwners {
locktime: (i + 1) as u64,
threshold: (i + 1) as u32,
addrs: vec![short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5])],
..OutputOwners::default()
},
});
outputs.push(TransferOutput {
amount: i as u64,
output_owners: OutputOwners {
locktime: (i + 1) as u64,
threshold: i as u32,
addrs: vec![short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5])],
..OutputOwners::default()
},
});
outputs.push(TransferOutput {
amount: i as u64,
output_owners: OutputOwners {
locktime: i as u64,
threshold: i as u32,
addrs: vec![short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5])],
..OutputOwners::default()
},
});
}
assert!(!cmp_manager::is_sorted_and_unique(&outputs));
outputs.sort();
let mut sorted_outputs: Vec<TransferOutput> = Vec::new();
for i in 0..10 {
sorted_outputs.push(TransferOutput {
amount: i as u64,
output_owners: OutputOwners {
locktime: i as u64,
threshold: i as u32,
addrs: vec![short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5])],
..OutputOwners::default()
},
});
sorted_outputs.push(TransferOutput {
amount: i as u64,
output_owners: OutputOwners {
locktime: (i + 1) as u64,
threshold: i as u32,
addrs: vec![short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5])],
..OutputOwners::default()
},
});
sorted_outputs.push(TransferOutput {
amount: i as u64,
output_owners: OutputOwners {
locktime: (i + 1) as u64,
threshold: (i + 1) as u32,
addrs: vec![short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5])],
..OutputOwners::default()
},
});
sorted_outputs.push(TransferOutput {
amount: i as u64,
output_owners: OutputOwners {
locktime: (i + 1) as u64,
threshold: (i + 1) as u32,
addrs: vec![
short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5]),
short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5]),
],
..OutputOwners::default()
},
});
sorted_outputs.push(TransferOutput {
amount: i as u64,
output_owners: OutputOwners {
locktime: (i + 1) as u64,
threshold: (i + 1) as u32,
addrs: vec![
short::Id::from_slice(&vec![i as u8, 1, 2, 3, 4, 5]),
short::Id::from_slice(&vec![i as u8, 2, 2, 3, 4, 5]),
],
..OutputOwners::default()
},
});
}
assert!(cmp_manager::is_sorted_and_unique(&sorted_outputs));
assert_eq!(outputs, sorted_outputs);
}
#[derive(Debug, Serialize, Deserialize, Eq, Clone)]
pub struct TransferInput {
pub amount: u64,
pub sig_indices: Vec<u32>,
}
impl Default for TransferInput {
fn default() -> Self {
Self::default()
}
}
impl TransferInput {
pub fn default() -> Self {
Self {
amount: 0,
sig_indices: Vec::new(),
}
}
pub fn new(amount: u64, sig_indices: Vec<u32>) -> Self {
Self {
amount,
sig_indices,
}
}
pub fn type_name() -> String {
"secp256k1fx.TransferInput".to_string()
}
pub fn type_id() -> u32 {
*(codec::X_TYPES.get(&Self::type_name()).unwrap()) as u32
}
pub fn verify(&self) -> io::Result<()> {
if self.amount == 0 {
return Err(Error::new(
ErrorKind::InvalidInput,
"input has no value", ));
}
if !cmp_manager::is_sorted_and_unique(&self.sig_indices) {
return Err(Error::new(
ErrorKind::InvalidInput,
"signatures not sorted and unique", ));
}
Ok(())
}
pub fn sig_costs(&self) -> u64 {
let sigs = self.sig_indices.len();
(sigs as u64) * 1000
}
}
impl Ord for TransferInput {
fn cmp(&self, other: &TransferInput) -> Ordering {
self.amount
.cmp(&(other.amount)) .then_with(
|| SigIndices::new(&self.sig_indices).cmp(&SigIndices::new(&other.sig_indices)), )
}
}
impl PartialOrd for TransferInput {
fn partial_cmp(&self, other: &TransferInput) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for TransferInput {
fn eq(&self, other: &TransferInput) -> bool {
self.cmp(other) == Ordering::Equal
}
}
#[derive(Eq)]
pub struct SigIndices(Vec<u32>);
impl SigIndices {
pub fn new(ids: &[u32]) -> Self {
SigIndices(Vec::from(ids))
}
}
impl Ord for SigIndices {
fn cmp(&self, other: &SigIndices) -> Ordering {
let l1 = self.0.len();
let l2 = other.0.len();
l1.cmp(&l2) .then_with(
|| self.0.cmp(&other.0), )
}
}
impl PartialOrd for SigIndices {
fn partial_cmp(&self, other: &SigIndices) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for SigIndices {
fn eq(&self, other: &SigIndices) -> bool {
self.cmp(other) == Ordering::Equal
}
}
#[test]
fn test_sort_transfer_inputs() {
let mut inputs: Vec<TransferInput> = Vec::new();
for i in (0..10).rev() {
inputs.push(TransferInput {
amount: 5,
sig_indices: vec![i as u32, 2, 2, 3, 4, 5, 6, 7, 8, 9],
});
inputs.push(TransferInput {
amount: 5,
sig_indices: vec![i as u32, 1, 2, 3, 4, 5, 6, 7, 8, 9],
});
inputs.push(TransferInput {
amount: 50,
sig_indices: vec![i as u32, 1, 2, 3, 4, 5],
});
inputs.push(TransferInput {
amount: 5,
sig_indices: vec![i as u32, 1, 2, 3, 4, 5],
});
inputs.push(TransferInput {
amount: 1,
sig_indices: vec![(i + 100) as u32, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9],
});
}
assert!(!cmp_manager::is_sorted_and_unique(&inputs));
inputs.sort();
let mut sorted_inputs: Vec<TransferInput> = Vec::new();
for i in 0..10 {
sorted_inputs.push(TransferInput {
amount: 1,
sig_indices: vec![(i + 100) as u32, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9],
});
}
for i in 0..10 {
sorted_inputs.push(TransferInput {
amount: 5,
sig_indices: vec![i as u32, 1, 2, 3, 4, 5],
});
}
for i in 0..10 {
sorted_inputs.push(TransferInput {
amount: 5,
sig_indices: vec![i as u32, 1, 2, 3, 4, 5, 6, 7, 8, 9],
});
sorted_inputs.push(TransferInput {
amount: 5,
sig_indices: vec![i as u32, 2, 2, 3, 4, 5, 6, 7, 8, 9],
});
}
for i in 0..10 {
sorted_inputs.push(TransferInput {
amount: 50,
sig_indices: vec![i as u32, 1, 2, 3, 4, 5],
});
}
assert!(cmp_manager::is_sorted_and_unique(&sorted_inputs));
assert_eq!(inputs, sorted_inputs);
}
#[derive(Debug, Serialize, Deserialize, Eq, Clone)]
pub struct Input {
pub sig_indices: Vec<u32>,
}
impl Default for Input {
fn default() -> Self {
Self::default()
}
}
impl Input {
pub fn default() -> Self {
Self {
sig_indices: Vec::new(),
}
}
pub fn new(sig_indices: Vec<u32>) -> Self {
Self { sig_indices }
}
pub fn type_name() -> String {
"secp256k1fx.Input".to_string()
}
pub fn type_id() -> u32 {
*(codec::P_TYPES.get(&Self::type_name()).unwrap()) as u32
}
}
impl Ord for Input {
fn cmp(&self, other: &Input) -> Ordering {
SigIndices::new(&self.sig_indices).cmp(&SigIndices::new(&other.sig_indices))
}
}
impl PartialOrd for Input {
fn partial_cmp(&self, other: &Input) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for Input {
fn eq(&self, other: &Input) -> bool {
self.cmp(other) == Ordering::Equal
}
}
#[test]
fn test_sort_inputs() {
let mut inputs: Vec<Input> = Vec::new();
for i in (0..10).rev() {
inputs.push(Input {
sig_indices: vec![i as u32, 2, 2, 3, 4, 5, 6, 7, 8, 9],
});
inputs.push(Input {
sig_indices: vec![i as u32, 1, 2, 3, 4, 5, 6, 7, 8, 9],
});
inputs.push(Input {
sig_indices: vec![i as u32, 1, 2, 3, 4, 5],
});
}
assert!(!cmp_manager::is_sorted_and_unique(&inputs));
inputs.sort();
let mut sorted_inputs: Vec<Input> = Vec::new();
for i in 0..10 {
sorted_inputs.push(Input {
sig_indices: vec![i as u32, 1, 2, 3, 4, 5],
});
}
for i in 0..10 {
sorted_inputs.push(Input {
sig_indices: vec![i as u32, 1, 2, 3, 4, 5, 6, 7, 8, 9],
});
sorted_inputs.push(Input {
sig_indices: vec![i as u32, 2, 2, 3, 4, 5, 6, 7, 8, 9],
});
}
assert!(cmp_manager::is_sorted_and_unique(&sorted_inputs));
assert_eq!(inputs, sorted_inputs);
}