<commit_before>//! Checks the licenses of third-party dependencies by inspecting vendors.

use std::collections::{BTreeSet, HashSet, HashMap};
use std::fs;
use std::path::Path;
use std::process::Command;

use serde::Deserialize;
use serde_json;

const LICENSES: &[&str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "Apache-2.0 OR MIT",
    "MIT",
    "Unlicense/MIT",
    "Unlicense OR MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std/test).
const EXCEPTIONS: &[&str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "arrayref",           // BSD-2-Clause, mdbook via handlebars via pest
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "rdrand",             // ISC, mdbook, rustfmt
    "fuchsia-cprng",      // BSD-3-Clause, mdbook, rustfmt
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0, rls
    "colored",            // MPL-2.0, rustfmt
    "ordslice",           // Apache-2.0, rls
    "cloudabi",           // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5)
    "ryu",                // Apache-2.0, rls/cargo/... (because of serde)
    "bytesize",           // Apache-2.0, cargo
    "im-rc",              // MPL-2.0+, cargo
    "adler32",            // BSD-3-Clause AND Zlib, cargo dep that isn't used
    "constant_time_eq",   // CC0-1.0, rustfmt
    "utf8parse",          // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
    "vte",                // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
    "sized-chunks",       // MPL-2.0+, cargo via im-rc
    // FIXME: this dependency violates the documentation comment above:
    "fortanix-sgx-abi",   // MPL-2.0+, libstd but only for `sgx` target
];

/// Which crates to check against the whitelist?
const WHITELIST_CRATES: &[CrateVersion<'_>] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_codegen_llvm", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
const WHITELIST: &[Crate<'_>] = &[
    Crate("adler32"),
    Crate("aho-corasick"),
    Crate("annotate-snippets"),
    Crate("ansi_term"),
    Crate("arrayvec"),
    Crate("atty"),
    Crate("autocfg"),
    Crate("backtrace"),
    Crate("backtrace-sys"),
    Crate("bitflags"),
    Crate("build_const"),
    Crate("byteorder"),
    Crate("c2-chacha"),
    Crate("cc"),
    Crate("cfg-if"),
    Crate("chalk-engine"),
    Crate("chalk-macros"),
    Crate("cloudabi"),
    Crate("cmake"),
    Crate("compiler_builtins"),
    Crate("crc"),
    Crate("crc32fast"),
    Crate("crossbeam-deque"),
    Crate("crossbeam-epoch"),
    Crate("crossbeam-utils"),
    Crate("datafrog"),
    Crate("dlmalloc"),
    Crate("either"),
    Crate("ena"),
    Crate("env_logger"),
    Crate("filetime"),
    Crate("flate2"),
    Crate("fortanix-sgx-abi"),
    Crate("fuchsia-zircon"),
    Crate("fuchsia-zircon-sys"),
    Crate("getopts"),
    Crate("getrandom"),
    Crate("hashbrown"),
    Crate("humantime"),
    Crate("indexmap"),
    Crate("itertools"),
    Crate("jobserver"),
    Crate("kernel32-sys"),
    Crate("lazy_static"),
    Crate("libc"),
    Crate("libz-sys"),
    Crate("lock_api"),
    Crate("log"),
    Crate("log_settings"),
    Crate("measureme"),
    Crate("memchr"),
    Crate("memmap"),
    Crate("memoffset"),
    Crate("miniz-sys"),
    Crate("miniz_oxide"),
    Crate("miniz_oxide_c_api"),
    Crate("nodrop"),
    Crate("num_cpus"),
    Crate("owning_ref"),
    Crate("parking_lot"),
    Crate("parking_lot_core"),
    Crate("pkg-config"),
    Crate("polonius-engine"),
    Crate("ppv-lite86"),
    Crate("proc-macro2"),
    Crate("quick-error"),
    Crate("quote"),
    Crate("rand"),
    Crate("rand_chacha"),
    Crate("rand_core"),
    Crate("rand_hc"),
    Crate("rand_isaac"),
    Crate("rand_pcg"),
    Crate("rand_xorshift"),
    Crate("redox_syscall"),
    Crate("redox_termios"),
    Crate("regex"),
    Crate("regex-syntax"),
    Crate("remove_dir_all"),
    Crate("rustc-demangle"),
    Crate("rustc-hash"),
    Crate("rustc-rayon"),
    Crate("rustc-rayon-core"),
    Crate("rustc_version"),
    Crate("scoped-tls"),
    Crate("scopeguard"),
    Crate("semver"),
    Crate("semver-parser"),
    Crate("serde"),
    Crate("serde_derive"),
    Crate("smallvec"),
    Crate("stable_deref_trait"),
    Crate("syn"),
    Crate("synstructure"),
    Crate("tempfile"),
    Crate("termcolor"),
    Crate("terminon"),
    Crate("termion"),
    Crate("thread_local"),
    Crate("ucd-util"),
    Crate("unicode-width"),
    Crate("unicode-xid"),
    Crate("unreachable"),
    Crate("utf8-ranges"),
    Crate("vcpkg"),
    Crate("version_check"),
    Crate("void"),
    Crate("winapi"),
    Crate("winapi-build"),
    Crate("winapi-i686-pc-windows-gnu"),
    Crate("winapi-util"),
    Crate("winapi-x86_64-pc-windows-gnu"),
    Crate("wincolor"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to.

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate.
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl Crate<'_> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dependency is in-tree.
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(' ');
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences.
    let path = path.join("../vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // Skip our exceptions.
        let is_exception = EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("vendor/{}", exception))
        });
        if is_exception {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = !check_license(&toml) || *bad;
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of `WHITELIST_CRATES` at the given path. Changes `bad` to `true` if a
/// check failed.
///
/// Specifically, this checks that the dependencies are on the `WHITELIST`.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from Cargo metadata.
    let resolve = get_deps(path, cargo);

    // Get the whitelist in a convenient form.
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies.
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
        unapproved.append(&mut bad);
    }

    if !unapproved.is_empty() {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }

    check_crate_duplicate(&resolve, bad);
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let contents = t!(fs::read_to_string(&path));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Gets the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies.
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("../Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a>(
    whitelist: &'a HashSet<Crate<'_>>,
    resolve: &'a Resolve,
    visited: &mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
    must_be_on_whitelist: bool,
) -> BTreeSet<Crate<'a>> {
    // This will contain bad deps.
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate.
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this path is in-tree, we don't require it to be on the whitelist.
    if must_be_on_whitelist {
        // If this dependency is not on `WHITELIST`, add to bad set.
        if !whitelist.contains(&krate.into()) {
            unapproved.insert(krate.into());
        }
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!).
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
        unapproved.append(&mut bad);
    }

    unapproved
}

fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) {
    const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
        // These two crates take quite a long time to build, so don't allow two versions of them
        // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
        // under control.

        "cargo",
        "rustc-ap-syntax",
    ];
    let mut name_to_id: HashMap<_, Vec<_>> = HashMap::new();
    for node in resolve.nodes.iter() {
        name_to_id.entry(node.id.split_whitespace().next().unwrap())
            .or_default()
            .push(&node.id);
    }

    for name in FORBIDDEN_TO_HAVE_DUPLICATES {
        if name_to_id[name].len() <= 1 {
            continue
        }
        println!("crate `{}` is duplicated in `Cargo.lock`", name);
        for id in name_to_id[name].iter() {
            println!("  * {}", id);
        }
        *bad = true;
    }
}
<commit_msg>add wasi license to the licenses whitelist<commit_after>//! Checks the licenses of third-party dependencies by inspecting vendors.

use std::collections::{BTreeSet, HashSet, HashMap};
use std::fs;
use std::path::Path;
use std::process::Command;

use serde::Deserialize;
use serde_json;

