<commit_before>extern crate regex;
extern crate chrono;

use command_executor::{Command, CommandContext, CommandMetadata, CommandParams, CommandGroup, CommandGroupMetadata, DynamicCompletionType};
use commands::*;

use indy::{ErrorCode, IndyError};
use libindy::payment::Payment;

use serde_json::Value as JSONValue;
use serde_json::Map as JSONMap;

use utils::table::print_list_table;

pub mod group {
    use super::*;

    command_group!(CommandGroupMetadata::new("payment-address", "Payment address management commands"));
}

pub mod create_command {
    use super::*;

    command!(CommandMetadata::build("create", "Create the payment address for specified payment method.")
                .add_required_param("payment_method", "Payment method to use")
                .add_optional_param("seed", "Seed for creating payment address")
                .add_example("payment-address create payment_method=sov")
                .add_example("payment-address create payment_method=sov seed=000000000000000000000000000Seed1")
                .finalize()
    );

    fn execute(ctx: &CommandContext, params: &CommandParams) -> Result<(), ()> {
        trace!("execute >> ctx {:?} params {:?}", ctx, params);

        let wallet_handle = ensure_opened_wallet_handle(&ctx)?;

        let payment_method = get_str_param("payment_method", params).map_err(error_err!())?;
        let seed = get_opt_str_param("seed", params).map_err(error_err!())?;

        let config = {
            let mut json = JSONMap::new();
            update_json_map_opt_key!(json, "seed", seed);
            JSONValue::from(json).to_string()
        };

        let res = match Payment::create_payment_address(wallet_handle, payment_method, &config) {
            Ok(payment_address) => {
                println_succ!("Payment Address has been created \"{}\"", payment_address);
                Ok(())
            },
            Err(err) => {
                handle_payment_error(err, Some(payment_method));
                Err(())
            },
        };

        trace!("execute << {:?}", res);
        res
    }
}

pub mod list_command {
    use super::*;

    command!(CommandMetadata::build("list", "Lists all payment addresses that are stored in the wallet.")
                .finalize());

    fn execute(ctx: &CommandContext, params: &CommandParams) -> Result<(), ()> {
        trace!("execute >> ctx {:?} params {:?}", ctx, params);

        let wallet_handle = ensure_opened_wallet_handle(&ctx)?;

        let res = match Payment::list_payment_addresses(wallet_handle) {
            Ok(payment_addresses_json) => {
                let payment_addresses: Vec<String> = serde_json::from_str(&payment_addresses_json)
                    .map_err(|_| println_err!("Wrong data has been received"))?;

                let list_addresses =
                    payment_addresses.iter()
                        .map(|payment_address| {
                            let parts = payment_address.split(':').collect::<Vec<&str>>();
                            json!({
                                "address": payment_address,
                                "method": parts.get(1).unwrap_or(&"Unknown payment method")
                            })
                        })
                        .collect::<Vec<serde_json::Value>>();

                print_list_table(&list_addresses,
                                 &[("address", "Payment Address"),
                                       ("method", "Payment Method")],
                                 "There are no payment addresses");
                Ok(())
            }
            Err(err) => {
                handle_indy_error(err, None, None, None);
                Err(())
            },
        };

        trace!("execute << {:?}", res);
        res
    }
}

pub mod sign_command {
    use super::*;

    command!(CommandMetadata::build("sign", "Create a proof of payment address control by signing an input and producing a signature.")
                .add_required_param_with_dynamic_completion("address","Payment address  to use", DynamicCompletionType::PaymentAddress)
                .add_required_param("input", "The input data to be signed")
                .add_example("payment-address sign address=pay:null:lUdSMj9AmoUbmRQ input=123456789")
                .finalize());

    fn execute(ctx: &CommandContext, params: &CommandParams) -> Result<(), ()> {
        trace!("execute >> ctx {:?} params {:?}", ctx, params);

        let wallet_handle = ensure_opened_wallet_handle(&ctx)?;

        let address = get_str_param("address", params).map_err(error_err!())?;
        let input = get_str_param("input", params).map_err(error_err!())?;

        let res = match Payment::sign_with_address(wallet_handle, address, input) {
            Ok(signature) => Ok(println_succ!("Signature \"0x{}\"", bin2hex(signature.as_slice()))),
            Err(err) => Err(handle_indy_error(err, None, None, None))
        };

        trace!("execute << {:?}", res);
        res
    }

    fn bin2hex(b: &[u8]) -> String {
        b.iter()
            .map(|b| format!("{:02x}", b))
            .collect::<Vec<_>>()
            .join("")
    }
}

pub mod verify_command {
    use super::*;

    command!(CommandMetadata::build("verify", "Verify a proof of payment address control by verifying a signature.")
             .add_required_param_with_dynamic_completion("address","Payment address  to use", DynamicCompletionType::PaymentAddress)
             .add_required_param("input", "The input data that was signed")
             .add_required_param("signature", "The signature generated from sign-with-address")
             .add_example("payment-address verify address=pay:null:lUdSMj9AmoUbmRQ input=123456789 signature=0x0006e83221cdaf70b3c01a613675274dd2064ea376bf35656cff8436e62cdf89")
             .finalize());

    fn execute(ctx: &CommandContext, params: &CommandParams) -> Result<(), ()> {
        trace!("execute >> ctx {:?} params {:?}", ctx, params);

        let address = get_str_param("address", params).map_err(error_err!())?;
        let input = get_str_param("input", params).map_err(error_err!())?;
        let signature = get_str_param("signature", params).map_err(error_err!())?;

        if &signature[0..2] != "0x" {
            println_err!("Wrong data has been received. Expected signature to start with '0x'");
            return Err(());
        }

        let sig = hex2bin(&signature[2..]).map_err(|e| println_err!("{}", e))?;

        let res = match Payment::verify_with_address(address, input, sig.as_slice()) {
            Ok(valid) => {
                if valid {
                    Ok(println_succ!("Valid signature"))
                } else {
                    Ok(println_err!("Invalid signature"))
                }
            }
            Err(err) => Err(handle_indy_error(err, None, None, None))
        };

        trace!("execute << {:?}", res);
        res
    }

    fn hex2bin(s: &str) -> Result<Vec<u8>, String> {
        if s.len() % 2 != 0 {
            return Err("Bad input".to_string());
        }
        for (i, ch) in s.chars().enumerate() {
            if !ch.is_digit(16) {
                return Err(format!(
                    "Bad character position {}",
                    i
                ));
            }
        }

        let input: Vec<_> = s.chars().collect();

        let decoded: Vec<u8> = input
            .chunks(2)
            .map(|chunk| {
                ((chunk[0].to_digit(16).unwrap() << 4) | (chunk[1].to_digit(16).unwrap())) as u8
            })
            .collect();

        Ok(decoded)
    }
}

pub fn handle_payment_error(err: IndyError, payment_method: Option<&str>) {
    match err.error_code {
        ErrorCode::UnknownPaymentMethod => println_err!("Unknown payment method {}", payment_method.unwrap_or("")),
        ErrorCode::IncompatiblePaymentError => println_err!("No methods were scraped or more than one was scraped"),
        ErrorCode::PaymentInsufficientFundsError => println_err!("Insufficient funds on inputs"),
        ErrorCode::PaymentExtraFundsError => println_err!("Extra funds on inputs"),
        ErrorCode::PaymentSourceDoesNotExistError => println_err!("Payment source not found"),
        ErrorCode::PaymentOperationNotSupportedError => println_err!("Payment operation not supported"),
        ErrorCode::WalletItemAlreadyExists => println_err!("Payment address already exists"),
        _ => println_err!("{}", err.message)
    }
}

pub fn list_payment_addresses(ctx: &CommandContext) -> Vec<String> {
    get_opened_wallet(ctx)
        .and_then(|(wallet_handle, _)|
            Payment::list_payment_addresses(wallet_handle).ok()
        )
        .and_then(|payment_addresses|
            serde_json::from_str(&payment_addresses).ok()
        )
        .unwrap_or_default()
}

#[cfg(test)]
#[cfg(feature = "nullpay_plugin")]
pub mod tests {
    use super::*;
    use commands::common::tests::{load_null_payment_plugin, NULL_PAYMENT_METHOD};
    use commands::did::tests::SEED_MY1;

    pub const INPUT: &str = "123456789";

    mod create {
        use super::*;

        #[test]
        pub fn create_works() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            {
                let cmd = create_command::new();
                let mut params = CommandParams::new();
                params.insert("payment_method", NULL_PAYMENT_METHOD.to_string());
                cmd.execute(&ctx, &params).unwrap();
            }
            let addresses = list_payment_addresses(&ctx);
            assert_eq!(1, addresses.len());
            assert!(addresses[0].starts_with("pay:null:"));

            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn create_works_for_seed() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            {
                let cmd = create_command::new();
                let mut params = CommandParams::new();
                params.insert("payment_method", NULL_PAYMENT_METHOD.to_string());
                params.insert("seed", SEED_MY1.to_string());
                cmd.execute(&ctx, &params).unwrap();
            }
            let addresses = list_payment_addresses(&ctx);
            assert_eq!(1, addresses.len());
            //            assert_eq!("pay:null:AkQr7K6CP1tslXd", addresses[0]);  TODO: Exactly check

            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn create_works_for_unknown_payment_method() {
            let ctx = setup_with_wallet();
            {
                let cmd = create_command::new();
                let mut params = CommandParams::new();
                params.insert("payment_method", "unknown_payment_method".to_string());
                cmd.execute(&ctx, &params).unwrap_err();
            }
            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn create_works_for_no_opened_wallet() {
            let ctx = setup();
            load_null_payment_plugin(&ctx);
            {
                let cmd = create_command::new();
                let mut params = CommandParams::new();
                params.insert("payment_method", NULL_PAYMENT_METHOD.to_string());
                cmd.execute(&ctx, &params).unwrap_err();
            }
            tear_down();
        }
    }

