<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// rustpkg unit tests

use context::Ctx;
use core::hashmap::HashMap;
use core::path::Path;
use core::prelude::*;
use std::tempfile::mkdtemp;
use util::{PkgId, default_version};
use path_util::{target_executable_in_workspace, target_library_in_workspace,
               target_test_in_workspace, target_bench_in_workspace,
               make_dir_rwx, u_rwx, RemotePath, LocalPath, normalize,
               built_bench_in_workspace, built_test_in_workspace};

fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
    Ctx {
        sysroot_opt: sysroot_opt,
        json: false,
        dep_cache: @mut HashMap::new()
    }
}

fn fake_pkg() -> PkgId {
    let sn = ~"bogus";
    let remote = RemotePath(Path(sn));
    PkgId {
        local_path: normalize(copy remote),
        remote_path: remote,
        short_name: sn,
        version: default_version()
    }
}

fn remote_pkg() -> PkgId {
    let remote = RemotePath(Path(~"github.com/catamorphism/test-pkg"));
    PkgId {
        local_path: normalize(copy remote),
        remote_path: remote,
        short_name: ~"test_pkg",
        version: default_version()
    }
}

fn writeFile(file_path: &Path, contents: ~str) {
    let out: @io::Writer =
        result::get(&io::file_writer(file_path,
                                     ~[io::Create, io::Truncate]));
    out.write_line(contents);
}

fn mk_temp_workspace(short_name: &LocalPath) -> Path {
    let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
    // include version number in directory name
    let package_dir = workspace.push(~"src").push(fmt!("%s-0.1", short_name.to_str()));
    assert!(os::mkdir_recursive(&package_dir, u_rwx));
    // Create main, lib, test, and bench files
    writeFile(&package_dir.push(~"main.rs"),
              ~"fn main() { let _x = (); }");
    writeFile(&package_dir.push(~"lib.rs"),
              ~"pub fn f() { let _x = (); }");
    writeFile(&package_dir.push(~"test.rs"),
              ~"#[test] pub fn f() { (); }");
    writeFile(&package_dir.push(~"bench.rs"),
              ~"#[bench] pub fn f() { (); }");
    workspace
}

fn is_rwx(p: &Path) -> bool {
    use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};

    match p.get_mode() {
        None => return false,
        Some(m) =>
            ((m & S_IRUSR as uint) == S_IRUSR as uint
            && (m & S_IWUSR as uint) == S_IWUSR as uint
            && (m & S_IXUSR as uint) == S_IXUSR as uint)
    }
}

fn test_sysroot() -> Path {
    // Totally gross hack but it's just for test cases.
    // Infer the sysroot from the exe name and pray that it's right.
    // (Did I mention it was a gross hack?)
    let self_path = os::self_exe_path().expect("Couldn't get self_exe path");
    self_path.pop()
}

// Ignored on i686 -- see #6517
#[test]
#[ignore(cfg(target_arch = "x86"))]
fn test_make_dir_rwx() {
    let temp = &os::tmpdir();
    let dir = temp.push(~"quux");
    assert!(!os::path_exists(&dir) ||
            os::remove_dir_recursive(&dir));
    debug!("Trying to make %s", dir.to_str());
    assert!(make_dir_rwx(&dir));
    assert!(os::path_is_dir(&dir));
    assert!(is_rwx(&dir));
    assert!(os::remove_dir_recursive(&dir));
}

#[test]
#[ignore(cfg(target_arch = "x86"))]
fn test_install_valid() {
    let sysroot = test_sysroot();
    debug!("sysroot = %s", sysroot.to_str());
    let ctxt = fake_ctxt(Some(@sysroot));
    let temp_pkg_id = fake_pkg();
    let temp_workspace = mk_temp_workspace(&temp_pkg_id.local_path);
    // should have test, bench, lib, and main
    ctxt.install(&temp_workspace, &temp_pkg_id);
    // Check that all files exist
    let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("exec = %s", exec.to_str());
    assert!(os::path_exists(&exec));
    assert!(is_rwx(&exec));
    let lib = target_library_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("lib = %s", lib.to_str());
    assert!(os::path_exists(&lib));
    assert!(is_rwx(&lib));
    // And that the test and bench executables aren't installed
    assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace)));
    let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("bench = %s", bench.to_str());
    assert!(!os::path_exists(&bench));
}

#[test]
#[ignore(cfg(target_arch = "x86"))]
fn test_install_invalid() {
    use conditions::nonexistent_package::cond;
    use cond1 = conditions::missing_pkg_files::cond;

    let ctxt = fake_ctxt(None);
    let pkgid = fake_pkg();
    let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
    let mut error_occurred = false;
    let mut error1_occurred = false;
    do cond1.trap(|_| {
        error1_occurred = true;
    }).in {
        do cond.trap(|_| {
            error_occurred = true;
        }).in {
            ctxt.install(&temp_workspace, &pkgid);
        }
    }
    assert!(error_occurred && error1_occurred);
}

#[test]
#[ignore(cfg(target_arch = "x86"))]
fn test_install_url() {
    let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
    let sysroot = test_sysroot();
    debug!("sysroot = %s", sysroot.to_str());
    let ctxt = fake_ctxt(Some(@sysroot));
    let temp_pkg_id = remote_pkg();
    // should have test, bench, lib, and main
    ctxt.install(&workspace, &temp_pkg_id);
    // Check that all files exist
    let exec = target_executable_in_workspace(&temp_pkg_id, &workspace);
    debug!("exec = %s", exec.to_str());
    assert!(os::path_exists(&exec));
    assert!(is_rwx(&exec));
    let lib = target_library_in_workspace(&temp_pkg_id, &workspace);
    debug!("lib = %s", lib.to_str());
    assert!(os::path_exists(&lib));
    assert!(is_rwx(&lib));
    let built_test = built_test_in_workspace(&temp_pkg_id, &workspace).expect(~"test_install_url");
    assert!(os::path_exists(&built_test));
    let built_bench = built_bench_in_workspace(&temp_pkg_id,
                                               &workspace).expect(~"test_install_url");
    assert!(os::path_exists(&built_bench));
    // And that the test and bench executables aren't installed
    let test = target_test_in_workspace(&temp_pkg_id, &workspace);
    assert!(!os::path_exists(&test));
    debug!("test = %s", test.to_str());
    let bench = target_bench_in_workspace(&temp_pkg_id, &workspace);
    debug!("bench = %s", bench.to_str());
    assert!(!os::path_exists(&bench));
}

#[test]
fn test_package_ids_must_be_relative_path_like() {
    use conditions::bad_pkg_id::cond;

    /*
    Okay:
    - One identifier, with no slashes
    - Several slash-delimited things, with no / at the root

    Not okay:
    - Empty string
    - Absolute path (as per os::is_absolute)

    */

    let default_version_str = "0.1";
    let addversion = |s| {
        fmt!("%s-%s", s, default_version_str)
    };

    let whatever = PkgId::new("foo");

    assert_eq!(addversion("foo"), whatever.to_str());
    assert!(addversion("github.com/mozilla/rust") ==
            PkgId::new("github.com/mozilla/rust").to_str());

    do cond.trap(|(p, e)| {
        assert!("" == p.to_str());
        assert!("0-length pkgid" == e);
        copy whatever
    }).in {
        let x = PkgId::new("");
        assert_eq!(addversion("foo"), x.to_str());
    }

    do cond.trap(|(p, e)| {
        assert_eq!(p.to_str(), os::make_absolute(&Path("foo/bar/quux")).to_str());
        assert!("absolute pkgid" == e);
        copy whatever
    }).in {
        let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str());
        assert_eq!(addversion("foo"), z.to_str());
    }

}
<commit_msg>cleanup warnings from librustpkg<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// rustpkg unit tests

use context::Ctx;
use core::hashmap::HashMap;
use core::prelude::*;
use std::tempfile::mkdtemp;
use util::{PkgId, default_version};
use path_util::{target_executable_in_workspace, target_library_in_workspace,
               target_test_in_workspace, target_bench_in_workspace,
               make_dir_rwx, u_rwx, RemotePath, LocalPath, normalize,
               built_bench_in_workspace, built_test_in_workspace};

fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
    Ctx {
        sysroot_opt: sysroot_opt,
        json: false,
        dep_cache: @mut HashMap::new()
    }
}

fn fake_pkg() -> PkgId {
    let sn = ~"bogus";
    let remote = RemotePath(Path(sn));
    PkgId {
        local_path: normalize(copy remote),
        remote_path: remote,
        short_name: sn,
        version: default_version()
    }
}

fn remote_pkg() -> PkgId {
    let remote = RemotePath(Path(~"github.com/catamorphism/test-pkg"));
    PkgId {
        local_path: normalize(copy remote),
        remote_path: remote,
        short_name: ~"test_pkg",
        version: default_version()
    }
}

fn writeFile(file_path: &Path, contents: ~str) {
    let out: @io::Writer =
        result::get(&io::file_writer(file_path,
                                     ~[io::Create, io::Truncate]));
    out.write_line(contents);
}

fn mk_temp_workspace(short_name: &LocalPath) -> Path {
    let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
    // include version number in directory name
    let package_dir = workspace.push(~"src").push(fmt!("%s-0.1", short_name.to_str()));
    assert!(os::mkdir_recursive(&package_dir, u_rwx));
    // Create main, lib, test, and bench files
    writeFile(&package_dir.push(~"main.rs"),
              ~"fn main() { let _x = (); }");
    writeFile(&package_dir.push(~"lib.rs"),
              ~"pub fn f() { let _x = (); }");
    writeFile(&package_dir.push(~"test.rs"),
              ~"#[test] pub fn f() { (); }");
    writeFile(&package_dir.push(~"bench.rs"),
              ~"#[bench] pub fn f() { (); }");
    workspace
}

fn is_rwx(p: &Path) -> bool {
    use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};

    match p.get_mode() {
        None => return false,
        Some(m) =>
            ((m & S_IRUSR as uint) == S_IRUSR as uint
            && (m & S_IWUSR as uint) == S_IWUSR as uint
            && (m & S_IXUSR as uint) == S_IXUSR as uint)
    }
}

fn test_sysroot() -> Path {
    // Totally gross hack but it's just for test cases.
    // Infer the sysroot from the exe name and pray that it's right.
    // (Did I mention it was a gross hack?)
    let self_path = os::self_exe_path().expect("Couldn't get self_exe path");
    self_path.pop()
}

// Ignored on i686 -- see #6517
#[test]
#[ignore(cfg(target_arch = "x86"))]
fn test_make_dir_rwx() {
    let temp = &os::tmpdir();
    let dir = temp.push(~"quux");
    assert!(!os::path_exists(&dir) ||
            os::remove_dir_recursive(&dir));
    debug!("Trying to make %s", dir.to_str());
    assert!(make_dir_rwx(&dir));
    assert!(os::path_is_dir(&dir));
    assert!(is_rwx(&dir));
    assert!(os::remove_dir_recursive(&dir));
}

#[test]
#[ignore(cfg(target_arch = "x86"))]
fn test_install_valid() {
    let sysroot = test_sysroot();
    debug!("sysroot = %s", sysroot.to_str());
    let ctxt = fake_ctxt(Some(@sysroot));
    let temp_pkg_id = fake_pkg();
    let temp_workspace = mk_temp_workspace(&temp_pkg_id.local_path);
    // should have test, bench, lib, and main
    ctxt.install(&temp_workspace, &temp_pkg_id);
    // Check that all files exist
    let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("exec = %s", exec.to_str());
    assert!(os::path_exists(&exec));
    assert!(is_rwx(&exec));
    let lib = target_library_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("lib = %s", lib.to_str());
    assert!(os::path_exists(&lib));
    assert!(is_rwx(&lib));
    // And that the test and bench executables aren't installed
    assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace)));
    let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace);
    debug!("bench = %s", bench.to_str());
    assert!(!os::path_exists(&bench));
}

