<commit_before>// Copyright (c) 2016-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// solid_signals.rs - Swaps all pixels on a Blinkt! board between red, green
// and blue in a loop, while handling any incoming SIGINT (Ctrl-C) and SIGTERM
// signals so the pixels can be cleared before the application exits.

use std::error::Error;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use std::{mem, thread};

// The simple-signal crate is used to handle incoming signals.
use simple_signal::{self, Signal};

use blinkt::Blinkt;

fn main() -> Result<(), Box<dyn Error>> {
    let mut blinkt = Blinkt::new()?;

    // Clone running, so we can safely access it from within the signal handler.
    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();

    // When a SIGINT (Ctrl-C) or SIGTERM signal is caught, atomically set running to false.
    simple_signal::set_handler(&[Signal::Int, Signal::Term], move |_| {
        r.store(false, Ordering::SeqCst);
    });

    let (red, green, blue) = (&mut 255, &mut 0, &mut 0);

    // Loop until running is set to false.
    while running.load(Ordering::SeqCst) {
        blinkt.set_all_pixels(*red, *green, *blue);
        blinkt.show()?;

        thread::sleep(Duration::from_millis(250));

        mem::swap(red, green);
        mem::swap(red, blue);
    }

    Ok(())

    // When the blinkt variable goes out of scope, all pixels are automatically cleared.
}
<commit_msg>Group cloned data with closure definition<commit_after>// Copyright (c) 2016-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// solid_signals.rs - Swaps all pixels on a Blinkt! board between red, green
// and blue in a loop, while handling any incoming SIGINT (Ctrl-C) and SIGTERM
// signals so the pixels can be cleared before the application exits.

use std::error::Error;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use std::{mem, thread};

// The simple-signal crate is used to handle incoming signals.
use simple_signal::{self, Signal};

use blinkt::Blinkt;

fn main() -> Result<(), Box<dyn Error>> {
    let mut blinkt = Blinkt::new()?;

    let running = Arc::new(AtomicBool::new(true));

    // When a SIGINT (Ctrl-C) or SIGTERM signal is caught, atomically set running to false.
    simple_signal::set_handler(&[Signal::Int, Signal::Term], {
        let running = running.clone();
        move |_| {
            running.store(false, Ordering::SeqCst);
        }
    });

    let (red, green, blue) = (&mut 255, &mut 0, &mut 0);

    // Loop until running is set to false.
    while running.load(Ordering::SeqCst) {
        blinkt.set_all_pixels(*red, *green, *blue);
        blinkt.show()?;

        thread::sleep(Duration::from_millis(250));

        mem::swap(red, green);
        mem::swap(red, blue);
    }

    Ok(())

    // When the blinkt variable goes out of scope, all pixels are automatically cleared.
}
<|endoftext|>


<commit_before>//! An example that determines the time stamp counter frequency (RDTSC, RDTSCP) .
extern crate raw_cpuid;

use std::time;

const MHZ_TO_HZ: u64 = 1000000;
const KHZ_TO_HZ: u64 = 1000;

#[rustversion::nightly]
use core::arch::x86_64::_rdtsc as rdtsc;

#[rustversion::stable]
unsafe fn rdtsc() -> u64 {
    0
}

fn main() {
    let cpuid = raw_cpuid::CpuId::new();
    let has_tsc = cpuid
        .get_feature_info()
        .map_or(false, |finfo| finfo.has_tsc());

    let has_invariant_tsc = cpuid
        .get_extended_function_info()
        .map_or(false, |efinfo| efinfo.has_invariant_tsc());

    let tsc_frequency_hz = cpuid.get_tsc_info().map(|tinfo| {
        if tinfo.nominal_frequency() != 0 {
            Some(tinfo.tsc_frequency())
        } else if tinfo.numerator() != 0 && tinfo.denominator() != 0 {
            // Skylake and Kabylake don't report the crystal clock, approximate with base frequency:
            cpuid
                .get_processor_frequency_info()
                .map(|pinfo| pinfo.processor_base_frequency() as u64 * MHZ_TO_HZ)
                .map(|cpu_base_freq_hz| {
                    let crystal_hz =
                        cpu_base_freq_hz * tinfo.denominator() as u64 / tinfo.numerator() as u64;
                    crystal_hz * tinfo.numerator() as u64 / tinfo.denominator() as u64
                })
        } else {
            None
        }
    });

    if has_tsc {
        // Try to figure out TSC frequency with CPUID
        println!(
            "TSC Frequency is: {} ({})",
            match tsc_frequency_hz {
                Some(x) => format!("{} Hz", x.unwrap_or(0)),
                None => String::from("unknown"),
            },
            if has_invariant_tsc {
                "invariant"
            } else {
                "TSC frequency varies with speed-stepping"
            }
        );

        // Check if we run in a VM and the hypervisor can give us the TSC frequency
        cpuid.get_hypervisor_info().map(|hv| {
            hv.tsc_frequency().map(|tsc_khz| {
                let virtual_tsc_frequency_hz = tsc_khz as u64 * KHZ_TO_HZ;
                println!(
                    "Hypervisor reports TSC Frequency at: {} Hz",
                    virtual_tsc_frequency_hz
                );
            })
        });

        {
            // Determine TSC frequency by measuring it (loop for a second, record ticks)
            let one_second = time::Duration::from_secs(1);
            let now = time::Instant::now();
            let start = unsafe { rdtsc() };
            loop {
                if now.elapsed() >= one_second {
                    break;
                }
            }
            let end = unsafe { rdtsc() };
            if end > 0 {
                println!(
                    "Empirical measurement of TSC frequency was: {} Hz",
                    (end - start)
                );
            } else {
                // Don't have rdtsc on stable!
            }
        }
    } else {
        println!("System does not have a TSC.")
    }
}
<commit_msg>Clean-up formatting.<commit_after>//! An example that determines the time stamp counter frequency (RDTSC, RDTSCP) .
extern crate raw_cpuid;

use std::time;

const MHZ_TO_HZ: u64 = 1000000;
const KHZ_TO_HZ: u64 = 1000;

#[rustversion::nightly]
use core::arch::x86_64::_rdtsc as rdtsc;

#[rustversion::stable]
unsafe fn rdtsc() -> u64 {
    0
}