    mod list {
        use super::*;

        #[test]
        pub fn list_works() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            create_payment_address(&ctx);
            {
                let cmd = list_command::new();
                let params = CommandParams::new();
                cmd.execute(&ctx, &params).unwrap();
            }
            let addresses = list_payment_addresses(&ctx);
            assert_eq!(1, addresses.len());

            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn list_works_for_empty_list() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            {
                let cmd = list_command::new();
                let params = CommandParams::new();
                cmd.execute(&ctx, &params).unwrap();
            }
            let addresses = list_payment_addresses(&ctx);
            assert_eq!(0, addresses.len());

            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn list_works_for_no_opened_wallet() {
            let ctx = setup();
            load_null_payment_plugin(&ctx);
            {
                let cmd = list_command::new();
                let params = CommandParams::new();
                cmd.execute(&ctx, &params).unwrap_err();
            }
            tear_down();
        }
    }

    mod sign {
        use super::*;

        #[test]
        pub fn sign_works() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            let payment_address = create_payment_address(&ctx);
            {
                let cmd = sign_command::new();
                let mut params = CommandParams::new();
                params.insert("address", payment_address);
                params.insert("input", INPUT.to_string());
                cmd.execute(&ctx, &params).unwrap();
            }
            tear_down_with_wallet(&ctx);
        }
    }

    mod verify {
        use super::*;

        const PAYMENT_ADDRESS: &str = "pay:null:lUdSMj9AmoUbmRQ";

        #[test]
        pub fn verify_works() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            {
                let cmd = verify_command::new();
                let mut params = CommandParams::new();
                params.insert("address", PAYMENT_ADDRESS.to_string());
                params.insert("input", INPUT.to_string());
                params.insert("signature", "0x0006e83221cdaf70b3c01a613675274dd2064ea376bf35656cff8436e62cdf89".to_string());
                cmd.execute(&ctx, &params).unwrap();
            }
            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn verify_works_for_invalid_signature() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            {
                let cmd = verify_command::new();
                let mut params = CommandParams::new();
                params.insert("address", PAYMENT_ADDRESS.to_string());
                params.insert("input", INPUT.to_string());
                params.insert("signature", "0x0006e83221cdaf70b3c01a613675274dd2064ea376bf11111111111111111111".to_string());
                cmd.execute(&ctx, &params).unwrap();
            }
            tear_down_with_wallet(&ctx);
        }
    }

    pub fn create_payment_address(ctx: &CommandContext) -> String {
        let wallet_handle = ensure_opened_wallet_handle(ctx).unwrap();
        Payment::create_payment_address(wallet_handle, NULL_PAYMENT_METHOD, "{}").unwrap()
    }
}
<commit_msg>Removed redundant spaces<commit_after>extern crate regex;
extern crate chrono;

use command_executor::{Command, CommandContext, CommandMetadata, CommandParams, CommandGroup, CommandGroupMetadata, DynamicCompletionType};
use commands::*;

use indy::{ErrorCode, IndyError};
use libindy::payment::Payment;

use serde_json::Value as JSONValue;
use serde_json::Map as JSONMap;

use utils::table::print_list_table;

pub mod group {
    use super::*;

    command_group!(CommandGroupMetadata::new("payment-address", "Payment address management commands"));
}

pub mod create_command {
    use super::*;

    command!(CommandMetadata::build("create", "Create the payment address for specified payment method.")
                .add_required_param("payment_method", "Payment method to use")
                .add_optional_param("seed", "Seed for creating payment address")
                .add_example("payment-address create payment_method=sov")
                .add_example("payment-address create payment_method=sov seed=000000000000000000000000000Seed1")
                .finalize()
    );

    fn execute(ctx: &CommandContext, params: &CommandParams) -> Result<(), ()> {
        trace!("execute >> ctx {:?} params {:?}", ctx, params);

        let wallet_handle = ensure_opened_wallet_handle(&ctx)?;

        let payment_method = get_str_param("payment_method", params).map_err(error_err!())?;
        let seed = get_opt_str_param("seed", params).map_err(error_err!())?;

        let config = {
            let mut json = JSONMap::new();
            update_json_map_opt_key!(json, "seed", seed);
            JSONValue::from(json).to_string()
        };

        let res = match Payment::create_payment_address(wallet_handle, payment_method, &config) {
            Ok(payment_address) => {
                println_succ!("Payment Address has been created \"{}\"", payment_address);
                Ok(())
            },
            Err(err) => {
                handle_payment_error(err, Some(payment_method));
                Err(())
            },
        };

        trace!("execute << {:?}", res);
        res
    }
}

pub mod list_command {
    use super::*;

    command!(CommandMetadata::build("list", "Lists all payment addresses that are stored in the wallet.")
                .finalize());

    fn execute(ctx: &CommandContext, params: &CommandParams) -> Result<(), ()> {
        trace!("execute >> ctx {:?} params {:?}", ctx, params);

        let wallet_handle = ensure_opened_wallet_handle(&ctx)?;

        let res = match Payment::list_payment_addresses(wallet_handle) {
            Ok(payment_addresses_json) => {
                let payment_addresses: Vec<String> = serde_json::from_str(&payment_addresses_json)
                    .map_err(|_| println_err!("Wrong data has been received"))?;

                let list_addresses =
                    payment_addresses.iter()
                        .map(|payment_address| {
                            let parts = payment_address.split(':').collect::<Vec<&str>>();
                            json!({
                                "address": payment_address,
                                "method": parts.get(1).unwrap_or(&"Unknown payment method")
                            })
                        })
                        .collect::<Vec<serde_json::Value>>();

                print_list_table(&list_addresses,
                                 &[("address", "Payment Address"),
                                       ("method", "Payment Method")],
                                 "There are no payment addresses");
                Ok(())
            }
            Err(err) => {
                handle_indy_error(err, None, None, None);
                Err(())
            },
        };

        trace!("execute << {:?}", res);
        res
    }
}

pub mod sign_command {
    use super::*;

    command!(CommandMetadata::build("sign", "Create a proof of payment address control by signing an input and producing a signature.")
                .add_required_param_with_dynamic_completion("address","Payment address to use", DynamicCompletionType::PaymentAddress)
                .add_required_param("input", "The input data to be signed")
                .add_example("payment-address sign address=pay:null:lUdSMj9AmoUbmRQ input=123456789")
                .finalize());

    fn execute(ctx: &CommandContext, params: &CommandParams) -> Result<(), ()> {
        trace!("execute >> ctx {:?} params {:?}", ctx, params);

        let wallet_handle = ensure_opened_wallet_handle(&ctx)?;

        let address = get_str_param("address", params).map_err(error_err!())?;
        let input = get_str_param("input", params).map_err(error_err!())?;

        let res = match Payment::sign_with_address(wallet_handle, address, input) {
            Ok(signature) => Ok(println_succ!("Signature \"0x{}\"", bin2hex(signature.as_slice()))),
            Err(err) => Err(handle_indy_error(err, None, None, None))
        };

        trace!("execute << {:?}", res);
        res
    }

    fn bin2hex(b: &[u8]) -> String {
        b.iter()
            .map(|b| format!("{:02x}", b))
            .collect::<Vec<_>>()
            .join("")
    }
}

pub mod verify_command {
    use super::*;

    command!(CommandMetadata::build("verify", "Verify a proof of payment address control by verifying a signature.")
             .add_required_param_with_dynamic_completion("address","Payment address to use", DynamicCompletionType::PaymentAddress)
             .add_required_param("input", "The input data that was signed")
             .add_required_param("signature", "The signature generated from sign-with-address")
             .add_example("payment-address verify address=pay:null:lUdSMj9AmoUbmRQ input=123456789 signature=0x0006e83221cdaf70b3c01a613675274dd2064ea376bf35656cff8436e62cdf89")
             .finalize());

    fn execute(ctx: &CommandContext, params: &CommandParams) -> Result<(), ()> {
        trace!("execute >> ctx {:?} params {:?}", ctx, params);

        let address = get_str_param("address", params).map_err(error_err!())?;
        let input = get_str_param("input", params).map_err(error_err!())?;
        let signature = get_str_param("signature", params).map_err(error_err!())?;

        if &signature[0..2] != "0x" {
            println_err!("Wrong data has been received. Expected signature to start with '0x'");
            return Err(());
        }

        let sig = hex2bin(&signature[2..]).map_err(|e| println_err!("{}", e))?;

        let res = match Payment::verify_with_address(address, input, sig.as_slice()) {
            Ok(valid) => {
                if valid {
                    Ok(println_succ!("Valid signature"))
                } else {
                    Ok(println_err!("Invalid signature"))
                }
            }
            Err(err) => Err(handle_indy_error(err, None, None, None))
        };

        trace!("execute << {:?}", res);
        res
    }

    fn hex2bin(s: &str) -> Result<Vec<u8>, String> {
        if s.len() % 2 != 0 {
            return Err("Bad input".to_string());
        }
        for (i, ch) in s.chars().enumerate() {
            if !ch.is_digit(16) {
                return Err(format!(
                    "Bad character position {}",
                    i
                ));
            }
        }

        let input: Vec<_> = s.chars().collect();

        let decoded: Vec<u8> = input
            .chunks(2)
            .map(|chunk| {
                ((chunk[0].to_digit(16).unwrap() << 4) | (chunk[1].to_digit(16).unwrap())) as u8
            })
            .collect();

        Ok(decoded)
    }
}

