1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use spec::{Function as FunctionInterface, ParamType};
use token::Token;
use encoder::Encoder;
use decoder::Decoder;
use signature::short_signature;
use errors::{Error, ErrorKind};
#[derive(Clone, Debug)]
pub struct Function {
interface: FunctionInterface,
}
impl Function {
pub fn new(interface: FunctionInterface) -> Self {
Function {
interface: interface
}
}
pub fn input_params(&self) -> Vec<ParamType> {
self.interface.input_param_types()
}
pub fn output_params(&self) -> Vec<ParamType> {
self.interface.output_param_types()
}
pub fn encode_call(&self, tokens: Vec<Token>) -> Result<Vec<u8>, Error> {
let params = self.interface.input_param_types();
if !type_check(&tokens, ¶ms) {
return Err(ErrorKind::InvalidData.into());
}
let signed = short_signature(&self.interface.name, ¶ms).to_vec();
let encoded = Encoder::encode(tokens);
Ok(signed.into_iter().chain(encoded.into_iter()).collect())
}
pub fn decode_output(&self, data: Vec<u8>) -> Result<Vec<Token>, Error> {
Decoder::decode(&self.interface.output_param_types(), data)
}
pub fn name(&self) -> &str {
&self.interface.name
}
}
pub fn type_check(tokens: &[Token], param_types: &[ParamType]) -> bool {
param_types.len() == tokens.len() && {
param_types.iter().zip(tokens).all(|e| {
let (param_type, token) = e;
token.type_check(param_type)
})
}
}
#[cfg(test)]
mod tests {
use hex::FromHex;
use spec::{Function as FunctionInterface, ParamType, Param};
use token::Token;
use super::Function;
use super::type_check;
#[test]
fn test_function_encode_call() {
let interface = FunctionInterface {
name: "baz".to_owned(),
inputs: vec![Param {
name: "a".to_owned(),
kind: ParamType::Uint(32),
}, Param {
name: "b".to_owned(),
kind: ParamType::Bool,
}],
outputs: vec![]
};
let func = Function::new(interface);
let mut uint = [0u8; 32];
uint[31] = 69;
let encoded = func.encode_call(vec![Token::Uint(uint), Token::Bool(true)]).unwrap();
let expected = "cdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001".from_hex().unwrap();
assert_eq!(encoded, expected);
}
#[test]
fn test_type_check() {
fn assert_type_check(tokens: Vec<Token>, param_types: Vec<ParamType>) {
assert!(type_check(&tokens, ¶m_types))
}
fn assert_not_type_check(tokens: Vec<Token>, param_types: Vec<ParamType>) {
assert!(!type_check(&tokens, ¶m_types))
}
assert_type_check(vec![Token::Uint([0u8; 32]), Token::Bool(false)], vec![ParamType::Uint(256), ParamType::Bool]);
assert_type_check(vec![Token::Uint([0u8; 32]), Token::Bool(false)], vec![ParamType::Uint(32), ParamType::Bool]);
assert_not_type_check(vec![Token::Uint([0u8; 32])], vec![ParamType::Uint(32), ParamType::Bool]);
assert_not_type_check(vec![Token::Uint([0u8; 32]), Token::Bool(false)], vec![ParamType::Uint(32)]);
assert_not_type_check(vec![Token::Bool(false), Token::Uint([0u8; 32])], vec![ParamType::Uint(32), ParamType::Bool]);
assert_type_check(vec![Token::FixedBytes(vec![0, 0, 0, 0])], vec![ParamType::FixedBytes(4)]);
assert_not_type_check(vec![Token::FixedBytes(vec![0, 0, 0, 0])], vec![ParamType::FixedBytes(3)]);
assert_type_check(vec![Token::Array(vec![Token::Bool(false), Token::Bool(true)])], vec![ParamType::Array(Box::new(ParamType::Bool))]);
assert_not_type_check(vec![Token::Array(vec![Token::Bool(false), Token::Uint([0u8; 32])])], vec![ParamType::Array(Box::new(ParamType::Bool))]);
assert_not_type_check(vec![Token::Array(vec![Token::Bool(false), Token::Bool(true)])], vec![ParamType::Array(Box::new(ParamType::Address))]);
assert_type_check(vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])], vec![ParamType::FixedArray(Box::new(ParamType::Bool), 2)]);
assert_not_type_check(vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])], vec![ParamType::FixedArray(Box::new(ParamType::Bool), 3)]);
assert_not_type_check(vec![Token::FixedArray(vec![Token::Bool(false), Token::Uint([0u8; 32])])], vec![ParamType::FixedArray(Box::new(ParamType::Bool), 2)]);
assert_not_type_check(vec![Token::FixedArray(vec![Token::Bool(false), Token::Bool(true)])], vec![ParamType::FixedArray(Box::new(ParamType::Address), 2)]);
}
}