fn main() {
    let cpuid = raw_cpuid::CpuId::new();
    let has_tsc = cpuid
        .get_feature_info()
        .map_or(false, |finfo| finfo.has_tsc());

    let has_invariant_tsc = cpuid
        .get_extended_function_info()
        .map_or(false, |efinfo| efinfo.has_invariant_tsc());

    let tsc_frequency_hz = cpuid.get_tsc_info().map(|tinfo| {
        if tinfo.nominal_frequency() != 0 {
            Some(tinfo.tsc_frequency())
        } else if tinfo.numerator() != 0 && tinfo.denominator() != 0 {
            // Skylake and Kabylake don't report the crystal clock, approximate with base frequency:
            cpuid
                .get_processor_frequency_info()
                .map(|pinfo| pinfo.processor_base_frequency() as u64 * MHZ_TO_HZ)
                .map(|cpu_base_freq_hz| {
                    let crystal_hz =
                        cpu_base_freq_hz * tinfo.denominator() as u64 / tinfo.numerator() as u64;
                    crystal_hz * tinfo.numerator() as u64 / tinfo.denominator() as u64
                })
        } else {
            None
        }
    });

    if has_tsc {
        // Try to figure out TSC frequency with CPUID
        println!(
            "TSC Frequency is: {} ({})",
            match tsc_frequency_hz {
                Some(x) => format!("{} Hz", x.unwrap_or(0)),
                None => String::from("unknown"),
            },
            if has_invariant_tsc {
                "invariant"
            } else {
                "TSC frequency varies with speed-stepping"
            }
        );

        // Check if we run in a VM and the hypervisor can give us the TSC frequency
        cpuid.get_hypervisor_info().map(|hv| {
            hv.tsc_frequency().map(|tsc_khz| {
                let virtual_tsc_frequency_hz = tsc_khz as u64 * KHZ_TO_HZ;
                println!(
                    "Hypervisor reports TSC Frequency at: {} Hz",
                    virtual_tsc_frequency_hz
                );
            })
        });

        // Determine TSC frequency by measuring it (loop for a second, record ticks)
        let one_second = time::Duration::from_secs(1);
        let now = time::Instant::now();
        let start = unsafe { rdtsc() };
        loop {
            if now.elapsed() >= one_second {
                break;
            }
        }
        let end = unsafe { rdtsc() };
        if end > 0 {
            println!(
                "Empirical measurement of TSC frequency was: {} Hz",
                (end - start)
            );
        } else {
            // Don't have rdtsc on stable!
        }
    } else {
        println!("System does not have a TSC.")
    }
}
<|endoftext|>


<commit_before>extern crate mioco;
extern crate env_logger;

use std::net::SocketAddr;
use std::str::FromStr;
use std::io::Write;
use mioco::mio::tcp::{TcpSocket};

const DEFAULT_LISTEN_ADDR : &'static str = "127.0.0.1:5555";

fn listend_addr() -> SocketAddr {
    FromStr::from_str(DEFAULT_LISTEN_ADDR).unwrap()
}

const RESPONSE: &'static str = "HTTP/1.1 200 OK\r
Content-Length: 14\r
\r
Hello World\r
\r";

fn main() {
    env_logger::init().unwrap();
    let addr = listend_addr();

    let sock = TcpSocket::v4().unwrap();
    sock.bind(&addr).unwrap();
    let sock = sock.listen(1024).unwrap();

    println!("Starting \"cheating\" http server on {:?}", sock.local_addr().unwrap());

    mioco::start(move |mioco| {
        for _ in 0..8 {
            let sock = try!(sock.try_clone());
            mioco.spawn(move |mioco| {
                let sock = mioco.wrap(sock);
                loop {
                    let conn = try!(sock.accept());
                    mioco.spawn(move |mioco| {
                        let mut conn = mioco.wrap(conn);
                        loop {
                            let _ = try!(conn.write(&RESPONSE.as_bytes()));
                        }
                    });
                }
            });
        }
        Ok(())
    });
}
<commit_msg>cheating-http-server: Fix wrk write/read errors.<commit_after>extern crate mioco;
extern crate env_logger;

use std::net::SocketAddr;
use std::str::FromStr;
use std::io::Write;
use mioco::mio::tcp::{TcpSocket};

const DEFAULT_LISTEN_ADDR : &'static str = "127.0.0.1:5555";

fn listend_addr() -> SocketAddr {
    FromStr::from_str(DEFAULT_LISTEN_ADDR).unwrap()
}

const RESPONSE: &'static str = "HTTP/1.1 200 OK\r
Content-Length: 14\r
\r
Hello World\r
\r";

fn main() {
    env_logger::init().unwrap();
    let addr = listend_addr();

    let sock = TcpSocket::v4().unwrap();
    sock.bind(&addr).unwrap();
    let sock = sock.listen(1024).unwrap();

    println!("Starting \"cheating\" http server on {:?}", sock.local_addr().unwrap());

    mioco::start(move |mioco| {
        for _ in 0..8 {
            let sock = try!(sock.try_clone());
            mioco.spawn(move |mioco| {
                let sock = mioco.wrap(sock);
                loop {
                    let conn = try!(sock.accept());
                    mioco.spawn(move |mioco| {
                        let mut conn = mioco.wrap(conn);
                        loop {
                            let _ = try!(conn.write_all(&RESPONSE.as_bytes()));
                        }
                    });
                }
            });
        }
        Ok(())
    });
}
<|endoftext|>


<commit_before>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

use std::fs::{File, remove_file, rename};
use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom};
use std::path::{PathBuf, Path};

fn main() {
    test_file();
    test_file_clone();
    test_seek();
    test_metadata();
    test_symlink();
    test_errors();
    test_rename();
}