pub fn handle_payment_error(err: IndyError, payment_method: Option<&str>) {
    match err.error_code {
        ErrorCode::UnknownPaymentMethod => println_err!("Unknown payment method {}", payment_method.unwrap_or("")),
        ErrorCode::IncompatiblePaymentError => println_err!("No methods were scraped or more than one was scraped"),
        ErrorCode::PaymentInsufficientFundsError => println_err!("Insufficient funds on inputs"),
        ErrorCode::PaymentExtraFundsError => println_err!("Extra funds on inputs"),
        ErrorCode::PaymentSourceDoesNotExistError => println_err!("Payment source not found"),
        ErrorCode::PaymentOperationNotSupportedError => println_err!("Payment operation not supported"),
        ErrorCode::WalletItemAlreadyExists => println_err!("Payment address already exists"),
        _ => println_err!("{}", err.message)
    }
}

pub fn list_payment_addresses(ctx: &CommandContext) -> Vec<String> {
    get_opened_wallet(ctx)
        .and_then(|(wallet_handle, _)|
            Payment::list_payment_addresses(wallet_handle).ok()
        )
        .and_then(|payment_addresses|
            serde_json::from_str(&payment_addresses).ok()
        )
        .unwrap_or_default()
}

#[cfg(test)]
#[cfg(feature = "nullpay_plugin")]
pub mod tests {
    use super::*;
    use commands::common::tests::{load_null_payment_plugin, NULL_PAYMENT_METHOD};
    use commands::did::tests::SEED_MY1;

    pub const INPUT: &str = "123456789";

    mod create {
        use super::*;

        #[test]
        pub fn create_works() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            {
                let cmd = create_command::new();
                let mut params = CommandParams::new();
                params.insert("payment_method", NULL_PAYMENT_METHOD.to_string());
                cmd.execute(&ctx, &params).unwrap();
            }
            let addresses = list_payment_addresses(&ctx);
            assert_eq!(1, addresses.len());
            assert!(addresses[0].starts_with("pay:null:"));

            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn create_works_for_seed() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            {
                let cmd = create_command::new();
                let mut params = CommandParams::new();
                params.insert("payment_method", NULL_PAYMENT_METHOD.to_string());
                params.insert("seed", SEED_MY1.to_string());
                cmd.execute(&ctx, &params).unwrap();
            }
            let addresses = list_payment_addresses(&ctx);
            assert_eq!(1, addresses.len());
            //            assert_eq!("pay:null:AkQr7K6CP1tslXd", addresses[0]);  TODO: Exactly check

            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn create_works_for_unknown_payment_method() {
            let ctx = setup_with_wallet();
            {
                let cmd = create_command::new();
                let mut params = CommandParams::new();
                params.insert("payment_method", "unknown_payment_method".to_string());
                cmd.execute(&ctx, &params).unwrap_err();
            }
            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn create_works_for_no_opened_wallet() {
            let ctx = setup();
            load_null_payment_plugin(&ctx);
            {
                let cmd = create_command::new();
                let mut params = CommandParams::new();
                params.insert("payment_method", NULL_PAYMENT_METHOD.to_string());
                cmd.execute(&ctx, &params).unwrap_err();
            }
            tear_down();
        }
    }

    mod list {
        use super::*;

        #[test]
        pub fn list_works() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            create_payment_address(&ctx);
            {
                let cmd = list_command::new();
                let params = CommandParams::new();
                cmd.execute(&ctx, &params).unwrap();
            }
            let addresses = list_payment_addresses(&ctx);
            assert_eq!(1, addresses.len());

            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn list_works_for_empty_list() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            {
                let cmd = list_command::new();
                let params = CommandParams::new();
                cmd.execute(&ctx, &params).unwrap();
            }
            let addresses = list_payment_addresses(&ctx);
            assert_eq!(0, addresses.len());

            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn list_works_for_no_opened_wallet() {
            let ctx = setup();
            load_null_payment_plugin(&ctx);
            {
                let cmd = list_command::new();
                let params = CommandParams::new();
                cmd.execute(&ctx, &params).unwrap_err();
            }
            tear_down();
        }
    }

    mod sign {
        use super::*;

        #[test]
        pub fn sign_works() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            let payment_address = create_payment_address(&ctx);
            {
                let cmd = sign_command::new();
                let mut params = CommandParams::new();
                params.insert("address", payment_address);
                params.insert("input", INPUT.to_string());
                cmd.execute(&ctx, &params).unwrap();
            }
            tear_down_with_wallet(&ctx);
        }
    }

    mod verify {
        use super::*;

        const PAYMENT_ADDRESS: &str = "pay:null:lUdSMj9AmoUbmRQ";

        #[test]
        pub fn verify_works() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            {
                let cmd = verify_command::new();
                let mut params = CommandParams::new();
                params.insert("address", PAYMENT_ADDRESS.to_string());
                params.insert("input", INPUT.to_string());
                params.insert("signature", "0x0006e83221cdaf70b3c01a613675274dd2064ea376bf35656cff8436e62cdf89".to_string());
                cmd.execute(&ctx, &params).unwrap();
            }
            tear_down_with_wallet(&ctx);
        }

        #[test]
        pub fn verify_works_for_invalid_signature() {
            let ctx = setup_with_wallet();
            load_null_payment_plugin(&ctx);
            {
                let cmd = verify_command::new();
                let mut params = CommandParams::new();
                params.insert("address", PAYMENT_ADDRESS.to_string());
                params.insert("input", INPUT.to_string());
                params.insert("signature", "0x0006e83221cdaf70b3c01a613675274dd2064ea376bf11111111111111111111".to_string());
                cmd.execute(&ctx, &params).unwrap();
            }
            tear_down_with_wallet(&ctx);
        }
    }

    pub fn create_payment_address(ctx: &CommandContext) -> String {
        let wallet_handle = ensure_opened_wallet_handle(ctx).unwrap();
        Payment::create_payment_address(wallet_handle, NULL_PAYMENT_METHOD, "{}").unwrap()
    }
}
<|endoftext|>


<commit_before>mod http;
mod udp;
mod errors;
mod dns;
mod dht;

use std::collections::VecDeque;
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};
use std::{result, io, thread};

use byteorder::{BigEndian, ReadBytesExt};
use url::Url;
use amy;

pub use self::errors::{Result, ResultExt, Error, ErrorKind};
use torrent::Torrent;
use bencode::BEncode;
use control::cio;
use handle;
use disk;
use CONFIG;

pub struct Tracker {
    poll: amy::Poller,
    ch: handle::Handle<Request, Response>,
    dns_res: amy::Receiver<dns::QueryResponse>,
    http: http::Handler,
    queue: VecDeque<Announce>,
    udp: udp::Handler,
    dht: dht::Manager,
    dns: dns::Resolver,
    timer: usize,
    shutting_down: bool,
}

#[derive(Debug)]
pub enum Request {
    Announce(Announce),
    GetPeers(GetPeers),
    AddNode(SocketAddr),
    DHTAnnounce([u8; 20]),
    Shutdown,
}

#[derive(Debug)]
pub struct Announce {
    id: usize,
    url: String,
    hash: [u8; 20],
    port: u16,
    uploaded: u64,
    downloaded: u64,
    left: u64,
    num_want: Option<u16>,
    event: Option<Event>,
}

#[derive(Debug)]
pub struct GetPeers {
    pub id: usize,
    pub hash: [u8; 20],
}

#[derive(Debug)]
pub enum Event {
    Started,
    Stopped,
    Completed,
}

pub type Response = (usize, Result<TrackerResponse>);

#[derive(Debug)]
pub struct TrackerResponse {
    pub peers: Vec<SocketAddr>,
    pub dht: bool,
    pub interval: u32,
    pub leechers: u32,
    pub seeders: u32,
}

const POLL_INT_MS: usize = 1000;

impl Tracker {
    pub fn start(
        creg: &mut amy::Registrar,
        db: amy::Sender<disk::Request>,
    ) -> io::Result<(handle::Handle<Response, Request>, thread::JoinHandle<()>)> {
        let poll = amy::Poller::new()?;
        let mut reg = poll.get_registrar()?;
        let (ch, dh) = handle::Handle::new(creg, &mut reg)?;
        let timer = reg.set_interval(150)?;
        let (dtx, drx) = reg.channel()?;
        let udp = udp::Handler::new(&reg)?;
        let dht = dht::Manager::new(&reg, db)?;
        let http = http::Handler::new(&reg)?;
        let dns = dns::Resolver::new(reg, dtx);
        let th = dh.run("trk", move |h| {
            Tracker {
                poll,
                ch: h,
                udp,
                dht,
                http,
                dns,
                dns_res: drx,
                timer,
                queue: VecDeque::new(),
                shutting_down: false,
            }.run()
        })?;
        Ok((ch, th))
    }

    pub fn run(&mut self) {
        self.dht.init();

        debug!("Initialized!");
        'outer: loop {
            for event in self.poll.wait(POLL_INT_MS).unwrap() {
                if self.handle_event(event).is_err() {
                    break 'outer;
                }
            }
        }

        debug!("Shutting down!");
        self.shutting_down = true;

