Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.

Commit c3f154b

Browse files
committed
added type-name parser
1 parent 9af7964 commit c3f154b

File tree

6 files changed

+226
-105
lines changed

6 files changed

+226
-105
lines changed

Cargo.lock

Lines changed: 29 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

util/EIP-712/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ failure_derive = "0.1"
1717
lazy_static = "1.1"
1818
valico = "2.2"
1919
linked_hash_set = "0.1.3"
20-
regex = "1.0"
20+
toolshed = "0.4"
21+
lunarity = { git = "https://github.com/paritytech/lunarity" }
2122

2223
[dev-dependencies]
2324
hex = "0.3"

util/EIP-712/src/eip712.rs

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,15 @@
1414
// You should have received a copy of the GNU General Public License
1515
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
1616

17+
//! EIP712 structs
18+
//!
19+
1720
use serde_json::{Value};
1821
use std::collections::HashMap;
19-
use serde::de;
20-
use std::fmt;
2122
use ethereum_types::{U256, H256, Address};
22-
use regex::Regex;
2323

2424
pub(crate) type MessageTypes = HashMap<String, Vec<FieldType>>;
2525

26-
lazy_static! {
27-
static ref RE: Regex = Regex::new(r"[a-zA-z](\[(([1-9][0-9])*)?\]+)?(([1-9][0-9])*)?").unwrap();
28-
}
2926

3027
#[serde(rename_all = "camelCase")]
3128
#[serde(deny_unknown_fields)]
@@ -51,37 +48,9 @@ pub struct EIP712 {
5148

5249
#[derive(Serialize, Deserialize, Debug, Clone)]
5350
pub(crate) struct FieldType {
54-
#[serde(deserialize_with = "deserialize_field_type_name")]
5551
pub name: String,
5652
#[serde(rename = "type")]
57-
pub type_: String
58-
}
59-
60-
fn deserialize_field_type_name<'de, D>(deserializer: D) -> Result<String, D::Error>
61-
where
62-
D: de::Deserializer<'de>,
63-
{
64-
struct FieldTypeNameVisitor;
65-
66-
impl<'de> de::Visitor<'de> for FieldTypeNameVisitor {
67-
type Value = String;
68-
69-
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
70-
formatter.write_str("a string containing json data")
71-
}
72-
73-
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
74-
where
75-
E: de::Error,
76-
{
77-
if !RE.is_match(v) {
78-
return Err(E::custom(format!("Invalid type definition {}", v)))
79-
}
80-
Ok(v.to_owned())
81-
}
82-
}
83-
84-
deserializer.deserialize_any(FieldTypeNameVisitor)
53+
pub type_: String,
8554
}
8655

8756
#[cfg(test)]

util/EIP-712/src/error.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,13 @@ pub enum ErrorKind {
4747
ArrayParseError(String),
4848
/// schema validation error
4949
#[fail(display = "{}", _0)]
50-
SchemaValidationError(String)
50+
SchemaValidationError(String),
51+
/// Unexpected token
52+
#[fail(display = "Unexpected token '{}' while parsing typename '{}'", _0, _1)]
53+
UnexpectedToken(String, String),
54+
/// the user has attempted to define an typed array with a depth > 10
55+
#[fail(display = "Maximum depth for nested arrays is 10")]
56+
UnsupportedArrayDepth
5157
}
5258

