<commit_before>//! Codegen vtables and vtable accesses.
//!
//! See `rustc_codegen_ssa/src/meth.rs` for reference.
// FIXME dedup this logic between miri, cg_llvm and cg_clif

use crate::prelude::*;
use ty::VtblEntry;

fn vtable_memflags() -> MemFlags {
    let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
    flags.set_readonly(); // A vtable is always read-only.
    flags
}

pub(crate) fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (ty::COMMON_VTABLE_ENTRIES_DROPINPLACE * usize_size) as i32,
    )
}

pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
    )
}

pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
    )
}

pub(crate) fn get_ptr_and_method_ref<'tcx>(
    fx: &mut FunctionCx<'_, '_, 'tcx>,
    arg: CValue<'tcx>,
    idx: usize,
) -> (Value, Value) {
    let (ptr, vtable) = if let Abi::ScalarPair(_, _) = arg.layout().abi {
        arg.load_scalar_pair(fx)
    } else {
        let (ptr, vtable) = arg.try_to_ptr().unwrap();
        (ptr.get_addr(fx), vtable.unwrap())
    };

    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes();
    let func_ref = fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (idx * usize_size as usize) as i32,
    );
    (ptr, func_ref)
}

pub(crate) fn get_vtable<'tcx>(
    fx: &mut FunctionCx<'_, '_, 'tcx>,
    layout: TyAndLayout<'tcx>,
    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> Value {
    let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) {
        *data_id
    } else {
        let data_id = build_vtable(fx, layout, trait_ref);
        fx.vtables.insert((layout.ty, trait_ref), data_id);
        data_id
    };

    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}

fn build_vtable<'tcx>(
    fx: &mut FunctionCx<'_, '_, 'tcx>,
    layout: TyAndLayout<'tcx>,
    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> DataId {
    let tcx = fx.tcx;
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;

    let drop_in_place_fn = import_function(
        tcx,
        fx.module,
        Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx),
    );

    let vtable_entries = if let Some(trait_ref) = trait_ref {
        tcx.vtable_entries(trait_ref.with_self_ty(tcx, layout.ty))
    } else {
        ty::COMMON_VTABLE_ENTRIES
    };

    let mut data_ctx = DataContext::new();
    let mut data = ::std::iter::repeat(0u8)
        .take(vtable_entries.len() * usize_size)
        .collect::<Vec<u8>>()
        .into_boxed_slice();

    for (idx, entry) in vtable_entries.iter().enumerate() {
        match entry {
            VtblEntry::MetadataSize => {
                write_usize(fx.tcx, &mut data, idx, layout.size.bytes());
            }
            VtblEntry::MetadataAlign => {
                write_usize(fx.tcx, &mut data, idx, layout.align.abi.bytes());
            }
            VtblEntry::MetadataDropInPlace | VtblEntry::Vacant | VtblEntry::Method(_, _) => {}
        }
    }
    data_ctx.define(data);

    for (idx, entry) in vtable_entries.iter().enumerate() {
        match entry {
            VtblEntry::MetadataDropInPlace => {
                let func_ref = fx.module.declare_func_in_data(drop_in_place_fn, &mut data_ctx);
                data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
            }
            VtblEntry::Method(def_id, substs) => {
                let func_id = import_function(
                    tcx,
                    fx.module,
                    Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), *def_id, substs)
                        .unwrap()
                        .polymorphize(fx.tcx),
                );
                let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
                data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
            }
            VtblEntry::MetadataSize | VtblEntry::MetadataAlign | VtblEntry::Vacant => {}
        }
    }

    data_ctx.set_align(fx.tcx.data_layout.pointer_align.pref.bytes());

    let data_id = fx.module.declare_anonymous_data(false, false).unwrap();

    fx.module.define_data(data_id, &data_ctx).unwrap();

    data_id
}

fn write_usize(tcx: TyCtxt<'_>, buf: &mut [u8], idx: usize, num: u64) {
    let pointer_size =
        tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.usize)).unwrap().size.bytes() as usize;
    let target = &mut buf[idx * pointer_size..(idx + 1) * pointer_size];

    match tcx.data_layout.endian {
        rustc_target::abi::Endian::Little => match pointer_size {
            4 => target.copy_from_slice(&(num as u32).to_le_bytes()),
            8 => target.copy_from_slice(&(num as u64).to_le_bytes()),
            _ => todo!("pointer size {} is not yet supported", pointer_size),
        },
        rustc_target::abi::Endian::Big => match pointer_size {
            4 => target.copy_from_slice(&(num as u32).to_be_bytes()),
            8 => target.copy_from_slice(&(num as u64).to_be_bytes()),
            _ => todo!("pointer size {} is not yet supported", pointer_size),
        },
    }
}
<commit_msg>Fix miscompilation in vtable access<commit_after>//! Codegen vtables and vtable accesses.
//!
//! See `rustc_codegen_ssa/src/meth.rs` for reference.
// FIXME dedup this logic between miri, cg_llvm and cg_clif

use crate::prelude::*;
use ty::VtblEntry;

fn vtable_memflags() -> MemFlags {
    let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
    flags.set_readonly(); // A vtable is always read-only.
    flags
}

pub(crate) fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (ty::COMMON_VTABLE_ENTRIES_DROPINPLACE * usize_size) as i32,
    )
}

pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
    )
}

pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
    fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (ty::COMMON_VTABLE_ENTRIES_ALIGN * usize_size) as i32,
    )
}

pub(crate) fn get_ptr_and_method_ref<'tcx>(
    fx: &mut FunctionCx<'_, '_, 'tcx>,
    arg: CValue<'tcx>,
    idx: usize,
) -> (Value, Value) {
    let (ptr, vtable) = if let Abi::ScalarPair(_, _) = arg.layout().abi {
        arg.load_scalar_pair(fx)
    } else {
        let (ptr, vtable) = arg.try_to_ptr().unwrap();
        (ptr.get_addr(fx), vtable.unwrap())
    };

    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes();
    let func_ref = fx.bcx.ins().load(
        pointer_ty(fx.tcx),
        vtable_memflags(),
        vtable,
        (idx * usize_size as usize) as i32,
    );
    (ptr, func_ref)
}

pub(crate) fn get_vtable<'tcx>(
    fx: &mut FunctionCx<'_, '_, 'tcx>,
    layout: TyAndLayout<'tcx>,
    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> Value {
    let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) {
        *data_id
    } else {
        let data_id = build_vtable(fx, layout, trait_ref);
        fx.vtables.insert((layout.ty, trait_ref), data_id);
        data_id
    };

    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}

fn build_vtable<'tcx>(
    fx: &mut FunctionCx<'_, '_, 'tcx>,
    layout: TyAndLayout<'tcx>,
    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> DataId {
    let tcx = fx.tcx;
    let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;

    let drop_in_place_fn = import_function(
        tcx,
        fx.module,
        Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx),
    );

    let vtable_entries = if let Some(trait_ref) = trait_ref {
        tcx.vtable_entries(trait_ref.with_self_ty(tcx, layout.ty))
    } else {
        ty::COMMON_VTABLE_ENTRIES
    };

    let mut data_ctx = DataContext::new();
    let mut data = ::std::iter::repeat(0u8)
        .take(vtable_entries.len() * usize_size)
        .collect::<Vec<u8>>()
        .into_boxed_slice();

    for (idx, entry) in vtable_entries.iter().enumerate() {
        match entry {
            VtblEntry::MetadataSize => {
                write_usize(fx.tcx, &mut data, idx, layout.size.bytes());
            }
            VtblEntry::MetadataAlign => {
                write_usize(fx.tcx, &mut data, idx, layout.align.abi.bytes());
            }
            VtblEntry::MetadataDropInPlace | VtblEntry::Vacant | VtblEntry::Method(_, _) => {}
        }
    }
    data_ctx.define(data);

    for (idx, entry) in vtable_entries.iter().enumerate() {
        match entry {
            VtblEntry::MetadataDropInPlace => {
                let func_ref = fx.module.declare_func_in_data(drop_in_place_fn, &mut data_ctx);
                data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
            }
            VtblEntry::Method(def_id, substs) => {
                let func_id = import_function(
                    tcx,
                    fx.module,
                    Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), *def_id, substs)
                        .unwrap()
                        .polymorphize(fx.tcx),
                );
                let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
                data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
            }
            VtblEntry::MetadataSize | VtblEntry::MetadataAlign | VtblEntry::Vacant => {}
        }
    }

    data_ctx.set_align(fx.tcx.data_layout.pointer_align.pref.bytes());

    let data_id = fx.module.declare_anonymous_data(false, false).unwrap();

    fx.module.define_data(data_id, &data_ctx).unwrap();

    data_id
}

fn write_usize(tcx: TyCtxt<'_>, buf: &mut [u8], idx: usize, num: u64) {
    let pointer_size =
        tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.usize)).unwrap().size.bytes() as usize;
    let target = &mut buf[idx * pointer_size..(idx + 1) * pointer_size];

    match tcx.data_layout.endian {
        rustc_target::abi::Endian::Little => match pointer_size {
            4 => target.copy_from_slice(&(num as u32).to_le_bytes()),
            8 => target.copy_from_slice(&(num as u64).to_le_bytes()),
            _ => todo!("pointer size {} is not yet supported", pointer_size),
        },
        rustc_target::abi::Endian::Big => match pointer_size {
            4 => target.copy_from_slice(&(num as u32).to_be_bytes()),
            8 => target.copy_from_slice(&(num as u64).to_be_bytes()),
            _ => todo!("pointer size {} is not yet supported", pointer_size),
        },
    }
}
<|endoftext|>


<commit_before>//! Compiler plugin for Rust-PHF
//!
//! See the documentation for the `phf` crate for more details.
#[crate_id="github.com/sfackler/rust-phf/phf_mac"];
#[crate_type="dylib"];
#[doc(html_root_url="http://www.rust-ci.org/sfackler/rust-phf/doc")];
#[feature(managed_boxes, macro_registrar)];

extern mod extra;
extern mod syntax;
extern mod phf;

use extra::time;
use std::hashmap::HashMap;
use std::rand;
use std::os;
use std::vec;
use syntax::ast;
use syntax::ast::{Name, TokenTree, LitStr, MutImmutable, Expr, ExprVec, ExprLit};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        MRExpr,
                        NormalTT,
                        BasicMacroExpander};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF, FAT_ARROW};

static DEFAULT_LAMBDA: uint = 5;

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("phf_map"),
             NormalTT(~BasicMacroExpander {
                expander: expand_mphf_map,
                span: None
             },
             None));
}

struct Entry {
    key_str: InternedString,
    key: @Expr,
    value: @Expr
}

fn expand_mphf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let mut entries = match parse_entries(cx, tts) {
        Some(entries) => entries,
        None => return MacResult::dummy_expr()
    };

    entries.sort_by(|a, b| a.key_str.cmp(&b.key_str));
    if check_for_duplicates(cx, sp, entries) {
        return MacResult::dummy_expr();
    }

    let start = time::precise_time_s();
    let state;
    loop {
        match generate_hash(entries) {
            Some(s) => {
                state = s;
                break;
            }
            None => {}
        }
    }
    let time = time::precise_time_s() - start;
    if os::getenv("PHF_STATS").is_some() {
        cx.span_note(sp, format!("PHF generation took {} seconds", time));
    }

    create_map(cx, sp, entries, state)
}

fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<~[Entry]> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_owned());
    let mut entries = ~[];

    let mut bad = false;
    while parser.token != EOF {
        let key = parser.parse_expr();

        let key_str = match key.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(ref s, _) => s.clone(),
                    _ => {
                        cx.span_err(key.span, "expected string literal");
                        bad = true;
                        InternedString::new("")
                    }
                }
            }
            _ => {
                cx.span_err(key.span, "expected string literal");
                bad = true;
                InternedString::new("")
            }
        };

        if !parser.eat(&FAT_ARROW) {
            cx.span_err(parser.span, "expected `=>`");
            return None;
        }

        let value = parser.parse_expr();

        entries.push(Entry {
            key_str: key_str,
            key: key,
            value: value
        });

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if entries.len() > phf::MAX_SIZE {
        cx.span_err(parser.span,
                    format!("maps with more than {} entries are not supported",
                            phf::MAX_SIZE));
        return None;
    }

    if bad {
        return None;
    }

    Some(entries)
}

fn check_for_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> bool {
    let mut dups = false;
    let mut in_dup = false;
    for window in entries.windows(2) {
        let ref a = window[0];
        let ref b = window[1];
        if a.key_str == b.key_str {
            dups = true;
            if !in_dup {
                cx.span_err(sp, format!("duplicate key \"{}\"", a.key_str));
                cx.span_note(a.key.span, "one occurrence here");
                in_dup = true;
            }
            cx.span_note(b.key.span, "one occurrence here");
        } else {
            in_dup = false;
        }
    }

    dups
}

struct HashState {
    k1: u64,
    k2: u64,
    disps: ~[(uint, uint)],
    map: ~[Option<uint>],
}

fn generate_hash(entries: &[Entry]) -> Option<HashState> {
    struct Bucket {
        idx: uint,
        keys: ~[uint],
    }

    struct Hashes {
        g: uint,
        f1: uint,
        f2: uint,
    }

    let k1 = rand::random();
    let k2 = rand::random();

    let hashes = entries.iter().map(|entry| {
            let (g, f1, f2) = phf::hash(entry.key_str.get(), k1, k2);
            Hashes {
                g: g,
                f1: f1,
                f2: f2
            }
        }).to_owned_vec();

    let buckets_len = (entries.len() + DEFAULT_LAMBDA - 1) / DEFAULT_LAMBDA;
    let mut buckets = vec::from_fn(buckets_len,
                                   |i| Bucket { idx: i, keys: ~[] });

    for (i, hash) in hashes.iter().enumerate() {
        buckets[hash.g % buckets_len].keys.push(i);
    }

    // Sort descending
    buckets.sort_by(|a, b| b.keys.len().cmp(&a.keys.len()));

    let table_len = entries.len();
    let mut map = vec::from_elem(table_len, None);
    let mut disps = vec::from_elem(buckets_len, None);
    let mut try_map = HashMap::new();
    'buckets: for bucket in buckets.iter() {
        for d1 in range(0, table_len) {
            'disps: for d2 in range(0, table_len) {
                try_map.clear();
                for &key in bucket.keys.iter() {
                    let idx = phf::displace(hashes[key].f1, hashes[key].f2,
                                            d1, d2) % table_len;
                    if try_map.find(&idx).is_some() || map[idx].is_some() {
                        continue 'disps;
                    }
                    try_map.insert(idx, key);
                }

                // We've picked a good set of disps
                disps[bucket.idx] = Some((d1, d2));
                for (&idx, &key) in try_map.iter() {
                    map[idx] = Some(key);
                }
                continue 'buckets;
            }
        }

        // Unable to find displacements for a bucket
        return None;
    }

    let disps = disps.move_iter().map(|i| i.expect("should have a bucket"))
            .collect();

    Some(HashState {
        k1: k1,
        k2: k2,
        disps: disps,
        map: map,
    })
}

fn create_map(cx: &mut ExtCtxt, sp: Span, entries: ~[Entry], state: HashState)
              -> MacResult {
    let len = entries.len();
    let k1 = state.k1;
    let k2 = state.k2;
    let disps = state.disps.iter().map(|&(d1, d2)| {
            quote_expr!(&*cx, ($d1, $d2))
        }).collect();
    let disps = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(disps, MutImmutable),
        span: sp,
    };
    let entries = state.map.iter().map(|&idx| {
            match idx {
                Some(idx) => {
                    let Entry { key, value, .. } = entries[idx];
                    quote_expr!(&*cx, Some(($key, $value)))
                }
                None => quote_expr!(&*cx, None),
            }
        }).collect();
    let entries = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(entries, MutImmutable),
        span: sp,
    };

    MRExpr(quote_expr!(cx, PhfMap {
        len: $len,
        k1: $k1,
        k2: $k2,
        disps: &'static $disps,
        entries: &'static $entries,
    }))
}
<commit_msg>Add quote feature<commit_after>//! Compiler plugin for Rust-PHF
//!
//! See the documentation for the `phf` crate for more details.
#[crate_id="github.com/sfackler/rust-phf/phf_mac"];
#[crate_type="dylib"];
#[doc(html_root_url="http://www.rust-ci.org/sfackler/rust-phf/doc")];
#[feature(managed_boxes, macro_registrar, quote)];

extern mod extra;
extern mod syntax;
extern mod phf;

use extra::time;
use std::hashmap::HashMap;
use std::rand;
use std::os;
use std::vec;
use syntax::ast;
use syntax::ast::{Name, TokenTree, LitStr, MutImmutable, Expr, ExprVec, ExprLit};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        MRExpr,
                        NormalTT,
                        BasicMacroExpander};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF, FAT_ARROW};

static DEFAULT_LAMBDA: uint = 5;

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("phf_map"),
             NormalTT(~BasicMacroExpander {
                expander: expand_mphf_map,
                span: None
             },
             None));
}

struct Entry {
    key_str: InternedString,
    key: @Expr,
    value: @Expr
}

fn expand_mphf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let mut entries = match parse_entries(cx, tts) {
        Some(entries) => entries,
        None => return MacResult::dummy_expr()
    };

    entries.sort_by(|a, b| a.key_str.cmp(&b.key_str));
    if check_for_duplicates(cx, sp, entries) {
        return MacResult::dummy_expr();
    }

    let start = time::precise_time_s();
    let state;
    loop {
        match generate_hash(entries) {
            Some(s) => {
                state = s;
                break;
            }
            None => {}
        }
    }
    let time = time::precise_time_s() - start;
    if os::getenv("PHF_STATS").is_some() {
        cx.span_note(sp, format!("PHF generation took {} seconds", time));
    }

    create_map(cx, sp, entries, state)
}

fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<~[Entry]> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_owned());
    let mut entries = ~[];

    let mut bad = false;
    while parser.token != EOF {
        let key = parser.parse_expr();

        let key_str = match key.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(ref s, _) => s.clone(),
                    _ => {
                        cx.span_err(key.span, "expected string literal");
                        bad = true;
                        InternedString::new("")
                    }
                }
            }
            _ => {
                cx.span_err(key.span, "expected string literal");
                bad = true;
                InternedString::new("")
            }
        };

        if !parser.eat(&FAT_ARROW) {
            cx.span_err(parser.span, "expected `=>`");
            return None;
        }

        let value = parser.parse_expr();

        entries.push(Entry {
            key_str: key_str,
            key: key,
            value: value
        });

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if entries.len() > phf::MAX_SIZE {
        cx.span_err(parser.span,
                    format!("maps with more than {} entries are not supported",
                            phf::MAX_SIZE));
        return None;
    }

    if bad {
        return None;
    }

    Some(entries)
}

fn check_for_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> bool {
    let mut dups = false;
    let mut in_dup = false;
    for window in entries.windows(2) {
        let ref a = window[0];
        let ref b = window[1];
        if a.key_str == b.key_str {
            dups = true;
            if !in_dup {
                cx.span_err(sp, format!("duplicate key \"{}\"", a.key_str));
                cx.span_note(a.key.span, "one occurrence here");
                in_dup = true;
            }
            cx.span_note(b.key.span, "one occurrence here");
        } else {
            in_dup = false;
        }
    }

    dups
}

struct HashState {
    k1: u64,
    k2: u64,
    disps: ~[(uint, uint)],
    map: ~[Option<uint>],
}

fn generate_hash(entries: &[Entry]) -> Option<HashState> {
    struct Bucket {
        idx: uint,
        keys: ~[uint],
    }

    struct Hashes {
        g: uint,
        f1: uint,
        f2: uint,
    }

    let k1 = rand::random();
    let k2 = rand::random();

    let hashes = entries.iter().map(|entry| {
            let (g, f1, f2) = phf::hash(entry.key_str.get(), k1, k2);
            Hashes {
                g: g,
                f1: f1,
                f2: f2
            }
        }).to_owned_vec();

    let buckets_len = (entries.len() + DEFAULT_LAMBDA - 1) / DEFAULT_LAMBDA;
    let mut buckets = vec::from_fn(buckets_len,
                                   |i| Bucket { idx: i, keys: ~[] });

    for (i, hash) in hashes.iter().enumerate() {
        buckets[hash.g % buckets_len].keys.push(i);
    }

    // Sort descending
    buckets.sort_by(|a, b| b.keys.len().cmp(&a.keys.len()));

    let table_len = entries.len();
    let mut map = vec::from_elem(table_len, None);
    let mut disps = vec::from_elem(buckets_len, None);
    let mut try_map = HashMap::new();
    'buckets: for bucket in buckets.iter() {
        for d1 in range(0, table_len) {
            'disps: for d2 in range(0, table_len) {
                try_map.clear();
                for &key in bucket.keys.iter() {
                    let idx = phf::displace(hashes[key].f1, hashes[key].f2,
                                            d1, d2) % table_len;
                    if try_map.find(&idx).is_some() || map[idx].is_some() {
                        continue 'disps;
                    }
                    try_map.insert(idx, key);
                }

                // We've picked a good set of disps
                disps[bucket.idx] = Some((d1, d2));
                for (&idx, &key) in try_map.iter() {
                    map[idx] = Some(key);
                }
                continue 'buckets;
            }
        }

        // Unable to find displacements for a bucket
        return None;
    }

    let disps = disps.move_iter().map(|i| i.expect("should have a bucket"))
            .collect();

    Some(HashState {
        k1: k1,
        k2: k2,
        disps: disps,
        map: map,
    })
}

fn create_map(cx: &mut ExtCtxt, sp: Span, entries: ~[Entry], state: HashState)
              -> MacResult {
    let len = entries.len();
    let k1 = state.k1;
    let k2 = state.k2;
    let disps = state.disps.iter().map(|&(d1, d2)| {
            quote_expr!(&*cx, ($d1, $d2))
        }).collect();
    let disps = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(disps, MutImmutable),
        span: sp,
    };
    let entries = state.map.iter().map(|&idx| {
            match idx {
                Some(idx) => {
                    let Entry { key, value, .. } = entries[idx];
                    quote_expr!(&*cx, Some(($key, $value)))
                }
                None => quote_expr!(&*cx, None),
            }
        }).collect();
    let entries = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(entries, MutImmutable),
        span: sp,
    };

    MRExpr(quote_expr!(cx, PhfMap {
        len: $len,
        k1: $k1,
        k2: $k2,
        disps: &'static $disps,
        entries: &'static $entries,
    }))
}
<|endoftext|>