        // Shutdown loop - wait for all requests to complete
        loop {
            for event in self.poll.wait(POLL_INT_MS).unwrap() {
                if self.handle_event(event).is_err() {}
                if self.http.complete() && self.udp.complete() {
                    return;
                }
            }
        }
    }

    fn handle_event(&mut self, event: amy::Notification) -> result::Result<(), ()> {
        if event.id == self.ch.rx.get_id() {
            return self.handle_request();
        } else if event.id == self.dns_res.get_id() {
            self.handle_dns_res();
        } else if event.id == self.timer {
            self.handle_timer();
        } else {
            self.handle_socket(event);
        }
        Ok(())
    }

    fn handle_request(&mut self) -> result::Result<(), ()> {
        while let Ok(r) = self.ch.recv() {
            match r {
                Request::Announce(req) => self.handle_announce(req),
                Request::GetPeers(gp) => {
                    debug!("Handling dht peer find req!");
                    self.dht.get_peers(gp.id, gp.hash);
                }
                Request::AddNode(addr) => {
                    debug!("Handling dht node addition req!");
                    self.dht.add_addr(addr);
                }
                Request::DHTAnnounce(hash) => {
                    debug!("Handling dht announce req!");
                    self.dht.announce(hash);
                }
                Request::Shutdown => {
                    return Err(());
                }
            }
        }
        Ok(())
    }

    fn handle_announce(&mut self, req: Announce) {
        debug!("Handling announce request!");
        if self.udp.active_requests() + self.http.active_requests() >
            CONFIG.net.max_open_announces
        {
            self.queue.push_back(req);
        } else {
            let id = req.id;
            let response = if let Ok(url) = Url::parse(&req.url) {
                match url.scheme() {
                    "http" | "https" => self.http.new_announce(req, &url, &mut self.dns),
                    "udp" => self.udp.new_announce(req, &url, &mut self.dns),
                    s => Err(
                        ErrorKind::InvalidRequest(format!("Unknown tracker url scheme: {}", s))
                            .into(),
                    ),
                }
            } else {
                Err(
                    ErrorKind::InvalidRequest(format!("Invalid url: {}", req.url)).into(),
                )
            };
            if let Err(e) = response {
                self.send_response((id, Err(e)));
            }
        }
    }

    fn dequeue_req(&mut self) {
        // Attempt to dequeue next request if we can
        if let Some(a) = self.queue.pop_front() {
            self.handle_announce(a);
        }
    }

    fn handle_dns_res(&mut self) {
        while let Ok(r) = self.dns_res.try_recv() {
            let resp = if self.http.contains(r.id) {
                self.http.dns_resolved(r)
            } else if self.udp.contains(r.id) {
                self.udp.dns_resolved(r)
            } else {
                None
            };
            if let Some(r) = resp {
                self.send_response(r);
            }
        }
    }

    fn handle_timer(&mut self) {
        for r in self.http.tick().into_iter().chain(
            self.udp.tick().into_iter(),
        )
        {
            self.send_response(r);
        }

        self.dns.tick();
        self.dht.tick();
    }

    fn handle_socket(&mut self, event: amy::Notification) {
        if self.http.contains(event.id) {
            let resp = if event.event.readable() {
                self.http.readable(event.id, &mut self.dns)
            } else {
                self.http.writable(event.id)
            };
            if let Some(r) = resp {
                self.send_response(r);
            }
        } else if self.udp.id() == event.id {
            for resp in self.udp.readable() {
                self.send_response(resp);
            }
        } else if self.dht.id() == event.id {
            for resp in self.dht.readable() {
                self.send_response(resp);
            }
        } else if self.dns.contains(event.id) {
            if event.event.readable() {
                self.dns.readable(event.id);
            } else {
                self.dns.writable(event.id);
            }
        } else {
            unreachable!();
        };

    }

    fn send_response(&mut self, r: Response) {
        if !self.shutting_down {
            debug!("Sending trk response to control!");
            self.ch.send(r).unwrap();
        }
        // TODO: The active announce queue could grow with DHT usage,
        // since DHT stuff doesn't go into the announce queue, but still triggers send_response.
        // Not a big deal, but worth thinking about for later.
        self.dequeue_req();
    }
}

impl Request {
    pub fn new_announce<T: cio::CIO>(torrent: &Torrent<T>, event: Option<Event>) -> Request {
        Request::Announce(Announce {
            id: torrent.id(),
            url: torrent.info().announce.clone(),
            hash: torrent.info().hash,
            port: CONFIG.port,
            uploaded: torrent.uploaded(),
            downloaded: torrent.downloaded(),
            // This should be fine because the true len is usually slightly less than
            // piece_len * pieces_dld (due to shorter last piece), so we always get
            // either the correct amount left or 0.
            left: torrent.info().total_len.saturating_sub(
                torrent.pieces().iter().count() as u64 *
                    torrent.info().piece_len as u64,
            ),
            // TODO: Develop better heuristics here.
            // For now, only request peers if we're leeching,
            // let existing peers connect otherwise
            num_want: if torrent.complete() { None } else { Some(50) },
            event,
        })
    }

    pub fn started<T: cio::CIO>(torrent: &Torrent<T>) -> Request {
        Request::new_announce(torrent, Some(Event::Started))
    }

    pub fn stopped<T: cio::CIO>(torrent: &Torrent<T>) -> Request {
        Request::new_announce(torrent, Some(Event::Stopped))
    }

    pub fn completed<T: cio::CIO>(torrent: &Torrent<T>) -> Request {
        Request::new_announce(torrent, Some(Event::Completed))
    }

    pub fn interval<T: cio::CIO>(torrent: &Torrent<T>) -> Request {
        Request::new_announce(torrent, None)
    }
}

impl TrackerResponse {
    pub fn empty() -> TrackerResponse {
        TrackerResponse {
            peers: vec![],
            interval: 900,
            leechers: 0,
            seeders: 0,
            dht: false,
        }
    }

    pub fn dht() -> TrackerResponse {
        TrackerResponse {
            peers: vec![],
            interval: 0,
            leechers: 0,
            seeders: 0,
            dht: true,
        }
    }

    pub fn from_bencode(data: BEncode) -> Result<TrackerResponse> {
        let mut d = data.into_dict().ok_or(ErrorKind::InvalidResponse(
            "Tracker response must be a dictionary type!",
        ))?;
        if let Some(BEncode::String(data)) = d.remove("failure reason") {
            let reason = String::from_utf8(data).chain_err(|| {
                ErrorKind::InvalidResponse("Failure reason must be UTF8!")
            })?;
            return Err(ErrorKind::TrackerError(reason).into());
        }
        let mut resp = TrackerResponse::empty();
        match d.remove("peers") {
            Some(BEncode::String(ref data)) => {
                for p in data.chunks(6) {
                    let ip = Ipv4Addr::new(p[0], p[1], p[2], p[3]);
                    let socket = SocketAddrV4::new(ip, (&p[4..]).read_u16::<BigEndian>().unwrap());
                    resp.peers.push(SocketAddr::V4(socket));
                }
            }
            _ => {}
        };
        match d.remove("interval") {
            Some(BEncode::Int(ref i)) => {
                resp.interval = *i as u32;
            }
            _ => {
                return Err(
                    ErrorKind::InvalidResponse("Response must have interval!").into(),
                );
            }
        };
        Ok(resp)
    }
}
<commit_msg>Don't unwrap tracker polls<commit_after>mod http;
mod udp;
mod errors;
mod dns;
mod dht;

use std::collections::VecDeque;
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};
use std::{result, io, thread};

use byteorder::{BigEndian, ReadBytesExt};
use url::Url;
use amy;

pub use self::errors::{Result, ResultExt, Error, ErrorKind};
use torrent::Torrent;
use bencode::BEncode;
use control::cio;
use handle;
use disk;
use CONFIG;

pub struct Tracker {
    poll: amy::Poller,
    ch: handle::Handle<Request, Response>,
    dns_res: amy::Receiver<dns::QueryResponse>,
    http: http::Handler,
    queue: VecDeque<Announce>,
    udp: udp::Handler,
    dht: dht::Manager,
    dns: dns::Resolver,
    timer: usize,
    shutting_down: bool,
}

#[derive(Debug)]
pub enum Request {
    Announce(Announce),
    GetPeers(GetPeers),
    AddNode(SocketAddr),
    DHTAnnounce([u8; 20]),
    Shutdown,
}

#[derive(Debug)]
pub struct Announce {
    id: usize,
    url: String,
    hash: [u8; 20],
    port: u16,
    uploaded: u64,
    downloaded: u64,
    left: u64,
    num_want: Option<u16>,
    event: Option<Event>,
}

#[derive(Debug)]
pub struct GetPeers {
    pub id: usize,
    pub hash: [u8; 20],
}

#[derive(Debug)]
pub enum Event {
    Started,
    Stopped,
    Completed,
}

pub type Response = (usize, Result<TrackerResponse>);

#[derive(Debug)]
pub struct TrackerResponse {
    pub peers: Vec<SocketAddr>,
    pub dht: bool,
    pub interval: u32,
    pub leechers: u32,
    pub seeders: u32,
}

const POLL_INT_MS: usize = 1000;

impl Tracker {
    pub fn start(
        creg: &mut amy::Registrar,
        db: amy::Sender<disk::Request>,
    ) -> io::Result<(handle::Handle<Response, Request>, thread::JoinHandle<()>)> {
        let poll = amy::Poller::new()?;
        let mut reg = poll.get_registrar()?;
        let (ch, dh) = handle::Handle::new(creg, &mut reg)?;
        let timer = reg.set_interval(150)?;
        let (dtx, drx) = reg.channel()?;
        let udp = udp::Handler::new(&reg)?;
        let dht = dht::Manager::new(&reg, db)?;
        let http = http::Handler::new(&reg)?;
        let dns = dns::Resolver::new(reg, dtx);
        let th = dh.run("trk", move |h| {
            Tracker {
                poll,
                ch: h,
                udp,
                dht,
                http,
                dns,
                dns_res: drx,
                timer,
                queue: VecDeque::new(),
                shutting_down: false,
            }.run()
        })?;
        Ok((ch, th))
    }

