<commit_before>use std::intrinsics::TypeId;
use std::any::AnyRefExt;
use std::default::Default;
use na::{Translate, Rotation, Cross};
use geometry::{Contact, contact, contacts};
use shape::{Shape, Ball, Plane, Cuboid, Capsule, Cone, Cylinder, Convex, Compound, Mesh, Segment,
            Triangle};
use math::{Scalar, Point, Vect, Isometry, HasInertiaMatrix};

macro_rules! dispatch_part(
    ($fname2: ident,
     $m1: ident, $g1: ident, $id1: ident,
     $m2: ident, $g2: ident, $id2: ident
     $(, $args: ident)*
     | $tg1: ty, $tg2: ty) => {
        if $id1 == TypeId::of::<$tg1>() && $id2 == TypeId::of::<$tg2>() {
            let exact_g1: &$tg1 = $g1.downcast_ref::<$tg1>().unwrap();
            let exact_g2: &$tg2 = $g2.downcast_ref::<$tg2>().unwrap();

            return $fname2($m1, exact_g1, $m2, exact_g2 $(, $args)*);
        }
    }
)

macro_rules! dispatch(
    ($dispatcher_name: ident, $fname: ident $(, $args: ident: $types: ty)* -> $result: ty) => {
        /// FIXME
        #[inline]
        pub fn $dispatcher_name<N, P, V, AV, M, I>(m1: &M, g1: &Shape<N, P, V, M>,
                                                   m2: &M, g2: &Shape<N, P, V, M>
                                                   $(, $args: $types)*)
                                                   -> $result
            where N:  Scalar,
                  P:  Point<N, V>,
                  V:  Vect<N> + Translate<P> + HasInertiaMatrix<I> + Cross<AV>,
                  AV: Vect<N>,
                  M:  Isometry<N, P, V> + Rotation<AV>,
                  I:  Send + Sync + Clone {
            let tg1 = g1.get_type_id();
            let tg2 = g2.get_type_id();

            // FIXME: use a hash-map instead of if-elses ?

            apply_to_all_shape_pair!(dispatch_part, $fname, m1, g1, tg1, m2, g2, tg2$(, $args)*)

            Default::default()
        }
    }
)

dispatch!(shape_against_shape, contact, prediction: N -> Option<Contact<N, P, V>>)
dispatch!(manifold_shape_against_shape, contacts, prediction: N, out: &mut Vec<Contact<N, P, V>> -> ())
<commit_msg>Fix comments for `shapes_against_shapes` and `manifold_shapes_against_shapes`.<commit_after>use std::intrinsics::TypeId;
use std::any::AnyRefExt;
use na::{Translate, Rotation, Cross};
use geometry::{Contact, contact, contacts};
use shape::{Shape, Ball, Plane, Cuboid, Capsule, Cone, Cylinder, Convex, Compound, Mesh, Segment,
            Triangle};
use math::{Scalar, Point, Vect, Isometry, HasInertiaMatrix};

macro_rules! dispatch_part(
    ($fname2: ident,
     $m1: ident, $g1: ident, $id1: ident,
     $m2: ident, $g2: ident, $id2: ident
     $(, $args: ident)*
     | $tg1: ty, $tg2: ty) => {
        if $id1 == TypeId::of::<$tg1>() && $id2 == TypeId::of::<$tg2>() {
            let exact_g1: &$tg1 = $g1.downcast_ref::<$tg1>().unwrap();
            let exact_g2: &$tg2 = $g2.downcast_ref::<$tg2>().unwrap();

            return $fname2($m1, exact_g1, $m2, exact_g2 $(, $args)*);
        }
    }
)

/// Best contact between two shapes (trait objects).
#[inline]
pub fn shape_against_shape<N, P, V, AV, M, I>(m1: &M, g1: &Shape<N, P, V, M>,
                                              m2: &M, g2: &Shape<N, P, V, M>,
                                              prediction: N)
                                              -> Option<Contact<N, P, V>>
    where N:  Scalar,
          P:  Point<N, V>,
          V:  Vect<N> + Translate<P> + HasInertiaMatrix<I> + Cross<AV>,
          AV: Vect<N>,
          M:  Isometry<N, P, V> + Rotation<AV>,
          I:  Send + Sync + Clone {
    let tg1 = g1.get_type_id();
    let tg2 = g2.get_type_id();

    // FIXME: use a hash-map instead of if-elses ?
    apply_to_all_shape_pair!(dispatch_part, contact, m1, g1, tg1, m2, g2, tg2, prediction)

    None
}

/// Contacts between two shapes (trait objects).
#[inline]
pub fn manifold_shape_against_shape<N, P, V, AV, M, I>(m1: &M, g1: &Shape<N, P, V, M>,
                                                       m2: &M, g2: &Shape<N, P, V, M>,
                                                       prediction: N,
                                                       out: &mut Vec<Contact<N, P, V>>)
    where N:  Scalar,
          P:  Point<N, V>,
          V:  Vect<N> + Translate<P> + HasInertiaMatrix<I> + Cross<AV>,
          AV: Vect<N>,
          M:  Isometry<N, P, V> + Rotation<AV>,
          I:  Send + Sync + Clone {
    let tg1 = g1.get_type_id();
    let tg2 = g2.get_type_id();

    // FIXME: use a hash-map instead of if-elses ?
    apply_to_all_shape_pair!(dispatch_part, contacts, m1, g1, tg1, m2, g2, tg2, prediction, out)
}
<|endoftext|>


<commit_before>use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::aspect_ratio::AspectRatio;
use crate::document::{AcquiredNodes, NodeId};
use crate::drawing_ctx::DrawingCtx;
use crate::element::{ElementResult, SetAttributes};
use crate::href::{is_href, set_href};
use crate::node::{CascadedValues, Node};
use crate::parsers::ParseValue;
use crate::properties::ComputedValues;
use crate::rect::Rect;
use crate::surface_utils::shared_surface::SharedImageSurface;
use crate::viewbox::ViewBox;
use crate::xml::Attributes;

use super::bounds::{Bounds, BoundsBuilder};
use super::context::{FilterContext, FilterOutput};
use super::{
    FilterEffect, FilterError, FilterResolveError, Primitive, PrimitiveParams, ResolvedPrimitive,
};

/// The `feImage` filter primitive.
#[derive(Default)]
pub struct FeImage {
    base: Primitive,
    params: ImageParams,
}

/// Resolved `feImage` primitive for rendering.
#[derive(Clone, Default)]
struct ImageParams {
    aspect: AspectRatio,
    href: Option<String>,
}

pub struct Image {
    params: ImageParams,
    feimage_values: ComputedValues,
}

impl Image {
    /// Renders the filter if the source is an existing node.
    fn render_node(
        &self,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
        bounds: Rect,
        node_id: &NodeId,
    ) -> Result<SharedImageSurface, FilterError> {
        let acquired = acquired_nodes
            .acquire(node_id)
            .map_err(|_| FilterError::InvalidInput)?;
        let referenced_node = acquired.get();

        // https://www.w3.org/TR/filter-effects/#feImageElement
        //
        // The filters spec says, "... otherwise [rendering a referenced object], the
        // referenced resource is rendered according to the behavior of the use element."
        // I think this means that we use the same cascading mode as <use>, i.e. the
        // referenced object inherits its properties from the feImage element.
        let cascaded = CascadedValues::new_from_values(&referenced_node, &self.feimage_values);

        let image = draw_ctx.draw_node_to_surface(
            &referenced_node,
            acquired_nodes,
            &cascaded,
            ctx.paffine(),
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let surface = ctx.source_graphic().paint_image(bounds, &image, None)?;

        Ok(surface)
    }

    /// Renders the filter if the source is an external image.
    fn render_external_image(
        &self,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        _draw_ctx: &DrawingCtx,
        bounds: &Bounds,
        url: &str,
    ) -> Result<SharedImageSurface, FilterError> {
        // FIXME: translate the error better here
        let image = acquired_nodes
            .lookup_image(url)
            .map_err(|_| FilterError::InvalidInput)?;

        let rect = self.params.aspect.compute(
            &ViewBox::from(Rect::from_size(
                f64::from(image.width()),
                f64::from(image.height()),
            )),
            &bounds.unclipped,
        );

        let surface = ctx
            .source_graphic()
            .paint_image(bounds.clipped, &image, Some(rect))?;

        Ok(surface)
    }
}

impl SetAttributes for FeImage {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        self.base.parse_no_inputs(attrs)?;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "preserveAspectRatio") => {
                    self.params.aspect = attr.parse(value)?
                }

