<commit_before>/**
use the taylor series to caculate tan^-1 (x) where |x| <= 1, x >= 0
**/
fn taylor_atan (x: f64) -> f64 {
    let mut a: f64 = 0.0;
    let mut s: f64 = 1.0;
    let mut xpow: f64;

    // by definition
    if x == 0.0 {
        return 0.0;
    }

    // this is well known, and the taylor series we are using explictly assumes |x| < 1
    if x == 1.0 {
        return std::f64::consts::FRAC_PI_4;
    }

    for ii in range(1i, 60) {
        if ii % 2 == 0 {
            continue;
        }
        xpow = 1.0;
        for _ in range(0i, ii) {
            xpow *= x;
        }
        a += s * xpow / (ii as f64);
        s = -1.0*s;
    }

    return a;
}

fn generate_table () {

    let pi: f64 = 3.1415926536897932384626;
    let k1: f64 = 0.6072529350088812561694; // 1/k
    let num_bits: uint = 32;
    let mul: uint = 1<<(num_bits-2);

    println!("Cordic sin in rust");
    println!("num bits {}", num_bits);
    println!("mul {}", mul);
    println!("1<<(num_bits-2) {}", ((1i << (num_bits-2)) as f64));
    println!("pi is {}", pi);
    println!("k1 is {}", k1);

    println!("let cordic_tab = [");

    let shift: f64 = 2.0;
    for ii in range(0, num_bits) {
        let ipow: f64 = 1f64/shift.powi(ii as i32);
        let cur: f64 = taylor_atan(ipow) * (mul as f64);

        if ii % 4 == 0 && ii > 0 {
            println!("");
        }
        if ii == 0 {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        } else {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        }
    }

    println!("];");
}

fn sin(theta: f64) -> f64 {

    let num_bits: uint = 32;

    let k1: f64 = 0.6072529350088812561694; // 1/k
    let mul: f64 = (1i << (num_bits-2)) as f64;
    let cordic_k1: f64 = k1 * mul;
    let mut x: int = cordic_k1.floor() as int; //0x26DD3B6A;
    let mut y: int = 0;
    let mut z: int = (mul * theta).floor() as int;
    let mut tx: int;
    let mut ty: int;
    let mut tz: int;

    let mut d: int;

    let cordic_tab = [
        0x3243f6a8, 0x1dac6705, 0xfadbafc, 0x7f56ea6,
        0x3feab76, 0x1ffd55b, 0xfffaaa, 0x7fff55,
        0x3fffea, 0x1ffffd, 0xfffff, 0x7ffff,
        0x3ffff, 0x1ffff, 0xffff, 0x7fff,
        0x3fff, 0x1fff, 0xfff, 0x7ff,
        0x3ff, 0x1ff, 0xff, 0x7f,
        0x3f, 0x1f, 0xf, 0x8,
        0x4, 0x2, 0x1, 0x0, ];

    for k in range(0, num_bits) {
        if z >= 0 {
            d = 0;
        } else {
            d = -1;
        }

        tx = x - (((y>>k) ^ d) - d);
        ty = y + (((x>>k) ^ d) - d);
        tz = z - ((cordic_tab[k] ^ d) - d);
        x = tx; y = ty; z = tz;
    }

    let s: f64 = (y as f64)/(mul as f64);

    return s;

}

fn main() {
    generate_table();

    let frac_pi_2: f64 = std::f64::consts::FRAC_PI_2; //pi/2.0;

    for ii in range(0i, 50) {
        let cur: f64 = ii as f64;
        let theta: f64 = cur/50.0 * frac_pi_2;
        let s: f64 = sin(theta);
            println!("s {}", s);
    }
}
<commit_msg>use built in f64 conts<commit_after>/**
use the taylor series to caculate tan^-1 (x) where |x| <= 1, x >= 0
**/
fn taylor_atan (x: f64) -> f64 {
    let mut a: f64 = 0.0;
    let mut s: f64 = 1.0;
    let mut xpow: f64;

    // by definition
    if x == 0.0 {
        return 0.0;
    }

    // this is well known, and the taylor series we are using explictly assumes |x| < 1
    if x == 1.0 {
        return std::f64::consts::FRAC_PI_4;
    }

    for ii in range(1i, 60) {
        if ii % 2 == 0 {
            continue;
        }
        xpow = 1.0;
        for _ in range(0i, ii) {
            xpow *= x;
        }
        a += s * xpow / (ii as f64);
        s = -1.0*s;
    }

    return a;
}

fn generate_table () {

    let pi: f64 = std::f64::consts::PI;
    let k1: f64 = 0.6072529350088812561694; // 1/k
    let num_bits: uint = 32;
    let mul: uint = 1<<(num_bits-2);

    println!("Cordic sin in rust");
    println!("num bits {}", num_bits);
    println!("mul {}", mul);
    println!("1<<(num_bits-2) {}", ((1i << (num_bits-2)) as f64));
    println!("pi is {}", pi);
    println!("k1 is {}", k1);

    println!("let cordic_tab = [");

    let shift: f64 = 2.0;
    for ii in range(0, num_bits) {
        let ipow: f64 = 1f64/shift.powi(ii as i32);
        let cur: f64 = taylor_atan(ipow) * (mul as f64);

        if ii % 4 == 0 && ii > 0 {
            println!("");
        }
        if ii == 0 {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        } else {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        }
    }

    println!("];");
}

fn sin(theta: f64) -> f64 {

    let num_bits: uint = 32;

    let k1: f64 = 0.6072529350088812561694; // 1/k
    let mul: f64 = (1i << (num_bits-2)) as f64;
    let cordic_k1: f64 = k1 * mul;
    let mut x: int = cordic_k1.floor() as int; //0x26DD3B6A;
    let mut y: int = 0;
    let mut z: int = (mul * theta).floor() as int;
    let mut tx: int;
    let mut ty: int;
    let mut tz: int;

    let mut d: int;

    let cordic_tab = [
        0x3243f6a8, 0x1dac6705, 0xfadbafc, 0x7f56ea6,
        0x3feab76, 0x1ffd55b, 0xfffaaa, 0x7fff55,
        0x3fffea, 0x1ffffd, 0xfffff, 0x7ffff,
        0x3ffff, 0x1ffff, 0xffff, 0x7fff,
        0x3fff, 0x1fff, 0xfff, 0x7ff,
        0x3ff, 0x1ff, 0xff, 0x7f,
        0x3f, 0x1f, 0xf, 0x8,
        0x4, 0x2, 0x1, 0x0, ];

    for k in range(0, num_bits) {
        if z >= 0 {
            d = 0;
        } else {
            d = -1;
        }

        tx = x - (((y>>k) ^ d) - d);
        ty = y + (((x>>k) ^ d) - d);
        tz = z - ((cordic_tab[k] ^ d) - d);
        x = tx; y = ty; z = tz;
    }

    let s: f64 = (y as f64)/(mul as f64);

    return s;

}

fn main() {
    generate_table();

    let frac_pi_2: f64 = std::f64::consts::FRAC_PI_2; //pi/2.0;

    for ii in range(0i, 50) {
        let cur: f64 = ii as f64;
        let theta: f64 = cur/50.0 * frac_pi_2;
        let s: f64 = sin(theta);
            println!("sin({}) ~= {}", theta, s);
    }
}
<|endoftext|>


<commit_before>/* diosix RV32G/RV64G code for managing physical memory
 *
 * (c) Chris Williams, 2019.
 *
 * See LICENSE for usage and copying.
 */

use core::intrinsics::transmute;
use devicetree;

/* we need this code from the assembly files */
extern "C"
{
    /* linker symbols */
    static __kernel_start: u8;
    static __kernel_end: u8;
    static __supervisor_shared_start: u8;
    static __supervisor_shared_end: u8;
    static __supervisor_data_start: u8;
    static __supervisor_data_end: u8;
}

/* place a memory barrier that ensures all RAM and MMIO read and write operations
complete in the eyes of other CPU cores before the barrier is encountered */
#[inline(always)]
pub fn barrier()
{
    unsafe
    {
        asm!("fence iorw, iorw" :::: "volatile");
    }
}

/* allowed physical memory access permissions */
pub enum AccessPermissions
{
    Read,
    ReadWrite,
    ReadExecute,
    NoAccess
}

/* there are a maximum number of physical memory regions */
const PHYS_PMP_MAX_REGIONS: usize = 8;
/* PMP access flags */
const PHYS_PMP_READ: usize  = 1 << 0;
const PHYS_PMP_WRITE: usize = 1 << 1;
const PHYS_PMP_EXEC: usize  = 1 << 2;
const PHYS_PMP_TOR: usize   = 1 << 3;

/* each CPU has a fix memory overhead, allocated during boot */
static PHYS_MEM_PER_CPU: usize = 1 << 18; /* 256KB. see ../asm/const.s */

/* standardize types for passing around physical RAM addresses */
pub type PhysMemBase = usize;
pub type PhysMemEnd  = usize;
pub type PhysMemSize = usize;

/* describe a physical RAM area using its start address and size */
pub struct RAMArea
{
    pub base: PhysMemBase,
    pub size: PhysMemSize
}

/* allow the higher level kernel to iterate over physical RAM, adding available blocks to its
allocator pool and skipping the kernel's footprint of code, data and boot payload */
pub struct RAMAreaIter
{
    total_area: RAMArea, /* describes the entire physical RAM block */
    kernel_area: RAMArea, /* describes RAM reserved by the kernel */
    pos: PhysMemBase /* current possition of the iterator into the total_area block */
}

impl Iterator for RAMAreaIter
{
    type Item = RAMArea;

    fn next(&mut self) -> Option<RAMArea>
    {
        /* if we're in the kernel area then round us up to the end of the kernel area */
        if self.pos >= self.kernel_area.base && self.pos < self.kernel_area.base + self.kernel_area.size as PhysMemBase
        {
            self.pos = self.kernel_area.base + self.kernel_area.size as PhysMemBase;
        }

        /* catch the iterator escaping the physical RAM area */
        if self.pos < self.total_area.base || self.pos >= self.total_area.base + self.total_area.size as PhysMemBase
        {
            return None;
        }

        /* determine whether we're outside a kernel area */
        if self.pos < self.kernel_area.base
        {
            /* round up from wherever we are to the kernel area base */
            let area = RAMArea
            {
                base: self.pos,
                size: (self.kernel_area.base - self.pos) as PhysMemSize
            };
            /* skip to the end of the kernel area */
            self.pos = self.kernel_area.base + self.kernel_area.size as PhysMemBase;
            return Some(area);
        }

        if self.pos >= self.kernel_area.base + self.kernel_area.size as PhysMemBase
        {
            /* we're clear of the kernel round up to end of ram */
            let area = RAMArea
            {
                base: self.pos,
                size: (self.kernel_area.base - self.pos) as PhysMemSize
            };
            self.pos = self.kernel_area.base + self.kernel_area.size as PhysMemBase;
            return Some(area);
        }

        /* we shouldn't fall through to here? */
        return None;
    }
}