const LICENSES: &[&str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "Apache-2.0 OR MIT",
    "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license
    "MIT",
    "Unlicense/MIT",
    "Unlicense OR MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std/test).
const EXCEPTIONS: &[&str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "arrayref",           // BSD-2-Clause, mdbook via handlebars via pest
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "rdrand",             // ISC, mdbook, rustfmt
    "fuchsia-cprng",      // BSD-3-Clause, mdbook, rustfmt
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0, rls
    "colored",            // MPL-2.0, rustfmt
    "ordslice",           // Apache-2.0, rls
    "cloudabi",           // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5)
    "ryu",                // Apache-2.0, rls/cargo/... (because of serde)
    "bytesize",           // Apache-2.0, cargo
    "im-rc",              // MPL-2.0+, cargo
    "adler32",            // BSD-3-Clause AND Zlib, cargo dep that isn't used
    "constant_time_eq",   // CC0-1.0, rustfmt
    "utf8parse",          // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
    "vte",                // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
    "sized-chunks",       // MPL-2.0+, cargo via im-rc
    // FIXME: this dependency violates the documentation comment above:
    "fortanix-sgx-abi",   // MPL-2.0+, libstd but only for `sgx` target
];

/// Which crates to check against the whitelist?
const WHITELIST_CRATES: &[CrateVersion<'_>] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_codegen_llvm", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
const WHITELIST: &[Crate<'_>] = &[
    Crate("adler32"),
    Crate("aho-corasick"),
    Crate("annotate-snippets"),
    Crate("ansi_term"),
    Crate("arrayvec"),
    Crate("atty"),
    Crate("autocfg"),
    Crate("backtrace"),
    Crate("backtrace-sys"),
    Crate("bitflags"),
    Crate("build_const"),
    Crate("byteorder"),
    Crate("c2-chacha"),
    Crate("cc"),
    Crate("cfg-if"),
    Crate("chalk-engine"),
    Crate("chalk-macros"),
    Crate("cloudabi"),
    Crate("cmake"),
    Crate("compiler_builtins"),
    Crate("crc"),
    Crate("crc32fast"),
    Crate("crossbeam-deque"),
    Crate("crossbeam-epoch"),
    Crate("crossbeam-utils"),
    Crate("datafrog"),
    Crate("dlmalloc"),
    Crate("either"),
    Crate("ena"),
    Crate("env_logger"),
    Crate("filetime"),
    Crate("flate2"),
    Crate("fortanix-sgx-abi"),
    Crate("fuchsia-zircon"),
    Crate("fuchsia-zircon-sys"),
    Crate("getopts"),
    Crate("getrandom"),
    Crate("hashbrown"),
    Crate("humantime"),
    Crate("indexmap"),
    Crate("itertools"),
    Crate("jobserver"),
    Crate("kernel32-sys"),
    Crate("lazy_static"),
    Crate("libc"),
    Crate("libz-sys"),
    Crate("lock_api"),
    Crate("log"),
    Crate("log_settings"),
    Crate("measureme"),
    Crate("memchr"),
    Crate("memmap"),
    Crate("memoffset"),
    Crate("miniz-sys"),
    Crate("miniz_oxide"),
    Crate("miniz_oxide_c_api"),
    Crate("nodrop"),
    Crate("num_cpus"),
    Crate("owning_ref"),
    Crate("parking_lot"),
    Crate("parking_lot_core"),
    Crate("pkg-config"),
    Crate("polonius-engine"),
    Crate("ppv-lite86"),
    Crate("proc-macro2"),
    Crate("quick-error"),
    Crate("quote"),
    Crate("rand"),
    Crate("rand_chacha"),
    Crate("rand_core"),
    Crate("rand_hc"),
    Crate("rand_isaac"),
    Crate("rand_pcg"),
    Crate("rand_xorshift"),
    Crate("redox_syscall"),
    Crate("redox_termios"),
    Crate("regex"),
    Crate("regex-syntax"),
    Crate("remove_dir_all"),
    Crate("rustc-demangle"),
    Crate("rustc-hash"),
    Crate("rustc-rayon"),
    Crate("rustc-rayon-core"),
    Crate("rustc_version"),
    Crate("scoped-tls"),
    Crate("scopeguard"),
    Crate("semver"),
    Crate("semver-parser"),
    Crate("serde"),
    Crate("serde_derive"),
    Crate("smallvec"),
    Crate("stable_deref_trait"),
    Crate("syn"),
    Crate("synstructure"),
    Crate("tempfile"),
    Crate("termcolor"),
    Crate("terminon"),
    Crate("termion"),
    Crate("thread_local"),
    Crate("ucd-util"),
    Crate("unicode-width"),
    Crate("unicode-xid"),
    Crate("unreachable"),
    Crate("utf8-ranges"),
    Crate("vcpkg"),
    Crate("version_check"),
    Crate("void"),
    Crate("winapi"),
    Crate("winapi-build"),
    Crate("winapi-i686-pc-windows-gnu"),
    Crate("winapi-util"),
    Crate("winapi-x86_64-pc-windows-gnu"),
    Crate("wincolor"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to.

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate.
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl Crate<'_> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dependency is in-tree.
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(' ');
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences.
    let path = path.join("../vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // Skip our exceptions.
        let is_exception = EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("vendor/{}", exception))
        });
        if is_exception {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = !check_license(&toml) || *bad;
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of `WHITELIST_CRATES` at the given path. Changes `bad` to `true` if a
/// check failed.
///
/// Specifically, this checks that the dependencies are on the `WHITELIST`.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from Cargo metadata.
    let resolve = get_deps(path, cargo);

    // Get the whitelist in a convenient form.
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies.
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
        unapproved.append(&mut bad);
    }

    if !unapproved.is_empty() {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }

    check_crate_duplicate(&resolve, bad);
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let contents = t!(fs::read_to_string(&path));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Gets the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies.
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("../Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a>(
    whitelist: &'a HashSet<Crate<'_>>,
    resolve: &'a Resolve,
    visited: &mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
    must_be_on_whitelist: bool,
) -> BTreeSet<Crate<'a>> {
    // This will contain bad deps.
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate.
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this path is in-tree, we don't require it to be on the whitelist.
    if must_be_on_whitelist {
        // If this dependency is not on `WHITELIST`, add to bad set.
        if !whitelist.contains(&krate.into()) {
            unapproved.insert(krate.into());
        }
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!).
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
        unapproved.append(&mut bad);
    }

    unapproved
}

fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) {
    const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
        // These two crates take quite a long time to build, so don't allow two versions of them
        // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
        // under control.

        "cargo",
        "rustc-ap-syntax",
    ];
    let mut name_to_id: HashMap<_, Vec<_>> = HashMap::new();
    for node in resolve.nodes.iter() {
        name_to_id.entry(node.id.split_whitespace().next().unwrap())
            .or_default()
            .push(&node.id);
    }

    for name in FORBIDDEN_TO_HAVE_DUPLICATES {
        if name_to_id[name].len() <= 1 {
            continue
        }
        println!("crate `{}` is duplicated in `Cargo.lock`", name);
        for id in name_to_id[name].iter() {
            println!("  * {}", id);
        }
        *bad = true;
    }
}
<|endoftext|>


<commit_before>use {
    AddPolygons,
    Borrowed,
    Color,
    Field,
    Matrix2d,
    TweenPolygonsColorContext,
    Value,
    View,
};
use vecmath::{
    identity
};

/// An animation inbetweening context with color.
pub struct TweenColorContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current color.
    pub color: Field<'a, Color>,
    /// Animation inbetweening factor.
    pub tween_factor: Field<'a, f64>,
}

impl<'a> AddPolygons<'a, TweenPolygonsColorContext<'a>> for TweenColorContext<'a> {
    #[inline(always)]
    fn polygons(&'a self, polygons: &'a [&'a [f64]]) -> TweenPolygonsColorContext<'a> {
        TweenPolygonsColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
            polygons: Value(polygons),
        }
    }
}

impl<'a> View<'a> for TweenColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            tween_factor: Borrowed(self.tween_factor.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }
}

<commit_msg>Implemented `HasColor` and `CanColor` for `TweenColorContext`<commit_after>use {
    AddPolygons,
    Borrowed,
    CanColor,
    Color,
    Field,
    HasColor,
    Matrix2d,
    TweenPolygonsColorContext,
    Value,
    View,
};
use vecmath::{
    identity
};

/// An animation inbetweening context with color.
pub struct TweenColorContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current color.
    pub color: Field<'a, Color>,
    /// Animation inbetweening factor.
    pub tween_factor: Field<'a, f64>,
}