#[test]
#[ignore(cfg(target_arch = "x86"))]
fn test_install_invalid() {
    use conditions::nonexistent_package::cond;
    use cond1 = conditions::missing_pkg_files::cond;

    let ctxt = fake_ctxt(None);
    let pkgid = fake_pkg();
    let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
    let mut error_occurred = false;
    let mut error1_occurred = false;
    do cond1.trap(|_| {
        error1_occurred = true;
    }).in {
        do cond.trap(|_| {
            error_occurred = true;
        }).in {
            ctxt.install(&temp_workspace, &pkgid);
        }
    }
    assert!(error_occurred && error1_occurred);
}

#[test]
#[ignore(cfg(target_arch = "x86"))]
fn test_install_url() {
    let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
    let sysroot = test_sysroot();
    debug!("sysroot = %s", sysroot.to_str());
    let ctxt = fake_ctxt(Some(@sysroot));
    let temp_pkg_id = remote_pkg();
    // should have test, bench, lib, and main
    ctxt.install(&workspace, &temp_pkg_id);
    // Check that all files exist
    let exec = target_executable_in_workspace(&temp_pkg_id, &workspace);
    debug!("exec = %s", exec.to_str());
    assert!(os::path_exists(&exec));
    assert!(is_rwx(&exec));
    let lib = target_library_in_workspace(&temp_pkg_id, &workspace);
    debug!("lib = %s", lib.to_str());
    assert!(os::path_exists(&lib));
    assert!(is_rwx(&lib));
    let built_test = built_test_in_workspace(&temp_pkg_id, &workspace).expect(~"test_install_url");
    assert!(os::path_exists(&built_test));
    let built_bench = built_bench_in_workspace(&temp_pkg_id,
                                               &workspace).expect(~"test_install_url");
    assert!(os::path_exists(&built_bench));
    // And that the test and bench executables aren't installed
    let test = target_test_in_workspace(&temp_pkg_id, &workspace);
    assert!(!os::path_exists(&test));
    debug!("test = %s", test.to_str());
    let bench = target_bench_in_workspace(&temp_pkg_id, &workspace);
    debug!("bench = %s", bench.to_str());
    assert!(!os::path_exists(&bench));
}

#[test]
fn test_package_ids_must_be_relative_path_like() {
    use conditions::bad_pkg_id::cond;

    /*
    Okay:
    - One identifier, with no slashes
    - Several slash-delimited things, with no / at the root

    Not okay:
    - Empty string
    - Absolute path (as per os::is_absolute)

    */

    let default_version_str = "0.1";
    let addversion = |s| {
        fmt!("%s-%s", s, default_version_str)
    };

    let whatever = PkgId::new("foo");

    assert_eq!(addversion("foo"), whatever.to_str());
    assert!(addversion("github.com/mozilla/rust") ==
            PkgId::new("github.com/mozilla/rust").to_str());

    do cond.trap(|(p, e)| {
        assert!("" == p.to_str());
        assert!("0-length pkgid" == e);
        copy whatever
    }).in {
        let x = PkgId::new("");
        assert_eq!(addversion("foo"), x.to_str());
    }

    do cond.trap(|(p, e)| {
        assert_eq!(p.to_str(), os::make_absolute(&Path("foo/bar/quux")).to_str());
        assert!("absolute pkgid" == e);
        copy whatever
    }).in {
        let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str());
        assert_eq!(addversion("foo"), z.to_str());
    }

}
<|endoftext|>


<commit_before>#[derive(RustcDecodable, Debug)]
pub struct GcmResponse {
  pub message_id: Option<u64>,
  pub error: Option<String>,
  pub multicast_id: Option<i64>,
  pub success: Option<u64>,
  pub failure: Option<u64>,
  pub canonical_ids: Option<u64>,
  pub results: Option<Vec<MessageResult>>
}

#[derive(RustcDecodable, Debug)]
pub struct MessageResult {
  pub message_id: Option<u64>,
  pub registration_id: Option<u64>,
  pub error: Option<String>
}

#[derive(PartialEq, Debug)]
pub enum GcmError {
  Unauthorized, InvalidMessage(String), ServerError
}
<commit_msg>formatting<commit_after>#[derive(RustcDecodable, Debug)]
pub struct GcmResponse {
  pub message_id: Option<u64>,
  pub error: Option<String>,
  pub multicast_id: Option<i64>,
  pub success: Option<u64>,
  pub failure: Option<u64>,
  pub canonical_ids: Option<u64>,
  pub results: Option<Vec<MessageResult>>
}

#[derive(RustcDecodable, Debug)]
pub struct MessageResult {
  pub message_id: Option<u64>,
  pub registration_id: Option<u64>,
  pub error: Option<String>
}

#[derive(PartialEq, Debug)]
pub enum GcmError {
  Unauthorized,
  InvalidMessage(String),
  ServerError
}
<|endoftext|>


<commit_before>use cmd;
use msg::RawMessage;

use server::{Server};
use con::Peer;

/// Handles the CAP command.
pub struct Cap {
    raw: RawMessage,
    subcmd: String,
    params: Vec<String>,
}

impl super::MessageHandler for Cap {
    fn from_message(message: RawMessage) -> Result<Box<Cap>, Option<RawMessage>> {
        let params = message.params();
        let mut params = params.iter().map(|&p|
            String::from_utf8_lossy(p).to_string()
        );
        let subcmd = if params.len() > 0 {
            params.nth(0).unwrap()
        } else { return Err(None) };
        Ok(box Cap {
            raw: message.clone(), subcmd: subcmd, params: params.collect()
        })
    }

    fn invoke(self, server: &mut Server, peer: Peer) {
        let server_name = server.host().to_string();
        spawn(proc() {
            let info = peer.info().read();
            let nick = info.nick().as_slice();
            match self.subcmd.as_slice() {
                "LS" => {
                    peer.send_msg(RawMessage::new(cmd::CAP, &[
                        nick, "LS", ""//, "multi-prefix sasl"
                    ], Some(server_name.as_slice())))
                },
                "REQ" => {
                    peer.send_msg(RawMessage::new(cmd::CAP, &[
                        nick, "NAQ", self.params.connect(" ").as_slice()
                    ], Some(server_name.as_slice())))
                },
                _ => {}
            }
        })
    }

    fn raw_message(&self) -> &RawMessage {
        &self.raw
    }
}<commit_msg>Fix CAP handling<commit_after>use cmd;
use msg::RawMessage;

use server::{Server};
use con::{Peer, Connection};

/// Handles the CAP command.
pub struct Cap {
    raw: RawMessage,
    subcmd: String,
    params: Vec<String>,
}

impl super::MessageHandler for Cap {
    fn from_message(message: RawMessage) -> Result<Box<Cap>, Option<RawMessage>> {
        let params = message.params();
        let mut params = params.iter().map(|&p|
            String::from_utf8_lossy(p).to_string()
        );
        let subcmd = if params.len() > 0 {
            params.nth(0).unwrap()
        } else { return Err(None) };
        Ok(box Cap {
            raw: message.clone(), subcmd: subcmd, params: params.collect()
        })
    }

    fn invoke(self, server: &mut Server, peer: Peer) {
        let server_name = server.host().to_string();
        info!("cap:invoke")
        spawn(proc() {
            let info = peer.info().read();
            let nick = info.nick().as_slice();
            match self.subcmd.as_slice() {
                "LS" => {
                    peer.send_msg(RawMessage::new(cmd::CAP, &[
                        nick, "LS", ""//, "multi-prefix sasl"
                    ], Some(server_name.as_slice())))
                },
                "REQ" => {
                    peer.send_msg(RawMessage::new(cmd::CAP, &[
                        nick, "NAQ", self.params.connect(" ").as_slice()
                    ], Some(server_name.as_slice())))
                },
                _ => {}
            }
        })
    }

    fn invoke_con(self, server: &mut Server, origin: Connection) {
        self.invoke(server, origin.peer())
    }

    fn raw_message(&self) -> &RawMessage {
        &self.raw
    }
}<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::executor_proxy::{ExecutorProxy, ExecutorProxyTrait};
use compiled_stdlib::transaction_scripts::StdlibScript;
use diem_crypto::{ed25519::*, HashValue, PrivateKey, Uniform};
use diem_types::{
    account_config::{diem_root_address, xus_tag},
    block_metadata::BlockMetadata,
    on_chain_config::{OnChainConfig, VMPublishingOption},
    transaction::{Transaction, WriteSetPayload},
};
use diem_vm::DiemVM;
use diemdb::DiemDB;
use executor::Executor;
use executor_test_helpers::{
    bootstrap_genesis, gen_block_id, gen_block_metadata, gen_ledger_info_with_sigs,
    get_test_signed_transaction,
};
use executor_types::BlockExecutor;
use futures::{future::FutureExt, stream::StreamExt};
use storage_interface::DbReaderWriter;
use subscription_service::ReconfigSubscription;
use transaction_builder::{
    encode_add_to_script_allow_list_script, encode_block_prologue_script,
    encode_peer_to_peer_with_metadata_script, encode_set_validator_config_and_reconfigure_script,
};