5359
pub(crate) fn serde_error(expected: &str, field: &str) -> ErrorKind {

util/EIP-712/src/lib.rs

Lines changed: 51 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -26,56 +26,34 @@ extern crate itertools;
2626
extern crate failure;
2727
extern crate valico;
2828
extern crate linked_hash_set;
29-
extern crate regex;
29+
extern crate lunarity;
30+
extern crate toolshed;
3031
#[macro_use]
3132
extern crate failure_derive;
3233
#[macro_use]
3334
extern crate serde_derive;
34-
#[macro_use]
35-
extern crate lazy_static;
3635

3736
#[cfg(test)]
3837
extern crate hex;
3938

4039
mod eip712;
4140
mod error;
4241
mod schema;
42+
mod parser;
43+
use parser::*;
4344
pub use error::*;
4445
pub use eip712::*;
4546
use schema::*;
4647

47-
use ethabi::{encode, Token};
48-
use ethereum_types::{Address, U256, H256};
48+
use ethabi::{encode, Token as EthAbiToken};
49+
use ethereum_types::{Address as EthAddress, U256, H256};
4950
use keccak_hash::keccak;
5051
use serde_json::Value;
51-
use std::collections::HashSet;
5252
use std::str::FromStr;
5353
use itertools::Itertools;
5454
use linked_hash_set::LinkedHashSet;
5555
use serde_json::to_value;
5656

57-
58-
lazy_static! {
59-
static ref INT_TYPES: HashSet<&'static str> = vec![
60-
"int8", "int16", "int24", "int32", "int40", "int48", "int56", "int64", "int72", "int80",
61-
"int88", "int96", "int104", "int112", "int120", "int128", "int136", "int144", "int152", "int160",
62-
"int168", "int176", "int184", "int192", "int200", "int208", "int216", "int224", "int232", "int240",
63-
"int248", "int256", "uint8", "uint16", "uint24", "uint32", "uint40", "uint48", "uint56",
64-
"uint64", "uint72", "uint80", "uint88", "uint96", "uint104", "uint112", "uint120", "uint128",
65-
"uint136", "uint144", "uint152", "uint160", "uint168", "uint176", "uint184", "uint192", "uint200",
66-
"uint208", "uint216", "uint224", "uint232", "uint240", "uint248", "uint256"
67-
].into_iter().collect();
68-
69-
static ref BYTES_TYPES: HashSet<&'static str> = vec![
70-
"bytes1", "bytes2", "bytes3", "bytes4", "bytes5", "bytes6", "bytes7", "bytes8",
71-
"bytes9", "bytes10", "bytes11", "bytes12", "bytes13", "bytes14", "bytes15", "bytes16", "bytes17",
72-
"bytes18", "bytes19", "bytes20", "bytes21", "bytes22", "bytes23", "bytes24", "bytes25", "bytes26",
73-
"bytes27", "bytes28", "bytes29", "bytes30", "bytes31", "bytes32"
74-
].into_iter().collect();
75-
76-
}
77-
78-
7957
/// given a type and HashMap<String, Vec<FieldType>>
8058
/// returns a HashSet of dependent types of the given type
8159
fn build_dependencies<'a>(message_type: &'a str, message_types: &'a MessageTypes) -> Option<(LinkedHashSet<&'a str>)>
@@ -138,38 +116,43 @@ fn type_hash(message_type: &str, typed_data: &MessageTypes) -> Result<H256> {
138116
Ok(keccak(encode_type(message_type, typed_data)?))
139117
}
140118