fn test_file() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_file.txt");
    let path = tmp.join(&filename);
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();

    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(&path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();
    assert_eq!(file.metadata().unwrap().len(), 0);

    file.write(bytes).unwrap();
    assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
    // Test opening, reading and closing a file.
    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_clone() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_file_clone.txt");
    let path = tmp.join(&filename);
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    // Cloning a file should be successful.
    let file = File::open(&path).unwrap();
    let mut cloned = file.try_clone().unwrap();
    // Reading from a cloned file should get the same text.
    let mut contents = Vec::new();
    cloned.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_seek() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_seek.txt");
    let path = tmp.join(&filename);
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    // Test that seeking to the beginning and reading until EOF gets the text again.
    file.seek(SeekFrom::Start(0)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test seeking relative to the end of the file.
    file.seek(SeekFrom::End(-1)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
    // Test seeking relative to the current position.
    file.seek(SeekFrom::Start(5)).unwrap();
    file.seek(SeekFrom::Current(-3)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[2..], contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
    // Test that the file metadata is correct.
    let metadata = path.metadata()?;
    // `path` should point to a file.
    assert!(metadata.is_file());
    // The size of the file must be equal to the number of written bytes.
    assert_eq!(bytes.len() as u64, metadata.len());
    Ok(())
}

fn test_metadata() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_metadata.txt");
    let path = tmp.join(&filename);
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    // Test that metadata of an absolute path is correct.
    check_metadata(bytes, &path).unwrap();
    // Test that metadata of a relative path is correct.
    std::env::set_current_dir(&tmp).unwrap();
    check_metadata(bytes, &filename).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_symlink() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_link_target.txt");
    let path = tmp.join(&filename);
    let symlink_path = tmp.join("miri_test_fs_symlink.txt");
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();
    remove_file(&symlink_path).ok();

    let mut file = File::create(&path).unwrap();
    file.write(bytes).unwrap();

    // Creating a symbolic link should succeed.
    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
    // Test that the symbolic link has the same contents as the file.
    let mut symlink_file = File::open(&symlink_path).unwrap();
    let mut contents = Vec::new();
    symlink_file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that metadata of a symbolic link is correct.
    check_metadata(bytes, &symlink_path).unwrap();
    // Test that the metadata of a symbolic link is correct when not following it.
    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
    // Removing symbolic link should succeed.
    remove_file(&symlink_path).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_errors() {
    let tmp = std::env::temp_dir();
    let filename = PathBuf::from("miri_test_fs_errors.txt");
    let path = tmp.join(&filename);
    let bytes = b"Hello, World!\n";
    // Clean the paths for robustness.
    remove_file(&path).ok();

    // The following tests also check that the `__errno_location()` shim is working properly.
    // Opening a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
    // Removing a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
    // Reading the metadata of a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind());
}

fn test_rename() {
    let tmp = std::env::temp_dir();
    // Renaming a file should succeed.
    let path1 = tmp.join("miri_test_fs_rename_source.txt");
    let path2 = tmp.join("miri_test_fs_rename_destination.txt");
    // Clean files for robustness.
    remove_file(&path1).ok();
    remove_file(&path2).ok();
    let file = File::create(&path1).unwrap();
    drop(file);
    rename(&path1, &path2).unwrap();
    assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
    assert!(path2.metadata().unwrap().is_file());
    remove_file(&path2).unwrap();
}
<commit_msg>Auto merge of #1180 - RalfJung:fs-refact, r=RalfJung<commit_after>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

use std::fs::{File, remove_file, rename};
use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom};
use std::path::{PathBuf, Path};

fn main() {
    test_file();
    test_file_clone();
    test_seek();
    test_metadata();
    test_symlink();
    test_errors();
    test_rename();
}

/// Prepare: compute filename and make sure the file does not exist.
fn prepare(filename: &str) -> PathBuf {
    let tmp = std::env::temp_dir();
    let path = tmp.join(filename);
    // Clean the paths for robustness.
    remove_file(&path).ok();
    path
}

/// Prepare like above, and also write some initial content to the file.
fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
    let path = prepare(filename);
    let mut file = File::create(&path).unwrap();
    file.write(content).unwrap();
    path
}

fn test_file() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_file.txt");

    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(&path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();
    assert_eq!(file.metadata().unwrap().len(), 0);

    file.write(bytes).unwrap();
    assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
    // Test opening, reading and closing a file.
    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_file_clone() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes);

    // Cloning a file should be successful.
    let file = File::open(&path).unwrap();
    let mut cloned = file.try_clone().unwrap();
    // Reading from a cloned file should get the same text.
    let mut contents = Vec::new();
    cloned.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_seek() {
    let bytes = b"Hello, entire World!\n";
    let path = prepare_with_content("miri_test_fs_seek.txt", bytes);

    let mut file = File::open(&path).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that seeking to the beginning and reading until EOF gets the text again.
    file.seek(SeekFrom::Start(0)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test seeking relative to the end of the file.
    file.seek(SeekFrom::End(-1)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice());
    // Test seeking relative to the current position.
    file.seek(SeekFrom::Start(5)).unwrap();
    file.seek(SeekFrom::Current(-3)).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(&bytes[2..], contents.as_slice());

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
    // Test that the file metadata is correct.
    let metadata = path.metadata()?;
    // `path` should point to a file.
    assert!(metadata.is_file());
    // The size of the file must be equal to the number of written bytes.
    assert_eq!(bytes.len() as u64, metadata.len());
    Ok(())
}

fn test_metadata() {
    let bytes = b"Hello, meta-World!\n";
    let path = prepare_with_content("miri_test_fs_metadata.txt", bytes);

    // Test that metadata of an absolute path is correct.
    check_metadata(bytes, &path).unwrap();
    // Test that metadata of a relative path is correct.
    std::env::set_current_dir(path.parent().unwrap()).unwrap();
    check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_symlink() {
    let bytes = b"Hello, World!\n";
    let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
    let symlink_path = prepare("miri_test_fs_symlink.txt");

    // Creating a symbolic link should succeed.
    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
    // Test that the symbolic link has the same contents as the file.
    let mut symlink_file = File::open(&symlink_path).unwrap();
    let mut contents = Vec::new();
    symlink_file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Test that metadata of a symbolic link is correct.
    check_metadata(bytes, &symlink_path).unwrap();
    // Test that the metadata of a symbolic link is correct when not following it.
    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
    // Removing symbolic link should succeed.
    remove_file(&symlink_path).unwrap();

    // Removing file should succeed.
    remove_file(&path).unwrap();
}

fn test_errors() {
    let bytes = b"Hello, World!\n";
    let path = prepare("miri_test_fs_errors.txt");

    // The following tests also check that the `__errno_location()` shim is working properly.
    // Opening a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind());
    // Removing a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind());
    // Reading the metadata of a non-existing file should fail with a "not found" error.
    assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind());
}

fn test_rename() {
    // Renaming a file should succeed.
    let path1 = prepare("miri_test_fs_rename_source.txt");
    let path2 = prepare("miri_test_fs_rename_destination.txt");

    let file = File::create(&path1).unwrap();
    drop(file);
    rename(&path1, &path2).unwrap();
    assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
    assert!(path2.metadata().unwrap().is_file());
    remove_file(&path2).unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// 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.

//! Different assorted utilities.

use std::env;
use std::io::{self, Write};
use std::time::SystemTime;

use log::{Level, Record, SetLoggerError};
use env_logger::{Builder, Formatter};
use colored::*;
use chrono::prelude::*;

use blockchain::{GenesisConfig, ValidatorKeys};
use node::NodeConfig;
use crypto::gen_keypair;

pub use self::types::{Height, Milliseconds, Round, ValidatorId};

mod types;

pub mod fabric;
pub mod config;
pub mod user_agent;
#[macro_use]
pub mod metrics;

/// Performs the logger initialization.
pub fn init_logger() -> Result<(), SetLoggerError> {
    let mut builder = Builder::new();
    builder.format(format_log_record);

    if env::var("RUST_LOG").is_ok() {
        builder.parse(&env::var("RUST_LOG").unwrap());
    }

    builder.try_init()
}

/// Generates testnet configuration.
pub fn generate_testnet_config(count: u8, start_port: u16) -> Vec<NodeConfig> {
    let (validators, services): (Vec<_>, Vec<_>) = (0..count as usize)
        .map(|_| (gen_keypair(), gen_keypair()))
        .unzip();
    let genesis = GenesisConfig::new(validators.iter().zip(services.iter()).map(|x| {
        ValidatorKeys {
            consensus_key: (x.0).0,
            service_key: (x.1).0,
        }
    }));
    let peers = (0..validators.len())
        .map(|x| {
            format!("127.0.0.1:{}", start_port + x as u16)
                .parse()
                .unwrap()
        })
        .collect::<Vec<_>>();

    validators
        .into_iter()
        .zip(services.into_iter())
        .enumerate()
        .map(|(idx, (validator, service))| {
            NodeConfig {
                listen_address: peers[idx],
                external_address: Some(peers[idx]),
                network: Default::default(),
                peers: peers.clone(),
                consensus_public_key: validator.0,
                consensus_secret_key: validator.1,
                service_public_key: service.0,
                service_secret_key: service.1,
                genesis: genesis.clone(),
                whitelist: Default::default(),
                api: Default::default(),
                mempool: Default::default(),
                services_configs: Default::default(),
            }
        })
        .collect::<Vec<_>>()
}

fn has_colors() -> bool {
    use term::terminfo::TerminfoTerminal;
    use term::Terminal;
    use std::io;
    use atty;

    let out = io::stderr();
    match TerminfoTerminal::new(out) {
        Some(ref term) if atty::is(atty::Stream::Stderr) => term.supports_color(),
        _ => false,
    }
}

fn format_time(time: SystemTime) -> String {
    DateTime::<Local>::from(time).to_rfc2822()
}

fn format_log_record(buf: &mut Formatter, record: &Record) -> io::Result<()> {
    let time = format_time(SystemTime::now());

    let verbose_src_path = match env::var("RUST_VERBOSE_PATH") {
        Ok(val) => val.parse::<bool>().unwrap_or(false),
        Err(_) => false,
    };

    let module = record.module_path().unwrap_or("unknown_module");
    let source_path = if verbose_src_path {
        let file = record.file().unwrap_or("unknown_file");
        let line = record.line().unwrap_or(0);
        format!("{}:{}:{}", module, file, line)
    } else {
        module.to_string()
    };

    if has_colors() {
        let level = match record.level() {
            Level::Error => "ERROR".red(),
            Level::Warn => "WARN".yellow(),
            Level::Info => "INFO".green(),
            Level::Debug => "DEBUG".cyan(),
            Level::Trace => "TRACE".white(),
        };
        writeln!(
            buf,
            "{} {} {} {}",
            time.dimmed(),
            level,
            source_path.dimmed(),
            record.args()
        )
    } else {
        let level = match record.level() {
            Level::Error => "ERROR",
            Level::Warn => "WARN",
            Level::Info => "INFO",
            Level::Debug => "DEBUG",
            Level::Trace => "TRACE",
        };
        writeln!(
            buf,
            "{} {} {} {}",
            time,
            level,
            &source_path,
            record.args()
        )
    }
}
<commit_msg>Format code<commit_after>// Copyright 2017 The Exonum Team
//
// 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.

//! Different assorted utilities.

use std::env;
use std::io::{self, Write};
use std::time::SystemTime;

use log::{Level, Record, SetLoggerError};
use env_logger::{Builder, Formatter};
use colored::*;
use chrono::prelude::*;

use blockchain::{GenesisConfig, ValidatorKeys};
use node::NodeConfig;
use crypto::gen_keypair;

pub use self::types::{Height, Milliseconds, Round, ValidatorId};

mod types;

pub mod fabric;
pub mod config;
pub mod user_agent;
#[macro_use]
pub mod metrics;

/// Performs the logger initialization.
pub fn init_logger() -> Result<(), SetLoggerError> {
    let mut builder = Builder::new();
    builder.format(format_log_record);

    if env::var("RUST_LOG").is_ok() {
        builder.parse(&env::var("RUST_LOG").unwrap());
    }

    builder.try_init()
}

/// Generates testnet configuration.
pub fn generate_testnet_config(count: u8, start_port: u16) -> Vec<NodeConfig> {
    let (validators, services): (Vec<_>, Vec<_>) = (0..count as usize)
        .map(|_| (gen_keypair(), gen_keypair()))
        .unzip();
    let genesis = GenesisConfig::new(validators.iter().zip(services.iter()).map(|x| {
        ValidatorKeys {
            consensus_key: (x.0).0,
            service_key: (x.1).0,
        }
    }));
    let peers = (0..validators.len())
        .map(|x| {
            format!("127.0.0.1:{}", start_port + x as u16)
                .parse()
                .unwrap()
        })
        .collect::<Vec<_>>();

    validators
        .into_iter()
        .zip(services.into_iter())
        .enumerate()
        .map(|(idx, (validator, service))| {
            NodeConfig {
                listen_address: peers[idx],
                external_address: Some(peers[idx]),
                network: Default::default(),
                peers: peers.clone(),
                consensus_public_key: validator.0,
                consensus_secret_key: validator.1,
                service_public_key: service.0,
                service_secret_key: service.1,
                genesis: genesis.clone(),
                whitelist: Default::default(),
                api: Default::default(),
                mempool: Default::default(),
                services_configs: Default::default(),
            }
        })
        .collect::<Vec<_>>()
}

fn has_colors() -> bool {
    use term::terminfo::TerminfoTerminal;
    use term::Terminal;
    use std::io;
    use atty;

    let out = io::stderr();
    match TerminfoTerminal::new(out) {
        Some(ref term) if atty::is(atty::Stream::Stderr) => term.supports_color(),
        _ => false,
    }
}

fn format_time(time: SystemTime) -> String {
    DateTime::<Local>::from(time).to_rfc2822()
}

fn format_log_record(buf: &mut Formatter, record: &Record) -> io::Result<()> {
    let time = format_time(SystemTime::now());

    let verbose_src_path = match env::var("RUST_VERBOSE_PATH") {
        Ok(val) => val.parse::<bool>().unwrap_or(false),
        Err(_) => false,
    };

    let module = record.module_path().unwrap_or("unknown_module");
    let source_path = if verbose_src_path {
        let file = record.file().unwrap_or("unknown_file");
        let line = record.line().unwrap_or(0);
        format!("{}:{}:{}", module, file, line)
    } else {
        module.to_string()
    };

    if has_colors() {
        let level = match record.level() {
            Level::Error => "ERROR".red(),
            Level::Warn => "WARN".yellow(),
            Level::Info => "INFO".green(),
            Level::Debug => "DEBUG".cyan(),
            Level::Trace => "TRACE".white(),
        };
        writeln!(
            buf,
            "{} {} {} {}",
            time.dimmed(),
            level,
            source_path.dimmed(),
            record.args()
        )
    } else {
        let level = match record.level() {
            Level::Error => "ERROR",
            Level::Warn => "WARN",
            Level::Info => "INFO",
            Level::Debug => "DEBUG",
            Level::Trace => "TRACE",
        };
        writeln!(buf, "{} {} {} {}", time, level, &source_path, record.args())
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 The Exonum Team
//
// 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.

//! Transactions Runtime.
//!
//! This module contains common building blocks for creating runtimes for the Exonum blockchain.
//!
//! Each runtime contains specific services to execute transactions, process events,
//! provide user APIs, etc. There is a unified dispatcher that redirects all the calls
//! and requests to the appropriate runtime environment. Thus, blockchain interacts with the
//! dispatcher, and not with a specific runtime instance.
//!
//! # Service Life Cycle
//!
//! 1. Each runtime has its own [artifacts] registry from which users can deploy them. The artifact
//! identifier is required by the runtime for constructing service instances. In other words,
//! an artifact identifier is similar to a class name, and a specific
//! service instance - to a class instance.
//!
//! 2. Each validator administrator requests the dispatcher to deploy an artifact
//! and then the validator node should send the confirmation if this request is successful. Then, if the
//! number of confirmations is equal to the total number of validators, each validator calls the
//! dispatcher to register the artifact as deployed. After that the validators can send requests to
//! start new service instances from this artifact.
//!
//! 3. To start a new service instance, each validator administrator should send a request
//! to the dispatcher. Each request contains exactly the same artifact identifier, instance name, and
//! instance configuration parameters. Then, as in the previous case, if the number of
//! confirmations is equal to the total number of validators, each validator calls the dispatcher
//! to start a new service instance.
//!
//! 4. // TODO modify instance configuration procedure.
//!
//! 5. // TODO stop instance procedure.
//!
//! Each Exonum transaction is an [`AnyTx`] message with a correct signature.
//!
//! # Transaction Life Cycle
//!
//! 1. An Exonum client creates a transaction message which includes [CallInfo] information
//! about the corresponding handler and serialized transaction parameters as a payload.
//! The client then signs the message with the author's key pair.
//!
//! 2. The client transmits the message to one of the Exonum nodes in the network.
//! The transaction is identified by the hash of the corresponding message.
//!
//! 3. The node verifies the transaction for correctness of the signature and retransmits it to
//! the other network nodes if it is correct.
//!
//! 4. When the validator decides to include the transaction into the next block it takes the message
//! from the transaction pool and passes it to the [`Dispatcher`] for execution.
//!
//! 5. The dispatcher uses a lookup table to find the corresponding [`Runtime`] for the transaction
//! by the service [instance_id] recorded in the message. If the corresponding runtime is
//! successfully found, the dispatcher passes the transaction into this runtime for
//! immediate [execution].
//!
//! 6. After execution the transaction [execution status] is written into the blockchain.
//!
//!
//! [`AnyTx`]: struct.AnyTx.html
//! [`CallInfo`]: struct.CallInfo.html
//! [`Dispatcher`]: dispatcher/struct.Dispatcher.html
//! [`instance_id`]: struct.CallInfo.html#structfield.instance_id
//! [`Runtime`]: trait.Runtime.html
//! [execution]: trait.Runtime.html#execute
//! [execution status]: error/struct.ExecutionStatus.html
//! [artifacts]: struct.ArtifactId.html

pub use self::{
    error::{ErrorKind, ExecutionError},
    types::{AnyTx, ArtifactId, CallInfo, InstanceId, InstanceSpec, MethodId},
};

#[macro_use]
pub mod rust;
pub mod api;
pub mod dispatcher;
pub mod error;
pub mod supervisor;

use exonum_merkledb::{Fork, Snapshot};
use futures::Future;

use std::fmt::Debug;

use crate::{
    api::ApiContext,
    crypto::{Hash, PublicKey, SecretKey},
    node::ApiSender,
    proto::Any,
};

use self::{
    api::ServiceApiBuilder,
    dispatcher::{Dispatcher, DispatcherSender},
};

mod types;

/// List of predefined runtimes.
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
#[repr(u32)]
pub enum RuntimeIdentifier {
    /// Built-in Rust runtime.
    Rust = 0,
    /// Exonum Java Binding runtime.
    Java = 1,
}

impl From<RuntimeIdentifier> for u32 {
    fn from(id: RuntimeIdentifier) -> Self {
        id as Self
    }
}

/// This trait describes runtime environment for the Exonum services.
///
/// You can read more about the life cycle of services and transactions
/// [above](index.html#service-life-cycle).
///
/// Using this trait, you can extend the Exonum blockchain with the services written in
/// different languages. It assumes that the deployment procedure of a new service may be
/// complex and long and even may fail;
/// therefore, we introduce an additional entity - artifacts.
/// Each artifact has a unique identifier and, depending on the runtime, may have an additional
/// specification needed for its deployment. For example, the file to be compiled.
/// Artifact creates corresponding service instances similar to classes in the object
/// oriented programming.
///
/// # Notes
///
/// * Please pay attention to the panic handling policy during the implementation of methods.
/// If no policy is specified, then the method should not panic and each panic will abort the node.
/// * If you have to revert changes in the fork, you should revert only changes which were made by
/// the service that caused panic.
/// * Keep in mind that runtime methods can be executed in two ways: during the blocks execution
/// and during the node restart. Thus, be careful to avoid unnecessary actions in the runtime
/// methods.
///
/// # Hints
///
/// * You may use [`catch_panic`](error/fn.catch_panic.html) method to catch panics according to panic policy.
pub trait Runtime: Send + Debug + 'static {
    /// Request to deploy artifact with the given identifier and additional deploy specification.
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and convert
    /// them into `ExecutionError`.
    fn deploy_artifact(
        &mut self,
        artifact: ArtifactId,
        deploy_spec: Any,
    ) -> Box<dyn Future<Item = (), Error = ExecutionError>>;

    /// Return true if the specified artifact is deployed in this runtime.
    fn is_artifact_deployed(&self, id: &ArtifactId) -> bool;

    /// Return Protobuf description of the deployed artifact with the specified identifier.
    /// If the artifact is not deployed, return `None`.
    ///
    /// # Notes for Runtime Developers
    ///
    /// * Ensure that the deployed artifact has the following information, even if it is empty.
    fn artifact_protobuf_spec(&self, id: &ArtifactId) -> Option<ArtifactProtobufSpec>;

    /// Start a new service instance with the given specification.
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and convert
    /// them into `ExecutionError`.
    /// * If panic occurs, the runtime must ensure that it is in a consistent state.
    fn start_service(&mut self, spec: &InstanceSpec) -> Result<(), ExecutionError>;

    /// Configure a service instance with the given parameters.
    ///
    /// This method is called in two cases:
    ///
    /// * After creating a new service instance by the [`start_service`] invocation. In this case,
    /// if an error during this action occurs, the dispatcher will invoke [`stop_service`].
    /// Make sure that this invocation will not fail.
    /// * During the configuration change procedure. [ECR-3306]
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and convert
    /// them into `ExecutionError`.
    ///
    /// ['start_service`]: #start_service
    /// ['stop_service`]: #stop_service
    fn configure_service(
        &self,
        fork: &Fork,
        descriptor: InstanceDescriptor,
        parameters: Any,
    ) -> Result<(), ExecutionError>;

    /// Stop existing service instance with the given specification.
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and convert
    /// them into `ExecutionError`.
    /// * If panic occurs, the runtime must ensure that it is in a consistent state.
    fn stop_service(&mut self, descriptor: InstanceDescriptor) -> Result<(), ExecutionError>;

    /// Execute service transaction.
    ///
    /// # Policy on Panics
    ///
    /// Do not process. Panic will be processed by the method caller.
    fn execute(
        &self,
        dispatcher: &dispatcher::Dispatcher,
        context: &mut ExecutionContext,
        call_info: CallInfo,
        arguments: &[u8],
    ) -> Result<(), ExecutionError>;

    /// Gets the state hashes of the every available service.
    fn state_hashes(&self, snapshot: &dyn Snapshot) -> StateHashAggregator;

    /// Calls `before_commit` for all the services stored in the runtime.
    ///
    /// # Notes for Runtime Developers.
    ///
    /// * The order of services during invocation of this method must be the same for each node.
    /// In other words, the order of the runtime services must be the same for each node.
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and write
    /// them into the log.
    /// * If panic occurs, the runtime rolls back the changes in the fork.
    fn before_commit(&self, dispatcher: &Dispatcher, fork: &mut Fork);

    /// Calls `after_commit` for all the services stored in the runtime.
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and write
    /// them into the log.
    fn after_commit(
        &self,
        dispatcher: &DispatcherSender,
        snapshot: &dyn Snapshot,
        service_keypair: &(PublicKey, SecretKey),
        tx_sender: &ApiSender,
    );

    /// Collect the full list of API handlers from the runtime for the built-in Exonum API server.
    ///
    /// This method is called during the API server restart. Use this method if you do not plan to
    /// use your own API processing mechanism.
    ///
    /// Warning! It is a temporary method which retains the existing `RustRuntime` code.
    /// It will be removed in the future.
    #[doc(hidden)]
    fn api_endpoints(&self, _context: &ApiContext) -> Vec<(String, ServiceApiBuilder)> {
        Vec::new()
    }

    /// Notify the runtime about the changes in the list of service instances.
    ///
    /// The purpose of this method is to provide building blocks to create your own
    /// API processing mechanisms.
    fn notify_api_changes(&self, _context: &ApiContext, _changes: &[ApiChange]) {}
}

impl<T> From<T> for Box<dyn Runtime>
where
    T: Runtime,
{
    fn from(runtime: T) -> Self {
        Box::new(runtime) as Self
    }
}

/// Artifact Protobuf specification for the Exonum clients.
#[derive(Debug, PartialEq)]
pub struct ArtifactProtobufSpec<'a> {
    /// List of Protobuf files that make up the service interface. The first element in the tuple
    /// is the file name, the second one is its content.
    ///
    /// The common interface entry point is always in the `service.proto` file.
    pub sources: &'a [(&'a str, &'a str)],
}

impl<'a> Default for ArtifactProtobufSpec<'a> {
    /// Create blank artifact information without any proto sources.
    fn default() -> Self {
        const EMPTY_SOURCES: [(&str, &str); 0] = [];

        Self {
            sources: EMPTY_SOURCES.as_ref(),
        }
    }
}

/// An accessory structure that aggregates root object hashes of the service
/// information schemas of the runtime with the root hash of the runtime information schema itself.
#[derive(Debug, PartialEq, Default)]
pub struct StateHashAggregator {
    /// List of hashes of the root objects of the runtime information schemas.
    pub runtime: Vec<Hash>,
    /// List of hashes of the root objects of the service instances schemas.
    pub instances: Vec<(InstanceId, Vec<Hash>)>,
}

/// The initiator of the transaction execution.
#[derive(Debug, PartialEq)]
pub enum Caller {
    /// A usual transaction from the Exonum client, authorized by its key pair.
    Transaction {
        /// Hash of the transaction message.
        hash: Hash,
        /// Public key of the user who signed this transaction.
        author: PublicKey,
    },
    // This transaction is invoked on behalf of the blockchain itself,
    // for example [`before_commit`](trait.Runtime#before_commit) event.
    Blockchain,
}

impl Caller {
    /// Return the author's public key, if it exists.
    pub fn author(&self) -> Option<PublicKey> {
        self.as_transaction().map(|(_hash, author)| *author)
    }

    /// Return the transaction hash, if it exists.
    pub fn transaction_hash(&self) -> Option<Hash> {
        self.as_transaction().map(|(hash, _)| *hash)
    }

    fn as_transaction(&self) -> Option<(&Hash, &PublicKey)> {
        if let Caller::Transaction { hash, author } = self {
            Some((hash, author))
        } else {
            None
        }
    }
}

/// Provide the current state of the blockchain and the caller information in respect of the transaction
/// which is being executed.
#[derive(Debug)]
pub struct ExecutionContext<'a> {
    /// The current state of the blockchain. It includes the new, not-yet-committed, changes to
    /// the database made by the previous transactions already executed in this block.
    pub fork: &'a Fork,
    /// The initiator of the transaction execution.
    pub caller: Caller,
    actions: Vec<dispatcher::Action>,
}

impl<'a> ExecutionContext<'a> {
    pub(crate) fn new(fork: &'a Fork, caller: Caller) -> Self {
        Self {
            fork,
            caller,
            actions: Vec::new(),
        }
    }

    pub(crate) fn dispatch_action(&mut self, action: dispatcher::Action) {
        self.actions.push(action);
    }
}

/// Instance descriptor contains information to access running service instance.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct InstanceDescriptor<'a> {
    /// The unique numeric ID of the service instance.
    /// [Read more.](struct.InstanceSpec.html#structfield.id)
    pub id: InstanceId,
    /// The unique name of the service instance.
    /// [Read more.](struct.InstanceSpec.html#structfield.name)
    pub name: &'a str,
}

impl std::fmt::Display for InstanceDescriptor<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}:{}", self.id, self.name)
    }
}