// TODO test for subscription with multiple subscribed configs once there are >1 on-chain configs
#[test]
fn test_on_chain_config_pub_sub() {
    let mut rt = tokio::runtime::Runtime::new().unwrap();
    // set up reconfig subscription
    let (subscription, mut reconfig_receiver) =
        ReconfigSubscription::subscribe_all("test", vec![VMPublishingOption::CONFIG_ID], vec![]);

    let (genesis, validators) = vm_genesis::test_genesis_change_set_and_validators(Some(1));
    let genesis_key = vm_genesis::GENESIS_KEYPAIR.0.clone();
    let genesis_txn = Transaction::GenesisTransaction(WriteSetPayload::Direct(genesis));
    let db_path = diem_temppath::TempPath::new();
    db_path.create_as_dir().unwrap();
    let (db, db_rw) = DbReaderWriter::wrap(DiemDB::new_for_test(db_path.path()));
    bootstrap_genesis::<DiemVM>(&db_rw, &genesis_txn).unwrap();

    let mut block_executor = Box::new(Executor::<DiemVM>::new(db_rw.clone()));
    let chunk_executor = Box::new(Executor::<DiemVM>::new(db_rw));
    let mut executor_proxy = ExecutorProxy::new(db, chunk_executor, vec![subscription]);

    assert!(
        reconfig_receiver
            .select_next_some()
            .now_or_never()
            .is_some(),
        "expect initial config notification",
    );

    ////////////////////////////////////////////////////////
    // Case 1: don't publish for no reconfiguration event //
    ////////////////////////////////////////////////////////
    executor_proxy
        .publish_on_chain_config_updates(vec![])
        .expect("failed to publish on-chain configs");

    assert_eq!(
        reconfig_receiver.select_next_some().now_or_never(),
        None,
        "did not expect reconfig update"
    );

    //////////////////////////////////////////////////
    // Case 2: publish if subscribed config changed //
    //////////////////////////////////////////////////
    let genesis_account = diem_root_address();
    let validator_account = validators[0].owner_address;
    let operator_key = validators[0].key.clone();
    let operator_public_key = operator_key.public_key();
    let operator_account = validators[0].operator_address;

    // Create a dummy block prologue transaction that will bump the timer.
    let txn1 = encode_block_prologue_script(gen_block_metadata(1, validator_account));

    // Add a script to allowlist.
    let new_allowlist = {
        let mut existing_list = StdlibScript::allowlist();
        existing_list.push(*HashValue::sha3_256_of(&[]).as_ref());
        existing_list
    };
    let vm_publishing_option = VMPublishingOption::locked(new_allowlist);

    let txn2 = get_test_signed_transaction(
        genesis_account,
        /* sequence_number = */ 1,
        genesis_key.clone(),
        genesis_key.public_key(),
        Some(encode_add_to_script_allow_list_script(
            HashValue::sha3_256_of(&[]).to_vec(),
            0,
        )),
    );

    let block1 = vec![txn1.clone(), txn2.clone()];
    let block1_id = gen_block_id(1);
    let parent_block_id = block_executor.committed_block_id();

    let output = block_executor
        .execute_block((block1_id, block1), parent_block_id)
        .expect("failed to execute block");
    assert!(
        output.has_reconfiguration(),
        "execution missing reconfiguration"
    );

    let ledger_info_with_sigs_epoch_1 = gen_ledger_info_with_sigs(1, output, block1_id, vec![]);
    let (_, reconfig_events) = block_executor
        .commit_blocks(vec![block1_id], ledger_info_with_sigs_epoch_1.clone())
        .unwrap();
    assert!(
        !reconfig_events.is_empty(),
        "expected reconfig events from executor commit"
    );
    executor_proxy
        .publish_on_chain_config_updates(reconfig_events)
        .expect("failed to publish on-chain configs");

    let receive_reconfig = async {
        let payload = reconfig_receiver.select_next_some().await;
        let received_config = payload.get::<VMPublishingOption>().unwrap();
        assert_eq!(received_config, vm_publishing_option);
    };

    rt.block_on(receive_reconfig);

    //////////////////////////////////////////////////////////////////////////////////////
    // Case 3: don't publish for reconfiguration that doesn't change subscribed configs //
    //////////////////////////////////////////////////////////////////////////////////////
    // give the validator some money so they can send a tx
    let txn3 = get_test_signed_transaction(
        genesis_account,
        /* sequence_number = */ 2,
        genesis_key.clone(),
        genesis_key.public_key(),
        Some(encode_peer_to_peer_with_metadata_script(
            xus_tag(),
            validator_account,
            1_000_000,
            vec![],
            vec![],
        )),
    );

    // Create a dummy block prologue transaction that will bump the timer.
    let txn4 = encode_block_prologue_script(BlockMetadata::new(
        gen_block_id(2),
        2,
        300000010,
        vec![],
        validator_account,
    ));

    // rotate the validator's consensus pubkey to trigger a reconfiguration
    let new_pubkey = Ed25519PrivateKey::generate_for_testing().public_key();
    let txn5 = get_test_signed_transaction(
        operator_account,
        /* sequence_number = */ 0,
        operator_key,
        operator_public_key,
        Some(encode_set_validator_config_and_reconfigure_script(
            validator_account,
            new_pubkey.to_bytes().to_vec(),
            Vec::new(),
            Vec::new(),
        )),
    );

    let block2 = vec![txn3, txn4, txn5];
    let block2_id = gen_block_id(2);

    let output = block_executor
        .execute_block((block2_id, block2), block_executor.committed_block_id())
        .expect("failed to execute block");
    assert!(
        output.has_reconfiguration(),
        "execution missing reconfiguration"
    );

    let ledger_info_with_sigs_epoch_2 = gen_ledger_info_with_sigs(2, output, block2_id, vec![]);
    let (_, reconfig_events) = block_executor
        .commit_blocks(vec![block2_id], ledger_info_with_sigs_epoch_2.clone())
        .unwrap();
    assert!(
        !reconfig_events.is_empty(),
        "expected reconfig events from executor commit"
    );

    executor_proxy
        .publish_on_chain_config_updates(reconfig_events)
        .expect("failed to publish on-chain configs");

    assert_eq!(
        reconfig_receiver.select_next_some().now_or_never(),
        None,
        "did not expect reconfig update"
    );

    ////////////////////////////////////////////////////////////////
    // Case 3: test failed on-chain reconfig publish throws error //
    ////////////////////////////////////////////////////////////////
    // test error throwing on failed reconfig publish
    drop(reconfig_receiver);

    // Create a dummy block prologue transaction that will bump the timer.
    let txn6 = encode_block_prologue_script(BlockMetadata::new(
        gen_block_id(2),
        3,
        300000020,
        vec![],
        validator_account,
    ));
    let txn7 = get_test_signed_transaction(
        genesis_account,
        /* sequence_number = */ 3,
        genesis_key.clone(),
        genesis_key.public_key(),
        Some(encode_add_to_script_allow_list_script(
            HashValue::sha3_256_of(&[1]).to_vec(),
            0,
        )),
    );

    let block3 = vec![txn6, txn7];
    let block3_id = gen_block_id(3);
    let parent_block_id = block_executor.committed_block_id();

    let output = block_executor
        .execute_block((block3_id, block3), parent_block_id)
        .expect("failed to execute block");
    assert!(
        output.has_reconfiguration(),
        "execution missing reconfiguration"
    );

    let ledger_info_with_sigs = gen_ledger_info_with_sigs(3, output, block3_id, vec![]);
    let (_, reconfig_events) = block_executor
        .commit_blocks(vec![block3_id], ledger_info_with_sigs)
        .unwrap();
    assert!(
        !reconfig_events.is_empty(),
        "expected reconfig events from executor commit"
    );

    // assert publishing on-chain config updates fails for dropped receiver
    assert!(executor_proxy
        .publish_on_chain_config_updates(reconfig_events)
        .is_err());

    // test state of DB using non-mocked executor proxy interface
    // Note: we mock out the executor proxy in the state sync integration tests because we also mock
    // out the storage/execution layer. We piggy-back on this expensive DB/runtime setup here in testing
    // on-chain reconfig to test the executor proxy interface against.
    let state = executor_proxy.get_local_storage_state().unwrap();
    assert_eq!(state.trusted_epoch(), 4);
    assert_eq!(state.synced_version(), 7);

    let txns = executor_proxy.get_chunk(0, 2, 2).unwrap();
    assert_eq!(txns.transactions, vec![txn1, txn2]);

    assert!(executor_proxy
        .execute_chunk(txns, ledger_info_with_sigs_epoch_1.clone(), None)
        .is_ok());

    let epoch_li = executor_proxy.get_epoch_proof(1).unwrap();
    assert_eq!(epoch_li, ledger_info_with_sigs_epoch_1);
    let epoch_li = executor_proxy.get_epoch_proof(2).unwrap();
    assert_eq!(epoch_li, ledger_info_with_sigs_epoch_2);

    // epoch 1 ended at version 2
    let epoch_li = executor_proxy.get_epoch_ending_ledger_info(2).unwrap();
    assert_eq!(epoch_li, ledger_info_with_sigs_epoch_1);
    // epoch 2 ended at version 5
    let epoch_li = executor_proxy.get_epoch_ending_ledger_info(5).unwrap();
    assert_eq!(epoch_li, ledger_info_with_sigs_epoch_2);

    assert!(executor_proxy.get_epoch_ending_ledger_info(3).is_err());
}
<commit_msg>[State Sync] Refactor the monster pub/sub state sync test into multiple tests and add missing behaviours.<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::executor_proxy::{ExecutorProxy, ExecutorProxyTrait};
use channel::diem_channel::Receiver;
use compiled_stdlib::transaction_scripts::StdlibScript;
use diem_crypto::{ed25519::*, HashValue, PrivateKey, Uniform};
use diem_types::{
    account_address::AccountAddress,
    account_config::{diem_root_address, xus_tag},
    block_metadata::BlockMetadata,
    contract_event::ContractEvent,
    ledger_info::LedgerInfoWithSignatures,
    on_chain_config::{
        OnChainConfig, OnChainConfigPayload, VMConfig, VMPublishingOption, ValidatorSet,
    },
    transaction::{Transaction, WriteSetPayload},
};
use diem_vm::DiemVM;
use diemdb::DiemDB;
use executor::Executor;
use executor_test_helpers::{
    bootstrap_genesis, gen_block_id, gen_ledger_info_with_sigs, get_test_signed_transaction,
};
use executor_types::BlockExecutor;
use futures::{future::FutureExt, stream::StreamExt};
use storage_interface::DbReaderWriter;
use subscription_service::ReconfigSubscription;
use transaction_builder::{
    encode_add_to_script_allow_list_script, encode_block_prologue_script,
    encode_peer_to_peer_with_metadata_script, encode_set_validator_config_and_reconfigure_script,
};
use vm_genesis::Validator;

// TODO(joshlind): add unit tests for subscription events.. seems like these are missing?

#[test]
fn test_pub_sub_different_subscription() {
    let (subscription, mut reconfig_receiver) =
        ReconfigSubscription::subscribe_all("", vec![VMConfig::CONFIG_ID], vec![]);
    let (validators, mut block_executor, mut executor_proxy) =
        bootstrap_genesis_and_set_subscription(subscription, &mut reconfig_receiver);

    // Create a dummy prologue transaction that will bump the timer, and update the VMPublishingOption
    let validator_account = validators[0].owner_address;
    let dummy_txn = create_dummy_transaction(1, validator_account);
    let (allowlist_txn, _) = create_new_allowlist_transaction(1);

    // Execute and commit the block
    let block = vec![dummy_txn, allowlist_txn];
    let (reconfig_events, _) = execute_and_commit_block(&mut block_executor, block, 1);

    // Publish the on chain config updates
    executor_proxy
        .publish_on_chain_config_updates(reconfig_events)
        .unwrap();

    // Verify no reconfig notification is sent (we only subscribed to VMConfig)
    assert!(reconfig_receiver
        .select_next_some()
        .now_or_never()
        .is_none());
}

#[test]
fn test_pub_sub_drop_receiver() {
    let (subscription, mut reconfig_receiver) =
        ReconfigSubscription::subscribe_all("", vec![VMPublishingOption::CONFIG_ID], vec![]);
    let (validators, mut block_executor, mut executor_proxy) =
        bootstrap_genesis_and_set_subscription(subscription, &mut reconfig_receiver);

    // Create a dummy prologue transaction that will bump the timer, and update the VMPublishingOption
    let validator_account = validators[0].owner_address;
    let dummy_txn = create_dummy_transaction(1, validator_account);
    let (allowlist_txn, _) = create_new_allowlist_transaction(1);

    // Execute and commit the reconfig block
    let block = vec![dummy_txn, allowlist_txn];
    let (reconfig_events, _) = execute_and_commit_block(&mut block_executor, block, 1);

    // Drop the reconfig receiver
    drop(reconfig_receiver);

    // Verify publishing on-chain config updates fails due to dropped receiver
    assert!(executor_proxy
        .publish_on_chain_config_updates(reconfig_events)
        .is_err());
}