/* obtain available physical memory details from system device tree. this assumes RISC-V systems have a single
   block of physical RAM. If this changes, then we need to add support for that. break up this block of physical RAM
   into one or more areas, skipping any physical RAM being used to store for the kernel, its data structures
   and boot payload to ensure this memory isn't reused for allocations.
=> device_tree_buf = device tree to parse
<= iterator that describes the available blocks of physical RAM, or None for failure */
pub fn available_ram(device_tree_buf: &u8) -> Option<RAMAreaIter>
{
    /* at the end of the kernel footprint is the per-cpu heaps in one long contiguous block.
    take this into account so the memory isn't reused for other allocations */
    let cpu_count = match devicetree::get_cpu_count(device_tree_buf)
    {
        Some(c) => c,
        None => return None
    };

    /* we'll assume the kernel, data, code, peer-CPU heaps, and its boot payload are in a contiguous block of physical RAM */
    let (phys_kernel_start, phys_kernel_end) = kernel_footprint(cpu_count);
    let phys_kernel_size = (phys_kernel_end - phys_kernel_start) as PhysMemSize;

    /* assumes RISC-V systems sport a single block of physical RAM for software use */
    let all_phys_ram = match devicetree::get_ram_area(device_tree_buf)
    {
        Some(a) => a,
        None => return None

    };

    /* return an iterator the higher level kernel can run through. this cuts the physical RAM
    block up into sections that do not contain the kernel footprint */
    return Some(RAMAreaIter
    {
        pos: all_phys_ram.base,
        total_area: all_phys_ram,
        kernel_area: RAMArea
        {
            base: phys_kernel_start,
            size: phys_kernel_size
        }
    });
}

/* return the (start address, end address) of the shared supervisor kernel code in physical memory.
shared in that there is code common to the supervisor and kernel that can be shared. in effect,
this shared code appears in the supervisor's read-only code region but can be used by the hypervisor, too. */
pub fn builtin_supervisor_code() -> (PhysMemBase, PhysMemEnd)
{
    /* derived from the .sshared linker section */
    let supervisor_start: PhysMemBase = unsafe { transmute(&__supervisor_shared_start) };
    let supervisor_end: PhysMemEnd = unsafe { transmute(&__supervisor_shared_end) };
    return (supervisor_start, supervisor_end);
}

/* return the (start address, end address) of the builtin supervisor's private static read-write data
in physical memory */
pub fn builtin_supervisor_data() -> (PhysMemBase, PhysMemEnd)
{
    /* derived from the .sdata linker section */
    let supervisor_start: PhysMemBase = unsafe { transmute(&__supervisor_data_start) };
    let supervisor_end: PhysMemEnd = unsafe { transmute(&__supervisor_data_end) };
    return (supervisor_start, supervisor_end);
}

/* return the (start address, end address) of the whole kernel's code and data in physical memory,
including the builtin supervisor and fixed per-CPU core private memory areas
=> cpu_count = number of CPU cores
<= base and end addresses of the kernel footprint */
fn kernel_footprint(cpu_count: usize) -> (PhysMemBase, PhysMemEnd)
{
    /* derived from the .sshared linker section */
    let kernel_start: PhysMemBase = unsafe { transmute(&__kernel_start) };
    let kernel_end: PhysMemEnd = unsafe { transmute::<_, PhysMemEnd>(&__kernel_end) } + (cpu_count * PHYS_MEM_PER_CPU) as PhysMemEnd;
    return (kernel_start, kernel_end);
}

/* create a per-CPU physical memory region and apply access permissions to it. if the region already exists, overwrite it.
each region is a RISC-V physical memory protection (PMP) area. we pair up PMP addresses in TOR (top of range) mode. eg, region 0
uses pmp0cfg and pmp1cfg in pmpcfg0 for start and end, region 1 uses pmp1cfg and pmp2cfg in pmpcfg0.
   => regionid = ID number of the region to create or update
      base, end = start and end addresses of region
      access = access permissions for the region
   <= true for success, or false for failure */
pub fn protect(regionid: usize, base: usize, end: usize, access: AccessPermissions) -> bool
{
    if regionid > PHYS_PMP_MAX_REGIONS { return false; }

    let accessbits = PHYS_PMP_TOR | match access
    {
        AccessPermissions::Read => PHYS_PMP_READ,
        AccessPermissions::ReadWrite => PHYS_PMP_READ | PHYS_PMP_WRITE,
        AccessPermissions::ReadExecute => PHYS_PMP_READ | PHYS_PMP_EXEC,
        AccessPermissions::NoAccess => 0
    };

    /* select the appropriate pmpcfg bits from the region ID */
    let pmpcfg_reg = regionid >> 1;
    let shift = ((regionid - (pmpcfg_reg << 1)) << 4) + 8;

    /* only update the access bits for the end address, leaving the base access bits at zero.
    according to the specification, only the end address access bits are checked */
    let mask = 0xff << shift;
    let cfgbits = read_pmpcfg(pmpcfg_reg) & !mask;
    write_pmpcfg(pmpcfg_reg, cfgbits | (accessbits << shift));

    /* program in the base and end addesses */
    write_pmpaddr(regionid * 2, base);
    write_pmpaddr((regionid * 2) + 1, end);

    return true;
}

/* read the value of the given PMP configuration register (pmpcfg0-3).
warning: silently fails with a zero on bad read */
fn read_pmpcfg(register: usize) -> usize
{
    match register
    {
        0 => read_csr!(pmpcfg0),
        1 => read_csr!(pmpcfg1),
        2 => read_csr!(pmpcfg2),
        3 => read_csr!(pmpcfg3),
        _ => 0
    }
}

/* write value to the given PMP configuration register (pmpcfg0-3). warning: silently fails */
fn write_pmpcfg(register: usize, value: usize)
{
    match register
    {
        0 => write_csr!(pmpcfg0, value),
        1 => write_csr!(pmpcfg1, value),
        2 => write_csr!(pmpcfg2, value),
        3 => write_csr!(pmpcfg3, value),
        _ => ()
    };
}

/* write value to the given PMP address register (pmpaddr0-15). warning: silently fails */
fn write_pmpaddr(register: usize, value: usize)
{
    match register
    {
        0 => write_csr!(pmpaddr0, value),
        1 => write_csr!(pmpaddr1, value),
        2 => write_csr!(pmpaddr2, value),
        3 => write_csr!(pmpaddr3, value),
        4 => write_csr!(pmpaddr4, value),
        5 => write_csr!(pmpaddr5, value),
        6 => write_csr!(pmpaddr6, value),
        7 => write_csr!(pmpaddr7, value),
        8 => write_csr!(pmpaddr8, value),
        9 => write_csr!(pmpaddr9, value),
        10 => write_csr!(pmpaddr10, value),
        11 => write_csr!(pmpaddr11, value),
        12 => write_csr!(pmpaddr12, value),
        13 => write_csr!(pmpaddr13, value),
        14 => write_csr!(pmpaddr14, value),
        15 => write_csr!(pmpaddr15, value),
        _ => ()
    };
}
<commit_msg>Differentiate between RV32 and RV64 PMP configurations using cfg<commit_after>/* diosix RV32G/RV64G code for managing physical memory
 *
 * (c) Chris Williams, 2019.
 *
 * See LICENSE for usage and copying.
 */

use core::intrinsics::transmute;
use devicetree;

/* we need this code from the assembly files */
extern "C"
{
    /* linker symbols */
    static __kernel_start: u8;
    static __kernel_end: u8;
    static __supervisor_shared_start: u8;
    static __supervisor_shared_end: u8;
    static __supervisor_data_start: u8;
    static __supervisor_data_end: u8;
}

/* place a memory barrier that ensures all RAM and MMIO read and write operations
complete in the eyes of other CPU cores before the barrier is encountered */
#[inline(always)]
pub fn barrier()
{
    unsafe
    {
        asm!("fence iorw, iorw" :::: "volatile");
    }
}

/* allowed physical memory access permissions */
pub enum AccessPermissions
{
    Read,
    ReadWrite,
    ReadExecute,
    NoAccess
}

/* there are a maximum number of physical memory regions */
const PHYS_PMP_MAX_REGIONS: usize = 15;
/* PMP access flags */
const PHYS_PMP_READ: usize  = 1 << 0;
const PHYS_PMP_WRITE: usize = 1 << 1;
const PHYS_PMP_EXEC: usize  = 1 << 2;
const PHYS_PMP_TOR: usize   = 1 << 3;

/* each CPU has a fix memory overhead, allocated during boot */
static PHYS_MEM_PER_CPU: usize = 1 << 18; /* 256KB. see ../asm/const.s */

/* standardize types for passing around physical RAM addresses */
pub type PhysMemBase = usize;
pub type PhysMemEnd  = usize;
pub type PhysMemSize = usize;

/* describe a physical RAM area using its start address and size */
pub struct RAMArea
{
    pub base: PhysMemBase,
    pub size: PhysMemSize
}

/* allow the higher level kernel to iterate over physical RAM, adding available blocks to its
allocator pool and skipping the kernel's footprint of code, data and boot payload */
pub struct RAMAreaIter
{
    total_area: RAMArea, /* describes the entire physical RAM block */
    kernel_area: RAMArea, /* describes RAM reserved by the kernel */
    pos: PhysMemBase /* current possition of the iterator into the total_area block */
}

impl Iterator for RAMAreaIter
{
    type Item = RAMArea;

    fn next(&mut self) -> Option<RAMArea>
    {
        /* if we're in the kernel area then round us up to the end of the kernel area */
        if self.pos >= self.kernel_area.base && self.pos < self.kernel_area.base + self.kernel_area.size as PhysMemBase
        {
            self.pos = self.kernel_area.base + self.kernel_area.size as PhysMemBase;
        }

        /* catch the iterator escaping the physical RAM area */
        if self.pos < self.total_area.base || self.pos >= self.total_area.base + self.total_area.size as PhysMemBase
        {
            return None;
        }

        /* determine whether we're outside a kernel area */
        if self.pos < self.kernel_area.base
        {
            /* round up from wherever we are to the kernel area base */
            let area = RAMArea
            {
                base: self.pos,
                size: (self.kernel_area.base - self.pos) as PhysMemSize
            };
            /* skip to the end of the kernel area */
            self.pos = self.kernel_area.base + self.kernel_area.size as PhysMemBase;
            return Some(area);
        }

        if self.pos >= self.kernel_area.base + self.kernel_area.size as PhysMemBase
        {
            /* we're clear of the kernel round up to end of ram */
            let area = RAMArea
            {
                base: self.pos,
                size: (self.kernel_area.base - self.pos) as PhysMemSize
            };
            self.pos = self.kernel_area.base + self.kernel_area.size as PhysMemBase;
            return Some(area);
        }

        /* we shouldn't fall through to here? */
        return None;
    }
}

/* obtain available physical memory details from system device tree. this assumes RISC-V systems have a single
   block of physical RAM. If this changes, then we need to add support for that. break up this block of physical RAM
   into one or more areas, skipping any physical RAM being used to store for the kernel, its data structures
   and boot payload to ensure this memory isn't reused for allocations.
=> device_tree_buf = device tree to parse
<= iterator that describes the available blocks of physical RAM, or None for failure */
pub fn available_ram(device_tree_buf: &u8) -> Option<RAMAreaIter>
{
    /* at the end of the kernel footprint is the per-cpu heaps in one long contiguous block.
    take this into account so the memory isn't reused for other allocations */
    let cpu_count = match devicetree::get_cpu_count(device_tree_buf)
    {
        Some(c) => c,
        None => return None
    };

    /* we'll assume the kernel, data, code, peer-CPU heaps, and its boot payload are in a contiguous block of physical RAM */
    let (phys_kernel_start, phys_kernel_end) = kernel_footprint(cpu_count);
    let phys_kernel_size = (phys_kernel_end - phys_kernel_start) as PhysMemSize;

    /* assumes RISC-V systems sport a single block of physical RAM for software use */
    let all_phys_ram = match devicetree::get_ram_area(device_tree_buf)
    {
        Some(a) => a,
        None => return None

    };

    /* return an iterator the higher level kernel can run through. this cuts the physical RAM
    block up into sections that do not contain the kernel footprint */
    return Some(RAMAreaIter
    {
        pos: all_phys_ram.base,
        total_area: all_phys_ram,
        kernel_area: RAMArea
        {
            base: phys_kernel_start,
            size: phys_kernel_size
        }
    });
}