impl From<InstanceDescriptor<'_>> for (InstanceId, String) {
    fn from(descriptor: InstanceDescriptor) -> Self {
        (descriptor.id, descriptor.name.to_owned())
    }
}

/// Change in the list of service instances.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ApiChange {
    /// New instance has been added.
    InstanceAdded(InstanceId),
    /// Instance has been removed.
    InstanceRemoved(InstanceId),
}
<commit_msg>Expand documentation on configuration parameters usage [ECR-3463] (#1430)<commit_after>// Copyright 2019 The Exonum Team
//
// 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.

//! Transactions Runtime.
//!
//! This module contains common building blocks for creating runtimes for the Exonum blockchain.
//!
//! Each runtime contains specific services to execute transactions, process events,
//! provide user APIs, etc. There is a unified dispatcher that redirects all the calls
//! and requests to the appropriate runtime environment. Thus, blockchain interacts with the
//! dispatcher, and not with a specific runtime instance.
//!
//! # Service Life Cycle
//!
//! 1. Each runtime has its own [artifacts] registry from which users can deploy them. The artifact
//! identifier is required by the runtime for constructing service instances. In other words,
//! an artifact identifier is similar to a class name, and a specific
//! service instance - to a class instance.
//!
//! 2. Each validator administrator requests the dispatcher to deploy an artifact
//! and then the validator node should send the confirmation if this request is successful. Then, if the
//! number of confirmations is equal to the total number of validators, each validator calls the
//! dispatcher to register the artifact as deployed. After that the validators can send requests to
//! start new service instances from this artifact.
//!
//! 3. To start a new service instance, each validator administrator should send a request
//! to the dispatcher. Each request contains exactly the same artifact identifier, instance name, and
//! instance configuration parameters. Then, as in the previous case, if the number of
//! confirmations is equal to the total number of validators, each validator calls the dispatcher
//! to start a new service instance.
//!
//! 4. // TODO modify instance configuration procedure.
//!
//! 5. // TODO stop instance procedure.
//!
//! Each Exonum transaction is an [`AnyTx`] message with a correct signature.
//!
//! # Transaction Life Cycle
//!
//! 1. An Exonum client creates a transaction message which includes [CallInfo] information
//! about the corresponding handler and serialized transaction parameters as a payload.
//! The client then signs the message with the author's key pair.
//!
//! 2. The client transmits the message to one of the Exonum nodes in the network.
//! The transaction is identified by the hash of the corresponding message.
//!
//! 3. The node verifies the transaction for correctness of the signature and retransmits it to
//! the other network nodes if it is correct.
//!
//! 4. When the validator decides to include the transaction into the next block it takes the message
//! from the transaction pool and passes it to the [`Dispatcher`] for execution.
//!
//! 5. The dispatcher uses a lookup table to find the corresponding [`Runtime`] for the transaction
//! by the service [instance_id] recorded in the message. If the corresponding runtime is
//! successfully found, the dispatcher passes the transaction into this runtime for
//! immediate [execution].
//!
//! 6. After execution the transaction [execution status] is written into the blockchain.
//!
//!
//! [`AnyTx`]: struct.AnyTx.html
//! [`CallInfo`]: struct.CallInfo.html
//! [`Dispatcher`]: dispatcher/struct.Dispatcher.html
//! [`instance_id`]: struct.CallInfo.html#structfield.instance_id
//! [`Runtime`]: trait.Runtime.html
//! [execution]: trait.Runtime.html#execute
//! [execution status]: error/struct.ExecutionStatus.html
//! [artifacts]: struct.ArtifactId.html

pub use self::{
    error::{ErrorKind, ExecutionError},
    types::{AnyTx, ArtifactId, CallInfo, InstanceId, InstanceSpec, MethodId},
};

#[macro_use]
pub mod rust;
pub mod api;
pub mod dispatcher;
pub mod error;
pub mod supervisor;

use exonum_merkledb::{Fork, Snapshot};
use futures::Future;

use std::fmt::Debug;

use crate::{
    api::ApiContext,
    crypto::{Hash, PublicKey, SecretKey},
    node::ApiSender,
    proto::Any,
};

use self::{
    api::ServiceApiBuilder,
    dispatcher::{Dispatcher, DispatcherSender},
};

mod types;

/// List of predefined runtimes.
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
#[repr(u32)]
pub enum RuntimeIdentifier {
    /// Built-in Rust runtime.
    Rust = 0,
    /// Exonum Java Binding runtime.
    Java = 1,
}

impl From<RuntimeIdentifier> for u32 {
    fn from(id: RuntimeIdentifier) -> Self {
        id as Self
    }
}

/// This trait describes runtime environment for the Exonum services.
///
/// You can read more about the life cycle of services and transactions
/// [above](index.html#service-life-cycle).
///
/// Using this trait, you can extend the Exonum blockchain with the services written in
/// different languages. It assumes that the deployment procedure of a new service may be
/// complex and long and even may fail;
/// therefore, we introduce an additional entity - artifacts.
/// Each artifact has a unique identifier and, depending on the runtime, may have an additional
/// specification needed for its deployment. For example, the file to be compiled.
/// Artifact creates corresponding service instances similar to classes in the object
/// oriented programming.
///
/// # Notes
///
/// * Please pay attention to the panic handling policy during the implementation of methods.
/// If no policy is specified, then the method should not panic and each panic will abort the node.
/// * If you have to revert changes in the fork, you should revert only changes which were made by
/// the service that caused panic.
/// * Keep in mind that runtime methods can be executed in two ways: during the blocks execution
/// and during the node restart. Thus, be careful to avoid unnecessary actions in the runtime
/// methods.
///
/// # Hints
///
/// * You may use [`catch_panic`](error/fn.catch_panic.html) method to catch panics according to panic policy.
pub trait Runtime: Send + Debug + 'static {
    /// Request to deploy artifact with the given identifier and additional deploy specification.
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and convert
    /// them into `ExecutionError`.
    fn deploy_artifact(
        &mut self,
        artifact: ArtifactId,
        deploy_spec: Any,
    ) -> Box<dyn Future<Item = (), Error = ExecutionError>>;

    /// Return true if the specified artifact is deployed in this runtime.
    fn is_artifact_deployed(&self, id: &ArtifactId) -> bool;

    /// Return Protobuf description of the deployed artifact with the specified identifier.
    /// If the artifact is not deployed, return `None`.
    ///
    /// # Notes for Runtime Developers
    ///
    /// * Ensure that the deployed artifact has the following information, even if it is empty.
    fn artifact_protobuf_spec(&self, id: &ArtifactId) -> Option<ArtifactProtobufSpec>;

    /// Start a new service instance with the given specification.
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and convert
    /// them into `ExecutionError`.
    /// * If panic occurs, the runtime must ensure that it is in a consistent state.
    fn start_service(&mut self, spec: &InstanceSpec) -> Result<(), ExecutionError>;

    /// Configure a service instance with the given parameters.
    ///
    /// The configuration parameters passed to the method are discarded immediately.
    /// So the service instance should save them by itself if it is important for
    /// the service business logic.
    ///
    /// This method is called in two cases:
    ///
    /// * After creating a new service instance by the [`start_service`] invocation. In this case,
    /// if an error during this action occurs, the dispatcher will invoke [`stop_service`].
    /// Make sure that this invocation will not fail.
    /// * During the configuration change procedure. [ECR-3306]
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and convert
    /// them into `ExecutionError`.
    ///
    /// ['start_service`]: #start_service
    /// ['stop_service`]: #stop_service
    fn configure_service(
        &self,
        fork: &Fork,
        descriptor: InstanceDescriptor,
        parameters: Any,
    ) -> Result<(), ExecutionError>;

    /// Stop existing service instance with the given specification.
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and convert
    /// them into `ExecutionError`.
    /// * If panic occurs, the runtime must ensure that it is in a consistent state.
    fn stop_service(&mut self, descriptor: InstanceDescriptor) -> Result<(), ExecutionError>;

    /// Execute service transaction.
    ///
    /// # Policy on Panics
    ///
    /// Do not process. Panic will be processed by the method caller.
    fn execute(
        &self,
        dispatcher: &dispatcher::Dispatcher,
        context: &mut ExecutionContext,
        call_info: CallInfo,
        arguments: &[u8],
    ) -> Result<(), ExecutionError>;

    /// Gets the state hashes of the every available service.
    fn state_hashes(&self, snapshot: &dyn Snapshot) -> StateHashAggregator;

    /// Calls `before_commit` for all the services stored in the runtime.
    ///
    /// # Notes for Runtime Developers.
    ///
    /// * The order of services during invocation of this method must be the same for each node.
    /// In other words, the order of the runtime services must be the same for each node.
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and write
    /// them into the log.
    /// * If panic occurs, the runtime rolls back the changes in the fork.
    fn before_commit(&self, dispatcher: &Dispatcher, fork: &mut Fork);

    /// Calls `after_commit` for all the services stored in the runtime.
    ///
    /// # Policy on Panics
    ///
    /// * Catch each kind of panics except for `FatalError` and write
    /// them into the log.
    fn after_commit(
        &self,
        dispatcher: &DispatcherSender,
        snapshot: &dyn Snapshot,
        service_keypair: &(PublicKey, SecretKey),
        tx_sender: &ApiSender,
    );

    /// Collect the full list of API handlers from the runtime for the built-in Exonum API server.
    ///
    /// This method is called during the API server restart. Use this method if you do not plan to
    /// use your own API processing mechanism.
    ///
    /// Warning! It is a temporary method which retains the existing `RustRuntime` code.
    /// It will be removed in the future.
    #[doc(hidden)]
    fn api_endpoints(&self, _context: &ApiContext) -> Vec<(String, ServiceApiBuilder)> {
        Vec::new()
    }

    /// Notify the runtime about the changes in the list of service instances.
    ///
    /// The purpose of this method is to provide building blocks to create your own
    /// API processing mechanisms.
    fn notify_api_changes(&self, _context: &ApiContext, _changes: &[ApiChange]) {}
}