<commit_before>use glium;
use frame::Frame;
use glium::glutin;
use std::path;
use support::events::{self, Event};
use img;
use glium::texture::Texture2d;
use std::io::prelude::*;
use std::fs::File;
use std::rc::Rc;

error_chain! {
    foreign_links {
        Io(::std::io::Error);
        Image(img::ImageError);
        Texture(glium::texture::TextureCreationError);
        Program(glium::program::ProgramChooserCreationError);
    }
}

/// Represets a window with OpenGL context.
///
/// This window provides image loading, rendering via `Window::next_frame(...)`,
/// and events via `Window::poll_events(...)`.
///
/// # Example
/// ```rust,no_run
/// extern crate nest;
/// use nest::{Window, Event};
///
/// fn main() {
///     let mut app = Window::new("Hello World", 640, 480);
///
///     loop {
///         // Note rust requires this code to be in a closure to please the borrow checker
///         {
///             let mut frame = app.next_frame();
///
///             // Render Code Goes Here
///
///             frame.finish();
///         }
///
///         for ev in app.poll_events() {
///             match ev {
///                 Event::Closed => break,
///                 _ => (),
///             }
///         }
///     }
/// }
/// ```
pub struct Window {
    pub(crate) display: glium::Display,
    events_loop: glium::glutin::EventsLoop,
    pub(crate) texture_program: glium::Program,
    pub(crate) plain_program: glium::Program,
}

impl Window {
    /// Create a new Window with a Title, and size (width / height) specified in
    /// pixels.
    ///
    /// # Pacnic
    /// This method will panic if there are any issues with creating the window
    /// or compiling the shaders. See the glium library for more specifics on
    /// window creation.
    ///
    /// # Example
    /// ```rust,no_run
    /// extern crate nest;
    /// # fn main() {
    /// use nest::Window;
    ///
    /// let mut app = Window::new("Hello World", 640, 480);
    /// # }
    /// ```
    pub fn new<S: Into<String>>(title: S, width: u32, height: u32) -> Result<Self> {
        let events_loop = glutin::EventsLoop::new();
        let window = glutin::WindowBuilder::new()
            .with_title(title)
            .with_dimensions(width, height);
        let context = glutin::ContextBuilder::new();
        let display =
            glium::Display::new(window, context, &events_loop).expect("Could not create Display");

        let texture_program = program!(&display,
            150 => {
                vertex: include_str!("shader/texture.vert"),
                geometry: include_str!("shader/texture.geom"),
                fragment: include_str!("shader/texture.frag"),
            },
        )?;

        let plain_program = program!(&display,
            150 => {
                vertex: include_str!("shader/plain.vert"),
                geometry: include_str!("shader/plain.geom"),
                fragment: include_str!("shader/plain.frag"),
            },
        )?;

        Ok(Window {
            display: display,
            events_loop: events_loop,
            texture_program: texture_program,
            plain_program: plain_program,
        })
    }

    /// Load an image from a file to be drawn by `Frame::draw_image(...)`.
    ///
    /// # Parameters
    ///
    /// * `path` - a path pointing to an image file
    ///
    /// # Example
    /// ```rust,no_run
    /// # extern crate nest;
    /// # fn main() {
    /// # use nest::Window;
    /// let mut app = Window::new("Hello World", 640, 480);
    /// let pic = app.load_image("res/city.jpg");
    /// # }
    /// ```
    pub fn load_image<'a, P: AsRef<path::Path>>(&self, path: P) -> Result<Rc<Texture2d>> {
        let mut buf = Vec::new();
        File::open(path)?.read_to_end(&mut buf)?;
        let image = img::load_from_memory(&buf[..])?.to_rgba();
        let dims = image.dimensions();
        Ok(Rc::new(Texture2d::new(
            &self.display,
            glium::texture::RawImage2d::from_raw_rgba(
                image.into_raw(),
                dims,
            ),
        )?))
    }

    /// Poll the window for events.
    ///
    /// # Example
    /// ```rust,no_run
    /// # extern crate nest;
    /// # use nest::Window;
    /// # fn main() {
    /// use nest::Event;
    ///
    /// let mut app = Window::new("Hello World", 640, 480);
    ///
    /// for ev in app.poll_events() {
    ///     match ev {
    ///         _ => ()
    ///     }
    /// }
    /// # }
    /// ```
    pub fn poll_events(&mut self) -> Vec<Event> {
        let mut events: Vec<Event> = Vec::new();

        self.events_loop.poll_events(|ev| {
            let event = events::translate(ev);
            match event {
                Event::Unsupported => (),
                event => events.push(event),
            }
        });

        events
    }

    /// Get the next frame for rendering.
    ///
    /// This method sets up the window and renderer for the next frame. The
    /// `Frame` object returned includes the methods for rendering to the frame
    /// along with delta time and window size.
    ///
    /// # Example
    /// ```rust,no_run
    /// # extern crate nest;
    /// # use nest::Window;
    /// # fn main() {
    /// let mut app = Window::new("Hello World", 640, 480);
    ///
    /// loop {
    ///     let mut frame = app.next_frame();
    ///
    ///     // Render code goes here
    ///
    ///     frame.finish();
    /// }
    /// # }
    /// ```
    pub fn next_frame(&self) -> Frame {
        Frame::new(self)
    }
}
<commit_msg>add display creation error<commit_after>use glium;
use frame::Frame;
use glium::glutin;
use std::path;
use support::events::{self, Event};
use img;
use glium::texture::Texture2d;
use std::io::prelude::*;
use std::fs::File;
use std::rc::Rc;

error_chain! {
    foreign_links {
        Io(::std::io::Error);
        Image(img::ImageError);
        Texture(glium::texture::TextureCreationError);
        Program(glium::program::ProgramChooserCreationError);
        DisplayCreation(glium::backend::glutin::DisplayCreationError);
    }
}

/// Represets a window with OpenGL context.
///
/// This window provides image loading, rendering via `Window::next_frame(...)`,
/// and events via `Window::poll_events(...)`.
///
/// # Example
/// ```rust,no_run
/// extern crate nest;
/// use nest::{Window, Event};
///
/// fn main() {
///     let mut app = Window::new("Hello World", 640, 480);
///
///     loop {
///         // Note rust requires this code to be in a closure to please the borrow checker
///         {
///             let mut frame = app.next_frame();
///
///             // Render Code Goes Here
///
///             frame.finish();
///         }
///
///         for ev in app.poll_events() {
///             match ev {
///                 Event::Closed => break,
///                 _ => (),
///             }
///         }
///     }
/// }
/// ```
pub struct Window {
    pub(crate) display: glium::Display,
    events_loop: glium::glutin::EventsLoop,
    pub(crate) texture_program: glium::Program,
    pub(crate) plain_program: glium::Program,
}

impl Window {
    /// Create a new Window with a Title, and size (width / height) specified in
    /// pixels.
    ///
    /// # Pacnic
    /// This method will panic if there are any issues with creating the window
    /// or compiling the shaders. See the glium library for more specifics on
    /// window creation.
    ///
    /// # Example
    /// ```rust,no_run
    /// extern crate nest;
    /// # fn main() {
    /// use nest::Window;
    ///
    /// let mut app = Window::new("Hello World", 640, 480);
    /// # }
    /// ```
    pub fn new<S: Into<String>>(title: S, width: u32, height: u32) -> Result<Self> {
        let events_loop = glutin::EventsLoop::new();
        let window = glutin::WindowBuilder::new()
            .with_title(title)
            .with_dimensions(width, height);
        let context = glutin::ContextBuilder::new();
        let display = glium::Display::new(window, context, &events_loop)?;

        let texture_program = program!(&display,
            150 => {
                vertex: include_str!("shader/texture.vert"),
                geometry: include_str!("shader/texture.geom"),
                fragment: include_str!("shader/texture.frag"),
            },
        )?;

        let plain_program = program!(&display,
            150 => {
                vertex: include_str!("shader/plain.vert"),
                geometry: include_str!("shader/plain.geom"),
                fragment: include_str!("shader/plain.frag"),
            },
        )?;

        Ok(Window {
            display: display,
            events_loop: events_loop,
            texture_program: texture_program,
            plain_program: plain_program,
        })
    }

    /// Load an image from a file to be drawn by `Frame::draw_image(...)`.
    ///
    /// # Parameters
    ///
    /// * `path` - a path pointing to an image file
    ///
    /// # Example
    /// ```rust,no_run
    /// # extern crate nest;
    /// # fn main() {
    /// # use nest::Window;
    /// let mut app = Window::new("Hello World", 640, 480);
    /// let pic = app.load_image("res/city.jpg");
    /// # }
    /// ```
    pub fn load_image<'a, P: AsRef<path::Path>>(&self, path: P) -> Result<Rc<Texture2d>> {
        let mut buf = Vec::new();
        File::open(path)?.read_to_end(&mut buf)?;
        let image = img::load_from_memory(&buf[..])?.to_rgba();
        let dims = image.dimensions();
        Ok(Rc::new(Texture2d::new(
            &self.display,
            glium::texture::RawImage2d::from_raw_rgba(
                image.into_raw(),
                dims,
            ),
        )?))
    }

    /// Poll the window for events.
    ///
    /// # Example
    /// ```rust,no_run
    /// # extern crate nest;
    /// # use nest::Window;
    /// # fn main() {
    /// use nest::Event;
    ///
    /// let mut app = Window::new("Hello World", 640, 480);
    ///
    /// for ev in app.poll_events() {
    ///     match ev {
    ///         _ => ()
    ///     }
    /// }
    /// # }
    /// ```
    pub fn poll_events(&mut self) -> Vec<Event> {
        let mut events: Vec<Event> = Vec::new();

        self.events_loop.poll_events(|ev| {
            let event = events::translate(ev);
            match event {
                Event::Unsupported => (),
                event => events.push(event),
            }
        });

        events
    }

    /// Get the next frame for rendering.
    ///
    /// This method sets up the window and renderer for the next frame. The
    /// `Frame` object returned includes the methods for rendering to the frame
    /// along with delta time and window size.
    ///
    /// # Example
    /// ```rust,no_run
    /// # extern crate nest;
    /// # use nest::Window;
    /// # fn main() {
    /// let mut app = Window::new("Hello World", 640, 480);
    ///
    /// loop {
    ///     let mut frame = app.next_frame();
    ///
    ///     // Render code goes here
    ///
    ///     frame.finish();
    /// }
    /// # }
    /// ```
    pub fn next_frame(&self) -> Frame {
        Frame::new(self)
    }
}
<|endoftext|>


<commit_before>use crate::SlotProcessingError;
use hashing::hash;
use int_to_bytes::int_to_bytes32;
use log::{debug, trace};
use ssz::{ssz_encode, TreeHash};
use types::*;