                // "path" is used by some older Adobe Illustrator versions
                ref a if is_href(a) || *a == expanded_name!("", "path") => {
                    set_href(a, &mut self.params.href, value.to_string());
                }

                _ => (),
            }
        }

        Ok(())
    }
}

impl Image {
    pub fn render(
        &self,
        bounds_builder: BoundsBuilder,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterOutput, FilterError> {
        let bounds = bounds_builder.compute(ctx);

        let href = self.params.href.as_ref().ok_or(FilterError::InvalidInput)?;

        let surface = if let Ok(node_id) = NodeId::parse(href) {
            // if href has a fragment specified, render as a node
            self.render_node(ctx, acquired_nodes, draw_ctx, bounds.clipped, &node_id)
        } else {
            self.render_external_image(ctx, acquired_nodes, draw_ctx, &bounds, href)
        }?;

        Ok(FilterOutput {
            surface,
            bounds: bounds.clipped.into(),
        })
    }
}

impl FilterEffect for FeImage {
    fn resolve(
        &self,
        _acquired_nodes: &mut AcquiredNodes<'_>,
        node: &Node,
    ) -> Result<ResolvedPrimitive, FilterResolveError> {
        let cascaded = CascadedValues::new_from_node(node);
        let feimage_values = cascaded.get().clone();

        Ok(ResolvedPrimitive {
            primitive: self.base.clone(),
            params: PrimitiveParams::Image(Image {
                params: self.params.clone(),
                feimage_values,
            }),
        })
    }
}
<commit_msg>feImage: detect circular references now that primitives are resolved early<commit_after>use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::aspect_ratio::AspectRatio;
use crate::document::{AcquiredNodes, NodeId};
use crate::drawing_ctx::DrawingCtx;
use crate::element::{ElementResult, SetAttributes};
use crate::href::{is_href, set_href};
use crate::node::{CascadedValues, Node};
use crate::parsers::ParseValue;
use crate::properties::ComputedValues;
use crate::rect::Rect;
use crate::surface_utils::shared_surface::SharedImageSurface;
use crate::viewbox::ViewBox;
use crate::xml::Attributes;

use super::bounds::{Bounds, BoundsBuilder};
use super::context::{FilterContext, FilterOutput};
use super::{
    FilterEffect, FilterError, FilterResolveError, Primitive, PrimitiveParams, ResolvedPrimitive,
};

/// The `feImage` filter primitive.
#[derive(Default)]
pub struct FeImage {
    base: Primitive,
    params: ImageParams,
}

#[derive(Clone, Default)]
struct ImageParams {
    aspect: AspectRatio,
    href: Option<String>,
}

/// Resolved `feImage` primitive for rendering.
pub struct Image {
    aspect: AspectRatio,
    source: Source,
    feimage_values: ComputedValues,
}

/// What a feImage references for rendering.
enum Source {
    /// Nothing is referenced; ignore the filter.
    None,

    /// Reference to a node.
    Node(Node),

    /// Reference to an external image.  This is just a URL.
    ExternalImage(String),
}

impl Image {
    /// Renders the filter if the source is an existing node.
    fn render_node(
        &self,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
        bounds: Rect,
        referenced_node: &Node,
    ) -> Result<SharedImageSurface, FilterError> {
        // https://www.w3.org/TR/filter-effects/#feImageElement
        //
        // The filters spec says, "... otherwise [rendering a referenced object], the
        // referenced resource is rendered according to the behavior of the use element."
        // I think this means that we use the same cascading mode as <use>, i.e. the
        // referenced object inherits its properties from the feImage element.
        let cascaded = CascadedValues::new_from_values(&referenced_node, &self.feimage_values);

        let image = draw_ctx.draw_node_to_surface(
            &referenced_node,
            acquired_nodes,
            &cascaded,
            ctx.paffine(),
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let surface = ctx.source_graphic().paint_image(bounds, &image, None)?;

        Ok(surface)
    }

    /// Renders the filter if the source is an external image.
    fn render_external_image(
        &self,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        _draw_ctx: &DrawingCtx,
        bounds: &Bounds,
        url: &str,
    ) -> Result<SharedImageSurface, FilterError> {
        // FIXME: translate the error better here
        let image = acquired_nodes
            .lookup_image(url)
            .map_err(|_| FilterError::InvalidInput)?;

        let rect = self.aspect.compute(
            &ViewBox::from(Rect::from_size(
                f64::from(image.width()),
                f64::from(image.height()),
            )),
            &bounds.unclipped,
        );

        let surface = ctx
            .source_graphic()
            .paint_image(bounds.clipped, &image, Some(rect))?;

        Ok(surface)
    }
}

impl SetAttributes for FeImage {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        self.base.parse_no_inputs(attrs)?;

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "preserveAspectRatio") => {
                    self.params.aspect = attr.parse(value)?
                }

                // "path" is used by some older Adobe Illustrator versions
                ref a if is_href(a) || *a == expanded_name!("", "path") => {
                    set_href(a, &mut self.params.href, value.to_string());
                }

                _ => (),
            }
        }

        Ok(())
    }
}