impl<T> From<T> for Box<dyn Runtime>
where
    T: Runtime,
{
    fn from(runtime: T) -> Self {
        Box::new(runtime) as Self
    }
}

/// Artifact Protobuf specification for the Exonum clients.
#[derive(Debug, PartialEq)]
pub struct ArtifactProtobufSpec<'a> {
    /// List of Protobuf files that make up the service interface. The first element in the tuple
    /// is the file name, the second one is its content.
    ///
    /// The common interface entry point is always in the `service.proto` file.
    pub sources: &'a [(&'a str, &'a str)],
}

impl<'a> Default for ArtifactProtobufSpec<'a> {
    /// Create blank artifact information without any proto sources.
    fn default() -> Self {
        const EMPTY_SOURCES: [(&str, &str); 0] = [];

        Self {
            sources: EMPTY_SOURCES.as_ref(),
        }
    }
}

/// An accessory structure that aggregates root object hashes of the service
/// information schemas of the runtime with the root hash of the runtime information schema itself.
#[derive(Debug, PartialEq, Default)]
pub struct StateHashAggregator {
    /// List of hashes of the root objects of the runtime information schemas.
    pub runtime: Vec<Hash>,
    /// List of hashes of the root objects of the service instances schemas.
    pub instances: Vec<(InstanceId, Vec<Hash>)>,
}