// TODO: define elsehwere.
const DOMAIN_PROPOSAL: u64 = 2;
const DOMAIN_EXIT: u64 = 3;
const DOMAIN_RANDAO: u64 = 4;
const PHASE_0_CUSTODY_BIT: bool = false;
const DOMAIN_ATTESTATION: u64 = 1;

#[derive(Debug, PartialEq)]
pub enum Error {
    DBError(String),
    StateAlreadyTransitioned,
    PresentSlotIsNone,
    UnableToDecodeBlock,
    MissingParentState(Hash256),
    InvalidParentState(Hash256),
    MissingBeaconBlock(Hash256),
    InvalidBeaconBlock(Hash256),
    MissingParentBlock(Hash256),
    StateSlotMismatch,
    BadBlockSignature,
    BadRandaoSignature,
    MaxProposerSlashingsExceeded,
    BadProposerSlashing,
    MaxAttestationsExceeded,
    InvalidAttestation(AttestationValidationError),
    NoBlockRoot,
    MaxDepositsExceeded,
    BadDeposit,
    MaxExitsExceeded,
    BadExit,
    BadCustodyReseeds,
    BadCustodyChallenges,
    BadCustodyResponses,
    BeaconStateError(BeaconStateError),
    SlotProcessingError(SlotProcessingError),
}

#[derive(Debug, PartialEq)]
pub enum AttestationValidationError {
    IncludedTooEarly,
    IncludedTooLate,
    WrongJustifiedSlot,
    WrongJustifiedRoot,
    BadLatestCrosslinkRoot,
    BadSignature,
    ShardBlockRootNotZero,
    NoBlockRoot,
    BeaconStateError(BeaconStateError),
}

macro_rules! ensure {
    ($condition: expr, $result: expr) => {
        if !$condition {
            return Err($result);
        }
    };
}

pub trait BlockProcessable {
    fn per_block_processing(&mut self, block: &BeaconBlock, spec: &ChainSpec) -> Result<(), Error>;
    fn per_block_processing_without_verifying_block_signature(
        &mut self,
        block: &BeaconBlock,
        spec: &ChainSpec,
    ) -> Result<(), Error>;
}

impl BlockProcessable for BeaconState {
    fn per_block_processing(&mut self, block: &BeaconBlock, spec: &ChainSpec) -> Result<(), Error> {
        per_block_processing_signature_optional(self, block, true, spec)
    }

    fn per_block_processing_without_verifying_block_signature(
        &mut self,
        block: &BeaconBlock,
        spec: &ChainSpec,
    ) -> Result<(), Error> {
        per_block_processing_signature_optional(self, block, false, spec)
    }
}

fn per_block_processing_signature_optional(
    state: &mut BeaconState,
    block: &BeaconBlock,
    verify_block_signature: bool,
    spec: &ChainSpec,
) -> Result<(), Error> {
    ensure!(block.slot == state.slot, Error::StateSlotMismatch);

    // Building the previous epoch could be delayed until an attestation from a previous epoch is
    // included. This is left for future optimisation.
    state.build_epoch_cache(RelativeEpoch::Previous, spec)?;
    state.build_epoch_cache(RelativeEpoch::Current, spec)?;

    /*
     * Proposer Signature
     */
    let block_proposer_index = state.get_beacon_proposer_index(block.slot, spec)?;
    let block_proposer = &state.validator_registry[block_proposer_index];

    if verify_block_signature {
        ensure!(
            bls_verify(
                &block_proposer.pubkey,
                &block.proposal_root(spec)[..],
                &block.signature,
                get_domain(&state.fork, state.current_epoch(spec), DOMAIN_PROPOSAL)
            ),
            Error::BadBlockSignature
        );
    }

    /*
     * RANDAO
     */
    ensure!(
        bls_verify(
            &block_proposer.pubkey,
            &int_to_bytes32(state.current_epoch(spec).as_u64()),
            &block.randao_reveal,
            get_domain(&state.fork, state.current_epoch(spec), DOMAIN_RANDAO)
        ),
        Error::BadRandaoSignature
    );

    // TODO: check this is correct.
    let new_mix = {
        let mut mix = state.latest_randao_mixes
            [state.slot.as_usize() % spec.latest_randao_mixes_length]
            .to_vec();
        mix.append(&mut ssz_encode(&block.randao_reveal));
        Hash256::from(&hash(&mix)[..])
    };

    state.latest_randao_mixes[state.slot.as_usize() % spec.latest_randao_mixes_length] = new_mix;

    /*
     * Eth1 data
     */
    // TODO: Eth1 data processing.

    /*
     * Proposer slashings
     */
    ensure!(
        block.body.proposer_slashings.len() as u64 <= spec.max_proposer_slashings,
        Error::MaxProposerSlashingsExceeded
    );
    for proposer_slashing in &block.body.proposer_slashings {
        let proposer = state
            .validator_registry
            .get(proposer_slashing.proposer_index as usize)
            .ok_or(Error::BadProposerSlashing)?;
        ensure!(
            proposer_slashing.proposal_data_1.slot == proposer_slashing.proposal_data_2.slot,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer_slashing.proposal_data_1.shard == proposer_slashing.proposal_data_2.shard,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer_slashing.proposal_data_1.block_root
                != proposer_slashing.proposal_data_2.block_root,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer.penalized_epoch > state.current_epoch(spec),
            Error::BadProposerSlashing
        );
        ensure!(
            bls_verify(
                &proposer.pubkey,
                &proposer_slashing.proposal_data_1.hash_tree_root(),
                &proposer_slashing.proposal_signature_1,
                get_domain(
                    &state.fork,
                    proposer_slashing
                        .proposal_data_1
                        .slot
                        .epoch(spec.epoch_length),
                    DOMAIN_PROPOSAL
                )
            ),
            Error::BadProposerSlashing
        );
        ensure!(
            bls_verify(
                &proposer.pubkey,
                &proposer_slashing.proposal_data_2.hash_tree_root(),
                &proposer_slashing.proposal_signature_2,
                get_domain(
                    &state.fork,
                    proposer_slashing
                        .proposal_data_2
                        .slot
                        .epoch(spec.epoch_length),
                    DOMAIN_PROPOSAL
                )
            ),
            Error::BadProposerSlashing
        );
        state.penalize_validator(proposer_slashing.proposer_index as usize, spec)?;
    }

    /*
     * Attestations
     */
    ensure!(
        block.body.attestations.len() as u64 <= spec.max_attestations,
        Error::MaxAttestationsExceeded
    );

    debug!("Verifying {} attestations.", block.body.attestations.len());

    for attestation in &block.body.attestations {
        validate_attestation(&state, attestation, spec)?;

        let pending_attestation = PendingAttestation {
            data: attestation.data.clone(),
            aggregation_bitfield: attestation.aggregation_bitfield.clone(),
            custody_bitfield: attestation.custody_bitfield.clone(),
            inclusion_slot: state.slot,
        };
        state.latest_attestations.push(pending_attestation);
    }

    /*
     * Deposits
     */
    ensure!(
        block.body.deposits.len() as u64 <= spec.max_deposits,
        Error::MaxDepositsExceeded
    );

    // TODO: verify deposit merkle branches.
    for deposit in &block.body.deposits {
        debug!(
            "Processing deposit for pubkey {:?}",
            deposit.deposit_data.deposit_input.pubkey
        );
        state
            .process_deposit(
                deposit.deposit_data.deposit_input.pubkey.clone(),
                deposit.deposit_data.amount,
                deposit
                    .deposit_data
                    .deposit_input
                    .proof_of_possession
                    .clone(),
                deposit.deposit_data.deposit_input.withdrawal_credentials,
                None,
                spec,
            )
            .map_err(|_| Error::BadDeposit)?;
    }

    /*
     * Exits
     */
    ensure!(
        block.body.exits.len() as u64 <= spec.max_exits,
        Error::MaxExitsExceeded
    );

    for exit in &block.body.exits {
        let validator = state
            .validator_registry
            .get(exit.validator_index as usize)
            .ok_or(Error::BadExit)?;
        ensure!(
            validator.exit_epoch
                > state.get_entry_exit_effect_epoch(state.current_epoch(spec), spec),
            Error::BadExit
        );
        ensure!(state.current_epoch(spec) >= exit.epoch, Error::BadExit);
        let exit_message = {
            let exit_struct = Exit {
                epoch: exit.epoch,
                validator_index: exit.validator_index,
                signature: spec.empty_signature.clone(),
            };
            exit_struct.hash_tree_root()
        };
        ensure!(
            bls_verify(
                &validator.pubkey,
                &exit_message,
                &exit.signature,
                get_domain(&state.fork, exit.epoch, DOMAIN_EXIT)
            ),
            Error::BadProposerSlashing
        );
        state.initiate_validator_exit(exit.validator_index as usize);
    }

    debug!("State transition complete.");

    Ok(())
}

pub fn validate_attestation(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
) -> Result<(), AttestationValidationError> {
    validate_attestation_signature_optional(state, attestation, spec, true)
}

pub fn validate_attestation_without_signature(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
) -> Result<(), AttestationValidationError> {
    validate_attestation_signature_optional(state, attestation, spec, false)
}

fn validate_attestation_signature_optional(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
    verify_signature: bool,
) -> Result<(), AttestationValidationError> {
    trace!(
        "validate_attestation_signature_optional: attestation epoch: {}",
        attestation.data.slot.epoch(spec.epoch_length)
    );
    ensure!(
        attestation.data.slot + spec.min_attestation_inclusion_delay <= state.slot,
        AttestationValidationError::IncludedTooEarly
    );
    ensure!(
        attestation.data.slot + spec.epoch_length >= state.slot,
        AttestationValidationError::IncludedTooLate
    );
    if attestation.data.slot >= state.current_epoch_start_slot(spec) {
        ensure!(
            attestation.data.justified_epoch == state.justified_epoch,
            AttestationValidationError::WrongJustifiedSlot
        );
    } else {
        ensure!(
            attestation.data.justified_epoch == state.previous_justified_epoch,
            AttestationValidationError::WrongJustifiedSlot
        );
    }
    ensure!(
        attestation.data.justified_block_root
            == *state
                .get_block_root(
                    attestation
                        .data
                        .justified_epoch
                        .start_slot(spec.epoch_length),
                    &spec
                )
                .ok_or(AttestationValidationError::NoBlockRoot)?,
        AttestationValidationError::WrongJustifiedRoot
    );
    let potential_crosslink = Crosslink {
        shard_block_root: attestation.data.shard_block_root,
        epoch: attestation.data.slot.epoch(spec.epoch_length),
    };
    ensure!(
        (attestation.data.latest_crosslink
            == state.latest_crosslinks[attestation.data.shard as usize])
            | (attestation.data.latest_crosslink == potential_crosslink),
        AttestationValidationError::BadLatestCrosslinkRoot
    );
    if verify_signature {
        let participants = state.get_attestation_participants(
            &attestation.data,
            &attestation.aggregation_bitfield,
            spec,
        )?;
        trace!(
            "slot: {}, shard: {}, participants: {:?}",
            attestation.data.slot,
            attestation.data.shard,
            participants
        );
        let mut group_public_key = AggregatePublicKey::new();
        for participant in participants {
            group_public_key.add(
                state.validator_registry[participant as usize]
                    .pubkey
                    .as_raw(),
            )
        }
        ensure!(
            attestation.verify_signature(
                &group_public_key,
                PHASE_0_CUSTODY_BIT,
                get_domain(
                    &state.fork,
                    attestation.data.slot.epoch(spec.epoch_length),
                    DOMAIN_ATTESTATION,
                )
            ),
            AttestationValidationError::BadSignature
        );
    }
    ensure!(
        attestation.data.shard_block_root == spec.zero_hash,
        AttestationValidationError::ShardBlockRootNotZero
    );
    Ok(())
}