impl Image {
    pub fn render(
        &self,
        bounds_builder: BoundsBuilder,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterOutput, FilterError> {
        let bounds = bounds_builder.compute(ctx);

        let surface = match &self.source {
            Source::None => return Err(FilterError::InvalidInput),

            Source::Node(node) => {
                if let Ok(acquired) = acquired_nodes.acquire_ref(node) {
                    self.render_node(
                        ctx,
                        acquired_nodes,
                        draw_ctx,
                        bounds.clipped,
                        &acquired.get(),
                    )?
                } else {
                    return Err(FilterError::InvalidInput);
                }
            }

            Source::ExternalImage(ref href) => {
                self.render_external_image(ctx, acquired_nodes, draw_ctx, &bounds, href)?
            }
        };

        Ok(FilterOutput {
            surface,
            bounds: bounds.clipped.into(),
        })
    }
}

impl FilterEffect for FeImage {
    fn resolve(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        node: &Node,
    ) -> Result<ResolvedPrimitive, FilterResolveError> {
        let cascaded = CascadedValues::new_from_node(node);
        let feimage_values = cascaded.get().clone();

        let source = match self.params.href {
            None => Source::None,

            Some(ref s) => {
                if let Ok(node_id) = NodeId::parse(s) {
                    acquired_nodes
                        .acquire(&node_id)
                        .map(|acquired| Source::Node(acquired.get().clone()))
                        .unwrap_or(Source::None)
                } else {
                    Source::ExternalImage(s.to_string())
                }
            }
        };

        Ok(ResolvedPrimitive {
            primitive: self.base.clone(),
            params: PrimitiveParams::Image(Image {
                aspect: self.params.aspect,
                source,
                feimage_values,
            }),
        })
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use std::error;
use std::result;
use std::fmt;

#[derive(Debug, PartialEq)]
/// Crowbook's error type
pub enum Error {
    /// An error in Parsing markdown file
    Parser(String),
    /// An error in parsing a book configuration file
    ConfigParser(&'static str, String), //error, line
    /// An error when a file is not found
    FileNotFound(String), //file
    /// An error in a renderer
    Render(String),
    /// An error during "zipping" processus
    Zipper(String),
    /// An error relative to BookOption convertion (usually a type error)
    BookOption(String),
    /// An invalid option
    InvalidOption(String),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ConfigParser(ref s, _)  => s,
            Error::Parser(ref s) | Error::Zipper(ref s) | Error::BookOption(ref s) | Error::InvalidOption(ref s) | Error::Render(ref s) => s,
            Error::FileNotFound(_) => "File not found",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Parser(ref s) => {
                try!(f.write_str("Error parsing markdown: "));
                f.write_str(&s)
            },
            Error::ConfigParser(ref s, ref line) => {
                try!(f.write_str("Error parsing configuration file: "));
                try!(f.write_str(s));
                try!(f.write_str(" in: "));
                f.write_str(line)
            },
            Error::FileNotFound(ref file) => {
                try!(f.write_str("File not found: "));
                f.write_str(file)
            },
            Error::Render(ref s) => {
                try!(f.write_str("Error during rendering: "));
                f.write_str(s)
            },
            Error::Zipper(ref s) => {
                try!(f.write_str("Error during temporary files editing: "));
                f.write_str(s)
            },
            Error::BookOption(ref s) => {
                try!(f.write_str("Error converting BookOption: "));
                f.write_str(s)
            },
            Error::InvalidOption(ref s) => {
                try!(f.write_str("Error accessing book option: "));
                f.write_str(s)
            },
        }
    }
}

/// Crowbook's Result type, used by many methods that can fail
pub type Result<T> = result::Result<T, Error>;

<commit_msg>Fix code formatting<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use std::error;
use std::result;
use std::fmt;

#[derive(Debug, PartialEq)]
/// Crowbook's error type
pub enum Error {
    /// An error in Parsing markdown file
    Parser(String),
    /// An error in parsing a book configuration file
    ConfigParser(&'static str, String), //error, line
    /// An error when a file is not found
    FileNotFound(String), //file
    /// An error in a renderer
    Render(String),
    /// An error during "zipping" processus
    Zipper(String),
    /// An error relative to BookOption convertion (usually a type error)
    BookOption(String),
    /// An invalid option
    InvalidOption(String),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ConfigParser(ref s, _)  => s,
            Error::Parser(ref s) | Error::Zipper(ref s) | Error::BookOption(ref s)
                | Error::InvalidOption(ref s) | Error::Render(ref s) => s,
            Error::FileNotFound(_) => "File not found",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Parser(ref s) => {
                try!(f.write_str("Error parsing markdown: "));
                f.write_str(&s)
            },
            Error::ConfigParser(ref s, ref line) => {
                try!(f.write_str("Error parsing configuration file: "));
                try!(f.write_str(s));
                try!(f.write_str(" in: "));
                f.write_str(line)
            },
            Error::FileNotFound(ref file) => {
                try!(f.write_str("File not found: "));
                f.write_str(file)
            },
            Error::Render(ref s) => {
                try!(f.write_str("Error during rendering: "));
                f.write_str(s)
            },
            Error::Zipper(ref s) => {
                try!(f.write_str("Error during temporary files editing: "));
                f.write_str(s)
            },
            Error::BookOption(ref s) => {
                try!(f.write_str("Error converting BookOption: "));
                f.write_str(s)
            },
            Error::InvalidOption(ref s) => {
                try!(f.write_str("Error accessing book option: "));
                f.write_str(s)
            },
        }
    }
}

/// Crowbook's Result type, used by many methods that can fail
pub type Result<T> = result::Result<T, Error>;

<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use std::error;
use std::result;
use std::fmt;

#[derive(Debug, PartialEq)]
/// Crowbook's error type
pub enum Error {
    /// An error in Parsing markdown file
    Parser(String),
    /// An error in parsing a book configuration file
    ConfigParser(&'static str, String), //error, line
    /// An error when a file is not found
    FileNotFound(String), //file
    /// An error in a renderer
    Render(String),
    /// An error during "zipping" processus
    Zipper(String),
    /// An error relative to BookOption convertion (usually a type error)
    BookOption(String),
    /// An invalid option
    InvalidOption(String),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ConfigParser(ref s, _)  => s,
            Error::Parser(ref s) | Error::Zipper(ref s) | Error::BookOption(ref s)
                | Error::InvalidOption(ref s) | Error::Render(ref s) => s,
            Error::FileNotFound(_) => "File not found",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Parser(ref s) => {
                try!(f.write_str("Error parsing markdown: "));
                f.write_str(&s)
            },
            Error::ConfigParser(ref s, ref line) => {
                try!(f.write_str("Error parsing configuration file: "));
                try!(f.write_str(s));
                try!(f.write_str(" in: "));
                f.write_str(line)
            },
            Error::FileNotFound(ref file) => {
                try!(f.write_str("File not found: "));
                f.write_str(file)
            },
            Error::Render(ref s) => {
                try!(f.write_str("Error during rendering: "));
                f.write_str(s)
            },
            Error::Zipper(ref s) => {
                try!(f.write_str("Error during temporary files editing: "));
                f.write_str(s)
            },
            Error::BookOption(ref s) => {
                try!(f.write_str("Error converting BookOption: "));
                f.write_str(s)
            },
            Error::InvalidOption(ref s) => {
                try!(f.write_str("Error accessing book option: "));
                f.write_str(s)
            },
        }
    }
}

/// Crowbook's Result type, used by many methods that can fail
pub type Result<T> = result::Result<T, Error>;

<commit_msg>Add Source struct<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use std::error;
use std::result;
use std::fmt;

#[derive(Debug)]
/// Source of an error file
pub struct Source {
    /// File name of the source
    file: Option<String>,
    /// Line number of the source
    line: Option<u32>,
}

impl Source {
    /// Create an empty source, with both fields set to None
    pub fn empty() -> Source {
        Source { file: None, line: None }
    }

    /// Create a new source pointing to file
    pub fn new(s: &str) -> Source {
        Source { file: Some(String::from(s)), line: None }
    }

    /// Sets line number of a source
    pub fn line(mut self, line: u32) -> Source {
        self.line = Some(line);
        self
    }
}

#[derive(Debug, PartialEq)]
/// Crowbook's error type
pub enum Error {
    /// An error in Parsing markdown file
    Parser(String),
    /// An error in parsing a book configuration file
    ConfigParser(&'static str, String), //error, line
    /// An error when a file is not found
    FileNotFound(String), //file
    /// An error in a renderer
    Render(String),
    /// An error during "zipping" processus
    Zipper(String),
    /// An error relative to BookOption convertion (usually a type error)
    BookOption(String),
    /// An invalid option
    InvalidOption(String),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ConfigParser(ref s, _)  => s,
            Error::Parser(ref s) | Error::Zipper(ref s) | Error::BookOption(ref s)
                | Error::InvalidOption(ref s) | Error::Render(ref s) => s,
            Error::FileNotFound(_) => "File not found",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Parser(ref s) => {
                try!(f.write_str("Error parsing markdown: "));
                f.write_str(&s)
            },
            Error::ConfigParser(ref s, ref line) => {
                try!(f.write_str("Error parsing configuration file: "));
                try!(f.write_str(s));
                try!(f.write_str(" in: "));
                f.write_str(line)
            },
            Error::FileNotFound(ref file) => {
                try!(f.write_str("File not found: "));
                f.write_str(file)
            },
            Error::Render(ref s) => {
                try!(f.write_str("Error during rendering: "));
                f.write_str(s)
            },
            Error::Zipper(ref s) => {
                try!(f.write_str("Error during temporary files editing: "));
                f.write_str(s)
            },
            Error::BookOption(ref s) => {
                try!(f.write_str("Error converting BookOption: "));
                f.write_str(s)
            },
            Error::InvalidOption(ref s) => {
                try!(f.write_str("Error accessing book option: "));
                f.write_str(s)
            },
        }
    }
}

/// Crowbook's Result type, used by many methods that can fail
pub type Result<T> = result::Result<T, Error>;

<|endoftext|>