/* return the (start address, end address) of the shared supervisor kernel code in physical memory.
shared in that there is code common to the supervisor and kernel that can be shared. in effect,
this shared code appears in the supervisor's read-only code region but can be used by the hypervisor, too. */
pub fn builtin_supervisor_code() -> (PhysMemBase, PhysMemEnd)
{
    /* derived from the .sshared linker section */
    let supervisor_start: PhysMemBase = unsafe { transmute(&__supervisor_shared_start) };
    let supervisor_end: PhysMemEnd = unsafe { transmute(&__supervisor_shared_end) };
    return (supervisor_start, supervisor_end);
}

/* return the (start address, end address) of the builtin supervisor's private static read-write data
in physical memory */
pub fn builtin_supervisor_data() -> (PhysMemBase, PhysMemEnd)
{
    /* derived from the .sdata linker section */
    let supervisor_start: PhysMemBase = unsafe { transmute(&__supervisor_data_start) };
    let supervisor_end: PhysMemEnd = unsafe { transmute(&__supervisor_data_end) };
    return (supervisor_start, supervisor_end);
}

/* return the (start address, end address) of the whole kernel's code and data in physical memory,
including the builtin supervisor and fixed per-CPU core private memory areas
=> cpu_count = number of CPU cores
<= base and end addresses of the kernel footprint */
fn kernel_footprint(cpu_count: usize) -> (PhysMemBase, PhysMemEnd)
{
    /* derived from the .sshared linker section */
    let kernel_start: PhysMemBase = unsafe { transmute(&__kernel_start) };
    let kernel_end: PhysMemEnd = unsafe { transmute::<_, PhysMemEnd>(&__kernel_end) } + (cpu_count * PHYS_MEM_PER_CPU) as PhysMemEnd;
    return (kernel_start, kernel_end);
}

/* create a per-CPU physical memory region and apply access permissions to it. if the region already exists, overwrite it.
each region is a RISC-V physical memory protection (PMP) area. we pair up PMP addresses in TOR (top of range) mode. eg, region 0
uses pmp0cfg and pmp1cfg in pmpcfg0 for start and end, region 1 uses pmp1cfg and pmp2cfg in pmpcfg0.
   => regionid = ID number of the region to create or update, from 0 to PHYS_PMP_MAX_REGIONS (typically 8)
      base, end = start and end addresses of region
      access = access permissions for the region
   <= true for success, or false for failure */
pub fn protect(regionid: usize, base: usize, end: usize, access: AccessPermissions) -> bool
{
    if regionid > PHYS_PMP_MAX_REGIONS { return false; }

    let accessbits = PHYS_PMP_TOR | match access
    {
        AccessPermissions::Read => PHYS_PMP_READ,
        AccessPermissions::ReadWrite => PHYS_PMP_READ | PHYS_PMP_WRITE,
        AccessPermissions::ReadExecute => PHYS_PMP_READ | PHYS_PMP_EXEC,
        AccessPermissions::NoAccess => 0
    };

    /* select the appropriate pmpcfg register and bits from the region ID
       if we're on RV32 then there are 4 PMP regions (0-3, 4-7 etc) per 32-bit configuration word.
       if we're on RV64 then there are 8 PMP regions (0-7, 7-15) per 64-bit configuration word.

       pmpcfg_reg = N, as in: alter control register pmpcfgN to manipulate the given region
       shift = number of bits to shift left to access region in the pmpcfgN control register */
    let (pmpcfg_reg, shift) = if cfg!(target_os = "riscv32")
    {
        /* divide the region ID by 4 (shift right twice) to convert regions 0-3 to pmpcfg0, 4-7 to pmpcfg1 etc
           then calculate shift position of the region ID in the resulting pmpcfgN register
           (by multiplying by 8 or shifting left 3) */
        (regionid >> 2, (regionid - ((regionid >> 2) << 2)) << 3)
    }
    else /* assumes RV128 isn't available yet */
    {
        /* divide the region ID by 8 (shift right thrice) then multiply by 2 (shift left once) to
           select pmpcfg0 or 2. then calculate shift offset into the selected register */
        ((regionid >> 3) << 1, (regionid - ((regionid >> 3) << 3)) << 3)
    };

    /* only update the access bits for the end address, leaving the base access bits at zero.
    according to the specification, only the end address access bits are checked */
    let mask = 0xff << shift;
    let cfgbits = read_pmpcfg(pmpcfg_reg) & !mask;
    write_pmpcfg(pmpcfg_reg, cfgbits | (accessbits << shift));

    /* program in the base and end addesses. shift left 1 to multiply by two.
    there are a pair of PMP addresses per region: the base and the end address */
    write_pmpaddr(regionid << 1, base);
    write_pmpaddr((regionid << 1) + 1, end);

    return true;
}

/* read_pmpcfg (32-bit)
   Read the 32-bit value of the given PMP configuration register (pmpcfg0-3)
   => register = selects N out of pmpcfgN, where N = 0 to 3
   <= value of the CSR, or 0 for can't read. Warning: this fails silently, therefore */
#[cfg(target_arch = "riscv32")]
fn read_pmpcfg(register: usize) -> usize
{
    match register
    {
        0 => read_csr!(pmpcfg0),
        1 => read_csr!(pmpcfg1),
        2 => read_csr!(pmpcfg2),
        3 => read_csr!(pmpcfg3),
        _ => 0
    }
}

/* read_pmpcfg (64-bit)
   Read the 64-bit value of the given PMP configuration register (pmpcfg0 or 2)
   => register = selects N out of pmpcfgN, where N = 0 or 2
   <= value of the CSR, or 0 for can't read. Warning: this fails silently, therefore */
#[cfg(target_arch = "riscv64")]
fn read_pmpcfg(register: usize) -> usize
{
    /* we must conditionally compile this because pmpcfg1 and pmpcfg3 aren't defined for riscv64 */
    match register
    {
        0 => read_csr!(pmpcfg0),
        2 => read_csr!(pmpcfg2),
        _ => 0
    }
}

/* write_pmpcfg (32-bit)
   Write value to the given PMP configuration register (pmpcfg0-3). Warning: silently fails
   => register = selects N out of pmpcfgN, where N = 0 to 3
      value = 32-bit value to write */
#[cfg(target_arch = "riscv32")]
fn write_pmpcfg32(register: usize, value: usize)
{
    match register
    {
        0 => write_csr!(pmpcfg0, value),
        1 => write_csr!(pmpcfg1, value),
        2 => write_csr!(pmpcfg2, value),
        3 => write_csr!(pmpcfg3, value),
        _ => ()
    };
}

/* write_pmpcfg (64-bit)
   Write 64-bit value to the given PMP configuration register (pmpcfg0 or 2). Warning: silently fails
   => register = selects N out of pmpcfgN, where N = 0 or 2
      value = 32-bit value to write */
#[cfg(target_arch = "riscv64")]
fn write_pmpcfg(register: usize, value: usize)
{
    /* we must conditionally compile this because pmpcfg1 and pmpcfg3 aren't defined for riscv64 */
    match register
    {
        0 => write_csr!(pmpcfg0, value),
        2 => write_csr!(pmpcfg2, value),
        _ => ()
    };
}

/* write value to the given PMP address register 0-15 (pmpaddr0-15). warning: silently fails */
fn write_pmpaddr(register: usize, value: usize)
{
    match register
    {
        0 => write_csr!(pmpaddr0, value),
        1 => write_csr!(pmpaddr1, value),
        2 => write_csr!(pmpaddr2, value),
        3 => write_csr!(pmpaddr3, value),
        4 => write_csr!(pmpaddr4, value),
        5 => write_csr!(pmpaddr5, value),
        6 => write_csr!(pmpaddr6, value),
        7 => write_csr!(pmpaddr7, value),
        8 => write_csr!(pmpaddr8, value),
        9 => write_csr!(pmpaddr9, value),
        10 => write_csr!(pmpaddr10, value),
        11 => write_csr!(pmpaddr11, value),
        12 => write_csr!(pmpaddr12, value),
        13 => write_csr!(pmpaddr13, value),
        14 => write_csr!(pmpaddr14, value),
        15 => write_csr!(pmpaddr15, value),
        _ => ()
    };
}
<|endoftext|>


<commit_before>#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
#![allow(dead_code)]

use std::os::raw::{c_void, c_char, c_int};

pub const RTLD_LAZY: c_int = 0x001;
pub const RTLD_NOW: c_int = 0x002;

