1use std::io::Read;
20use crate::spec::{Params, Genesis, Engine, State, HardcodedSync};
21use serde::Deserialize;
22use serde_json::Error;
23
24#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize)]
26pub enum ForkSpec {
27 EIP150,
29 EIP158,
31 Frontier,
33 Homestead,
35 Byzantium,
37 Constantinople,
39 ConstantinopleFix,
41 Istanbul,
43 EIP158ToByzantiumAt5,
45 FrontierToHomesteadAt5,
47 HomesteadToDaoAt5,
49 HomesteadToEIP150At5,
51}
52
53#[derive(Debug, PartialEq, Deserialize)]
55#[serde(deny_unknown_fields)]
56#[serde(rename_all = "camelCase")]
57pub struct Spec {
58 pub name: String,
60 pub data_dir: Option<String>,
62 pub engine: Engine,
64 pub params: Params,
66 pub genesis: Genesis,
68 pub accounts: State,
70 pub nodes: Option<Vec<String>>,
72 pub hardcoded_sync: Option<HardcodedSync>,
74}
75
76impl Spec {
77 pub fn load<R>(reader: R) -> Result<Self, Error> where R: Read {
79 serde_json::from_reader(reader)
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::Spec;
86
87 #[test]
88 fn should_error_on_unknown_fields() {
89 let s = r#"{
90 "name": "Morden",
91 "dataDir": "morden",
92 "engine": {
93 "Vapash": {
94 "params": {
95 "minimumDifficulty": "0x020000",
96 "difficultyBoundDivisor": "0x0800",
97 "durationLimit": "0x0d",
98 "homesteadTransition" : "0x",
99 "daoHardforkTransition": "0xffffffffffffffff",
100 "daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
101 "daoHardforkAccounts": []
102 }
103 }
104 },
105 "params": {
106 "accountStartNonce": "0x0100000",
107 "maximumExtraDataSize": "0x20",
108 "minGasLimit": "0x1388",
109 "networkID" : "0x2",
110 "forkBlock": "0xffffffffffffffff",
111 "forkCanonHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
112 "gasLimitBoundDivisor": "0x20",
113 "unknownField": "0x0"
114 },
115 "genesis": {
116 "seal": {
117 "vapory": {
118 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
119 "nonce": "0x00006d6f7264656e"
120 }
121 },
122 "difficulty": "0x20000",
123 "author": "0x0000000000000000000000000000000000000000",
124 "timestamp": "0x00",
125 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
126 "extraData": "0x",
127 "gasLimit": "0x2fefd8"
128 },
129 "nodes": [
130 "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303"
131 ],
132 "accounts": {
133 "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
134 "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
135 "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
136 "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
137 "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
138 },
139 "hardcodedSync": {
140 "header": "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23",
141 "totalDifficulty": "0x400000000",
142 "CHTs": [
143 "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
144 "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
145 ]
146 }
147 }"#;
148 let result: Result<Spec, _> = serde_json::from_str(s);
149 assert!(result.is_err());
150 }
151
152 #[test]
153 fn spec_deserialization() {
154 let s = r#"{
155 "name": "Morden",
156 "dataDir": "morden",
157 "engine": {
158 "Vapash": {
159 "params": {
160 "minimumDifficulty": "0x020000",
161 "difficultyBoundDivisor": "0x0800",
162 "durationLimit": "0x0d",
163 "homesteadTransition" : "0x",
164 "daoHardforkTransition": "0xffffffffffffffff",
165 "daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
166 "daoHardforkAccounts": []
167 }
168 }
169 },
170 "params": {
171 "accountStartNonce": "0x0100000",
172 "maximumExtraDataSize": "0x20",
173 "minGasLimit": "0x1388",
174 "networkID" : "0x2",
175 "forkBlock": "0xffffffffffffffff",
176 "forkCanonHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
177 "gasLimitBoundDivisor": "0x20"
178 },
179 "genesis": {
180 "seal": {
181 "vapory": {
182 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
183 "nonce": "0x00006d6f7264656e"
184 }
185 },
186 "difficulty": "0x20000",
187 "author": "0x0000000000000000000000000000000000000000",
188 "timestamp": "0x00",
189 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
190 "extraData": "0x",
191 "gasLimit": "0x2fefd8"
192 },
193 "nodes": [
194 "enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303"
195 ],
196 "accounts": {
197 "0000000000000000000000000000000000000001": {
198 "balance": "1",
199 "nonce": "1048576",
200 "builtin": {
201 "name": "ecrecover",
202 "pricing": {
203 "linear": {
204 "base": 3000,
205 "word": 0
206 }
207 }
208 }
209 },
210 "0000000000000000000000000000000000000002": {
211 "balance": "1",
212 "nonce": "1048576",
213 "builtin": {
214 "name": "sha256",
215 "pricing": {
216 "linear": {
217 "base": 60,
218 "word": 12
219 }
220 }
221 }
222 },
223 "0000000000000000000000000000000000000003": {
224 "balance": "1",
225 "nonce": "1048576",
226 "builtin": {
227 "name": "ripemd160",
228 "pricing": {
229 "linear": {
230 "base": 600,
231 "word": 120
232 }
233 }
234 }
235 },
236 "0000000000000000000000000000000000000004": {
237 "balance": "1",
238 "nonce": "1048576",
239 "builtin": {
240 "name": "identity",
241 "pricing": {
242 "linear": {
243 "base": 15,
244 "word": 3
245 }
246 }
247 }
248 },
249 "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
250 },
251 "hardcodedSync": {
252 "header": "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23",
253 "totalDifficulty": "0x400000000",
254 "CHTs": [
255 "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
256 "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
257 ]
258 }
259 }"#;
260 let _deserialized: Spec = serde_json::from_str(s).unwrap();
261 }
263}