<commit_before>/// The Validator Client service.
///
/// Connects to a beacon node and negotiates the correct chain id.
///
/// Once connected, the service loads known validators keypairs from disk. Every slot,
/// the service pings the beacon node, asking for new duties for each of the validators.
///
/// When a validator needs to either produce a block or sign an attestation, it requests the
/// data from the beacon node and performs the signing before publishing the block to the beacon
/// node.
use crate::attestation_producer::AttestationProducer;
use crate::block_producer::{BeaconBlockGrpcClient, BlockProducer};
use crate::config::Config as ValidatorConfig;
use crate::duties::{BeaconNodeDuties, DutiesManager, EpochDutiesMap};
use crate::error as error_chain;
use crate::signer::Signer;
use bls::Keypair;
use eth2_config::Eth2Config;
use grpcio::{ChannelBuilder, EnvBuilder};
use protos::services::Empty;
use protos::services_grpc::{
    AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient,
    ValidatorServiceClient,
};
use slog::{crit, error, info, warn};
use slot_clock::{SlotClock, SystemTimeSlotClock};
use std::marker::PhantomData;
use std::sync::Arc;
use std::sync::RwLock;
use std::time::{Duration, Instant};
use tokio::prelude::*;
use tokio::runtime::Builder;
use tokio::timer::Interval;
use tokio_timer::clock::Clock;
use types::{ChainSpec, Epoch, EthSpec, Fork, Slot};

/// A fixed amount of time after a slot to perform operations. This gives the node time to complete
/// per-slot processes.
const TIME_DELAY_FROM_SLOT: Duration = Duration::from_millis(100);

/// The validator service. This is the main thread that executes and maintains validator
/// duties.
//TODO: Generalize the BeaconNode types to use testing
pub struct Service<B: BeaconNodeDuties + 'static, S: Signer + 'static, E: EthSpec> {
    /// The node's current fork version we are processing on.
    fork: Fork,
    /// The slot clock for this service.
    slot_clock: SystemTimeSlotClock,
    /// The current slot we are processing.
    current_slot: Slot,
    slots_per_epoch: u64,
    /// The chain specification for this clients instance.
    spec: Arc<ChainSpec>,
    /// The duties manager which maintains the state of when to perform actions.
    duties_manager: Arc<DutiesManager<B, S>>,
    // GRPC Clients
    /// The beacon block GRPC client.
    beacon_block_client: Arc<BeaconBlockGrpcClient>,
    /// The attester GRPC client.
    attestation_client: Arc<AttestationServiceClient>,
    /// The validator client logger.
    log: slog::Logger,
    _phantom: PhantomData<E>,
}