    pub fn run(&mut self) {
        self.dht.init();

        debug!("Initialized!");
        'outer: loop {
            match self.poll.wait(POLL_INT_MS) {
                Ok(events) => {
                    for event in events {
                        if self.handle_event(event).is_err() {
                            break 'outer;
                        }
                    }
                }
                Err(e) => {
                    error!("Failed to poll for events: {:?}", e);
                }
            }
        }

        debug!("Shutting down!");
        self.shutting_down = true;

        // Shutdown loop - wait for all requests to complete
        loop {
            for event in self.poll.wait(POLL_INT_MS).unwrap() {
                if self.handle_event(event).is_err() {}
                if self.http.complete() && self.udp.complete() {
                    return;
                }
            }
        }
    }

    fn handle_event(&mut self, event: amy::Notification) -> result::Result<(), ()> {
        if event.id == self.ch.rx.get_id() {
            return self.handle_request();
        } else if event.id == self.dns_res.get_id() {
            self.handle_dns_res();
        } else if event.id == self.timer {
            self.handle_timer();
        } else {
            self.handle_socket(event);
        }
        Ok(())
    }

    fn handle_request(&mut self) -> result::Result<(), ()> {
        while let Ok(r) = self.ch.recv() {
            match r {
                Request::Announce(req) => self.handle_announce(req),
                Request::GetPeers(gp) => {
                    debug!("Handling dht peer find req!");
                    self.dht.get_peers(gp.id, gp.hash);
                }
                Request::AddNode(addr) => {
                    debug!("Handling dht node addition req!");
                    self.dht.add_addr(addr);
                }
                Request::DHTAnnounce(hash) => {
                    debug!("Handling dht announce req!");
                    self.dht.announce(hash);
                }
                Request::Shutdown => {
                    return Err(());
                }
            }
        }
        Ok(())
    }

    fn handle_announce(&mut self, req: Announce) {
        debug!("Handling announce request!");
        if self.udp.active_requests() + self.http.active_requests() >
            CONFIG.net.max_open_announces
        {
            self.queue.push_back(req);
        } else {
            let id = req.id;
            let response = if let Ok(url) = Url::parse(&req.url) {
                match url.scheme() {
                    "http" | "https" => self.http.new_announce(req, &url, &mut self.dns),
                    "udp" => self.udp.new_announce(req, &url, &mut self.dns),
                    s => Err(
                        ErrorKind::InvalidRequest(format!("Unknown tracker url scheme: {}", s))
                            .into(),
                    ),
                }
            } else {
                Err(
                    ErrorKind::InvalidRequest(format!("Invalid url: {}", req.url)).into(),
                )
            };
            if let Err(e) = response {
                self.send_response((id, Err(e)));
            }
        }
    }

    fn dequeue_req(&mut self) {
        // Attempt to dequeue next request if we can
        if let Some(a) = self.queue.pop_front() {
            self.handle_announce(a);
        }
    }

    fn handle_dns_res(&mut self) {
        while let Ok(r) = self.dns_res.try_recv() {
            let resp = if self.http.contains(r.id) {
                self.http.dns_resolved(r)
            } else if self.udp.contains(r.id) {
                self.udp.dns_resolved(r)
            } else {
                None
            };
            if let Some(r) = resp {
                self.send_response(r);
            }
        }
    }

    fn handle_timer(&mut self) {
        for r in self.http.tick().into_iter().chain(
            self.udp.tick().into_iter(),
        )
        {
            self.send_response(r);
        }

        self.dns.tick();
        self.dht.tick();
    }

    fn handle_socket(&mut self, event: amy::Notification) {
        if self.http.contains(event.id) {
            let resp = if event.event.readable() {
                self.http.readable(event.id, &mut self.dns)
            } else {
                self.http.writable(event.id)
            };
            if let Some(r) = resp {
                self.send_response(r);
            }
        } else if self.udp.id() == event.id {
            for resp in self.udp.readable() {
                self.send_response(resp);
            }
        } else if self.dht.id() == event.id {
            for resp in self.dht.readable() {
                self.send_response(resp);
            }
        } else if self.dns.contains(event.id) {
            if event.event.readable() {
                self.dns.readable(event.id);
            } else {
                self.dns.writable(event.id);
            }
        } else {
            unreachable!();
        };

    }

    fn send_response(&mut self, r: Response) {
        if !self.shutting_down {
            debug!("Sending trk response to control!");
            self.ch.send(r).unwrap();
        }
        // TODO: The active announce queue could grow with DHT usage,
        // since DHT stuff doesn't go into the announce queue, but still triggers send_response.
        // Not a big deal, but worth thinking about for later.
        self.dequeue_req();
    }
}

impl Request {
    pub fn new_announce<T: cio::CIO>(torrent: &Torrent<T>, event: Option<Event>) -> Request {
        Request::Announce(Announce {
            id: torrent.id(),
            url: torrent.info().announce.clone(),
            hash: torrent.info().hash,
            port: CONFIG.port,
            uploaded: torrent.uploaded(),
            downloaded: torrent.downloaded(),
            // This should be fine because the true len is usually slightly less than
            // piece_len * pieces_dld (due to shorter last piece), so we always get
            // either the correct amount left or 0.
            left: torrent.info().total_len.saturating_sub(
                torrent.pieces().iter().count() as u64 *
                    torrent.info().piece_len as u64,
            ),
            // TODO: Develop better heuristics here.
            // For now, only request peers if we're leeching,
            // let existing peers connect otherwise
            num_want: if torrent.complete() { None } else { Some(50) },
            event,
        })
    }

    pub fn started<T: cio::CIO>(torrent: &Torrent<T>) -> Request {
        Request::new_announce(torrent, Some(Event::Started))
    }

    pub fn stopped<T: cio::CIO>(torrent: &Torrent<T>) -> Request {
        Request::new_announce(torrent, Some(Event::Stopped))
    }

    pub fn completed<T: cio::CIO>(torrent: &Torrent<T>) -> Request {
        Request::new_announce(torrent, Some(Event::Completed))
    }

    pub fn interval<T: cio::CIO>(torrent: &Torrent<T>) -> Request {
        Request::new_announce(torrent, None)
    }
}

impl TrackerResponse {
    pub fn empty() -> TrackerResponse {
        TrackerResponse {
            peers: vec![],
            interval: 900,
            leechers: 0,
            seeders: 0,
            dht: false,
        }
    }

    pub fn dht() -> TrackerResponse {
        TrackerResponse {
            peers: vec![],
            interval: 0,
            leechers: 0,
            seeders: 0,
            dht: true,
        }
    }

    pub fn from_bencode(data: BEncode) -> Result<TrackerResponse> {
        let mut d = data.into_dict().ok_or(ErrorKind::InvalidResponse(
            "Tracker response must be a dictionary type!",
        ))?;
        if let Some(BEncode::String(data)) = d.remove("failure reason") {
            let reason = String::from_utf8(data).chain_err(|| {
                ErrorKind::InvalidResponse("Failure reason must be UTF8!")
            })?;
            return Err(ErrorKind::TrackerError(reason).into());
        }
        let mut resp = TrackerResponse::empty();
        match d.remove("peers") {
            Some(BEncode::String(ref data)) => {
                for p in data.chunks(6) {
                    let ip = Ipv4Addr::new(p[0], p[1], p[2], p[3]);
                    let socket = SocketAddrV4::new(ip, (&p[4..]).read_u16::<BigEndian>().unwrap());
                    resp.peers.push(SocketAddr::V4(socket));
                }
            }
            _ => {}
        };
        match d.remove("interval") {
            Some(BEncode::Int(ref i)) => {
                resp.interval = *i as u32;
            }
            _ => {
                return Err(
                    ErrorKind::InvalidResponse("Response must have interval!").into(),
                );
            }
        };
        Ok(resp)
    }
}
<|endoftext|>


<commit_before>type Node<T> = Option<Box<Link<T>>>;

struct Link<T> {
    value: T,
    next: Node<T>,
}

struct LinkedList<T> {
    head: Link<T>,
}

impl<T> LinkedList<T> {
    pub fn new(value: T) -> LinkedList<T> {
        LinkedList{head: Link{value: value, next: None}}
    }

    pub fn insert(&self, value: T) -> LinkedList<T> {
        let h = self.head;
        LinkedList{head: Link{value: value, next: Some(Box::new(h))}}
    }
}

#[test]
fn it_works() {
    let ll = LinkedList::new(1);
}
<commit_msg>LinkedList compiling<commit_after>type Node<T> = Option<Box<Link<T>>>;

struct Link<T> {
    value: T,
    next: Node<T>,
}

struct LinkedList<T> {
    head: Option<Link<T>>,
}

impl<T> LinkedList<T> {
    pub fn new() -> LinkedList<T> {
        LinkedList{head: None}
    }

    pub fn insert(&mut self, value: T) -> LinkedList<T> {
        let h = match self.head.take() {
            Some(n) => Some(Link{value: value, next: Some(Box::new(n))}),
            None => None,
        };

        LinkedList{head: h}
    }
}

