[builtin]: support multiple prices and activations in chain spec (#11039)

* [builtin]: impl new builtin type

Have an enum to deserialize either a builtin of a single price or several prices

* [builtin]: style cleanup

* [builtin]: fix tests

* [builtin]: replace boxing with wrapper enum

* cleanup

* fix: make it backward compatible with old builtin

* fix: update chain specs

* fix: revert use of `type alias` on enum

The CI doesn't use the latest rust.

This commit reverts that change

* fix: builtin tests

* fix: revert use of `type alias` on enum

* [basic-authority]: update test-chainspec

* fix failing tests

* [builtin]: multi-prices add `info field`

It might be hard to read chain specs with several activations points.
This commit introduces a `info` field which may be used to write some
information about the current activation such as:

`Istanbul hardfork EIP-1108` or something similar.

* fix: bad rebase

Co-Authored-By: David <dvdplm@gmail.com>

* fix(grumbles): make it backward compatible

* grumbles: resolve `NOTE`

* revert chain specs changes

* rename test

Co-Authored-By: David <dvdplm@gmail.com>

* [builtin docs]: price -> Fixed price

Co-Authored-By: Andronik Ordian <write@reusable.software>

* [json]: address naming grumbles

InnerPricing -> PricingInner
PriceWithActivationAt -> PricingAt

* docs: revert changes for `AltBn128ConstOperations`

* [json]: usize -> u64

Use explicit types to cope with platform dependent issues for `usize`

* grumble: simplify `spec_backward_compability.json`

* docs: add issue link to `TODO`

* [builtin]: replace `match` with `map`

* [builtin]: add deprecation message `eip1108` params

* nits

* [json spec tests]: fix json indentation

* [json docs]: fix typos

* [json]: `compability layer` + deser to BTreeMap

Previously we had to match `Pricing::Single` and `PricingMulti` which this fixes.
It does by introducing a compability layer and into() implemenentation.

In addition, I switched the deserialization to `BTreeMap` instead of `Vec`.
That changes the format of the chain spec again

* [json]: rename `BuiltinCombat` -> `BuiltinCompat`

* Update ethcore/builtin/src/lib.rs

Co-Authored-By: David <dvdplm@gmail.com>

* [json builtin]: improve docs

Co-Authored-By: David <dvdplm@gmail.com>

* [json builtin]: improve docs

Co-Authored-By: David <dvdplm@gmail.com>

* chore(builtin): sort dependencies

* [json builtin]: deprecate `eip1108` params

* [machine]: add bench for calling builtin contract

* [machine]: reduce calls to `Builtin::is_active`

* [builtin]: fix nits

* [json]: revert breakage of chain specs

* [json builtin]: remove `eip1108` params

* [chain specs]: update to new format

* [machine]: revert changes

* [devp2p]: revert change

* [builtin]: doc nits
This commit is contained in:
Niklas Adolfsson
2019-10-31 17:09:08 +01:00
committed by Andronik Ordian
parent 80754c3426
commit 13729a0f7f
47 changed files with 1703 additions and 908 deletions

View File

@@ -18,16 +18,17 @@
use std::collections::BTreeMap;
use crate::{bytes::Bytes, spec::builtin::Builtin, uint::Uint};
use crate::{bytes::Bytes, spec::builtin::BuiltinCompat, uint::Uint};
use serde::Deserialize;
/// Spec account.
#[cfg_attr(any(test, feature = "test-helpers"), derive(Clone))]
#[derive(Debug, PartialEq, Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "camelCase")]
pub struct Account {
/// Builtin contract.
pub builtin: Option<Builtin>,
pub builtin: Option<BuiltinCompat>,
/// Balance.
pub balance: Option<Uint>,
/// Nonce.
@@ -101,7 +102,15 @@ mod tests {
#[test]
fn account_empty() {
let s = r#"{
"builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } }
"builtin": {
"name": "ecrecover",
"pricing": {
"linear": {
"base": 3000,
"word": 0
}
}
}
}"#;
let deserialized: Account = serde_json::from_str(s).unwrap();
assert!(deserialized.is_empty());
@@ -112,8 +121,16 @@ mod tests {
let s = r#"{
"balance": "1",
"nonce": "0",
"builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } },
"code": "1234"
"code": "1234",
"builtin": {
"name": "ecrecover",
"pricing": {
"linear": {
"base": 3000,
"word": 0
}
}
}
}"#;
let deserialized: Account = serde_json::from_str(s).unwrap();
assert!(!deserialized.is_empty());

View File

@@ -16,18 +16,19 @@
//! Spec builtin deserialization.
use std::collections::BTreeMap;
use crate::uint::Uint;
use serde::Deserialize;
/// Linear pricing.
#[derive(Debug, PartialEq, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct Linear {
/// Base price.
pub base: usize,
pub base: u64,
/// Price for word.
pub word: usize,
pub word: u64,
}
/// Pricing for modular exponentiation.
@@ -35,7 +36,7 @@ pub struct Linear {
#[serde(deny_unknown_fields)]
pub struct Modexp {
/// Price divisor.
pub divisor: usize,
pub divisor: u64,
}
/// Pricing for constant alt_bn128 operations (ECADD and ECMUL)
@@ -43,9 +44,7 @@ pub struct Modexp {
#[serde(deny_unknown_fields)]
pub struct AltBn128ConstOperations {
/// price
pub price: usize,
/// EIP 1108 transition price
pub eip1108_transition_price: usize,
pub price: u64,
}
/// Pricing for alt_bn128_pairing.
@@ -53,13 +52,9 @@ pub struct AltBn128ConstOperations {
#[serde(deny_unknown_fields)]
pub struct AltBn128Pairing {
/// Base price.
pub base: usize,
pub base: u64,
/// Price per point pair.
pub pair: usize,
/// EIP 1108 transition base price
pub eip1108_transition_base: usize,
/// EIP 1108 transition price per point pair
pub eip1108_transition_pair: usize,
pub pair: u64,
}
/// Pricing variants.
@@ -82,23 +77,70 @@ pub enum Pricing {
AltBn128ConstOperations(AltBn128ConstOperations),
}
/// Spec builtin.
/// Builtin compability layer
#[derive(Debug, PartialEq, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct BuiltinCompat {
/// Builtin name.
name: String,
/// Builtin pricing.
pricing: PricingCompat,
/// Activation block.
activate_at: Option<Uint>,
}
/// Spec builtin.
#[derive(Debug, PartialEq, Clone)]
pub struct Builtin {
/// Builtin name.
pub name: String,
/// Builtin pricing.
pub pricing: Pricing,
/// Activation block.
pub activate_at: Option<Uint>,
/// EIP 1108
pub eip1108_transition: Option<Uint>,
pub pricing: BTreeMap<u64, PricingAt>,
}
impl From<BuiltinCompat> for Builtin {
fn from(legacy: BuiltinCompat) -> Self {
let pricing = match legacy.pricing {
PricingCompat::Single(pricing) => {
let mut map = BTreeMap::new();
let activate_at: u64 = legacy.activate_at.map_or(0, Into::into);
map.insert(activate_at, PricingAt { info: None, price: pricing });
map
}
PricingCompat::Multi(pricings) => {
pricings.into_iter().map(|(a, p)| (a.into(), p)).collect()
}
};
Self { name: legacy.name, pricing }
}
}
/// Compability layer for different pricings
#[derive(Debug, PartialEq, Deserialize, Clone)]
#[serde(rename_all = "snake_case")]
#[serde(deny_unknown_fields)]
#[serde(untagged)]
enum PricingCompat {
/// Single builtin
Single(Pricing),
/// Multiple builtins
Multi(BTreeMap<Uint, PricingAt>),
}
/// Price for a builtin, with the block number to activate it on
#[derive(Debug, PartialEq, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct PricingAt {
/// Description of the activation, e.g. "PunyPony HF, March 12, 2025".
pub info: Option<String>,
/// Builtin pricing.
pub price: Pricing,
}
#[cfg(test)]
mod tests {
use super::{Builtin, Modexp, Linear, Pricing, Uint};
use super::{Builtin, BuiltinCompat, BTreeMap, Pricing, PricingAt, Linear, Modexp, AltBn128ConstOperations};
use macros::map;
#[test]
fn builtin_deserialization() {
@@ -106,10 +148,42 @@ mod tests {
"name": "ecrecover",
"pricing": { "linear": { "base": 3000, "word": 0 } }
}"#;
let deserialized: Builtin = serde_json::from_str(s).unwrap();
assert_eq!(deserialized.name, "ecrecover");
assert_eq!(deserialized.pricing, Pricing::Linear(Linear { base: 3000, word: 0 }));
assert!(deserialized.activate_at.is_none());
let builtin: Builtin = serde_json::from_str::<BuiltinCompat>(s).unwrap().into();
assert_eq!(builtin.name, "ecrecover");
assert_eq!(builtin.pricing, map![
0 => PricingAt {
info: None,
price: Pricing::Linear(Linear { base: 3000, word: 0 })
}
]);
}
#[test]
fn deserialize_multiple_pricings() {
let s = r#"{
"name": "ecrecover",
"pricing": {
"0": {
"price": {"linear": { "base": 3000, "word": 0 }}
},
"500": {
"info": "enable fake EIP at block 500",
"price": {"linear": { "base": 10, "word": 0 }}
}
}
}"#;
let builtin: Builtin = serde_json::from_str::<BuiltinCompat>(s).unwrap().into();
assert_eq!(builtin.name, "ecrecover");
assert_eq!(builtin.pricing, map![
0 => PricingAt {
info: None,
price: Pricing::Linear(Linear { base: 3000, word: 0 })
},
500 => PricingAt {
info: Some(String::from("enable fake EIP at block 500")),
price: Pricing::Linear(Linear { base: 10, word: 0 })
}
]);
}
#[test]
@@ -119,10 +193,14 @@ mod tests {
"activate_at": "0xffffff",
"pricing": { "blake2_f": { "gas_per_round": 123 } }
}"#;
let deserialized: Builtin = serde_json::from_str(s).unwrap();
assert_eq!(deserialized.name, "blake2_f");
assert_eq!(deserialized.pricing, Pricing::Blake2F { gas_per_round: 123 });
assert!(deserialized.activate_at.is_some());
let builtin: Builtin = serde_json::from_str::<BuiltinCompat>(s).unwrap().into();
assert_eq!(builtin.name, "blake2_f");
assert_eq!(builtin.pricing, map![
0xffffff => PricingAt {
info: None,
price: Pricing::Blake2F { gas_per_round: 123 }
}
]);
}
#[test]
@@ -133,9 +211,13 @@ mod tests {
"pricing": { "modexp": { "divisor": 5 } }
}"#;
let deserialized: Builtin = serde_json::from_str(s).unwrap();
assert_eq!(deserialized.name, "late_start");
assert_eq!(deserialized.pricing, Pricing::Modexp(Modexp { divisor: 5 }));
assert_eq!(deserialized.activate_at, Some(Uint(100000.into())));
let builtin: Builtin = serde_json::from_str::<BuiltinCompat>(s).unwrap().into();
assert_eq!(builtin.name, "late_start");
assert_eq!(builtin.pricing, map![
100_000 => PricingAt {
info: None,
price: Pricing::Modexp(Modexp { divisor: 5 })
}
]);
}
}