impl<B: BeaconNodeDuties + 'static, S: Signer + 'static, E: EthSpec> Service<B, S, E> {
    ///  Initial connection to the beacon node to determine its properties.
    ///
    ///  This tries to connect to a beacon node. Once connected, it initialised the gRPC clients
    ///  and returns an instance of the service.
    fn initialize_service(
        client_config: ValidatorConfig,
        eth2_config: Eth2Config,
        log: slog::Logger,
    ) -> error_chain::Result<Service<ValidatorServiceClient, Keypair, E>> {
        let server_url = format!(
            "{}:{}",
            client_config.server, client_config.server_grpc_port
        );

        let env = Arc::new(EnvBuilder::new().build());
        // Beacon node gRPC beacon node endpoints.
        let beacon_node_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&server_url);
            BeaconNodeServiceClient::new(ch)
        };

        // retrieve node information and validate the beacon node
        let node_info = loop {
            match beacon_node_client.info(&Empty::new()) {
                Err(e) => {
                    let retry_seconds = 5;
                    warn!(
                        log,
                        "Could not connect to beacon node";
                        "error" => format!("{:?}", e),
                        "retry_in" => format!("{} seconds", retry_seconds),
                    );
                    std::thread::sleep(Duration::from_secs(retry_seconds));
                    continue;
                }
                Ok(info) => {
                    // verify the node's network id
                    if eth2_config.spec.network_id != info.network_id as u8 {
                        error!(
                            log,
                            "Beacon Node's genesis time is in the future. No work to do.\n Exiting"
                        );
                        return Err(format!("Beacon node has the wrong chain id. Expected chain id: {}, node's chain id: {}", eth2_config.spec.network_id, info.network_id).into());
                    }
                    break info;
                }
            };
        };

        // build requisite objects to form Self
        let genesis_time = node_info.get_genesis_time();
        let genesis_slot = Slot::from(node_info.get_genesis_slot());

        info!(
            log,
            "Beacon node connected";
            "version" => node_info.version.clone(),
            "network_id" => node_info.network_id,
            "genesis_time" => genesis_time
        );

        let proto_fork = node_info.get_fork();
        let mut previous_version: [u8; 4] = [0; 4];
        let mut current_version: [u8; 4] = [0; 4];
        previous_version.copy_from_slice(&proto_fork.get_previous_version()[..4]);
        current_version.copy_from_slice(&proto_fork.get_current_version()[..4]);
        let fork = Fork {
            previous_version,
            current_version,
            epoch: Epoch::from(proto_fork.get_epoch()),
        };

        // initialize the RPC clients

        // Beacon node gRPC beacon block endpoints.
        let beacon_block_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&server_url);
            let beacon_block_service_client = Arc::new(BeaconBlockServiceClient::new(ch));
            // a wrapper around the service client to implement the beacon block node trait
            Arc::new(BeaconBlockGrpcClient::new(beacon_block_service_client))
        };

        // Beacon node gRPC validator endpoints.
        let validator_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&server_url);
            Arc::new(ValidatorServiceClient::new(ch))
        };

        //Beacon node gRPC attester endpoints.
        let attestation_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&server_url);
            Arc::new(AttestationServiceClient::new(ch))
        };

        // build the validator slot clock
        let slot_clock = SystemTimeSlotClock::from_eth2_genesis(
            genesis_slot,
            genesis_time,
            Duration::from_millis(eth2_config.spec.milliseconds_per_slot),
        )
        .map_err::<error_chain::Error, _>(|e| {
            format!("Unable to start slot clock: {}.", e).into()
        })?;

        let current_slot = slot_clock.now().unwrap_or_else(|| Slot::new(0));

        /* Generate the duties manager */

        // Load generated keypairs
        let keypairs = Arc::new(client_config.fetch_keys(&log)?);

        let slots_per_epoch = E::slots_per_epoch();

        // TODO: keypairs are randomly generated; they should be loaded from a file or generated.
        // https://github.com/sigp/lighthouse/issues/160
        //let keypairs = Arc::new(generate_deterministic_keypairs(8));

        // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty)
        // where EpochDuty contains slot numbers and attestation data that each validator needs to
        // produce work on.
        let duties_map = RwLock::new(EpochDutiesMap::new(slots_per_epoch));

        // builds a manager which maintains the list of current duties for all known validators
        // and can check when a validator needs to perform a task.
        let duties_manager = Arc::new(DutiesManager {
            duties_map,
            // these are abstract objects capable of signing
            signers: keypairs,
            beacon_node: validator_client,
        });

        let spec = Arc::new(eth2_config.spec);

        Ok(Service {
            fork,
            slot_clock,
            current_slot,
            slots_per_epoch,
            spec,
            duties_manager,
            beacon_block_client,
            attestation_client,
            log,
            _phantom: PhantomData,
        })
    }

    /// Initialise the service then run the core thread.
    // TODO: Improve handling of generic BeaconNode types, to stub grpcClient
    pub fn start(
        client_config: ValidatorConfig,
        eth2_config: Eth2Config,
        log: slog::Logger,
    ) -> error_chain::Result<()> {
        // connect to the node and retrieve its properties and initialize the gRPC clients
        let mut service = Service::<ValidatorServiceClient, Keypair, E>::initialize_service(
            client_config,
            eth2_config,
            log.clone(),
        )?;

        // we have connected to a node and established its parameters. Spin up the core service

        // set up the validator service runtime
        let mut runtime = Builder::new()
            .clock(Clock::system())
            .name_prefix("validator-client-")
            .build()
            .map_err(|e| format!("Tokio runtime failed: {}", e))?;

        let duration_to_next_slot = service
            .slot_clock
            .duration_to_next_slot()
            .ok_or_else::<error_chain::Error, _>(|| {
                "Unable to determine duration to next slot. Exiting.".into()
            })?;

        // set up the validator work interval - start at next slot and proceed every slot
        let interval = {
            // Set the interval to start at the next slot, and every slot after
            let slot_duration = Duration::from_millis(service.spec.milliseconds_per_slot);
            //TODO: Handle checked add correctly
            Interval::new(Instant::now() + duration_to_next_slot, slot_duration)
        };

        if service.slot_clock.now().is_none() {
            warn!(
                log,
                "Starting node prior to genesis";
            );
        }

        info!(
            log,
            "Waiting for next slot";
            "seconds_to_wait" => duration_to_next_slot.as_secs()
        );

        /* kick off the core service */
        runtime.block_on(
            interval
                .for_each(move |_| {
                    // wait for node to process
                    std::thread::sleep(TIME_DELAY_FROM_SLOT);
                    // if a non-fatal error occurs, proceed to the next slot.
                    let _ignore_error = service.per_slot_execution();
                    // completed a slot process
                    Ok(())
                })
                .map_err(|e| format!("Service thread failed: {:?}", e)),
        )?;
        // validator client exited
        Ok(())
    }

    /// The execution logic that runs every slot.
    // Errors are logged to output, and core execution continues unless fatal errors occur.
    fn per_slot_execution(&mut self) -> error_chain::Result<()> {
        /* get the new current slot and epoch */
        self.update_current_slot()?;

        /* check for new duties */
        self.check_for_duties();

        /* process any required duties for validators */
        self.process_duties();

        Ok(())
    }

    /// Updates the known current slot and epoch.
    fn update_current_slot(&mut self) -> error_chain::Result<()> {
        let current_slot = self
            .slot_clock
            .now()
            .ok_or_else::<error_chain::Error, _>(|| {
                "Genesis is not in the past. Exiting.".into()
            })?;

        let current_epoch = current_slot.epoch(self.slots_per_epoch);

        // this is a non-fatal error. If the slot clock repeats, the node could
        // have been slow to process the previous slot and is now duplicating tasks.
        // We ignore duplicated but raise a critical error.
        if current_slot <= self.current_slot {
            crit!(
                self.log,
                "The validator tried to duplicate a slot. Likely missed the previous slot"
            );
            return Err("Duplicate slot".into());
        }
        self.current_slot = current_slot;
        info!(self.log, "Processing"; "slot" => current_slot.as_u64(), "epoch" => current_epoch.as_u64());
        Ok(())
    }

    /// For all known validator keypairs, update any known duties from the beacon node.
    fn check_for_duties(&mut self) {
        let cloned_manager = self.duties_manager.clone();
        let cloned_log = self.log.clone();
        let current_epoch = self.current_slot.epoch(self.slots_per_epoch);
        // spawn a new thread separate to the runtime
        // TODO: Handle thread termination/timeout
        // TODO: Add duties thread back in, with channel to process duties in duty change.
        // leave sequential for now.
        //std::thread::spawn(move || {
        // the return value is a future which returns ready.
        // built to be compatible with the tokio runtime.
        let _empty = cloned_manager.run_update(current_epoch, cloned_log.clone());
        //});
    }

    /// If there are any duties to process, spawn a separate thread and perform required actions.
    fn process_duties(&mut self) {
        if let Some(work) = self.duties_manager.get_current_work(self.current_slot) {
            for (signer_index, work_type) in work {
                if work_type.produce_block {
                    // we need to produce a block
                    // spawns a thread to produce a beacon block
                    let signers = self.duties_manager.signers.clone(); // this is an arc
                    let fork = self.fork.clone();
                    let slot = self.current_slot;
                    let spec = self.spec.clone();
                    let beacon_node = self.beacon_block_client.clone();
                    let log = self.log.clone();
                    let slots_per_epoch = self.slots_per_epoch;
                    std::thread::spawn(move || {
                        info!(log, "Producing a block"; "Validator"=> format!("{}", signers[signer_index]));
                        let signer = &signers[signer_index];
                        let mut block_producer = BlockProducer {
                            fork,
                            slot,
                            spec,
                            beacon_node,
                            signer,
                            slots_per_epoch,
                            _phantom: PhantomData::<E>,
                        };
                        block_producer.handle_produce_block(log);
                    });
                }
                if work_type.attestation_duty.is_some() {
                    // we need to produce an attestation
                    // spawns a thread to produce and sign an attestation
                    let signers = self.duties_manager.signers.clone(); // this is an arc
                    let fork = self.fork.clone();
                    let spec = self.spec.clone();
                    let beacon_node = self.attestation_client.clone();
                    let log = self.log.clone();
                    let slots_per_epoch = self.slots_per_epoch;
                    std::thread::spawn(move || {
                        info!(log, "Producing an attestation"; "Validator"=> format!("{}", signers[signer_index]));
                        let signer = &signers[signer_index];
                        let mut attestation_producer = AttestationProducer {
                            fork,
                            duty: work_type.attestation_duty.expect("Should never be none"),
                            spec,
                            beacon_node,
                            signer,
                            slots_per_epoch,
                            _phantom: PhantomData::<E>,
                        };
                        attestation_producer.handle_produce_attestation(log);
                    });
                }
            }
        }
    }
}
<commit_msg>Add option to validator service to fix bug<commit_after>/// The Validator Client service.
///
/// Connects to a beacon node and negotiates the correct chain id.
///
/// Once connected, the service loads known validators keypairs from disk. Every slot,
/// the service pings the beacon node, asking for new duties for each of the validators.
///
/// When a validator needs to either produce a block or sign an attestation, it requests the
/// data from the beacon node and performs the signing before publishing the block to the beacon
/// node.
use crate::attestation_producer::AttestationProducer;
use crate::block_producer::{BeaconBlockGrpcClient, BlockProducer};
use crate::config::Config as ValidatorConfig;
use crate::duties::{BeaconNodeDuties, DutiesManager, EpochDutiesMap};
use crate::error as error_chain;
use crate::signer::Signer;
use bls::Keypair;
use eth2_config::Eth2Config;
use grpcio::{ChannelBuilder, EnvBuilder};
use protos::services::Empty;
use protos::services_grpc::{
    AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient,
    ValidatorServiceClient,
};
use slog::{crit, error, info, warn};
use slot_clock::{SlotClock, SystemTimeSlotClock};
use std::marker::PhantomData;
use std::sync::Arc;
use std::sync::RwLock;
use std::time::{Duration, Instant};
use tokio::prelude::*;
use tokio::runtime::Builder;
use tokio::timer::Interval;
use tokio_timer::clock::Clock;
use types::{ChainSpec, Epoch, EthSpec, Fork, Slot};

/// A fixed amount of time after a slot to perform operations. This gives the node time to complete
/// per-slot processes.
const TIME_DELAY_FROM_SLOT: Duration = Duration::from_millis(100);

/// The validator service. This is the main thread that executes and maintains validator
/// duties.
//TODO: Generalize the BeaconNode types to use testing
pub struct Service<B: BeaconNodeDuties + 'static, S: Signer + 'static, E: EthSpec> {
    /// The node's current fork version we are processing on.
    fork: Fork,
    /// The slot clock for this service.
    slot_clock: SystemTimeSlotClock,
    /// The slot that is currently, or was previously processed by the service.
    current_slot: Option<Slot>,
    slots_per_epoch: u64,
    /// The chain specification for this clients instance.
    spec: Arc<ChainSpec>,
    /// The duties manager which maintains the state of when to perform actions.
    duties_manager: Arc<DutiesManager<B, S>>,
    // GRPC Clients
    /// The beacon block GRPC client.
    beacon_block_client: Arc<BeaconBlockGrpcClient>,
    /// The attester GRPC client.
    attestation_client: Arc<AttestationServiceClient>,
    /// The validator client logger.
    log: slog::Logger,
    _phantom: PhantomData<E>,
}