#[test]
fn test_pub_sub_multiple_subscriptions() {
    let (subscription, mut reconfig_receiver) = ReconfigSubscription::subscribe_all(
        "",
        vec![ValidatorSet::CONFIG_ID, VMPublishingOption::CONFIG_ID],
        vec![],
    );
    let (validators, mut block_executor, mut executor_proxy) =
        bootstrap_genesis_and_set_subscription(subscription, &mut reconfig_receiver);

    // Create a dummy prologue transaction that will bump the timer, and update the VMPublishingOption
    let validator_account = validators[0].owner_address;
    let dummy_txn = create_dummy_transaction(1, validator_account);
    let (allowlist_txn, _) = create_new_allowlist_transaction(1);

    // Give the validator some money so it can send a rotation tx and rotate the validator's consensus key.
    let money_txn = create_transfer_to_validator_transaction(validator_account, 2);
    let rotation_txn = create_consensus_key_rotation_transaction(&validators[0], 0);

    // Execute and commit the reconfig block
    let block = vec![dummy_txn, allowlist_txn, money_txn, rotation_txn];
    let (reconfig_events, _) = execute_and_commit_block(&mut block_executor, block, 1);

    // Publish the on chain config updates
    executor_proxy
        .publish_on_chain_config_updates(reconfig_events)
        .unwrap();

    // Verify reconfig notification is sent
    assert!(reconfig_receiver
        .select_next_some()
        .now_or_never()
        .is_some());
}

#[test]
fn test_pub_sub_no_reconfig_events() {
    let (subscription, mut reconfig_receiver) =
        ReconfigSubscription::subscribe_all("", vec![VMPublishingOption::CONFIG_ID], vec![]);
    let (_, _, mut executor_proxy) =
        bootstrap_genesis_and_set_subscription(subscription, &mut reconfig_receiver);

    // Publish no on chain config updates
    executor_proxy
        .publish_on_chain_config_updates(vec![])
        .unwrap();

    // Verify no reconfig notification is sent
    assert!(reconfig_receiver
        .select_next_some()
        .now_or_never()
        .is_none());
}

#[test]
fn test_pub_sub_no_subscriptions() {
    let (subscription, mut reconfig_receiver) =
        ReconfigSubscription::subscribe_all("", vec![], vec![]);
    let (validators, mut block_executor, mut executor_proxy) =
        bootstrap_genesis_and_set_subscription(subscription, &mut reconfig_receiver);

    // Create a dummy prologue transaction that will bump the timer, and update the VMPublishingOption
    let validator_account = validators[0].owner_address;
    let dummy_txn = create_dummy_transaction(1, validator_account);
    let (allowlist_txn, _) = create_new_allowlist_transaction(1);

    // Execute and commit the reconfig block
    let block = vec![dummy_txn, allowlist_txn];
    let (reconfig_events, _) = execute_and_commit_block(&mut block_executor, block, 1);

    // Publish the on chain config updates
    executor_proxy
        .publish_on_chain_config_updates(reconfig_events)
        .unwrap();

    // Verify no reconfig notification is sent
    assert!(reconfig_receiver
        .select_next_some()
        .now_or_never()
        .is_none());
}

#[test]
fn test_pub_sub_vm_publishing_option() {
    let (subscription, mut reconfig_receiver) =
        ReconfigSubscription::subscribe_all("", vec![VMPublishingOption::CONFIG_ID], vec![]);
    let (validators, mut block_executor, mut executor_proxy) =
        bootstrap_genesis_and_set_subscription(subscription, &mut reconfig_receiver);

    // Create a dummy prologue transaction that will bump the timer, and update the VMPublishingOption
    let validator_account = validators[0].owner_address;
    let dummy_txn = create_dummy_transaction(1, validator_account);
    let (allowlist_txn, vm_publishing_option) = create_new_allowlist_transaction(1);

    // Execute and commit the reconfig block
    let block = vec![dummy_txn, allowlist_txn];
    let (reconfig_events, _) = execute_and_commit_block(&mut block_executor, block, 1);

    // Publish the on chain config updates
    executor_proxy
        .publish_on_chain_config_updates(reconfig_events)
        .unwrap();

    // Verify the correct reconfig notification is sent
    let payload = reconfig_receiver.select_next_some().now_or_never().unwrap();
    let received_config = payload.get::<VMPublishingOption>().unwrap();
    assert_eq!(received_config, vm_publishing_option);
}

#[test]
fn test_pub_sub_with_executor_proxy() {
    let (subscription, mut reconfig_receiver) = ReconfigSubscription::subscribe_all(
        "",
        vec![ValidatorSet::CONFIG_ID, VMPublishingOption::CONFIG_ID],
        vec![],
    );
    let (validators, mut block_executor, mut executor_proxy) =
        bootstrap_genesis_and_set_subscription(subscription, &mut reconfig_receiver);

    // Create a dummy prologue transaction that will bump the timer and update the VMPublishingOption
    let validator_account = validators[0].owner_address;
    let dummy_txn_1 = create_dummy_transaction(1, validator_account);
    let (allowlist_txn, _) = create_new_allowlist_transaction(1);

    // Execute and commit the reconfig block
    let block = vec![dummy_txn_1.clone(), allowlist_txn.clone()];
    let (_, ledger_info_epoch_1) = execute_and_commit_block(&mut block_executor, block, 1);

    // Give the validator some money so it can send a rotation tx, create another dummy prologue
    // to bump the timer and rotate the validator's consensus key.
    let money_txn = create_transfer_to_validator_transaction(validator_account, 2);
    let dummy_txn_2 = create_dummy_transaction(2, validator_account);
    let rotation_txn = create_consensus_key_rotation_transaction(&validators[0], 0);

    // Execute and commit the reconfig block
    let block = vec![money_txn.clone(), dummy_txn_2.clone(), rotation_txn.clone()];
    let (_, ledger_info_epoch_2) = execute_and_commit_block(&mut block_executor, block, 2);

    // Grab the first two executed transactions and verify responses
    let txns = executor_proxy.get_chunk(0, 2, 2).unwrap();
    assert_eq!(txns.transactions, vec![dummy_txn_1, allowlist_txn]);
    assert!(executor_proxy
        .execute_chunk(txns, ledger_info_epoch_1.clone(), None)
        .is_ok());
    assert_eq!(
        ledger_info_epoch_1,
        executor_proxy.get_epoch_proof(1).unwrap()
    );
    assert_eq!(
        ledger_info_epoch_1,
        executor_proxy.get_epoch_ending_ledger_info(2).unwrap()
    );

    // Grab the next two executed transactions (forced by limit) and verify responses
    let txns = executor_proxy.get_chunk(2, 2, 5).unwrap();
    assert_eq!(txns.transactions, vec![money_txn, dummy_txn_2]);
    executor_proxy.get_epoch_ending_ledger_info(4).unwrap_err();

    // Grab the last transaction and verify responses
    let txns = executor_proxy.get_chunk(4, 1, 5).unwrap();
    assert_eq!(txns.transactions, vec![rotation_txn]);
    assert!(executor_proxy
        .execute_chunk(txns, ledger_info_epoch_2.clone(), None)
        .is_ok());
    assert_eq!(
        ledger_info_epoch_2,
        executor_proxy.get_epoch_proof(2).unwrap()
    );
    assert_eq!(
        ledger_info_epoch_2,
        executor_proxy.get_epoch_ending_ledger_info(5).unwrap()
    );
}

#[test]
fn test_pub_sub_with_executor_sync_state() {
    let (subscription, mut reconfig_receiver) = ReconfigSubscription::subscribe_all(
        "",
        vec![ValidatorSet::CONFIG_ID, VMPublishingOption::CONFIG_ID],
        vec![],
    );
    let (validators, mut block_executor, executor_proxy) =
        bootstrap_genesis_and_set_subscription(subscription, &mut reconfig_receiver);

    // Create a dummy prologue transaction that will bump the timer and update the VMPublishingOption
    let validator_account = validators[0].owner_address;
    let dummy_txn = create_dummy_transaction(1, validator_account);
    let (allowlist_txn, _) = create_new_allowlist_transaction(1);

    // Execute and commit the reconfig block
    let block = vec![dummy_txn, allowlist_txn];
    let _ = execute_and_commit_block(&mut block_executor, block, 1);

    // Verify executor proxy sync state
    let sync_state = executor_proxy.get_local_storage_state().unwrap();
    assert_eq!(sync_state.trusted_epoch(), 2); // 1 reconfiguration has occurred, trusted = next
    assert_eq!(sync_state.committed_version(), 2); // 2 transactions have committed
    assert_eq!(sync_state.synced_version(), 2); // 2 transactions have synced

    // Give the validator some money so it can send a rotation tx, create another dummy prologue
    // to bump the timer and rotate the validator's consensus key.
    let money_txn = create_transfer_to_validator_transaction(validator_account, 2);
    let dummy_txn = create_dummy_transaction(2, validator_account);
    let rotation_txn = create_consensus_key_rotation_transaction(&validators[0], 0);

    // Execute and commit the reconfig block
    let block = vec![money_txn, dummy_txn, rotation_txn];
    let _ = execute_and_commit_block(&mut block_executor, block, 2);

    // Verify executor proxy sync state
    let sync_state = executor_proxy.get_local_storage_state().unwrap();
    assert_eq!(sync_state.trusted_epoch(), 3); // 2 reconfigurations have occurred, trusted = next
    assert_eq!(sync_state.committed_version(), 5); // 5 transactions have committed
    assert_eq!(sync_state.synced_version(), 5); // 5 transactions have synced
}

/// Executes a genesis transaction, creates the executor proxy and sets the given reconfig
/// subscription.
fn bootstrap_genesis_and_set_subscription(
    subscription: ReconfigSubscription,
    reconfig_receiver: &mut Receiver<(), OnChainConfigPayload>,
) -> (Vec<Validator>, Box<Executor<DiemVM>>, ExecutorProxy) {
    // Generate a genesis change set
    let (genesis, validators) = vm_genesis::test_genesis_change_set_and_validators(Some(1));

    // Create test diem database
    let db_path = diem_temppath::TempPath::new();
    db_path.create_as_dir().unwrap();
    let (db, db_rw) = DbReaderWriter::wrap(DiemDB::new_for_test(db_path.path()));

    // Boostrap the genesis transaction
    let genesis_txn = Transaction::GenesisTransaction(WriteSetPayload::Direct(genesis));
    bootstrap_genesis::<DiemVM>(&db_rw, &genesis_txn).unwrap();

    // Create executor proxy with given subscription
    let block_executor = Box::new(Executor::<DiemVM>::new(db_rw.clone()));
    let chunk_executor = Box::new(Executor::<DiemVM>::new(db_rw));
    let executor_proxy = ExecutorProxy::new(db, chunk_executor, vec![subscription]);

    // Verify initial reconfiguration notification is sent
    assert!(
        reconfig_receiver
            .select_next_some()
            .now_or_never()
            .is_some(),
        "Expected an initial reconfig notification on executor proxy creation!",
    );

    (validators, block_executor, executor_proxy)
}

/// Creates a transaction that rotates the consensus key of the given validator account.
fn create_consensus_key_rotation_transaction(
    validator: &Validator,
    sequence_number: u64,
) -> Transaction {
    let operator_key = validator.key.clone();
    let operator_public_key = operator_key.public_key();
    let operator_account = validator.operator_address;
    let new_consensus_key = Ed25519PrivateKey::generate_for_testing().public_key();

    get_test_signed_transaction(
        operator_account,
        sequence_number,
        operator_key,
        operator_public_key,
        Some(encode_set_validator_config_and_reconfigure_script(
            validator.owner_address,
            new_consensus_key.to_bytes().to_vec(),
            Vec::new(),
            Vec::new(),
        )),
    )
}

/// Creates a dummy transaction (useful for bumping the timer).
fn create_dummy_transaction(index: u8, validator_account: AccountAddress) -> Transaction {
    encode_block_prologue_script(BlockMetadata::new(
        gen_block_id(index),
        index as u64,
        (index as u64 + 1) * 100000010,
        vec![],
        validator_account,
    ))
}