#[test]
fn it_works() {
    let mut ll: LinkedList<i32> = LinkedList::new();
    ll.insert(1);
    ll.insert(2);
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Node manager.

use super::{encode_contract_name, to_address_vec, to_low_u64_vec};
use super::ContractCallExt;
use libexecutor::executor::Executor;
use rand::{Rng, SeedableRng, StdRng};
use rustc_hex::ToHex;
use std::cmp::Ordering;
use std::iter;
use std::str::FromStr;
use util::{Address, H160};

const LIST_NODE: &'static [u8] = &*b"listNode()";
const LIST_STAKE: &'static [u8] = *&b"listStake()";
/// Each epoch is divided into 1000 slots, each slot represent one opportunity of block proposer
const EPOCH: u64 = 1000;

lazy_static! {
    static ref LIST_NODE_ENCODED: Vec<u8> = encode_contract_name(LIST_NODE);
    static ref LIST_STAKE_ENCODED: Vec<u8> = encode_contract_name(LIST_STAKE);
    static ref CONTRACT_ADDRESS: H160 = H160::from_str("00000000000000000000000000000000013241a2").unwrap();
}

pub fn party_seats<T>(parties: Vec<T>, seats: &[u64]) -> Vec<T>
where
    T: Clone,
{
    let mut party_seats: Vec<T> = Vec::new();
    let seats_len = seats.len();
    for (index, party) in parties.into_iter().enumerate() {
        if index < seats_len {
            party_seats.extend(iter::repeat(party).take(seats[index] as usize));
        }
    }
    party_seats
}

/// https://en.wikipedia.org/wiki/Largest_remainder_method
/// Hare quota
pub fn largest_remainder_electoral(votes: &Vec<u64>, seat_number: u64) -> Vec<u64> {
    let total = votes.iter().fold(0, |acc, &x| acc + x);
    // TODO: PLS fix me!!!
    let hare_quota = total as f64 / seat_number as f64;

    let votes_quota: Vec<f64> = votes
        .iter()
        .map(|vote| (*vote as f64) / hare_quota)
        .collect();

    // calculate automatic seats first
    let mut seats: Vec<u64> = votes_quota.iter().map(|v| v.floor() as u64).collect();

    let mut remainders: Vec<(f64, u64)> = votes_quota
        .iter()
        .enumerate()
        .map(|(i, v)| (v.fract(), i as u64))
        .collect();

    let remaining_seat: u64 = seat_number - seats.iter().fold(0, |acc, &x| acc + x);

    remainders.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal));
    remainders.reverse();

    let highest_remainder_seats: Vec<u64> = remainders
        .iter()
        .take(remaining_seat as usize)
        .map(|v| v.1)
        .collect();

    for index in highest_remainder_seats {
        seats[index as usize] += 1;
    }

    seats
}

pub struct NodeManager;

impl NodeManager {
    pub fn nodes(executor: &Executor) -> Vec<Address> {
        let output = executor.call_method_latest(&*CONTRACT_ADDRESS, &*LIST_NODE_ENCODED.as_slice());
        trace!(
            "node manager output: {:?}",
            ToHex::to_hex(output.as_slice())
        );

        let nodes: Vec<Address> = to_address_vec(&output);
        trace!("node manager nodes: {:?}", nodes);
        nodes
    }

    pub fn shuffle_node<T>(node_vec: &mut Vec<T>, rng_seed: u64) {
        let seed: &[_] = &[rng_seed as usize];
        let mut rng: StdRng = SeedableRng::from_seed(seed);

        for i in 0..node_vec.len() {
            let j: usize = rng.gen::<usize>() % (i + 1);
            node_vec.swap(i, j);
        }
    }

    pub fn stakes(executor: &Executor) -> Vec<u64> {
        let output = executor.call_method_latest(&*CONTRACT_ADDRESS, &*LIST_STAKE_ENCODED.as_slice());
        trace!("stakes output: {:?}", ToHex::to_hex(output.as_slice()));

        let stakes: Vec<u64> = to_low_u64_vec(&output);
        trace!("node manager stakes: {:?}", stakes);
        stakes
    }

    pub fn stake_nodes(exeuctor: &Executor) -> Vec<Address> {
        let nodes = NodeManager::nodes(&exeuctor);
        let stakes = NodeManager::stakes(&exeuctor);
        let total = stakes.iter().fold(0, |acc, &x| acc + x);
        let stake_nodes: Vec<Address>;

        if total == 0 {
            stake_nodes = nodes;
        } else {
            let total_seats = largest_remainder_electoral(&stakes, EPOCH);
            stake_nodes = party_seats(nodes, &total_seats);
        }
        stake_nodes
=======
            if j != i {
                ret[i] = ret[j];
            }
            ret[j] = node_vec[i];
        }
        ret
>>>>>>> provide the random-shuffle function
    }
}

#[cfg(test)]
mod tests {
    extern crate logger;
    extern crate mktemp;

    use super::{largest_remainder_electoral, party_seats, NodeManager};
    use std::str::FromStr;
    use tests::helpers::init_executor;
    use util::H160;

    #[test]
    fn test_node_manager_contract() {
        let executor = init_executor();
        let nodes = NodeManager::nodes(&executor);

        assert_eq!(
            nodes,
            vec![
                H160::from_str("50ad2b9d6946d9c75ae978534043e3021ee1bfb1").unwrap(),
                H160::from_str("eeb3a71c4046f63a941013f826fccc503be26b77").unwrap(),
                H160::from_str("a2bbb65d4f8c3ada29f7471abe416e18061127f3").unwrap(),
                H160::from_str("72eb1e258c9cdccebb7b62930a35cfb6ef4cd24b").unwrap(),
            ]
        )
    }

    #[test]
    fn test_largest_remainder_electoral() {
        let votes = vec![47_000, 16_000, 15_800, 12_000, 6_100, 3_100];
        let seats = 10;
        let total_seats = largest_remainder_electoral(&votes, seats);
        assert_eq!(vec![5, 2, 1, 1, 1, 0], total_seats);
    }

    #[test]
    fn test_largest_remainder_electoral_again() {
        let votes = vec![1500, 1500, 900, 500, 500, 200];
        let seats = 25;
        let total_seats = largest_remainder_electoral(&votes, seats);
        assert_eq!(vec![7, 7, 4, 3, 3, 1], total_seats);

        let new_seats = 26;
        let new_total_seats = largest_remainder_electoral(&votes, new_seats);
        assert_eq!(vec![8, 8, 5, 2, 2, 1], new_total_seats);
    }

    #[test]
    fn test_party_seats() {
        let parties = vec!["a", "b", "c"];
        let seats = vec![3, 5, 2, 2, 1];
        assert_eq!(
            party_seats(parties, &seats),
            vec!["a", "a", "a", "b", "b", "b", "b", "b", "c", "c"]
        );

        let parties = vec!["a", "b"];
        let seats = vec![2, 1];
        assert_eq!(party_seats(parties, &seats), vec!["a", "a", "b"]);

        let parties = vec!["a", "b", "c"];
        let seats = vec![2, 2];
        assert_eq!(party_seats(parties, &seats), vec!["a", "a", "b", "b"]);
    }
}
<commit_msg>change it to generic version<commit_after>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Node manager.

use super::{encode_contract_name, to_address_vec, to_low_u64_vec};
use super::ContractCallExt;
use libexecutor::executor::Executor;
use rand::{Rng, SeedableRng, StdRng};
use rustc_hex::ToHex;
use std::cmp::Ordering;
use std::iter;
use std::str::FromStr;
use util::{Address, H160};

const LIST_NODE: &'static [u8] = &*b"listNode()";
const LIST_STAKE: &'static [u8] = *&b"listStake()";
/// Each epoch is divided into 1000 slots, each slot represent one opportunity of block proposer
const EPOCH: u64 = 1000;

lazy_static! {
    static ref LIST_NODE_ENCODED: Vec<u8> = encode_contract_name(LIST_NODE);
    static ref LIST_STAKE_ENCODED: Vec<u8> = encode_contract_name(LIST_STAKE);
    static ref CONTRACT_ADDRESS: H160 = H160::from_str("00000000000000000000000000000000013241a2").unwrap();
}

pub fn party_seats<T>(parties: Vec<T>, seats: &[u64]) -> Vec<T>
where
    T: Clone,
{
    let mut party_seats: Vec<T> = Vec::new();
    let seats_len = seats.len();
    for (index, party) in parties.into_iter().enumerate() {
        if index < seats_len {
            party_seats.extend(iter::repeat(party).take(seats[index] as usize));
        }
    }
    party_seats
}

/// https://en.wikipedia.org/wiki/Largest_remainder_method
/// Hare quota
pub fn largest_remainder_electoral(votes: &Vec<u64>, seat_number: u64) -> Vec<u64> {
    let total = votes.iter().fold(0, |acc, &x| acc + x);
    // TODO: PLS fix me!!!
    let hare_quota = total as f64 / seat_number as f64;

    let votes_quota: Vec<f64> = votes
        .iter()
        .map(|vote| (*vote as f64) / hare_quota)
        .collect();

    // calculate automatic seats first
    let mut seats: Vec<u64> = votes_quota.iter().map(|v| v.floor() as u64).collect();

    let mut remainders: Vec<(f64, u64)> = votes_quota
        .iter()
        .enumerate()
        .map(|(i, v)| (v.fract(), i as u64))
        .collect();

    let remaining_seat: u64 = seat_number - seats.iter().fold(0, |acc, &x| acc + x);

    remainders.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal));
    remainders.reverse();

    let highest_remainder_seats: Vec<u64> = remainders
        .iter()
        .take(remaining_seat as usize)
        .map(|v| v.1)
        .collect();

    for index in highest_remainder_seats {
        seats[index as usize] += 1;
    }

    seats
}

pub struct NodeManager;