impl<'a> HasColor<'a, Color> for TweenColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, TweenColorContext<'a>, Color> for TweenColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(value),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }
}

impl<'a> AddPolygons<'a, TweenPolygonsColorContext<'a>> for TweenColorContext<'a> {
    #[inline(always)]
    fn polygons(&'a self, polygons: &'a [&'a [f64]]) -> TweenPolygonsColorContext<'a> {
        TweenPolygonsColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
            polygons: Value(polygons),
        }
    }
}

impl<'a> View<'a> for TweenColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            tween_factor: Borrowed(self.tween_factor.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> TweenColorContext<'a> {
        TweenColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

extern crate docopt;
extern crate quiche;

use std::fs;
use std::net;
use std::path;
use std::collections::hash_map;
use std::collections::HashMap;

use docopt::Docopt;

use quiche::packet;
use quiche::rand;

const LOCAL_CONN_ID_LEN: usize = 16;

static TRANSPORT_PARAMS: quiche::TransportParams = quiche::TransportParams {
    idle_timeout: 30,
    initial_max_data: 10000000,
    initial_max_bidi_streams: 100,
    initial_max_uni_streams: 100,
    max_packet_size: 1500,
    ack_delay_exponent: 3,
    disable_migration: true,
    max_ack_delay: 25,
    initial_max_stream_data_bidi_local: 1000000,
    initial_max_stream_data_bidi_remote: 1000000,
    initial_max_stream_data_uni: 1000000,
    stateless_reset_token_present: true,
    stateless_reset_token: [0xba; 16],
};

const USAGE: &'static str = "Usage: server [options]

Options:
  -h --help         Show this screen.
  --listen <addr>   Listen on the given IP:port [default: 127.0.0.1:4433]
  --cert <file>     TLS certificate path [default: examples/cert.crt]
  --key <file>      TLS certificate key path [default: examples/cert.key]
  --root <dir>      Root directory [default: examples/root/]
  --name <str>      Name of the server [default: quic.tech]
";

fn main() {
    let mut buf = [0; 65535];
    let mut out = [0; 65535];

    let args = Docopt::new(USAGE)
                      .and_then(|dopt| dopt.parse())
                      .unwrap_or_else(|e| e.exit());

    let socket = net::UdpSocket::bind(args.get_str("--listen")).unwrap();

    let mut connections: HashMap<net::SocketAddr, Box<quiche::Conn>> = HashMap::new();

    loop {
        let (len, src) = socket.recv_from(&mut buf).unwrap();
        println!("Got {} bytes from {}", len, src);

        let buf = &mut buf[..len];

        let hdr = if packet::has_long_header(buf[0]) {
            packet::Header::decode_long(buf)
        } else {
            packet::Header::decode_short(buf, LOCAL_CONN_ID_LEN)
        };

        let hdr = match hdr {
            Ok(v) => v,

            Err(e) => panic!("PARSING HEADER FAILED: {:?}", e),
        };

        let conn = match connections.entry(src) {
            hash_map::Entry::Vacant(v) =>{
                if hdr.version != quiche::VERSION_DRAFT15 {
                    println!("VERSION NEGOTIATION");

                    let len = packet::negotiate_version(&hdr, &mut out).unwrap();
                    let out = &out[..len];

                    socket.send_to(out, &src).unwrap();
                    continue;
                }

                if hdr.ty != packet::Type::Initial {
                    println!("NOT INITIAL PACKET");
                    continue;
                }

                let mut scid: [u8; LOCAL_CONN_ID_LEN] = [0; LOCAL_CONN_ID_LEN];
                rand::rand_bytes(&mut scid[..]);

                let config = quiche::Config {
                    version: quiche::VERSION_DRAFT15,

                    local_conn_id: &scid,

                    local_transport_params: &TRANSPORT_PARAMS,

                    tls_server_name: args.get_str("--name"),
                    tls_certificate: args.get_str("--cert"),
                    tls_certificate_key: args.get_str("--key"),
                };

                println!("Created connection {:x?}", scid);

                let conn = quiche::Conn::new(config, true).unwrap();

                v.insert(conn)
            },

            hash_map::Entry::Occupied(v) => v.into_mut(),
        };

        let mut left = len;

        // Process potentially coalesced packets.
        while left > 0 {
            let read = match conn.recv(&mut buf[len - left..len]) {
                Ok(v)  => v,
                Err(e) => panic!("RECV FAILED: {:?}", e),
            };

            left -= read;
        }

        let streams: Vec<u64> = conn.stream_iter().collect();
        for s in streams {
            println!("Readable stream {}", s);

            handle_stream(conn, s, &args);
        }

        loop {
            let write = match conn.send(&mut out) {
                Ok(v)   => v,
                Err(quiche::Error::NothingToDo) => {
                    println!("DONE WRITING");
                    break;
                },

                Err(e)  => panic!("SEND FAILED: {:?}", e),
            };

            // TODO: coalesce packets.
            socket.send_to(&out[..write], &src).unwrap();

            println!("WRITTEN {}", write);
        }
    }
}

fn handle_stream(conn: &mut quiche::Conn, stream: u64, args: &docopt::ArgvMap) {
    let stream_data = match conn.stream_recv(stream) {
        Ok(v) => v,
        Err(e) => panic!("STREAM RECV FAILED {:?}", e),
    };

    if &stream_data[..4] == b"GET " {
        let uri = &stream_data[4..stream_data.len()];
        let uri = String::from_utf8(uri.to_vec()).unwrap();
        let uri = String::from(uri.lines().next().unwrap());
        let uri = path::Path::new(&uri);
        let mut path = path::PathBuf::from(args.get_str("--root"));

        for c in uri.components() {
            match c {
                path::Component::Normal(v) => path.push(v),
                _ => (),
            }
        }

        println!("Got GET request for {:?} on stream {}", path, stream);

        let error = Vec::from(String::from("Not Found!"));
        let data = fs::read(path.as_path()).unwrap_or(error);
        if let Err(e) = conn.stream_send(stream, &data, true) {
            panic!("STREAM SEND FAILED {:?}", e);
        }
    }
}
<commit_msg>server: cap input/output buffers to more sane limits<commit_after>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

extern crate docopt;
extern crate quiche;

use std::fs;
use std::net;
use std::path;
use std::collections::hash_map;
use std::collections::HashMap;

use docopt::Docopt;

use quiche::packet;
use quiche::rand;

const LOCAL_CONN_ID_LEN: usize = 16;

const TRANSPORT_PARAMS: quiche::TransportParams = quiche::TransportParams {
    idle_timeout: 30,
    initial_max_data: 10000000,
    initial_max_bidi_streams: 100,
    initial_max_uni_streams: 100,
    max_packet_size: 1500,
    ack_delay_exponent: 3,
    disable_migration: true,
    max_ack_delay: 25,
    initial_max_stream_data_bidi_local: 1000000,
    initial_max_stream_data_bidi_remote: 1000000,
    initial_max_stream_data_uni: 1000000,
    stateless_reset_token_present: true,
    stateless_reset_token: [0xba; 16],
};

const USAGE: &'static str = "Usage: server [options]

Options:
  -h --help         Show this screen.
  --listen <addr>   Listen on the given IP:port [default: 127.0.0.1:4433]
  --cert <file>     TLS certificate path [default: examples/cert.crt]
  --key <file>      TLS certificate key path [default: examples/cert.key]
  --root <dir>      Root directory [default: examples/root/]
  --name <str>      Name of the server [default: quic.tech]
";

fn main() {
    let mut buf = [0; TRANSPORT_PARAMS.max_packet_size as usize];
    let mut out = [0; TRANSPORT_PARAMS.max_packet_size as usize];

    let args = Docopt::new(USAGE)
                      .and_then(|dopt| dopt.parse())
                      .unwrap_or_else(|e| e.exit());

    let socket = net::UdpSocket::bind(args.get_str("--listen")).unwrap();

    let mut connections: HashMap<net::SocketAddr, Box<quiche::Conn>> = HashMap::new();

    loop {
        let (len, src) = socket.recv_from(&mut buf).unwrap();
        println!("Got {} bytes from {}", len, src);

        let buf = &mut buf[..len];

        let hdr = if packet::has_long_header(buf[0]) {
            packet::Header::decode_long(buf)
        } else {
            packet::Header::decode_short(buf, LOCAL_CONN_ID_LEN)
        };

        let hdr = match hdr {
            Ok(v) => v,

            Err(e) => panic!("PARSING HEADER FAILED: {:?}", e),
        };

        let conn = match connections.entry(src) {
            hash_map::Entry::Vacant(v) =>{
                if hdr.version != quiche::VERSION_DRAFT15 {
                    println!("VERSION NEGOTIATION");

                    let len = packet::negotiate_version(&hdr, &mut out).unwrap();
                    let out = &out[..len];

                    socket.send_to(out, &src).unwrap();
                    continue;
                }

                if hdr.ty != packet::Type::Initial {
                    println!("NOT INITIAL PACKET");
                    continue;
                }

                let mut scid: [u8; LOCAL_CONN_ID_LEN] = [0; LOCAL_CONN_ID_LEN];
                rand::rand_bytes(&mut scid[..]);

                let config = quiche::Config {
                    version: quiche::VERSION_DRAFT15,

                    local_conn_id: &scid,

                    local_transport_params: &TRANSPORT_PARAMS,

                    tls_server_name: args.get_str("--name"),
                    tls_certificate: args.get_str("--cert"),
                    tls_certificate_key: args.get_str("--key"),
                };

                println!("Created connection {:x?}", scid);

                let conn = quiche::Conn::new(config, true).unwrap();

                v.insert(conn)
            },

            hash_map::Entry::Occupied(v) => v.into_mut(),
        };

        let mut left = len;

        // Process potentially coalesced packets.
        while left > 0 {
            let read = match conn.recv(&mut buf[len - left..len]) {
                Ok(v)  => v,
                Err(e) => panic!("RECV FAILED: {:?}", e),
            };

            left -= read;
        }

        let streams: Vec<u64> = conn.stream_iter().collect();
        for s in streams {
            println!("Readable stream {}", s);

            handle_stream(conn, s, &args);
        }

        loop {
            let write = match conn.send(&mut out) {
                Ok(v)   => v,
                Err(quiche::Error::NothingToDo) => {
                    println!("DONE WRITING");
                    break;
                },

                Err(e)  => panic!("SEND FAILED: {:?}", e),
            };

            // TODO: coalesce packets.
            socket.send_to(&out[..write], &src).unwrap();

            println!("WRITTEN {}", write);
        }
    }
}

fn handle_stream(conn: &mut quiche::Conn, stream: u64, args: &docopt::ArgvMap) {
    let stream_data = match conn.stream_recv(stream) {
        Ok(v) => v,
        Err(e) => panic!("STREAM RECV FAILED {:?}", e),
    };

    if &stream_data[..4] == b"GET " {
        let uri = &stream_data[4..stream_data.len()];
        let uri = String::from_utf8(uri.to_vec()).unwrap();
        let uri = String::from(uri.lines().next().unwrap());
        let uri = path::Path::new(&uri);
        let mut path = path::PathBuf::from(args.get_str("--root"));

        for c in uri.components() {
            match c {
                path::Component::Normal(v) => path.push(v),
                _ => (),
            }
        }

        println!("Got GET request for {:?} on stream {}", path, stream);

        let error = Vec::from(String::from("Not Found!"));
        let data = fs::read(path.as_path()).unwrap_or(error);
        if let Err(e) = conn.stream_send(stream, &data, true) {
            panic!("STREAM SEND FAILED {:?}", e);
        }
    }
}
<|endoftext|>


<commit_before>//! "Weighted" graph types

use std;
use std::ops;
use std::fmt::Debug;

use smallvec::SmallVec;

use super::iter::{Indices,Successors};
use super::interface::{self, Id, Node as INode, Edge as IEdge};
use super::common::{IndexType,NodeIndex,EdgeIndex,DefaultIndexType};

/// Trait bounds for types used as edge and node data payloads.
pub trait Data: Clone + Debug {}
impl<T> Data for T where T: Clone + Debug {}

// ----------------------------------------------------------------
// Edge

/// Weighted edge type.
#[derive(Clone,Debug)]
pub struct Edge<T: Data, I: Id> {
    source: I,
    target: I,
    data: T
}

impl<T, I> interface::Edge for Edge<T, I>
    where T: Data, I: Id {
    impl_basic_edge!(I);
}

impl<T: Data, I: Id> Edge<T, I> {
    /// Create an edge with the given source & target node indices and
    /// weight data.
    pub fn new(source: I, target: I, data: T) -> Self {
        Edge{source: source, target: target, data: data}
    }
}
///
impl<T: Data, I: Id> std::ops::Deref for Edge<T, I> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T: Data, I: Id, I2: Copy> From<(I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}

impl<T: Data, I: Id, I2: Copy> From<(I2, I2, T)> for Edge<T, I>
    where I: From<I2> {
    fn from(u: (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2)
    }
}

impl<'a, T: Data, I: Id, I2: Copy> From<&'a (I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: &'a (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}
impl<'a, T: Data, I: Id, I2: Copy> From<&'a (I2, I2, T)> for Edge<T, I>
    where T: Clone, I: From<I2> {
    fn from(u: &'a (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2.clone())
    }
}

// ----------------------------------------------------------------
// Node

///  Weighted node implementation.
///
/// A reference to the node's weight data can be obtained using the type's
/// `Deref` implementation.
///
/// ```rust
/// use cripes::util::graph::{EdgeIndex,WeightedNode};
///
/// # fn main() {
/// let n = WeightedNode::<_, EdgeIndex<u8>>::new(32);
/// assert_eq!(32, *n);
/// # }
/// ```

#[derive(Clone,Debug)]
pub struct Node<T: Data, I: Id> {
    incoming_edges: SmallVec<[I; 8]>,
    outgoing_edges: SmallVec<[I; 8]>,
    data: T
}

impl<T: Data, I: Id> Node<T, I> {
    /// Instantiate a new node with the given data.
    pub fn new(data: T) -> Self {
        Node{incoming_edges: SmallVec::new(), outgoing_edges: SmallVec::new(), data: data}
    }
}

impl<T: Data, I: Id> std::ops::Deref for Node<T, I> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T, I> interface::Node for Node<T, I>
        where T: Data, I: Id {
    impl_basic_node!(I);
}

// ----------------------------------------------------------------
// Graph

/// Directed graph with user-defined node and edge weights.
#[derive(Clone,Debug)]
pub struct Graph<N: Data, E: Data, Ix: IndexType = DefaultIndexType> {
    nodes: Vec<Node<N, EdgeIndex<Ix>>>,
    edges: Vec<Edge<E, NodeIndex<Ix>>>
}

impl<N, E, Ix> interface::Graph for Graph<N, E, Ix>
    where N: Data, E: Data, Ix: IndexType {
    type NodeId = NodeIndex<Ix>;
    type EdgeId = EdgeIndex<Ix>;
    type Node = Node<N, Self::EdgeId>;
    type Edge = Edge<E, Self::NodeId>;
    type EdgeIdIterator = Indices<Self::EdgeId>;
    type NodeIdIterator = Indices<Self::NodeId>;

    fn new() -> Self {
        Graph{nodes: Vec::new(), edges: Vec::new()}
    }

    fn add_node(&mut self, n: Self::Node) -> Self::NodeId {
        self.nodes.push(n);
        NodeIndex::new(self.nodes.len() - 1)
    }

    #[inline(always)]
    fn contains_node(&self, n: Self::NodeId) -> bool {
        n.index() < self.nodes.len()
    }

    #[inline(always)]
    fn node(&self, n: Self::NodeId) -> &Self::Node {
        &self.nodes[n.index()]
    }

    #[inline(always)]
    fn node_mut(&mut self, n: Self::NodeId) -> &mut Self::Node {
        &mut self.nodes[n.index()]
    }

    #[inline]
    fn node_ids(&self) -> Self::NodeIdIterator {
        Indices::new(0..self.nodes.len())
    }

    #[inline]
    fn node_count(&self) -> usize {
        self.nodes.len()
    }

    fn add_edge(&mut self, e: Self::Edge) -> Self::EdgeId {
        let srcidx = e.source();
        let destidx = e.target();

        self.edges.push(e);
        let index = EdgeIndex::new(self.edges.len() - 1);

        // Update cross-referenced edge lists for the connected nodes.
        self.nodes[srcidx.index()].add_outgoing_edge(index);
        self.nodes[destidx.index()].add_incoming_edge(index);

        index
    }

    fn edge(&self, e: Self::EdgeId) -> &Self::Edge {
        &self.edges[e.index()]
    }

    fn contains_edge(&self, e: Self::EdgeId) -> bool {
        e.index() < self.edges.len()
    }

    fn edge_ids(&self) -> Self::EdgeIdIterator {
        Indices::new(0..self.edges.len())
    }

    fn edge_count(&self) -> usize {
        self.edges.len()
    }
}

impl<N: Data, E: Data, Ix: IndexType> Graph<N, E, Ix> {
    /// Add a node to the graph.
    ///
    /// @return Index of the newly-added node.
    pub fn add_node(&mut self, data: N) -> NodeIndex<Ix> {
        <Self as interface::Graph>::add_node(self, <Self as interface::Graph>::Node::new(data))
    }

    /// Add an edge to the graph.
    ///
    /// The source and target nodes, as identified by calling `edge.source()`
    /// and `edge.target()` on the edge, will be updated as appropriate.
    ///
    /// **Panics** if either of the source or target node indices are invalid.
    ///
    /// @return Index of the newly-added edge.
    ///
    /// @fixme Is there any way we can make this operation atomic, or at least
    /// less drawn-out?
    pub fn add_edge(&mut self, source: NodeIndex<Ix>, target: NodeIndex<Ix>, data: E) -> EdgeIndex<Ix> {
        panic_unless!(source.index() < self.nodes.len(), "Invalid source-node index provided to `Graph::add_edge`");
        panic_unless!(target.index() < self.nodes.len(), "Invalid target-node index provided to `Graph::add_edge`");

        // Add the edge itself
        self.edges.push(<Self as interface::Graph>::Edge::new(source, target, data));

        // ...and add cross-references to the nodes.
        let edge = EdgeIndex::new(self.edges.len() - 1);
        self.nodes[source.index()].add_outgoing_edge(edge);
        self.nodes[target.index()].add_incoming_edge(edge);

        edge
    }
}

// Implement node-data lookup via indexing.
macro_rules! graph_index_impl {
    ($tp: ty, $n: ident, $e: ident, $r: ident, $m: ident) => {
        impl<$n: Data, $e: Data, Ix: IndexType> ops::Index<$tp> for Graph<N, E, Ix> {
            type Output = $r;
            fn index(&self, ix: $tp) -> &$r {
                &self.$m[ix.index()].data
            }

        }
        impl<$n: Data, $e: Data, Ix: IndexType> ops::IndexMut<$tp> for Graph<N, E, Ix> {
            fn index_mut(&mut self, ix: $tp) -> &mut $r {
                &mut self.$m[ix.index()].data
            }

        }
    }
}
graph_index_impl!(EdgeIndex<Ix>, N, E, E, edges);
graph_index_impl!(NodeIndex<Ix>, N, E, N, nodes);
<commit_msg>util/graph/weighted.rs: add missing `DerefMut` impls for Node, Edge<commit_after>//! "Weighted" graph types

use std;
use std::ops::{Deref,DerefMut};
use std::fmt::Debug;

use smallvec::SmallVec;

use super::iter::{Indices,Successors};
use super::interface::{self, Id, Node as INode, Edge as IEdge};
use super::common::{IndexType,NodeIndex,EdgeIndex,DefaultIndexType};

/// Trait bounds for types used as edge and node data payloads.
pub trait Data: Clone + Debug {}
impl<T> Data for T where T: Clone + Debug {}

// ----------------------------------------------------------------
// Edge

/// Weighted edge type.
#[derive(Clone,Debug)]
pub struct Edge<T: Data, I: Id> {
    source: I,
    target: I,
    data: T
}

impl<T, I> interface::Edge for Edge<T, I>
    where T: Data, I: Id {
    impl_basic_edge!(I);
}

impl<T: Data, I: Id> Edge<T, I> {
    /// Create an edge with the given source & target node indices and
    /// weight data.
    pub fn new(source: I, target: I, data: T) -> Self {
        Edge{source: source, target: target, data: data}
    }
}

impl<T: Data, I: Id> Deref for Edge<T, I> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T: Data, I: Id> DerefMut for Edge<T, I> {
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        &mut self.data
    }
}

impl<T: Data, I: Id, I2: Copy> From<(I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}

impl<T: Data, I: Id, I2: Copy> From<(I2, I2, T)> for Edge<T, I>
    where I: From<I2> {
    fn from(u: (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2)
    }
}

impl<'a, T: Data, I: Id, I2: Copy> From<&'a (I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: &'a (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}
impl<'a, T: Data, I: Id, I2: Copy> From<&'a (I2, I2, T)> for Edge<T, I>
    where T: Clone, I: From<I2> {
    fn from(u: &'a (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2.clone())
    }
}

// ----------------------------------------------------------------
// Node

///  Weighted node implementation.
///
/// A reference to the node's weight data can be obtained using the type's
/// `Deref` implementation.
///
/// ```rust
/// use cripes::util::graph::{EdgeIndex,WeightedNode};
///
/// # fn main() {
/// let n = WeightedNode::<_, EdgeIndex<u8>>::new(32);
/// assert_eq!(32, *n);
/// # }
/// ```

#[derive(Clone,Debug)]
pub struct Node<T: Data, I: Id> {
    incoming_edges: SmallVec<[I; 8]>,
    outgoing_edges: SmallVec<[I; 8]>,
    data: T
}

impl<T: Data, I: Id> Node<T, I> {
    /// Instantiate a new node with the given data.
    pub fn new(data: T) -> Self {
        Node{incoming_edges: SmallVec::new(), outgoing_edges: SmallVec::new(), data: data}
    }
}

impl<T: Data, I: Id> Deref for Node<T, I> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T: Data, I: Id> DerefMut for Node<T, I> {
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        &mut self.data
    }
}

impl<T, I> interface::Node for Node<T, I>
        where T: Data, I: Id {
    impl_basic_node!(I);
}

// ----------------------------------------------------------------
// Graph

/// Directed graph with user-defined node and edge weights.
#[derive(Clone,Debug)]
pub struct Graph<N: Data, E: Data, Ix: IndexType = DefaultIndexType> {
    nodes: Vec<Node<N, EdgeIndex<Ix>>>,
    edges: Vec<Edge<E, NodeIndex<Ix>>>
}

impl<N, E, Ix> interface::Graph for Graph<N, E, Ix>
    where N: Data, E: Data, Ix: IndexType {
    type NodeId = NodeIndex<Ix>;
    type EdgeId = EdgeIndex<Ix>;
    type Node = Node<N, Self::EdgeId>;
    type Edge = Edge<E, Self::NodeId>;
    type EdgeIdIterator = Indices<Self::EdgeId>;
    type NodeIdIterator = Indices<Self::NodeId>;

    fn new() -> Self {
        Graph{nodes: Vec::new(), edges: Vec::new()}
    }

    fn add_node(&mut self, n: Self::Node) -> Self::NodeId {
        self.nodes.push(n);
        NodeIndex::new(self.nodes.len() - 1)
    }

    #[inline(always)]
    fn contains_node(&self, n: Self::NodeId) -> bool {
        n.index() < self.nodes.len()
    }

    #[inline(always)]
    fn node(&self, n: Self::NodeId) -> &Self::Node {
        &self.nodes[n.index()]
    }

    #[inline(always)]
    fn node_mut(&mut self, n: Self::NodeId) -> &mut Self::Node {
        &mut self.nodes[n.index()]
    }

    #[inline]
    fn node_ids(&self) -> Self::NodeIdIterator {
        Indices::new(0..self.nodes.len())
    }

    #[inline]
    fn node_count(&self) -> usize {
        self.nodes.len()
    }

    fn add_edge(&mut self, e: Self::Edge) -> Self::EdgeId {
        let srcidx = e.source();
        let destidx = e.target();

        self.edges.push(e);
        let index = EdgeIndex::new(self.edges.len() - 1);

        // Update cross-referenced edge lists for the connected nodes.
        self.nodes[srcidx.index()].add_outgoing_edge(index);
        self.nodes[destidx.index()].add_incoming_edge(index);

        index
    }

    fn edge(&self, e: Self::EdgeId) -> &Self::Edge {
        &self.edges[e.index()]
    }

    fn contains_edge(&self, e: Self::EdgeId) -> bool {
        e.index() < self.edges.len()
    }

    fn edge_ids(&self) -> Self::EdgeIdIterator {
        Indices::new(0..self.edges.len())
    }

    fn edge_count(&self) -> usize {
        self.edges.len()
    }
}

impl<N: Data, E: Data, Ix: IndexType> Graph<N, E, Ix> {
    /// Add a node to the graph.
    ///
    /// @return Index of the newly-added node.
    pub fn add_node(&mut self, data: N) -> NodeIndex<Ix> {
        <Self as interface::Graph>::add_node(self, <Self as interface::Graph>::Node::new(data))
    }

    /// Add an edge to the graph.
    ///
    /// The source and target nodes, as identified by calling `edge.source()`
    /// and `edge.target()` on the edge, will be updated as appropriate.
    ///
    /// **Panics** if either of the source or target node indices are invalid.
    ///
    /// @return Index of the newly-added edge.
    ///
    /// @fixme Is there any way we can make this operation atomic, or at least
    /// less drawn-out?
    pub fn add_edge(&mut self, source: NodeIndex<Ix>, target: NodeIndex<Ix>, data: E) -> EdgeIndex<Ix> {
        panic_unless!(source.index() < self.nodes.len(), "Invalid source-node index provided to `Graph::add_edge`");
        panic_unless!(target.index() < self.nodes.len(), "Invalid target-node index provided to `Graph::add_edge`");

        // Add the edge itself
        self.edges.push(<Self as interface::Graph>::Edge::new(source, target, data));

        // ...and add cross-references to the nodes.
        let edge = EdgeIndex::new(self.edges.len() - 1);
        self.nodes[source.index()].add_outgoing_edge(edge);
        self.nodes[target.index()].add_incoming_edge(edge);

        edge
    }
}

// Implement node-data lookup via indexing.
macro_rules! graph_index_impl {
    ($tp: ty, $n: ident, $e: ident, $r: ident, $m: ident) => {
        impl<$n: Data, $e: Data, Ix: IndexType> ops::Index<$tp> for Graph<N, E, Ix> {
            type Output = $r;
            fn index(&self, ix: $tp) -> &$r {
                &self.$m[ix.index()].data
            }

        }
        impl<$n: Data, $e: Data, Ix: IndexType> ops::IndexMut<$tp> for Graph<N, E, Ix> {
            fn index_mut(&mut self, ix: $tp) -> &mut $r {
                &mut self.$m[ix.index()].data
            }

        }
    }
}
graph_index_impl!(EdgeIndex<Ix>, N, E, E, edges);
graph_index_impl!(NodeIndex<Ix>, N, E, N, nodes);
<|endoftext|>


<commit_before>// Copyright 2018 The Grin 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.

//! Main for building the genesis generation utility.

use std::io::{BufRead, Write};
use std::sync::Arc;
use std::{fs, io, path, process};

use chrono::prelude::Utc;
use chrono::{Datelike, Duration, Timelike};
use curl;
use rpassword;
use serde_json;

use cuckoo_miner as cuckoo;
use grin_chain as chain;
use grin_core as core;
use grin_miner_plugin as plugin;
use grin_store as store;
use grin_util as util;
use grin_wallet as wallet;

use grin_core::core::hash::Hashed;
use grin_core::core::verifier_cache::LruVerifierCache;
use grin_keychain::{BlindingFactor, ExtKeychain, Keychain};

static BCHAIN_INFO_URL: &str = "https://blockchain.info/latestblock";
static BCYPHER_URL: &str = "https://api.blockcypher.com/v1/btc/main";
static BCHAIR_URL: &str = "https://api.blockchair.com/bitcoin/blocks?limit=2";

static GENESIS_RS_PATH: &str = "../../core/src/genesis.rs";
static PLUGIN_PATH: &str = "./cuckaroo_mean_cuda_29.cuckooplugin";
static WALLET_SEED_PATH: &str = "./wallet.seed";

fn main() {
	if !path::Path::new(GENESIS_RS_PATH).exists() {
		panic!(
			"File {} not found, make sure you're running this from the gen_gen directory",
			GENESIS_RS_PATH
		);
	}
	if !path::Path::new(PLUGIN_PATH).exists() {
		panic!(
			"File {} not found, make sure you're running this from the gen_gen directory",
			PLUGIN_PATH
		);
	}
	if !path::Path::new(WALLET_SEED_PATH).exists() {
		panic!(
			"File {} not found, make sure you're running this from the gen_gen directory",
			WALLET_SEED_PATH
		);
	}

	// get the latest bitcoin hash
	let h1 = get_bchain_head();
	let h2 = get_bcypher_head();
	let h3 = get_bchair_head();
	if h1 != h2 || h1 != h3 {
		panic!(
			"Bitcoin chain head is inconsistent, please retry ({}, {}, {}).",
			h1, h2, h3
		);
	}
	println!("Using bitcoin block hash {}", h1);

	// build the basic parts of the genesis block header
	let mut gen = core::genesis::genesis_main();
	gen.header.timestamp = Utc::now() + Duration::minutes(30);
	gen.header.prev_root = core::core::hash::Hash::from_hex(&h1).unwrap();

	// build the wallet seed and derive a coinbase from local wallet.seed
	let seed = wallet::WalletSeed::from_file(
		&wallet::WalletConfig::default(),
		&rpassword::prompt_password_stdout("Password: ").unwrap()
	).unwrap();
	let keychain: ExtKeychain = seed.derive_keychain().unwrap();
	let key_id = ExtKeychain::derive_key_id(2, 1, 0, 0, 0);
	let reward = core::libtx::reward::output(&keychain, &key_id, 0).unwrap();
	gen = gen.with_reward(reward.0, reward.1);

	{
		// setup a tmp chain to set block header roots
		core::global::set_mining_mode(core::global::ChainTypes::AutomatedTesting);
		let tmp_chain = setup_chain(".grin.tmp", core::pow::mine_genesis_block().unwrap());
		tmp_chain.set_txhashset_roots(&mut gen).unwrap();
	}

	// mine a Cuckaroo29 block
	core::global::set_mining_mode(core::global::ChainTypes::Mainnet);
	let plugin_lib = cuckoo::PluginLibrary::new(PLUGIN_PATH).unwrap();
	let mut params = plugin_lib.get_default_params();
	params.mutate_nonce = false;
	let solver_ctx = plugin_lib.create_solver_ctx(&mut params);

	let mut solver_sols = plugin::SolverSolutions::default();
	let mut solver_stats = plugin::SolverStats::default();
	let mut nonce = 0;
	while solver_sols.num_sols == 0 {
		solver_sols = plugin::SolverSolutions::default();
		gen.header.pow.nonce = nonce;
		let _ = plugin_lib.run_solver(
			solver_ctx,
			gen.header.pre_pow(),
			nonce,
			1,
			&mut solver_sols,
			&mut solver_stats,
		);
		if solver_stats.has_errored {
			println!(
				"Plugin {} has errored, device: {}. Reason: {}",
				solver_stats.get_plugin_name(),
				solver_stats.get_device_name(),
				solver_stats.get_error_reason(),
			);
			return;
		}

		nonce += 1;
	}

	// Set the PoW solution and make sure the block is mostly valid
	gen.header.pow.proof.nonces = solver_sols.sols[0].to_u64s();
	assert!(gen.header.pow.is_secondary(), "Not a secondary header");
	println!("Built genesis:\n{:?}", gen);
	core::pow::verify_size(&gen.header).unwrap();
	gen.validate(
		&BlindingFactor::zero(),
		Arc::new(util::RwLock::new(LruVerifierCache::new())),
	)
	.unwrap();

	println!("\nFinal genesis cyclehash: {}", gen.hash().to_hex());
	let gen_bin = core::ser::ser_vec(&gen).unwrap();
	println!("Final genesis full hash: {}\n", gen_bin.hash().to_hex());

	update_genesis_rs(&gen);
	println!("genesis.rs has been updated, check it and run mainnet_genesis_hash test");
	println!("also check bitcoin block {} hasn't been orphaned.", h1);
	println!("press c+enter to proceed.");
	let mut input = String::new();
	io::stdin().read_line(&mut input).unwrap();
	if input != "c\n" {
		return;
	}

	// Commit genesis block info in git and tag
	process::Command::new("git")
		.args(&["commit", "-am", "Minor: finalized genesis block"])
		.status()
		.expect("git commit failed");
	process::Command::new("git")
		.args(&["tag", "-a", "v1.0", "-m", "Mainnet release"])
		.status()
		.expect("git tag failed");
	process::Command::new("git")
		.args(&["push", "origin", "v1.0"])
		.status()
		.expect("git tag push failed");
	println!("All done!");
}

fn update_genesis_rs(gen: &core::core::Block) {
	// set the replacement patterns
	let mut replacements = vec![];
	replacements.push((
		"timestamp".to_string(),
		format!(
			"Utc.ymd({}, {}, {}).and_hms({}, {}, {})",
			gen.header.timestamp.date().year(),
			gen.header.timestamp.date().month(),
			gen.header.timestamp.date().day(),
			gen.header.timestamp.time().hour(),
			gen.header.timestamp.time().minute(),
			gen.header.timestamp.time().second(),
		),
	));
	replacements.push((
		"prev_root".to_string(),
		format!(
			"Hash::from_hex(\"{}\").unwrap()",
			gen.header.prev_root.to_hex()
		),
	));
	replacements.push((
		"output_root".to_string(),
		format!(
			"Hash::from_hex(\"{}\").unwrap()",
			gen.header.output_root.to_hex()
		),
	));
	replacements.push((
		"range_proof_root".to_string(),
		format!(
			"Hash::from_hex(\"{}\").unwrap()",
			gen.header.range_proof_root.to_hex()
		),
	));
	replacements.push((
		"kernel_root".to_string(),
		format!(
			"Hash::from_hex(\"{}\").unwrap()",
			gen.header.kernel_root.to_hex()
		),
	));
	replacements.push((
		"total_kernel_offset".to_string(),
		format!(
			"BlindingFactor::from_hex(\"{}\").unwrap()",
			gen.header.total_kernel_offset.to_hex()
		),
	));
	replacements.push(("nonce".to_string(), format!("{}", gen.header.pow.nonce)));
	replacements.push((
		"nonces".to_string(),
		format!("vec!{:?}", gen.header.pow.proof.nonces),
	));
	replacements.push((
		"excess".to_string(),
		format!(
			"Commitment::from_vec(util::from_hex({:x?}.to_string()).unwrap())",
			util::to_hex(gen.kernels()[0].excess.0.to_vec())
		),
	));
	replacements.push((
		"excess_sig".to_string(),
		format!(
			"Signature::from_raw_data(&{:?}).unwrap()",
			gen.kernels()[0].excess_sig.to_raw_data().to_vec(),
		),
	));
	replacements.push((
		"commit".to_string(),
		format!(
			"Commitment::from_vec(util::from_hex({:x?}.to_string()).unwrap())",
			util::to_hex(gen.outputs()[0].commitment().0.to_vec())
		),
	));
	replacements.push((
		"proof".to_string(),
		format!("{:?}", gen.outputs()[0].proof.bytes().to_vec()),
	));

	// check each possible replacement in the file, remove the replacement from
	// the list when found to avoid double replacements
	let mut replaced = String::new();
	{
		let genesis_rs = fs::File::open(GENESIS_RS_PATH).unwrap();
		let reader = io::BufReader::new(&genesis_rs);
		for rline in reader.lines() {
			let line = rline.unwrap();
			let mut has_replaced = false;
			if line.contains("REPLACE") {
				for (pos, replacement) in replacements.iter().enumerate() {
					if line.contains(&replacement.0) {
						replaced.push_str(&format!("{}: {},\n", replacement.0, replacement.1));
						replacements.remove(pos);
						has_replaced = true;
						break;
					}
				}
			}
			if !has_replaced {
				replaced.push_str(&format!("{}\n", line));
			}
		}
	}
	let mut genesis_rs = fs::File::create(GENESIS_RS_PATH).unwrap();
	genesis_rs.write_all(replaced.as_bytes()).unwrap();
}

fn setup_chain(dir_name: &str, genesis: core::core::Block) -> chain::Chain {
	util::init_test_logger();
	let _ = fs::remove_dir_all(dir_name);
	let verifier_cache = Arc::new(util::RwLock::new(
		core::core::verifier_cache::LruVerifierCache::new(),
	));
	let db_env = Arc::new(store::new_env(dir_name.to_string()));
	chain::Chain::init(
		dir_name.to_string(),
		db_env,
		Arc::new(chain::types::NoopAdapter {}),
		genesis,
		core::pow::verify_size,
		verifier_cache,
		false,
		Arc::new(util::Mutex::new(util::StopState::new())),
	)
	.unwrap()
}

fn get_bchain_head() -> String {
	get_json(BCHAIN_INFO_URL)["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_bcypher_head() -> String {
	get_json(BCYPHER_URL)["hash"].as_str().unwrap().to_string()
}

fn get_bchair_head() -> String {
	get_json(BCHAIR_URL)["data"][0]["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_json(url: &str) -> serde_json::Value {
	let mut body = Vec::new();
	let mut easy = curl::easy::Easy::new();
	easy.url(url).unwrap();
	{
		let mut transfer = easy.transfer();
		transfer
			.write_function(|data| {
				body.extend_from_slice(data);
				Ok(data.len())
			})
			.unwrap();
		transfer.perform().unwrap();
	}
	serde_json::from_slice(&body).unwrap()
}

<commit_msg>Move prev_root setting to after set_txhashset_roots so it doesn't get overwritten. Remove git interactions, easier done manually.<commit_after>// Copyright 2018 The Grin 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.

//! Main for building the genesis generation utility.

use std::io::{BufRead, Write};
use std::sync::Arc;
use std::{fs, io, path};

use chrono::prelude::Utc;
use chrono::{Datelike, Duration, Timelike};
use curl;
use rpassword;
use serde_json;

use cuckoo_miner as cuckoo;
use grin_chain as chain;
use grin_core as core;
use grin_miner_plugin as plugin;
use grin_store as store;
use grin_util as util;
use grin_wallet as wallet;

use grin_core::core::hash::Hashed;
use grin_core::core::verifier_cache::LruVerifierCache;
use grin_keychain::{BlindingFactor, ExtKeychain, Keychain};

static BCHAIN_INFO_URL: &str = "https://blockchain.info/latestblock";
static BCYPHER_URL: &str = "https://api.blockcypher.com/v1/btc/main";
static BCHAIR_URL: &str = "https://api.blockchair.com/bitcoin/blocks?limit=2";

static GENESIS_RS_PATH: &str = "../../core/src/genesis.rs";
static PLUGIN_PATH: &str = "./cuckaroo_mean_cuda_29.cuckooplugin";
static WALLET_SEED_PATH: &str = "./wallet.seed";

fn main() {
	if !path::Path::new(GENESIS_RS_PATH).exists() {
		panic!(
			"File {} not found, make sure you're running this from the gen_gen directory",
			GENESIS_RS_PATH
		);
	}
	if !path::Path::new(PLUGIN_PATH).exists() {
		panic!(
			"File {} not found, make sure you're running this from the gen_gen directory",
			PLUGIN_PATH
		);
	}
	if !path::Path::new(WALLET_SEED_PATH).exists() {
		panic!(
			"File {} not found, make sure you're running this from the gen_gen directory",
			WALLET_SEED_PATH
		);
	}

	// get the latest bitcoin hash
	let h1 = get_bchain_head();
	let h2 = get_bcypher_head();
	let h3 = get_bchair_head();
	if h1 != h2 || h1 != h3 {
		panic!(
			"Bitcoin chain head is inconsistent, please retry ({}, {}, {}).",
			h1, h2, h3
		);
	}
	println!("Using bitcoin block hash {}", h1);

	// build the basic parts of the genesis block header
	let mut gen = core::genesis::genesis_main();

	// build the wallet seed and derive a coinbase from local wallet.seed
	let seed = wallet::WalletSeed::from_file(
		&wallet::WalletConfig::default(),
		&rpassword::prompt_password_stdout("Password: ").unwrap()
	).unwrap();
	let keychain: ExtKeychain = seed.derive_keychain().unwrap();
	let key_id = ExtKeychain::derive_key_id(2, 1, 0, 0, 0);
	let reward = core::libtx::reward::output(&keychain, &key_id, 0).unwrap();
	gen = gen.with_reward(reward.0, reward.1);

	{
		// setup a tmp chain to set block header roots
		core::global::set_mining_mode(core::global::ChainTypes::AutomatedTesting);
		let tmp_chain = setup_chain(".grin.tmp", core::pow::mine_genesis_block().unwrap());
		tmp_chain.set_txhashset_roots(&mut gen).unwrap();
	}

	// sets the timestamp and prev_root from the bitcoin block (needs to be
	// after set_txhashset roots to not get overwritten)
	gen.header.timestamp = Utc::now() + Duration::minutes(30);
	gen.header.prev_root = core::core::hash::Hash::from_hex(&h1).unwrap();

	// mine a Cuckaroo29 block
	core::global::set_mining_mode(core::global::ChainTypes::Mainnet);
	let plugin_lib = cuckoo::PluginLibrary::new(PLUGIN_PATH).unwrap();
	let mut params = plugin_lib.get_default_params();
	params.mutate_nonce = false;
	let solver_ctx = plugin_lib.create_solver_ctx(&mut params);

	let mut solver_sols = plugin::SolverSolutions::default();
	let mut solver_stats = plugin::SolverStats::default();
	let mut nonce = 0;
	while solver_sols.num_sols == 0 {
		solver_sols = plugin::SolverSolutions::default();
		gen.header.pow.nonce = nonce;
		let _ = plugin_lib.run_solver(
			solver_ctx,
			gen.header.pre_pow(),
			nonce,
			1,
			&mut solver_sols,
			&mut solver_stats,
		);
		if solver_stats.has_errored {
			println!(
				"Plugin {} has errored, device: {}. Reason: {}",
				solver_stats.get_plugin_name(),
				solver_stats.get_device_name(),
				solver_stats.get_error_reason(),
			);
			return;
		}

		nonce += 1;
	}

	// Set the PoW solution and make sure the block is mostly valid
	gen.header.pow.proof.nonces = solver_sols.sols[0].to_u64s();
	assert!(gen.header.pow.is_secondary(), "Not a secondary header");
	println!("Built genesis:\n{:?}", gen);
	core::pow::verify_size(&gen.header).unwrap();
	gen.validate(
		&BlindingFactor::zero(),
		Arc::new(util::RwLock::new(LruVerifierCache::new())),
	)
	.unwrap();

	println!("\nFinal genesis cyclehash: {}", gen.hash().to_hex());
	let gen_bin = core::ser::ser_vec(&gen).unwrap();
	println!("Final genesis full hash: {}\n", gen_bin.hash().to_hex());

	update_genesis_rs(&gen);
	println!("genesis.rs has been updated, check it and run mainnet_genesis_hash test");
	println!("also check bitcoin block {} hasn't been orphaned.", h1);
	println!("All done!");
}

fn update_genesis_rs(gen: &core::core::Block) {
	// set the replacement patterns
	let mut replacements = vec![];
	replacements.push((
		"timestamp".to_string(),
		format!(
			"Utc.ymd({}, {}, {}).and_hms({}, {}, {})",
			gen.header.timestamp.date().year(),
			gen.header.timestamp.date().month(),
			gen.header.timestamp.date().day(),
			gen.header.timestamp.time().hour(),
			gen.header.timestamp.time().minute(),
			gen.header.timestamp.time().second(),
		),
	));
	replacements.push((
		"prev_root".to_string(),
		format!(
			"Hash::from_hex(\"{}\").unwrap()",
			gen.header.prev_root.to_hex()
		),
	));
	replacements.push((
		"output_root".to_string(),
		format!(
			"Hash::from_hex(\"{}\").unwrap()",
			gen.header.output_root.to_hex()
		),
	));
	replacements.push((
		"range_proof_root".to_string(),
		format!(
			"Hash::from_hex(\"{}\").unwrap()",
			gen.header.range_proof_root.to_hex()
		),
	));
	replacements.push((
		"kernel_root".to_string(),
		format!(
			"Hash::from_hex(\"{}\").unwrap()",
			gen.header.kernel_root.to_hex()
		),
	));
	replacements.push((
		"total_kernel_offset".to_string(),
		format!(
			"BlindingFactor::from_hex(\"{}\").unwrap()",
			gen.header.total_kernel_offset.to_hex()
		),
	));
	replacements.push(("nonce".to_string(), format!("{}", gen.header.pow.nonce)));
	replacements.push((
		"nonces".to_string(),
		format!("vec!{:?}", gen.header.pow.proof.nonces),
	));
	replacements.push((
		"excess".to_string(),
		format!(
			"Commitment::from_vec(util::from_hex({:x?}.to_string()).unwrap())",
			util::to_hex(gen.kernels()[0].excess.0.to_vec())
		),
	));
	replacements.push((
		"excess_sig".to_string(),
		format!(
			"Signature::from_raw_data(&{:?}).unwrap()",
			gen.kernels()[0].excess_sig.to_raw_data().to_vec(),
		),
	));
	replacements.push((
		"commit".to_string(),
		format!(
			"Commitment::from_vec(util::from_hex({:x?}.to_string()).unwrap())",
			util::to_hex(gen.outputs()[0].commitment().0.to_vec())
		),
	));
	replacements.push((
		"proof".to_string(),
		format!("{:?}", gen.outputs()[0].proof.bytes().to_vec()),
	));

	// check each possible replacement in the file, remove the replacement from
	// the list when found to avoid double replacements
	let mut replaced = String::new();
	{
		let genesis_rs = fs::File::open(GENESIS_RS_PATH).unwrap();
		let reader = io::BufReader::new(&genesis_rs);
		for rline in reader.lines() {
			let line = rline.unwrap();
			let mut has_replaced = false;
			if line.contains("REPLACE") {
				for (pos, replacement) in replacements.iter().enumerate() {
					if line.contains(&replacement.0) {
						replaced.push_str(&format!("{}: {},\n", replacement.0, replacement.1));
						replacements.remove(pos);
						has_replaced = true;
						break;
					}
				}
			}
			if !has_replaced {
				replaced.push_str(&format!("{}\n", line));
			}
		}
	}
	let mut genesis_rs = fs::File::create(GENESIS_RS_PATH).unwrap();
	genesis_rs.write_all(replaced.as_bytes()).unwrap();
}

fn setup_chain(dir_name: &str, genesis: core::core::Block) -> chain::Chain {
	util::init_test_logger();
	let _ = fs::remove_dir_all(dir_name);
	let verifier_cache = Arc::new(util::RwLock::new(
		core::core::verifier_cache::LruVerifierCache::new(),
	));
	let db_env = Arc::new(store::new_env(dir_name.to_string()));
	chain::Chain::init(
		dir_name.to_string(),
		db_env,
		Arc::new(chain::types::NoopAdapter {}),
		genesis,
		core::pow::verify_size,
		verifier_cache,
		false,
		Arc::new(util::Mutex::new(util::StopState::new())),
	)
	.unwrap()
}

fn get_bchain_head() -> String {
	get_json(BCHAIN_INFO_URL)["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_bcypher_head() -> String {
	get_json(BCYPHER_URL)["hash"].as_str().unwrap().to_string()
}

fn get_bchair_head() -> String {
	get_json(BCHAIR_URL)["data"][0]["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_json(url: &str) -> serde_json::Value {
	let mut body = Vec::new();
	let mut easy = curl::easy::Easy::new();
	easy.url(url).unwrap();
	{
		let mut transfer = easy.transfer();
		transfer
			.write_function(|data| {
				body.extend_from_slice(data);
				Ok(data.len())
			})
			.unwrap();
		transfer.perform().unwrap();
	}
	serde_json::from_slice(&body).unwrap()
}

<|endoftext|>