2016-02-05 13:40:41 +01:00
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity 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 General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
2016-08-30 11:10:59 +02:00
use crypto ::sha2 ::Sha256 as Sha256Digest ;
use crypto ::ripemd160 ::Ripemd160 as Ripemd160Digest ;
2016-01-08 00:26:52 +01:00
use crypto ::digest ::Digest ;
2016-08-24 18:35:21 +02:00
use util ::* ;
2016-08-30 11:10:59 +02:00
use ethkey ::{ Signature , recover as ec_recover } ;
2016-04-09 19:20:35 +02:00
use ethjson ;
2015-12-20 21:45:43 +01:00
2016-08-30 11:10:59 +02:00
/// Native implementation of a built-in contract.
pub trait Impl : Send + Sync {
/// execute this built-in on the given input, writing to the given output.
fn execute ( & self , input : & [ u8 ] , out : & mut [ u8 ] ) ;
2015-12-20 21:45:43 +01:00
}
2016-01-04 22:47:45 +01:00
2016-08-30 11:10:59 +02:00
/// A gas pricing scheme for built-in contracts.
pub trait Pricer : Send + Sync {
/// The gas cost of running this built-in for the given size of input data.
fn cost ( & self , in_size : usize ) -> U256 ;
}
2016-01-11 11:51:31 +01:00
2016-08-30 11:10:59 +02:00
/// A linear pricing model. This computes a price using a base cost and a cost per-word.
struct Linear {
base : usize ,
word : usize ,
2016-01-07 19:10:29 +01:00
}
2016-08-30 11:10:59 +02:00
impl Pricer for Linear {
fn cost ( & self , in_size : usize ) -> U256 {
U256 ::from ( self . base ) + U256 ::from ( self . word ) * U256 ::from ( ( in_size + 31 ) / 32 )
2016-01-05 19:11:41 +01:00
}
2016-08-30 11:10:59 +02:00
}
2016-01-05 19:11:41 +01:00
2016-08-30 11:10:59 +02:00
/// Pricing scheme and execution definition for a built-in contract.
pub struct Builtin {
pricer : Box < Pricer > ,
native : Box < Impl > ,
}
2016-01-05 19:11:41 +01:00
2016-08-30 11:10:59 +02:00
impl Builtin {
2016-01-14 21:58:37 +01:00
/// Simple forwarder for cost.
2016-08-30 11:10:59 +02:00
pub fn cost ( & self , s : usize ) -> U256 { self . pricer . cost ( s ) }
2016-01-14 21:58:37 +01:00
/// Simple forwarder for execute.
2016-08-30 11:10:59 +02:00
pub fn execute ( & self , input : & [ u8 ] , output : & mut [ u8 ] ) { self . native . execute ( input , output ) }
2016-04-09 19:20:35 +02:00
}
2016-01-14 21:58:37 +01:00
2016-04-09 19:20:35 +02:00
impl From < ethjson ::spec ::Builtin > for Builtin {
fn from ( b : ethjson ::spec ::Builtin ) -> Self {
2016-08-30 11:10:59 +02:00
let pricer = match b . pricing {
2016-04-09 19:20:35 +02:00
ethjson ::spec ::Pricing ::Linear ( linear ) = > {
2016-08-30 11:10:59 +02:00
Box ::new ( Linear {
base : linear . base ,
word : linear . word ,
} )
2016-01-05 19:11:41 +01:00
}
2016-08-30 11:10:59 +02:00
} ;
Builtin {
pricer : pricer ,
native : ethereum_builtin ( & b . name ) ,
2016-01-05 19:11:41 +01:00
}
}
}
2016-08-30 11:10:59 +02:00
// Ethereum builtin creator.
fn ethereum_builtin ( name : & str ) -> Box < Impl > {
match name {
" identity " = > Box ::new ( Identity ) as Box < Impl > ,
" ecrecover " = > Box ::new ( EcRecover ) as Box < Impl > ,
" sha256 " = > Box ::new ( Sha256 ) as Box < Impl > ,
" ripemd160 " = > Box ::new ( Ripemd160 ) as Box < Impl > ,
_ = > panic! ( " invalid builtin name: {} " , name ) ,
2016-01-08 00:26:52 +01:00
}
2016-01-04 22:47:45 +01:00
}
2016-08-30 11:10:59 +02:00
// Ethereum builtins:
//
// - The identity function
// - ec recovery
// - sha256
// - ripemd160
#[ derive(Debug) ]
struct Identity ;
#[ derive(Debug) ]
struct EcRecover ;
#[ derive(Debug) ]
struct Sha256 ;
#[ derive(Debug) ]
struct Ripemd160 ;
impl Impl for Identity {
fn execute ( & self , input : & [ u8 ] , output : & mut [ u8 ] ) {
let len = min ( input . len ( ) , output . len ( ) ) ;
output [ .. len ] . copy_from_slice ( & input [ .. len ] ) ;
}
}
impl Impl for EcRecover {
fn execute ( & self , i : & [ u8 ] , output : & mut [ u8 ] ) {
let len = min ( i . len ( ) , 128 ) ;
let mut input = [ 0 ; 128 ] ;
input [ .. len ] . copy_from_slice ( & i [ .. len ] ) ;
let hash = H256 ::from_slice ( & input [ 0 .. 32 ] ) ;
let v = H256 ::from_slice ( & input [ 32 .. 64 ] ) ;
let r = H256 ::from_slice ( & input [ 64 .. 96 ] ) ;
let s = H256 ::from_slice ( & input [ 96 .. 128 ] ) ;
let bit = match v [ 31 ] {
27 | 28 if & v . as_slice ( ) [ .. 31 ] = = & [ 0 ; 31 ] = > v [ 31 ] - 27 ,
_ = > return ,
} ;
let s = Signature ::from_rsv ( & r , & s , bit ) ;
if s . is_valid ( ) {
if let Ok ( p ) = ec_recover ( & s , & hash ) {
let r = p . as_slice ( ) . sha3 ( ) ;
let out_len = min ( output . len ( ) , 32 ) ;
for x in & mut output [ 0 .. min ( 12 , out_len ) ] {
* x = 0 ;
}
if out_len > 12 {
output [ 12 .. out_len ] . copy_from_slice ( & r [ 12 .. out_len ] ) ;
2016-01-07 23:55:14 +01:00
}
2016-01-07 19:10:29 +01:00
}
2016-04-09 19:20:35 +02:00
}
2016-01-04 22:47:45 +01:00
}
}
2016-08-30 11:10:59 +02:00
impl Impl for Sha256 {
fn execute ( & self , input : & [ u8 ] , output : & mut [ u8 ] ) {
let out_len = min ( output . len ( ) , 32 ) ;
2016-01-05 19:11:41 +01:00
2016-08-30 11:10:59 +02:00
let mut sha = Sha256Digest ::new ( ) ;
sha . input ( input ) ;
2016-01-05 19:11:41 +01:00
2016-08-30 11:10:59 +02:00
if out_len = = 32 {
sha . result ( & mut output [ 0 .. 32 ] ) ;
} else {
let mut out = [ 0 ; 32 ] ;
sha . result ( & mut out ) ;
2016-01-05 19:11:41 +01:00
2016-08-30 11:10:59 +02:00
output . copy_from_slice ( & out [ .. out_len ] )
}
}
2016-01-05 19:23:40 +01:00
}
2016-08-30 11:10:59 +02:00
impl Impl for Ripemd160 {
fn execute ( & self , input : & [ u8 ] , output : & mut [ u8 ] ) {
let out_len = min ( output . len ( ) , 32 ) ;
2016-01-08 00:26:52 +01:00
2016-08-30 11:10:59 +02:00
let mut sha = Ripemd160Digest ::new ( ) ;
sha . input ( input ) ;
for x in & mut output [ 0 .. min ( 12 , out_len ) ] {
* x = 0 ;
}
2016-01-08 00:26:52 +01:00
2016-08-30 11:10:59 +02:00
if out_len > = 32 {
sha . result ( & mut output [ 12 .. 32 ] ) ;
} else if out_len > 12 {
let mut out = [ 0 ; 20 ] ;
sha . result ( & mut out ) ;
2016-01-08 00:26:52 +01:00
2016-08-30 11:10:59 +02:00
output . copy_from_slice ( & out [ 12 .. out_len ] )
}
}
2016-01-08 00:26:52 +01:00
}
2016-08-30 11:10:59 +02:00
#[ cfg(test) ]
mod tests {
use super ::{ Builtin , Linear , ethereum_builtin , Pricer } ;
use ethjson ;
use util ::U256 ;
2016-01-08 00:31:21 +01:00
2016-08-30 11:10:59 +02:00
#[ test ]
fn identity ( ) {
let f = ethereum_builtin ( " identity " ) ;
2016-01-08 00:31:21 +01:00
2016-08-30 11:10:59 +02:00
let i = [ 0 u8 , 1 , 2 , 3 ] ;
2016-01-08 00:31:21 +01:00
2016-08-30 11:10:59 +02:00
let mut o2 = [ 255 u8 ; 2 ] ;
f . execute ( & i [ .. ] , & mut o2 [ .. ] ) ;
assert_eq! ( i [ 0 .. 2 ] , o2 ) ;
2016-01-08 00:31:21 +01:00
2016-08-30 11:10:59 +02:00
let mut o4 = [ 255 u8 ; 4 ] ;
f . execute ( & i [ .. ] , & mut o4 [ .. ] ) ;
assert_eq! ( i , o4 ) ;
2016-01-07 23:55:14 +01:00
2016-08-30 11:10:59 +02:00
let mut o8 = [ 255 u8 ; 8 ] ;
f . execute ( & i [ .. ] , & mut o8 [ .. ] ) ;
assert_eq! ( i , o8 [ .. 4 ] ) ;
assert_eq! ( [ 255 u8 ; 4 ] , o8 [ 4 .. ] ) ;
}
2016-04-09 19:20:35 +02:00
2016-08-30 11:10:59 +02:00
#[ test ]
fn sha256 ( ) {
use rustc_serialize ::hex ::FromHex ;
let f = ethereum_builtin ( " sha256 " ) ;
2016-01-05 19:23:40 +01:00
2016-08-30 11:10:59 +02:00
let i = [ 0 u8 ; 0 ] ;
let mut o = [ 255 u8 ; 32 ] ;
f . execute ( & i [ .. ] , & mut o [ .. ] ) ;
assert_eq! ( & o [ .. ] , & ( FromHex ::from_hex ( " e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 " ) . unwrap ( ) ) [ .. ] ) ;
let mut o8 = [ 255 u8 ; 8 ] ;
f . execute ( & i [ .. ] , & mut o8 [ .. ] ) ;
assert_eq! ( & o8 [ .. ] , & ( FromHex ::from_hex ( " e3b0c44298fc1c14 " ) . unwrap ( ) ) [ .. ] ) ;
let mut o34 = [ 255 u8 ; 34 ] ;
f . execute ( & i [ .. ] , & mut o34 [ .. ] ) ;
assert_eq! ( & o34 [ .. ] , & ( FromHex ::from_hex ( " e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855ffff " ) . unwrap ( ) ) [ .. ] ) ;
}
#[ test ]
fn ripemd160 ( ) {
use rustc_serialize ::hex ::FromHex ;
let f = ethereum_builtin ( " ripemd160 " ) ;
let i = [ 0 u8 ; 0 ] ;
let mut o = [ 255 u8 ; 32 ] ;
f . execute ( & i [ .. ] , & mut o [ .. ] ) ;
assert_eq! ( & o [ .. ] , & ( FromHex ::from_hex ( " 0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31 " ) . unwrap ( ) ) [ .. ] ) ;
let mut o8 = [ 255 u8 ; 8 ] ;
f . execute ( & i [ .. ] , & mut o8 [ .. ] ) ;
assert_eq! ( & o8 [ .. ] , & ( FromHex ::from_hex ( " 0000000000000000 " ) . unwrap ( ) ) [ .. ] ) ;
let mut o34 = [ 255 u8 ; 34 ] ;
f . execute ( & i [ .. ] , & mut o34 [ .. ] ) ;
assert_eq! ( & o34 [ .. ] , & ( FromHex ::from_hex ( " 0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31ffff " ) . unwrap ( ) ) [ .. ] ) ;
}
#[ test ]
fn ecrecover ( ) {
use rustc_serialize ::hex ::FromHex ;
/* let k = KeyPair::from_secret(b"test".sha3()).unwrap();
let a : Address = From ::from ( k . public ( ) . sha3 ( ) ) ;
println! ( " Address: {} " , a ) ;
let m = b " hello world " . sha3 ( ) ;
println! ( " Message: {} " , m ) ;
let s = k . sign ( & m ) . unwrap ( ) ;
println! ( " Signed: {} " , s ) ; * /
let f = ethereum_builtin ( " ecrecover " ) ;
let i = FromHex ::from_hex ( " 47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03 " ) . unwrap ( ) ;
let mut o = [ 255 u8 ; 32 ] ;
f . execute ( & i [ .. ] , & mut o [ .. ] ) ;
assert_eq! ( & o [ .. ] , & ( FromHex ::from_hex ( " 000000000000000000000000c08b5542d177ac6686946920409741463a15dddb " ) . unwrap ( ) ) [ .. ] ) ;
let mut o8 = [ 255 u8 ; 8 ] ;
f . execute ( & i [ .. ] , & mut o8 [ .. ] ) ;
assert_eq! ( & o8 [ .. ] , & ( FromHex ::from_hex ( " 0000000000000000 " ) . unwrap ( ) ) [ .. ] ) ;
let mut o34 = [ 255 u8 ; 34 ] ;
f . execute ( & i [ .. ] , & mut o34 [ .. ] ) ;
assert_eq! ( & o34 [ .. ] , & ( FromHex ::from_hex ( " 000000000000000000000000c08b5542d177ac6686946920409741463a15dddbffff " ) . unwrap ( ) ) [ .. ] ) ;
let i_bad = FromHex ::from_hex ( " 47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001a650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03 " ) . unwrap ( ) ;
let mut o = [ 255 u8 ; 32 ] ;
f . execute ( & i_bad [ .. ] , & mut o [ .. ] ) ;
assert_eq! ( & o [ .. ] , & ( FromHex ::from_hex ( " ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff " ) . unwrap ( ) ) [ .. ] ) ;
let i_bad = FromHex ::from_hex ( " 47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000 " ) . unwrap ( ) ;
let mut o = [ 255 u8 ; 32 ] ;
f . execute ( & i_bad [ .. ] , & mut o [ .. ] ) ;
assert_eq! ( & o [ .. ] , & ( FromHex ::from_hex ( " ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff " ) . unwrap ( ) ) [ .. ] ) ;
let i_bad = FromHex ::from_hex ( " 47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b " ) . unwrap ( ) ;
let mut o = [ 255 u8 ; 32 ] ;
f . execute ( & i_bad [ .. ] , & mut o [ .. ] ) ;
assert_eq! ( & o [ .. ] , & ( FromHex ::from_hex ( " ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff " ) . unwrap ( ) ) [ .. ] ) ;
let i_bad = FromHex ::from_hex ( " 47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000001b " ) . unwrap ( ) ;
let mut o = [ 255 u8 ; 32 ] ;
f . execute ( & i_bad [ .. ] , & mut o [ .. ] ) ;
assert_eq! ( & o [ .. ] , & ( FromHex ::from_hex ( " ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff " ) . unwrap ( ) ) [ .. ] ) ;
let i_bad = FromHex ::from_hex ( " 47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff " ) . unwrap ( ) ;
let mut o = [ 255 u8 ; 32 ] ;
f . execute ( & i_bad [ .. ] , & mut o [ .. ] ) ;
assert_eq! ( & o [ .. ] , & ( FromHex ::from_hex ( " ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff " ) . unwrap ( ) ) [ .. ] ) ;
// TODO: Should this (corrupted version of the above) fail rather than returning some address?
/* let i_bad = FromHex::from_hex("48173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
let mut o = [ 255 u8 ; 32 ] ;
f . execute ( & i_bad [ .. ] , & mut o [ .. ] ) ;
assert_eq! ( & o [ .. ] , & ( FromHex ::from_hex ( " ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff " ) . unwrap ( ) ) [ .. ] ) ; * /
}
#[ test ]
#[ should_panic ]
fn from_unknown_linear ( ) {
let _ = ethereum_builtin ( " foo " ) ;
}
#[ test ]
fn from_named_linear ( ) {
let pricer = Box ::new ( Linear { base : 10 , word : 20 } ) ;
let b = Builtin {
pricer : pricer as Box < Pricer > ,
native : ethereum_builtin ( " identity " ) ,
} ;
assert_eq! ( b . cost ( 0 ) , U256 ::from ( 10 ) ) ;
assert_eq! ( b . cost ( 1 ) , U256 ::from ( 30 ) ) ;
assert_eq! ( b . cost ( 32 ) , U256 ::from ( 30 ) ) ;
assert_eq! ( b . cost ( 33 ) , U256 ::from ( 50 ) ) ;
let i = [ 0 u8 , 1 , 2 , 3 ] ;
let mut o = [ 255 u8 ; 4 ] ;
b . execute ( & i [ .. ] , & mut o [ .. ] ) ;
assert_eq! ( i , o ) ;
}
#[ test ]
fn from_json ( ) {
let b = Builtin ::from ( ethjson ::spec ::Builtin {
name : " identity " . to_owned ( ) ,
pricing : ethjson ::spec ::Pricing ::Linear ( ethjson ::spec ::Linear {
base : 10 ,
word : 20 ,
} )
} ) ;
assert_eq! ( b . cost ( 0 ) , U256 ::from ( 10 ) ) ;
assert_eq! ( b . cost ( 1 ) , U256 ::from ( 30 ) ) ;
assert_eq! ( b . cost ( 32 ) , U256 ::from ( 30 ) ) ;
assert_eq! ( b . cost ( 33 ) , U256 ::from ( 50 ) ) ;
let i = [ 0 u8 , 1 , 2 , 3 ] ;
let mut o = [ 255 u8 ; 4 ] ;
b . execute ( & i [ .. ] , & mut o [ .. ] ) ;
assert_eq! ( i , o ) ;
}
}