/// Creates a transaction that updates the on chain allowlist.
fn create_new_allowlist_transaction(sequencer_number: u64) -> (Transaction, VMPublishingOption) {
    // Add a new script to the allowlist
    let new_allowlist = {
        let mut existing_list = StdlibScript::allowlist();
        existing_list.push(*HashValue::sha3_256_of(&[]).as_ref());
        existing_list
    };
    let vm_publishing_option = VMPublishingOption::locked(new_allowlist);

    // Create a transaction for the new allowlist
    let genesis_key = vm_genesis::GENESIS_KEYPAIR.0.clone();
    let txn = get_test_signed_transaction(
        diem_root_address(),
        /* sequence_number = */ sequencer_number,
        genesis_key.clone(),
        genesis_key.public_key(),
        Some(encode_add_to_script_allow_list_script(
            HashValue::sha3_256_of(&[]).to_vec(),
            0,
        )),
    );

    (txn, vm_publishing_option)
}

/// Creates a transaction that sends funds to the specified validator account.
fn create_transfer_to_validator_transaction(
    validator_account: AccountAddress,
    sequence_number: u64,
) -> Transaction {
    let genesis_key = vm_genesis::GENESIS_KEYPAIR.0.clone();
    get_test_signed_transaction(
        diem_root_address(),
        sequence_number,
        genesis_key.clone(),
        genesis_key.public_key(),
        Some(encode_peer_to_peer_with_metadata_script(
            xus_tag(),
            validator_account,
            1_000_000,
            vec![],
            vec![],
        )),
    )
}

/// Executes and commits a given block that will cause a reconfiguration event.
fn execute_and_commit_block(
    block_executor: &mut Box<Executor<DiemVM>>,
    block: Vec<Transaction>,
    block_id: u8,
) -> (Vec<ContractEvent>, LedgerInfoWithSignatures) {
    let block_hash = gen_block_id(block_id);

    // Execute block
    let output = block_executor
        .execute_block((block_hash, block), block_executor.committed_block_id())
        .expect("Failed to execute block!");
    assert!(
        output.has_reconfiguration(),
        "Block execution is missing a reconfiguration!"
    );

    // Commit block
    let ledger_info_with_sigs =
        gen_ledger_info_with_sigs(block_id.into(), output, block_hash, vec![]);
    let (_, reconfig_events) = block_executor
        .commit_blocks(vec![block_hash], ledger_info_with_sigs.clone())
        .unwrap();
    assert!(
        !reconfig_events.is_empty(),
        "Expected reconfig events from block commit!"
    );

    (reconfig_events, ledger_info_with_sigs)
}
<|endoftext|>


<commit_before>// Copyright 2015 The Noise-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// TODO: Use PrimInt + Signed instead of SignedInt + NumCast once num has
// PrimInt implementations

use math;
use num_traits::{NumCast, PrimInt, Signed};
use rand::{Rand, Rng, SeedableRng, XorShiftRng};
use std::fmt;

const TABLE_SIZE: usize = 256;

/// A seed table, required by all noise functions.
///
/// Table creation is expensive, so in most circumstances you'll only want to
/// create one of these per generator.
#[derive(Copy)]
#[deprecated(since="0.3.0", note="will be made private by 1.0")]
pub struct PermutationTable {
    values: [u8; TABLE_SIZE],
}

impl Rand for PermutationTable {
    /// Generates a PermutationTable using a random seed.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate noise;
    /// extern crate rand;
    ///
    /// use noise::PermutationTable;
    ///
    /// # fn main() {
    /// let perm_table = rand::random::<PermutationTable>();
    /// # }
    /// ```
    ///
    /// ```rust
    /// extern crate noise;
    /// extern crate rand;
    ///
    /// use noise::PermutationTable;
    /// use rand::{SeedableRng, Rng, XorShiftRng};
    ///
    /// # fn main() {
    /// let mut rng: XorShiftRng = SeedableRng::from_seed([1, 2, 3, 4]);
    /// let perm_table = rng.gen::<PermutationTable>();
    /// # }
    /// ```
    fn rand<R: Rng>(rng: &mut R) -> PermutationTable {
        let mut seq: Vec<u8> = (0..TABLE_SIZE).map(|x| x as u8).collect();
        rng.shuffle(&mut *seq);

        // It's unfortunate that this double-initializes the array, but Rust
        // doesn't currently provide a clean way to do this in one pass. Hopefully
        // it won't matter, as Seed creation will usually be a one-time event.
        let mut perm_table = PermutationTable { values: [0; TABLE_SIZE] };
        let seq_it = seq.iter();
        for (x, y) in perm_table.values.iter_mut().zip(seq_it) {
            *x = *y
        }
        perm_table
    }
}

impl PermutationTable {
    /// Deterministically generates a new permutation table based on a `u32` seed value.
    ///
    /// Internally this uses a `XorShiftRng`, but we don't really need to worry
    /// about cryptographic security when working with procedural noise.
    ///
    /// # Example
    ///
    /// ```rust
    /// use noise::PermutationTable;
    ///
    /// let perm_table = PermutationTable::new(12);
    /// ```
    pub fn new(seed: u32) -> PermutationTable {
        let mut rng: XorShiftRng = SeedableRng::from_seed([1, seed, seed, seed]);
        rng.gen()
    }

    #[inline(always)]
    pub fn get1<T: Signed + PrimInt + NumCast>(&self, x: T) -> usize {
        let x: usize = math::cast(x & math::cast(0xff));
        self.values[x] as usize
    }

    #[inline(always)]
    pub fn get2<T: Signed + PrimInt + NumCast>(&self, pos: math::Point2<T>) -> usize {
        let y: usize = math::cast(pos[1] & math::cast(0xff));
        self.values[self.get1(pos[0]) ^ y] as usize
    }

    #[inline(always)]
    pub fn get3<T: Signed + PrimInt + NumCast>(&self, pos: math::Point3<T>) -> usize {
        let z: usize = math::cast(pos[2] & math::cast(0xff));
        self.values[self.get2([pos[0], pos[1]]) ^ z] as usize
    }

    #[inline(always)]
    pub fn get4<T: Signed + PrimInt + NumCast>(&self, pos: math::Point4<T>) -> usize {
        let w: usize = math::cast(pos[3] & math::cast(0xff));
        self.values[self.get3([pos[0], pos[1], pos[2]]) ^ w] as usize
    }
}

impl Clone for PermutationTable {
    fn clone(&self) -> PermutationTable {
        PermutationTable { values: self.values }
    }
}

impl fmt::Debug for PermutationTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PermutationTable {{ .. }}")
    }
}

#[cfg(test)]
mod tests {
    use super::PermutationTable;
    use perlin::perlin3;
    use rand::random;

    #[test]
    fn test_random_seed() {
        let _ = perlin3::<f32>(&random(), &[1.0, 2.0, 3.0]);
    }

    #[test]
    fn test_negative_params() {
        let _ = perlin3::<f32>(&PermutationTable::new(0), &[-1.0, 2.0, 3.0]);
    }
}
<commit_msg>Clarify PermutationTable deprecation<commit_after>// Copyright 2015 The Noise-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// TODO: Use PrimInt + Signed instead of SignedInt + NumCast once num has
// PrimInt implementations

use math;
use num_traits::{NumCast, PrimInt, Signed};
use rand::{Rand, Rng, SeedableRng, XorShiftRng};
use std::fmt;

const TABLE_SIZE: usize = 256;

/// A seed table, required by all noise functions.
///
/// Table creation is expensive, so in most circumstances you'll only want to
/// create one of these per generator.
#[derive(Copy)]
#[deprecated(since="0.3.0", note="will be made private by 1.0; noise generator structs (e.g. Perlin) now store permutation table internally, so if you were storing PermutationTable for performance reasons, store the noise generator object instead")]
pub struct PermutationTable {
    values: [u8; TABLE_SIZE],
}

impl Rand for PermutationTable {
    /// Generates a PermutationTable using a random seed.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate noise;
    /// extern crate rand;
    ///
    /// use noise::PermutationTable;
    ///
    /// # fn main() {
    /// let perm_table = rand::random::<PermutationTable>();
    /// # }
    /// ```
    ///
    /// ```rust
    /// extern crate noise;
    /// extern crate rand;
    ///
    /// use noise::PermutationTable;
    /// use rand::{SeedableRng, Rng, XorShiftRng};
    ///
    /// # fn main() {
    /// let mut rng: XorShiftRng = SeedableRng::from_seed([1, 2, 3, 4]);
    /// let perm_table = rng.gen::<PermutationTable>();
    /// # }
    /// ```
    fn rand<R: Rng>(rng: &mut R) -> PermutationTable {
        let mut seq: Vec<u8> = (0..TABLE_SIZE).map(|x| x as u8).collect();
        rng.shuffle(&mut *seq);

        // It's unfortunate that this double-initializes the array, but Rust
        // doesn't currently provide a clean way to do this in one pass. Hopefully
        // it won't matter, as Seed creation will usually be a one-time event.
        let mut perm_table = PermutationTable { values: [0; TABLE_SIZE] };
        let seq_it = seq.iter();
        for (x, y) in perm_table.values.iter_mut().zip(seq_it) {
            *x = *y
        }
        perm_table
    }
}

impl PermutationTable {
    /// Deterministically generates a new permutation table based on a `u32` seed value.
    ///
    /// Internally this uses a `XorShiftRng`, but we don't really need to worry
    /// about cryptographic security when working with procedural noise.
    ///
    /// # Example
    ///
    /// ```rust
    /// use noise::PermutationTable;
    ///
    /// let perm_table = PermutationTable::new(12);
    /// ```
    pub fn new(seed: u32) -> PermutationTable {
        let mut rng: XorShiftRng = SeedableRng::from_seed([1, seed, seed, seed]);
        rng.gen()
    }

    #[inline(always)]
    pub fn get1<T: Signed + PrimInt + NumCast>(&self, x: T) -> usize {
        let x: usize = math::cast(x & math::cast(0xff));
        self.values[x] as usize
    }

    #[inline(always)]
    pub fn get2<T: Signed + PrimInt + NumCast>(&self, pos: math::Point2<T>) -> usize {
        let y: usize = math::cast(pos[1] & math::cast(0xff));
        self.values[self.get1(pos[0]) ^ y] as usize
    }

    #[inline(always)]
    pub fn get3<T: Signed + PrimInt + NumCast>(&self, pos: math::Point3<T>) -> usize {
        let z: usize = math::cast(pos[2] & math::cast(0xff));
        self.values[self.get2([pos[0], pos[1]]) ^ z] as usize
    }

    #[inline(always)]
    pub fn get4<T: Signed + PrimInt + NumCast>(&self, pos: math::Point4<T>) -> usize {
        let w: usize = math::cast(pos[3] & math::cast(0xff));
        self.values[self.get3([pos[0], pos[1], pos[2]]) ^ w] as usize
    }
}

impl Clone for PermutationTable {
    fn clone(&self) -> PermutationTable {
        PermutationTable { values: self.values }
    }
}

impl fmt::Debug for PermutationTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PermutationTable {{ .. }}")
    }
}

#[cfg(test)]
mod tests {
    use super::PermutationTable;
    use perlin::perlin3;
    use rand::random;

    #[test]
    fn test_random_seed() {
        let _ = perlin3::<f32>(&random(), &[1.0, 2.0, 3.0]);
    }

    #[test]
    fn test_negative_params() {
        let _ = perlin3::<f32>(&PermutationTable::new(0), &[-1.0, 2.0, 3.0]);
    }
}
<|endoftext|>