impl<B: BeaconNodeDuties + 'static, S: Signer + 'static, E: EthSpec> Service<B, S, E> {
    ///  Initial connection to the beacon node to determine its properties.
    ///
    ///  This tries to connect to a beacon node. Once connected, it initialised the gRPC clients
    ///  and returns an instance of the service.
    fn initialize_service(
        client_config: ValidatorConfig,
        eth2_config: Eth2Config,
        log: slog::Logger,
    ) -> error_chain::Result<Service<ValidatorServiceClient, Keypair, E>> {
        let server_url = format!(
            "{}:{}",
            client_config.server, client_config.server_grpc_port
        );

        let env = Arc::new(EnvBuilder::new().build());
        // Beacon node gRPC beacon node endpoints.
        let beacon_node_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&server_url);
            BeaconNodeServiceClient::new(ch)
        };

        // retrieve node information and validate the beacon node
        let node_info = loop {
            match beacon_node_client.info(&Empty::new()) {
                Err(e) => {
                    let retry_seconds = 5;
                    warn!(
                        log,
                        "Could not connect to beacon node";
                        "error" => format!("{:?}", e),
                        "retry_in" => format!("{} seconds", retry_seconds),
                    );
                    std::thread::sleep(Duration::from_secs(retry_seconds));
                    continue;
                }
                Ok(info) => {
                    // verify the node's network id
                    if eth2_config.spec.network_id != info.network_id as u8 {
                        error!(
                            log,
                            "Beacon Node's genesis time is in the future. No work to do.\n Exiting"
                        );
                        return Err(format!("Beacon node has the wrong chain id. Expected chain id: {}, node's chain id: {}", eth2_config.spec.network_id, info.network_id).into());
                    }
                    break info;
                }
            };
        };

        // build requisite objects to form Self
        let genesis_time = node_info.get_genesis_time();
        let genesis_slot = Slot::from(node_info.get_genesis_slot());

        info!(
            log,
            "Beacon node connected";
            "version" => node_info.version.clone(),
            "network_id" => node_info.network_id,
            "genesis_time" => genesis_time
        );

        let proto_fork = node_info.get_fork();
        let mut previous_version: [u8; 4] = [0; 4];
        let mut current_version: [u8; 4] = [0; 4];
        previous_version.copy_from_slice(&proto_fork.get_previous_version()[..4]);
        current_version.copy_from_slice(&proto_fork.get_current_version()[..4]);
        let fork = Fork {
            previous_version,
            current_version,
            epoch: Epoch::from(proto_fork.get_epoch()),
        };

        // initialize the RPC clients

        // Beacon node gRPC beacon block endpoints.
        let beacon_block_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&server_url);
            let beacon_block_service_client = Arc::new(BeaconBlockServiceClient::new(ch));
            // a wrapper around the service client to implement the beacon block node trait
            Arc::new(BeaconBlockGrpcClient::new(beacon_block_service_client))
        };

        // Beacon node gRPC validator endpoints.
        let validator_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&server_url);
            Arc::new(ValidatorServiceClient::new(ch))
        };

        //Beacon node gRPC attester endpoints.
        let attestation_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&server_url);
            Arc::new(AttestationServiceClient::new(ch))
        };

        // build the validator slot clock
        let slot_clock = SystemTimeSlotClock::from_eth2_genesis(
            genesis_slot,
            genesis_time,
            Duration::from_millis(eth2_config.spec.milliseconds_per_slot),
        )
        .map_err::<error_chain::Error, _>(|e| {
            format!("Unable to start slot clock: {}.", e).into()
        })?;

        /* Generate the duties manager */

        // Load generated keypairs
        let keypairs = Arc::new(client_config.fetch_keys(&log)?);

        let slots_per_epoch = E::slots_per_epoch();

        // TODO: keypairs are randomly generated; they should be loaded from a file or generated.
        // https://github.com/sigp/lighthouse/issues/160
        //let keypairs = Arc::new(generate_deterministic_keypairs(8));

        // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty)
        // where EpochDuty contains slot numbers and attestation data that each validator needs to
        // produce work on.
        let duties_map = RwLock::new(EpochDutiesMap::new(slots_per_epoch));

        // builds a manager which maintains the list of current duties for all known validators
        // and can check when a validator needs to perform a task.
        let duties_manager = Arc::new(DutiesManager {
            duties_map,
            // these are abstract objects capable of signing
            signers: keypairs,
            beacon_node: validator_client,
        });

        let spec = Arc::new(eth2_config.spec);

        Ok(Service {
            fork,
            slot_clock,
            current_slot: None,
            slots_per_epoch,
            spec,
            duties_manager,
            beacon_block_client,
            attestation_client,
            log,
            _phantom: PhantomData,
        })
    }

    /// Initialise the service then run the core thread.
    // TODO: Improve handling of generic BeaconNode types, to stub grpcClient
    pub fn start(
        client_config: ValidatorConfig,
        eth2_config: Eth2Config,
        log: slog::Logger,
    ) -> error_chain::Result<()> {
        // connect to the node and retrieve its properties and initialize the gRPC clients
        let mut service = Service::<ValidatorServiceClient, Keypair, E>::initialize_service(
            client_config,
            eth2_config,
            log.clone(),
        )?;

        // we have connected to a node and established its parameters. Spin up the core service

        // set up the validator service runtime
        let mut runtime = Builder::new()
            .clock(Clock::system())
            .name_prefix("validator-client-")
            .build()
            .map_err(|e| format!("Tokio runtime failed: {}", e))?;

        let duration_to_next_slot = service
            .slot_clock
            .duration_to_next_slot()
            .ok_or_else::<error_chain::Error, _>(|| {
                "Unable to determine duration to next slot. Exiting.".into()
            })?;

        // set up the validator work interval - start at next slot and proceed every slot
        let interval = {
            // Set the interval to start at the next slot, and every slot after
            let slot_duration = Duration::from_millis(service.spec.milliseconds_per_slot);
            //TODO: Handle checked add correctly
            Interval::new(Instant::now() + duration_to_next_slot, slot_duration)
        };

        if service.slot_clock.now().is_none() {
            warn!(
                log,
                "Starting node prior to genesis";
            );
        }

        info!(
            log,
            "Waiting for next slot";
            "seconds_to_wait" => duration_to_next_slot.as_secs()
        );

        /* kick off the core service */
        runtime.block_on(
            interval
                .for_each(move |_| {
                    // wait for node to process
                    std::thread::sleep(TIME_DELAY_FROM_SLOT);
                    // if a non-fatal error occurs, proceed to the next slot.
                    let _ignore_error = service.per_slot_execution();
                    // completed a slot process
                    Ok(())
                })
                .map_err(|e| format!("Service thread failed: {:?}", e)),
        )?;
        // validator client exited
        Ok(())
    }

    /// The execution logic that runs every slot.
    // Errors are logged to output, and core execution continues unless fatal errors occur.
    fn per_slot_execution(&mut self) -> error_chain::Result<()> {
        /* get the new current slot and epoch */
        self.update_current_slot()?;

        /* check for new duties */
        self.check_for_duties();

        /* process any required duties for validators */
        self.process_duties();

        Ok(())
    }

    /// Updates the known current slot and epoch.
    fn update_current_slot(&mut self) -> error_chain::Result<()> {
        let wall_clock_slot = self
            .slot_clock
            .now()
            .ok_or_else::<error_chain::Error, _>(|| {
                "Genesis is not in the past. Exiting.".into()
            })?;

        let wall_clock_epoch = wall_clock_slot.epoch(self.slots_per_epoch);

        // this is a non-fatal error. If the slot clock repeats, the node could
        // have been slow to process the previous slot and is now duplicating tasks.
        // We ignore duplicated but raise a critical error.
        if let Some(current_slot) = self.current_slot {
            if wall_clock_slot <= current_slot {
                crit!(
                    self.log,
                    "The validator tried to duplicate a slot. Likely missed the previous slot"
                );
                return Err("Duplicate slot".into());
            }
        }
        self.current_slot = Some(wall_clock_slot);
        info!(self.log, "Processing"; "slot" => wall_clock_slot.as_u64(), "epoch" => wall_clock_epoch.as_u64());
        Ok(())
    }

    /// For all known validator keypairs, update any known duties from the beacon node.
    fn check_for_duties(&mut self) {
        let cloned_manager = self.duties_manager.clone();
        let cloned_log = self.log.clone();
        let current_epoch = self
            .current_slot
            .expect("The current slot must be updated before checking for duties")
            .epoch(self.slots_per_epoch);
        // spawn a new thread separate to the runtime
        // TODO: Handle thread termination/timeout
        // TODO: Add duties thread back in, with channel to process duties in duty change.
        // leave sequential for now.
        //std::thread::spawn(move || {
        // the return value is a future which returns ready.
        // built to be compatible with the tokio runtime.
        let _empty = cloned_manager.run_update(current_epoch, cloned_log.clone());
        //});
    }

    /// If there are any duties to process, spawn a separate thread and perform required actions.
    fn process_duties(&mut self) {
        if let Some(work) = self.duties_manager.get_current_work(
            self.current_slot
                .expect("The current slot must be updated before processing duties"),
        ) {
            for (signer_index, work_type) in work {
                if work_type.produce_block {
                    // we need to produce a block
                    // spawns a thread to produce a beacon block
                    let signers = self.duties_manager.signers.clone(); // this is an arc
                    let fork = self.fork.clone();
                    let slot = self
                        .current_slot
                        .expect("The current slot must be updated before processing duties");
                    let spec = self.spec.clone();
                    let beacon_node = self.beacon_block_client.clone();
                    let log = self.log.clone();
                    let slots_per_epoch = self.slots_per_epoch;
                    std::thread::spawn(move || {
                        info!(log, "Producing a block"; "Validator"=> format!("{}", signers[signer_index]));
                        let signer = &signers[signer_index];
                        let mut block_producer = BlockProducer {
                            fork,
                            slot,
                            spec,
                            beacon_node,
                            signer,
                            slots_per_epoch,
                            _phantom: PhantomData::<E>,
                        };
                        block_producer.handle_produce_block(log);
                    });
                }
                if work_type.attestation_duty.is_some() {
                    // we need to produce an attestation
                    // spawns a thread to produce and sign an attestation
                    let signers = self.duties_manager.signers.clone(); // this is an arc
                    let fork = self.fork.clone();
                    let spec = self.spec.clone();
                    let beacon_node = self.attestation_client.clone();
                    let log = self.log.clone();
                    let slots_per_epoch = self.slots_per_epoch;
                    std::thread::spawn(move || {
                        info!(log, "Producing an attestation"; "Validator"=> format!("{}", signers[signer_index]));
                        let signer = &signers[signer_index];
                        let mut attestation_producer = AttestationProducer {
                            fork,
                            duty: work_type.attestation_duty.expect("Should never be none"),
                            spec,
                            beacon_node,
                            signer,
                            slots_per_epoch,
                            _phantom: PhantomData::<E>,
                        };
                        attestation_producer.handle_produce_attestation(log);
                    });
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#[derive(Debug)]
pub struct Register8 {
    value: u8,
}

impl Register8 {
    pub fn new(v: u8) -> Register8 {
        Register8 { value: v }
    }

    pub fn get(&self) -> u8 {
        self.value
    }

    pub fn set(&mut self, value: u8) {
        self.value = value;
    }

    pub fn increase(&mut self) {
        self.value.wrapping_add(1);
    }
}

#[derive(Debug)]
pub struct Register16 {
    pub low: Register8,
    pub high: Register8,
}

impl Register16 {
    pub fn new(v: u16) -> Register16 {
        let low = (v & 0x00FF) as u8;
        let high = ((v & 0xFF00) >> 8) as u8;

        Register16 {
            low: Register8::new(low),
            high: Register8::new(high),
        }
    }

    pub fn increase(&mut self) {
        // self.value.wrapping_add(1);
    }

    pub fn get_low(&self) -> u8 {
        self.low.get()
    }

    pub fn get_high(&self) -> u8 {
        self.high.get()
    }

    pub fn set_low(&mut self, v: u8) {
        self.low.set(v)
    }

    pub fn set_high(&mut self, v: u8) {
        self.high.set(v)
    }

    pub fn get(&self) -> u16 {
        ((self.high.get() as u16) << 8) | self.low.get() as u16
    }
}

#[derive(Debug)]
pub struct Registers {
    // registers are 16 bit wide and can be accessed as L(low) and H(high)
    // register AF is used for (A) accumulator and (F) flags
    pub af: Register16,
    pub bc: Register16,
    pub de: Register16,
    pub hl: Register16,

    pub pc: Register16, // program counter
    pub sp: Register16, // stack pointer
}

impl Registers {
    /// true if bit 7 of flags is 1
    pub fn zero_flag(&self) -> bool {
        (self.af.get_low() & 0x80) == 0x80
    }

    /// true if bit 6 of flags is 1
    pub fn add_sub_flag(&self) -> bool {
        (self.af.get_low() & 0x40) == 0x40
    }

    /// true if bit 5 of flags is 1
    pub fn half_carry_flag(&self) -> bool {
        (self.af.get_low() & 0x20) == 0x20
    }

    /// true if bit 4 of flags is 1
    pub fn carry_flag(&self) -> bool {
        (self.af.get_low() & 0x10) == 0x10
    }

    /// sets bit 7 of flags to 1
    pub fn set_zero_flag(&mut self) {
        let f = self.af.get_low();
        self.af.set_low(f | 0x80);
    }

    // /// sets bit 6 of flags to 1
    // pub fn set_add_sub_flag(&mut self) {
    //     self.af.set_low(self.af.get_low() | 0x40);
    // }
    //
    // /// sets bit 5 of flags to 1
    // pub fn set_half_carry_flag(&mut self) {
    //     self.af.set_low(self.af.get_low() | 0x20);
    // }
    //
    // /// sets bit 4 of flags to 1
    // pub fn set_carry_flag(&mut self) {
    //     self.af.set_low(self.af.get_low() | 0x10);
    // }
    //
    // /// clears bit 7 of flags
    // pub fn clear_zero_flag(&mut self) {
    //     self.af.set_low(self.af.get_low() & 0x7F);
    // }
    //
    // /// clears bit 6 of flags
    // pub fn clear_add_sub_flag(&mut self) {
    //     self.af.set_low(self.af.get_low() & 0xBF);
    // }
    //
    // /// clears bit 5 of flags
    // pub fn clear_half_carry_flag(&mut self) {
    //     self.af.set_low(self.af.get_low() & 0xDF);
    // }
    //
    // /// clears bit 4 of flags
    // pub fn clear_carry_flag(&mut self) {
    //     self.af.set_low(self.af.get_low() & 0xEF);
    // }
}
<commit_msg>Fixed commented functions in registers.rs<commit_after>#[derive(Debug)]
pub struct Register8 {
    value: u8,
}

impl Register8 {
    pub fn new(v: u8) -> Register8 {
        Register8 { value: v }
    }

    pub fn get(&self) -> u8 {
        self.value
    }

    pub fn set(&mut self, value: u8) {
        self.value = value;
    }

    pub fn increase(&mut self) {
        self.value.wrapping_add(1);
    }
}

#[derive(Debug)]
pub struct Register16 {
    pub low: Register8,
    pub high: Register8,
}

impl Register16 {
    pub fn new(v: u16) -> Register16 {
        let low = (v & 0x00FF) as u8;
        let high = ((v & 0xFF00) >> 8) as u8;

        Register16 {
            low: Register8::new(low),
            high: Register8::new(high),
        }
    }

    pub fn increase(&mut self) {
        let new_value = self.get().wrapping_add(1);
        self.set(new_value);
    }

    pub fn get_low(&self) -> u8 {
        self.low.get()
    }

    pub fn get_high(&self) -> u8 {
        self.high.get()
    }

    pub fn set_low(&mut self, v: u8) {
        self.low.set(v)
    }

    pub fn set_high(&mut self, v: u8) {
        self.high.set(v)
    }

    pub fn get(&self) -> u16 {
        ((self.high.get() as u16) << 8) | self.low.get() as u16
    }

    pub fn set(&mut self, v: u16) {
        let low = (v & 0x00FF) as u8;
        let high = (v >> 8) as u8;

        self.set_low(low);
        self.set_high(high);
    }
}

#[derive(Debug)]
pub struct Registers {
    // registers are 16 bit wide and can be accessed as L(low) and H(high)
    // register AF is used for (A) accumulator and (F) flags
    pub af: Register16,
    pub bc: Register16,
    pub de: Register16,
    pub hl: Register16,

    pub pc: Register16, // program counter
    pub sp: Register16, // stack pointer
}

impl Registers {
    /// true if bit 7 of flags is 1
    pub fn zero_flag(&self) -> bool {
        (self.af.get_low() & 0x80) == 0x80
    }

    /// true if bit 6 of flags is 1
    pub fn add_sub_flag(&self) -> bool {
        (self.af.get_low() & 0x40) == 0x40
    }

    /// true if bit 5 of flags is 1
    pub fn half_carry_flag(&self) -> bool {
        (self.af.get_low() & 0x20) == 0x20
    }

    /// true if bit 4 of flags is 1
    pub fn carry_flag(&self) -> bool {
        (self.af.get_low() & 0x10) == 0x10
    }

    /// sets bit 7 of flags to the specified bool value
    pub fn set_zero_flag(&mut self, flag: bool) {
        let f = self.af.get_low();

        match flag {
            true => self.af.set_low(f | 0x80),
            false => self.af.set_low(f & 0x7F),
        };
    }

    /// sets bit 6 of flags to the specified bool value
    pub fn set_add_sub_flag(&mut self, flag: bool) {
        let f = {self.af.get_low()};

        match flag {
            true => self.af.set_low(f | 0x40),
            false => self.af.set_low(f & 0xBF),
        };
    }

    /// sets bit 5 of flags to the specified bool value
    pub fn set_half_carry_flag(&mut self, flag: bool) {
        let f = {self.af.get_low()};

        match flag {
            true => self.af.set_low(f | 0x20),
            false => self.af.set_low(f & 0xDF),
        };
    }

    /// sets bit 4 of flags to the specified bool value
    pub fn set_carry_flag(&mut self, flag: bool) {
        let f = {self.af.get_low()};

        match flag {
            true => self.af.set_low(f | 0x10),
            false => self.af.set_low(f & 0xEF),
        };
    }

}
<|endoftext|>


<commit_before>use std::borrow::Cow;

use types::{AliasData, ArcType, Type, TypeEnv};
use symbol::Symbol;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        UndefinedType(id: Symbol) {
            description("undefined type")
            display("Type `{}` does not exist.", id)
        }
    }
}

/// Removes type aliases from `typ` until it is an actual type
pub fn remove_aliases(env: &TypeEnv, mut typ: ArcType) -> ArcType {
    while let Ok(Some(new)) = remove_alias(env, &typ) {
        typ = new;
    }
    typ
}

pub fn remove_aliases_cow<'t>(env: &TypeEnv, typ: &'t ArcType) -> Cow<'t, ArcType> {
    match remove_alias(env, typ) {
        Ok(Some(typ)) => Cow::Owned(remove_aliases(env, typ)),
        _ => Cow::Borrowed(typ),
    }
}