/// The initiator of the transaction execution.
#[derive(Debug, PartialEq)]
pub enum Caller {
    /// A usual transaction from the Exonum client, authorized by its key pair.
    Transaction {
        /// Hash of the transaction message.
        hash: Hash,
        /// Public key of the user who signed this transaction.
        author: PublicKey,
    },
    // This transaction is invoked on behalf of the blockchain itself,
    // for example [`before_commit`](trait.Runtime#before_commit) event.
    Blockchain,
}

impl Caller {
    /// Return the author's public key, if it exists.
    pub fn author(&self) -> Option<PublicKey> {
        self.as_transaction().map(|(_hash, author)| *author)
    }

    /// Return the transaction hash, if it exists.
    pub fn transaction_hash(&self) -> Option<Hash> {
        self.as_transaction().map(|(hash, _)| *hash)
    }

    fn as_transaction(&self) -> Option<(&Hash, &PublicKey)> {
        if let Caller::Transaction { hash, author } = self {
            Some((hash, author))
        } else {
            None
        }
    }
}

/// Provide the current state of the blockchain and the caller information in respect of the transaction
/// which is being executed.
#[derive(Debug)]
pub struct ExecutionContext<'a> {
    /// The current state of the blockchain. It includes the new, not-yet-committed, changes to
    /// the database made by the previous transactions already executed in this block.
    pub fork: &'a Fork,
    /// The initiator of the transaction execution.
    pub caller: Caller,
    actions: Vec<dispatcher::Action>,
}

impl<'a> ExecutionContext<'a> {
    pub(crate) fn new(fork: &'a Fork, caller: Caller) -> Self {
        Self {
            fork,
            caller,
            actions: Vec::new(),
        }
    }

    pub(crate) fn dispatch_action(&mut self, action: dispatcher::Action) {
        self.actions.push(action);
    }
}

/// Instance descriptor contains information to access running service instance.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct InstanceDescriptor<'a> {
    /// The unique numeric ID of the service instance.
    /// [Read more.](struct.InstanceSpec.html#structfield.id)
    pub id: InstanceId,
    /// The unique name of the service instance.
    /// [Read more.](struct.InstanceSpec.html#structfield.name)
    pub name: &'a str,
}

impl std::fmt::Display for InstanceDescriptor<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}:{}", self.id, self.name)
    }
}

impl From<InstanceDescriptor<'_>> for (InstanceId, String) {
    fn from(descriptor: InstanceDescriptor) -> Self {
        (descriptor.id, descriptor.name.to_owned())
    }
}

/// Change in the list of service instances.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ApiChange {
    /// New instance has been added.
    InstanceAdded(InstanceId),
    /// Instance has been removed.
    InstanceRemoved(InstanceId),
}
<|endoftext|>