<commit_before>use std::{io, path, ptr, time, fs, mem};
use std::os::unix::io::AsRawFd;
use std::mem::size_of;
use libc::{c_void, c_int, c_uint, c_ulong, c_uchar, ioctl, sysctl, timeval};
use data::*;
use super::common::*;
use super::unix;
use super::bsd;

pub struct PlatformImpl;

macro_rules! sysctl {
    ($mib:expr, $dataptr:expr, $size:expr, $shouldcheck:expr) => {
        {
            let mib = &$mib;
            let mut size = $size;
            if unsafe { sysctl(&mib[0], mib.len() as u32,
                               $dataptr as *mut _ as *mut c_void, &mut size, ptr::null_mut(), 0) } != 0 && $shouldcheck {
                return Err(io::Error::new(io::ErrorKind::Other, "sysctl() failed"))
            }
            size
        }
    };
    ($mib:expr, $dataptr:expr, $size:expr) => {
        sysctl!($mib, $dataptr, $size, true)
    }
}

lazy_static! {
    static ref APM_IOC_GETPOWER: c_ulong = (0x40000000u64 | ((size_of::<apm_power_info>() & 0x1fff) << 16) as u64 | (0x41 << 8) | 3);
    // OpenBSD does not have sysctlnametomib, so more copy-pasting of magic numbers from C headers :(
    static ref HW_NCPU: [c_int; 2] = [6, 3];
    static ref KERN_CPTIME2: [c_int; 3] = [1, 71, 0];
    static ref KERN_BOOTTIME: [c_int; 2] = [1, 21];
    static ref VM_UVMEXP: [c_int; 2] = [2, 4];
    static ref VFS_BCACHESTAT: [c_int; 3] = [10, 0, 3];
}

/// An implementation of `Platform` for OpenBSD.
/// See `Platform` for documentation.
impl Platform for PlatformImpl {
    #[inline(always)]
    fn new() -> Self {
        PlatformImpl
    }

    fn cpu_load(&self) -> io::Result<DelayedMeasurement<Vec<CPULoad>>> {
        let loads = try!(measure_cpu());
        Ok(DelayedMeasurement::new(
                Box::new(move || Ok(loads.iter()
                               .zip(try!(measure_cpu()).iter())
                               .map(|(prev, now)| (*now - prev).to_cpuload())
                               .collect::<Vec<_>>()))))
    }

    fn load_average(&self) -> io::Result<LoadAverage> {
        unix::load_average()
    }

    fn memory(&self) -> io::Result<Memory> {
        let mut uvm_info = uvmexp::default(); sysctl!(VM_UVMEXP, &mut uvm_info, mem::size_of::<uvmexp>());
        let mut bcache_info = bcachestats::default(); sysctl!(VFS_BCACHESTAT, &mut bcache_info, mem::size_of::<bcachestats>());
        let total = ByteSize::kib((uvm_info.npages << *bsd::PAGESHIFT) as usize);
        let pmem = PlatformMemory {
            active: ByteSize::kib((uvm_info.active << *bsd::PAGESHIFT) as usize),
            inactive: ByteSize::kib((uvm_info.inactive << *bsd::PAGESHIFT) as usize),
            wired: ByteSize::kib((uvm_info.wired << *bsd::PAGESHIFT) as usize),
            cache: ByteSize::kib((bcache_info.numbufpages << *bsd::PAGESHIFT) as usize),
            free: ByteSize::kib((uvm_info.free << *bsd::PAGESHIFT) as usize),
            paging: ByteSize::kib((uvm_info.paging << *bsd::PAGESHIFT) as usize),
        };
        Ok(Memory {
            total: total,
            free: pmem.inactive + pmem.cache + pmem.free + pmem.paging,
            platform_memory: pmem,
        })
    }

    fn boot_time(&self) -> io::Result<DateTime<UTC>> {
        let mut data: timeval = unsafe { mem::zeroed() };
        sysctl!(KERN_BOOTTIME, &mut data, mem::size_of::<timeval>());
        Ok(DateTime::<UTC>::from_utc(NaiveDateTime::from_timestamp(data.tv_sec, data.tv_usec as u32), UTC))
    }

    // /dev/apm is probably the nicest interface I've seen :)
    fn battery_life(&self) -> io::Result<BatteryLife> {
        let f = try!(fs::File::open("/dev/apm"));
        let mut info = apm_power_info::default();
        if unsafe { ioctl(f.as_raw_fd(), *APM_IOC_GETPOWER, &mut info) } == -1 {
            return Err(io::Error::new(io::ErrorKind::Other, "ioctl() failed"))
        }
        if info.battery_state == 0xff { // APM_BATT_UNKNOWN
            return Err(io::Error::new(io::ErrorKind::Other, "Battery state unknown"))
        }
        if info.battery_state == 4 { // APM_BATTERY_ABSENT
            return Err(io::Error::new(io::ErrorKind::Other, "Battery absent"))
        }
        Ok(BatteryLife {
            remaining_capacity: info.battery_life as f32,
            remaining_time: time::Duration::from_secs(info.minutes_left as u64),
        })
    }

    fn on_ac_power(&self) -> io::Result<bool> {
        let f = try!(fs::File::open("/dev/apm"));
        let mut info = apm_power_info::default();
        if unsafe { ioctl(f.as_raw_fd(), *APM_IOC_GETPOWER, &mut info) } == -1 {
            return Err(io::Error::new(io::ErrorKind::Other, "ioctl() failed"))
        }
        Ok(info.ac_state == 0x01) // APM_AC_ON
    }

    fn mounts(&self) -> io::Result<Vec<Filesystem>> {
        Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
    }

    fn mount_at<P: AsRef<path::Path>>(&self, _: P) -> io::Result<Filesystem> {
        Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
    }

    fn networks(&self) -> io::Result<BTreeMap<String, Network>> {
        unix::networks()
    }
}

fn measure_cpu() -> io::Result<Vec<CpuTime>> {
    let mut cpus: usize = 0;
    sysctl!(HW_NCPU, &mut cpus, mem::size_of::<usize>());
    let mut data: Vec<bsd::sysctl_cpu> = Vec::with_capacity(cpus);
    unsafe { data.set_len(cpus) };
    for i in 0..cpus {
        let mut mib = KERN_CPTIME2.clone();
        mib[2] = i as i32;
        sysctl!(mib, &mut data[i], mem::size_of::<bsd::sysctl_cpu>());
    }
    Ok(data.into_iter().map(|cpu| cpu.into()).collect())
}

#[derive(Default, Debug)]
#[repr(C)]
struct apm_power_info {
    battery_state: c_uchar,
    ac_state: c_uchar,
    battery_life: c_uchar,
    spare1: c_uchar,
    minutes_left: c_uint,
    spare2: [c_uint; 6],
}

#[derive(Default, Debug)]
#[repr(C)]
struct bcachestats {
    numbufs: i64,		/* number of buffers allocated */
    numbufpages: i64,		/* number of pages in buffer cache */
    numdirtypages: i64, 		/* number of dirty free pages */
    numcleanpages: i64, 		/* number of clean free pages */
    pendingwrites: i64,		/* number of pending writes */
    pendingreads: i64,		/* number of pending reads */
    numwrites: i64,		/* total writes started */
    numreads: i64,		/* total reads started */
    cachehits: i64,		/* total reads found in cache */
    busymapped: i64,		/* number of busy and mapped buffers */
    dmapages: i64,		/* dma reachable pages in buffer cache */
    highpages: i64,		/* pages above dma region */
    delwribufs: i64,		/* delayed write buffers */
    kvaslots: i64,		/* kva slots total */
    kvaslots_avail: i64,		/* available kva slots */
    highflips: i64,		/* total flips to above DMA */
    highflops: i64,		/* total failed flips to above DMA */
    dmaflips: i64,		/* total flips from high to DMA */
}

#[derive(Default, Debug)]
#[repr(C)]
struct uvmexp {
    /* vm_page constants */
    pagesize: c_int,   /* size of a page (PAGE_SIZE): must be power of 2 */
    pagemask: c_int,   /* page mask */
    pageshift: c_int,  /* page shift */

    /* vm_page counters */
    npages: c_int,     /* number of pages we manage */
    free: c_int,       /* number of free pages */
    active: c_int,     /* number of active pages */
    inactive: c_int,   /* number of pages that we free'd but may want back */
    paging: c_int,	/* number of pages in the process of being paged out */
    wired: c_int,      /* number of wired pages */

    zeropages: c_int,		/* number of zero'd pages */
    reserve_pagedaemon: c_int, /* number of pages reserved for pagedaemon */
    reserve_kernel: c_int,	/* number of pages reserved for kernel */
    anonpages: c_int,		/* number of pages used by anon pagers */
    vnodepages: c_int,		/* number of pages used by vnode page cache */
    vtextpages: c_int,		/* number of pages used by vtext vnodes */

    /* pageout params */
    freemin: c_int,    /* min number of free pages */
    freetarg: c_int,   /* target number of free pages */
    inactarg: c_int,   /* target number of inactive pages */
    wiredmax: c_int,   /* max number of wired pages */
    anonmin: c_int,	/* min threshold for anon pages */
    vtextmin: c_int,	/* min threshold for vtext pages */
    vnodemin: c_int,	/* min threshold for vnode pages */
    anonminpct: c_int,	/* min percent anon pages */
    vtextminpct: c_int,/* min percent vtext pages */
    vnodeminpct: c_int,/* min percent vnode pages */

    /* swap */
    nswapdev: c_int,	/* number of configured swap devices in system */
    swpages: c_int,	/* number of PAGE_SIZE'ed swap pages */
    swpginuse: c_int,	/* number of swap pages in use */
    swpgonly: c_int,	/* number of swap pages in use, not also in RAM */
    nswget: c_int,	/* number of times fault calls uvm_swap_get() */
    nanon: c_int,	/* number total of anon's in system */
    nanonneeded: c_int,/* number of anons currently needed */
    nfreeanon: c_int,	/* number of free anon's */

    /* stat counters */
    faults: c_int,		/* page fault count */
    traps: c_int,		/* trap count */
    intrs: c_int,		/* interrupt count */
    swtch: c_int,		/* context switch count */
    softs: c_int,		/* software interrupt count */
    syscalls: c_int,		/* system calls */
    pageins: c_int,		/* pagein operation count */
    /* pageouts are in pdpageouts below */
    obsolete_swapins: c_int,	/* swapins */
    obsolete_swapouts: c_int,	/* swapouts */
    pgswapin: c_int,		/* pages swapped in */
    pgswapout: c_int,		/* pages swapped out */
    forks: c_int,  		/* forks */
    forks_ppwait: c_int,	/* forks where parent waits */
    forks_sharevm: c_int,	/* forks where vmspace is shared */
    pga_zerohit: c_int,	/* pagealloc where zero wanted and zero
                           was available */
    pga_zeromiss: c_int,	/* pagealloc where zero wanted and zero
                               not available */
    zeroaborts: c_int,		/* number of times page zeroing was
                               aborted */

    /* fault subcounters */
    fltnoram: c_int,	/* number of times fault was out of ram */
    fltnoanon: c_int,	/* number of times fault was out of anons */
    fltnoamap: c_int,	/* number of times fault was out of amap chunks */
    fltpgwait: c_int,	/* number of times fault had to wait on a page */
    fltpgrele: c_int,	/* number of times fault found a released page */
    fltrelck: c_int,	/* number of times fault relock called */
    fltrelckok: c_int,	/* number of times fault relock is a success */
    fltanget: c_int,	/* number of times fault gets anon page */
    fltanretry: c_int,	/* number of times fault retrys an anon get */
    fltamcopy: c_int,	/* number of times fault clears "needs copy" */
    fltnamap: c_int,	/* number of times fault maps a neighbor anon page */
    fltnomap: c_int,	/* number of times fault maps a neighbor obj page */
    fltlget: c_int,	/* number of times fault does a locked pgo_get */
    fltget: c_int,	/* number of times fault does an unlocked get */
    flt_anon: c_int,	/* number of times fault anon (case 1a) */
    flt_acow: c_int,	/* number of times fault anon cow (case 1b) */
    flt_obj: c_int,	/* number of times fault is on object page (2a) */
    flt_prcopy: c_int,	/* number of times fault promotes with copy (2b) */
    flt_przero: c_int,	/* number of times fault promotes with zerofill (2b) */