impl NodeManager {
    pub fn nodes(executor: &Executor) -> Vec<Address> {
        let output = executor.call_method_latest(&*CONTRACT_ADDRESS, &*LIST_NODE_ENCODED.as_slice());
        trace!(
            "node manager output: {:?}",
            ToHex::to_hex(output.as_slice())
        );

        let nodes: Vec<Address> = to_address_vec(&output);
        trace!("node manager nodes: {:?}", nodes);
        nodes
    }
<<<<<<< HEAD

=======

>>>>>>> change it to generic version
    pub fn shuffle_node<T>(node_vec: &mut Vec<T>, rng_seed: u64) {
        let seed: &[_] = &[rng_seed as usize];
        let mut rng: StdRng = SeedableRng::from_seed(seed);

        for i in 0..node_vec.len() {
            let j: usize = rng.gen::<usize>() % (i + 1);
            node_vec.swap(i, j);
<<<<<<< HEAD
        }
    }

    pub fn stakes(executor: &Executor) -> Vec<u64> {
        let output = executor.call_method_latest(&*CONTRACT_ADDRESS, &*LIST_STAKE_ENCODED.as_slice());
        trace!("stakes output: {:?}", ToHex::to_hex(output.as_slice()));

        let stakes: Vec<u64> = to_low_u64_vec(&output);
        trace!("node manager stakes: {:?}", stakes);
        stakes
    }

    pub fn stake_nodes(exeuctor: &Executor) -> Vec<Address> {
        let nodes = NodeManager::nodes(&exeuctor);
        let stakes = NodeManager::stakes(&exeuctor);
        let total = stakes.iter().fold(0, |acc, &x| acc + x);
        let stake_nodes: Vec<Address>;

        if total == 0 {
            stake_nodes = nodes;
        } else {
            let total_seats = largest_remainder_electoral(&stakes, EPOCH);
            stake_nodes = party_seats(nodes, &total_seats);
        }
        stake_nodes
    }
}

#[cfg(test)]
mod tests {
    extern crate logger;
    extern crate mktemp;

    use super::{largest_remainder_electoral, party_seats, NodeManager};
    use std::str::FromStr;
    use tests::helpers::init_executor;
    use util::H160;

    #[test]
    fn test_node_manager_contract() {
        let executor = init_executor();
        let nodes = NodeManager::nodes(&executor);

        assert_eq!(
            nodes,
            vec![
                H160::from_str("50ad2b9d6946d9c75ae978534043e3021ee1bfb1").unwrap(),
                H160::from_str("eeb3a71c4046f63a941013f826fccc503be26b77").unwrap(),
                H160::from_str("a2bbb65d4f8c3ada29f7471abe416e18061127f3").unwrap(),
                H160::from_str("72eb1e258c9cdccebb7b62930a35cfb6ef4cd24b").unwrap(),
            ]
        )
    }

    #[test]
    fn test_largest_remainder_electoral() {
        let votes = vec![47_000, 16_000, 15_800, 12_000, 6_100, 3_100];
        let seats = 10;
        let total_seats = largest_remainder_electoral(&votes, seats);
        assert_eq!(vec![5, 2, 1, 1, 1, 0], total_seats);
    }

    #[test]
    fn test_largest_remainder_electoral_again() {
        let votes = vec![1500, 1500, 900, 500, 500, 200];
        let seats = 25;
        let total_seats = largest_remainder_electoral(&votes, seats);
        assert_eq!(vec![7, 7, 4, 3, 3, 1], total_seats);

        let new_seats = 26;
        let new_total_seats = largest_remainder_electoral(&votes, new_seats);
        assert_eq!(vec![8, 8, 5, 2, 2, 1], new_total_seats);
    }

    #[test]
    fn test_party_seats() {
        let parties = vec!["a", "b", "c"];
        let seats = vec![3, 5, 2, 2, 1];
        assert_eq!(
            party_seats(parties, &seats),
            vec!["a", "a", "a", "b", "b", "b", "b", "b", "c", "c"]
        );

        let parties = vec!["a", "b"];
        let seats = vec![2, 1];
        assert_eq!(party_seats(parties, &seats), vec!["a", "a", "b"]);

        let parties = vec!["a", "b", "c"];
        let seats = vec![2, 2];
        assert_eq!(party_seats(parties, &seats), vec!["a", "a", "b", "b"]);
    }
}
<|endoftext|>


<commit_before>use super::*;
use petgraph::algo;
use petgraph::prelude::{Outgoing, StableDiGraph};
use petgraph::visit::IntoEdgeReferences;

use quickcheck::TestResult;
use std::collections::HashMap;
use std::hash::Hash;
use std::iter::FromIterator;

/// Tests that `slice` returns an acyclic graph and a topological ordering.
#[quickcheck]
fn qc_slice(mut graph: StableDiGraph<(), ()>, start_i: usize, end_is: Vec<usize>) -> TestResult {
    let nodes: Vec<_> = graph.node_indices().collect();
    if nodes.is_empty() {
        return TestResult::discard();
    }
    let start = nodes[start_i % nodes.len()];
    let ends: IxBitSet<_> = end_is
        .into_iter()
        .map(|end_i| nodes[end_i % nodes.len()])
        .collect();
    println!("start: {:?}", start);
    println!("ends: {:?}", ends);
    let slice = slice(&graph, start, &ends);
    let trace_nodes = IxBitSet::from_iter(&slice.topo_order);
    if trace_nodes != slice.nodes {
        println!("wrong nodes in topo_order:");
        println!("  real: {:?}", slice.nodes);
        println!("  order: {:?}", slice.topo_order);
        return TestResult::failed();
    }
    graph.retain_nodes(|_, n| slice.nodes.contains(n));
    graph.retain_edges(|_, e| slice.edges.contains(e));
    if algo::is_cyclic_directed(&graph) {
        println!("cyclic slice:");
        println!("  slice: {:?}", graph);
        return TestResult::failed();
    }
    if !is_topological_ordering(&graph, &slice.topo_order) {
        println!("bad topological ordering: {:?}", slice.topo_order);
        println!("  slice: {:?}", graph);
        return TestResult::failed();
    }
    TestResult::passed()
}

/// Tests that `slice`ing a connected rooted acyclic graph is a no-op.
#[quickcheck]
fn qc_slice_acyclic(mut graph: StableDiGraph<(), ()>, root_i: usize) -> TestResult {
    let root = if let Some(root) = mk_rooted_stable_graph(&mut graph, root_i, true) {
        root
    } else {
        return TestResult::discard();
    };
    println!("graph: {:?}", graph);
    println!("root: {:?}", root);
    assert!(!algo::is_cyclic_directed(&graph));
    let sinks: IxBitSet<_> = graph
        .node_indices()
        .filter(|&n| graph.edges_directed(n, Outgoing).next().is_none())
        .collect();
    let slice = slice(&graph, root, &sinks);
    println!("slice_nodes: {:?}", slice.nodes);
    println!(
        "slice_edges: {:?}",
        slice
            .edges
            .iter()
            .map(|e| graph.edge_endpoints(e).unwrap())
            .collect::<Vec<_>>()
    );
    TestResult::from_bool(
        graph.node_indices().all(|n| slice.nodes.contains(n))
            && graph.edge_indices().all(|e| slice.edges.contains(e)),
    )
}

/// Tests that nearest common dominator works
#[quickcheck]
fn qc_nearest_common_dominator(
    mut graph: StableDiGraph<(), ()>,
    root_i: usize,
    in_node_is: Vec<usize>,
) -> TestResult {
    if in_node_is.is_empty() {
        return TestResult::discard();
    }
    let root = if let Some(root) = mk_rooted_stable_graph(&mut graph, root_i, false) {
        root
    } else {
        return TestResult::discard();
    };

    let nodes: Vec<_> = graph.node_indices().collect();
    let in_nodes: IxBitSet<_> = in_node_is
        .into_iter()
        .map(|in_node_i| nodes[in_node_i % nodes.len()])
        .collect();

    println!("graph: {:?}", graph);
    println!("root: {:?}", root);
    println!("in_nodes: {:?}", in_nodes);

    let dominators = algo::dominators::simple_fast(&graph, root);

    let ncd = nearest_common_dominator(&graph, root, &in_nodes);

    let mut common_dominators = in_nodes
        .iter()
        .map(|u| IxBitSet::from_iter(dominators.dominators(u).unwrap()))
        .fold(IxBitSet::from_iter(graph.node_indices()), |mut acc, x| {
            acc.intersect_with(&x);
            acc
        });
    // `ncd` dominates every node in `in_nodes`
    if !common_dominators.remove(ncd) {
        return TestResult::failed();
    }
    // `ncd` does not dominate any other common dominator
    for cand in &common_dominators {
        if dominators.dominators(cand).unwrap().any(|d| d == ncd) {
            return TestResult::failed();
        }
    }

    TestResult::passed()
}

#[quickcheck]
fn qc_dominated_by(mut graph: StableDiGraph<(), ()>, root_i: usize, h_i: usize) -> TestResult {
    let root = if let Some(root) = mk_rooted_stable_graph(&mut graph, root_i, false) {
        root
    } else {
        return TestResult::discard();
    };
    let nodes: Vec<_> = graph.node_indices().collect();
    let h = nodes[h_i % nodes.len()];

    let dominators = algo::dominators::simple_fast(&graph, root);
    let true_dom_set: IxBitSet<_> = graph
        .node_indices()
        .filter(|&n| dominators.dominators(n).unwrap().any(|d| d == h))
        .collect();

    let dom_set = dominated_by(&graph, root, h);

    TestResult::from_bool(dom_set == true_dom_set)
}

