<commit_before>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Start,
    End
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    segments = Vec::new ();
    state = SegmentState::End;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        let needs_new_segment: bool;
        let seg: Segment;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                seg = Segment::Degenerate {
                    x: cur_x,
                    y: cur_y
                };
                needs_new_segment = true;

                state = SegmentState::Start;
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };
            },

            cairo::PathSegment::CurveTo ((mut x2, mut y2), (mut x3, mut y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                let x1 = last_x;
                let y1 = last_y;

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }

                /* Fix the tangents for when the middle control points coincide with their respective endpoints */

                if double_equals (x2, x1) && double_equals (y2, y1) {
                    x2 = x3;
                    y2 = y3;
                }

                if double_equals (x3, x4) && double_equals (y3, y4) {
                    x3 = x2;
                    y3 = y2;
                }

                seg = Segment::LineOrCurve {
                    x1: x1,
                    y1: y1,

                    x2: x2,
                    y2: y2,

                    x3: x3,
                    y3: y3,

                    x4: x4,
                    y4: y4,
                };
            }

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = false;
                        /* nothing; closepath after moveto (or a single lone closepath) does nothing */
                    }
                }

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };
            }
        }

        if needs_new_segment {
            segments.push (seg);
        } else {
            let len = segments.len ();
            segments[len - 1] = seg;
        }
    }

    segments
}

#[cfg(test)]
mod tests {
    use super::*;
    extern crate cairo;

    fn setup_open_path () -> cairo::Path {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            Segment::LineOrCurve { x1: 10.0, y1: 10.0, x2: 20.0, y2: 10.0, x3: 10.0, y3: 10.0, x4: 20.0, y4: 10.0 },
            Segment::LineOrCurve { x1: 20.0, y1: 10.0, x2: 20.0, y2: 20.0, x3: 20.0, y3: 10.0, x4: 20.0, y4: 20.0 }
        ];

        let path = setup_open_path ();
        let segments = path_to_segments (path);

        assert_eq! (expected_segments, segments);
    }
}
<commit_msg>marker.rs: Separate segment setup from the state machine logic<commit_after>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Start,
    End
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    segments = Vec::new ();
    state = SegmentState::End;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        let needs_new_segment: bool;
        let seg: Segment;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = Segment::Degenerate {
                    x: cur_x,
                    y: cur_y
                };
                needs_new_segment = true;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                state = SegmentState::Start;
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            },

            cairo::PathSegment::CurveTo ((mut x2, mut y2), (mut x3, mut y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                /* Fix the tangents for when the middle control points coincide with their respective endpoints */

                let x1 = last_x;
                let y1 = last_y;

                if double_equals (x2, x1) && double_equals (y2, y1) {
                    x2 = x3;
                    y2 = y3;
                }

                if double_equals (x3, x4) && double_equals (y3, y4) {
                    x3 = x2;
                    y3 = y2;
                }

                seg = Segment::LineOrCurve {
                    x1: x1,
                    y1: y1,

                    x2: x2,
                    y2: y2,

                    x3: x3,
                    y3: y3,

                    x4: x4,
                    y4: y4,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            }

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                seg = Segment::LineOrCurve {
                    x1: last_x,
                    y1: last_y,

                    x2: cur_x,
                    y2: cur_y,

                    x3: last_x,
                    y3: last_y,

                    x4: cur_x,
                    y4: cur_y,
                };

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = false;
                        /* nothing; closepath after moveto (or a single lone closepath) does nothing */
                    }
                }
            }
        }

        if needs_new_segment {
            segments.push (seg);
        } else {
            let len = segments.len ();
            segments[len - 1] = seg;
        }
    }

    segments
}

#[cfg(test)]
mod tests {
    use super::*;
    extern crate cairo;

    fn setup_open_path () -> cairo::Path {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            Segment::LineOrCurve { x1: 10.0, y1: 10.0, x2: 20.0, y2: 10.0, x3: 10.0, y3: 10.0, x4: 20.0, y4: 10.0 },
            Segment::LineOrCurve { x1: 20.0, y1: 10.0, x2: 20.0, y2: 20.0, x3: 20.0, y3: 10.0, x4: 20.0, y4: 20.0 }
        ];

        let path = setup_open_path ();
        let segments = path_to_segments (path);

        assert_eq! (expected_segments, segments);
    }
}
<|endoftext|>


<commit_before><commit_msg>Remove old tables.rs file<commit_after><|endoftext|>


<commit_before>// check-pass

#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash

struct Const<const N: usize>;

impl<const C: usize> Const<{C}> {
    fn successor() -> Const<{C + 1}> {
        Const
    }
}

fn main() {
    Const::<1>::successor();
}
<commit_msg>Apply suggestion from Centril<commit_after>// check-pass

#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash

struct Const<const N: usize>;

impl<const C: usize> Const<{C}> {
    fn successor() -> Const<{C + 1}> {
        Const
    }
}

fn main() {
    let _x: Const::<2> = Const::<1>::successor();
}
<|endoftext|>


<commit_before>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use rustc_serialize::json;
use std::error::{self, Error};
use std::num;
use std::io;
use std::fmt;
use hyper;
use hyper::error::Error as HttpError;

#[derive(Debug)]
pub enum Kind {
    AuthenticationFailed,
    NoMatchingCommand,
    NotOnABranch,
    CannotReviewSameBranch,
    FailedToExecute,
    PushFailed,
    BadGitOutputMatch,
    MissingMetadataVersion,
    BadMetadataVersionMatch,
    NoGitConfig,
    GitFailed,
    GitSetupFailed,
    ConfigParse,
    MissingConfig,
    ConfigValidation,
    IoError,
    JsonError,
    JsonEncode,
    NoBuildCookbook,
    NoHomedir,
    ExpectedJsonString,
    BerksFailed,
    NoValidBuildCookbook,
    CopyFailed,
    MissingBuildCookbookName,
    SupermarketFailed,
    MoveFailed,
    RemoveFailed,
    TarFailed,
    MissingBuildCookbookField,
    ChefServerFailed,
    ChownFailed,
    ChefFailed,
    ChmodFailed,
    UnsupportedHttpMethod,
    HttpError(HttpError),
    UnsupportedProtocol,
    ApiError(hyper::status::StatusCode, Result<String, io::Error>),
    JsonParseError,
    IntParseError,
    OpenFailed,
    NoToken,
    NoEditor,
    MissingProjectConfig
}

#[derive(Debug)]
pub struct DeliveryError {
    pub kind: Kind,
    pub detail: Option<String>,
}

impl DeliveryError {
    pub fn detail(&self) -> Option<String> {
        self.detail.clone()
    }
}