    /* daemon counters */
    pdwoke: c_int,	/* number of times daemon woke up */
    pdrevs: c_int,	/* number of times daemon rev'd clock hand */
    pdswout: c_int,	/* number of times daemon called for swapout */
    pdfreed: c_int,	/* number of pages daemon freed since boot */
    pdscans: c_int,	/* number of pages daemon scanned since boot */
    pdanscan: c_int,	/* number of anonymous pages scanned by daemon */
    pdobscan: c_int,	/* number of object pages scanned by daemon */
    pdreact: c_int,	/* number of pages daemon reactivated since boot */
    pdbusy: c_int,	/* number of times daemon found a busy page */
    pdpageouts: c_int,	/* number of times daemon started a pageout */
    pdpending: c_int,	/* number of times daemon got a pending pagout */
    pddeact: c_int,	/* number of pages daemon deactivates */
    pdreanon: c_int,	/* anon pages reactivated due to min threshold */
    pdrevnode: c_int,	/* vnode pages reactivated due to min threshold */
    pdrevtext: c_int,	/* vtext pages reactivated due to min threshold */

    fpswtch: c_int,	/* FPU context switches */
    kmapent: c_int,	/* number of kernel map entries */
}
<commit_msg>openbsd: UTC -> Utc<commit_after>use std::{io, path, ptr, time, fs, mem};
use std::os::unix::io::AsRawFd;
use std::mem::size_of;
use libc::{c_void, c_int, c_uint, c_ulong, c_uchar, ioctl, sysctl, timeval};
use data::*;
use super::common::*;
use super::unix;
use super::bsd;

pub struct PlatformImpl;

macro_rules! sysctl {
    ($mib:expr, $dataptr:expr, $size:expr, $shouldcheck:expr) => {
        {
            let mib = &$mib;
            let mut size = $size;
            if unsafe { sysctl(&mib[0], mib.len() as u32,
                               $dataptr as *mut _ as *mut c_void, &mut size, ptr::null_mut(), 0) } != 0 && $shouldcheck {
                return Err(io::Error::new(io::ErrorKind::Other, "sysctl() failed"))
            }
            size
        }
    };
    ($mib:expr, $dataptr:expr, $size:expr) => {
        sysctl!($mib, $dataptr, $size, true)
    }
}

lazy_static! {
    static ref APM_IOC_GETPOWER: c_ulong = (0x40000000u64 | ((size_of::<apm_power_info>() & 0x1fff) << 16) as u64 | (0x41 << 8) | 3);
    // OpenBSD does not have sysctlnametomib, so more copy-pasting of magic numbers from C headers :(
    static ref HW_NCPU: [c_int; 2] = [6, 3];
    static ref KERN_CPTIME2: [c_int; 3] = [1, 71, 0];
    static ref KERN_BOOTTIME: [c_int; 2] = [1, 21];
    static ref VM_UVMEXP: [c_int; 2] = [2, 4];
    static ref VFS_BCACHESTAT: [c_int; 3] = [10, 0, 3];
}

/// An implementation of `Platform` for OpenBSD.
/// See `Platform` for documentation.
impl Platform for PlatformImpl {
    #[inline(always)]
    fn new() -> Self {
        PlatformImpl
    }

    fn cpu_load(&self) -> io::Result<DelayedMeasurement<Vec<CPULoad>>> {
        let loads = try!(measure_cpu());
        Ok(DelayedMeasurement::new(
                Box::new(move || Ok(loads.iter()
                               .zip(try!(measure_cpu()).iter())
                               .map(|(prev, now)| (*now - prev).to_cpuload())
                               .collect::<Vec<_>>()))))
    }

    fn load_average(&self) -> io::Result<LoadAverage> {
        unix::load_average()
    }

    fn memory(&self) -> io::Result<Memory> {
        let mut uvm_info = uvmexp::default(); sysctl!(VM_UVMEXP, &mut uvm_info, mem::size_of::<uvmexp>());
        let mut bcache_info = bcachestats::default(); sysctl!(VFS_BCACHESTAT, &mut bcache_info, mem::size_of::<bcachestats>());
        let total = ByteSize::kib((uvm_info.npages << *bsd::PAGESHIFT) as usize);
        let pmem = PlatformMemory {
            active: ByteSize::kib((uvm_info.active << *bsd::PAGESHIFT) as usize),
            inactive: ByteSize::kib((uvm_info.inactive << *bsd::PAGESHIFT) as usize),
            wired: ByteSize::kib((uvm_info.wired << *bsd::PAGESHIFT) as usize),
            cache: ByteSize::kib((bcache_info.numbufpages << *bsd::PAGESHIFT) as usize),
            free: ByteSize::kib((uvm_info.free << *bsd::PAGESHIFT) as usize),
            paging: ByteSize::kib((uvm_info.paging << *bsd::PAGESHIFT) as usize),
        };
        Ok(Memory {
            total: total,
            free: pmem.inactive + pmem.cache + pmem.free + pmem.paging,
            platform_memory: pmem,
        })
    }

    fn boot_time(&self) -> io::Result<DateTime<Utc>> {
        let mut data: timeval = unsafe { mem::zeroed() };
        sysctl!(KERN_BOOTTIME, &mut data, mem::size_of::<timeval>());
        Ok(DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(data.tv_sec, data.tv_usec as u32), Utc))
    }

    // /dev/apm is probably the nicest interface I've seen :)
    fn battery_life(&self) -> io::Result<BatteryLife> {
        let f = try!(fs::File::open("/dev/apm"));
        let mut info = apm_power_info::default();
        if unsafe { ioctl(f.as_raw_fd(), *APM_IOC_GETPOWER, &mut info) } == -1 {
            return Err(io::Error::new(io::ErrorKind::Other, "ioctl() failed"))
        }
        if info.battery_state == 0xff { // APM_BATT_UNKNOWN
            return Err(io::Error::new(io::ErrorKind::Other, "Battery state unknown"))
        }
        if info.battery_state == 4 { // APM_BATTERY_ABSENT
            return Err(io::Error::new(io::ErrorKind::Other, "Battery absent"))
        }
        Ok(BatteryLife {
            remaining_capacity: info.battery_life as f32,
            remaining_time: time::Duration::from_secs(info.minutes_left as u64),
        })
    }

    fn on_ac_power(&self) -> io::Result<bool> {
        let f = try!(fs::File::open("/dev/apm"));
        let mut info = apm_power_info::default();
        if unsafe { ioctl(f.as_raw_fd(), *APM_IOC_GETPOWER, &mut info) } == -1 {
            return Err(io::Error::new(io::ErrorKind::Other, "ioctl() failed"))
        }
        Ok(info.ac_state == 0x01) // APM_AC_ON
    }

    fn mounts(&self) -> io::Result<Vec<Filesystem>> {
        Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
    }

    fn mount_at<P: AsRef<path::Path>>(&self, _: P) -> io::Result<Filesystem> {
        Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
    }

    fn networks(&self) -> io::Result<BTreeMap<String, Network>> {
        unix::networks()
    }
}

fn measure_cpu() -> io::Result<Vec<CpuTime>> {
    let mut cpus: usize = 0;
    sysctl!(HW_NCPU, &mut cpus, mem::size_of::<usize>());
    let mut data: Vec<bsd::sysctl_cpu> = Vec::with_capacity(cpus);
    unsafe { data.set_len(cpus) };
    for i in 0..cpus {
        let mut mib = KERN_CPTIME2.clone();
        mib[2] = i as i32;
        sysctl!(mib, &mut data[i], mem::size_of::<bsd::sysctl_cpu>());
    }
    Ok(data.into_iter().map(|cpu| cpu.into()).collect())
}

#[derive(Default, Debug)]
#[repr(C)]
struct apm_power_info {
    battery_state: c_uchar,
    ac_state: c_uchar,
    battery_life: c_uchar,
    spare1: c_uchar,
    minutes_left: c_uint,
    spare2: [c_uint; 6],
}

#[derive(Default, Debug)]
#[repr(C)]
struct bcachestats {
    numbufs: i64,		/* number of buffers allocated */
    numbufpages: i64,		/* number of pages in buffer cache */
    numdirtypages: i64, 		/* number of dirty free pages */
    numcleanpages: i64, 		/* number of clean free pages */
    pendingwrites: i64,		/* number of pending writes */
    pendingreads: i64,		/* number of pending reads */
    numwrites: i64,		/* total writes started */
    numreads: i64,		/* total reads started */
    cachehits: i64,		/* total reads found in cache */
    busymapped: i64,		/* number of busy and mapped buffers */
    dmapages: i64,		/* dma reachable pages in buffer cache */
    highpages: i64,		/* pages above dma region */
    delwribufs: i64,		/* delayed write buffers */
    kvaslots: i64,		/* kva slots total */
    kvaslots_avail: i64,		/* available kva slots */
    highflips: i64,		/* total flips to above DMA */
    highflops: i64,		/* total failed flips to above DMA */
    dmaflips: i64,		/* total flips from high to DMA */
}

#[derive(Default, Debug)]
#[repr(C)]
struct uvmexp {
    /* vm_page constants */
    pagesize: c_int,   /* size of a page (PAGE_SIZE): must be power of 2 */
    pagemask: c_int,   /* page mask */
    pageshift: c_int,  /* page shift */

    /* vm_page counters */
    npages: c_int,     /* number of pages we manage */
    free: c_int,       /* number of free pages */
    active: c_int,     /* number of active pages */
    inactive: c_int,   /* number of pages that we free'd but may want back */
    paging: c_int,	/* number of pages in the process of being paged out */
    wired: c_int,      /* number of wired pages */

    zeropages: c_int,		/* number of zero'd pages */
    reserve_pagedaemon: c_int, /* number of pages reserved for pagedaemon */
    reserve_kernel: c_int,	/* number of pages reserved for kernel */
    anonpages: c_int,		/* number of pages used by anon pagers */
    vnodepages: c_int,		/* number of pages used by vnode page cache */
    vtextpages: c_int,		/* number of pages used by vtext vnodes */

    /* pageout params */
    freemin: c_int,    /* min number of free pages */
    freetarg: c_int,   /* target number of free pages */
    inactarg: c_int,   /* target number of inactive pages */
    wiredmax: c_int,   /* max number of wired pages */
    anonmin: c_int,	/* min threshold for anon pages */
    vtextmin: c_int,	/* min threshold for vtext pages */
    vnodemin: c_int,	/* min threshold for vnode pages */
    anonminpct: c_int,	/* min percent anon pages */
    vtextminpct: c_int,/* min percent vtext pages */
    vnodeminpct: c_int,/* min percent vnode pages */

    /* swap */
    nswapdev: c_int,	/* number of configured swap devices in system */
    swpages: c_int,	/* number of PAGE_SIZE'ed swap pages */
    swpginuse: c_int,	/* number of swap pages in use */
    swpgonly: c_int,	/* number of swap pages in use, not also in RAM */
    nswget: c_int,	/* number of times fault calls uvm_swap_get() */
    nanon: c_int,	/* number total of anon's in system */
    nanonneeded: c_int,/* number of anons currently needed */
    nfreeanon: c_int,	/* number of free anon's */