#[quickcheck]
fn qc_dag_transitive_closure(graph: StableDiGraph<(), ()>) -> TestResult {
    if algo::is_cyclic_directed(&graph) {
        return TestResult::discard();
    }

    let reachable_map = dag_transitive_closure(&graph);

    if reachable_map.len() != graph.node_count() {
        return TestResult::failed();
    }
    TestResult::from_bool(graph.node_indices().all(|n| {
        let dfs_reachable: IxBitSet<_> = Dfs::new(&graph, n).iter(&graph).collect();
        dfs_reachable == reachable_map[&n]
    }))
}

fn mk_rooted_stable_graph(
    graph: &mut StableDiGraph<(), ()>,
    root_i: usize,
    prune_cycles: bool,
) -> Option<NodeIndex> {
    let nodes: Vec<_> = graph.node_indices().collect();
    if nodes.is_empty() {
        return None;
    }
    let root = nodes[root_i % nodes.len()];
    let mut reachable = IxBitSet::new();
    let mut back_edges = IxBitSet::new();
    depth_first_search(&*graph, root, |ev| {
        use super::DfsEvent::*;
        match ev {
            Discover(n) => {
                reachable.insert(n);
            }
            BackEdge(e) => {
                back_edges.insert(e.id());
            }
            _ => (),
        }
    });
    if graph.node_indices().any(|n| !reachable.contains(n)) {
        return None;
    }
    // graph.retain_nodes(|_, n| reachable.contains(n));
    if prune_cycles {
        // discarding cyclic graphs make tests take too long
        // instead we just remove cycles
        graph.retain_edges(|_, e| !back_edges.contains(e));
    }
    Some(root)
}

fn is_topological_ordering<G>(graph: G, topo_order: &[G::NodeId]) -> bool
where
    G: IntoEdgeReferences,
    G::NodeId: Eq + Hash,
{
    let order_idx: HashMap<_, _> = topo_order
        .into_iter()
        .enumerate()
        .map(|(i, n)| (n, i))
        .collect();
    graph
        .edge_references()
        .all(|e| order_idx[&e.source()] < order_idx[&e.target()])
}
<commit_msg>[graph_utils] Fix `nearest_common_dominator` test<commit_after>use super::*;
use petgraph::algo;
use petgraph::prelude::{Outgoing, StableDiGraph};
use petgraph::visit::IntoEdgeReferences;

use quickcheck::TestResult;
use std::collections::HashMap;
use std::hash::Hash;
use std::iter::FromIterator;

/// Tests that `slice` returns an acyclic graph and a topological ordering.
#[quickcheck]
fn qc_slice(mut graph: StableDiGraph<(), ()>, start_i: usize, end_is: Vec<usize>) -> TestResult {
    let nodes: Vec<_> = graph.node_indices().collect();
    if nodes.is_empty() {
        return TestResult::discard();
    }
    let start = nodes[start_i % nodes.len()];
    let ends: IxBitSet<_> = end_is
        .into_iter()
        .map(|end_i| nodes[end_i % nodes.len()])
        .collect();
    println!("start: {:?}", start);
    println!("ends: {:?}", ends);
    let slice = slice(&graph, start, &ends);
    let trace_nodes = IxBitSet::from_iter(&slice.topo_order);
    if trace_nodes != slice.nodes {
        println!("wrong nodes in topo_order:");
        println!("  real: {:?}", slice.nodes);
        println!("  order: {:?}", slice.topo_order);
        return TestResult::failed();
    }
    graph.retain_nodes(|_, n| slice.nodes.contains(n));
    graph.retain_edges(|_, e| slice.edges.contains(e));
    if algo::is_cyclic_directed(&graph) {
        println!("cyclic slice:");
        println!("  slice: {:?}", graph);
        return TestResult::failed();
    }
    if !is_topological_ordering(&graph, &slice.topo_order) {
        println!("bad topological ordering: {:?}", slice.topo_order);
        println!("  slice: {:?}", graph);
        return TestResult::failed();
    }
    TestResult::passed()
}

/// Tests that `slice`ing a connected rooted acyclic graph is a no-op.
#[quickcheck]
fn qc_slice_acyclic(mut graph: StableDiGraph<(), ()>, root_i: usize) -> TestResult {
    let root = if let Some(root) = mk_rooted_stable_graph(&mut graph, root_i, true) {
        root
    } else {
        return TestResult::discard();
    };
    println!("graph: {:?}", graph);
    println!("root: {:?}", root);
    assert!(!algo::is_cyclic_directed(&graph));
    let sinks: IxBitSet<_> = graph
        .node_indices()
        .filter(|&n| graph.edges_directed(n, Outgoing).next().is_none())
        .collect();
    let slice = slice(&graph, root, &sinks);
    println!("slice_nodes: {:?}", slice.nodes);
    println!(
        "slice_edges: {:?}",
        slice
            .edges
            .iter()
            .map(|e| graph.edge_endpoints(e).unwrap())
            .collect::<Vec<_>>()
    );
    TestResult::from_bool(
        graph.node_indices().all(|n| slice.nodes.contains(n))
            && graph.edge_indices().all(|e| slice.edges.contains(e)),
    )
}

/// Tests that nearest common dominator works
#[quickcheck]
fn qc_nearest_common_dominator(
    mut graph: StableDiGraph<(), ()>,
    root_i: usize,
    in_node_is: Vec<usize>,
) -> TestResult {
    if in_node_is.is_empty() {
        return TestResult::discard();
    }
    let root = if let Some(root) = mk_rooted_stable_graph(&mut graph, root_i, true) {
        root
    } else {
        return TestResult::discard();
    };

    let nodes: Vec<_> = graph.node_indices().collect();
    let in_nodes: IxBitSet<_> = in_node_is
        .into_iter()
        .map(|in_node_i| nodes[in_node_i % nodes.len()])
        .collect();

    println!("graph: {:?}", graph);
    println!("root: {:?}", root);
    println!("in_nodes: {:?}", in_nodes);

    let dominators = algo::dominators::simple_fast(&graph, root);

    let ncd = nearest_common_dominator(&graph, root, &in_nodes);

    let mut common_dominators = in_nodes
        .iter()
        .map(|u| IxBitSet::from_iter(dominators.dominators(u).unwrap()))
        .fold(IxBitSet::from_iter(graph.node_indices()), |mut acc, x| {
            acc.intersect_with(&x);
            acc
        });
    // `ncd` dominates every node in `in_nodes`
    if !common_dominators.remove(ncd) {
        return TestResult::failed();
    }
    // `ncd` does not dominate any other common dominator
    for cand in &common_dominators {
        if dominators.dominators(cand).unwrap().any(|d| d == ncd) {
            return TestResult::failed();
        }
    }

    TestResult::passed()
}

#[quickcheck]
fn qc_dominated_by(mut graph: StableDiGraph<(), ()>, root_i: usize, h_i: usize) -> TestResult {
    let root = if let Some(root) = mk_rooted_stable_graph(&mut graph, root_i, false) {
        root
    } else {
        return TestResult::discard();
    };
    let nodes: Vec<_> = graph.node_indices().collect();
    let h = nodes[h_i % nodes.len()];

    let dominators = algo::dominators::simple_fast(&graph, root);
    let true_dom_set: IxBitSet<_> = graph
        .node_indices()
        .filter(|&n| dominators.dominators(n).unwrap().any(|d| d == h))
        .collect();

    let dom_set = dominated_by(&graph, root, h);

    TestResult::from_bool(dom_set == true_dom_set)
}

#[quickcheck]
fn qc_dag_transitive_closure(graph: StableDiGraph<(), ()>) -> TestResult {
    if algo::is_cyclic_directed(&graph) {
        return TestResult::discard();
    }

    let reachable_map = dag_transitive_closure(&graph);

    if reachable_map.len() != graph.node_count() {
        return TestResult::failed();
    }
    TestResult::from_bool(graph.node_indices().all(|n| {
        let dfs_reachable: IxBitSet<_> = Dfs::new(&graph, n).iter(&graph).collect();
        dfs_reachable == reachable_map[&n]
    }))
}

fn mk_rooted_stable_graph(
    graph: &mut StableDiGraph<(), ()>,
    root_i: usize,
    prune_cycles: bool,
) -> Option<NodeIndex> {
    let nodes: Vec<_> = graph.node_indices().collect();
    if nodes.is_empty() {
        return None;
    }
    let root = nodes[root_i % nodes.len()];
    let mut reachable = IxBitSet::new();
    let mut back_edges = IxBitSet::new();
    depth_first_search(&*graph, root, |ev| {
        use super::DfsEvent::*;
        match ev {
            Discover(n) => {
                reachable.insert(n);
            }
            BackEdge(e) => {
                back_edges.insert(e.id());
            }
            _ => (),
        }
    });
    if graph.node_indices().any(|n| !reachable.contains(n)) {
        return None;
    }
    // graph.retain_nodes(|_, n| reachable.contains(n));
    if prune_cycles {
        // discarding cyclic graphs make tests take too long
        // instead we just remove cycles
        graph.retain_edges(|_, e| !back_edges.contains(e));
    }
    Some(root)
}

fn is_topological_ordering<G>(graph: G, topo_order: &[G::NodeId]) -> bool
where
    G: IntoEdgeReferences,
    G::NodeId: Eq + Hash,
{
    let order_idx: HashMap<_, _> = topo_order
        .into_iter()
        .enumerate()
        .map(|(i, n)| (n, i))
        .collect();
    graph
        .edge_references()
        .all(|e| order_idx[&e.source()] < order_idx[&e.target()])
}
<|endoftext|>