fn get_domain(fork: &Fork, epoch: Epoch, domain_type: u64) -> u64 {
    fork.get_domain(epoch, domain_type)
}

fn bls_verify(pubkey: &PublicKey, message: &[u8], signature: &Signature, domain: u64) -> bool {
    signature.verify(message, domain, pubkey)
}

impl From<AttestationValidationError> for Error {
    fn from(e: AttestationValidationError) -> Error {
        Error::InvalidAttestation(e)
    }
}

impl From<BeaconStateError> for Error {
    fn from(e: BeaconStateError) -> Error {
        Error::BeaconStateError(e)
    }
}

impl From<SlotProcessingError> for Error {
    fn from(e: SlotProcessingError) -> Error {
        Error::SlotProcessingError(e)
    }
}

impl From<BeaconStateError> for AttestationValidationError {
    fn from(e: BeaconStateError) -> AttestationValidationError {
        AttestationValidationError::BeaconStateError(e)
    }
}
<commit_msg>Remove domain constants from block_processable<commit_after>use crate::SlotProcessingError;
use hashing::hash;
use int_to_bytes::int_to_bytes32;
use log::{debug, trace};
use ssz::{ssz_encode, TreeHash};
use types::*;

const PHASE_0_CUSTODY_BIT: bool = false;

#[derive(Debug, PartialEq)]
pub enum Error {
    DBError(String),
    StateAlreadyTransitioned,
    PresentSlotIsNone,
    UnableToDecodeBlock,
    MissingParentState(Hash256),
    InvalidParentState(Hash256),
    MissingBeaconBlock(Hash256),
    InvalidBeaconBlock(Hash256),
    MissingParentBlock(Hash256),
    StateSlotMismatch,
    BadBlockSignature,
    BadRandaoSignature,
    MaxProposerSlashingsExceeded,
    BadProposerSlashing,
    MaxAttestationsExceeded,
    InvalidAttestation(AttestationValidationError),
    NoBlockRoot,
    MaxDepositsExceeded,
    BadDeposit,
    MaxExitsExceeded,
    BadExit,
    BadCustodyReseeds,
    BadCustodyChallenges,
    BadCustodyResponses,
    BeaconStateError(BeaconStateError),
    SlotProcessingError(SlotProcessingError),
}

#[derive(Debug, PartialEq)]
pub enum AttestationValidationError {
    IncludedTooEarly,
    IncludedTooLate,
    WrongJustifiedSlot,
    WrongJustifiedRoot,
    BadLatestCrosslinkRoot,
    BadSignature,
    ShardBlockRootNotZero,
    NoBlockRoot,
    BeaconStateError(BeaconStateError),
}

macro_rules! ensure {
    ($condition: expr, $result: expr) => {
        if !$condition {
            return Err($result);
        }
    };
}

pub trait BlockProcessable {
    fn per_block_processing(&mut self, block: &BeaconBlock, spec: &ChainSpec) -> Result<(), Error>;
    fn per_block_processing_without_verifying_block_signature(
        &mut self,
        block: &BeaconBlock,
        spec: &ChainSpec,
    ) -> Result<(), Error>;
}

impl BlockProcessable for BeaconState {
    fn per_block_processing(&mut self, block: &BeaconBlock, spec: &ChainSpec) -> Result<(), Error> {
        per_block_processing_signature_optional(self, block, true, spec)
    }

    fn per_block_processing_without_verifying_block_signature(
        &mut self,
        block: &BeaconBlock,
        spec: &ChainSpec,
    ) -> Result<(), Error> {
        per_block_processing_signature_optional(self, block, false, spec)
    }
}

fn per_block_processing_signature_optional(
    state: &mut BeaconState,
    block: &BeaconBlock,
    verify_block_signature: bool,
    spec: &ChainSpec,
) -> Result<(), Error> {
    ensure!(block.slot == state.slot, Error::StateSlotMismatch);

    // Building the previous epoch could be delayed until an attestation from a previous epoch is
    // included. This is left for future optimisation.
    state.build_epoch_cache(RelativeEpoch::Previous, spec)?;
    state.build_epoch_cache(RelativeEpoch::Current, spec)?;

    /*
     * Proposer Signature
     */
    let block_proposer_index = state.get_beacon_proposer_index(block.slot, spec)?;
    let block_proposer = &state.validator_registry[block_proposer_index];

    if verify_block_signature {
        ensure!(
            bls_verify(
                &block_proposer.pubkey,
                &block.proposal_root(spec)[..],
                &block.signature,
                get_domain(&state.fork, state.current_epoch(spec), spec.domain_proposal)
            ),
            Error::BadBlockSignature
        );
    }

    /*
     * RANDAO
     */
    ensure!(
        bls_verify(
            &block_proposer.pubkey,
            &int_to_bytes32(state.current_epoch(spec).as_u64()),
            &block.randao_reveal,
            get_domain(&state.fork, state.current_epoch(spec), spec.domain_randao)
        ),
        Error::BadRandaoSignature
    );

    // TODO: check this is correct.
    let new_mix = {
        let mut mix = state.latest_randao_mixes
            [state.slot.as_usize() % spec.latest_randao_mixes_length]
            .to_vec();
        mix.append(&mut ssz_encode(&block.randao_reveal));
        Hash256::from(&hash(&mix)[..])
    };

    state.latest_randao_mixes[state.slot.as_usize() % spec.latest_randao_mixes_length] = new_mix;

    /*
     * Eth1 data
     */
    // TODO: Eth1 data processing.

    /*
     * Proposer slashings
     */
    ensure!(
        block.body.proposer_slashings.len() as u64 <= spec.max_proposer_slashings,
        Error::MaxProposerSlashingsExceeded
    );
    for proposer_slashing in &block.body.proposer_slashings {
        let proposer = state
            .validator_registry
            .get(proposer_slashing.proposer_index as usize)
            .ok_or(Error::BadProposerSlashing)?;
        ensure!(
            proposer_slashing.proposal_data_1.slot == proposer_slashing.proposal_data_2.slot,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer_slashing.proposal_data_1.shard == proposer_slashing.proposal_data_2.shard,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer_slashing.proposal_data_1.block_root
                != proposer_slashing.proposal_data_2.block_root,
            Error::BadProposerSlashing
        );
        ensure!(
            proposer.penalized_epoch > state.current_epoch(spec),
            Error::BadProposerSlashing
        );
        ensure!(
            bls_verify(
                &proposer.pubkey,
                &proposer_slashing.proposal_data_1.hash_tree_root(),
                &proposer_slashing.proposal_signature_1,
                get_domain(
                    &state.fork,
                    proposer_slashing
                        .proposal_data_1
                        .slot
                        .epoch(spec.epoch_length),
                    spec.domain_proposal
                )
            ),
            Error::BadProposerSlashing
        );
        ensure!(
            bls_verify(
                &proposer.pubkey,
                &proposer_slashing.proposal_data_2.hash_tree_root(),
                &proposer_slashing.proposal_signature_2,
                get_domain(
                    &state.fork,
                    proposer_slashing
                        .proposal_data_2
                        .slot
                        .epoch(spec.epoch_length),
                    spec.domain_proposal
                )
            ),
            Error::BadProposerSlashing
        );
        state.penalize_validator(proposer_slashing.proposer_index as usize, spec)?;
    }

    /*
     * Attestations
     */
    ensure!(
        block.body.attestations.len() as u64 <= spec.max_attestations,
        Error::MaxAttestationsExceeded
    );

    debug!("Verifying {} attestations.", block.body.attestations.len());

    for attestation in &block.body.attestations {
        validate_attestation(&state, attestation, spec)?;

        let pending_attestation = PendingAttestation {
            data: attestation.data.clone(),
            aggregation_bitfield: attestation.aggregation_bitfield.clone(),
            custody_bitfield: attestation.custody_bitfield.clone(),
            inclusion_slot: state.slot,
        };
        state.latest_attestations.push(pending_attestation);
    }

    /*
     * Deposits
     */
    ensure!(
        block.body.deposits.len() as u64 <= spec.max_deposits,
        Error::MaxDepositsExceeded
    );

    // TODO: verify deposit merkle branches.
    for deposit in &block.body.deposits {
        debug!(
            "Processing deposit for pubkey {:?}",
            deposit.deposit_data.deposit_input.pubkey
        );
        state
            .process_deposit(
                deposit.deposit_data.deposit_input.pubkey.clone(),
                deposit.deposit_data.amount,
                deposit
                    .deposit_data
                    .deposit_input
                    .proof_of_possession
                    .clone(),
                deposit.deposit_data.deposit_input.withdrawal_credentials,
                None,
                spec,
            )
            .map_err(|_| Error::BadDeposit)?;
    }

    /*
     * Exits
     */
    ensure!(
        block.body.exits.len() as u64 <= spec.max_exits,
        Error::MaxExitsExceeded
    );

    for exit in &block.body.exits {
        let validator = state
            .validator_registry
            .get(exit.validator_index as usize)
            .ok_or(Error::BadExit)?;
        ensure!(
            validator.exit_epoch
                > state.get_entry_exit_effect_epoch(state.current_epoch(spec), spec),
            Error::BadExit
        );
        ensure!(state.current_epoch(spec) >= exit.epoch, Error::BadExit);
        let exit_message = {
            let exit_struct = Exit {
                epoch: exit.epoch,
                validator_index: exit.validator_index,
                signature: spec.empty_signature.clone(),
            };
            exit_struct.hash_tree_root()
        };
        ensure!(
            bls_verify(
                &validator.pubkey,
                &exit_message,
                &exit.signature,
                get_domain(&state.fork, exit.epoch, spec.domain_exit)
            ),
            Error::BadProposerSlashing
        );
        state.initiate_validator_exit(exit.validator_index as usize);
    }

    debug!("State transition complete.");

    Ok(())
}

pub fn validate_attestation(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
) -> Result<(), AttestationValidationError> {
    validate_attestation_signature_optional(state, attestation, spec, true)
}

pub fn validate_attestation_without_signature(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
) -> Result<(), AttestationValidationError> {
    validate_attestation_signature_optional(state, attestation, spec, false)
}