#[link="dl"]
extern {
    pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
    pub fn dlerror() -> *mut c_char;
    pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
    pub fn dlclose(handle: *mut c_void) -> c_int;
}
<commit_msg>Fix warning (#880)<commit_after>#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
#![allow(dead_code)]

use std::os::raw::{c_void, c_char, c_int};

pub const RTLD_LAZY: c_int = 0x001;
pub const RTLD_NOW: c_int = 0x002;

#[link(name ="dl")]
extern {
    pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
    pub fn dlerror() -> *mut c_char;
    pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
    pub fn dlclose(handle: *mut c_void) -> c_int;
}
<|endoftext|>


<commit_before>// Function names are formatted differently in old versions of GDB
// min-gdb-version: 10.1

// compile-flags:-g

// === GDB TESTS ===================================================================================

// Top-level function
// gdb-command:info functions -q function_names::main
// gdb-check:[...]static fn function_names::main();
// gdb-command:info functions -q function_names::generic_func<*
// gdb-check:[...]static fn function_names::generic_func(i32) -> i32;

// Implementations
// gdb-command:info functions -q function_names::.*::impl_function.*
// gdb-check:[...]static fn function_names::GenericStruct<T1,T2>::impl_function();
// gdb-check:[...]static fn function_names::Mod1::TestStruct2::impl_function();
// gdb-check:[...]static fn function_names::TestStruct1::impl_function();

// Trait implementations
// gdb-command:info functions -q function_names::.*::trait_function.*
// gdb-check:[...]static fn <function_names::GenericStruct<T,i32> as function_names::TestTrait1>::trait_function();
// gdb-check:[...]static fn <function_names::GenericStruct<[T; N],f32> as function_names::TestTrait1>::trait_function();
// gdb-check:[...]static fn <function_names::Mod1::TestStruct2 as function_names::Mod1::TestTrait2>::trait_function();
// gdb-check:[...]static fn <function_names::TestStruct1 as function_names::TestTrait1>::trait_function();

// Closure
// gdb-command:info functions -q function_names::.*::{{closure.*
// gdb-check:[...]static fn function_names::GenericStruct<T1,T2>::impl_function::{{closure}}(*mut function_names::{impl#2}::impl_function::{closure#0});
// gdb-check:[...]static fn function_names::generic_func::{{closure}}(*mut function_names::generic_func::{closure#0});
// gdb-check:[...]static fn function_names::main::{{closure}}(*mut function_names::main::{closure#0});

// Generator
// Generators don't seem to appear in GDB's symbol table.

// Const generic parameter
// gdb-command:info functions -q function_names::const_generic_fn.*
// gdb-check:[...]static fn function_names::const_generic_fn_bool();
// gdb-check:[...]static fn function_names::const_generic_fn_non_int();
// gdb-check:[...]static fn function_names::const_generic_fn_signed_int();
// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int();

// === CDB TESTS ===================================================================================

// Top-level function
// cdb-command:x a!function_names::main
// cdb-check:[...] a!function_names::main (void)
// cdb-command:x a!function_names::generic_func<*
// cdb-check:[...] a!function_names::generic_func<i32> (int)

// Implementations
// cdb-command:x a!function_names::*::impl_function*
// cdb-check:[...] a!function_names::Mod1::TestStruct2::impl_function (void)
// cdb-check:[...] a!function_names::TestStruct1::impl_function (void)
// cdb-check:[...] a!function_names::GenericStruct<i32,i32>::impl_function<i32,i32> (void)

// Trait implementations
// cdb-command:x a!function_names::*::trait_function*
// cdb-check:[...] a!function_names::impl$3::trait_function<i32> (void)
// cdb-check:[...] a!function_names::impl$6::trait_function<i32,1> (void)
// cdb-check:[...] a!function_names::impl$1::trait_function (void)
// cdb-check:[...] a!function_names::impl$5::trait_function3<function_names::TestStruct1> (void)
// cdb-check:[...] a!function_names::Mod1::impl$1::trait_function (void)

// Closure
// cdb-command:x a!function_names::*::closure*
// cdb-check:[...] a!function_names::impl$2::impl_function::closure$0<i32,i32> (void)
// cdb-check:[...] a!function_names::main::closure$0 (void)
// cdb-check:[...] a!function_names::generic_func::closure$0<i32> (void)

// Generator
// cdb-command:x a!function_names::*::generator*
// cdb-check:[...] a!function_names::main::generator$1 (void)

// Const generic parameter
// cdb-command:x a!function_names::const_generic_fn*
// cdb-check:[...] a!function_names::const_generic_fn_bool<false> (void)
// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$fe3cfa0214ac55c7> (void)
// cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void)
// cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void)

#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#![feature(adt_const_params, generators, generator_trait)]
#![allow(incomplete_features)]

use Mod1::TestTrait2;
use std::ops::Generator;
use std::pin::Pin;

fn main() {
    // Implementations
    TestStruct1::impl_function();
    Mod1::TestStruct2::impl_function();
    GenericStruct::<i32, i32>::impl_function();

    // Trait implementations
    TestStruct1::trait_function();
    Mod1::TestStruct2::trait_function();
    GenericStruct::<i32, i32>::trait_function();
    GenericStruct::<[i32; 1], f32>::trait_function();
    GenericStruct::<TestStruct1, usize>::trait_function3();

    // Generic function
    let _ = generic_func(42);

    // Closure
    let closure = || { TestStruct1 };
    closure();

    // Generator
    let mut generator = || { yield; return; };
    Pin::new(&mut generator).resume(());

    // Const generic functions
    const_generic_fn_bool::<false>();
    const_generic_fn_non_int::<{()}>();
    const_generic_fn_signed_int::<-7>();
    const_generic_fn_unsigned_int::<14>();
}

struct TestStruct1;
trait TestTrait1 {
    fn trait_function();
}

// Implementation
impl TestStruct1 {
    pub fn impl_function() {}
}

// Implementation for a trait
impl TestTrait1 for TestStruct1 {
    fn trait_function() {}
}

// Implementation and implementation within a mod
mod Mod1 {
    pub struct TestStruct2;
    pub trait TestTrait2 {
        fn trait_function();
    }

    impl TestStruct2 {
        pub fn impl_function() {}
    }

    impl TestTrait2 for TestStruct2 {
        fn trait_function() {}
    }
}

struct GenericStruct<T1, T2>(std::marker::PhantomData<(T1, T2)>);

// Generic implementation
impl<T1, T2> GenericStruct<T1, T2> {
    pub fn impl_function() {
        // Closure in a generic implementation
        let closure = || { TestStruct1 };
        closure();
    }
}

// Generic trait implementation
impl<T> TestTrait1 for GenericStruct<T, i32> {
    fn trait_function() {}
}

// Implementation based on associated type
trait TestTrait3 {
    type AssocType;
    fn trait_function3();
}
impl TestTrait3 for TestStruct1 {
    type AssocType = usize;
    fn trait_function3() {}
}
impl<T: TestTrait3> TestTrait3 for GenericStruct<T, T::AssocType> {
    type AssocType = T::AssocType;
    fn trait_function3() {}
}

// Generic trait implementation with const generics
impl<T, const N: usize> TestTrait1 for GenericStruct<[T; N], f32> {
    fn trait_function() {}
}

// Generic function
fn generic_func<T>(value: T) -> T {
    // Closure in a generic function
    let closure = || { TestStruct1 };
    closure();

    value
}

fn const_generic_fn_bool<const C: bool>() {}
fn const_generic_fn_non_int<const C: ()>() {}
fn const_generic_fn_signed_int<const C: i64>() {}
fn const_generic_fn_unsigned_int<const C: u32>() {}
<commit_msg>Fix function-names test for GDB 10.1<commit_after>// Function names are formatted differently in old versions of GDB
// min-gdb-version: 10.1

// compile-flags:-g

// === GDB TESTS ===================================================================================

// Top-level function
// gdb-command:info functions -q function_names::main
// gdb-check:[...]static fn function_names::main();
// gdb-command:info functions -q function_names::generic_func<*
// gdb-check:[...]static fn function_names::generic_func<i32>(i32) -> i32;

// Implementations
// gdb-command:info functions -q function_names::.*::impl_function.*
// gdb-check:[...]static fn function_names::GenericStruct<i32, i32>::impl_function<i32, i32>();
// gdb-check:[...]static fn function_names::Mod1::TestStruct2::impl_function();
// gdb-check:[...]static fn function_names::TestStruct1::impl_function();

// Trait implementations
// gdb-command:info functions -q function_names::.*::trait_function.*
// gdb-check:[...]static fn function_names::Mod1::{impl#1}::trait_function();
// gdb-check:[...]static fn function_names::{impl#1}::trait_function();
// gdb-check:[...]static fn function_names::{impl#3}::trait_function<i32>();
// gdb-check:[...]static fn function_names::{impl#5}::trait_function3<function_names::TestStruct1>();
// gdb-check:[...]static fn function_names::{impl#6}::trait_function<i32, 1>();

// Closure
// gdb-command:info functions -q function_names::.*::{closure.*
// gdb-check:[...]static fn function_names::generic_func::{closure#0}<i32>(*mut function_names::generic_func::{closure#0});
// gdb-check:[...]static fn function_names::main::{closure#0}(*mut function_names::main::{closure#0});
// gdb-check:[...]static fn function_names::{impl#2}::impl_function::{closure#0}<i32, i32>(*mut function_names::{impl#2}::impl_function::{closure#0});

// Generator
// Generators don't seem to appear in GDB's symbol table.

// Const generic parameter
// gdb-command:info functions -q function_names::const_generic_fn.*
// gdb-check:[...]static fn function_names::const_generic_fn_bool<false>();
// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#fe3cfa0214ac55c7}>();
// gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>();
// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>();

// === CDB TESTS ===================================================================================

// Top-level function
// cdb-command:x a!function_names::main
// cdb-check:[...] a!function_names::main (void)
// cdb-command:x a!function_names::generic_func<*
// cdb-check:[...] a!function_names::generic_func<i32> (int)

// Implementations
// cdb-command:x a!function_names::*::impl_function*
// cdb-check:[...] a!function_names::Mod1::TestStruct2::impl_function (void)
// cdb-check:[...] a!function_names::TestStruct1::impl_function (void)
// cdb-check:[...] a!function_names::GenericStruct<i32,i32>::impl_function<i32,i32> (void)

// Trait implementations
// cdb-command:x a!function_names::*::trait_function*
// cdb-check:[...] a!function_names::impl$3::trait_function<i32> (void)
// cdb-check:[...] a!function_names::impl$6::trait_function<i32,1> (void)
// cdb-check:[...] a!function_names::impl$1::trait_function (void)
// cdb-check:[...] a!function_names::impl$5::trait_function3<function_names::TestStruct1> (void)
// cdb-check:[...] a!function_names::Mod1::impl$1::trait_function (void)

// Closure
// cdb-command:x a!function_names::*::closure*
// cdb-check:[...] a!function_names::impl$2::impl_function::closure$0<i32,i32> (void)
// cdb-check:[...] a!function_names::main::closure$0 (void)
// cdb-check:[...] a!function_names::generic_func::closure$0<i32> (void)

// Generator
// cdb-command:x a!function_names::*::generator*
// cdb-check:[...] a!function_names::main::generator$1 (void)

// Const generic parameter
// cdb-command:x a!function_names::const_generic_fn*
// cdb-check:[...] a!function_names::const_generic_fn_bool<false> (void)
// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$fe3cfa0214ac55c7> (void)
// cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void)
// cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void)

#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#![feature(adt_const_params, generators, generator_trait)]
#![allow(incomplete_features)]

use Mod1::TestTrait2;
use std::ops::Generator;
use std::pin::Pin;

fn main() {
    // Implementations
    TestStruct1::impl_function();
    Mod1::TestStruct2::impl_function();
    GenericStruct::<i32, i32>::impl_function();

    // Trait implementations
    TestStruct1::trait_function();
    Mod1::TestStruct2::trait_function();
    GenericStruct::<i32, i32>::trait_function();
    GenericStruct::<[i32; 1], f32>::trait_function();
    GenericStruct::<TestStruct1, usize>::trait_function3();

    // Generic function
    let _ = generic_func(42i32);

    // Closure
    let closure = || { TestStruct1 };
    closure();

    // Generator
    let mut generator = || { yield; return; };
    Pin::new(&mut generator).resume(());

    // Const generic functions
    const_generic_fn_bool::<false>();
    const_generic_fn_non_int::<{()}>();
    const_generic_fn_signed_int::<-7>();
    const_generic_fn_unsigned_int::<14>();
}

struct TestStruct1;
trait TestTrait1 {
    fn trait_function();
}

// Implementation
impl TestStruct1 {
    pub fn impl_function() {}
}

// Implementation for a trait
impl TestTrait1 for TestStruct1 {
    fn trait_function() {}
}

// Implementation and implementation within a mod
mod Mod1 {
    pub struct TestStruct2;
    pub trait TestTrait2 {
        fn trait_function();
    }

    impl TestStruct2 {
        pub fn impl_function() {}
    }

    impl TestTrait2 for TestStruct2 {
        fn trait_function() {}
    }
}

struct GenericStruct<T1, T2>(std::marker::PhantomData<(T1, T2)>);

// Generic implementation
impl<T1, T2> GenericStruct<T1, T2> {
    pub fn impl_function() {
        // Closure in a generic implementation
        let closure = || { TestStruct1 };
        closure();
    }
}

// Generic trait implementation
impl<T> TestTrait1 for GenericStruct<T, i32> {
    fn trait_function() {}
}

// Implementation based on associated type
trait TestTrait3 {
    type AssocType;
    fn trait_function3();
}
impl TestTrait3 for TestStruct1 {
    type AssocType = usize;
    fn trait_function3() {}
}
impl<T: TestTrait3> TestTrait3 for GenericStruct<T, T::AssocType> {
    type AssocType = T::AssocType;
    fn trait_function3() {}
}

// Generic trait implementation with const generics
impl<T, const N: usize> TestTrait1 for GenericStruct<[T; N], f32> {
    fn trait_function() {}
}

// Generic function
fn generic_func<T>(value: T) -> T {
    // Closure in a generic function
    let closure = || { TestStruct1 };
    closure();

    value
}

fn const_generic_fn_bool<const C: bool>() {}
fn const_generic_fn_non_int<const C: ()>() {}
fn const_generic_fn_signed_int<const C: i64>() {}
fn const_generic_fn_unsigned_int<const C: u32>() {}
<|endoftext|>


<commit_before>
// xfail-test

fn altsimple(any x) {
  match type (f) {
    case (int i) { print("int"); }
    case (str s) { print("str"); }
  }
}

pub fn main() {
  altsimple(5);
  altsimple("asdfasdfsDF");
}
<commit_msg>Remove test for any type -> match type, which doesn't seem to exist anymore<commit_after><|endoftext|>


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

use crate::streaming_client::Epoch;
use async_trait::async_trait;
use diem_crypto::{ed25519::Ed25519PrivateKey, HashValue, PrivateKey, SigningKey, Uniform};
use diem_data_client::{
    AdvertisedData, DataClientPayload, DataClientResponse, DiemDataClient, GlobalDataSummary,
    OptimalChunkSizes, ResponseError,
};
use diem_types::{
    account_address::AccountAddress,
    account_state_blob::AccountStatesChunkWithProof,
    block_info::BlockInfo,
    chain_id::ChainId,
    ledger_info::{LedgerInfo, LedgerInfoWithSignatures},
    proof::SparseMerkleRangeProof,
    transaction::{
        default_protocol::TransactionOutputListWithProof, RawTransaction, Script,
        SignedTransaction, Transaction, TransactionListWithProof, TransactionOutput,
        TransactionPayload, TransactionStatus,
    },
    write_set::WriteSet,
};
use rand::{rngs::OsRng, RngCore};
use std::{collections::BTreeMap, thread, time::Duration};
use storage_service_types::CompleteDataRange;

/// The number of accounts held at any version
pub const TOTAL_NUM_ACCOUNTS: u64 = 2000;

/// Test constants for advertised data
pub const MAX_RESPONSE_ID: u64 = 100000;
pub const MIN_ADVERTISED_ACCOUNTS: u64 = 9500;
pub const MAX_ADVERTISED_ACCOUNTS: u64 = 10000;
pub const MIN_ADVERTISED_EPOCH: u64 = 100;
pub const MAX_ADVERTISED_EPOCH: u64 = 1000;
pub const MIN_ADVERTISED_TRANSACTION: u64 = 10;
pub const MAX_ADVERTISED_TRANSACTION: u64 = 10000;
pub const MIN_ADVERTISED_TRANSACTION_OUTPUT: u64 = 5000;
pub const MAX_ADVERTISED_TRANSACTION_OUTPUT: u64 = 10000;

/// Test timeout constant
pub const MAX_NOTIFICATION_TIMEOUT_SECS: u64 = 5;

/// A simple mock of the Diem Data Client
#[derive(Clone)]
pub struct MockDiemDataClient {}

impl MockDiemDataClient {
    fn emulate_network_latencies(&self) {
        // Sleep for 100 ms
        thread::sleep(Duration::from_millis(100));

        // Sleep an additional amount of time (< 0.4 second) to emulate variance
        thread::sleep(Duration::from_millis(create_random_u64(400)));
    }
}

#[async_trait]
impl DiemDataClient for MockDiemDataClient {
    async fn get_account_states_with_proof(
        &self,
        _version: u64,
        start_index: u64,
        end_index: u64,
    ) -> Result<DataClientResponse, diem_data_client::Error> {
        self.emulate_network_latencies();

        // Create epoch ending ledger infos according to the requested epochs
        let mut account_blobs = vec![];
        for _ in start_index..=end_index {
            account_blobs.push((HashValue::random(), vec![].into()));
        }

        // Create an account states chunk with proof
        let accounts_with_proofs = AccountStatesChunkWithProof {
            first_index: start_index,
            last_index: end_index,
            first_key: HashValue::random(),
            last_key: HashValue::random(),
            account_blobs,
            proof: SparseMerkleRangeProof::new(vec![]),
        };
        let response_payload = DataClientPayload::AccountStatesWithProof(accounts_with_proofs);

        // Return the chunk
        Ok(create_data_client_response(response_payload))
    }

    async fn get_epoch_ending_ledger_infos(
        &self,
        start_epoch: u64,
        end_epoch: u64,
    ) -> Result<DataClientResponse, diem_data_client::Error> {
        self.emulate_network_latencies();

        // Create epoch ending ledger infos according to the requested epochs
        let mut epoch_ending_ledger_infos = vec![];
        for epoch in start_epoch..=end_epoch {
            epoch_ending_ledger_infos.push(create_ledger_info(epoch));
        }
        let response_payload = DataClientPayload::EpochEndingLedgerInfos(epoch_ending_ledger_infos);

        // Return the ledger infos
        Ok(create_data_client_response(response_payload))
    }

    fn get_global_data_summary(&self) -> Result<DataClientResponse, diem_data_client::Error> {
        // Create a random set of optimal chunk sizes to emulate changing environments
        let optimal_chunk_sizes = OptimalChunkSizes {
            account_states_chunk_size: create_non_zero_random_u64(100),
            epoch_chunk_size: create_non_zero_random_u64(100),
            transaction_chunk_size: create_non_zero_random_u64(2000),
            transaction_output_chunk_size: create_non_zero_random_u64(100),
        };

        // Create a global data summary with a fixed set of data
        let advertised_data = AdvertisedData {
            account_states: vec![CompleteDataRange::new(
                MIN_ADVERTISED_ACCOUNTS,
                MAX_ADVERTISED_ACCOUNTS,
            )],
            epoch_ending_ledger_infos: vec![CompleteDataRange::new(
                MIN_ADVERTISED_EPOCH,
                MAX_ADVERTISED_EPOCH,
            )],
            synced_ledger_infos: vec![],
            transactions: vec![CompleteDataRange::new(
                MIN_ADVERTISED_TRANSACTION,
                MAX_ADVERTISED_TRANSACTION,
            )],
            transaction_outputs: vec![CompleteDataRange::new(
                MIN_ADVERTISED_TRANSACTION_OUTPUT,
                MAX_ADVERTISED_TRANSACTION_OUTPUT,
            )],
        };
        let response_payload = DataClientPayload::GlobalDataSummary(GlobalDataSummary {
            advertised_data,
            optimal_chunk_sizes,
        });

        // Return the global data summary
        Ok(create_data_client_response(response_payload))
    }

    async fn get_number_of_account_states(
        &self,
        _version: u64,
    ) -> Result<DataClientResponse, diem_data_client::Error> {
        Ok(create_data_client_response(
            DataClientPayload::NumberOfAccountStates(TOTAL_NUM_ACCOUNTS),
        ))
    }

    async fn get_transaction_outputs_with_proof(
        &self,
        _proof_version: u64,
        start_version: u64,
        end_version: u64,
    ) -> Result<DataClientResponse, diem_data_client::Error> {
        self.emulate_network_latencies();

        // Create the requested transactions and transaction outputs
        let mut transactions_and_outputs = vec![];
        for _ in start_version..=end_version {
            transactions_and_outputs.push((create_transaction(), create_transaction_output()));
        }

        // Create a transaction output list with an empty proof
        let mut output_list_with_proof = TransactionOutputListWithProof::new_empty();
        output_list_with_proof.first_transaction_output_version = Some(start_version);
        output_list_with_proof.transactions_and_outputs = transactions_and_outputs;
        let response_payload =
            DataClientPayload::TransactionOutputsWithProof(output_list_with_proof);

        // Return the transaction output list with proofs
        Ok(create_data_client_response(response_payload))
    }

    async fn get_transactions_with_proof(
        &self,
        _proof_version: u64,
        start_version: u64,
        end_version: u64,
        include_events: bool,
    ) -> Result<DataClientResponse, diem_data_client::Error> {
        self.emulate_network_latencies();

        // Include events if required
        let events = if include_events { Some(vec![]) } else { None };

        // Create the requested transactions
        let mut transactions = vec![];
        for _ in start_version..=end_version {
            transactions.push(create_transaction());
        }

        // Create a transaction list with an empty proof
        let mut transaction_list_with_proof = TransactionListWithProof::new_empty();
        transaction_list_with_proof.first_transaction_version = Some(start_version);
        transaction_list_with_proof.events = events;
        transaction_list_with_proof.transactions = transactions;
        let response_payload =
            DataClientPayload::TransactionsWithProof(transaction_list_with_proof);

        // Return the transaction list with proofs
        Ok(create_data_client_response(response_payload))
    }

    async fn notify_bad_response(
        &self,
        _response_id: u64,
        _response_error: ResponseError,
    ) -> Result<(), diem_data_client::Error> {
        unimplemented!();
    }
}

/// Creates a data client response using a specified payload and random id
pub fn create_data_client_response(response_payload: DataClientPayload) -> DataClientResponse {
    let response_id = create_random_u64(MAX_RESPONSE_ID);
    DataClientResponse {
        response_id,
        response_payload,
    }
}

/// Creates a ledger info with the given epoch
pub fn create_ledger_info(epoch: Epoch) -> LedgerInfoWithSignatures {
    let block_info = BlockInfo::new(epoch, 0, HashValue::zero(), HashValue::zero(), 0, 0, None);
    LedgerInfoWithSignatures::new(
        LedgerInfo::new(block_info, HashValue::zero()),
        BTreeMap::new(),
    )
}

/// Creates a simple test transaction
fn create_transaction() -> Transaction {
    let private_key = Ed25519PrivateKey::generate_for_testing();
    let public_key = private_key.public_key();

    let transaction_payload = TransactionPayload::Script(Script::new(vec![], vec![], vec![]));
    let raw_transaction = RawTransaction::new(
        AccountAddress::random(),
        0,
        transaction_payload,
        0,
        0,
        "".into(),
        0,
        ChainId::new(10),
    );
    let signature = private_key.sign(&raw_transaction);
    let signed_transaction = SignedTransaction::new(raw_transaction, public_key, signature);

    Transaction::UserTransaction(signed_transaction)
}

/// Creates an empty transaction output
fn create_transaction_output() -> TransactionOutput {
    TransactionOutput::new(WriteSet::default(), vec![], 0, TransactionStatus::Retry)
}

/// Returns a random u64 with a value between 0 and `max_value` - 1 (inclusive).
fn create_random_u64(max_value: u64) -> u64 {
    let mut rng = OsRng;
    rng.next_u64() % max_value
}

/// Returns a random (but non-zero) u64 with a value between 1 and `max_value` - 1 (inclusive).
fn create_non_zero_random_u64(max_value: u64) -> u64 {
    create_random_u64(max_value - 1) + 1
}
<commit_msg>[state-sync] Use range random in state sync tests<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::streaming_client::Epoch;
use async_trait::async_trait;
use diem_crypto::{ed25519::Ed25519PrivateKey, HashValue, PrivateKey, SigningKey, Uniform};
use diem_data_client::{
    AdvertisedData, DataClientPayload, DataClientResponse, DiemDataClient, GlobalDataSummary,
    OptimalChunkSizes, ResponseError,
};
use diem_types::{
    account_address::AccountAddress,
    account_state_blob::AccountStatesChunkWithProof,
    block_info::BlockInfo,
    chain_id::ChainId,
    ledger_info::{LedgerInfo, LedgerInfoWithSignatures},
    proof::SparseMerkleRangeProof,
    transaction::{
        default_protocol::TransactionOutputListWithProof, RawTransaction, Script,
        SignedTransaction, Transaction, TransactionListWithProof, TransactionOutput,
        TransactionPayload, TransactionStatus,
    },
    write_set::WriteSet,
};
use rand::{rngs::OsRng, Rng};
use std::{collections::BTreeMap, thread, time::Duration};
use storage_service_types::CompleteDataRange;

/// The number of accounts held at any version
pub const TOTAL_NUM_ACCOUNTS: u64 = 2000;

/// Test constants for advertised data
pub const MAX_RESPONSE_ID: u64 = 100000;
pub const MIN_ADVERTISED_ACCOUNTS: u64 = 9500;
pub const MAX_ADVERTISED_ACCOUNTS: u64 = 10000;
pub const MIN_ADVERTISED_EPOCH: u64 = 100;
pub const MAX_ADVERTISED_EPOCH: u64 = 1000;
pub const MIN_ADVERTISED_TRANSACTION: u64 = 10;
pub const MAX_ADVERTISED_TRANSACTION: u64 = 10000;
pub const MIN_ADVERTISED_TRANSACTION_OUTPUT: u64 = 5000;
pub const MAX_ADVERTISED_TRANSACTION_OUTPUT: u64 = 10000;

/// Test timeout constant
pub const MAX_NOTIFICATION_TIMEOUT_SECS: u64 = 5;

/// A simple mock of the Diem Data Client
#[derive(Clone)]
pub struct MockDiemDataClient {}

impl MockDiemDataClient {
    fn emulate_network_latencies(&self) {
        // Sleep for 100 - 500 ms to emulate variance
        thread::sleep(Duration::from_millis(create_range_random_u64(100, 500)));
    }
}

#[async_trait]
impl DiemDataClient for MockDiemDataClient {
    async fn get_account_states_with_proof(
        &self,
        _version: u64,
        start_index: u64,
        end_index: u64,
    ) -> Result<DataClientResponse, diem_data_client::Error> {
        self.emulate_network_latencies();

        // Create epoch ending ledger infos according to the requested epochs
        let mut account_blobs = vec![];
        for _ in start_index..=end_index {
            account_blobs.push((HashValue::random(), vec![].into()));
        }

        // Create an account states chunk with proof
        let accounts_with_proofs = AccountStatesChunkWithProof {
            first_index: start_index,
            last_index: end_index,
            first_key: HashValue::random(),
            last_key: HashValue::random(),
            account_blobs,
            proof: SparseMerkleRangeProof::new(vec![]),
        };
        let response_payload = DataClientPayload::AccountStatesWithProof(accounts_with_proofs);

        // Return the chunk
        Ok(create_data_client_response(response_payload))
    }

    async fn get_epoch_ending_ledger_infos(
        &self,
        start_epoch: u64,
        end_epoch: u64,
    ) -> Result<DataClientResponse, diem_data_client::Error> {
        self.emulate_network_latencies();

        // Create epoch ending ledger infos according to the requested epochs
        let mut epoch_ending_ledger_infos = vec![];
        for epoch in start_epoch..=end_epoch {
            epoch_ending_ledger_infos.push(create_ledger_info(epoch));
        }
        let response_payload = DataClientPayload::EpochEndingLedgerInfos(epoch_ending_ledger_infos);

        // Return the ledger infos
        Ok(create_data_client_response(response_payload))
    }

    fn get_global_data_summary(&self) -> Result<DataClientResponse, diem_data_client::Error> {
        // Create a random set of optimal chunk sizes to emulate changing environments
        let optimal_chunk_sizes = OptimalChunkSizes {
            account_states_chunk_size: create_non_zero_random_u64(100),
            epoch_chunk_size: create_non_zero_random_u64(100),
            transaction_chunk_size: create_non_zero_random_u64(2000),
            transaction_output_chunk_size: create_non_zero_random_u64(100),
        };

        // Create a global data summary with a fixed set of data
        let advertised_data = AdvertisedData {
            account_states: vec![CompleteDataRange::new(
                MIN_ADVERTISED_ACCOUNTS,
                MAX_ADVERTISED_ACCOUNTS,
            )],
            epoch_ending_ledger_infos: vec![CompleteDataRange::new(
                MIN_ADVERTISED_EPOCH,
                MAX_ADVERTISED_EPOCH,
            )],
            synced_ledger_infos: vec![],
            transactions: vec![CompleteDataRange::new(
                MIN_ADVERTISED_TRANSACTION,
                MAX_ADVERTISED_TRANSACTION,
            )],
            transaction_outputs: vec![CompleteDataRange::new(
                MIN_ADVERTISED_TRANSACTION_OUTPUT,
                MAX_ADVERTISED_TRANSACTION_OUTPUT,
            )],
        };
        let response_payload = DataClientPayload::GlobalDataSummary(GlobalDataSummary {
            advertised_data,
            optimal_chunk_sizes,
        });

        // Return the global data summary
        Ok(create_data_client_response(response_payload))
    }

    async fn get_number_of_account_states(
        &self,
        _version: u64,
    ) -> Result<DataClientResponse, diem_data_client::Error> {
        Ok(create_data_client_response(
            DataClientPayload::NumberOfAccountStates(TOTAL_NUM_ACCOUNTS),
        ))
    }

    async fn get_transaction_outputs_with_proof(
        &self,
        _proof_version: u64,
        start_version: u64,
        end_version: u64,
    ) -> Result<DataClientResponse, diem_data_client::Error> {
        self.emulate_network_latencies();

        // Create the requested transactions and transaction outputs
        let mut transactions_and_outputs = vec![];
        for _ in start_version..=end_version {
            transactions_and_outputs.push((create_transaction(), create_transaction_output()));
        }

        // Create a transaction output list with an empty proof
        let mut output_list_with_proof = TransactionOutputListWithProof::new_empty();
        output_list_with_proof.first_transaction_output_version = Some(start_version);
        output_list_with_proof.transactions_and_outputs = transactions_and_outputs;
        let response_payload =
            DataClientPayload::TransactionOutputsWithProof(output_list_with_proof);

        // Return the transaction output list with proofs
        Ok(create_data_client_response(response_payload))
    }

    async fn get_transactions_with_proof(
        &self,
        _proof_version: u64,
        start_version: u64,
        end_version: u64,
        include_events: bool,
    ) -> Result<DataClientResponse, diem_data_client::Error> {
        self.emulate_network_latencies();

        // Include events if required
        let events = if include_events { Some(vec![]) } else { None };

        // Create the requested transactions
        let mut transactions = vec![];
        for _ in start_version..=end_version {
            transactions.push(create_transaction());
        }

        // Create a transaction list with an empty proof
        let mut transaction_list_with_proof = TransactionListWithProof::new_empty();
        transaction_list_with_proof.first_transaction_version = Some(start_version);
        transaction_list_with_proof.events = events;
        transaction_list_with_proof.transactions = transactions;
        let response_payload =
            DataClientPayload::TransactionsWithProof(transaction_list_with_proof);

        // Return the transaction list with proofs
        Ok(create_data_client_response(response_payload))
    }

    async fn notify_bad_response(
        &self,
        _response_id: u64,
        _response_error: ResponseError,
    ) -> Result<(), diem_data_client::Error> {
        unimplemented!();
    }
}

/// Creates a data client response using a specified payload and random id
pub fn create_data_client_response(response_payload: DataClientPayload) -> DataClientResponse {
    let response_id = create_random_u64(MAX_RESPONSE_ID);
    DataClientResponse {
        response_id,
        response_payload,
    }
}

/// Creates a ledger info with the given epoch
pub fn create_ledger_info(epoch: Epoch) -> LedgerInfoWithSignatures {
    let block_info = BlockInfo::new(epoch, 0, HashValue::zero(), HashValue::zero(), 0, 0, None);
    LedgerInfoWithSignatures::new(
        LedgerInfo::new(block_info, HashValue::zero()),
        BTreeMap::new(),
    )
}

/// Creates a simple test transaction
fn create_transaction() -> Transaction {
    let private_key = Ed25519PrivateKey::generate_for_testing();
    let public_key = private_key.public_key();

    let transaction_payload = TransactionPayload::Script(Script::new(vec![], vec![], vec![]));
    let raw_transaction = RawTransaction::new(
        AccountAddress::random(),
        0,
        transaction_payload,
        0,
        0,
        "".into(),
        0,
        ChainId::new(10),
    );
    let signature = private_key.sign(&raw_transaction);
    let signed_transaction = SignedTransaction::new(raw_transaction, public_key, signature);

    Transaction::UserTransaction(signed_transaction)
}

/// Creates an empty transaction output
fn create_transaction_output() -> TransactionOutput {
    TransactionOutput::new(WriteSet::default(), vec![], 0, TransactionStatus::Retry)
}

/// Returns a random u64 with a value between 0 and `max_value` - 1 (inclusive).
fn create_random_u64(max_value: u64) -> u64 {
    create_range_random_u64(0, max_value)
}

/// Returns a random (but non-zero) u64 with a value between 1 and `max_value` - 1 (inclusive).
fn create_non_zero_random_u64(max_value: u64) -> u64 {
    create_range_random_u64(1, max_value)
}

/// Returns a random u64 within the range, [min, max)
fn create_range_random_u64(min_value: u64, max_value: u64) -> u64 {
    let mut rng = OsRng;
    rng.gen_range(min_value..max_value)
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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
//
//     https://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.

// OCSP request is defined in
// https://tools.ietf.org/html/rfc6960#section-4.1
//
// OCSP over http is defined in
// https://tools.ietf.org/html/rfc2560#appendix-A.1

use crate::crypto::{CertificateChain, HashAlgorithm};
use crate::fetcher::Fetcher;
use crate::http::{HttpRequest, Method};
use crate::runtime::Runtime;
use anyhow::{anyhow, Error, Result};
use der_parser::{
    ber::{BerObject, BerObjectContent},
    oid,
    oid::Oid,
};
use serde::{Deserialize, Serialize};
use std::time::{Duration, SystemTime};
use tokio::sync::Mutex;
use x509_parser::{
    certificate::X509Certificate,
    extensions::{GeneralName, ParsedExtension},
};

fn create_ocsp_request(cert: &X509Certificate, issuer: &X509Certificate) -> Vec<u8> {
    let hash_algorithm = HashAlgorithm::Sha1;
    let issuer_name = issuer.tbs_certificate.subject.as_raw();
    let issuer_key = issuer
        .tbs_certificate
        .subject_pki
        .subject_public_key
        .data
        .as_ref();
    let issuer_key_hash = hash_algorithm.digest(issuer_key);
    let issuer_name_hash = hash_algorithm.digest(issuer_name);
    let serial_number = cert.tbs_certificate.raw_serial();
    // https://tools.ietf.org/html/rfc6960#section-4.1.1
    // CertID          ::=     SEQUENCE {
    //     hashAlgorithm       AlgorithmIdentifier,
    //     issuerNameHash      OCTET STRING, -- Hash of issuer's DN
    //     issuerKeyHash       OCTET STRING, -- Hash of issuer's public key
    //     serialNumber        CertificateSerialNumber }
    let cert_id = BerObject::from_seq(vec![
        hash_algorithm.to_ber(),
        BerObject::from_obj(BerObjectContent::OctetString(&issuer_name_hash)),
        BerObject::from_obj(BerObjectContent::OctetString(&issuer_key_hash)),
        BerObject::from_obj(BerObjectContent::Integer(serial_number)),
    ]);
    // https://tools.ietf.org/html/rfc6960#section-4.1.1
    // Request         ::=     SEQUENCE {
    //     reqCert                     CertID,
    //     singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
    let request = BerObject::from_seq(vec![cert_id]);
    // https://tools.ietf.org/html/rfc6960#section-4.1.1
    // TBSRequest      ::=     SEQUENCE {
    //     version             [0]     EXPLICIT Version DEFAULT v1,
    //     requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
    //     requestList                 SEQUENCE OF Request,
    //     requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
    let tbs_request = BerObject::from_seq(vec![BerObject::from_seq(vec![request])]);
    // https://tools.ietf.org/html/rfc6960#section-4.1.1
    // OCSPRequest     ::=     SEQUENCE {
    //     tbsRequest                  TBSRequest,
    //     optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
    let ocsp_request = BerObject::from_seq(vec![tbs_request]);
    ocsp_request.to_vec().unwrap()
}

// https://datatracker.ietf.org/doc/html/rfc4325#section-2
// https://datatracker.ietf.org/doc/html/rfc3280#section-4.2.2.1
const AIA: Oid<'static> = oid!(1.3.6 .1 .5 .5 .7 .1 .1);
// https://www.iana.org/assignments/smi-numbers/smi-numbers.xhtml#smi-numbers-1.3.6.1.5.5.7.48.1
const AIA_OCSP: Oid<'static> = oid!(1.3.6 .1 .5 .5 .7 .48 .1);

pub async fn fetch_from_ca(
    cert_der: &[u8],
    issuer_der: &[u8],
    fetcher: &dyn Fetcher,
) -> Result<Vec<u8>> {
    let cert = x509_parser::parse_x509_certificate(cert_der)
        .map_err(|e| Error::from(e).context("Failed to parse cert DER"))?
        .1;
    let issuer = x509_parser::parse_x509_certificate(issuer_der)
        .map_err(|e| Error::from(e).context("Failed to parse issuer DER"))?
        .1;
    let aia = cert.extensions().iter().find(|ext| ext.oid == AIA);
    let aia = if let Some(aia) = aia {
        aia
    } else {
        // If the certificate doesn't include an AIA section, it is probably a
        // self-signed certificate. Return a stub OCSP response.
        return Ok(b"ocsp".to_vec());
    };
    let aia = if let ParsedExtension::AuthorityInfoAccess(aia) = aia.parsed_extension() {
        aia
    } else {
        return Err(anyhow!("Failed to parse AIA extension"));
    };
    let url = aia
        .accessdescs
        .iter()
        .find_map(|access_desc| {
            if access_desc.access_method == AIA_OCSP {
                match access_desc.access_location {
                    GeneralName::URI(url) => Some(url),
                    _ => None,
                }
            } else {
                None
            }
        })
        .ok_or_else(|| anyhow!("AIA OCSP responder with type of URI is not found."))?;
    let req = HttpRequest {
        body: create_ocsp_request(&cert, &issuer),
        headers: vec![(
            String::from("content-type"),
            String::from("application/ocsp-request"),
        )],
        method: Method::Post,
        url: url.into(),
    };
    let rsp = fetcher
        .fetch(req)
        .await
        .map_err(|e| e.context("Failed to fetch OCSP"))?;
    Ok(rsp.body)
}

const OCSP_KEY: &str = "OCSP";

#[derive(Serialize, Deserialize)]
struct OcspData {
    pub expiration_time: SystemTime,
    pub recommended_update_time: SystemTime,
    #[serde(with = "crate::serde_helpers::base64")]
    pub value: Vec<u8>,
}

pub enum OcspUpdateStrategy {
    EarlyAsRecommended,
    LazyIfUnexpired,
}

/// Reads OCSP in storage, checks the expiration status, and returns latest.
/// If OCSP in storage needs update, fetches it from the server and writes it
/// into storage. The outging traffic to the server is throttled to be a
/// single task.
/// If there is any error when reading from and writing to storage, the error
/// will be ignored but an error message will be printed to output/log.
pub async fn read_and_update_ocsp_in_storage(
    certificate_chain: &CertificateChain,
    runtime: &Runtime,
    strategy: OcspUpdateStrategy,
) -> Result<Vec<u8>> {
    // Checks whether we can directly return the existing OCSP in storage.
    match runtime.storage.read(OCSP_KEY).await {
        Ok(Some(old_ocsp)) => {
            if let Ok(old_ocsp) = serde_json::from_str::<OcspData>(&old_ocsp) {
                match strategy {
                    OcspUpdateStrategy::EarlyAsRecommended => {
                        if old_ocsp.recommended_update_time > runtime.now {
                            return Ok(old_ocsp.value);
                        }
                    }
                    OcspUpdateStrategy::LazyIfUnexpired => {
                        if old_ocsp.expiration_time > runtime.now {
                            return Ok(old_ocsp.value);
                        }
                    }
                }
            } else {
                // The existing OCSP in storage can't be parsed as `OcspData`.
            }
        }
        Ok(None) => {
            // There is no OCSP in storage.
        }
        Err(e) => {
            println!("Failed to read OCSP from storage. {}", e);
        }
    }
    if certificate_chain.issuers.is_empty() {
        return Err(Error::msg("Certiciate chain contains no issuer."));
    }
    let cert_der = &certificate_chain.end_entity.der;
    let issuer_der = &certificate_chain.issuers[0].der;
    let new_ocsp_value = {
        static SINGLE_TASK: Mutex<()> = Mutex::const_new(());
        let guard = SINGLE_TASK.lock().await;
        let ocsp = fetch_from_ca(cert_der, issuer_der, runtime.fetcher.as_ref()).await?;
        std::mem::drop(guard);
        ocsp
    };
    const SIX_DAYS: Duration = Duration::from_secs(3600 * 24 * 6);
    const ONE_DAY: Duration = Duration::from_secs(3600 * 24);
    let new_ocsp = OcspData {
        expiration_time: runtime.now + SIX_DAYS,
        recommended_update_time: runtime.now + ONE_DAY,
        value: new_ocsp_value,
    };
    let write_result = runtime
        .storage
        .write(OCSP_KEY, &serde_json::to_string(&new_ocsp)?)
        .await;
    if let Err(e) = write_result {
        println!("Failed to write OCSP to storage. {}", e);
    }
    Ok(new_ocsp.value)
}
<commit_msg>Fix a typo (#372)<commit_after>// Copyright 2021 Google LLC
//
// 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
//
//     https://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.

// OCSP request is defined in
// https://tools.ietf.org/html/rfc6960#section-4.1
//
// OCSP over http is defined in
// https://tools.ietf.org/html/rfc2560#appendix-A.1

use crate::crypto::{CertificateChain, HashAlgorithm};
use crate::fetcher::Fetcher;
use crate::http::{HttpRequest, Method};
use crate::runtime::Runtime;
use anyhow::{anyhow, Error, Result};
use der_parser::{
    ber::{BerObject, BerObjectContent},
    oid,
    oid::Oid,
};
use serde::{Deserialize, Serialize};
use std::time::{Duration, SystemTime};
use tokio::sync::Mutex;
use x509_parser::{
    certificate::X509Certificate,
    extensions::{GeneralName, ParsedExtension},
};

fn create_ocsp_request(cert: &X509Certificate, issuer: &X509Certificate) -> Vec<u8> {
    let hash_algorithm = HashAlgorithm::Sha1;
    let issuer_name = issuer.tbs_certificate.subject.as_raw();
    let issuer_key = issuer
        .tbs_certificate
        .subject_pki
        .subject_public_key
        .data
        .as_ref();
    let issuer_key_hash = hash_algorithm.digest(issuer_key);
    let issuer_name_hash = hash_algorithm.digest(issuer_name);
    let serial_number = cert.tbs_certificate.raw_serial();
    // https://tools.ietf.org/html/rfc6960#section-4.1.1
    // CertID          ::=     SEQUENCE {
    //     hashAlgorithm       AlgorithmIdentifier,
    //     issuerNameHash      OCTET STRING, -- Hash of issuer's DN
    //     issuerKeyHash       OCTET STRING, -- Hash of issuer's public key
    //     serialNumber        CertificateSerialNumber }
    let cert_id = BerObject::from_seq(vec![
        hash_algorithm.to_ber(),
        BerObject::from_obj(BerObjectContent::OctetString(&issuer_name_hash)),
        BerObject::from_obj(BerObjectContent::OctetString(&issuer_key_hash)),
        BerObject::from_obj(BerObjectContent::Integer(serial_number)),
    ]);
    // https://tools.ietf.org/html/rfc6960#section-4.1.1
    // Request         ::=     SEQUENCE {
    //     reqCert                     CertID,
    //     singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
    let request = BerObject::from_seq(vec![cert_id]);
    // https://tools.ietf.org/html/rfc6960#section-4.1.1
    // TBSRequest      ::=     SEQUENCE {
    //     version             [0]     EXPLICIT Version DEFAULT v1,
    //     requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
    //     requestList                 SEQUENCE OF Request,
    //     requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
    let tbs_request = BerObject::from_seq(vec![BerObject::from_seq(vec![request])]);
    // https://tools.ietf.org/html/rfc6960#section-4.1.1
    // OCSPRequest     ::=     SEQUENCE {
    //     tbsRequest                  TBSRequest,
    //     optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
    let ocsp_request = BerObject::from_seq(vec![tbs_request]);
    ocsp_request.to_vec().unwrap()
}

// https://datatracker.ietf.org/doc/html/rfc4325#section-2
// https://datatracker.ietf.org/doc/html/rfc3280#section-4.2.2.1
const AIA: Oid<'static> = oid!(1.3.6 .1 .5 .5 .7 .1 .1);
// https://www.iana.org/assignments/smi-numbers/smi-numbers.xhtml#smi-numbers-1.3.6.1.5.5.7.48.1
const AIA_OCSP: Oid<'static> = oid!(1.3.6 .1 .5 .5 .7 .48 .1);

pub async fn fetch_from_ca(
    cert_der: &[u8],
    issuer_der: &[u8],
    fetcher: &dyn Fetcher,
) -> Result<Vec<u8>> {
    let cert = x509_parser::parse_x509_certificate(cert_der)
        .map_err(|e| Error::from(e).context("Failed to parse cert DER"))?
        .1;
    let issuer = x509_parser::parse_x509_certificate(issuer_der)
        .map_err(|e| Error::from(e).context("Failed to parse issuer DER"))?
        .1;
    let aia = cert.extensions().iter().find(|ext| ext.oid == AIA);
    let aia = if let Some(aia) = aia {
        aia
    } else {
        // If the certificate doesn't include an AIA section, it is probably a
        // self-signed certificate. Return a stub OCSP response.
        return Ok(b"ocsp".to_vec());
    };
    let aia = if let ParsedExtension::AuthorityInfoAccess(aia) = aia.parsed_extension() {
        aia
    } else {
        return Err(anyhow!("Failed to parse AIA extension"));
    };
    let url = aia
        .accessdescs
        .iter()
        .find_map(|access_desc| {
            if access_desc.access_method == AIA_OCSP {
                match access_desc.access_location {
                    GeneralName::URI(url) => Some(url),
                    _ => None,
                }
            } else {
                None
            }
        })
        .ok_or_else(|| anyhow!("AIA OCSP responder with type of URI is not found."))?;
    let req = HttpRequest {
        body: create_ocsp_request(&cert, &issuer),
        headers: vec![(
            String::from("content-type"),
            String::from("application/ocsp-request"),
        )],
        method: Method::Post,
        url: url.into(),
    };
    let rsp = fetcher
        .fetch(req)
        .await
        .map_err(|e| e.context("Failed to fetch OCSP"))?;
    Ok(rsp.body)
}

const OCSP_KEY: &str = "OCSP";

#[derive(Serialize, Deserialize)]
struct OcspData {
    pub expiration_time: SystemTime,
    pub recommended_update_time: SystemTime,
    #[serde(with = "crate::serde_helpers::base64")]
    pub value: Vec<u8>,
}

pub enum OcspUpdateStrategy {
    EarlyAsRecommended,
    LazyIfUnexpired,
}

/// Reads OCSP in storage, checks the expiration status, and returns latest.
/// If OCSP in storage needs update, fetches it from the server and writes it
/// into storage. The outging traffic to the server is throttled to be a
/// single task.
/// If there is any error when reading from and writing to storage, the error
/// will be ignored but an error message will be printed to output/log.
pub async fn read_and_update_ocsp_in_storage(
    certificate_chain: &CertificateChain,
    runtime: &Runtime,
    strategy: OcspUpdateStrategy,
) -> Result<Vec<u8>> {
    // Checks whether we can directly return the existing OCSP in storage.
    match runtime.storage.read(OCSP_KEY).await {
        Ok(Some(old_ocsp)) => {
            if let Ok(old_ocsp) = serde_json::from_str::<OcspData>(&old_ocsp) {
                match strategy {
                    OcspUpdateStrategy::EarlyAsRecommended => {
                        if old_ocsp.recommended_update_time > runtime.now {
                            return Ok(old_ocsp.value);
                        }
                    }
                    OcspUpdateStrategy::LazyIfUnexpired => {
                        if old_ocsp.expiration_time > runtime.now {
                            return Ok(old_ocsp.value);
                        }
                    }
                }
            } else {
                // The existing OCSP in storage can't be parsed as `OcspData`.
            }
        }
        Ok(None) => {
            // There is no OCSP in storage.
        }
        Err(e) => {
            println!("Failed to read OCSP from storage. {}", e);
        }
    }
    if certificate_chain.issuers.is_empty() {
        return Err(Error::msg("Certificate chain contains no issuer."));
    }
    let cert_der = &certificate_chain.end_entity.der;
    let issuer_der = &certificate_chain.issuers[0].der;
    let new_ocsp_value = {
        static SINGLE_TASK: Mutex<()> = Mutex::const_new(());
        let guard = SINGLE_TASK.lock().await;
        let ocsp = fetch_from_ca(cert_der, issuer_der, runtime.fetcher.as_ref()).await?;
        std::mem::drop(guard);
        ocsp
    };
    const SIX_DAYS: Duration = Duration::from_secs(3600 * 24 * 6);
    const ONE_DAY: Duration = Duration::from_secs(3600 * 24);
    let new_ocsp = OcspData {
        expiration_time: runtime.now + SIX_DAYS,
        recommended_update_time: runtime.now + ONE_DAY,
        value: new_ocsp_value,
    };
    let write_result = runtime
        .storage
        .write(OCSP_KEY, &serde_json::to_string(&new_ocsp)?)
        .await;
    if let Err(e) = write_result {
        println!("Failed to write OCSP to storage. {}", e);
    }
    Ok(new_ocsp.value)
}
<|endoftext|>


<commit_before>extern crate cc;

/*

N.B. This build script is invoked by `cargo` by way of this configuration
in our Cargo.toml:

    [project]
    ...
    build = "src/cffi_build.rs"

Within, we use the `gcc` crate to compile the CFFI C sources (`native_engine.c`)
generated by `bootstrap.sh` into a (private) static lib (`libnative_engine_ffi.a`),
which then gets linked into the final `cargo build` product (the native engine binary).
This process mixes the Python module initialization function and other symbols into the
native engine binary, allowing us to address it both as an importable python module
(`from _native_engine import X`) as well as a C library (`ffi.dlopen(native_engine.so)`).

*/

use std::fs;
use std::io::{Read, Result};
use std::path::{Path, PathBuf};

fn main() {
  // We depend on grpcio, which uses C++.
  // On Linux, with g++, some part of that compilation depends on
  // __gxx_personality_v0 which is present in the C++ standard library.
  // I don't know why. It shouldn't, and before grpcio 0.2.0, it didn't.
  //
  // So we need to link against the C++ standard library. Nothing under us
  // in the dependency tree appears to export this fact.
  // Ideally, we would be linking dynamically, because statically linking
  // against libstdc++ is kind of scary. But we're only doing it to pull in a
  // bogus symbol anyway, so what's the worst that can happen?
  //
  // The only way I can find to dynamically link against libstdc++ is to pass
  // `-C link-args=lstdc++` to rustc, but we can only do this from a
  // .cargo/config file, which applies that argument to every compile/link which
  // happens in a subdirectory of that directory, which isn't what we want to do.
  // So we'll statically link. Because what's the worst that can happen?
  //
  // The following do not work:
  //  * Using the link argument in Cargo.toml to specify stdc++.
  //  * Specifying `rustc-flags=-lstdc++`
  //    (which is equivalent to `-ldylib=stdc++`).
  //  * Specifying `rustc-link-lib=stdc++`
  //    (which is equivalent to `rustc-link-lib=dylib=stdc++).
  if cfg!(target_os = "linux") {
    println!("cargo:rustc-link-lib=static=stdc++");
  }

  let mut config = cc::Build::new();

  // Don't implicitly set -Wall -Wextra because cffi generates code with warnings.
  // TODO: Consider removing this if/when https://github.com/alexcrichton/cc-rs/pull/248 lands.
  config.warnings(false);

  // N.B. The filename of this source code - at generation time - must line up 1:1 with the
  // python import name, as python keys the initialization function name off of the import name.
  let cffi_dir = Path::new("src/cffi");
  let c_path = mark_for_change_detection(cffi_dir.join("native_engine.c"));
  let env_script_path = mark_for_change_detection(cffi_dir.join("native_engine.cflags"));

  config.file(c_path.to_str().unwrap());
  for flag in make_flags(&env_script_path).unwrap() {
    config.flag(flag.as_str());
  }

  config.compile("libnative_engine_ffi.a");
}

fn mark_for_change_detection(path: PathBuf) -> PathBuf {
  // Restrict re-compilation check to just our input files.
  // See: http://doc.crates.io/build-script.html#outputs-of-the-build-script
  println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
  path
}

fn make_flags(env_script_path: &Path) -> Result<Vec<String>> {
  let mut contents = String::new();
  fs::File::open(env_script_path)?.read_to_string(
    &mut contents,
  )?;
  // It would be a shame if someone were to include a space in an actual quoted value.
  // If they did that, I guess we'd need to implement shell tokenization or something.
  return Ok(
    contents
      .trim()
      .split_whitespace()
      .map(str::to_owned)
      .collect(),
  );
}
<commit_msg>Narrow the warnings we ignore when compiling our cffi (#5458)<commit_after>extern crate cc;

/*

N.B. This build script is invoked by `cargo` by way of this configuration
in our Cargo.toml:

    [project]
    ...
    build = "src/cffi_build.rs"

Within, we use the `gcc` crate to compile the CFFI C sources (`native_engine.c`)
generated by `bootstrap.sh` into a (private) static lib (`libnative_engine_ffi.a`),
which then gets linked into the final `cargo build` product (the native engine binary).
This process mixes the Python module initialization function and other symbols into the
native engine binary, allowing us to address it both as an importable python module
(`from _native_engine import X`) as well as a C library (`ffi.dlopen(native_engine.so)`).

*/

use std::fs;
use std::io::{Read, Result};
use std::path::{Path, PathBuf};

fn main() {
  // We depend on grpcio, which uses C++.
  // On Linux, with g++, some part of that compilation depends on
  // __gxx_personality_v0 which is present in the C++ standard library.
  // I don't know why. It shouldn't, and before grpcio 0.2.0, it didn't.
  //
  // So we need to link against the C++ standard library. Nothing under us
  // in the dependency tree appears to export this fact.
  // Ideally, we would be linking dynamically, because statically linking
  // against libstdc++ is kind of scary. But we're only doing it to pull in a
  // bogus symbol anyway, so what's the worst that can happen?
  //
  // The only way I can find to dynamically link against libstdc++ is to pass
  // `-C link-args=lstdc++` to rustc, but we can only do this from a
  // .cargo/config file, which applies that argument to every compile/link which
  // happens in a subdirectory of that directory, which isn't what we want to do.
  // So we'll statically link. Because what's the worst that can happen?
  //
  // The following do not work:
  //  * Using the link argument in Cargo.toml to specify stdc++.
  //  * Specifying `rustc-flags=-lstdc++`
  //    (which is equivalent to `-ldylib=stdc++`).
  //  * Specifying `rustc-link-lib=stdc++`
  //    (which is equivalent to `rustc-link-lib=dylib=stdc++).
  if cfg!(target_os = "linux") {
    println!("cargo:rustc-link-lib=static=stdc++");
  }

  let mut config = cc::Build::new();

  // N.B. The filename of this source code - at generation time - must line up 1:1 with the
  // python import name, as python keys the initialization function name off of the import name.
  let cffi_dir = Path::new("src/cffi");
  let c_path = mark_for_change_detection(cffi_dir.join("native_engine.c"));
  let env_script_path = mark_for_change_detection(cffi_dir.join("native_engine.cflags"));

  config.file(c_path.to_str().unwrap());
  for flag in make_flags(&env_script_path).unwrap() {
    config.flag(flag.as_str());
  }

  // cffi generates missing field initializers :(
  config.flag("-Wno-missing-field-initializers");

  config.compile("libnative_engine_ffi.a");
}

fn mark_for_change_detection(path: PathBuf) -> PathBuf {
  // Restrict re-compilation check to just our input files.
  // See: http://doc.crates.io/build-script.html#outputs-of-the-build-script
  println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
  path
}

fn make_flags(env_script_path: &Path) -> Result<Vec<String>> {
  let mut contents = String::new();
  fs::File::open(env_script_path)?.read_to_string(
    &mut contents,
  )?;
  // It would be a shame if someone were to include a space in an actual quoted value.
  // If they did that, I guess we'd need to implement shell tokenization or something.
  return Ok(
    contents
      .trim()
      .split_whitespace()
      .map(str::to_owned)
      .collect(),
  );
}
<|endoftext|>