141-
fn encode_data(message_type: &str, message_types: &MessageTypes, message: &Value) -> Result<Vec<u8>> {
119+
fn encode_data(parser: &Parser, message_type: &str, message_types: &MessageTypes, message: &Value) -> Result<Vec<u8>> {
142120
let type_hash = (&type_hash(message_type, &message_types)?).to_vec();
143-
let mut tokens = vec![Token::FixedBytes(type_hash)];
121+
let mut tokens = vec![EthAbiToken::FixedBytes(type_hash)];
122+
144123
for field in message_types.get(message_type).ok_or_else(|| ErrorKind::NonExistentType)? {
145124
let value = &message[&field.name];
146-
match &*field.type_ {
147-
// Array type e.g uint256[], string[]
148-
ty if ty.len() > 1 && ty.rfind(']') == Some(ty.len() - 1) => {
149-
let array_type = ty.find('[')
150-
.and_then(|index| ty.get(..index))
151-
.ok_or_else(|| ErrorKind::ArrayParseError(field.name.clone()))?;
125+
let type_ = parser.parse_type(&*field.type_)?;
152126

127+
match type_ {
128+
Type::Array(array_type) => {
153129
let mut items = vec![];
154130

155131
for item in value.as_array().ok_or_else(|| serde_error("array", &field.name))? {
156-
// is the array defined in the custom types?
157-
if let Some(_) = message_types.get(array_type) {
158-
let encoded = encode_data(array_type.into(), &message_types, item)?;
159-
items.push(encoded);
160-
} else {
161-
// it's either a primitive or invalid
162-
let token = encode_primitive(array_type.into(), &field.name, item)?;
163-
items.push(encode(&[token]));
164-
}
132+
let nested_type = *array_type.clone();
133+
match nested_type {
134+
Type::Array(nested_arr) => {
135+
let nested_type: String = (*nested_arr).into();
136+
let encoded = encode_data(parser, &*nested_type, &message_types, item)?;
137+
items.push(encoded);
138+
},
139+
Type::Custom(ident) => {
140+
let encoded = encode_data(parser, &ident, &message_types, item)?;
141+
items.push(encoded);
142+
}
143+
_ => {
144+
let token = encode_primitive(nested_type, &field.name, item)?;
145+
items.push(encode(&[token]));
146+
}
147+
};
165148
}
166-
tokens.push(Token::FixedBytes(keccak(items.concat()).0.to_vec()));
149+
tokens.push(EthAbiToken::FixedBytes(keccak(items.concat()).0.to_vec()));
167150
}
168151
// custom type defined in message types
169-
t if message_types.get(t).is_some() => {
170-
let encoded = encode_data(&field.type_, &message_types, &value)?;
152+
Type::Custom(ref ident) if message_types.get(&*ident).is_some() => {
153+
let encoded = encode_data(parser, &ident, &message_types, &value)?;
171154
let hash = (&keccak(encoded)).to_vec();
172-
tokens.push(Token::FixedBytes(hash));
155+
tokens.push(EthAbiToken::FixedBytes(hash));
173156
}
174157
// ethabi primitive types
175158
field_type => {
@@ -181,9 +164,9 @@ fn encode_data(message_type: &str, message_types: &MessageTypes, message: &Value
181164
return Ok(encode(&tokens));
182165
}
183166

184-
fn encode_primitive(field_type: &str, field_name: &str, value: &Value) -> Result<Token> {
167+
fn encode_primitive(field_type: Type, field_name: &str, value: &Value) -> Result<EthAbiToken> {
185168
match field_type {
186-
"bytes" => {
169+
Type::Bytes(size) if size == 32 => {
187170
let string = value.as_str().ok_or_else(|| serde_error("string", field_name))?;
188171
if string.len() <= 2 {
189172
return Err(ErrorKind::HexParseError(
@@ -193,9 +176,9 @@ fn encode_primitive(field_type: &str, field_name: &str, value: &Value) -> Result
193176
let string = string.get(2..).expect("line 188 checks for length; qed");
194177
let bytes = H256::from_str(string).map_err(|err| ErrorKind::HexParseError(format!("{}", err)))?;
195178
let hash = (&keccak(&bytes)).to_vec();
196-
return Ok(Token::FixedBytes(hash));
179+
return Ok(EthAbiToken::FixedBytes(hash));
197180
}
198-
ty if BYTES_TYPES.contains(ty) => {
181+
Type::Bytes(size) if size < 32 => {
199182
let string = value.as_str().ok_or_else(|| serde_error("string", field_name))?;
200183
if string.len() <= 2 {
201184
return Err(ErrorKind::HexParseError(
@@ -204,26 +187,25 @@ fn encode_primitive(field_type: &str, field_name: &str, value: &Value) -> Result
204187
}
205188
let string = string.get(2..).expect("line 200 checks for length; qed");
206189
let bytes = H256::from_str(string).map_err(|err| ErrorKind::HexParseError(format!("{}", err)))?;
207-
return Ok(Token::FixedBytes(bytes.to_vec()));
190+
return Ok(EthAbiToken::FixedBytes(bytes.to_vec()));
208191
}
209-
"string" => {
192+
Type::String => {
210193
let value = value.as_str().ok_or_else(|| serde_error("string", field_name))?;
211194
let hash = (&keccak(value)).to_vec();
212-
return Ok(Token::FixedBytes(hash));
195+
return Ok(EthAbiToken::FixedBytes(hash));
213196
}
214-
"bool" => return Ok(Token::Bool(value.as_bool().ok_or_else(|| serde_error("bool", field_name))?)),
215-
"address" => {
197+
Type::Bool => return Ok(EthAbiToken::Bool(value.as_bool().ok_or_else(|| serde_error("bool", field_name))?)),
198+
Type::Address => {
216199
let addr = value.as_str().ok_or_else(|| serde_error("string", field_name))?;
217200
if addr.len() != 42 {
218201
return Err(ErrorKind::InvalidAddressLength(addr.len()))?;
219202
}
220203
// we've checked the address length, this is safe
221204
let addr = addr.get(2..).unwrap();
222-
let address = Address::from_str(addr).map_err(|err| ErrorKind::HexParseError(format!("{}", err)))?;
223-
return Ok(Token::Address(address));
205+
let address = EthAddress::from_str(addr).map_err(|err| ErrorKind::HexParseError(format!("{}", err)))?;
206+
return Ok(EthAbiToken::Address(address));
224207
}
225-
// (un)signed integers
226-
ty if INT_TYPES.contains(ty) => {
208+
Type::Uint => {
227209
// try to deserialize as a number first, then a string
228210
let uint = match (value.as_u64(), value.as_str()) {
229211
(Some(number), _) => U256::from(number),
@@ -238,10 +220,10 @@ fn encode_primitive(field_type: &str, field_name: &str, value: &Value) -> Result
238220
}
239221
_ => return Err(serde_error("int/uint", field_name))?
240222
};
241-
return Ok(Token::Uint(uint));
223+
return Ok(EthAbiToken::Uint(uint));
242224
}
243225
// the type couldn't be encoded
244-
_ => return Err(ErrorKind::UnknownType(field_name.to_owned(), field_type.to_owned()))?
226+
_ => return Err(ErrorKind::UnknownType(field_name.to_owned(), "".to_owned()))?
245227
}
246228
}
247229

@@ -252,9 +234,10 @@ pub fn hash_data(typed_data: EIP712) -> Result<Vec<u8>> {
252234
// EIP-191 compliant
253235
let prefix = (b"\x19\x01").to_vec();
254236
let domain = to_value(&typed_data.domain).unwrap();
237+
let parser = Parser::new();
255238
let (domain_hash, data_hash) = (
256-
keccak(encode_data("EIP712Domain", &typed_data.types, &domain)?).0,
257-
keccak(encode_data(&typed_data.primary_type, &typed_data.types, &typed_data.message)?).0
239+
keccak(encode_data(&parser, "EIP712Domain", &typed_data.types, &domain)?).0,
240+
keccak(encode_data(&parser, &typed_data.primary_type, &typed_data.types, &typed_data.message)?).0
258241
);
259242
let concat = [&prefix[..], &domain_hash[..], &data_hash[..]].concat();
260243
Ok((&keccak(concat)).to_vec())
@@ -403,7 +386,8 @@ mod tests {
403386
#[test]
404387
fn test_encode_data() {
405388
let typed_data = from_str::<EIP712>(JSON).expect("alas error!");
406-
let encoded = encode_data("Mail".into(), &typed_data.types, &typed_data.message).expect("alas error!");
389+
let encoded = encode_data(&Parser::new(), "Mail".into(), &typed_data.types, &typed_data.message).expect("alas \
390+
error!");
407391
assert_eq!(hex::encode(encoded), "a0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8cd54f074a4af31b4411ff6a60c9719dbd559c221c8ac3492d9d872b041d703d1b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8")
408392
}
409393

0 commit comments

Comments
 (0)