fn validate_attestation_signature_optional(
    state: &BeaconState,
    attestation: &Attestation,
    spec: &ChainSpec,
    verify_signature: bool,
) -> Result<(), AttestationValidationError> {
    trace!(
        "validate_attestation_signature_optional: attestation epoch: {}",
        attestation.data.slot.epoch(spec.epoch_length)
    );
    ensure!(
        attestation.data.slot + spec.min_attestation_inclusion_delay <= state.slot,
        AttestationValidationError::IncludedTooEarly
    );
    ensure!(
        attestation.data.slot + spec.epoch_length >= state.slot,
        AttestationValidationError::IncludedTooLate
    );
    if attestation.data.slot >= state.current_epoch_start_slot(spec) {
        ensure!(
            attestation.data.justified_epoch == state.justified_epoch,
            AttestationValidationError::WrongJustifiedSlot
        );
    } else {
        ensure!(
            attestation.data.justified_epoch == state.previous_justified_epoch,
            AttestationValidationError::WrongJustifiedSlot
        );
    }
    ensure!(
        attestation.data.justified_block_root
            == *state
                .get_block_root(
                    attestation
                        .data
                        .justified_epoch
                        .start_slot(spec.epoch_length),
                    &spec
                )
                .ok_or(AttestationValidationError::NoBlockRoot)?,
        AttestationValidationError::WrongJustifiedRoot
    );
    let potential_crosslink = Crosslink {
        shard_block_root: attestation.data.shard_block_root,
        epoch: attestation.data.slot.epoch(spec.epoch_length),
    };
    ensure!(
        (attestation.data.latest_crosslink
            == state.latest_crosslinks[attestation.data.shard as usize])
            | (attestation.data.latest_crosslink == potential_crosslink),
        AttestationValidationError::BadLatestCrosslinkRoot
    );
    if verify_signature {
        let participants = state.get_attestation_participants(
            &attestation.data,
            &attestation.aggregation_bitfield,
            spec,
        )?;
        trace!(
            "slot: {}, shard: {}, participants: {:?}",
            attestation.data.slot,
            attestation.data.shard,
            participants
        );
        let mut group_public_key = AggregatePublicKey::new();
        for participant in participants {
            group_public_key.add(
                state.validator_registry[participant as usize]
                    .pubkey
                    .as_raw(),
            )
        }
        ensure!(
            attestation.verify_signature(
                &group_public_key,
                PHASE_0_CUSTODY_BIT,
                get_domain(
                    &state.fork,
                    attestation.data.slot.epoch(spec.epoch_length),
                    spec.domain_attestation,
                )
            ),
            AttestationValidationError::BadSignature
        );
    }
    ensure!(
        attestation.data.shard_block_root == spec.zero_hash,
        AttestationValidationError::ShardBlockRootNotZero
    );
    Ok(())
}

fn get_domain(fork: &Fork, epoch: Epoch, domain_type: u64) -> u64 {
    fork.get_domain(epoch, domain_type)
}

fn bls_verify(pubkey: &PublicKey, message: &[u8], signature: &Signature, domain: u64) -> bool {
    signature.verify(message, domain, pubkey)
}

impl From<AttestationValidationError> for Error {
    fn from(e: AttestationValidationError) -> Error {
        Error::InvalidAttestation(e)
    }
}

impl From<BeaconStateError> for Error {
    fn from(e: BeaconStateError) -> Error {
        Error::BeaconStateError(e)
    }
}

impl From<SlotProcessingError> for Error {
    fn from(e: SlotProcessingError) -> Error {
        Error::SlotProcessingError(e)
    }
}

impl From<BeaconStateError> for AttestationValidationError {
    fn from(e: BeaconStateError) -> AttestationValidationError {
        AttestationValidationError::BeaconStateError(e)
    }
}
<|endoftext|>


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

#![allow(clippy::unit_arg)]

use crate::{
    access_path::{AccessPath, Accesses},
    account_address::{AccountAddress, ADDRESS_LENGTH},
    account_state_blob::AccountStateBlob,
    byte_array::ByteArray,
    language_storage::StructTag,
};
#[cfg(any(test, feature = "testing"))]
use canonical_serialization::SimpleSerializer;
use canonical_serialization::{
    CanonicalDeserialize, CanonicalDeserializer, CanonicalSerialize, CanonicalSerializer,
    SimpleDeserializer,
};
use crypto::HashValue;
use failure::prelude::*;
#[cfg(any(test, feature = "testing"))]
use proptest_derive::Arbitrary;
use std::{
    collections::BTreeMap,
    convert::{TryFrom, TryInto},
};
#[cfg(any(test, feature = "testing"))]
use tiny_keccak::sha3_256;

/// An account object. This is the top-level entry in global storage. We'll never need to create an
/// `Account` struct, but if we did, it would look something like
/// pub struct Account {
/// // Address holding this account
/// address: Address,
/// // Struct types defined by this account
/// code: HashMap<Name, Code>,
/// // Resurces owned by this account
/// resoruces: HashMap<ObjectName, StructInstance>,
/// }

// LibraCoin
pub const COIN_MODULE_NAME: &str = "LibraCoin";
pub const COIN_STRUCT_NAME: &str = "T";

// Account
pub const ACCOUNT_MODULE_NAME: &str = "LibraAccount";
pub const ACCOUNT_STRUCT_NAME: &str = "T";

// Hash
pub const HASH_MODULE_NAME: &str = "Hash";

pub fn core_code_address() -> AccountAddress {
    AccountAddress::default()
}

pub fn association_address() -> AccountAddress {
    AccountAddress::from_hex_literal("0xA550C18")
        .expect("Parsing valid hex literal should always succeed")
}

pub fn coin_struct_tag() -> StructTag {
    StructTag {
        module: COIN_MODULE_NAME.to_string(),
        name: COIN_STRUCT_NAME.to_string(),
        address: core_code_address(),
        type_params: vec![],
    }
}

pub fn account_struct_tag() -> StructTag {
    StructTag {
        module: ACCOUNT_MODULE_NAME.to_string(),
        name: ACCOUNT_STRUCT_NAME.to_string(),
        address: core_code_address(),
        type_params: vec![],
    }
}

/// A Rust representation of an Event Handle Resource.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct EventHandle {
    /// The associated globally unique key that is used as the key to the EventStore.
    key: ByteArray,
    /// Number of events in the event stream.
    count: u64,
}

/// A Rust representation of an Account resource.
/// This is not how the Account is represented in the VM but it's a convenient representation.
#[derive(Debug, Default)]
#[cfg_attr(any(test, feature = "testing"), derive(Arbitrary))]
pub struct AccountResource {
    balance: u64,
    sequence_number: u64,
    authentication_key: ByteArray,
    delegated_withdrawal_capability: bool,
    sent_events: EventHandle,
    received_events: EventHandle,
}

impl EventHandle {
    /// Constructs a new Event Handle
    pub fn new(key: ByteArray, count: u64) -> Self {
        EventHandle { key, count }
    }

    /// Return the key to where this event is stored in EventStore.
    pub fn key(&self) -> &[u8] {
        self.key.as_bytes()
    }
    /// Return the counter for the handle
    pub fn count(&self) -> u64 {
        self.count
    }

    /// Return the AccessPath to where this event is stored in EventStore.
    /// TODO: Clean up this API by creating a new type wrapper for this new key type.
    pub fn as_access_path(&self) -> Result<AccessPath> {
        Ok(AccessPath::new(
            AccountAddress::try_from(self.key())?,
            vec![],
        ))
    }

    #[cfg(any(test, feature = "testing"))]
    /// Create a random event handle for testing
    pub fn random_handle(count: u64) -> Self {
        Self {
            key: ByteArray::new(HashValue::random().to_vec()),
            count,
        }
    }

    #[cfg(any(test, feature = "testing"))]
    /// Derive a unique handle by using an AccountAddress and a counter.
    pub fn new_from_address(addr: &AccountAddress, salt: u64) -> Self {
        let mut serializer: SimpleSerializer<Vec<u8>> = SimpleSerializer::new();
        serializer.encode_u64(salt).expect("Can't serialize salt");
        serializer
            .encode_struct(addr)
            .expect("Can't serialize address");
        let event_handle = sha3_256(&serializer.get_output());
        Self {
            key: ByteArray::new(event_handle.to_vec()),
            count: 0,
        }
    }
}

impl AccountResource {
    /// Constructs an Account resource.
    pub fn new(
        balance: u64,
        sequence_number: u64,
        authentication_key: ByteArray,
        delegated_withdrawal_capability: bool,
        sent_events: EventHandle,
        received_events: EventHandle,
    ) -> Self {
        AccountResource {
            balance,
            sequence_number,
            authentication_key,
            delegated_withdrawal_capability,
            sent_events,
            received_events,
        }
    }

    /// Given an account map (typically from storage) retrieves the Account resource associated.
    pub fn make_from(account_map: &BTreeMap<Vec<u8>, Vec<u8>>) -> Result<Self> {
        let ap = account_resource_path();
        match account_map.get(&ap) {
            Some(bytes) => SimpleDeserializer::deserialize(bytes),
            None => bail!("No data for {:?}", ap),
        }
    }

    /// Return the sequence_number field for the given AccountResource
    pub fn sequence_number(&self) -> u64 {
        self.sequence_number
    }

    /// Return the balance field for the given AccountResource
    pub fn balance(&self) -> u64 {
        self.balance
    }

    /// Return the authentication_key field for the given AccountResource
    pub fn authentication_key(&self) -> &ByteArray {
        &self.authentication_key
    }

    /// Return the sent_events handle for the given AccountResource
    pub fn sent_events(&self) -> &EventHandle {
        &self.sent_events
    }

    /// Return the received_events handle for the given AccountResource
    pub fn received_events(&self) -> &EventHandle {
        &self.received_events
    }

    /// Return the delegated_withdrawal_capability field for the given AccountResource
    pub fn delegated_withdrawal_capability(&self) -> bool {
        self.delegated_withdrawal_capability
    }

    pub fn get_event_handle_by_query_path(&self, query_path: &AccessPath) -> Result<&EventHandle> {
        if account_received_event_path() == query_path.path {
            Ok(&self.received_events)
        } else if account_sent_event_path() == query_path.path {
            Ok(&self.sent_events)
        } else {
            bail!("Unrecognized query path: {}", query_path);
        }
    }
}

impl CanonicalSerialize for EventHandle {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        serializer
            .encode_u64(self.count)?
            .encode_struct(&self.key)?;
        Ok(())
    }
}

impl CanonicalDeserialize for EventHandle {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let count = deserializer.decode_u64()?;
        let key = deserializer.decode_struct()?;
        Ok(EventHandle { count, key })
    }
}
impl CanonicalSerialize for AccountResource {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        // TODO(drussi): the order in which these fields are serialized depends on some
        // implementation details in the VM.
        serializer
            .encode_struct(&self.authentication_key)?
            .encode_u64(self.balance)?
            .encode_bool(self.delegated_withdrawal_capability)?
            .encode_struct(&self.received_events)?
            .encode_struct(&self.sent_events)?
            .encode_u64(self.sequence_number)?;
        Ok(())
    }
}

impl CanonicalDeserialize for AccountResource {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let authentication_key = deserializer.decode_struct()?;
        let balance = deserializer.decode_u64()?;
        let delegated_withdrawal_capability = deserializer.decode_bool()?;
        let received_events = deserializer.decode_struct()?;
        let sent_events = deserializer.decode_struct()?;
        let sequence_number = deserializer.decode_u64()?;