View File

@@ -87,63 +87,63 @@ mod tests {
#[test]
fn should_error_on_unknown_fields() {
let s = r#"{
"name": "Morden",
"dataDir": "morden",
"engine": {
"Ethash": {
"params": {
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"homesteadTransition" : "0x",
"daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": []
}
}
},
"params": {
"accountStartNonce": "0x0100000",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2",
"forkBlock": "0xffffffffffffffff",
"forkCanonHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimitBoundDivisor": "0x20",
"unknownField": "0x0"
},
"genesis": {
"seal": {
"ethereum": {
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x00006d6f7264656e"
"name": "Morden",
"dataDir": "morden",
"engine": {
"Ethash": {
"params": {
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"homesteadTransition" : "0x",
"daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": []
}
}
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2fefd8"
},
"nodes": [
"enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303"
],
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
},
"hardcodedSync": {
"header": "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23",
"totalDifficulty": "0x400000000",
"CHTs": [
"params": {
"accountStartNonce": "0x0100000",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2",
"forkBlock": "0xffffffffffffffff",
"forkCanonHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimitBoundDivisor": "0x20",
"unknownField": "0x0"
},
"genesis": {
"seal": {
"ethereum": {
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x00006d6f7264656e"
}
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2fefd8"
},
"nodes": [
"enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303"
],
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
},
"hardcodedSync": {
"header": "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23",
"totalDifficulty": "0x400000000",
"CHTs": [
"0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
]
}
]
}
}"#;
let result: Result<Spec, _> = serde_json::from_str(s);
assert!(result.is_err());
@@ -152,62 +152,110 @@ mod tests {
#[test]
fn spec_deserialization() {
let s = r#"{
"name": "Morden",
"dataDir": "morden",
"engine": {
"Ethash": {
"params": {
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"homesteadTransition" : "0x",
"daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": []
}
}
},
"params": {
"accountStartNonce": "0x0100000",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2",
"forkBlock": "0xffffffffffffffff",
"forkCanonHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimitBoundDivisor": "0x20"
},
"genesis": {
"seal": {
"ethereum": {
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x00006d6f7264656e"
"name": "Morden",
"dataDir": "morden",
"engine": {
"Ethash": {
"params": {
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"homesteadTransition" : "0x",
"daoHardforkTransition": "0xffffffffffffffff",
"daoHardforkBeneficiary": "0x0000000000000000000000000000000000000000",
"daoHardforkAccounts": []
}
}
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2fefd8"
},
"nodes": [
"enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303"
],
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
},
"hardcodedSync": {
"header": "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23",
"totalDifficulty": "0x400000000",
"CHTs": [
"0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
]
}
"params": {
"accountStartNonce": "0x0100000",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2",
"forkBlock": "0xffffffffffffffff",
"forkCanonHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimitBoundDivisor": "0x20"
},
"genesis": {
"seal": {
"ethereum": {
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x00006d6f7264656e"
}
},
"difficulty": "0x20000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x2fefd8"
},
"nodes": [
"enode://b1217cbaa440e35ed471157123fe468e19e8b5ad5bedb4b1fdbcbdab6fb2f5ed3e95dd9c24a22a79fdb2352204cea207df27d92bfd21bfd41545e8b16f637499@104.44.138.37:30303"
],
"accounts": {
"0000000000000000000000000000000000000001": {
"balance": "1",
"nonce": "1048576",
"builtin": {
"name": "ecrecover",
"pricing": {
"linear": {
"base": 3000,
"word": 0
}
}
}
},
"0000000000000000000000000000000000000002": {
"balance": "1",
"nonce": "1048576",
"builtin": {
"name": "sha256",
"pricing": {
"linear": {
"base": 60,
"word": 12
}
}
}
},
"0000000000000000000000000000000000000003": {
"balance": "1",
"nonce": "1048576",
"builtin": {
"name": "ripemd160",
"pricing": {
"linear": {
"base": 600,
"word": 120
}
}
}
},
"0000000000000000000000000000000000000004": {
"balance": "1",
"nonce": "1048576",
"builtin": {
"name": "identity",
"pricing": {
"linear": {
"base": 15,
"word": 3
}
}
}
},
"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "nonce": "1048576" }
},
"hardcodedSync": {
"header": "f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23",
"totalDifficulty": "0x400000000",
"CHTs": [
"0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
]
}
}"#;
let _deserialized: Spec = serde_json::from_str(s).unwrap();
// TODO: validate all fields

View File

@@ -50,7 +50,7 @@ impl State {
HashOrMap::Hash(_) => BTreeMap::default(),
HashOrMap::Map(map) => {
map.iter().filter_map(|(add, ref acc)| {
acc.builtin.clone().map(|b| (add.clone(), b))
acc.builtin.clone().map(|b| (add.clone(), b.into()))
}).collect()
}