    /* stat counters */
    faults: c_int,		/* page fault count */
    traps: c_int,		/* trap count */
    intrs: c_int,		/* interrupt count */
    swtch: c_int,		/* context switch count */
    softs: c_int,		/* software interrupt count */
    syscalls: c_int,		/* system calls */
    pageins: c_int,		/* pagein operation count */
    /* pageouts are in pdpageouts below */
    obsolete_swapins: c_int,	/* swapins */
    obsolete_swapouts: c_int,	/* swapouts */
    pgswapin: c_int,		/* pages swapped in */
    pgswapout: c_int,		/* pages swapped out */
    forks: c_int,  		/* forks */
    forks_ppwait: c_int,	/* forks where parent waits */
    forks_sharevm: c_int,	/* forks where vmspace is shared */
    pga_zerohit: c_int,	/* pagealloc where zero wanted and zero
                           was available */
    pga_zeromiss: c_int,	/* pagealloc where zero wanted and zero
                               not available */
    zeroaborts: c_int,		/* number of times page zeroing was
                               aborted */

    /* fault subcounters */
    fltnoram: c_int,	/* number of times fault was out of ram */
    fltnoanon: c_int,	/* number of times fault was out of anons */
    fltnoamap: c_int,	/* number of times fault was out of amap chunks */
    fltpgwait: c_int,	/* number of times fault had to wait on a page */
    fltpgrele: c_int,	/* number of times fault found a released page */
    fltrelck: c_int,	/* number of times fault relock called */
    fltrelckok: c_int,	/* number of times fault relock is a success */
    fltanget: c_int,	/* number of times fault gets anon page */
    fltanretry: c_int,	/* number of times fault retrys an anon get */
    fltamcopy: c_int,	/* number of times fault clears "needs copy" */
    fltnamap: c_int,	/* number of times fault maps a neighbor anon page */
    fltnomap: c_int,	/* number of times fault maps a neighbor obj page */
    fltlget: c_int,	/* number of times fault does a locked pgo_get */
    fltget: c_int,	/* number of times fault does an unlocked get */
    flt_anon: c_int,	/* number of times fault anon (case 1a) */
    flt_acow: c_int,	/* number of times fault anon cow (case 1b) */
    flt_obj: c_int,	/* number of times fault is on object page (2a) */
    flt_prcopy: c_int,	/* number of times fault promotes with copy (2b) */
    flt_przero: c_int,	/* number of times fault promotes with zerofill (2b) */

    /* daemon counters */
    pdwoke: c_int,	/* number of times daemon woke up */
    pdrevs: c_int,	/* number of times daemon rev'd clock hand */
    pdswout: c_int,	/* number of times daemon called for swapout */
    pdfreed: c_int,	/* number of pages daemon freed since boot */
    pdscans: c_int,	/* number of pages daemon scanned since boot */
    pdanscan: c_int,	/* number of anonymous pages scanned by daemon */
    pdobscan: c_int,	/* number of object pages scanned by daemon */
    pdreact: c_int,	/* number of pages daemon reactivated since boot */
    pdbusy: c_int,	/* number of times daemon found a busy page */
    pdpageouts: c_int,	/* number of times daemon started a pageout */
    pdpending: c_int,	/* number of times daemon got a pending pagout */
    pddeact: c_int,	/* number of pages daemon deactivates */
    pdreanon: c_int,	/* anon pages reactivated due to min threshold */
    pdrevnode: c_int,	/* vnode pages reactivated due to min threshold */
    pdrevtext: c_int,	/* vtext pages reactivated due to min threshold */

    fpswtch: c_int,	/* FPU context switches */
    kmapent: c_int,	/* number of kernel map entries */
}
<|endoftext|>


<commit_before>extern crate reqwest;
extern crate serde;
extern crate serde_json;
extern crate regex;

use std::io::Read;
use irc::client::prelude::*;
use irc::error::Error as IrcError;
use self::reqwest::Client;
use self::reqwest::header::Connection;
use self::serde_json::Value;

use plugin::*;

#[derive(PluginName, Debug)]
pub struct Currency;

struct ConvertionRequest<'a> {
    value: f64,
    source: &'a str,
    target: &'a str,
}

macro_rules! try_option {
    ($e:expr) => {
        match $e {
            Some(v) => v,
            None    => { return None; }
        }
    }
}

impl<'a> ConvertionRequest<'a> {
    fn send(&self) -> Option<f64> {

        let response = Client::new()
            .get("https://api.fixer.io/latest")
            .form(&[("base", self.source)])
            .header(Connection::close())
            .send();

        match response {
            Ok(mut response) => {
                let mut body = String::new();
                try_option!(response.read_to_string(&mut body).ok());

                let convertion_rates: Result<Value, _> = serde_json::from_str(&body);
                match convertion_rates {
                    Ok(convertion_rates) => {

                        let rates: &Value = try_option!(convertion_rates.get("rates"));
                        let target_rate: &Value =
                            try_option!(rates.get(self.target.to_uppercase()));
                        Some(self.value * try_option!(target_rate.as_f64()))
                    }
                    Err(_) => None,
                }
            }
            Err(_) => None,
        }
    }
}

impl Currency {
    pub fn new() -> Currency {
        Currency {}
    }

    fn eval_command<'a>(&self, tokens: &'a [String]) -> Option<ConvertionRequest<'a>> {
        if let Some(parsed) = tokens[0].parse().ok() {
            Some(ConvertionRequest {
                value: parsed,
                source: &tokens[1],
                target: &tokens[2],
            })
        } else {
            None
        }
    }

    fn convert(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> {

        if command.tokens.len() < 3 {
            return self.invalid_command(server, &command);
        }

        let request = match self.eval_command(&command.tokens) {
            Some(request) => request,
            None => {
                return self.invalid_command(server, &command);
            }
        };

        match request.send() {
            Some(response) => {
                let response = format!("{} {} => {:.4} {}",
                                       request.value,
                                       request.source.to_lowercase(),
                                       response / 1.00000000,
                                       request.target.to_lowercase());

                server.send_privmsg(&command.target, &response)
            }
            None => server.send_notice(&command.source, "Error while converting given currency"),
        }
    }

    fn help(&self, server: &IrcServer, command: &mut PluginCommand) -> Result<(), IrcError> {
        let help = format!("usage: {} currency value from_currency to_currency\r\n\
                            example: 1.5 eur usd\r\n\
                            available currencies: AUD, BGN, BRL, CAD, \
                            CHF, CNY, CZK, DKK, GBP, HKD, HRK, HUF, \
                            IDR, ILS, INR, JPY, KRW, MXN, MYR, NOK, \
                            NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, \
                            TRY, USD, ZAR",
                           server.current_nickname());

        server.send_notice(&command.source, &help)
    }

    fn invalid_command(&self, server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> {
        let help = format!("Incorrect Command. \
                           Send \"{} help currency\" for help.",
                           server.current_nickname());

        server.send_notice(&command.source, &help)
    }
}

impl Plugin for Currency {
    fn is_allowed(&self, _: &IrcServer, _: &Message) -> bool {
        false
    }

    fn execute(&mut self, _: &IrcServer, _: &Message) -> Result<(), IrcError> {
        Ok(())
    }

    fn command(&mut self, server: &IrcServer, mut command: PluginCommand) -> Result<(), IrcError> {

        if command.tokens.is_empty() {
            return self.invalid_command(server, &command);
        }

        match command.tokens[0].as_ref() {
            "help" => self.help(server, &mut command),
            _ => self.convert(server, command),
        }
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>Pass on a Result from the Currency eval function<commit_after>extern crate reqwest;
extern crate serde;
extern crate serde_json;
extern crate regex;

use std::io::Read;
use std::num::ParseFloatError;

use irc::client::prelude::*;
use irc::error::Error as IrcError;

use self::reqwest::Client;
use self::reqwest::header::Connection;
use self::serde_json::Value;

use plugin::*;

#[derive(PluginName, Debug)]
pub struct Currency;

struct ConvertionRequest<'a> {
    value: f64,
    source: &'a str,
    target: &'a str,
}

macro_rules! try_option {
    ($e:expr) => {
        match $e {
            Some(v) => v,
            None    => { return None; }
        }
    }
}

impl<'a> ConvertionRequest<'a> {
    fn send(&self) -> Option<f64> {

        let response = Client::new()
            .get("https://api.fixer.io/latest")
            .form(&[("base", self.source)])
            .header(Connection::close())
            .send();

        match response {
            Ok(mut response) => {
                let mut body = String::new();
                try_option!(response.read_to_string(&mut body).ok());

                let convertion_rates: Result<Value, _> = serde_json::from_str(&body);
                match convertion_rates {
                    Ok(convertion_rates) => {

                        let rates: &Value = try_option!(convertion_rates.get("rates"));
                        let target_rate: &Value =
                            try_option!(rates.get(self.target.to_uppercase()));
                        Some(self.value * try_option!(target_rate.as_f64()))
                    }
                    Err(_) => None,
                }
            }
            Err(_) => None,
        }
    }
}

impl Currency {
    pub fn new() -> Currency {
        Currency {}
    }

    fn eval_command<'a>(&self, tokens: &'a [String]) -> Result<ConvertionRequest<'a>, ParseFloatError> {
        Ok(ConvertionRequest {
            value: tokens[0].parse()?,
            source: &tokens[1],
            target: &tokens[2],
        })
    }

    fn convert(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> {

        if command.tokens.len() < 3 {
            return self.invalid_command(server, &command);
        }

        let request = match self.eval_command(&command.tokens) {
            Ok(request) => request,
            Err(_) => {
                return self.invalid_command(server, &command);
            }
        };

        match request.send() {
            Some(response) => {
                let response = format!("{} {} => {:.4} {}",
                                       request.value,
                                       request.source.to_lowercase(),
                                       response / 1.00000000,
                                       request.target.to_lowercase());

                server.send_privmsg(&command.target, &response)
            }
            None => server.send_notice(&command.source, "Error while converting given currency"),
        }
    }

    fn help(&self, server: &IrcServer, command: &mut PluginCommand) -> Result<(), IrcError> {
        let help = format!("usage: {} currency value from_currency to_currency\r\n\
                            example: 1.5 eur usd\r\n\
                            available currencies: AUD, BGN, BRL, CAD, \
                            CHF, CNY, CZK, DKK, GBP, HKD, HRK, HUF, \
                            IDR, ILS, INR, JPY, KRW, MXN, MYR, NOK, \
                            NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, \
                            TRY, USD, ZAR",
                           server.current_nickname());

        server.send_notice(&command.source, &help)
    }

    fn invalid_command(&self, server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> {
        let help = format!("Incorrect Command. \
                           Send \"{} help currency\" for help.",
                           server.current_nickname());

        server.send_notice(&command.source, &help)
    }
}

impl Plugin for Currency {
    fn is_allowed(&self, _: &IrcServer, _: &Message) -> bool {
        false
    }

    fn execute(&mut self, _: &IrcServer, _: &Message) -> Result<(), IrcError> {
        Ok(())
    }

    fn command(&mut self, server: &IrcServer, mut command: PluginCommand) -> Result<(), IrcError> {

        if command.tokens.is_empty() {
            return self.invalid_command(server, &command);
        }

        match command.tokens[0].as_ref() {
            "help" => self.help(server, &mut command),
            _ => self.convert(server, command),
        }
    }
}

#[cfg(test)]
mod tests {}
<|endoftext|>