pub fn canonical_alias<'t, F>(env: &TypeEnv, typ: &'t ArcType, canonical: F) -> Cow<'t, ArcType>
where
    F: Fn(&AliasData<Symbol, ArcType>) -> bool,
{
    match peek_alias(env, typ) {
        Ok(Some(alias)) if !canonical(alias) => alias
            .unresolved_type()
            .apply_args(typ.unapplied_args())
            .map(|typ| {
                Cow::Owned(canonical_alias(env, &typ, canonical).into_owned())
            })
            .unwrap_or(Cow::Borrowed(typ)),
        _ => Cow::Borrowed(typ),
    }
}

/// Expand `typ` if it is an alias that can be expanded and return the expanded type.
/// Returns `None` if the type is not an alias or the alias could not be expanded.
pub fn remove_alias(env: &TypeEnv, typ: &ArcType) -> Result<Option<ArcType>, Error> {
    Ok(peek_alias(env, typ)?.and_then(|alias| {
        alias.unresolved_type().apply_args(typ.unapplied_args())
    }))
}

pub fn peek_alias<'t>(
    env: &'t TypeEnv,
    typ: &'t ArcType,
) -> Result<Option<&'t AliasData<Symbol, ArcType>>, Error> {
    let maybe_alias = match **typ {
        Type::Alias(ref alias) if alias.params().is_empty() => Some(alias),
        Type::App(ref alias, ref args) => match **alias {
            Type::Alias(ref alias) if alias.params().len() == args.len() => Some(alias),
            _ => None,
        },
        _ => None,
    };

    match typ.alias_ident() {
        Some(id) => {
            let alias = match maybe_alias {
                Some(alias) => alias,
                None => env.find_type_info(id)
                    .map(|a| &**a)
                    .ok_or_else(|| Error::UndefinedType(id.clone()))?,
            };
            Ok(Some(alias))
        }
        None => Ok(None),
    }
}
<commit_msg>Skolemize before trying to remove aliases<commit_after>use std::borrow::Cow;