        Ok(AccountResource {
            balance,
            sequence_number,
            authentication_key,
            delegated_withdrawal_capability,
            sent_events,
            received_events,
        })
    }
}

pub fn get_account_resource_or_default(
    account_state: &Option<AccountStateBlob>,
) -> Result<AccountResource> {
    match account_state {
        Some(blob) => {
            let account_btree = blob.try_into()?;
            AccountResource::make_from(&account_btree)
        }
        None => Ok(AccountResource::default()),
    }
}

/// Return the path to the Account resource. It can be used to create an AccessPath for an
/// Account resource.
pub fn account_resource_path() -> Vec<u8> {
    AccessPath::resource_access_vec(
        &StructTag {
            address: core_code_address(),
            module: ACCOUNT_MODULE_NAME.to_string(),
            name: ACCOUNT_STRUCT_NAME.to_string(),
            type_params: vec![],
        },
        &Accesses::empty(),
    )
}

/// Return the path to the sent event counter for an Account resource.
/// It can be used to query the event DB for the given event.
pub fn account_sent_event_path() -> Vec<u8> {
    let mut path = account_resource_path();
    path.push(b'/');
    path.extend_from_slice(b"sent_events_count");
    path.push(b'/');
    path
}

/// Return the path to the received event counter for an Account resource.
/// It can be used to query the event DB for the given event.
pub fn account_received_event_path() -> Vec<u8> {
    let mut path = account_resource_path();
    path.push(b'/');
    path.extend_from_slice(b"received_events_count");
    path.push(b'/');
    path
}

/// Generic struct that represents an Account event.
/// Both SentPaymentEvent and ReceivedPaymentEvent are representable with this struct.
/// They have an AccountAddress for the sender or receiver and the amount transferred.
#[derive(Debug, Default)]
pub struct AccountEvent {
    account: AccountAddress,
    amount: u64,
}

impl AccountEvent {
    /// Get the account related to the event
    pub fn account(&self) -> AccountAddress {
        self.account
    }

    /// Get the amount sent or received
    pub fn amount(&self) -> u64 {
        self.amount
    }
}

impl CanonicalDeserialize for AccountEvent {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        // TODO: this is a horrible hack and we need to come up with a proper separation of
        // data/code so that we don't need the entire VM to read an Account event.
        // Also we cannot depend on the VM here as we would have a circular dependency and
        // it's not clear if this API should live in the VM or in types
        let amount = deserializer.decode_u64()?;
        let account =
            AccountAddress::try_from(deserializer.decode_bytes_with_len(ADDRESS_LENGTH as u32)?)?;

        Ok(AccountEvent { account, amount })
    }
}
<commit_msg>[Types] Fix warning<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![allow(clippy::unit_arg)]

use crate::{
    access_path::{AccessPath, Accesses},
    account_address::{AccountAddress, ADDRESS_LENGTH},
    account_state_blob::AccountStateBlob,
    byte_array::ByteArray,
    language_storage::StructTag,
};
#[cfg(any(test, feature = "testing"))]
use canonical_serialization::SimpleSerializer;
use canonical_serialization::{
    CanonicalDeserialize, CanonicalDeserializer, CanonicalSerialize, CanonicalSerializer,
    SimpleDeserializer,
};
#[cfg(any(test, feature = "testing"))]
use crypto::HashValue;
use failure::prelude::*;
#[cfg(any(test, feature = "testing"))]
use proptest_derive::Arbitrary;
use std::{
    collections::BTreeMap,
    convert::{TryFrom, TryInto},
};
#[cfg(any(test, feature = "testing"))]
use tiny_keccak::sha3_256;

/// An account object. This is the top-level entry in global storage. We'll never need to create an
/// `Account` struct, but if we did, it would look something like
/// pub struct Account {
/// // Address holding this account
/// address: Address,
/// // Struct types defined by this account
/// code: HashMap<Name, Code>,
/// // Resurces owned by this account
/// resoruces: HashMap<ObjectName, StructInstance>,
/// }

// LibraCoin
pub const COIN_MODULE_NAME: &str = "LibraCoin";
pub const COIN_STRUCT_NAME: &str = "T";

// Account
pub const ACCOUNT_MODULE_NAME: &str = "LibraAccount";
pub const ACCOUNT_STRUCT_NAME: &str = "T";

// Hash
pub const HASH_MODULE_NAME: &str = "Hash";

pub fn core_code_address() -> AccountAddress {
    AccountAddress::default()
}

pub fn association_address() -> AccountAddress {
    AccountAddress::from_hex_literal("0xA550C18")
        .expect("Parsing valid hex literal should always succeed")
}

pub fn coin_struct_tag() -> StructTag {
    StructTag {
        module: COIN_MODULE_NAME.to_string(),
        name: COIN_STRUCT_NAME.to_string(),
        address: core_code_address(),
        type_params: vec![],
    }
}

pub fn account_struct_tag() -> StructTag {
    StructTag {
        module: ACCOUNT_MODULE_NAME.to_string(),
        name: ACCOUNT_STRUCT_NAME.to_string(),
        address: core_code_address(),
        type_params: vec![],
    }
}

/// A Rust representation of an Event Handle Resource.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct EventHandle {
    /// The associated globally unique key that is used as the key to the EventStore.
    key: ByteArray,
    /// Number of events in the event stream.
    count: u64,
}

/// A Rust representation of an Account resource.
/// This is not how the Account is represented in the VM but it's a convenient representation.
#[derive(Debug, Default)]
#[cfg_attr(any(test, feature = "testing"), derive(Arbitrary))]
pub struct AccountResource {
    balance: u64,
    sequence_number: u64,
    authentication_key: ByteArray,
    delegated_withdrawal_capability: bool,
    sent_events: EventHandle,
    received_events: EventHandle,
}

impl EventHandle {
    /// Constructs a new Event Handle
    pub fn new(key: ByteArray, count: u64) -> Self {
        EventHandle { key, count }
    }

    /// Return the key to where this event is stored in EventStore.
    pub fn key(&self) -> &[u8] {
        self.key.as_bytes()
    }
    /// Return the counter for the handle
    pub fn count(&self) -> u64 {
        self.count
    }

    /// Return the AccessPath to where this event is stored in EventStore.
    /// TODO: Clean up this API by creating a new type wrapper for this new key type.
    pub fn as_access_path(&self) -> Result<AccessPath> {
        Ok(AccessPath::new(
            AccountAddress::try_from(self.key())?,
            vec![],
        ))
    }

    #[cfg(any(test, feature = "testing"))]
    /// Create a random event handle for testing
    pub fn random_handle(count: u64) -> Self {
        Self {
            key: ByteArray::new(HashValue::random().to_vec()),
            count,
        }
    }

    #[cfg(any(test, feature = "testing"))]
    /// Derive a unique handle by using an AccountAddress and a counter.
    pub fn new_from_address(addr: &AccountAddress, salt: u64) -> Self {
        let mut serializer: SimpleSerializer<Vec<u8>> = SimpleSerializer::new();
        serializer.encode_u64(salt).expect("Can't serialize salt");
        serializer
            .encode_struct(addr)
            .expect("Can't serialize address");
        let event_handle = sha3_256(&serializer.get_output());
        Self {
            key: ByteArray::new(event_handle.to_vec()),
            count: 0,
        }
    }
}

impl AccountResource {
    /// Constructs an Account resource.
    pub fn new(
        balance: u64,
        sequence_number: u64,
        authentication_key: ByteArray,
        delegated_withdrawal_capability: bool,
        sent_events: EventHandle,
        received_events: EventHandle,
    ) -> Self {
        AccountResource {
            balance,
            sequence_number,
            authentication_key,
            delegated_withdrawal_capability,
            sent_events,
            received_events,
        }
    }

    /// Given an account map (typically from storage) retrieves the Account resource associated.
    pub fn make_from(account_map: &BTreeMap<Vec<u8>, Vec<u8>>) -> Result<Self> {
        let ap = account_resource_path();
        match account_map.get(&ap) {
            Some(bytes) => SimpleDeserializer::deserialize(bytes),
            None => bail!("No data for {:?}", ap),
        }
    }

    /// Return the sequence_number field for the given AccountResource
    pub fn sequence_number(&self) -> u64 {
        self.sequence_number
    }

    /// Return the balance field for the given AccountResource
    pub fn balance(&self) -> u64 {
        self.balance
    }

    /// Return the authentication_key field for the given AccountResource
    pub fn authentication_key(&self) -> &ByteArray {
        &self.authentication_key
    }

    /// Return the sent_events handle for the given AccountResource
    pub fn sent_events(&self) -> &EventHandle {
        &self.sent_events
    }

    /// Return the received_events handle for the given AccountResource
    pub fn received_events(&self) -> &EventHandle {
        &self.received_events
    }

    /// Return the delegated_withdrawal_capability field for the given AccountResource
    pub fn delegated_withdrawal_capability(&self) -> bool {
        self.delegated_withdrawal_capability
    }

    pub fn get_event_handle_by_query_path(&self, query_path: &AccessPath) -> Result<&EventHandle> {
        if account_received_event_path() == query_path.path {
            Ok(&self.received_events)
        } else if account_sent_event_path() == query_path.path {
            Ok(&self.sent_events)
        } else {
            bail!("Unrecognized query path: {}", query_path);
        }
    }
}

impl CanonicalSerialize for EventHandle {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        serializer
            .encode_u64(self.count)?
            .encode_struct(&self.key)?;
        Ok(())
    }
}

impl CanonicalDeserialize for EventHandle {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let count = deserializer.decode_u64()?;
        let key = deserializer.decode_struct()?;
        Ok(EventHandle { count, key })
    }
}
impl CanonicalSerialize for AccountResource {
    fn serialize(&self, serializer: &mut impl CanonicalSerializer) -> Result<()> {
        // TODO(drussi): the order in which these fields are serialized depends on some
        // implementation details in the VM.
        serializer
            .encode_struct(&self.authentication_key)?
            .encode_u64(self.balance)?
            .encode_bool(self.delegated_withdrawal_capability)?
            .encode_struct(&self.received_events)?
            .encode_struct(&self.sent_events)?
            .encode_u64(self.sequence_number)?;
        Ok(())
    }
}

impl CanonicalDeserialize for AccountResource {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        let authentication_key = deserializer.decode_struct()?;
        let balance = deserializer.decode_u64()?;
        let delegated_withdrawal_capability = deserializer.decode_bool()?;
        let received_events = deserializer.decode_struct()?;
        let sent_events = deserializer.decode_struct()?;
        let sequence_number = deserializer.decode_u64()?;

        Ok(AccountResource {
            balance,
            sequence_number,
            authentication_key,
            delegated_withdrawal_capability,
            sent_events,
            received_events,
        })
    }
}

pub fn get_account_resource_or_default(
    account_state: &Option<AccountStateBlob>,
) -> Result<AccountResource> {
    match account_state {
        Some(blob) => {
            let account_btree = blob.try_into()?;
            AccountResource::make_from(&account_btree)
        }
        None => Ok(AccountResource::default()),
    }
}

