openethereum/crates/util/EIP-712/src/parser.rs

164 lines
5.0 KiB
Rust
Raw Normal View History

2020-09-22 14:53:52 +02:00
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
2020-09-22 14:53:52 +02:00
// OpenEthereum 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.
2020-09-22 14:53:52 +02:00
// OpenEthereum 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
2020-09-22 14:53:52 +02:00
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Solidity type-name parsing
use crate::error::*;
2020-08-05 06:08:03 +02:00
use lunarity_lexer::{Lexer, Token};
use std::{fmt, result};
#[derive(Debug, Clone, PartialEq)]
pub enum Type {
2020-08-05 06:08:03 +02:00
Address,
Uint,
Int,
String,
Bool,
Bytes,
Byte(u8),
Custom(String),
Array {
length: Option<u64>,
inner: Box<Type>,
},
}
impl From<Type> for String {
2020-08-05 06:08:03 +02:00
fn from(field_type: Type) -> String {
match field_type {
Type::Address => "address".into(),
Type::Uint => "uint".into(),
Type::Int => "int".into(),
Type::String => "string".into(),
Type::Bool => "bool".into(),
Type::Bytes => "bytes".into(),
Type::Byte(len) => format!("bytes{}", len),
Type::Custom(custom) => custom,
Type::Array { inner, length } => {
let inner: String = (*inner).into();
match length {
None => format!("{}[]", inner),
Some(length) => format!("{}[{}]", inner, length),
}
}
}
}
}
impl fmt::Display for Type {
2020-08-05 06:08:03 +02:00
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
let item: String = self.clone().into();
write!(f, "{}", item)
}
}
v2.5.10 stable (#11239) * ropsten #6631425 foundation #8798209 (#11201) * [stable] builtin, istanbul and mordor testnet backports (#11234) * ethcore-builtin (#10850) * [builtin]: support `multiple prices and activations` in chain spec (#11039) * [chain specs]: activate `Istanbul` on mainnet (#11228) * ethcore/res: add mordor testnet configuration (#11200) * Update list of bootnodes for xDai chain (#11236) * ethcore: remove `test-helper feat` from build (#11047) * Secret store: fix Instant::now() related race in net_keep_alive (#11155) (#11159) * [stable]: backport #10691 and #10683 (#11143) * Fix compiler warning (that will become an error) (#10683) * Refactor Clique stepping (#10691) * Add Constantinople eips to the dev (instant_seal) config (#10809) * Add cargo-remote dir to .gitignore (?) * Insert explicit warning into the panic hook (#11225) * Fix docker centos build (#11226) * Update MIX bootnodes. (#11203) * Use provided usd-per-eth value if an endpoint is specified (#11209) * Add new line after writing block to hex file. (#10984) * Type annotation for next_key() matching of json filter options (#11192) (but no `FilterOption` in 2.5 so…) * Upgrade jsonrpc to latest (#11206) * [CI] check evmbin build (#11096) * Correct EIP-712 encoding (#11092) * [client]: Fix for incorrectly dropped consensus messages (#11086) * Fix block detail updating (#11015) * Switching sccache from local to Redis (#10971) * Made ecrecover implementation trait public (#11188) * [dependencies]: jsonrpc `14.0.1` (#11183) * [receipt]: add `sender` & `receiver` to `RichReceipts` (#11179) * [ethcore/builtin]: do not panic in blake2pricer on short input (#11180) * util Host: fix a double Read Lock bug in fn Host::session_readable() (#11175) * ethcore client: fix a double Read Lock bug in fn Client::logs() (#11172) * Change how RPCs eth_call and eth_estimateGas handle "Pending" (#11127) * Cleanup stratum a bit (#11161) * Upgrade to jsonrpc v14 (#11151) * SecretStore: expose restore_key_public in HTTP API (#10241)
2019-11-11 21:57:38 +01:00
/// the type string is being validated before it's parsed.
pub fn parse_type(field_type: &str) -> Result<Type> {
2020-08-05 06:08:03 +02:00
#[derive(PartialEq)]
enum State {
Open,
Close,
}
let mut lexer = Lexer::new(field_type);
let mut token = None;
let mut state = State::Close;
let mut array_depth = 0;
let mut current_array_length: Option<u64> = None;
while lexer.token != Token::EndOfProgram {
let type_ = match lexer.token {
Token::Identifier => Type::Custom(lexer.slice().to_owned()),
Token::TypeByte => Type::Byte(lexer.extras.0),
Token::TypeBytes => Type::Bytes,
Token::TypeBool => Type::Bool,
Token::TypeUint => Type::Uint,
Token::TypeInt => Type::Int,
Token::TypeString => Type::String,
Token::TypeAddress => Type::Address,
Token::LiteralInteger => {
let length = lexer.slice();
current_array_length = Some(
length
.parse()
.map_err(|_| ErrorKind::InvalidArraySize(length.into()))?,
);
lexer.advance();
continue;
}
Token::BracketOpen if token.is_some() && state == State::Close => {
state = State::Open;
lexer.advance();
continue;
}
Token::BracketClose if array_depth < 10 => {
if state == State::Open && token.is_some() {
let length = current_array_length.take();
state = State::Close;
token = Some(Type::Array {
inner: Box::new(token.expect("if statement checks for some; qed")),
length,
});
lexer.advance();
array_depth += 1;
continue;
} else {
return Err(ErrorKind::UnexpectedToken(
lexer.slice().to_owned(),
field_type.to_owned(),
))?;
}
}
Token::BracketClose if array_depth == 10 => {
return Err(ErrorKind::UnsupportedArrayDepth)?;
}
_ => {
return Err(ErrorKind::UnexpectedToken(
lexer.slice().to_owned(),
field_type.to_owned(),
))?
}
};
token = Some(type_);
lexer.advance();
}
Ok(token.ok_or(ErrorKind::NonExistentType)?)
}
#[cfg(test)]
mod tests {
2020-08-05 06:08:03 +02:00
use super::*;
#[test]
fn test_parser() {
let source = "byte[][][7][][][][][][][]";
parse_type(source).unwrap();
}
#[test]
fn test_nested_array() {
let source = "byte[][][7][][][][][][][][]";
assert_eq!(parse_type(source).is_err(), true);
}
#[test]
fn test_malformed_array_type() {
let source = "byte[7[]uint][]";
assert_eq!(parse_type(source).is_err(), true)
}
}