impl error::Error for DeliveryError {
    fn description(&self) -> &str {
        match self.kind {
            Kind::NoMatchingCommand => "No command matches your arguments - likely unimplemented feature",
            Kind::NotOnABranch => "You must be on a branch",
            Kind::CannotReviewSameBranch => "You cannot target code for review from the same branch as the review is targeted for",
            Kind::FailedToExecute => "Tried to fork a process, and failed",
            Kind::PushFailed => "Git Push failed!",
            Kind::GitFailed => "Git command failed!",
            Kind::GitSetupFailed => "Setup failed; you have already set up delivery.",
            Kind::BadGitOutputMatch => "A line of git porcelain did not match!",
            Kind::BadMetadataVersionMatch => "Metadata version mismatch!",
            Kind::MissingMetadataVersion => "Missing a version entry into the metadata.rb",
            Kind::NoGitConfig => "Cannot find a .git/config file",
            Kind::ConfigParse => "Failed to parse the cli config file",
            Kind::MissingConfig => "A configuration value is missing",
            Kind::ConfigValidation => "A required option is missing - use the command line options or 'delivery setup'",
            Kind::IoError => "An I/O Error occurred",
            Kind::JsonError => "A JSON Parser error occured",
            Kind::JsonEncode => "A JSON Encoding error occured",
            Kind::NoBuildCookbook => "No build_cookbook entry in .delivery/config.json",
            Kind::NoHomedir => "Cannot find a homedir",
            Kind::BerksFailed => "Berkshelf command failed",
            Kind::ExpectedJsonString => "Expected a JSON string",
            Kind::NoValidBuildCookbook => "Cannot find a valid build_cookbook entry in .delivery/config.json",
            Kind::MissingBuildCookbookName => "You must have a name field in you build_cookbook",
            Kind::CopyFailed => "Failed to copy files",
            Kind::SupermarketFailed => "Failed to download a cookbook from the supermarket",
            Kind::TarFailed => "Cannot untar a file",
            Kind::MoveFailed => "Cannot move a file",
            Kind::RemoveFailed => "Cannot remove a file or directory",
            Kind::MissingBuildCookbookField => "Missing a required field in your build_cookbook",
            Kind::ChefServerFailed => "Failed to download a cookbook from the Chef Server",
            Kind::ChownFailed => "Cannot set ownership to the dbuild user and group",
            Kind::ChefFailed => "Chef Client failed",
            Kind::ChmodFailed => "Cannot set permissions",
            Kind::UnsupportedHttpMethod => "Unsupported HTTP method",
            Kind::UnsupportedProtocol => "Unsupported protocol",
            Kind::HttpError(_) => "An HTTP Error occured",
            Kind::ApiError(_, _) => "An API Error occured",
            Kind::JsonParseError => "Attempted to parse invalid JSON",
            Kind::IntParseError => "Attempted to parse invalid Int",
            Kind::OpenFailed => "Open command failed",
            Kind::AuthenticationFailed => "Authentication failed",
            Kind::NoToken => "Missing API token. Try `delivery token` to create one",
            Kind::NoEditor => "Environment variable EDITOR not set",
            Kind::MissingProjectConfig => "Unable to find .delivery/config.json in this directory or its parents"
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self.kind {
            Kind::HttpError(ref e) => Some(e),
            Kind::ApiError(_, ref e) => {
                match *e {
                    Ok(_) => None,
                    Err(ref e) => Some(e)
                }
            },
            _ => None
        }
    }
}

impl fmt::Display for DeliveryError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl From<json::EncoderError> for DeliveryError {
    fn from(err: json::EncoderError) -> DeliveryError {
        DeliveryError{
            kind: Kind::JsonEncode,
            detail: Some(err.description().to_string())
        }
    }
}

impl From<json::DecoderError> for DeliveryError {
    fn from(err: json::DecoderError) -> DeliveryError {
        DeliveryError{
            kind: Kind::JsonParseError,
            detail: Some(format!("{}: {}", err.description().to_string(), err))
        }
    }
}

impl From<io::Error> for DeliveryError {
    fn from(err: io::Error) -> DeliveryError {
        DeliveryError{
            kind: Kind::IoError,
            detail: Some(format!("{}", err))
        }
    }
}

impl From<json::ParserError> for DeliveryError {
    fn from(err: json::ParserError) -> DeliveryError {
        DeliveryError{
            kind: Kind::JsonError,
            detail: Some(err.description().to_string())
        }
    }
}

impl From<HttpError> for DeliveryError {
    fn from(err: HttpError) -> DeliveryError {
        let detail = Some(err.description().to_string());
        DeliveryError{
            kind: Kind::HttpError(err),
            detail: detail
        }
    }
}

impl From<num::ParseIntError> for DeliveryError {
    fn from(err: num::ParseIntError) -> DeliveryError {
        let detail = Some(err.description().to_string());
        DeliveryError{
            kind: Kind::IntParseError,
            detail: detail
        }
    }
}
<commit_msg>Add different kind of errors<commit_after>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use rustc_serialize::json;
use std::error::{self, Error};
use std::num;
use std::io;
use std::fmt;
use hyper;
use hyper::error::Error as HttpError;

#[derive(Debug)]
pub enum Kind {
    AuthenticationFailed,
    NoMatchingCommand,
    NotOnABranch,
    CannotReviewSameBranch,
    FailedToExecute,
    PushFailed,
    BadGitOutputMatch,
    MissingMetadataVersion,
    BadMetadataVersionMatch,
    NoGitConfig,
    NoBitbucketSCPConfig,
    NoGithubSCPConfig,
    OptionConstraint,
    UnknownProjectType,
    GitFailed,
    GitSetupFailed,
    ConfigParse,
    MissingConfig,
    ConfigValidation,
    IoError,
    JsonError,
    JsonEncode,
    NoBuildCookbook,
    NoHomedir,
    ExpectedJsonString,
    BerksFailed,
    NoValidBuildCookbook,
    CopyFailed,
    MissingBuildCookbookName,
    SupermarketFailed,
    MoveFailed,
    RemoveFailed,
    TarFailed,
    MissingBuildCookbookField,
    ChefServerFailed,
    ChownFailed,
    ChefFailed,
    ChmodFailed,
    UnsupportedHttpMethod,
    HttpError(HttpError),
    UnsupportedProtocol,
    ApiError(hyper::status::StatusCode, Result<String, io::Error>),
    JsonParseError,
    IntParseError,
    OpenFailed,
    NoToken,
    TokenExpired,
    NoEditor,
    MissingProjectConfig
}

#[derive(Debug)]
pub struct DeliveryError {
    pub kind: Kind,
    pub detail: Option<String>,
}

impl DeliveryError {
    pub fn detail(&self) -> Option<String> {
        self.detail.clone()
    }
}

impl error::Error for DeliveryError {
    fn description(&self) -> &str {
        match self.kind {
            Kind::NoMatchingCommand => "No command matches your arguments - likely unimplemented feature",
            Kind::NotOnABranch => "You must be on a branch",
            Kind::CannotReviewSameBranch => "You cannot target code for review from the same branch as the review is targeted for",
            Kind::FailedToExecute => "Tried to fork a process, and failed",
            Kind::PushFailed => "Git Push failed!",
            Kind::GitFailed => "Git command failed!",
            Kind::GitSetupFailed => "Setup failed; you have already set up delivery.",
            Kind::BadGitOutputMatch => "A line of git porcelain did not match!",
            Kind::BadMetadataVersionMatch => "Metadata version mismatch!",
            Kind::MissingMetadataVersion => "Missing a version entry into the metadata.rb",
            Kind::NoGitConfig => "Cannot find a .git/config file",
            Kind::NoBitbucketSCPConfig => "Bitbucket Source Code Provider configuration not found; a Delivery administrator must first configure the link with Bitbucket",
            Kind::NoGithubSCPConfig => "Github Source Code Provider configuration not found; a Delivery administrator must first configure the link with Github",
            Kind::OptionConstraint => "Invalid option constraint",
            Kind::UnknownProjectType => "Unknown Project Type",
            Kind::ConfigParse => "Failed to parse the cli config file",
            Kind::MissingConfig => "A configuration value is missing",
            Kind::ConfigValidation => "A required option is missing - use the command line options or 'delivery setup'",
            Kind::IoError => "An I/O Error occurred",
            Kind::JsonError => "A JSON Parser error occured",
            Kind::JsonEncode => "A JSON Encoding error occured",
            Kind::NoBuildCookbook => "No build_cookbook entry in .delivery/config.json",
            Kind::NoHomedir => "Cannot find a homedir",
            Kind::BerksFailed => "Berkshelf command failed",
            Kind::ExpectedJsonString => "Expected a JSON string",
            Kind::NoValidBuildCookbook => "Cannot find a valid build_cookbook entry in .delivery/config.json",
            Kind::MissingBuildCookbookName => "You must have a name field in you build_cookbook",
            Kind::CopyFailed => "Failed to copy files",
            Kind::SupermarketFailed => "Failed to download a cookbook from the supermarket",
            Kind::TarFailed => "Cannot untar a file",
            Kind::MoveFailed => "Cannot move a file",
            Kind::RemoveFailed => "Cannot remove a file or directory",
            Kind::MissingBuildCookbookField => "Missing a required field in your build_cookbook",
            Kind::ChefServerFailed => "Failed to download a cookbook from the Chef Server",
            Kind::ChownFailed => "Cannot set ownership to the dbuild user and group",
            Kind::ChefFailed => "Chef Client failed",
            Kind::ChmodFailed => "Cannot set permissions",
            Kind::UnsupportedHttpMethod => "Unsupported HTTP method",
            Kind::UnsupportedProtocol => "Unsupported protocol",
            Kind::HttpError(_) => "An HTTP Error occured",
            Kind::ApiError(_, _) => "An API Error occured",
            Kind::JsonParseError => "Attempted to parse invalid JSON",
            Kind::IntParseError => "Attempted to parse invalid Int",
            Kind::OpenFailed => "Open command failed",
            Kind::AuthenticationFailed => "Authentication failed",
            Kind::NoToken => "Missing API token. Try `delivery token` to create one",
            Kind::TokenExpired => "The API token has expired. Try `delivery token` to generate a new one",
            Kind::NoEditor => "Environment variable EDITOR not set",
            Kind::MissingProjectConfig => "Unable to find .delivery/config.json in this directory or its parents"
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self.kind {
            Kind::HttpError(ref e) => Some(e),
            Kind::ApiError(_, ref e) => {
                match *e {
                    Ok(_) => None,
                    Err(ref e) => Some(e)
                }
            },
            _ => None
        }
    }
}

impl fmt::Display for DeliveryError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl From<json::EncoderError> for DeliveryError {
    fn from(err: json::EncoderError) -> DeliveryError {
        DeliveryError{
            kind: Kind::JsonEncode,
            detail: Some(err.description().to_string())
        }
    }
}

impl From<json::DecoderError> for DeliveryError {
    fn from(err: json::DecoderError) -> DeliveryError {
        DeliveryError{
            kind: Kind::JsonParseError,
            detail: Some(format!("{}: {}", err.description().to_string(), err))
        }
    }
}

impl From<io::Error> for DeliveryError {
    fn from(err: io::Error) -> DeliveryError {
        DeliveryError{
            kind: Kind::IoError,
            detail: Some(format!("{}", err))
        }
    }
}

impl From<json::ParserError> for DeliveryError {
    fn from(err: json::ParserError) -> DeliveryError {
        DeliveryError{
            kind: Kind::JsonError,
            detail: Some(err.description().to_string())
        }
    }
}

impl From<HttpError> for DeliveryError {
    fn from(err: HttpError) -> DeliveryError {
        let detail = Some(err.description().to_string());
        DeliveryError{
            kind: Kind::HttpError(err),
            detail: detail
        }
    }
}

impl From<num::ParseIntError> for DeliveryError {
    fn from(err: num::ParseIntError) -> DeliveryError {
        let detail = Some(err.description().to_string());
        DeliveryError{
            kind: Kind::IntParseError,
            detail: detail
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains various functions for producing and verifying `ExecutionPayloads`.
//!
//! Lighthouse tends to do payload tasks in *slightly* different locations to the specification.
//! This is because some tasks involve calling out to external servers and it's nice to keep those
//! away from our pure `state_processing` and `fork_choice` crates.
//!
//! So, this module contains functions that one might expect to find in other crates, but they live
//! here for good reason.

use crate::{
    BeaconChain, BeaconChainError, BeaconChainTypes, BlockError, BlockProductionError,
    ExecutionPayloadError,
};
use execution_layer::ExecutePayloadResponseStatus;
use fork_choice::PayloadVerificationStatus;
use proto_array::{Block as ProtoBlock, ExecutionStatus};
use slog::debug;
use slot_clock::SlotClock;
use state_processing::per_block_processing::{
    compute_timestamp_at_slot, is_execution_enabled, is_merge_transition_complete,
    partially_verify_execution_payload,
};
use types::*;

/// Verify that `execution_payload` contained by `block` is considered valid by an execution
/// engine.
///
/// ## Specification
///
/// Equivalent to the `execute_payload` function in the merge Beacon Chain Changes, although it
/// contains a few extra checks by running `partially_verify_execution_payload` first:
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/beacon-chain.md#execute_payload
pub fn execute_payload<T: BeaconChainTypes>(
    chain: &BeaconChain<T>,
    state: &BeaconState<T::EthSpec>,
    block: BeaconBlockRef<T::EthSpec>,
) -> Result<PayloadVerificationStatus, BlockError<T::EthSpec>> {
    if !is_execution_enabled(state, block.body()) {
        return Ok(PayloadVerificationStatus::Irrelevant);
    }

    let execution_payload = block.execution_payload()?;

    // Perform the initial stages of payload verification.
    //
    // We will duplicate these checks again during `per_block_processing`, however these checks
    // are cheap and doing them here ensures we protect the execution payload from junk.
    partially_verify_execution_payload(state, execution_payload, &chain.spec)
        .map_err(BlockError::PerBlockProcessingError)?;

    let execution_layer = chain
        .execution_layer
        .as_ref()
        .ok_or(ExecutionPayloadError::NoExecutionConnection)?;
    let execute_payload_response = execution_layer
        .block_on(|execution_layer| execution_layer.execute_payload(execution_payload));

    match execute_payload_response {
        Ok((status, _latest_valid_hash)) => match status {
            ExecutePayloadResponseStatus::Valid => Ok(PayloadVerificationStatus::Verified),
            // TODO(merge): invalidate any invalid ancestors of this block in fork choice.
            ExecutePayloadResponseStatus::Invalid => {
                Err(ExecutionPayloadError::RejectedByExecutionEngine.into())
            }
            ExecutePayloadResponseStatus::Syncing => Ok(PayloadVerificationStatus::NotVerified),
        },
        Err(_) => Ok(PayloadVerificationStatus::NotVerified),
    }
}

/// Verify that the block which triggers the merge is valid to be imported to fork choice.
///
/// ## Errors
///
/// Will return an error when using a pre-merge fork `state`. Ensure to only run this function
/// after the merge fork.
///
/// ## Specification
///
/// Equivalent to the `validate_merge_block` function in the merge Fork Choice Changes:
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/fork-choice.md#validate_merge_block
pub fn validate_merge_block<T: BeaconChainTypes>(
    chain: &BeaconChain<T>,
    block: BeaconBlockRef<T::EthSpec>,
) -> Result<(), BlockError<T::EthSpec>> {
    let spec = &chain.spec;
    let block_epoch = block.slot().epoch(T::EthSpec::slots_per_epoch());
    let execution_payload = block.execution_payload()?;

    if spec.terminal_block_hash != Hash256::zero() {
        if block_epoch < spec.terminal_block_hash_activation_epoch {
            return Err(ExecutionPayloadError::InvalidActivationEpoch {
                activation_epoch: spec.terminal_block_hash_activation_epoch,
                epoch: block_epoch,
            }
            .into());
        }

        if execution_payload.parent_hash != spec.terminal_block_hash {
            return Err(ExecutionPayloadError::InvalidTerminalBlockHash {
                terminal_block_hash: spec.terminal_block_hash,
                payload_parent_hash: execution_payload.parent_hash,
            }
            .into());
        }

        return Ok(());
    }

    let execution_layer = chain
        .execution_layer
        .as_ref()
        .ok_or(ExecutionPayloadError::NoExecutionConnection)?;

    let is_valid_terminal_pow_block = execution_layer
        .block_on(|execution_layer| {
            execution_layer.is_valid_terminal_pow_block_hash(execution_payload.parent_hash, spec)
        })
        .map_err(ExecutionPayloadError::from)?;

    match is_valid_terminal_pow_block {
        Some(true) => Ok(()),
        Some(false) => Err(ExecutionPayloadError::InvalidTerminalPoWBlock {
            parent_hash: execution_payload.parent_hash,
        }
        .into()),
        None => {
            debug!(
                chain.log,
                "Optimistically accepting terminal block";
                "block_hash" => ?execution_payload.parent_hash,
                "msg" => "the terminal block/parent was unavailable"
            );
            Ok(())
        }
    }
}

/// Validate the gossip block's execution_payload according to the checks described here:
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/p2p-interface.md#beacon_block
pub fn validate_execution_payload_for_gossip<T: BeaconChainTypes>(
    parent_block: &ProtoBlock,
    block: BeaconBlockRef<'_, T::EthSpec>,
    chain: &BeaconChain<T>,
) -> Result<(), BlockError<T::EthSpec>> {
    // Only apply this validation if this is a merge beacon block.
    if let Some(execution_payload) = block.body().execution_payload() {
        // This logic should match `is_execution_enabled`. We use only the execution block hash of
        // the parent here in order to avoid loading the parent state during gossip verification.

        let is_merge_transition_complete = match parent_block.execution_status {
            // Optimistically declare that an "unknown" status block has completed the merge.
            ExecutionStatus::Valid(_) | ExecutionStatus::Unknown(_) => true,
            // It's impossible for an irrelevant block to have completed the merge. It is pre-merge
            // by definition.
            ExecutionStatus::Irrelevant(_) => false,
            // If the parent has an invalid payload then it's impossible to build a valid block upon
            // it. Reject the block.
            ExecutionStatus::Invalid(_) => {
                return Err(BlockError::ParentExecutionPayloadInvalid {
                    parent_root: parent_block.root,
                })
            }
        };

        if is_merge_transition_complete || execution_payload != &<_>::default() {
            let expected_timestamp = chain
                .slot_clock
                .start_of(block.slot())
                .map(|d| d.as_secs())
                .ok_or(BlockError::BeaconChainError(
                    BeaconChainError::UnableToComputeTimeAtSlot,
                ))?;

            // The block's execution payload timestamp is correct with respect to the slot
            if execution_payload.timestamp != expected_timestamp {
                return Err(BlockError::ExecutionPayloadError(
                    ExecutionPayloadError::InvalidPayloadTimestamp {
                        expected: expected_timestamp,
                        found: execution_payload.timestamp,
                    },
                ));
            }
        }
    }

    Ok(())
}

/// Gets an execution payload for inclusion in a block.
///
/// ## Errors
///
/// Will return an error when using a pre-merge fork `state`. Ensure to only run this function
/// after the merge fork.
///
/// ## Specification
///
/// Equivalent to the `get_execution_payload` function in the Validator Guide:
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/validator.md#block-proposal
pub fn get_execution_payload<T: BeaconChainTypes>(
    chain: &BeaconChain<T>,
    state: &BeaconState<T::EthSpec>,
) -> Result<ExecutionPayload<T::EthSpec>, BlockProductionError> {
    Ok(prepare_execution_payload_blocking(chain, state)?.unwrap_or_default())
}

/// Wraps the async `prepare_execution_payload` function as a blocking task.
pub fn prepare_execution_payload_blocking<T: BeaconChainTypes>(
    chain: &BeaconChain<T>,
    state: &BeaconState<T::EthSpec>,
) -> Result<Option<ExecutionPayload<T::EthSpec>>, BlockProductionError> {
    let execution_layer = chain
        .execution_layer
        .as_ref()
        .ok_or(BlockProductionError::ExecutionLayerMissing)?;

    execution_layer
        .block_on_generic(|_| async { prepare_execution_payload(chain, state).await })
        .map_err(BlockProductionError::BlockingFailed)?
}

/// Prepares an execution payload for inclusion in a block.
///
/// Will return `Ok(None)` if the merge fork has occurred, but a terminal block has not been found.
///
/// ## Errors
///
/// Will return an error when using a pre-merge fork `state`. Ensure to only run this function
/// after the merge fork.
///
/// ## Specification
///
/// Equivalent to the `prepare_execution_payload` function in the Validator Guide:
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/validator.md#block-proposal
pub async fn prepare_execution_payload<T: BeaconChainTypes>(
    chain: &BeaconChain<T>,
    state: &BeaconState<T::EthSpec>,
) -> Result<Option<ExecutionPayload<T::EthSpec>>, BlockProductionError> {
    let spec = &chain.spec;
    let execution_layer = chain
        .execution_layer
        .as_ref()
        .ok_or(BlockProductionError::ExecutionLayerMissing)?;

    let parent_hash = if !is_merge_transition_complete(state) {
        let is_terminal_block_hash_set = spec.terminal_block_hash != Hash256::zero();
        let is_activation_epoch_reached =
            state.current_epoch() >= spec.terminal_block_hash_activation_epoch;

        if is_terminal_block_hash_set && !is_activation_epoch_reached {
            return Ok(None);
        }

        let terminal_pow_block_hash = execution_layer
            .get_terminal_pow_block_hash(spec)
            .await
            .map_err(BlockProductionError::TerminalPoWBlockLookupFailed)?;

        if let Some(terminal_pow_block_hash) = terminal_pow_block_hash {
            terminal_pow_block_hash
        } else {
            return Ok(None);
        }
    } else {
        state.latest_execution_payload_header()?.block_hash
    };

    let timestamp = compute_timestamp_at_slot(state, spec).map_err(BeaconStateError::from)?;
    let random = *state.get_randao_mix(state.current_epoch())?;
    let finalized_root = state.finalized_checkpoint().root;

    // The finalized block hash is not included in the specification, however we provide this
    // parameter so that the execution layer can produce a payload id if one is not already known
    // (e.g., due to a recent reorg).
    let finalized_block_hash =
        if let Some(block) = chain.fork_choice.read().get_block(&finalized_root) {
            block.execution_status.block_hash()
        } else {
            chain
                .store
                .get_block(&finalized_root)
                .map_err(BlockProductionError::FailedToReadFinalizedBlock)?
                .ok_or(BlockProductionError::MissingFinalizedBlock(finalized_root))?
                .message()
                .body()
                .execution_payload()
                .map(|ep| ep.block_hash)
        };

    // Note: the suggested_fee_recipient is stored in the `execution_layer`, it will add this parameter.
    let execution_payload = execution_layer
        .get_payload(
            parent_hash,
            timestamp,
            random,
            finalized_block_hash.unwrap_or_else(Hash256::zero),
        )
        .await
        .map_err(BlockProductionError::GetPayloadFailed)?;

    Ok(Some(execution_payload))
}
<commit_msg>Only import blocks with valid execution payloads (#2869)<commit_after>//! This module contains various functions for producing and verifying `ExecutionPayloads`.
//!
//! Lighthouse tends to do payload tasks in *slightly* different locations to the specification.
//! This is because some tasks involve calling out to external servers and it's nice to keep those
//! away from our pure `state_processing` and `fork_choice` crates.
//!
//! So, this module contains functions that one might expect to find in other crates, but they live
//! here for good reason.

use crate::{
    BeaconChain, BeaconChainError, BeaconChainTypes, BlockError, BlockProductionError,
    ExecutionPayloadError,
};
use execution_layer::ExecutePayloadResponseStatus;
use fork_choice::PayloadVerificationStatus;
use proto_array::{Block as ProtoBlock, ExecutionStatus};
use slog::debug;
use slot_clock::SlotClock;
use state_processing::per_block_processing::{
    compute_timestamp_at_slot, is_execution_enabled, is_merge_transition_complete,
    partially_verify_execution_payload,
};
use types::*;

/// Verify that `execution_payload` contained by `block` is considered valid by an execution
/// engine.
///
/// ## Specification
///
/// Equivalent to the `execute_payload` function in the merge Beacon Chain Changes, although it
/// contains a few extra checks by running `partially_verify_execution_payload` first:
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/beacon-chain.md#execute_payload
pub fn execute_payload<T: BeaconChainTypes>(
    chain: &BeaconChain<T>,
    state: &BeaconState<T::EthSpec>,
    block: BeaconBlockRef<T::EthSpec>,
) -> Result<PayloadVerificationStatus, BlockError<T::EthSpec>> {
    if !is_execution_enabled(state, block.body()) {
        return Ok(PayloadVerificationStatus::Irrelevant);
    }

    let execution_payload = block.execution_payload()?;

    // Perform the initial stages of payload verification.
    //
    // We will duplicate these checks again during `per_block_processing`, however these checks
    // are cheap and doing them here ensures we protect the execution payload from junk.
    partially_verify_execution_payload(state, execution_payload, &chain.spec)
        .map_err(BlockError::PerBlockProcessingError)?;

    let execution_layer = chain
        .execution_layer
        .as_ref()
        .ok_or(ExecutionPayloadError::NoExecutionConnection)?;
    let execute_payload_response = execution_layer
        .block_on(|execution_layer| execution_layer.execute_payload(execution_payload));

    match execute_payload_response {
        Ok((status, _latest_valid_hash)) => match status {
            ExecutePayloadResponseStatus::Valid => Ok(PayloadVerificationStatus::Verified),
            // TODO(merge): invalidate any invalid ancestors of this block in fork choice.
            ExecutePayloadResponseStatus::Invalid => {
                Err(ExecutionPayloadError::RejectedByExecutionEngine.into())
            }
            ExecutePayloadResponseStatus::Syncing => Ok(PayloadVerificationStatus::NotVerified),
        },
        Err(_) => Err(ExecutionPayloadError::RejectedByExecutionEngine.into()),
    }
}

/// Verify that the block which triggers the merge is valid to be imported to fork choice.
///
/// ## Errors
///
/// Will return an error when using a pre-merge fork `state`. Ensure to only run this function
/// after the merge fork.
///
/// ## Specification
///
/// Equivalent to the `validate_merge_block` function in the merge Fork Choice Changes:
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/fork-choice.md#validate_merge_block
pub fn validate_merge_block<T: BeaconChainTypes>(
    chain: &BeaconChain<T>,
    block: BeaconBlockRef<T::EthSpec>,
) -> Result<(), BlockError<T::EthSpec>> {
    let spec = &chain.spec;
    let block_epoch = block.slot().epoch(T::EthSpec::slots_per_epoch());
    let execution_payload = block.execution_payload()?;

    if spec.terminal_block_hash != Hash256::zero() {
        if block_epoch < spec.terminal_block_hash_activation_epoch {
            return Err(ExecutionPayloadError::InvalidActivationEpoch {
                activation_epoch: spec.terminal_block_hash_activation_epoch,
                epoch: block_epoch,
            }
            .into());
        }

        if execution_payload.parent_hash != spec.terminal_block_hash {
            return Err(ExecutionPayloadError::InvalidTerminalBlockHash {
                terminal_block_hash: spec.terminal_block_hash,
                payload_parent_hash: execution_payload.parent_hash,
            }
            .into());
        }

        return Ok(());
    }

    let execution_layer = chain
        .execution_layer
        .as_ref()
        .ok_or(ExecutionPayloadError::NoExecutionConnection)?;

    let is_valid_terminal_pow_block = execution_layer
        .block_on(|execution_layer| {
            execution_layer.is_valid_terminal_pow_block_hash(execution_payload.parent_hash, spec)
        })
        .map_err(ExecutionPayloadError::from)?;

    match is_valid_terminal_pow_block {
        Some(true) => Ok(()),
        Some(false) => Err(ExecutionPayloadError::InvalidTerminalPoWBlock {
            parent_hash: execution_payload.parent_hash,
        }
        .into()),
        None => {
            debug!(
                chain.log,
                "Optimistically accepting terminal block";
                "block_hash" => ?execution_payload.parent_hash,
                "msg" => "the terminal block/parent was unavailable"
            );
            Ok(())
        }
    }
}

/// Validate the gossip block's execution_payload according to the checks described here:
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/p2p-interface.md#beacon_block
pub fn validate_execution_payload_for_gossip<T: BeaconChainTypes>(
    parent_block: &ProtoBlock,
    block: BeaconBlockRef<'_, T::EthSpec>,
    chain: &BeaconChain<T>,
) -> Result<(), BlockError<T::EthSpec>> {
    // Only apply this validation if this is a merge beacon block.
    if let Some(execution_payload) = block.body().execution_payload() {
        // This logic should match `is_execution_enabled`. We use only the execution block hash of
        // the parent here in order to avoid loading the parent state during gossip verification.

        let is_merge_transition_complete = match parent_block.execution_status {
            // Optimistically declare that an "unknown" status block has completed the merge.
            ExecutionStatus::Valid(_) | ExecutionStatus::Unknown(_) => true,
            // It's impossible for an irrelevant block to have completed the merge. It is pre-merge
            // by definition.
            ExecutionStatus::Irrelevant(_) => false,
            // If the parent has an invalid payload then it's impossible to build a valid block upon
            // it. Reject the block.
            ExecutionStatus::Invalid(_) => {
                return Err(BlockError::ParentExecutionPayloadInvalid {
                    parent_root: parent_block.root,
                })
            }
        };

        if is_merge_transition_complete || execution_payload != &<_>::default() {
            let expected_timestamp = chain
                .slot_clock
                .start_of(block.slot())
                .map(|d| d.as_secs())
                .ok_or(BlockError::BeaconChainError(
                    BeaconChainError::UnableToComputeTimeAtSlot,
                ))?;

            // The block's execution payload timestamp is correct with respect to the slot
            if execution_payload.timestamp != expected_timestamp {
                return Err(BlockError::ExecutionPayloadError(
                    ExecutionPayloadError::InvalidPayloadTimestamp {
                        expected: expected_timestamp,
                        found: execution_payload.timestamp,
                    },
                ));
            }
        }
    }

    Ok(())
}

/// Gets an execution payload for inclusion in a block.
///
/// ## Errors
///
/// Will return an error when using a pre-merge fork `state`. Ensure to only run this function
/// after the merge fork.
///
/// ## Specification
///
/// Equivalent to the `get_execution_payload` function in the Validator Guide:
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/validator.md#block-proposal
pub fn get_execution_payload<T: BeaconChainTypes>(
    chain: &BeaconChain<T>,
    state: &BeaconState<T::EthSpec>,
) -> Result<ExecutionPayload<T::EthSpec>, BlockProductionError> {
    Ok(prepare_execution_payload_blocking(chain, state)?.unwrap_or_default())
}

/// Wraps the async `prepare_execution_payload` function as a blocking task.
pub fn prepare_execution_payload_blocking<T: BeaconChainTypes>(
    chain: &BeaconChain<T>,
    state: &BeaconState<T::EthSpec>,
) -> Result<Option<ExecutionPayload<T::EthSpec>>, BlockProductionError> {
    let execution_layer = chain
        .execution_layer
        .as_ref()
        .ok_or(BlockProductionError::ExecutionLayerMissing)?;

    execution_layer
        .block_on_generic(|_| async { prepare_execution_payload(chain, state).await })
        .map_err(BlockProductionError::BlockingFailed)?
}

/// Prepares an execution payload for inclusion in a block.
///
/// Will return `Ok(None)` if the merge fork has occurred, but a terminal block has not been found.
///
/// ## Errors
///
/// Will return an error when using a pre-merge fork `state`. Ensure to only run this function
/// after the merge fork.
///
/// ## Specification
///
/// Equivalent to the `prepare_execution_payload` function in the Validator Guide:
///
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/validator.md#block-proposal
pub async fn prepare_execution_payload<T: BeaconChainTypes>(
    chain: &BeaconChain<T>,
    state: &BeaconState<T::EthSpec>,
) -> Result<Option<ExecutionPayload<T::EthSpec>>, BlockProductionError> {
    let spec = &chain.spec;
    let execution_layer = chain
        .execution_layer
        .as_ref()
        .ok_or(BlockProductionError::ExecutionLayerMissing)?;

    let parent_hash = if !is_merge_transition_complete(state) {
        let is_terminal_block_hash_set = spec.terminal_block_hash != Hash256::zero();
        let is_activation_epoch_reached =
            state.current_epoch() >= spec.terminal_block_hash_activation_epoch;

        if is_terminal_block_hash_set && !is_activation_epoch_reached {
            return Ok(None);
        }

        let terminal_pow_block_hash = execution_layer
            .get_terminal_pow_block_hash(spec)
            .await
            .map_err(BlockProductionError::TerminalPoWBlockLookupFailed)?;

        if let Some(terminal_pow_block_hash) = terminal_pow_block_hash {
            terminal_pow_block_hash
        } else {
            return Ok(None);
        }
    } else {
        state.latest_execution_payload_header()?.block_hash
    };

    let timestamp = compute_timestamp_at_slot(state, spec).map_err(BeaconStateError::from)?;
    let random = *state.get_randao_mix(state.current_epoch())?;
    let finalized_root = state.finalized_checkpoint().root;

    // The finalized block hash is not included in the specification, however we provide this
    // parameter so that the execution layer can produce a payload id if one is not already known
    // (e.g., due to a recent reorg).
    let finalized_block_hash =
        if let Some(block) = chain.fork_choice.read().get_block(&finalized_root) {
            block.execution_status.block_hash()
        } else {
            chain
                .store
                .get_block(&finalized_root)
                .map_err(BlockProductionError::FailedToReadFinalizedBlock)?
                .ok_or(BlockProductionError::MissingFinalizedBlock(finalized_root))?
                .message()
                .body()
                .execution_payload()
                .map(|ep| ep.block_hash)
        };

    // Note: the suggested_fee_recipient is stored in the `execution_layer`, it will add this parameter.
    let execution_payload = execution_layer
        .get_payload(
            parent_hash,
            timestamp,
            random,
            finalized_block_hash.unwrap_or_else(Hash256::zero),
        )
        .await
        .map_err(BlockProductionError::GetPayloadFailed)?;

    Ok(Some(execution_payload))
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLTableElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLTableElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLTableElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLTableElement {
    pub htmlelement: HTMLElement,
}

impl HTMLTableElementDerived for EventTarget {
    fn is_htmltableelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLTableElementTypeId))
    }
}

impl HTMLTableElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLTableElement {
        HTMLTableElement {
            htmlelement: HTMLElement::new_inherited(HTMLTableElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLTableElement> {
        let element = HTMLTableElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLTableElementBinding::Wrap)
    }
}

pub trait HTMLTableElementMethods {
    fn DeleteCaption(&self);
    fn DeleteTHead(&self);
    fn DeleteTFoot(&self);
    fn DeleteRow(&mut self, _index: i32) -> ErrorResult;
    fn Sortable(&self) -> bool;
    fn SetSortable(&self, _sortable: bool);
    fn StopSorting(&self);
    fn Align(&self) -> DOMString;
    fn SetAlign(&self, _align: DOMString) -> ErrorResult;
    fn Border(&self) -> DOMString;
    fn SetBorder(&self, _border: DOMString) -> ErrorResult;
    fn Frame(&self) -> DOMString;
    fn SetFrame(&self, _frame: DOMString) -> ErrorResult;
    fn Rules(&self) -> DOMString;
    fn SetRules(&self, _rules: DOMString) -> ErrorResult;
    fn Summary(&self) -> DOMString;
    fn SetSummary(&self, _summary: DOMString) -> ErrorResult;
    fn Width(&self) -> DOMString;
    fn SetWidth(&self, _width: DOMString) -> ErrorResult;
    fn BgColor(&self) -> DOMString;
    fn SetBgColor(&self, _bg_color: DOMString) -> ErrorResult;
    fn CellPadding(&self) -> DOMString;
    fn SetCellPadding(&self, _cell_padding: DOMString) -> ErrorResult;
    fn CellSpacing(&self) -> DOMString;
    fn SetCellSpacing(&self, _cell_spacing: DOMString) -> ErrorResult;
}

impl<'a> HTMLTableElementMethods for JSRef<'a, HTMLTableElement> {
    fn DeleteCaption(&self) {
    }

    fn DeleteTHead(&self) {
    }

    fn DeleteTFoot(&self) {
    }

    fn DeleteRow(&mut self, _index: i32) -> ErrorResult {
        Ok(())
    }

    fn Sortable(&self) -> bool {
        false
    }

    fn SetSortable(&self, _sortable: bool) {
    }

    fn StopSorting(&self) {
    }

    fn Align(&self) -> DOMString {
        "".to_owned()
    }

    fn SetAlign(&self, _align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Border(&self) -> DOMString {
        "".to_owned()
    }

    fn SetBorder(&self, _border: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Frame(&self) -> DOMString {
        "".to_owned()
    }

    fn SetFrame(&self, _frame: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Rules(&self) -> DOMString {
        "".to_owned()
    }

    fn SetRules(&self, _rules: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Summary(&self) -> DOMString {
        "".to_owned()
    }

    fn SetSummary(&self, _summary: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Width(&self) -> DOMString {
        "".to_owned()
    }

    fn SetWidth(&self, _width: DOMString) -> ErrorResult {
        Ok(())
    }

    fn BgColor(&self) -> DOMString {
        "".to_owned()
    }

    fn SetBgColor(&self, _bg_color: DOMString) -> ErrorResult {
        Ok(())
    }

    fn CellPadding(&self) -> DOMString {
        "".to_owned()
    }

    fn SetCellPadding(&self, _cell_padding: DOMString) -> ErrorResult {
        Ok(())
    }

    fn CellSpacing(&self) -> DOMString {
        "".to_owned()
    }

    fn SetCellSpacing(&self, _cell_spacing: DOMString) -> ErrorResult {
        Ok(())
    }
}
<commit_msg>Remove needless '&mut self' from HTMLTableElementMethods.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLTableElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLTableElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLTableElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLTableElement {
    pub htmlelement: HTMLElement,
}

impl HTMLTableElementDerived for EventTarget {
    fn is_htmltableelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLTableElementTypeId))
    }
}

impl HTMLTableElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLTableElement {
        HTMLTableElement {
            htmlelement: HTMLElement::new_inherited(HTMLTableElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLTableElement> {
        let element = HTMLTableElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLTableElementBinding::Wrap)
    }
}

pub trait HTMLTableElementMethods {
    fn DeleteCaption(&self);
    fn DeleteTHead(&self);
    fn DeleteTFoot(&self);
    fn DeleteRow(&self, _index: i32) -> ErrorResult;
    fn Sortable(&self) -> bool;
    fn SetSortable(&self, _sortable: bool);
    fn StopSorting(&self);
    fn Align(&self) -> DOMString;
    fn SetAlign(&self, _align: DOMString) -> ErrorResult;
    fn Border(&self) -> DOMString;
    fn SetBorder(&self, _border: DOMString) -> ErrorResult;
    fn Frame(&self) -> DOMString;
    fn SetFrame(&self, _frame: DOMString) -> ErrorResult;
    fn Rules(&self) -> DOMString;
    fn SetRules(&self, _rules: DOMString) -> ErrorResult;
    fn Summary(&self) -> DOMString;
    fn SetSummary(&self, _summary: DOMString) -> ErrorResult;
    fn Width(&self) -> DOMString;
    fn SetWidth(&self, _width: DOMString) -> ErrorResult;
    fn BgColor(&self) -> DOMString;
    fn SetBgColor(&self, _bg_color: DOMString) -> ErrorResult;
    fn CellPadding(&self) -> DOMString;
    fn SetCellPadding(&self, _cell_padding: DOMString) -> ErrorResult;
    fn CellSpacing(&self) -> DOMString;
    fn SetCellSpacing(&self, _cell_spacing: DOMString) -> ErrorResult;
}

impl<'a> HTMLTableElementMethods for JSRef<'a, HTMLTableElement> {
    fn DeleteCaption(&self) {
    }

    fn DeleteTHead(&self) {
    }

    fn DeleteTFoot(&self) {
    }

    fn DeleteRow(&self, _index: i32) -> ErrorResult {
        Ok(())
    }

    fn Sortable(&self) -> bool {
        false
    }

    fn SetSortable(&self, _sortable: bool) {
    }

    fn StopSorting(&self) {
    }

    fn Align(&self) -> DOMString {
        "".to_owned()
    }

    fn SetAlign(&self, _align: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Border(&self) -> DOMString {
        "".to_owned()
    }

    fn SetBorder(&self, _border: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Frame(&self) -> DOMString {
        "".to_owned()
    }

    fn SetFrame(&self, _frame: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Rules(&self) -> DOMString {
        "".to_owned()
    }

    fn SetRules(&self, _rules: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Summary(&self) -> DOMString {
        "".to_owned()
    }

    fn SetSummary(&self, _summary: DOMString) -> ErrorResult {
        Ok(())
    }

    fn Width(&self) -> DOMString {
        "".to_owned()
    }

    fn SetWidth(&self, _width: DOMString) -> ErrorResult {
        Ok(())
    }

    fn BgColor(&self) -> DOMString {
        "".to_owned()
    }

    fn SetBgColor(&self, _bg_color: DOMString) -> ErrorResult {
        Ok(())
    }

    fn CellPadding(&self) -> DOMString {
        "".to_owned()
    }

    fn SetCellPadding(&self, _cell_padding: DOMString) -> ErrorResult {
        Ok(())
    }

    fn CellSpacing(&self) -> DOMString {
        "".to_owned()
    }

    fn SetCellSpacing(&self, _cell_spacing: DOMString) -> ErrorResult {
        Ok(())
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use std::cell::RefCell;
use std::ops::Deref;
use std::any::Any;
use std::fs::{File};
use std::io::Error;
use std::path::Path;
use std::io::Write;

use ::paint::{Point, Rect};
use ::draw::{BoundingBox};
use ::props::{Directionality, Color};
use ::skia_sys::{Surface, Paint, ImageInfo, ColorType, AlphaType, Typeface,
             Color as SkiaColor, TextEncoding, Rect as SkiaRect, Path as SkiaPath};

pub struct Canvas {
    surface: Surface,
    paint: RefCell<Paint>
}

impl Canvas {
    pub fn new(width: f32, height: f32, typeface: &Typeface) -> Canvas {
        let surface = Surface::new_raster(&ImageInfo {
            width: width.ceil() as i32,
            height: height.ceil() as i32,
            colorType: ColorType::default_8888(),
            alphaType: AlphaType::PREMUL_SK_ALPHATYPE,
        }, &None);

        let mut paint = Paint::new();
        paint.set_typeface(typeface);

        Canvas {
            surface,
            paint: RefCell::new(paint),
        }
    }

    pub fn snapshot(&self, path: &Path) -> Result<(), Error> {
        let data = self.surface.new_image_snapshot().encode();
        let mut file = File::create(path)?;

        file.write(data.get_data())?;

        Ok(())
    }
}

impl ::paint::Canvas for Canvas {
    fn draw_text(&self, top_left: &Point, bound: &BoundingBox, text: &str, color: &Color, size: f32,
                 _: &Directionality) {

        let mut paint = self.paint.borrow_mut();
        paint.set_color(&SkiaColor {
            r: color.r(),
            g: color.g(),
            b: color.b(),
            a: color.a(),
        });
        paint.set_text_size(size);
        paint.set_text_encoding(TextEncoding::kUTF8_TextEncoding);
        paint.set_antialias(true);
        paint.set_stroke(false);

        self.surface.get_canvas().draw_text(text, top_left.x(), top_left.y()+bound.baseline_pos(),
                                            paint.deref());
    }

    fn draw_glyph(&self, top_left: &Point, bounds: &BoundingBox, glyph_index: u32, color: &Color,
                  size: f32, _: &Directionality) {
        let mut paint = self.paint.borrow_mut();
        paint.set_color(&SkiaColor {
            r: color.r(),
            g: color.g(),
            b: color.b(),
            a: color.a(),
        });
        paint.set_text_size(size);
        paint.set_text_encoding(TextEncoding::kGlyphID_TextEncoding);
        paint.set_antialias(true);
        paint.set_stroke(false);

        self.surface.get_canvas().draw_blob(&[glyph_index as u16], top_left.x(),
                                            top_left.y()+bounds.baseline_pos(), paint.deref());
    }

    fn draw_rect(&self, top_left: &Point, rect: &Rect, color: &Color) {
        let mut paint = self.paint.borrow_mut();
        paint.set_color(&SkiaColor {
            r: color.r(),
            g: color.g(),
            b: color.b(),
            a: color.a(),
        });
        paint.set_antialias(true);
        paint.set_stroke(false);

        self.surface.get_canvas().draw_rect(&SkiaRect {
            left: top_left.x(),
            top: top_left.y(),
            right: top_left.x()+rect.width(),
            bottom: top_left.y()+rect.height(),
        }, paint.deref());
    }

    fn draw_rect_outline(&self, top_left: &Point, rect: &Rect, color: &Color, stroke_width: f32) {
        let mut paint = self.paint.borrow_mut();
        paint.set_color(&SkiaColor {
            r: color.r(),
            g: color.g(),
            b: color.b(),
            a: color.a(),
        });
        paint.set_antialias(true);
        paint.set_stroke(true);
        paint.set_stroke_width(stroke_width);

        self.surface.get_canvas().draw_rect(&SkiaRect {
            left: top_left.x(),
            top: top_left.y(),
            right: top_left.x()+rect.width(),
            bottom: top_left.y()+rect.height(),
        }, paint.deref());
    }

    fn draw_line(&self, start: &Point, end: &Point, color: &Color, stroke_width: f32) {
        let mut paint = self.paint.borrow_mut();
        paint.set_color(&SkiaColor {
            r: color.r(),
            g: color.g(),
            b: color.b(),
            a: color.a(),
        });
        paint.set_antialias(true);
        paint.set_stroke(true);
        paint.set_stroke_width(stroke_width);

        let mut path = SkiaPath::new();
        path.move_to(start.x(), start.y());
        path.line_to(end.x(), end.y());

        self.surface.get_canvas().draw_path(&path, paint.deref());
    }

    fn as_any(&self) -> &Any {
        self
    }
}<commit_msg>Fix drawing glyph variants<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use std::cell::RefCell;
use std::ops::Deref;
use std::any::Any;
use std::fs::{File};
use std::io::Error;
use std::path::Path;
use std::io::Write;

use ::paint::{Point, Rect};
use ::draw::{BoundingBox};
use ::props::{Directionality, Color};
use ::skia_sys::{Surface, Paint, ImageInfo, ColorType, AlphaType, Typeface,
             Color as SkiaColor, TextEncoding, Rect as SkiaRect, Path as SkiaPath};

pub struct Canvas {
    surface: Surface,
    paint: RefCell<Paint>
}

impl Canvas {
    pub fn new(width: f32, height: f32, typeface: &Typeface) -> Canvas {
        let surface = Surface::new_raster(&ImageInfo {
            width: width.ceil() as i32,
            height: height.ceil() as i32,
            colorType: ColorType::default_8888(),
            alphaType: AlphaType::PREMUL_SK_ALPHATYPE,
        }, &None);

        let mut paint = Paint::new();
        paint.set_typeface(typeface);

        Canvas {
            surface,
            paint: RefCell::new(paint),
        }
    }

    pub fn snapshot(&self, path: &Path) -> Result<(), Error> {
        let data = self.surface.new_image_snapshot().encode();
        let mut file = File::create(path)?;

        file.write(data.get_data())?;

        Ok(())
    }
}

impl ::paint::Canvas for Canvas {
    fn draw_text(&self, top_left: &Point, bound: &BoundingBox, text: &str, color: &Color, size: f32,
                 _: &Directionality) {

        let mut paint = self.paint.borrow_mut();
        paint.set_color(&SkiaColor {
            r: color.r(),
            g: color.g(),
            b: color.b(),
            a: color.a(),
        });
        paint.set_text_size(size);
        paint.set_text_encoding(TextEncoding::kUTF8_TextEncoding);
        paint.set_antialias(true);
        paint.set_stroke(false);

        self.surface.get_canvas().draw_text(text, top_left.x(), top_left.y()+bound.baseline_pos(),
                                            paint.deref());
    }

    fn draw_glyph(&self, top_left: &Point, bounds: &BoundingBox, glyph_index: u32, color: &Color,
                  size: f32, _: &Directionality) {
        let mut paint = self.paint.borrow_mut();
        paint.set_color(&SkiaColor {
            r: color.r(),
            g: color.g(),
            b: color.b(),
            a: color.a(),
        });
        paint.set_text_size(size);
        paint.set_text_encoding(TextEncoding::kGlyphID_TextEncoding);
        paint.set_antialias(true);
        paint.set_stroke(false);

        let baseline_pos = if bounds.rect().height()-size > 5f32 {
            bounds.rect().height()-size
        } else {
            bounds.baseline_pos()
        };

        self.surface.get_canvas().draw_blob(&[glyph_index as u16], top_left.x(),
                                            top_left.y()+baseline_pos, paint.deref());
    }

    fn draw_rect(&self, top_left: &Point, rect: &Rect, color: &Color) {
        let mut paint = self.paint.borrow_mut();
        paint.set_color(&SkiaColor {
            r: color.r(),
            g: color.g(),
            b: color.b(),
            a: color.a(),
        });
        paint.set_antialias(true);
        paint.set_stroke(false);

        self.surface.get_canvas().draw_rect(&SkiaRect {
            left: top_left.x(),
            top: top_left.y(),
            right: top_left.x()+rect.width(),
            bottom: top_left.y()+rect.height(),
        }, paint.deref());
    }

    fn draw_rect_outline(&self, top_left: &Point, rect: &Rect, color: &Color, stroke_width: f32) {
        let mut paint = self.paint.borrow_mut();
        paint.set_color(&SkiaColor {
            r: color.r(),
            g: color.g(),
            b: color.b(),
            a: color.a(),
        });
        paint.set_antialias(true);
        paint.set_stroke(true);
        paint.set_stroke_width(stroke_width);

        self.surface.get_canvas().draw_rect(&SkiaRect {
            left: top_left.x(),
            top: top_left.y(),
            right: top_left.x()+rect.width(),
            bottom: top_left.y()+rect.height(),
        }, paint.deref());
    }

    fn draw_line(&self, start: &Point, end: &Point, color: &Color, stroke_width: f32) {
        let mut paint = self.paint.borrow_mut();
        paint.set_color(&SkiaColor {
            r: color.r(),
            g: color.g(),
            b: color.b(),
            a: color.a(),
        });
        paint.set_antialias(true);
        paint.set_stroke(true);
        paint.set_stroke_width(stroke_width);

        let mut path = SkiaPath::new();
        path.move_to(start.x(), start.y());
        path.line_to(end.x(), end.y());

        self.surface.get_canvas().draw_path(&path, paint.deref());
    }

    fn as_any(&self) -> &Any {
        self
    }
}<|endoftext|>