use fnv::FnvMap;
use types::{AliasData, ArcType, Type, TypeEnv};
use symbol::Symbol;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        UndefinedType(id: Symbol) {
            description("undefined type")
            display("Type `{}` does not exist.", id)
        }
    }
}

/// Removes type aliases from `typ` until it is an actual type
pub fn remove_aliases(env: &TypeEnv, mut typ: ArcType) -> ArcType {
    while let Ok(Some(new)) = remove_alias(env, &typ) {
        typ = new;
    }
    typ
}

pub fn remove_aliases_cow<'t>(env: &TypeEnv, typ: &'t ArcType) -> Cow<'t, ArcType> {
    match remove_alias(env, typ) {
        Ok(Some(typ)) => Cow::Owned(remove_aliases(env, typ)),
        _ => Cow::Borrowed(typ),
    }
}

pub fn canonical_alias<'t, F>(env: &TypeEnv, typ: &'t ArcType, canonical: F) -> Cow<'t, ArcType>
where
    F: Fn(&AliasData<Symbol, ArcType>) -> bool,
{
    match peek_alias(env, typ) {
        Ok(Some(alias)) if !canonical(alias) => alias
            .unresolved_type()
            .apply_args(typ.unapplied_args())
            .map(|typ| {
                Cow::Owned(canonical_alias(env, &typ, canonical).into_owned())
            })
            .unwrap_or(Cow::Borrowed(typ)),
        _ => Cow::Borrowed(typ),
    }
}

/// Expand `typ` if it is an alias that can be expanded and return the expanded type.
/// Returns `None` if the type is not an alias or the alias could not be expanded.
pub fn remove_alias(env: &TypeEnv, typ: &ArcType) -> Result<Option<ArcType>, Error> {
    let typ = typ.skolemize(&mut FnvMap::default());
    Ok(peek_alias(env, &typ)?.and_then(|alias| {
        alias.unresolved_type().apply_args(typ.unapplied_args())
    }))
}

pub fn peek_alias<'t>(
    env: &'t TypeEnv,
    typ: &'t ArcType,
) -> Result<Option<&'t AliasData<Symbol, ArcType>>, Error> {
    let maybe_alias = match **typ {
        Type::Alias(ref alias) if alias.params().is_empty() => Some(alias),
        Type::App(ref alias, ref args) => match **alias {
            Type::Alias(ref alias) if alias.params().len() == args.len() => Some(alias),
            _ => None,
        },
        _ => None,
    };

    match typ.alias_ident() {
        Some(id) => {
            let alias = match maybe_alias {
                Some(alias) => alias,
                None => env.find_type_info(id)
                    .map(|a| &**a)
                    .ok_or_else(|| Error::UndefinedType(id.clone()))?,
            };
            Ok(Some(alias))
        }
        None => Ok(None),
    }
}
<|endoftext|>