/// Return the path to the Account resource. It can be used to create an AccessPath for an
/// Account resource.
pub fn account_resource_path() -> Vec<u8> {
    AccessPath::resource_access_vec(
        &StructTag {
            address: core_code_address(),
            module: ACCOUNT_MODULE_NAME.to_string(),
            name: ACCOUNT_STRUCT_NAME.to_string(),
            type_params: vec![],
        },
        &Accesses::empty(),
    )
}

/// Return the path to the sent event counter for an Account resource.
/// It can be used to query the event DB for the given event.
pub fn account_sent_event_path() -> Vec<u8> {
    let mut path = account_resource_path();
    path.push(b'/');
    path.extend_from_slice(b"sent_events_count");
    path.push(b'/');
    path
}

/// Return the path to the received event counter for an Account resource.
/// It can be used to query the event DB for the given event.
pub fn account_received_event_path() -> Vec<u8> {
    let mut path = account_resource_path();
    path.push(b'/');
    path.extend_from_slice(b"received_events_count");
    path.push(b'/');
    path
}

/// Generic struct that represents an Account event.
/// Both SentPaymentEvent and ReceivedPaymentEvent are representable with this struct.
/// They have an AccountAddress for the sender or receiver and the amount transferred.
#[derive(Debug, Default)]
pub struct AccountEvent {
    account: AccountAddress,
    amount: u64,
}

impl AccountEvent {
    /// Get the account related to the event
    pub fn account(&self) -> AccountAddress {
        self.account
    }

    /// Get the amount sent or received
    pub fn amount(&self) -> u64 {
        self.amount
    }
}

impl CanonicalDeserialize for AccountEvent {
    fn deserialize(deserializer: &mut impl CanonicalDeserializer) -> Result<Self> {
        // TODO: this is a horrible hack and we need to come up with a proper separation of
        // data/code so that we don't need the entire VM to read an Account event.
        // Also we cannot depend on the VM here as we would have a circular dependency and
        // it's not clear if this API should live in the VM or in types
        let amount = deserializer.decode_u64()?;
        let account =
            AccountAddress::try_from(deserializer.decode_bytes_with_len(ADDRESS_LENGTH as u32)?)?;

        Ok(AccountEvent { account, amount })
    }
}
<|endoftext|>


<commit_before>use std::{
    fmt::Write,
    path::{Path, PathBuf},
};

use regex::Regex;

#[derive(serde::Deserialize, Debug)]
struct RustcMessage {
    rendered: Option<String>,
    spans: Vec<Span>,
    level: String,
    message: String,
    children: Vec<RustcMessage>,
}

#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub(crate) enum Level {
    Error = 4,
    Warn = 3,
    Help = 2,
    Note = 1,
    /// Only used for "For more information about this error, try `rustc --explain EXXXX`".
    FailureNote = 0,
}

#[derive(Debug)]
pub(crate) struct Message {
    pub(crate) level: Level,
    pub(crate) message: String,
}

/// Information about macro expansion.
#[derive(serde::Deserialize, Debug)]
struct Expansion {
    span: Span,
}

#[derive(serde::Deserialize, Debug)]
struct Span {
    line_start: usize,
    file_name: PathBuf,
    expansion: Option<Box<Expansion>>,
}

impl std::str::FromStr for Level {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "ERROR" | "error" => Ok(Self::Error),
            "WARN" | "warning" => Ok(Self::Warn),
            "HELP" | "help" => Ok(Self::Help),
            "NOTE" | "note" => Ok(Self::Note),
            "failure-note" => Ok(Self::FailureNote),
            _ => Err(format!("unknown level `{s}`")),
        }
    }
}

#[derive(Debug)]
pub(crate) struct Diagnostics {
    /// Rendered and concatenated version of all diagnostics.
    /// This is equivalent to non-json diagnostics.
    pub rendered: String,
    /// Per line, a list of messages for that line.
    pub messages: Vec<Vec<Message>>,
    /// Messages not on any line (usually because they are from libstd)
    pub messages_from_unknown_file_or_line: Vec<Message>,
}

impl RustcMessage {
    fn line(&self, file: &Path) -> Option<usize> {
        self.spans.iter().find_map(|span| span.line(file))
    }

    /// Put the message and its children into the line-indexed list.
    fn insert_recursive(
        self,
        file: &Path,
        messages: &mut Vec<Vec<Message>>,
        messages_from_unknown_file_or_line: &mut Vec<Message>,
        line: Option<usize>,
    ) {
        let line = self.line(file).or(line);
        let msg = Message { level: self.level.parse().unwrap(), message: self.message };
        if let Some(line) = line {
            if messages.len() <= line {
                messages.resize_with(line + 1, Vec::new);
            }
            messages[line].push(msg);
        // All other messages go into the general bin, unless they are specifically of the
        // "aborting due to X previous errors" variety, as we never want to match those. They
        // only count the number of errors and provide no useful information about the tests.
        } else if !(msg.message.starts_with("aborting due to")
            && msg.message.contains("previous error"))
        {
            messages_from_unknown_file_or_line.push(msg);
        }
        for child in self.children {
            child.insert_recursive(file, messages, messages_from_unknown_file_or_line, line)
        }
    }
}

impl Span {
    /// Returns a line number *in the given file*, if possible.
    fn line(&self, file: &Path) -> Option<usize> {
        if self.file_name == file {
            Some(self.line_start)
        } else {
            self.expansion.as_ref()?.span.line(file)
        }
    }
}

pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> {
    let annotations = Regex::new(r"\s*//~.*").unwrap();
    annotations.replace_all(&rendered, "")
}

pub(crate) fn process(file: &Path, stderr: &[u8]) -> Diagnostics {
    let stderr = std::str::from_utf8(&stderr).unwrap();
    let mut rendered = String::new();
    let mut messages = vec![];
    let mut messages_from_unknown_file_or_line = vec![];
    for line in stderr.lines() {
        if line.starts_with("{") {
            match serde_json::from_str::<RustcMessage>(line) {
                Ok(msg) => {
                    write!(
                        rendered,
                        "{}",
                        filter_annotations_from_rendered(msg.rendered.as_ref().unwrap())
                    )
                    .unwrap();
                    msg.insert_recursive(
                        file,
                        &mut messages,
                        &mut messages_from_unknown_file_or_line,
                        None,
                    );
                }
                Err(err) =>
                    panic!("failed to parse rustc JSON output at line: {}\nerr:{}", line, err),
            }
        } else {
            // FIXME: do we want to throw interpreter stderr into a separate file?
            writeln!(rendered, "{}", line).unwrap();
        }
    }
    Diagnostics { rendered, messages, messages_from_unknown_file_or_line }
}
<commit_msg>add ICE error level<commit_after>use std::{
    fmt::Write,
    path::{Path, PathBuf},
};

use regex::Regex;

#[derive(serde::Deserialize, Debug)]
struct RustcMessage {
    rendered: Option<String>,
    spans: Vec<Span>,
    level: String,
    message: String,
    children: Vec<RustcMessage>,
}

#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub(crate) enum Level {
    Ice = 5,
    Error = 4,
    Warn = 3,
    Help = 2,
    Note = 1,
    /// Only used for "For more information about this error, try `rustc --explain EXXXX`".
    FailureNote = 0,
}

#[derive(Debug)]
pub(crate) struct Message {
    pub(crate) level: Level,
    pub(crate) message: String,
}

/// Information about macro expansion.
#[derive(serde::Deserialize, Debug)]
struct Expansion {
    span: Span,
}

#[derive(serde::Deserialize, Debug)]
struct Span {
    line_start: usize,
    file_name: PathBuf,
    expansion: Option<Box<Expansion>>,
}

impl std::str::FromStr for Level {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "ERROR" | "error" => Ok(Self::Error),
            "WARN" | "warning" => Ok(Self::Warn),
            "HELP" | "help" => Ok(Self::Help),
            "NOTE" | "note" => Ok(Self::Note),
            "failure-note" => Ok(Self::FailureNote),
            "error: internal compiler error" => Ok(Self::Ice),
            _ => Err(format!("unknown level `{s}`")),
        }
    }
}

#[derive(Debug)]
pub(crate) struct Diagnostics {
    /// Rendered and concatenated version of all diagnostics.
    /// This is equivalent to non-json diagnostics.
    pub rendered: String,
    /// Per line, a list of messages for that line.
    pub messages: Vec<Vec<Message>>,
    /// Messages not on any line (usually because they are from libstd)
    pub messages_from_unknown_file_or_line: Vec<Message>,
}

impl RustcMessage {
    fn line(&self, file: &Path) -> Option<usize> {
        self.spans.iter().find_map(|span| span.line(file))
    }

    /// Put the message and its children into the line-indexed list.
    fn insert_recursive(
        self,
        file: &Path,
        messages: &mut Vec<Vec<Message>>,
        messages_from_unknown_file_or_line: &mut Vec<Message>,
        line: Option<usize>,
    ) {
        let line = self.line(file).or(line);
        let msg = Message { level: self.level.parse().unwrap(), message: self.message };
        if let Some(line) = line {
            if messages.len() <= line {
                messages.resize_with(line + 1, Vec::new);
            }
            messages[line].push(msg);
        // All other messages go into the general bin, unless they are specifically of the
        // "aborting due to X previous errors" variety, as we never want to match those. They
        // only count the number of errors and provide no useful information about the tests.
        } else if !(msg.message.starts_with("aborting due to")
            && msg.message.contains("previous error"))
        {
            messages_from_unknown_file_or_line.push(msg);
        }
        for child in self.children {
            child.insert_recursive(file, messages, messages_from_unknown_file_or_line, line)
        }
    }
}

impl Span {
    /// Returns a line number *in the given file*, if possible.
    fn line(&self, file: &Path) -> Option<usize> {
        if self.file_name == file {
            Some(self.line_start)
        } else {
            self.expansion.as_ref()?.span.line(file)
        }
    }
}

pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> {
    let annotations = Regex::new(r"\s*//~.*").unwrap();
    annotations.replace_all(&rendered, "")
}

pub(crate) fn process(file: &Path, stderr: &[u8]) -> Diagnostics {
    let stderr = std::str::from_utf8(&stderr).unwrap();
    let mut rendered = String::new();
    let mut messages = vec![];
    let mut messages_from_unknown_file_or_line = vec![];
    for line in stderr.lines() {
        if line.starts_with("{") {
            match serde_json::from_str::<RustcMessage>(line) {
                Ok(msg) => {
                    write!(
                        rendered,
                        "{}",
                        filter_annotations_from_rendered(msg.rendered.as_ref().unwrap())
                    )
                    .unwrap();
                    msg.insert_recursive(
                        file,
                        &mut messages,
                        &mut messages_from_unknown_file_or_line,
                        None,
                    );
                }
                Err(err) =>
                    panic!("failed to parse rustc JSON output at line: {}\nerr:{}", line, err),
            }
        } else {
            // FIXME: do we want to throw interpreter stderr into a separate file?
            writeln!(rendered, "{}", line).unwrap();
        }
    }
    Diagnostics { rendered, messages, messages_from_unknown_file_or_line }
}
<|endoftext|>